diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index f49d3e0d1d23..b2eac6ca41e7 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -5,6 +5,3 @@ 21a696ef9b170e14ad2daf53364a4c2113822c2f # Update copyright information for 2023 c795874f7f281297bbd3bad2fdb58b24cb4ce624 -# switch to double quotes -5c72ea0046a6b5230bf456f55a296ed6fd579535 -9e4934cd0a468f46d8f0fc0f11ebc2d4216f789c diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 7a014e6b9d54..937c42cd3c66 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,7 +12,7 @@ on: inputs: tag: description: "The tag to release. Note that this happens by default on the tag push. Only run this action when something went wrong!" - required: false + required: true permissions: contents: read # to fetch code (actions/checkout) @@ -23,7 +23,7 @@ env: jobs: build: if: github.repository == 'opf/openproject' - runs-on: runs-on,runner=8cpu-linux,family=m7i+m7a,run-id=${{ github.run_id }} + runs-on: [ self-hosted, aws, ubuntu22, x64, 2XL ] strategy: matrix: include: @@ -45,31 +45,21 @@ jobs: run: | if [[ ${{ github.event_name }} == 'push' ]]; then TAG_REF=${GITHUB_REF#refs/tags/} - CHECKOUT_REF=$GITHUB_REF - elif [[ ${{ github.event_name }} == 'schedule' ]]; then - TAG_REF=dev - CHECKOUT_REF=refs/heads/dev elif [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then TAG_REF=${{ inputs.tag }} - CHECKOUT_REF=${{ inputs.tag }} - else - echo "Unsupported event" - exit 1 - fi - - if [ -z "$TAG_REF" ] || [ -z "$CHECKOUT_REF" ]; then - echo "No TAG_REF or CHECKOUT_REF set. Aborting" - exit 1 fi VERSION=${TAG_REF#v} echo "Version: $VERSION" echo "::set-output name=version::$VERSION" - echo "::set-output name=checkout_ref::$CHECKOUT_REF" - - name: Checkout + - name: Checkout current release + if: ${{ github.event_name == 'push' }} + uses: actions/checkout@v3 + - name: Checkout specific version + if: ${{ github.event_name != 'push' }} with: - ref: ${{ steps.extract_version.outputs.checkout_ref }} - uses: actions/checkout@v4 + ref: ${{ inputs.tag }} + uses: actions/checkout@v3 - name: Prepare docker files run: | cp ./docker/prod/Dockerfile ./Dockerfile @@ -92,7 +82,6 @@ jobs: images: | ${{ env.REGISTRY_IMAGE }} - name: Build image - id: build uses: docker/build-push-action@v4 with: context: . @@ -115,7 +104,7 @@ jobs: -e SUPERVISORD_LOG_LEVEL=debug \ -e OPENPROJECT_LOGIN__REQUIRED=false \ -e OPENPROJECT_HTTPS=false \ - ${{ steps.build.outputs.imageid }} + ${{ fromJSON(steps.meta.outputs.json).tags[0] }} sleep 60 diff --git a/.rubocop.yml b/.rubocop.yml index f646e9c75e1f..b951a30741b5 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -415,9 +415,10 @@ Style/SpecialGlobalVars: # For the record: using single quotes does NOT have any performance advantages. # Even if it did, this would be a silly argument. # -# Quote away. +# Ideally we would just use double quotes everywhere but since that would result +# in innumerable rubocop offenses we will just disable this. Quote away. Style/StringLiterals: - EnforcedStyle: double_quotes + Enabled: false Style/TrivialAccessors: Enabled: false diff --git a/Gemfile b/Gemfile index 057eea92f93d..fe91826a6a2a 100644 --- a/Gemfile +++ b/Gemfile @@ -26,361 +26,362 @@ # See COPYRIGHT and LICENSE files for more details. #++ -source "https://rubygems.org" +source 'https://rubygems.org' # TODO: Once packager.io and heroku buildpacks support bundler 2.4.22, # then we can use the new bundler syntax `ruby file: '.ruby-version'`. # https://github.com/heroku/heroku-buildpack-ruby/issues/1408#issuecomment-1841596215 -ruby File.read(".ruby-version").strip +ruby File.read('.ruby-version').strip -gem "actionpack-xml_parser", "~> 2.0.0" -gem "activemodel-serializers-xml", "~> 1.0.1" -gem "activerecord-import", "~> 1.6.0" -gem "activerecord-session_store", "~> 2.1.0" -gem "ox" -gem "rails", "~> 7.1.3" -gem "responders", "~> 3.0" +gem 'actionpack-xml_parser', '~> 2.0.0' +gem 'activemodel-serializers-xml', '~> 1.0.1' +gem 'activerecord-import', '~> 1.5.0' +gem 'activerecord-session_store', '~> 2.1.0' +gem 'ox' +gem 'rails', '~> 7.1.3' +gem 'responders', '~> 3.0' -gem "ffi", "~> 1.15" +gem 'ffi', '~> 1.15' -gem "rdoc", ">= 2.4.2" +gem 'rdoc', '>= 2.4.2' -gem "doorkeeper", "~> 5.6.6" +gem 'doorkeeper', '~> 5.6.6' # Maintain our own omniauth due to relative URL root issues # see upstream PR: https://github.com/omniauth/omniauth/pull/903 -gem "omniauth", git: "https://github.com/opf/omniauth", ref: "fe862f986b2e846e291784d2caa3d90a658c67f0" -gem "request_store", "~> 1.6.0" +gem 'omniauth', git: 'https://github.com/opf/omniauth', ref: 'fe862f986b2e846e291784d2caa3d90a658c67f0' +gem 'request_store', '~> 1.6.0' -gem "warden", "~> 1.2" -gem "warden-basic_auth", "~> 0.2.1" +gem 'warden', '~> 1.2' +gem 'warden-basic_auth', '~> 0.2.1' -gem "will_paginate", "~> 4.0.0" +gem 'will_paginate', '~> 4.0.0' -gem "friendly_id", "~> 5.5.0" +gem 'friendly_id', '~> 5.5.0' -gem "acts_as_list", "~> 1.1.0" -gem "acts_as_tree", "~> 2.9.0" -gem "awesome_nested_set", "~> 3.6.0" -gem "closure_tree", "~> 7.4.0" -gem "rubytree", "~> 2.0.0" +gem 'acts_as_list', '~> 1.1.0' +gem 'acts_as_tree', '~> 2.9.0' +gem 'awesome_nested_set', '~> 3.6.0' +gem 'closure_tree', '~> 7.4.0' +gem 'rubytree', '~> 2.0.0' # Only used in down migrations now. # Is to be removed once the referencing migrations have been squashed. -gem "typed_dag", "~> 2.0.2", require: false +gem 'typed_dag', '~> 2.0.2', require: false -gem "addressable", "~> 2.8.0" +gem 'addressable', '~> 2.8.0' # Remove whitespace from model input -gem "auto_strip_attributes", "~> 2.5" +gem 'auto_strip_attributes', '~> 2.5' # Provide timezone info for TZInfo used by AR -gem "tzinfo-data", "~> 1.2024.1" +gem 'tzinfo-data', '~> 1.2024.1' # to generate html-diffs (e.g. for wiki comparison) -gem "htmldiff" +gem 'htmldiff' # Generate url slugs with #to_url and other string niceties -gem "stringex", "~> 2.8.5" +gem 'stringex', '~> 2.8.5' # CommonMark markdown parser with GFM extension -gem "commonmarker", "~> 1.0.3" +gem 'commonmarker', '~> 1.0.3' # HTML pipeline for transformations on text formatter output # such as sanitization or additional features -gem "html-pipeline", "~> 2.14.0" +gem 'html-pipeline', '~> 2.14.0' # Tasklist parsing and renderer -gem "deckar01-task_list", "~> 2.3.1" +gem 'deckar01-task_list', '~> 2.3.1' # Requires escape-utils for faster escaping -gem "escape_utils", "~> 1.3" +gem 'escape_utils', '~> 1.3' # Syntax highlighting used in html-pipeline with rouge -gem "rouge", "~> 4.2.0" +gem 'rouge', '~> 4.2.0' # HTML sanitization used for html-pipeline -gem "sanitize", "~> 6.1.0" +gem 'sanitize', '~> 6.1.0' # HTML autolinking for mails and urls (replaces autolink) -gem "rinku", "~> 2.0.4", require: %w[rinku rails_rinku] +gem 'rinku', '~> 2.0.4', require: %w[rinku rails_rinku] # Version parsing with semver -gem "semantic", "~> 1.6.1" +gem 'semantic', '~> 1.6.1' # generates SVG Graphs # used for statistics on svn repositories -gem "svg-graph", "~> 2.2.0" +gem 'svg-graph', '~> 2.2.0' -gem "date_validator", "~> 0.12.0" -gem "email_validator", "~> 2.2.3" -gem "json_schemer", "~> 2.2.0" -gem "ruby-duration", "~> 3.2.0" +gem 'date_validator', '~> 0.12.0' +gem 'email_validator', '~> 2.2.3' +gem 'json_schemer', '~> 2.1.0' +gem 'ruby-duration', '~> 3.2.0' # `config/initializers/mail_starttls_patch.rb` has also been patched to # fix STARTTLS handling until https://github.com/mikel/mail/pull/1536 is # released. -gem "mail", "= 2.8.1" +gem 'mail', '= 2.8.1' # provide compatible filesystem information for available storage -gem "sys-filesystem", "~> 1.4.0", require: false +gem 'sys-filesystem', '~> 1.4.0', require: false -gem "bcrypt", "~> 3.1.6" +gem 'bcrypt', '~> 3.1.6' -gem "multi_json", "~> 1.15.0" -gem "oj", "~> 3.16.0" +gem 'multi_json', '~> 1.15.0' +gem 'oj', '~> 3.16.0' -gem "daemons" -gem "good_job", "= 3.26.2" # update should be done manually in sync with saas-openproject version. +gem 'daemons' +gem 'delayed_cron_job', '~> 0.9.0' +gem 'delayed_job_active_record', '~> 4.1.5' -gem "rack-protection", "~> 3.2.0" +gem 'rack-protection', '~> 3.2.0' # Rack::Attack is a rack middleware to protect your web app from bad clients. # It allows whitelisting, blacklisting, throttling, and tracking based # on arbitrary properties of the request. # https://github.com/kickstarter/rack-attack -gem "rack-attack", "~> 6.7.0" +gem 'rack-attack', '~> 6.7.0' # CSP headers -gem "secure_headers", "~> 6.5.0" +gem 'secure_headers', '~> 6.5.0' # Browser detection for incompatibility checks -gem "browser", "~> 5.3.0" +gem 'browser', '~> 5.3.0' # Providing health checks -gem "okcomputer", "~> 1.18.1" +gem 'okcomputer', '~> 1.18.1' -gem "gon", "~> 6.4.0" +gem 'gon', '~> 6.4.0' # Lograge to provide sane and non-verbose logging -gem "lograge", "~> 0.14.0" +gem 'lograge', '~> 0.14.0' # Structured warnings to selectively disable them in production -gem "structured_warnings", "~> 0.4.0" +gem 'structured_warnings', '~> 0.4.0' # catch exceptions and send them to any airbrake compatible backend # don't require by default, instead load on-demand when actually configured -gem "airbrake", "~> 13.0.0", require: false +gem 'airbrake', '~> 13.0.0', require: false -gem "md_to_pdf", git: "https://github.com/opf/md-to-pdf", ref: "8f14736a88ad0064d2a97be108fe7061ffbcee91" -gem "prawn", "~> 2.4" +gem 'md_to_pdf', git: 'https://github.com/opf/md-to-pdf', ref: '8f14736a88ad0064d2a97be108fe7061ffbcee91' +gem 'prawn', '~> 2.4' # prawn implicitly depends on matrix gem no longer in ruby core with 3.1 -gem "matrix", "~> 0.4.2" +gem 'matrix', '~> 0.4.2' -gem "meta-tags", "~> 2.20.0" +gem 'meta-tags', '~> 2.20.0' -gem "paper_trail", "~> 15.1.0" +gem 'paper_trail', '~> 15.1.0' -gem "clamav-client", github: "honestica/clamav-client", ref: "29e78ae94307cb34e79ddd29c5da79752239d8b7" +gem 'clamav-client', github: 'honestica/clamav-client', ref: '29e78ae94307cb34e79ddd29c5da79752239d8b7' group :production do # we use dalli as standard memcache client # requires memcached 1.4+ - gem "dalli", "~> 3.2.0" - gem "redis", "~> 5.1.0" + gem 'dalli', '~> 3.2.0' + gem 'redis', '~> 5.1.0' end -gem "i18n-js", "~> 4.2.3" -gem "rails-i18n", "~> 7.0.0" +gem 'i18n-js', '~> 4.2.3' +gem 'rails-i18n', '~> 7.0.0' -gem "sprockets", "~> 3.7.2" # lock sprockets below 4.0 -gem "sprockets-rails", "~> 3.4.2" +gem 'sprockets', '~> 3.7.2' # lock sprockets below 4.0 +gem 'sprockets-rails', '~> 3.4.2' -gem "puma", "~> 6.4" -gem "puma-plugin-statsd", "~> 2.0" -gem "rack-timeout", "~> 0.6.3", require: "rack/timeout/base" +gem 'puma', '~> 6.4' +gem 'puma-plugin-statsd', '~> 2.0' +gem 'rack-timeout', '~> 0.6.3', require: 'rack/timeout/base' -gem "nokogiri", "~> 1.16.0" +gem 'nokogiri', '~> 1.16.0' -gem "carrierwave", "~> 1.3.1" -gem "carrierwave_direct", "~> 2.1.0" -gem "fog-aws" +gem 'carrierwave', '~> 1.3.1' +gem 'carrierwave_direct', '~> 2.1.0' +gem 'fog-aws' -gem "aws-sdk-core", "~> 3.107" +gem 'aws-sdk-core', '~> 3.107' # File upload via fog + screenshots on travis -gem "aws-sdk-s3", "~> 1.91" +gem 'aws-sdk-s3', '~> 1.91' -gem "openproject-token", "~> 4.0" +gem 'openproject-token', '~> 4.0' -gem "plaintext", "~> 0.3.2" +gem 'plaintext', '~> 0.3.2' -gem "ruby-progressbar", "~> 1.13.0", require: false +gem 'ruby-progressbar', '~> 1.13.0', require: false -gem "mini_magick", "~> 4.12.0", require: false +gem 'mini_magick', '~> 4.12.0', require: false -gem "validate_url" +gem 'validate_url' # Storages support code -gem "dry-container" +gem 'dry-container' # ActiveRecord extension which adds typecasting to store accessors -gem "store_attribute", "~> 1.0" +gem 'store_attribute', '~> 1.0' # Appsignal integration -gem "appsignal", "~> 3.0", require: false +gem 'appsignal', '~> 3.0', require: false -gem "view_component" +gem 'view_component' # Lookbook -gem "lookbook", "~> 2.2.1" +gem 'lookbook', '~> 2.2.1' # Require factory_bot for usage with openproject plugins testing -gem "factory_bot", "~> 6.4.0", require: false +gem 'factory_bot', '~> 6.4.0', require: false # require factory_bot_rails for convenience in core development -gem "factory_bot_rails", "~> 6.4.0", require: false +gem 'factory_bot_rails', '~> 6.4.0', require: false -gem "turbo-rails", "~> 2.0.0" +gem 'turbo-rails', '~> 2.0.0' -gem "httpx" +gem 'httpx' group :test do - gem "launchy", "~> 3.0.0" - gem "rack-test", "~> 2.1.0" - gem "shoulda-context", "~> 2.0" + gem 'launchy', '~> 3.0.0' + gem 'rack-test', '~> 2.1.0' + gem 'shoulda-context', '~> 2.0' # Test prof provides factories from code # and other niceties - gem "test-prof", "~> 1.3.0" - gem "turbo_tests", github: "crohr/turbo_tests", ref: "fix/runtime-info" + gem 'test-prof', '~> 1.3.0' + gem 'turbo_tests', github: 'crohr/turbo_tests', ref: 'fix/runtime-info' - gem "rack_session_access" - gem "rspec", "~> 3.13.0" + gem 'rack_session_access' + gem 'rspec', '~> 3.13.0' # also add to development group, so 'spec' rake task gets loaded - gem "rspec-rails", "~> 6.1.0", group: :development + gem 'rspec-rails', '~> 6.1.0', group: :development # Retry failures within the same environment - gem "retriable", "~> 3.1.1" - gem "rspec-retry", "~> 0.6.1" + gem 'retriable', '~> 3.1.1' + gem 'rspec-retry', '~> 0.6.1' # Accessibility tests - gem "axe-core-rspec" + gem 'axe-core-rspec' # Modify ENV - gem "climate_control" + gem 'climate_control' # XML comparison tests - gem "compare-xml", "~> 0.66", require: false + gem 'compare-xml', '~> 0.66', require: false # PDF Export tests - gem "pdf-inspector", "~> 1.2" + gem 'pdf-inspector', '~> 1.2' # brings back testing for 'assigns' and 'assert_template' extracted in rails 5 - gem "rails-controller-testing", "~> 1.0.2" + gem 'rails-controller-testing', '~> 1.0.2' - gem "capybara", "~> 3.40.0" - gem "capybara_accessible_selectors", git: "https://github.com/citizensadvice/capybara_accessible_selectors", branch: "main" - gem "capybara-screenshot", "~> 1.0.17" - gem "cuprite", "~> 0.15.0" - gem "selenium-devtools" - gem "selenium-webdriver", "~> 4.18.0" + gem 'capybara', '~> 3.40.0' + gem 'capybara_accessible_selectors', git: 'https://github.com/citizensadvice/capybara_accessible_selectors', branch: 'main' + gem 'capybara-screenshot', '~> 1.0.17' + gem 'cuprite', '~> 0.15.0' + gem 'selenium-devtools' + gem 'selenium-webdriver', '~> 4.18.0' - gem "fuubar", "~> 2.5.0" - gem "timecop", "~> 0.9.0" + gem 'fuubar', '~> 2.5.0' + gem 'timecop', '~> 0.9.0' # Record your test suite's HTTP interactions and replay them during future test runs for fast, deterministic, accurate tests. - gem "vcr" + gem 'vcr' # Mock backend requests (for ruby tests) - gem "webmock", "~> 3.12", require: false + gem 'webmock', '~> 3.12', require: false # Mock selenium requests through proxy (for feature tests) - gem "puffing-billy", "~> 4.0.0" - gem "table_print", "~> 1.5.6" + gem 'puffing-billy', '~> 4.0.0' + gem 'table_print', '~> 1.5.6' - gem "equivalent-xml", "~> 0.6" - gem "json_spec", "~> 1.1.4" - gem "shoulda-matchers", "~> 6.0", require: nil + gem 'equivalent-xml', '~> 0.6' + gem 'json_spec', '~> 1.1.4' + gem 'shoulda-matchers', '~> 6.0', require: nil - gem "parallel_tests", "~> 4.0" + gem 'parallel_tests', '~> 4.0' end group :ldap do - gem "net-ldap", "~> 0.19.0" + gem 'net-ldap', '~> 0.19.0' end group :development do - gem "listen", "~> 3.9.0" # Use for event-based reloaders + gem 'listen', '~> 3.9.0' # Use for event-based reloaders - gem "letter_opener" + gem 'letter_opener' - gem "spring" - gem "spring-commands-rspec" - gem "spring-commands-rubocop" + gem 'spring' + gem 'spring-commands-rspec' + gem 'spring-commands-rubocop' - gem "colored2" + gem 'colored2' # git hooks manager - gem "lefthook", require: false + gem 'lefthook', require: false end group :development, :test do - gem "dotenv-rails" + gem 'dotenv-rails' # Tracing and profiling gems - gem "flamegraph", require: false - gem "rack-mini-profiler", require: false - gem "ruby-prof", require: false - gem "stackprof", require: false + gem 'flamegraph', require: false + gem 'rack-mini-profiler', require: false + gem 'ruby-prof', require: false + gem 'stackprof', require: false # REPL with debug commands - gem "debug" + gem 'debug' - gem "pry-byebug", "~> 3.10.0", platforms: [:mri] - gem "pry-doc" - gem "pry-rails", "~> 0.3.6" - gem "pry-rescue", "~> 1.6.0" + gem 'pry-byebug', '~> 3.10.0', platforms: [:mri] + gem 'pry-doc' + gem 'pry-rails', '~> 0.3.6' + gem 'pry-rescue', '~> 1.6.0' # ruby linting - gem "rubocop", require: false - gem "rubocop-inflector", require: false - gem "rubocop-performance", require: false - gem "rubocop-rails", require: false - gem "rubocop-rspec", require: false + gem 'rubocop', require: false + gem 'rubocop-inflector', require: false + gem 'rubocop-performance', require: false + gem 'rubocop-rails', require: false + gem 'rubocop-rspec', require: false # erb linting - gem "erb_lint", require: false - gem "erblint-github", require: false + gem 'erb_lint', require: false + gem 'erblint-github', require: false # Brakeman scanner - gem "brakeman", "~> 6.1.0" + gem 'brakeman', '~> 6.1.0' # i18n-tasks helps find and manage missing and unused translations. - gem "i18n-tasks", "~> 1.0.13" + gem 'i18n-tasks', '~> 1.0.13' end -gem "bootsnap", "~> 1.18.0", require: false +gem 'bootsnap', '~> 1.18.0', require: false # API gems -gem "grape", "~> 2.0.0" -gem "grape_logging", "~> 1.8.4" -gem "roar", "~> 1.2.0" +gem 'grape', '~> 2.0.0' +gem 'grape_logging', '~> 1.8.4' +gem 'roar', '~> 1.2.0' # CORS for API -gem "rack-cors", "~> 2.0.2" +gem 'rack-cors', '~> 2.0.2' # Gmail API -gem "google-apis-gmail_v1", require: false -gem "googleauth", require: false +gem 'google-apis-gmail_v1', require: false +gem 'googleauth', require: false # Required for contracts -gem "disposable", "~> 0.6.2" +gem 'disposable', '~> 0.6.2' platforms :mri, :mingw, :x64_mingw do group :postgres do - gem "pg", "~> 1.5.0" + gem 'pg', '~> 1.5.0' end # Support application loading when no database exists yet. - gem "activerecord-nulldb-adapter", "~> 1.0.0" + gem 'activerecord-nulldb-adapter', '~> 1.0.0' # Have application level locks on the database to have a mutex shared between workers/hosts. # We e.g. employ this to safeguard the creation of journals. - gem "with_advisory_lock", "~> 5.1.0" + gem 'with_advisory_lock', '~> 5.1.0' end # Load Gemfile.modules explicitly to allow dependabot to work -eval_gemfile "./Gemfile.modules" +eval_gemfile './Gemfile.modules' # Load Gemfile.local, Gemfile.plugins and custom Gemfiles -gemfiles = Dir.glob File.expand_path("{Gemfile.plugins,Gemfile.local}", __dir__) -gemfiles << ENV["CUSTOM_PLUGIN_GEMFILE"] unless ENV["CUSTOM_PLUGIN_GEMFILE"].nil? +gemfiles = Dir.glob File.expand_path('{Gemfile.plugins,Gemfile.local}', __dir__) +gemfiles << ENV['CUSTOM_PLUGIN_GEMFILE'] unless ENV['CUSTOM_PLUGIN_GEMFILE'].nil? gemfiles.each do |file| # We use send to allow dependabot to function # don't use eval_gemfile(file) here as it will break dependabot! send(:eval_gemfile, file) if File.readable?(file) end -gem "openproject-octicons", "~>19.8.0" -gem "openproject-octicons_helper", "~>19.8.0" -gem "openproject-primer_view_components", "~>0.23.0" +gem 'openproject-octicons', '~>19.8.0' +gem 'openproject-octicons_helper', '~>19.8.0' +gem 'openproject-primer_view_components', '~>0.23.0' diff --git a/Gemfile.lock b/Gemfile.lock index 3e765d435607..b11656d518b2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -299,7 +299,7 @@ GEM activemodel (= 7.1.3.2) activesupport (= 7.1.3.2) timeout (>= 0.4.0) - activerecord-import (1.6.0) + activerecord-import (1.5.1) activerecord (>= 4.2) activerecord-nulldb-adapter (1.0.1) activerecord (>= 5.2.0, < 7.2) @@ -339,7 +339,7 @@ GEM airbrake-ruby (6.2.2) rbtree3 (~> 0.6) android_key_attestation (0.3.0) - appsignal (3.6.2) + appsignal (3.6.1) rack ast (2.4.2) attr_required (1.0.2) @@ -349,16 +349,16 @@ GEM activerecord (>= 4.0.0, < 7.2) awrence (1.2.1) aws-eventstream (1.3.0) - aws-partitions (1.899.0) - aws-sdk-core (3.191.4) + aws-partitions (1.895.0) + aws-sdk-core (3.191.3) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.78.0) + aws-sdk-kms (1.77.0) aws-sdk-core (~> 3, >= 3.191.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.146.0) + aws-sdk-s3 (1.143.0) aws-sdk-core (~> 3, >= 3.191.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.8) @@ -380,14 +380,14 @@ GEM thread_safe (~> 0.3, >= 0.3.1) base64 (0.2.0) bcrypt (3.1.20) - better_html (2.1.1) + better_html (2.0.2) actionview (>= 6.0) activesupport (>= 6.0) ast (~> 2.0) erubi (~> 1.4) parser (>= 2.4) smart_properties - bigdecimal (3.1.7) + bigdecimal (3.1.6) bindata (2.5.0) bootsnap (1.18.3) msgpack (~> 1.2) @@ -459,6 +459,13 @@ GEM deckar01-task_list (2.3.4) html-pipeline (~> 2.0) declarative (0.0.20) + delayed_cron_job (0.9.0) + fugit (>= 1.5) + delayed_job (4.1.11) + activesupport (>= 3.0, < 8.0) + delayed_job_active_record (4.1.8) + activerecord (>= 3.0, < 8.0) + delayed_job (>= 3.0, < 5) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) diff-lcs (1.5.1) @@ -514,11 +521,11 @@ GEM erblint-github (1.0.1) erubi (1.12.0) escape_utils (1.3.0) - et-orbi (1.2.9) + et-orbi (1.2.7) tzinfo eventmachine (1.2.7) eventmachine_httpserver (0.2.1) - excon (0.110.0) + excon (0.109.0) factory_bot (6.4.6) activesupport (>= 5.0.0) factory_bot_rails (6.4.3) @@ -538,7 +545,7 @@ GEM websocket-driver (>= 0.6, < 0.8) ffi (1.16.3) flamegraph (0.9.5) - fog-aws (3.22.0) + fog-aws (3.21.0) fog-core (~> 2.1) fog-json (~> 1.1) fog-xml (~> 0.1) @@ -557,7 +564,7 @@ GEM friendly_id (5.5.1) activerecord (>= 4.0.0) front_matter_parser (1.0.1) - fugit (1.10.1) + fugit (1.9.0) et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) fuubar (2.5.1) @@ -571,14 +578,7 @@ GEM i18n (>= 0.7) multi_json request_store (>= 1.0) - good_job (3.26.2) - activejob (>= 6.0.0) - activerecord (>= 6.0.0) - concurrent-ruby (>= 1.0.2) - fugit (>= 1.1) - railties (>= 6.0.0) - thor (>= 0.14.1) - google-apis-core (0.14.1) + google-apis-core (0.14.0) addressable (~> 2.5, >= 2.5.1) googleauth (~> 1.9) httpclient (>= 2.8.1, < 3.a) @@ -624,7 +624,7 @@ GEM httpclient (2.8.3) httpx (1.2.3) http-2-next (>= 1.0.3) - i18n (1.14.4) + i18n (1.14.1) concurrent-ruby (~> 1.0) i18n-js (4.2.3) glob (>= 0.4.0) @@ -646,7 +646,7 @@ GEM ice_nine (0.11.2) interception (0.5) io-console (0.7.2) - irb (1.12.0) + irb (1.11.2) rdoc reline (>= 0.4.2) iso8601 (0.13.0) @@ -659,11 +659,9 @@ GEM bindata faraday (~> 2.0) faraday-follow_redirects - json-schema (4.2.0) + json-schema (4.1.1) addressable (>= 2.8) - json_schemer (2.2.1) - base64 - bigdecimal + json_schemer (2.1.1) hana (~> 1.3) regexp_parser (~> 2.0) simpleidn (~> 0.2) @@ -678,7 +676,7 @@ GEM launchy (3.0.0) addressable (~> 2.8) childprocess (~> 5.0) - lefthook (1.6.7) + lefthook (1.6.5) letter_opener (1.0.0) launchy (>= 2.0.4) listen (3.9.0) @@ -696,7 +694,7 @@ GEM loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) - lookbook (2.2.2) + lookbook (2.2.1) activemodel css_parser htmlbeautifier (~> 1.3) @@ -706,7 +704,7 @@ GEM redcarpet (~> 3.5) rouge (>= 3.26, < 5.0) view_component (>= 2.0) - yard (~> 0.9) + yard (~> 0.9.25) zeitwerk (~> 2.5) mail (2.8.1) mini_mime (>= 0.1.1) @@ -722,11 +720,11 @@ GEM method_source (1.0.0) mime-types (3.5.2) mime-types-data (~> 3.2015) - mime-types-data (3.2024.0305) + mime-types-data (3.2024.0206) mini_magick (4.12.0) mini_mime (1.1.5) mini_portile2 (2.8.5) - minitest (5.22.3) + minitest (5.22.2) msgpack (1.7.2) multi_json (1.15.0) mustermann (3.0.0) @@ -747,7 +745,7 @@ GEM net-smtp (0.4.0.1) net-protocol nio4r (2.7.0) - nokogiri (1.16.3) + nokogiri (1.16.2) mini_portile2 (~> 2.8.2) racc (~> 1.4) oj (3.16.3) @@ -901,7 +899,7 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - rails-i18n (7.0.9) + rails-i18n (7.0.8) i18n (>= 0.7, < 2) railties (>= 6.0.0, < 8) railties (7.1.3.2) @@ -925,7 +923,7 @@ GEM redcarpet (3.6.0) redis (5.1.0) redis-client (>= 0.17.0) - redis-client (0.21.0) + redis-client (0.20.0) connection_pool regexp_parser (2.9.0) reline (0.4.3) @@ -945,7 +943,7 @@ GEM roar (1.2.0) representable (~> 3.1) rotp (6.3.0) - rouge (4.2.1) + rouge (4.2.0) rspec (3.13.0) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) @@ -958,18 +956,18 @@ GEM rspec-mocks (3.13.0) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.2) + rspec-rails (6.1.1) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) - rspec-core (~> 3.13) - rspec-expectations (~> 3.13) - rspec-mocks (~> 3.13) - rspec-support (~> 3.13) + rspec-core (~> 3.12) + rspec-expectations (~> 3.12) + rspec-mocks (~> 3.12) + rspec-support (~> 3.12) rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.13.1) - rubocop (1.62.1) + rubocop (1.62.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -980,7 +978,7 @@ GEM rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.2) + rubocop-ast (1.31.1) parser (>= 3.3.0.4) rubocop-capybara (2.20.0) rubocop (~> 1.41) @@ -1032,7 +1030,7 @@ GEM websocket (~> 1.0) semantic (1.6.1) shoulda-context (2.0.0) - shoulda-matchers (6.2.0) + shoulda-matchers (6.1.0) activesupport (>= 5.2.0) signet (0.19.0) addressable (~> 2.8) @@ -1075,7 +1073,7 @@ GEM table_print (1.5.7) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - test-prof (1.3.2) + test-prof (1.3.1) text-hyphen (1.5.0) thor (1.3.1) thread_safe (0.3.6) @@ -1088,7 +1086,7 @@ GEM trailblazer-option (0.1.2) ttfunk (1.8.0) bigdecimal (~> 3.1) - turbo-rails (2.0.5) + turbo-rails (2.0.4) actionpack (>= 6.0.0) activejob (>= 6.0.0) railties (>= 6.0.0) @@ -1160,7 +1158,7 @@ PLATFORMS DEPENDENCIES actionpack-xml_parser (~> 2.0.0) activemodel-serializers-xml (~> 1.0.1) - activerecord-import (~> 1.6.0) + activerecord-import (~> 1.5.0) activerecord-nulldb-adapter (~> 1.0.0) activerecord-session_store (~> 2.1.0) acts_as_list (~> 1.1.0) @@ -1197,6 +1195,8 @@ DEPENDENCIES date_validator (~> 0.12.0) debug deckar01-task_list (~> 2.3.1) + delayed_cron_job (~> 0.9.0) + delayed_job_active_record (~> 4.1.5) disposable (~> 0.6.2) doorkeeper (~> 5.6.6) dotenv-rails @@ -1214,7 +1214,6 @@ DEPENDENCIES friendly_id (~> 5.5.0) fuubar (~> 2.5.0) gon (~> 6.4.0) - good_job (= 3.26.2) google-apis-gmail_v1 googleauth grape (~> 2.0.0) @@ -1225,7 +1224,7 @@ DEPENDENCIES httpx i18n-js (~> 4.2.3) i18n-tasks (~> 1.0.13) - json_schemer (~> 2.2.0) + json_schemer (~> 2.1.0) json_spec (~> 1.1.4) ladle launchy (~> 3.0.0) diff --git a/Procfile.dev b/Procfile.dev index 26ad472210c8..60c25648b2df 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,3 +1,3 @@ web: bundle exec rails server -p 3000 -b ${HOST:="127.0.0.1"} --environment ${RAILS_ENV:="development"} angular: npm run serve -worker: bundle exec good_job start +worker: bundle exec rake jobs:work diff --git a/README.md b/README.md index cdb6ab166a74..4089849e7cb7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub release (latest by date)](https://img.shields.io/github/v/release/opf/openproject) ![GitHub commit activity](https://img.shields.io/github/commit-activity/m/opf/openproject) ![GitHub branch checks state](https://img.shields.io/github/checks-status/opf/openproject/dev) -[![Github Tests](https://github.com/opf/openproject/actions/workflows/test-core.yml/badge.svg?branch=dev)](https://github.com/opf/openproject/actions/workflows/test-core.yml) +[![GitHub Tests](https://github.com/opf/openproject/actions/workflows/test-core.yml/badge.svg?branch=dev)](https://github.com/opf/openproject/actions/workflows/test-core.yml) OpenProject is a web-based project management software. Its key features are: diff --git a/Rakefile b/Rakefile index 30e586c3e063..536d51cd911d 100755 --- a/Rakefile +++ b/Rakefile @@ -30,9 +30,9 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path("config/application", __dir__) +require File.expand_path('config/application', __dir__) Rails.application.load_rake_tasks Rake::Task[:default].clear -task default: "test:suite:run" +task default: 'test:suite:run' diff --git a/app/components/activities/days_component.rb b/app/components/activities/days_component.rb index fe76971cb6c8..27c7668f5c44 100644 --- a/app/components/activities/days_component.rb +++ b/app/components/activities/days_component.rb @@ -29,7 +29,7 @@ #++ class Activities::DaysComponent < ViewComponent::Base - def initialize(events:, current_project: nil, display_user: true, header_tag: "h3", activity_page: nil) + def initialize(events:, current_project: nil, display_user: true, header_tag: 'h3', activity_page: nil) super() @events = events @current_project = current_project diff --git a/app/components/add_button_component.rb b/app/components/add_button_component.rb index 956d16c5fec5..5f267b1ad661 100644 --- a/app/components/add_button_component.rb +++ b/app/components/add_button_component.rb @@ -33,7 +33,7 @@ class AddButtonComponent < ApplicationComponent options :current_project def render? - raise "Implement the conditions for which the component should render or not" + raise 'Implement the conditions for which the component should render or not' end def dynamic_path @@ -45,7 +45,7 @@ def id end def li_css_class - "toolbar-item" + 'toolbar-item' end def title @@ -55,7 +55,7 @@ def title def label content_tag(:span, label_text, - class: "button--text") + class: 'button--text') end def aria_label @@ -71,10 +71,10 @@ def label_text end def link_css_class - "button -primary" + 'button -alt-highlight' end def icon - helpers.op_icon("button--icon icon-add") + helpers.op_icon('button--icon icon-add') end end diff --git a/app/components/admin/quarantined_attachments/row_component.rb b/app/components/admin/quarantined_attachments/row_component.rb index 0af393a4b4d1..392929a4db1a 100644 --- a/app/components/admin/quarantined_attachments/row_component.rb +++ b/app/components/admin/quarantined_attachments/row_component.rb @@ -45,7 +45,7 @@ def row_css_id delegate :filename, to: :attachment def attached_to - description = attachment.description.present? ? "(#{attachment.description})" : "" + description = attachment.description.present? ? "(#{attachment.description})" : '' text = "#{container_name} #{attachment.container_id} #{description}" case container when Message @@ -83,9 +83,9 @@ def button_links def delete_link helpers.link_to( - helpers.op_icon("icon icon-delete"), - { controller: "/admin/attachments/quarantined_attachments", action: :destroy, id: model }, - title: I18n.t("antivirus_scan.quarantined_attachments.delete"), + helpers.op_icon('icon icon-delete'), + { controller: '/admin/attachments/quarantined_attachments', action: :destroy, id: model }, + title: I18n.t('antivirus_scan.quarantined_attachments.delete'), method: :delete, data: { confirm: I18n.t(:text_are_you_sure), disable_with: I18n.t(:label_loading) } ) diff --git a/app/components/admin/quarantined_attachments/table_component.rb b/app/components/admin/quarantined_attachments/table_component.rb index 7ea4e52020fd..f2f2d429b814 100644 --- a/app/components/admin/quarantined_attachments/table_component.rb +++ b/app/components/admin/quarantined_attachments/table_component.rb @@ -44,10 +44,10 @@ def sortable? def headers [ - ["filename", { caption: Attachment.human_attribute_name(:filename) }], - ["attached_to", { caption: I18n.t("antivirus_scan.quarantined_attachments.container") }], - ["author", { caption: Attachment.human_attribute_name(:author) }], - ["created_at", { caption: Attachment.human_attribute_name(:created_at) }] + ['filename', { caption: Attachment.human_attribute_name(:filename) }], + ['attached_to', { caption: I18n.t('antivirus_scan.quarantined_attachments.container') }], + ['author', { caption: Attachment.human_attribute_name(:author) }], + ['created_at', { caption: Attachment.human_attribute_name(:created_at) }] ] end end diff --git a/app/components/custom_actions/row_component.rb b/app/components/custom_actions/row_component.rb index a8f2f3586cec..78aae79668f9 100644 --- a/app/components/custom_actions/row_component.rb +++ b/app/components/custom_actions/row_component.rb @@ -41,7 +41,7 @@ def name delegate :description, to: :action def sort - helpers.reorder_links("custom_action", { action: "update", id: action }, method: :put) + helpers.reorder_links('custom_action', { action: 'update', id: action }, method: :put) end def button_links @@ -53,7 +53,7 @@ def button_links def edit_link link_to( - helpers.op_icon("icon icon-edit"), + helpers.op_icon('icon icon-edit'), helpers.edit_custom_action_path(action), title: t(:button_edit) ) @@ -61,7 +61,7 @@ def edit_link def delete_link link_to( - helpers.op_icon("icon icon-delete"), + helpers.op_icon('icon icon-delete'), helpers.custom_action_path(action), method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, diff --git a/app/components/custom_actions/table_component.rb b/app/components/custom_actions/table_component.rb index 0c7dfe58fd4f..5b35e3a3c40e 100644 --- a/app/components/custom_actions/table_component.rb +++ b/app/components/custom_actions/table_component.rb @@ -36,18 +36,18 @@ class TableComponent < ::TableComponent def headers [ - ["name", { caption: CustomAction.human_attribute_name(:name) }], - ["description", { caption: CustomAction.human_attribute_name(:description) }], - ["sort", { caption: I18n.t(:label_sort) }] + ['name', { caption: CustomAction.human_attribute_name(:name) }], + ['description', { caption: CustomAction.human_attribute_name(:description) }], + ['sort', { caption: I18n.t(:label_sort) }] ] end def inline_create_link link_to new_custom_action_path, - aria: { label: t("custom_actions.new") }, - class: "wp-inline-create--add-link", - title: t("custom_actions.new") do - helpers.op_icon("icon icon-add") + aria: { label: t('custom_actions.new') }, + class: 'wp-inline-create--add-link', + title: t('custom_actions.new') do + helpers.op_icon('icon icon-add') end end end diff --git a/app/components/enumerations/row_component.rb b/app/components/enumerations/row_component.rb index 9c885f3a3752..78c5597f23cc 100644 --- a/app/components/enumerations/row_component.rb +++ b/app/components/enumerations/row_component.rb @@ -51,7 +51,7 @@ def active end def sort - helpers.reorder_links("enumeration", { action: "move", id: enumeration }, method: :post) + helpers.reorder_links('enumeration', { action: 'move', id: enumeration }, method: :post) end def button_links @@ -62,7 +62,7 @@ def button_links def delete_link helpers.link_to( - helpers.op_icon("icon icon-delete"), + helpers.op_icon('icon icon-delete'), helpers.enumeration_path(enumeration), method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, diff --git a/app/components/enumerations/table_component.rb b/app/components/enumerations/table_component.rb index bba8eff05e1e..08b5c1a4286c 100644 --- a/app/components/enumerations/table_component.rb +++ b/app/components/enumerations/table_component.rb @@ -44,13 +44,13 @@ def sortable? def headers [ - ["name", { caption: Enumeration.human_attribute_name(:name) }], - ["is_default", { caption: Enumeration.human_attribute_name(:is_default) }], - ["active", { caption: Enumeration.human_attribute_name(:active) }], - ["sort", { caption: I18n.t(:label_sort) }] + ['name', { caption: Enumeration.human_attribute_name(:name) }], + ['is_default', { caption: Enumeration.human_attribute_name(:is_default) }], + ['active', { caption: Enumeration.human_attribute_name(:active) }], + ['sort', { caption: I18n.t(:label_sort) }] ].tap do |default| if with_colors - default.insert 3, ["color", { caption: Enumeration.human_attribute_name(:color) }] + default.insert 3, ['color', { caption: Enumeration.human_attribute_name(:color) }] end end end @@ -62,10 +62,10 @@ def with_colors def inline_create_link link_to new_enumeration_path(type: rows.name), aria: { label: t(:label_enumeration_new) }, - class: "wp-inline-create--add-link", - data: { "test-selector": "create-enumeration-#{rows.name.underscore.dasherize}" }, + class: 'wp-inline-create--add-link', + data: { 'test-selector': "create-enumeration-#{rows.name.underscore.dasherize}" }, title: t(:label_enumeration_new) do - helpers.op_icon("icon icon-add") + helpers.op_icon('icon icon-add') end end end diff --git a/app/components/filters_component.html.erb b/app/components/filters_component.html.erb index f17e15685497..0fab3fba3f19 100644 --- a/app/components/filters_component.html.erb +++ b/app/components/filters_component.html.erb @@ -123,7 +123,7 @@
  • - <%= submit_tag t('button_apply'), class: 'button -small -primary', name: nil %> + <%= submit_tag t('button_apply'), class: 'button -small -highlight', name: nil %>
  • <% unless EnterpriseToken.allows_to?(:custom_fields_in_projects_list)%> diff --git a/app/components/individual_principal_base_filter_component.html.erb b/app/components/individual_principal_base_filter_component.html.erb index 265c4a8ad61a..588b7e913c94 100644 --- a/app/components/individual_principal_base_filter_component.html.erb +++ b/app/components/individual_principal_base_filter_component.html.erb @@ -105,7 +105,7 @@ See COPYRIGHT and LICENSE files for more details. <%= text_field_tag 'name', params[:name], class: 'simple-filters--filter-value' %>
  • - <%= submit_tag t(:button_apply), class: 'button -primary -small', name: nil %> + <%= submit_tag t(:button_apply), class: 'button -highlight -small', name: nil %> <%= link_to t(:button_clear), clear_url, class: 'button -small -with-icon icon-undo' %>
  • diff --git a/app/components/individual_principal_base_filter_component.rb b/app/components/individual_principal_base_filter_component.rb index b82f9f6bd263..1bff0229a696 100644 --- a/app/components/individual_principal_base_filter_component.rb +++ b/app/components/individual_principal_base_filter_component.rb @@ -52,25 +52,25 @@ def filtered?(params) def filter_name(query, name) if name.present? - query.where(:any_name_attribute, "~", name) + query.where(:any_name_attribute, '~', name) end end def filter_group(query, group_id) if group_id.present? - query.where(:group, "=", group_id) + query.where(:group, '=', group_id) end end def filter_role(query, role_id) if role_id.present? - query.where(:role_id, "=", role_id) + query.where(:role_id, '=', role_id) end end def filter_project(query, project_id) if project_id.present? - query.where(:project_id, "=", project_id) + query.where(:project_id, '=', project_id) end end diff --git a/app/components/ldap_auth_sources/row_component.rb b/app/components/ldap_auth_sources/row_component.rb index 975c87e46252..2e8a9a8ccdf2 100644 --- a/app/components/ldap_auth_sources/row_component.rb +++ b/app/components/ldap_auth_sources/row_component.rb @@ -33,7 +33,7 @@ class RowComponent < ::RowComponent def name content = link_to model.name, edit_ldap_auth_source_path(model) if model.seeded_from_env? - content += helpers.op_icon("icon icon-info2", title: I18n.t(:label_seeded_from_env_warning)) + content += helpers.op_icon('icon icon-info2', title: I18n.t(:label_seeded_from_env_warning)) end content @@ -54,17 +54,17 @@ def button_links end def test_link - link_to t(:button_test), { controller: "ldap_auth_sources", action: "test_connection", id: model } + link_to t(:button_test), { controller: 'ldap_auth_sources', action: 'test_connection', id: model } end def delete_link return if users > 0 link_to I18n.t(:button_delete), - { controller: "ldap_auth_sources", id: model.id, action: :destroy }, + { controller: 'ldap_auth_sources', id: model.id, action: :destroy }, method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, - class: "icon icon-delete", + class: 'icon icon-delete', title: I18n.t(:button_delete) end end diff --git a/app/components/ldap_auth_sources/table_component.rb b/app/components/ldap_auth_sources/table_component.rb index ffbf507c6b39..f4735796b600 100644 --- a/app/components/ldap_auth_sources/table_component.rb +++ b/app/components/ldap_auth_sources/table_component.rb @@ -46,17 +46,17 @@ def sortable_column?(_column) def inline_create_link link_to(new_ldap_auth_source_path, - class: "budget-add-row wp-inline-create--add-link", + class: 'budget-add-row wp-inline-create--add-link', title: I18n.t(:label_ldap_auth_source_new)) do - helpers.op_icon("icon icon-add") + helpers.op_icon('icon icon-add') end end def headers [ - ["name", { caption: LdapAuthSource.human_attribute_name("name") }], - ["host", { caption: LdapAuthSource.human_attribute_name("host") }], - ["users", { caption: I18n.t(:label_user_plural) }] + ['name', { caption: LdapAuthSource.human_attribute_name('name') }], + ['host', { caption: LdapAuthSource.human_attribute_name('host') }], + ['users', { caption: I18n.t(:label_user_plural) }] ] end end diff --git a/app/components/members/index_page_header_component.rb b/app/components/members/index_page_header_component.rb index 485aa1e1b6a4..689eb40daab8 100644 --- a/app/components/members/index_page_header_component.rb +++ b/app/components/members/index_page_header_component.rb @@ -41,20 +41,20 @@ def initialize(project: nil) def add_button_data_attributes attributes = { - "members-form-target": "addMemberButton", - action: "members-form#showAddMemberForm", - "test-selector": "member-add-button" + 'members-form-target': 'addMemberButton', + action: 'members-form#showAddMemberForm', + 'test-selector': 'member-add-button' } - attributes["trigger-initially"] = "true" if params[:show_add_members] + attributes['trigger-initially'] = "true" if params[:show_add_members] attributes end def filter_button_data_attributes { - "members-form-target": "filterMemberButton", - action: "members-form#toggleMemberFilter" + 'members-form-target': 'filterMemberButton', + action: 'members-form#toggleMemberFilter' } end end diff --git a/app/components/members/role_form_component.html.erb b/app/components/members/role_form_component.html.erb index f07b488ed48c..45d06ed41219 100644 --- a/app/components/members/role_form_component.html.erb +++ b/app/components/members/role_form_component.html.erb @@ -48,7 +48,7 @@ See COPYRIGHT and LICENSE files for more details.

    - <%= f.submit t(:button_change), class: "button -primary -small" %> + <%= f.submit t(:button_change), class: "button -highlight -small" %> <%= link_to t(:button_cancel), '#', data: { diff --git a/app/components/members/role_form_component.rb b/app/components/members/role_form_component.rb index c207c31c03df..47eca2ba63d5 100644 --- a/app/components/members/role_form_component.rb +++ b/app/components/members/role_form_component.rb @@ -41,7 +41,7 @@ def form_html_options id: "#{row.roles_css_id}-form", class: row.toggle_item_class_name, style: "display:none", - data: { "members-form-target": "membershipEditForm" } + data: { 'members-form-target': 'membershipEditForm' } } end diff --git a/app/components/members/user_filter_component.rb b/app/components/members/user_filter_component.rb index e128e44d99a7..3dc96333fc07 100644 --- a/app/components/members/user_filter_component.rb +++ b/app/components/members/user_filter_component.rb @@ -30,7 +30,7 @@ module Members class UserFilterComponent < ::UserFilterComponent - ALL_SHARED_FILTER_KEY = "all" + ALL_SHARED_FILTER_KEY = 'all' def initially_visible? false @@ -52,12 +52,12 @@ def shares # Adapts the user filter counts to count members as opposed to users. def extra_user_status_options { - all: status_members_query("all").count, - blocked: status_members_query("blocked").count, - active: status_members_query("active").count, - invited: status_members_query("invited").count, - registered: status_members_query("registered").count, - locked: status_members_query("locked").count + all: status_members_query('all').count, + blocked: status_members_query('blocked').count, + active: status_members_query('active').count, + invited: status_members_query('invited').count, + registered: status_members_query('registered').count, + locked: status_members_query('locked').count } end @@ -89,7 +89,7 @@ def share_options .order(builtin: :asc) .map { |role| [mapped_shared_role_name(role), role.id] } - share_options.unshift([I18n.t("members.filters.all_shares"), ALL_SHARED_FILTER_KEY]) + share_options.unshift([I18n.t('members.filters.all_shares'), ALL_SHARED_FILTER_KEY]) end def builtin_share_roles @@ -103,11 +103,11 @@ def builtin_share_roles def mapped_shared_role_name(role) case role.builtin when Role::BUILTIN_WORK_PACKAGE_VIEWER - I18n.t("work_package.sharing.permissions.view") + I18n.t('work_package.sharing.permissions.view') when Role::BUILTIN_WORK_PACKAGE_COMMENTER - I18n.t("work_package.sharing.permissions.comment") + I18n.t('work_package.sharing.permissions.comment') when Role::BUILTIN_WORK_PACKAGE_EDITOR - I18n.t("work_package.sharing.permissions.edit") + I18n.t('work_package.sharing.permissions.edit') else role.name end @@ -121,9 +121,9 @@ def filter_shares(query, role_id) .where(builtin: builtin_share_roles) .pluck(:id) - query.where(:role_id, "=", ids.uniq) + query.where(:role_id, '=', ids.uniq) elsif role_id.to_i > 0 - query.where(:role_id, "=", role_id.to_i) + query.where(:role_id, '=', role_id.to_i) end end diff --git a/app/components/oauth/applications/row_component.rb b/app/components/oauth/applications/row_component.rb index 70b598eac265..33bfc1e631db 100644 --- a/app/components/oauth/applications/row_component.rb +++ b/app/components/oauth/applications/row_component.rb @@ -47,20 +47,20 @@ def owner def confidential if application.confidential? - helpers.op_icon "icon icon-checkmark" + helpers.op_icon 'icon icon-checkmark' end end def redirect_uri urls = application.redirect_uri.split("\n") - safe_join urls, "
    ".html_safe + safe_join urls, '
    '.html_safe end def client_credentials if user_id = application.client_credentials_user_id helpers.link_to_user User.find(user_id) else - "-" + '-' end end diff --git a/app/components/oauth/applications/table_component.rb b/app/components/oauth/applications/table_component.rb index 144742596aa5..86b0cd15f099 100644 --- a/app/components/oauth/applications/table_component.rb +++ b/app/components/oauth/applications/table_component.rb @@ -51,10 +51,10 @@ def columns def inline_create_link link_to new_oauth_application_path, - aria: { label: t("oauth.application.new") }, - class: "wp-inline-create--add-link", - title: t("oauth.application.new") do - helpers.op_icon("icon icon-add") + aria: { label: t('oauth.application.new') }, + class: 'wp-inline-create--add-link', + title: t('oauth.application.new') do + helpers.op_icon('icon icon-add') end end @@ -64,11 +64,11 @@ def empty_row_message def headers [ - ["name", { caption: ::Doorkeeper::Application.human_attribute_name(:name) }], - ["owner", { caption: ::Doorkeeper::Application.human_attribute_name(:owner) }], - ["client_credentials", { caption: I18n.t("oauth.client_credentials") }], - ["redirect_uri", { caption: ::Doorkeeper::Application.human_attribute_name(:redirect_uri) }], - ["confidential", { caption: ::Doorkeeper::Application.human_attribute_name(:confidential) }] + ['name', { caption: ::Doorkeeper::Application.human_attribute_name(:name) }], + ['owner', { caption: ::Doorkeeper::Application.human_attribute_name(:owner) }], + ['client_credentials', { caption: I18n.t('oauth.client_credentials') }], + ['redirect_uri', { caption: ::Doorkeeper::Application.human_attribute_name(:redirect_uri) }], + ['confidential', { caption: ::Doorkeeper::Application.human_attribute_name(:confidential) }] ] end end diff --git a/app/components/open_project/common/duration_component.rb b/app/components/open_project/common/duration_component.rb index 70639b9dd3a5..f5dd5c34de0e 100644 --- a/app/components/open_project/common/duration_component.rb +++ b/app/components/open_project/common/duration_component.rb @@ -32,7 +32,7 @@ class DurationComponent < Primer::Component VALID_TYPES = %i[seconds minutes hours days weeks months years].freeze attr_reader :duration, :abbreviated, :separator - def initialize(duration, type = :seconds, separator: ", ", abbreviated: false, **args) + def initialize(duration, type = :seconds, separator: ', ', abbreviated: false, **args) super @duration = parse_duration(duration, type) diff --git a/app/components/placeholder_users/placeholder_user_filter_component.rb b/app/components/placeholder_users/placeholder_user_filter_component.rb index a9d999197f90..989b3991a4a0 100644 --- a/app/components/placeholder_users/placeholder_user_filter_component.rb +++ b/app/components/placeholder_users/placeholder_user_filter_component.rb @@ -40,7 +40,7 @@ def apply_filters(params, query) # Filter for active placeholders # to skip to-be-deleted users - query.where(:status, "=", :active) + query.where(:status, '=', :active) end end diff --git a/app/components/placeholder_users/row_component.rb b/app/components/placeholder_users/row_component.rb index e419ddeb4351..3f439b37fb7d 100644 --- a/app/components/placeholder_users/row_component.rb +++ b/app/components/placeholder_users/row_component.rb @@ -47,10 +47,10 @@ def button_links def delete_link if helpers.can_delete_placeholder_user?(placeholder_user, User.current) link_to deletion_info_placeholder_user_path(placeholder_user) do - helpers.tooltip_tag I18n.t("placeholder_users.delete_tooltip"), icon: "icon-delete" + helpers.tooltip_tag I18n.t('placeholder_users.delete_tooltip'), icon: 'icon-delete' end else - helpers.tooltip_tag I18n.t("placeholder_users.right_to_manage_members_missing"), icon: "icon-help2" + helpers.tooltip_tag I18n.t('placeholder_users.right_to_manage_members_missing'), icon: 'icon-help2' end end diff --git a/app/components/placeholder_users/table_component.rb b/app/components/placeholder_users/table_component.rb index cebf3a43a88a..99cd383d0485 100644 --- a/app/components/placeholder_users/table_component.rb +++ b/app/components/placeholder_users/table_component.rb @@ -43,7 +43,7 @@ def headers def header_options(name) options = { caption: PlaceholderUser.human_attribute_name(name) } - options[:default_order] = "desc" if desc_by_default.include? name + options[:default_order] = 'desc' if desc_by_default.include? name options end diff --git a/app/components/projects/configure_view_modal_component.rb b/app/components/projects/configure_view_modal_component.rb index 5d1f93d83aae..173b3bfeaf12 100644 --- a/app/components/projects/configure_view_modal_component.rb +++ b/app/components/projects/configure_view_modal_component.rb @@ -29,9 +29,9 @@ # ++ class Projects::ConfigureViewModalComponent < ApplicationComponent - MODAL_ID = "op-project-list-configure-dialog" - COLUMN_FORM_ID = "op-project-list-configure-columns-form" - COLUMN_HTML_NAME = "columns" + MODAL_ID = 'op-project-list-configure-dialog' + COLUMN_FORM_ID = 'op-project-list-configure-columns-form' + COLUMN_HTML_NAME = 'columns' options :query diff --git a/app/components/projects/delete_list_modal_component.rb b/app/components/projects/delete_list_modal_component.rb index d8ba7523c3a0..70f8c39fdad7 100644 --- a/app/components/projects/delete_list_modal_component.rb +++ b/app/components/projects/delete_list_modal_component.rb @@ -29,7 +29,7 @@ # ++ class Projects::DeleteListModalComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent - MODAL_ID = "op-project-list-delete-dialog" + MODAL_ID = 'op-project-list-delete-dialog' options :query end diff --git a/app/components/projects/export_list_modal_component.rb b/app/components/projects/export_list_modal_component.rb index e540403fbd98..601cc29649a5 100644 --- a/app/components/projects/export_list_modal_component.rb +++ b/app/components/projects/export_list_modal_component.rb @@ -29,7 +29,7 @@ # ++ class Projects::ExportListModalComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent - MODAL_ID = "op-project-list-export-dialog" + MODAL_ID = 'op-project-list-export-dialog' options :query end diff --git a/app/components/projects/row_component.rb b/app/components/projects/row_component.rb index 62e6d88d4890..e6fb6f526ce2 100644 --- a/app/components/projects/row_component.rb +++ b/app/components/projects/row_component.rb @@ -39,7 +39,7 @@ def level # Hierarchy cell is just a placeholder def hierarchy - "" + '' end def column_value(column) @@ -56,10 +56,10 @@ def custom_field_column(column) cf = column.custom_field custom_value = project.formatted_custom_value_for(cf) - if cf.field_format == "text" && custom_value.present? + if cf.field_format == 'text' && custom_value.present? render OpenProject::Common::AttributeComponent.new("dialog-#{project.id}-cf-#{cf.id}", cf.name, custom_value.html_safe) # rubocop:disable Rails/OutputSafety elsif custom_value.is_a?(Array) - safe_join(Array(custom_value).compact_blank, ", ") + safe_join(Array(custom_value).compact_blank, ', ') else custom_value end @@ -74,20 +74,20 @@ def latest_activity_at end def required_disk_space - return "" unless project.required_disk_space.to_i > 0 + return '' unless project.required_disk_space.to_i > 0 number_to_human_size(project.required_disk_space, precision: 2) end def name - content = content_tag(:i, "", class: "projects-table--hierarchy-icon") + content = content_tag(:i, '', class: "projects-table--hierarchy-icon") if project.archived? - content << " " - content << content_tag(:span, I18n.t("project.archive.archived"), class: "archived-label") + content << ' ' + content << content_tag(:span, I18n.t('project.archive.archived'), class: 'archived-label') end - content << " " + content << ' ' content << helpers.link_to_project(project, {}, {}, false) content end @@ -95,13 +95,13 @@ def name def project_status return nil unless user_can_view_project? - content = "".html_safe + content = ''.html_safe status_code = project.status_code if status_code classes = helpers.project_status_css_class(status_code) - content << content_tag(:span, "", class: "project-status--bulb -inline #{classes}") + content << content_tag(:span, '', class: "project-status--bulb -inline #{classes}") content << content_tag(:span, helpers.project_status_name(status_code), class: "project-status--name #{classes}") end @@ -113,7 +113,7 @@ def status_explanation if project.status_explanation.present? && project.status_explanation render OpenProject::Common::AttributeComponent.new("dialog-#{project.id}-status-explanation", - I18n.t("activerecord.attributes.project.status_explanation"), + I18n.t('activerecord.attributes.project.status_explanation'), project.status_explanation) end end @@ -123,7 +123,7 @@ def description if project.description.present? render OpenProject::Common::AttributeComponent.new("dialog-#{project.id}-description", - I18n.t("activerecord.attributes.project.description"), + I18n.t('activerecord.attributes.project.description'), project.description) end end @@ -149,11 +149,11 @@ def row_css_level_classes end def project_css_classes - s = " project ".html_safe + s = ' project '.html_safe - s << " root" if project.root? - s << " child" if project.child? - s << (project.leaf? ? " leaf" : " parent") + s << ' root' if project.root? + s << ' child' if project.child? + s << (project.leaf? ? ' leaf' : ' parent') s end @@ -169,7 +169,7 @@ def additional_css_class(column) "project-long-text-container" elsif custom_field_column?(column) cf = column.custom_field - formattable = cf.field_format == "text" ? " project-long-text-container" : "" + formattable = cf.field_format == 'text' ? ' project-long-text-container' : '' "format-#{cf.field_format}#{formattable}" end end @@ -188,17 +188,17 @@ def more_menu_subproject_item if User.current.allowed_in_project?(:add_subprojects, project) [t(:label_subproject_new), new_project_path(parent_id: project.id), - { class: "icon-context icon-add", + { class: 'icon-context icon-add', title: t(:label_subproject_new) }] end end def more_menu_settings_item - if User.current.allowed_in_project?({ controller: "/projects/settings/general", action: "show", project_id: project.id }, + if User.current.allowed_in_project?({ controller: '/projects/settings/general', action: 'show', project_id: project.id }, project) [t(:label_project_settings), project_settings_general_path(project), - { class: "icon-context icon-settings", + { class: 'icon-context icon-settings', title: t(:label_project_settings) }] end end @@ -207,8 +207,8 @@ def more_menu_activity_item if User.current.allowed_in_project?(:view_project_activity, project) [ t(:label_project_activity), - project_activity_index_path(project, event_types: ["project_attributes"]), - { class: "icon-context icon-checkmark", + project_activity_index_path(project, event_types: ['project_attributes']), + { class: 'icon-context icon-checkmark', title: t(:label_project_activity) } ] end @@ -218,9 +218,9 @@ def more_menu_archive_item if User.current.allowed_in_project?(:archive_project, project) && project.active? [t(:button_archive), project_archive_path(project, status: params[:status]), - { data: { confirm: t("project.archive.are_you_sure", name: project.name) }, + { data: { confirm: t('project.archive.are_you_sure', name: project.name) }, method: :post, - class: "icon-context icon-locked", + class: 'icon-context icon-locked', title: t(:button_archive) }] end end @@ -230,7 +230,7 @@ def more_menu_unarchive_item [t(:button_unarchive), project_archive_path(project, status: params[:status]), { method: :delete, - class: "icon-context icon-unlocked", + class: 'icon-context icon-unlocked', title: t(:button_unarchive) }] end end @@ -239,7 +239,7 @@ def more_menu_copy_item if User.current.allowed_in_project?(:copy_projects, project) && !project.archived? [t(:button_copy), copy_project_path(project), - { class: "icon-context icon-copy", + { class: 'icon-context icon-copy', title: t(:button_copy) }] end end @@ -248,7 +248,7 @@ def more_menu_delete_item if User.current.admin [t(:button_delete), confirm_destroy_project_path(project), - { class: "icon-context icon-delete", + { class: 'icon-context icon-delete', title: t(:button_delete) }] end end diff --git a/app/components/projects/table_component.rb b/app/components/projects/table_component.rb index 4183827f40f7..2033139373d2 100644 --- a/app/components/projects/table_component.rb +++ b/app/components/projects/table_component.rb @@ -48,7 +48,7 @@ def initial_sort end def table_id - "project-table" + 'project-table' end ## @@ -80,13 +80,13 @@ def paginated? def deactivate_class_on_lft_sort if sorted_by_lft? - "spot-link_inactive" + 'spot-link_inactive' end end def href_only_when_not_sort_lft unless sorted_by_lft? - projects_path(sortBy: JSON::dump([["lft", "asc"]])) + projects_path(sortBy: JSON::dump([['lft', 'asc']])) end end @@ -96,9 +96,9 @@ def order_options(select) data: { controller: "params-from-query", - "application-target": "dynamic", - "params-from-query-allowed-value": '["query_id"]', - "params-from-query-all-anchors-value": "true" + 'application-target': "dynamic", + 'params-from-query-allowed-value': '["query_id"]', + 'params-from-query-all-anchors-value': "true" } } end diff --git a/app/components/row_component.rb b/app/components/row_component.rb index 7ed07b4e4af7..640a26176676 100644 --- a/app/components/row_component.rb +++ b/app/components/row_component.rb @@ -70,7 +70,7 @@ def row_css_class def checkmark(condition) if condition - helpers.op_icon "icon icon-checkmark" + helpers.op_icon 'icon icon-checkmark' end end end diff --git a/app/components/settings/time_zone_setting_component.rb b/app/components/settings/time_zone_setting_component.rb index 7cb43e8120de..84b2f964c1b7 100644 --- a/app/components/settings/time_zone_setting_component.rb +++ b/app/components/settings/time_zone_setting_component.rb @@ -79,7 +79,7 @@ def time_zone_entries private def time_zone_option(canonical_zone, zones) - zone_names = zones.map(&:name).join(", ") + zone_names = zones.map(&:name).join(', ') [ "(UTC#{ActiveSupport::TimeZone.seconds_to_utc_offset(canonical_zone.base_utc_offset)}) #{zone_names}", canonical_zone.identifier diff --git a/app/components/statuses/row_component.rb b/app/components/statuses/row_component.rb index 8c2f1d8d6b6c..27c24d9b14b2 100644 --- a/app/components/statuses/row_component.rb +++ b/app/components/statuses/row_component.rb @@ -59,8 +59,8 @@ def done_ratio end def sort - helpers.reorder_links "status", - { action: "update", id: status }, + helpers.reorder_links 'status', + { action: 'update', id: status }, method: :patch end @@ -72,7 +72,7 @@ def button_links def delete_link link_to( - helpers.op_icon("icon icon-delete"), + helpers.op_icon('icon icon-delete'), status_path(status), method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, diff --git a/app/components/statuses/table_component.rb b/app/components/statuses/table_component.rb index 9bfbaab1d108..e7792d44ae5b 100644 --- a/app/components/statuses/table_component.rb +++ b/app/components/statuses/table_component.rb @@ -45,9 +45,9 @@ def columns def inline_create_link link_to new_status_path, aria: { label: t(:label_work_package_status_new) }, - class: "wp-inline-create--add-link", + class: 'wp-inline-create--add-link', title: t(:label_work_package_status_new) do - helpers.op_icon("icon icon-add") + helpers.op_icon('icon icon-add') end end diff --git a/app/components/table_component.rb b/app/components/table_component.rb index c1c85c05fcc4..26a88eaa6784 100644 --- a/app/components/table_component.rb +++ b/app/components/table_component.rb @@ -174,7 +174,7 @@ def initial_sort end def initial_order - initial_sort_correlation.join(" ") + initial_sort_correlation.join(' ') end def paginated? diff --git a/app/components/user_filter_component.rb b/app/components/user_filter_component.rb index 9cd43c565989..c70909092459 100644 --- a/app/components/user_filter_component.rb +++ b/app/components/user_filter_component.rb @@ -35,20 +35,20 @@ class << self # or the default status to be filtered by (all) # if no status is given. def status_param(params) - params[:status].presence || "all" + params[:status].presence || 'all' end def filter_status(query, status) - return unless status && status != "all" + return unless status && status != 'all' case status - when "blocked" - query.where(:blocked, "=", :blocked) - when "active" - query.where(:status, "=", status.to_sym) - query.where(:blocked, "!", :blocked) + when 'blocked' + query.where(:blocked, '=', :blocked) + when 'active' + query.where(:status, '=', status.to_sym) + query.where(:blocked, '!', :blocked) else - query.where(:status, "=", status.to_sym) + query.where(:status, '=', status.to_sym) end end diff --git a/app/components/users/auto_login_tokens/row_component.rb b/app/components/users/auto_login_tokens/row_component.rb index 640415c2af8f..784205909c99 100644 --- a/app/components/users/auto_login_tokens/row_component.rb +++ b/app/components/users/auto_login_tokens/row_component.rb @@ -45,22 +45,22 @@ def current? def is_current # rubocop:disable Naming/PredicateName if current? - helpers.op_icon "icon-yes" + helpers.op_icon 'icon-yes' end end def device - token_data[:platform] || I18n.t("users.sessions.unknown_os") + token_data[:platform] || I18n.t('users.sessions.unknown_os') end def browser - name = token_data[:browser] || "unknown browser" + name = token_data[:browser] || 'unknown browser' version = token_data[:browser_version] "#{name} #{version ? "(Version #{version})" : ''}" end def platform - token_data[:platform] || "unknown platform" + token_data[:platform] || 'unknown platform' end def expires_on @@ -76,9 +76,9 @@ def delete_link return if current? link_to( - helpers.op_icon("icon icon-delete"), - { controller: "/my/auto_login_tokens", action: "destroy", id: token.id }, - class: "button--link", + helpers.op_icon('icon icon-delete'), + { controller: '/my/auto_login_tokens', action: 'destroy', id: token.id }, + class: 'button--link', role: :button, method: :delete, data: { confirm: I18n.t(:text_are_you_sure), disable_with: I18n.t(:label_loading) }, diff --git a/app/components/users/auto_login_tokens/table_component.rb b/app/components/users/auto_login_tokens/table_component.rb index eda17cd9ea12..a73c1a959857 100644 --- a/app/components/users/auto_login_tokens/table_component.rb +++ b/app/components/users/auto_login_tokens/table_component.rb @@ -41,10 +41,10 @@ def sortable? def headers [ - [:is_current, { caption: I18n.t("users.sessions.current") }], - [:browser, { caption: I18n.t("users.sessions.browser") }], - [:device, { caption: I18n.t("users.sessions.device") }], - [:expires_on, { caption: I18n.t("attributes.expires_at") }] + [:is_current, { caption: I18n.t('users.sessions.current') }], + [:browser, { caption: I18n.t('users.sessions.browser') }], + [:device, { caption: I18n.t('users.sessions.device') }], + [:expires_on, { caption: I18n.t('attributes.expires_at') }] ] end end diff --git a/app/components/users/avatar_component.rb b/app/components/users/avatar_component.rb index df53c25f2394..a95a5f0c3683 100644 --- a/app/components/users/avatar_component.rb +++ b/app/components/users/avatar_component.rb @@ -32,7 +32,7 @@ class AvatarComponent < ApplicationComponent include AvatarHelper include OpPrimer::ComponentHelpers - def initialize(user:, show_name: true, link: true, size: "default", classes: "", title: nil, name_classes: "") + def initialize(user:, show_name: true, link: true, size: 'default', classes: '', title: nil, name_classes: '') super @user = user diff --git a/app/components/users/sessions/row_component.rb b/app/components/users/sessions/row_component.rb index 6888306c7a76..3410ffcda4c2 100644 --- a/app/components/users/sessions/row_component.rb +++ b/app/components/users/sessions/row_component.rb @@ -48,27 +48,27 @@ def current? def is_current # rubocop:disable Naming/PredicateName if current? - helpers.op_icon "icon-yes" + helpers.op_icon 'icon-yes' end end def device - session_data[:platform] || I18n.t("users.sessions.unknown_os") + session_data[:platform] || I18n.t('users.sessions.unknown_os') end def browser - name = session_data[:browser] || "unknown browser" + name = session_data[:browser] || 'unknown browser' version = session_data[:browser_version] "#{name} #{version ? "(Version #{version})" : ''}" end def platform - session_data[:platform] || "unknown platform" + session_data[:platform] || 'unknown platform' end def updated_at if current? - I18n.t("users.sessions.current") + I18n.t('users.sessions.current') else helpers.format_time session.updated_at end @@ -82,9 +82,9 @@ def delete_link return if current? link_to( - helpers.op_icon("icon icon-delete"), - { controller: "/my/sessions", action: "destroy", id: session }, - class: "button--link", + helpers.op_icon('icon icon-delete'), + { controller: '/my/sessions', action: 'destroy', id: session }, + class: 'button--link', role: :button, method: :delete, data: { confirm: I18n.t(:text_are_you_sure), disable_with: I18n.t(:label_loading) }, diff --git a/app/components/users/sessions/table_component.rb b/app/components/users/sessions/table_component.rb index 0abc12875df7..8cff7a6775c2 100644 --- a/app/components/users/sessions/table_component.rb +++ b/app/components/users/sessions/table_component.rb @@ -41,10 +41,10 @@ def initial_sort def headers [ - [:is_current, { caption: I18n.t("users.sessions.current") }], - [:browser, { caption: I18n.t("users.sessions.browser") }], - [:device, { caption: I18n.t("users.sessions.device") }], - [:updated_at, { caption: I18n.t("attributes.updated_at") }] + [:is_current, { caption: I18n.t('users.sessions.current') }], + [:browser, { caption: I18n.t('users.sessions.browser') }], + [:device, { caption: I18n.t('users.sessions.device') }], + [:updated_at, { caption: I18n.t('attributes.updated_at') }] ] end end diff --git a/app/components/users/table_component.rb b/app/components/users/table_component.rb index cd159c89dd0d..b7f2eea504b3 100644 --- a/app/components/users/table_component.rb +++ b/app/components/users/table_component.rb @@ -46,7 +46,7 @@ def headers def header_options(name) options = { caption: User.human_attribute_name(name) } - options[:default_order] = "desc" if desc_by_default.include? name + options[:default_order] = 'desc' if desc_by_default.include? name options end diff --git a/app/components/versions/row_component.rb b/app/components/versions/row_component.rb index d1fb386ecca8..0bddbf1bc6cb 100644 --- a/app/components/versions/row_component.rb +++ b/app/components/versions/row_component.rb @@ -75,11 +75,11 @@ def sharing end def wiki_page - return "" if wiki_page_title.blank? || version.project.wiki.nil? + return '' if wiki_page_title.blank? || version.project.wiki.nil? helpers.link_to_if_authorized(wiki_page_title, - controller: "/wiki", - action: "show", + controller: '/wiki', + action: 'show', project_id: version.project, id: wiki_page_title) || h(wiki_page_title) end @@ -97,20 +97,20 @@ def wiki_page_title def edit_link return unless version.project == table.project - helpers.link_to_if_authorized "", - { controller: "/versions", action: "edit", id: version }, - class: "icon icon-edit", + helpers.link_to_if_authorized '', + { controller: '/versions', action: 'edit', id: version }, + class: 'icon icon-edit', title: t(:button_edit) end def delete_link return unless version.project == table.project - helpers.link_to_if_authorized "", - { controller: "/versions", action: "destroy", id: version }, + helpers.link_to_if_authorized '', + { controller: '/versions', action: 'destroy', id: version }, data: { confirm: t(:text_are_you_sure) }, method: :delete, - class: "icon icon-delete", + class: 'icon icon-delete', title: t(:button_delete) end diff --git a/app/components/versions/table_component.rb b/app/components/versions/table_component.rb index bede23fbfdcc..eebc3e41af4f 100644 --- a/app/components/versions/table_component.rb +++ b/app/components/versions/table_component.rb @@ -49,7 +49,7 @@ def header_options(name) end def wiki_page_header_options - ["wiki_page_title", { caption: WikiPage.model_name.human }] + ['wiki_page_title', { caption: WikiPage.model_name.human }] end end end diff --git a/app/components/work_packages/share/concerns/displayable_roles.rb b/app/components/work_packages/share/concerns/displayable_roles.rb index ff0faa338347..d02b55255c6d 100644 --- a/app/components/work_packages/share/concerns/displayable_roles.rb +++ b/app/components/work_packages/share/concerns/displayable_roles.rb @@ -34,15 +34,15 @@ module Concerns module DisplayableRoles def options [ - { label: I18n.t("work_package.sharing.permissions.edit"), + { label: I18n.t('work_package.sharing.permissions.edit'), value: Role::BUILTIN_WORK_PACKAGE_EDITOR, - description: I18n.t("work_package.sharing.permissions.edit_description") }, - { label: I18n.t("work_package.sharing.permissions.comment"), + description: I18n.t('work_package.sharing.permissions.edit_description') }, + { label: I18n.t('work_package.sharing.permissions.comment'), value: Role::BUILTIN_WORK_PACKAGE_COMMENTER, - description: I18n.t("work_package.sharing.permissions.comment_description") }, - { label: I18n.t("work_package.sharing.permissions.view"), + description: I18n.t('work_package.sharing.permissions.comment_description') }, + { label: I18n.t('work_package.sharing.permissions.view'), value: Role::BUILTIN_WORK_PACKAGE_VIEWER, - description: I18n.t("work_package.sharing.permissions.view_description") } + description: I18n.t('work_package.sharing.permissions.view_description') } ] end end diff --git a/app/components/work_packages/share/modal_body_component.rb b/app/components/work_packages/share/modal_body_component.rb index e8a3c661d94a..2d80e91e9c10 100644 --- a/app/components/work_packages/share/modal_body_component.rb +++ b/app/components/work_packages/share/modal_body_component.rb @@ -55,39 +55,39 @@ def insert_target_modified? end def insert_target_modifier_id - "op-share-wp-active-shares" + 'op-share-wp-active-shares' end def blankslate_config @blankslate_config ||= {}.tap do |config| if params[:filters].blank? config[:icon] = :people - config[:heading_text] = I18n.t("work_package.sharing.text_empty_state_header") - config[:description_text] = I18n.t("work_package.sharing.text_empty_state_description") + config[:heading_text] = I18n.t('work_package.sharing.text_empty_state_header') + config[:description_text] = I18n.t('work_package.sharing.text_empty_state_description') else config[:icon] = :search - config[:heading_text] = I18n.t("work_package.sharing.text_empty_search_header") - config[:description_text] = I18n.t("work_package.sharing.text_empty_search_description") + config[:heading_text] = I18n.t('work_package.sharing.text_empty_search_header') + config[:description_text] = I18n.t('work_package.sharing.text_empty_search_description') end end end def type_filter_options [ - { label: I18n.t("work_package.sharing.filter.project_member"), - value: { principal_type: "User", project_member: true } }, - { label: I18n.t("work_package.sharing.filter.not_project_member"), - value: { principal_type: "User", project_member: false } }, - { label: I18n.t("work_package.sharing.filter.project_group"), - value: { principal_type: "Group", project_member: true } }, - { label: I18n.t("work_package.sharing.filter.not_project_group"), - value: { principal_type: "Group", project_member: false } } + { label: I18n.t('work_package.sharing.filter.project_member'), + value: { principal_type: 'User', project_member: true } }, + { label: I18n.t('work_package.sharing.filter.not_project_member'), + value: { principal_type: 'User', project_member: false } }, + { label: I18n.t('work_package.sharing.filter.project_group'), + value: { principal_type: 'Group', project_member: true } }, + { label: I18n.t('work_package.sharing.filter.not_project_group'), + value: { principal_type: 'Group', project_member: false } } ] end def type_filter_option_active?(_option) - principal_type_filter_value = current_filter_value(params[:filters], "principal_type") - project_member_filter_value = current_filter_value(params[:filters], "also_project_member") + principal_type_filter_value = current_filter_value(params[:filters], 'principal_type') + project_member_filter_value = current_filter_value(params[:filters], 'also_project_member') return false if principal_type_filter_value.nil? || project_member_filter_value.nil? @@ -100,7 +100,7 @@ def type_filter_option_active?(_option) end def role_filter_option_active?(_option) - role_filter_value = current_filter_value(params[:filters], "role_id") + role_filter_value = current_filter_value(params[:filters], 'role_id') return false if role_filter_value.nil? @@ -122,7 +122,7 @@ def filter_url(type_option: nil, role_option: nil) end def apply_role_filter(_option) - current_role_filter_value = current_filter_value(params[:filters], "role_id") + current_role_filter_value = current_filter_value(params[:filters], 'role_id') filter = [] if _option.nil? && current_role_filter_value.present? @@ -141,8 +141,8 @@ def role_filter_for(_option, builtin_role: true) end def apply_type_filter(_option) - current_type_filter_value = current_filter_value(params[:filters], "principal_type") - current_member_filter_value = current_filter_value(params[:filters], "also_project_member") + current_type_filter_value = current_filter_value(params[:filters], 'principal_type') + current_member_filter_value = current_filter_value(params[:filters], 'also_project_member') filter = [] if _option.nil? && current_type_filter_value.present? && current_member_filter_value.present? @@ -173,7 +173,7 @@ def current_filter_value(filters, filter_key) return nil if filters.nil? given_filters = JSON.parse(filters).find { |key| key.key?(filter_key) } - given_filters ? given_filters[filter_key]["values"].first : nil + given_filters ? given_filters[filter_key]['values'].first : nil end end end diff --git a/app/components/work_packages/share/permission_button_component.rb b/app/components/work_packages/share/permission_button_component.rb index 9bfee0e573d2..e6e03482a364 100644 --- a/app/components/work_packages/share/permission_button_component.rb +++ b/app/components/work_packages/share/permission_button_component.rb @@ -54,7 +54,7 @@ def option_active?(option) end def wrapper_uniq_by - share.id || @system_arguments.dig(:data, :"test-selector") + share.id || @system_arguments.dig(:data, :'test-selector') end private @@ -77,8 +77,8 @@ def permission_name(value) def form_inputs(role_id) [].tap do |inputs| - inputs << { name: "role_ids[]", value: role_id } - inputs << { name: "filters", value: params[:filters] } if params[:filters] + inputs << { name: 'role_ids[]', value: role_id } + inputs << { name: 'filters', value: params[:filters] } if params[:filters] end end end diff --git a/app/components/work_packages/share/share_row_component.rb b/app/components/work_packages/share/share_row_component.rb index 16d82a331a09..ef5dbb1fbf7f 100644 --- a/app/components/work_packages/share/share_row_component.rb +++ b/app/components/work_packages/share/share_row_component.rb @@ -60,9 +60,9 @@ def share_editable? def grid_css_classes if sharing_manageable? - "op-share-wp-modal-body--user-row_manageable" + 'op-share-wp-modal-body--user-row_manageable' else - "op-share-wp-modal-body--user-row" + 'op-share-wp-modal-body--user-row' end end diff --git a/app/contracts/attachments/validate_replacements.rb b/app/contracts/attachments/validate_replacements.rb index 7bbc91d763bf..b283805712d0 100644 --- a/app/contracts/attachments/validate_replacements.rb +++ b/app/contracts/attachments/validate_replacements.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "model_contract" +require 'model_contract' module Attachments module ValidateReplacements diff --git a/app/contracts/authentication/omniauth_auth_hash_contract.rb b/app/contracts/authentication/omniauth_auth_hash_contract.rb index ba0b257f1761..3e89231559a0 100644 --- a/app/contracts/authentication/omniauth_auth_hash_contract.rb +++ b/app/contracts/authentication/omniauth_auth_hash_contract.rb @@ -49,9 +49,9 @@ def validate_auth_hash end def validate_auth_hash_not_expired - return unless auth_hash["timestamp"] + return unless auth_hash['timestamp'] - if auth_hash["timestamp"] < Time.now - 30.minutes + if auth_hash['timestamp'] < Time.now - 30.minutes errors.add(:base, I18n.t(:error_omniauth_registration_timed_out)) end end diff --git a/app/contracts/concerns/assignable_custom_field_values.rb b/app/contracts/concerns/assignable_custom_field_values.rb index 133f1ecbf6f2..91d7339f9bab 100644 --- a/app/contracts/concerns/assignable_custom_field_values.rb +++ b/app/contracts/concerns/assignable_custom_field_values.rb @@ -32,9 +32,9 @@ module AssignableCustomFieldValues included do def assignable_custom_field_values(custom_field) case custom_field.field_format - when "list" + when 'list' custom_field.possible_values - when "version" + when 'version' assignable_versions(only_open: !custom_field.allow_non_open_versions?) end end diff --git a/app/contracts/custom_actions/cu_contract.rb b/app/contracts/custom_actions/cu_contract.rb index e2c2d65abcc4..54e7025349d1 100644 --- a/app/contracts/custom_actions/cu_contract.rb +++ b/app/contracts/custom_actions/cu_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "model_contract" +require 'model_contract' # Contract for create (c) and update (u) module CustomActions diff --git a/app/contracts/groups/create_contract.rb b/app/contracts/groups/create_contract.rb index af3eb12b13ad..8c7d48ed5005 100644 --- a/app/contracts/groups/create_contract.rb +++ b/app/contracts/groups/create_contract.rb @@ -36,7 +36,7 @@ class CreateContract < BaseContract def type_is_group unless model.type == Group.name - errors.add(:type, "Type and class mismatch") + errors.add(:type, 'Type and class mismatch') end end end diff --git a/app/contracts/model_contract.rb b/app/contracts/model_contract.rb index 07ba44ffd920..4c482f3cbdf1 100644 --- a/app/contracts/model_contract.rb +++ b/app/contracts/model_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "base_contract" +require_relative 'base_contract' ## # Model contract for AR records that diff --git a/app/contracts/placeholder_users/create_contract.rb b/app/contracts/placeholder_users/create_contract.rb index 308b7750fd99..7a02a7b15da7 100644 --- a/app/contracts/placeholder_users/create_contract.rb +++ b/app/contracts/placeholder_users/create_contract.rb @@ -39,7 +39,7 @@ class CreateContract < BaseContract def type_is_placeholder_user unless model.type == PlaceholderUser.name - errors.add(:type, "Type and class mismatch") + errors.add(:type, 'Type and class mismatch') end end end diff --git a/app/contracts/projects/create_contract.rb b/app/contracts/projects/create_contract.rb index 78b38a775c73..2db60762324c 100644 --- a/app/contracts/projects/create_contract.rb +++ b/app/contracts/projects/create_contract.rb @@ -28,11 +28,6 @@ module Projects class CreateContract < BaseContract - include AdminWritableTimestamps - # Projects update their updated_at timestamp due to awesome_nested_set - # so allowing writing here would be useless. - allow_writable_timestamps :created_at - private def validate_user_allowed_to_manage diff --git a/app/contracts/queries/copy_contract.rb b/app/contracts/queries/copy_contract.rb index c184b13b43f2..b67a0c02dcd5 100644 --- a/app/contracts/queries/copy_contract.rb +++ b/app/contracts/queries/copy_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "queries/base_contract" +require 'queries/base_contract' module Queries class CopyContract < BaseContract diff --git a/app/contracts/queries/global_create_contract.rb b/app/contracts/queries/global_create_contract.rb index ba75246e447a..586679b96758 100644 --- a/app/contracts/queries/global_create_contract.rb +++ b/app/contracts/queries/global_create_contract.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require "queries/create_contract" +require 'queries/create_contract' module Queries class GlobalCreateContract < CreateContract diff --git a/app/contracts/queries/ical_sharing_contract.rb b/app/contracts/queries/ical_sharing_contract.rb index 58390a9d0c06..64dcc1f8db58 100644 --- a/app/contracts/queries/ical_sharing_contract.rb +++ b/app/contracts/queries/ical_sharing_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "queries/base_contract" +require 'queries/base_contract' module Queries class ICalSharingContract < BaseContract diff --git a/app/contracts/queries/update_contract.rb b/app/contracts/queries/update_contract.rb index 867c2559b925..a2479b775187 100644 --- a/app/contracts/queries/update_contract.rb +++ b/app/contracts/queries/update_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "queries/base_contract" +require 'queries/base_contract' module Queries class UpdateContract < BaseContract diff --git a/app/contracts/queries/update_form_contract.rb b/app/contracts/queries/update_form_contract.rb index 8f2805706d78..ff83d8dad989 100644 --- a/app/contracts/queries/update_form_contract.rb +++ b/app/contracts/queries/update_form_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "queries/base_contract" +require 'queries/base_contract' module Queries class UpdateFormContract < BaseContract diff --git a/app/contracts/relations/base_contract.rb b/app/contracts/relations/base_contract.rb index 2a1ddc9d7056..981653ad605c 100644 --- a/app/contracts/relations/base_contract.rb +++ b/app/contracts/relations/base_contract.rb @@ -57,7 +57,7 @@ def validate_to_exists def validate_nodes_relatable if (model.from_id_changed? || model.to_id_changed?) && WorkPackage.relatable(model.from, model.relation_type, ignored_relation: model).where(id: model.to_id).empty? - errors.add :base, I18n.t(:"activerecord.errors.messages.circular_dependency") + errors.add :base, I18n.t(:'activerecord.errors.messages.circular_dependency') end end diff --git a/app/contracts/relations/create_contract.rb b/app/contracts/relations/create_contract.rb index fe139dfa70bb..6f6318ceef6d 100644 --- a/app/contracts/relations/create_contract.rb +++ b/app/contracts/relations/create_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "relations/base_contract" +require 'relations/base_contract' module Relations class CreateContract < BaseContract diff --git a/app/contracts/settings/working_days_params_contract.rb b/app/contracts/settings/working_days_params_contract.rb index 42bacb779bab..c19f63062f85 100644 --- a/app/contracts/settings/working_days_params_contract.rb +++ b/app/contracts/settings/working_days_params_contract.rb @@ -42,7 +42,7 @@ def working_days_are_present end def unique_job - WorkPackages::ApplyWorkingDaysChangeJob.new.check_concurrency do + if WorkPackages::ApplyWorkingDaysChangeJob.scheduled? errors.add :base, :previous_working_day_changes_unprocessed end end diff --git a/app/contracts/types/base_contract.rb b/app/contracts/types/base_contract.rb index 59d349d82afa..22202424a38b 100644 --- a/app/contracts/types/base_contract.rb +++ b/app/contracts/types/base_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "model_contract" +require 'model_contract' module Types class BaseContract < ::ModelContract @@ -93,7 +93,7 @@ def validate_attribute_group(group) if key.is_a?(String) && valid_attributes.exclude?(key) errors.add( :attribute_groups, - I18n.t("activerecord.errors.models.type.attributes.attribute_groups.attribute_unknown_name", + I18n.t('activerecord.errors.models.type.attributes.attribute_groups.attribute_unknown_name', attribute: key) ) end diff --git a/app/contracts/user_preferences/base_contract.rb b/app/contracts/user_preferences/base_contract.rb index 4aa2a4be0757..c23970bf1e7f 100644 --- a/app/contracts/user_preferences/base_contract.rb +++ b/app/contracts/user_preferences/base_contract.rb @@ -81,7 +81,7 @@ def namesake_time_zone(time_zones) if time_zones.length == 1 time_zones.first else - time_zones.detect { |tz| tz.tzinfo.name.include?(tz.name.tr(" ", "_")) } + time_zones.detect { |tz| tz.tzinfo.name.include?(tz.name.tr(' ', '_')) } end end end @@ -109,7 +109,7 @@ def user_allowed_to_access end def full_hour_reminder_time - unless model.daily_reminders[:times].all? { |time| time.end_with?("00:00+00:00") } + unless model.daily_reminders[:times].all? { |time| time.end_with?('00:00+00:00') } errors.add :daily_reminders, :full_hour end end diff --git a/app/contracts/users/base_contract.rb b/app/contracts/users/base_contract.rb index 2dfb83fd0c6f..a28ddcd0ec13 100644 --- a/app/contracts/users/base_contract.rb +++ b/app/contracts/users/base_contract.rb @@ -64,7 +64,7 @@ def self.model def reduce_writable_attributes(attributes) super.tap do |writable| - writable << "password" if password_writable? + writable << 'password' if password_writable? end end diff --git a/app/contracts/users/create_contract.rb b/app/contracts/users/create_contract.rb index 2ef001e6446b..3055261bf060 100644 --- a/app/contracts/users/create_contract.rb +++ b/app/contracts/users/create_contract.rb @@ -76,7 +76,7 @@ def user_allowed_to_add def type_is_user unless model.type == User.name - errors.add(:type, "Type and class mismatch") + errors.add(:type, 'Type and class mismatch') end end end diff --git a/app/contracts/work_packages/copy_project_contract.rb b/app/contracts/work_packages/copy_project_contract.rb index 5aa7993f1fdb..178289a5517c 100644 --- a/app/contracts/work_packages/copy_project_contract.rb +++ b/app/contracts/work_packages/copy_project_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "work_packages/create_contract" +require 'work_packages/create_contract' # Can be used to copy all of a project's work packages. As the # work packages can be old, some of the validations that would diff --git a/app/contracts/work_packages/create_contract.rb b/app/contracts/work_packages/create_contract.rb index e8086638b262..a8090b4ff267 100644 --- a/app/contracts/work_packages/create_contract.rb +++ b/app/contracts/work_packages/create_contract.rb @@ -26,16 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "work_packages/base_contract" +require 'work_packages/base_contract' module WorkPackages class CreateContract < BaseContract - include AdminWritableTimestamps - allow_writable_timestamps - attribute :author_id, - writable: -> { default_attributes_admin_writable? } - + writable: false do + errors.add :author_id, :invalid if model.author != user + end attribute :status_id, # Overriding permission from WP base contract to ignore change_work_package_status for creation, # because we don't require that permission for writable status during WP creation. @@ -64,7 +62,7 @@ def user_allowed_to_manage_file_links def attributes_changed_by_user # lock version is initialized by AR itself - super - ["lock_version"] + super - ['lock_version'] end end end diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb index 700a0c132ed2..9ff7cc1a4114 100644 --- a/app/controllers/account_controller.rb +++ b/app/controllers/account_controller.rb @@ -42,7 +42,7 @@ class AccountController < ApplicationController before_action :check_auth_source_sso_failure, only: :auth_source_sso_failed before_action :check_internal_login_enabled, only: :internal_login - layout "no_menu" + layout 'no_menu' # Login request and validation def login @@ -58,7 +58,7 @@ def login end def internal_login - render "account/login" + render 'account/login' end # Log out current user and redirect to welcome page @@ -88,12 +88,12 @@ def lost_password if call.success? @token.destroy - redirect_to action: "login" + redirect_to action: 'login' return end end - render template: "account/password_recovery" + render template: 'account/password_recovery' elsif request.post? mail = params[:mail] user = User.find_by_mail(mail) if mail.present? @@ -120,7 +120,7 @@ def lost_password if token.save UserMailer.password_lost(token).deliver_later flash[:notice] = I18n.t(:notice_account_lost_email_sent) - redirect_to action: "login", back_url: home_url + redirect_to action: 'login', back_url: home_url nil end end @@ -235,7 +235,7 @@ def activate_user(user) if omniauth_direct_login? direct_login user elsif OpenProject::Configuration.disable_password_login? - flash[:notice] = I18n.t("account.omniauth_login") + flash[:notice] = I18n.t('account.omniauth_login') redirect_to signin_path else @@ -249,7 +249,7 @@ def activate_through_ldap(user) ldap_auth_source_id: user.ldap_auth_source_id } - flash[:notice] = I18n.t("account.auth_source_login", login: user.login).html_safe + flash[:notice] = I18n.t('account.auth_source_login', login: user.login).html_safe redirect_to signin_path(username: user.login) end @@ -283,7 +283,7 @@ def auth_source_sso_failed flash.now[:error] = I18n.t(:error_auth_source_sso_failed, value: failure[:login]) + ": " + String(flash.now[:error]) - render action: "login", back_url: failure[:back_url] + render action: 'login', back_url: failure[:back_url] end private @@ -470,11 +470,11 @@ def pending_omniauth_registration? def onthefly_creation_failed(user, auth_source_options = {}) @user = user session[:auth_source_registration] = auth_source_options unless auth_source_options.empty? - render action: "register" + render action: 'register' end def self_registration_disabled - flash[:error] = I18n.t("account.error_self_registration_disabled") + flash[:error] = I18n.t('account.error_self_registration_disabled') redirect_to signin_url end @@ -489,18 +489,18 @@ def account_inactive(user, flash_now: true) # Log an attempt to log in to an account in "registered" state and show a flash message. def account_not_activated(flash_now: true) - flash_error_message(log_reason: "NOT ACTIVATED", flash_now:) do + flash_error_message(log_reason: 'NOT ACTIVATED', flash_now:) do if Setting::SelfRegistration.by_email? - "account.error_inactive_activation_by_mail" + 'account.error_inactive_activation_by_mail' else - "account.error_inactive_manual_activation" + 'account.error_inactive_manual_activation' end end end def invited_account_not_activated(_user) - flash_error_message(log_reason: "invited, NOT ACTIVATED", flash_now: false) do - "account.error_inactive_activation_by_mail" + flash_error_message(log_reason: 'invited, NOT ACTIVATED', flash_now: false) do + 'account.error_inactive_activation_by_mail' end end diff --git a/app/controllers/activities_controller.rb b/app/controllers/activities_controller.rb index fee13edbd990..89aec8fd9052 100644 --- a/app/controllers/activities_controller.rb +++ b/app/controllers/activities_controller.rb @@ -75,7 +75,7 @@ def set_activity end def verify_activities_module_activated - render_403 if @project && !@project.module_enabled?("activity") + render_403 if @project && !@project.module_enabled?('activity') end def determine_date_range @@ -101,7 +101,7 @@ def determine_subprojects elsif params[:with_subprojects].nil? session[:activity][:with_subprojects] else - params[:with_subprojects] == "1" + params[:with_subprojects] == '1' end end @@ -136,7 +136,7 @@ def activity_scope end def set_current_activity_page - @activity_page = @project ? "projects/#{@project.identifier}" : "all" + @activity_page = @project ? "projects/#{@project.identifier}" : 'all' end def set_session diff --git a/app/controllers/admin/attachments/quarantined_attachments_controller.rb b/app/controllers/admin/attachments/quarantined_attachments_controller.rb index 8856adcce0c9..a931d5576ad8 100644 --- a/app/controllers/admin/attachments/quarantined_attachments_controller.rb +++ b/app/controllers/admin/attachments/quarantined_attachments_controller.rb @@ -29,7 +29,7 @@ module Admin module Attachments class QuarantinedAttachmentsController < ApplicationController - layout "admin" + layout 'admin' before_action :require_admin before_action :find_quarantined_attachments @@ -45,14 +45,14 @@ def destroy create_journal(container, User.system, - I18n.t("antivirus_scan.deleted_by_admin", filename: @attachment.filename)) + I18n.t('antivirus_scan.deleted_by_admin', filename: @attachment.filename)) flash[:notice] = t(:notice_successful_delete) redirect_to action: :index end def default_breadcrumb - t("antivirus_scan.quarantined_attachments.title") + t('antivirus_scan.quarantined_attachments.title') end def show_local_breadcrumb diff --git a/app/controllers/admin/settings/aggregation_settings_controller.rb b/app/controllers/admin/settings/aggregation_settings_controller.rb index 56ebfd5880c4..a01f5b774a33 100644 --- a/app/controllers/admin/settings/aggregation_settings_controller.rb +++ b/app/controllers/admin/settings/aggregation_settings_controller.rb @@ -37,7 +37,7 @@ def show end def default_breadcrumb - t(:"menus.admin.aggregation") + t(:'menus.admin.aggregation') end def show_local_breadcrumb diff --git a/app/controllers/admin/settings/attachments_settings_controller.rb b/app/controllers/admin/settings/attachments_settings_controller.rb index 5b2440de78b3..929520884250 100644 --- a/app/controllers/admin/settings/attachments_settings_controller.rb +++ b/app/controllers/admin/settings/attachments_settings_controller.rb @@ -31,7 +31,7 @@ class AttachmentsSettingsController < ::Admin::SettingsController menu_item :attachments_settings def default_breadcrumb - t(:"attributes.attachments") + t(:'attributes.attachments') end def settings_params diff --git a/app/controllers/admin/settings/date_format_settings_controller.rb b/app/controllers/admin/settings/date_format_settings_controller.rb index 9c14335914fe..27f21858d511 100644 --- a/app/controllers/admin/settings/date_format_settings_controller.rb +++ b/app/controllers/admin/settings/date_format_settings_controller.rb @@ -48,7 +48,7 @@ def validate_start_of_week_and_first_week_of_year_combination if start_of_week.present? ^ start_of_year.present? flash[:error] = I18n.t( - "settings.date_format.first_date_of_week_and_year_set", + 'settings.date_format.first_date_of_week_and_year_set', first_week_setting_name: I18n.t(:setting_first_week_of_year), day_of_week_setting_name: I18n.t(:setting_start_of_week) ) diff --git a/app/controllers/admin/settings/mail_notifications_settings_controller.rb b/app/controllers/admin/settings/mail_notifications_settings_controller.rb index 8af36f26c00f..2029d00a2a22 100644 --- a/app/controllers/admin/settings/mail_notifications_settings_controller.rb +++ b/app/controllers/admin/settings/mail_notifications_settings_controller.rb @@ -39,7 +39,7 @@ def show end def default_breadcrumb - t(:"menus.admin.mail_notification") + t(:'menus.admin.mail_notification') end def show_local_breadcrumb diff --git a/app/controllers/admin/settings/users_settings_controller.rb b/app/controllers/admin/settings/users_settings_controller.rb index 8fb79712df0a..e41ae5479f27 100644 --- a/app/controllers/admin/settings/users_settings_controller.rb +++ b/app/controllers/admin/settings/users_settings_controller.rb @@ -47,7 +47,7 @@ def show_local_breadcrumb def settings_params super.tap do |settings| - if settings["consent_required"] == "1" && params["toggle_consent_time"] == "1" + if settings["consent_required"] == '1' && params['toggle_consent_time'] == '1' settings["consent_time"] = Time.zone.now.iso8601 end end diff --git a/app/controllers/admin/settings/virus_scanning_settings_controller.rb b/app/controllers/admin/settings/virus_scanning_settings_controller.rb index 842990f4a726..a15aff0fbc87 100644 --- a/app/controllers/admin/settings/virus_scanning_settings_controller.rb +++ b/app/controllers/admin/settings/virus_scanning_settings_controller.rb @@ -34,7 +34,7 @@ class VirusScanningSettingsController < ::Admin::SettingsController before_action :check_clamav, only: %i[update], if: -> { scan_enabled? } def default_breadcrumb - t("settings.antivirus.title") + t('settings.antivirus.title') end def av_form @@ -52,7 +52,7 @@ def av_form private def require_ee - render("upsale") unless EnterpriseToken.allows_to?(:virus_scanning) + render('upsale') unless EnterpriseToken.allows_to?(:virus_scanning) end def mark_unscanned_attachments @@ -60,7 +60,7 @@ def mark_unscanned_attachments end def check_clamav - return if params.dig(:settings, :antivirus_scan_mode) == "disabled" + return if params.dig(:settings, :antivirus_scan_mode) == 'disabled' service = ::Attachments::ClamAVService.new(params[:settings][:antivirus_scan_mode].to_sym, params[:settings][:antivirus_scan_target]) @@ -68,12 +68,12 @@ def check_clamav service.ping rescue StandardError => e Rails.logger.error { "Failed to check availability of ClamAV: #{e.message}" } - flash[:error] = t(:"settings.antivirus.clamav_ping_failed") + flash[:error] = t(:'settings.antivirus.clamav_ping_failed') redirect_to action: :show end def scan_enabled? - Setting.antivirus_scan_mode != :disabled || params.dig(:settings, :antivirus_scan_mode) != "disabled" + Setting.antivirus_scan_mode != :disabled || params.dig(:settings, :antivirus_scan_mode) != 'disabled' end def success_callback(_call) @@ -87,7 +87,7 @@ def success_callback(_call) end def rescan_files - flash[:notice] = t("settings.antivirus.remaining_rescanned_files", + flash[:notice] = t('settings.antivirus.remaining_rescanned_files', file_count: t(:label_x_files, count: Attachment.status_uploaded.count)) Attachment.status_uploaded.update_all(status: :rescan) @@ -96,8 +96,8 @@ def rescan_files end def remaining_quarantine_warning - flash[:info] = t("settings.antivirus.remaining_quarantined_files_html", - link: helpers.link_to(t("antivirus_scan.quarantined_attachments.title"), + flash[:info] = t('settings.antivirus.remaining_quarantined_files_html', + link: helpers.link_to(t('antivirus_scan.quarantined_attachments.title'), admin_quarantined_attachments_path), file_count: t(:label_x_files, count: Attachment.status_quarantined.count)) redirect_to action: :show diff --git a/app/controllers/admin/settings/working_days_settings_controller.rb b/app/controllers/admin/settings/working_days_settings_controller.rb index fa0d390f7e49..f0c7bdfa89fb 100644 --- a/app/controllers/admin/settings/working_days_settings_controller.rb +++ b/app/controllers/admin/settings/working_days_settings_controller.rb @@ -37,7 +37,7 @@ def default_breadcrumb def failure_callback(call) @modified_non_working_days = modified_non_working_days_for(call.result) flash[:error] = call.message || I18n.t(:notice_internal_server_error) - render action: "show" + render action: 'show' end protected diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index 8d9823ced5a1..72d222b08e68 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -28,7 +28,7 @@ module Admin class SettingsController < ApplicationController - layout "admin" + layout 'admin' before_action :require_admin before_action :find_plugin, only: %i[show_plugin update_plugin] @@ -99,12 +99,12 @@ def update_service def success_callback(_call) flash[:notice] = t(:notice_successful_update) - redirect_to action: "show", tab: params[:tab] + redirect_to action: 'show', tab: params[:tab] end def failure_callback(call) flash[:error] = call.message || I18n.t(:notice_internal_server_error) - redirect_to action: "show", tab: params[:tab] + redirect_to action: 'show', tab: params[:tab] end end end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 88eb45a947e4..91dd292afc99 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "open3" +require 'open3' class AdminController < ApplicationController - layout "admin" + layout 'admin' before_action :require_admin, except: %i[index] before_action :authorize_global, only: %i[index] @@ -53,11 +53,11 @@ def index end def projects - redirect_to controller: "projects", action: "index" + redirect_to controller: 'projects', action: 'index' end def plugins - @plugins = Redmine::Plugin.not_bundled.sort + @plugins = Redmine::Plugin.all.sort end def test_email @@ -91,9 +91,9 @@ def info def default_breadcrumb case params[:action] - when "plugins" + when 'plugins' t(:label_plugins) - when "info" + when 'info' t(:label_information) end end @@ -111,12 +111,12 @@ def hidden_admin_menu_items def plaintext_extraction_checks if OpenProject::Database.allows_tsv? [ - [:"extraction.available.pdftotext", Plaintext::PdfHandler.available?], - [:"extraction.available.unrtf", Plaintext::RtfHandler.available?], - [:"extraction.available.catdoc", Plaintext::DocHandler.available?], - [:"extraction.available.xls2csv", Plaintext::XlsHandler.available?], - [:"extraction.available.catppt", Plaintext::PptHandler.available?], - [:"extraction.available.tesseract", Plaintext::ImageHandler.available?] + [:'extraction.available.pdftotext', Plaintext::PdfHandler.available?], + [:'extraction.available.unrtf', Plaintext::RtfHandler.available?], + [:'extraction.available.catdoc', Plaintext::DocHandler.available?], + [:'extraction.available.xls2csv', Plaintext::XlsHandler.available?], + [:'extraction.available.catppt', Plaintext::PptHandler.available?], + [:'extraction.available.tesseract', Plaintext::ImageHandler.available?] ] else [] @@ -124,11 +124,11 @@ def plaintext_extraction_checks end def image_conversion_checks - [[:"image_conversion.imagemagick", image_conversion_libs_available?]] + [[:'image_conversion.imagemagick', image_conversion_libs_available?]] end def image_conversion_libs_available? - Open3.capture2e("convert", "-version").first.include?("ImageMagick") + Open3.capture2e('convert', '-version').first.include?('ImageMagick') rescue StandardError false end diff --git a/app/controllers/angular_controller.rb b/app/controllers/angular_controller.rb index d44fd99127a7..c92abcda3769 100644 --- a/app/controllers/angular_controller.rb +++ b/app/controllers/angular_controller.rb @@ -32,13 +32,13 @@ class AngularController < ApplicationController def empty_layout # Frontend will handle rendering # but we will need to render with layout - render html: "", layout: "angular/angular" + render html: '', layout: 'angular/angular' end def notifications_layout # Frontend will handle rendering # but we will need to render with notification specific layout - render html: "", layout: "angular/notifications" + render html: '', layout: 'angular/notifications' end def login_back_url_params diff --git a/app/controllers/announcements_controller.rb b/app/controllers/announcements_controller.rb index 59591fb70d56..ec637699c1ea 100644 --- a/app/controllers/announcements_controller.rb +++ b/app/controllers/announcements_controller.rb @@ -1,5 +1,5 @@ class AnnouncementsController < ApplicationController - layout "admin" + layout 'admin' before_action :require_admin @@ -15,7 +15,7 @@ def update flash[:notice] = t(:notice_successful_update) end - redirect_to action: "edit" + redirect_to action: 'edit' end private @@ -29,6 +29,6 @@ def show_local_breadcrumb end def announcement_params - params.require(:announcement).permit("text", "show_until", "active") + params.require(:announcement).permit('text', 'show_until', 'active') end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4375d2aa21dc..564973057f70 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "uri" -require "cgi" +require 'uri' +require 'cgi' -require "doorkeeper/dashboard_helper" +require 'doorkeeper/dashboard_helper' class ApplicationController < ActionController::Base class_attribute :_model_object @@ -51,7 +51,7 @@ class ApplicationController < ActionController::Base include AdditionalUrlHelpers include OpenProjectErrorHelper - layout "base" + layout 'base' protect_from_forgery # CSRF protection prevents two things. It prevents an attacker from using a @@ -74,7 +74,7 @@ class ApplicationController < ActionController::Base # Thus, we show an error message unless the request probably is an API # request. def handle_unverified_request - cookies.delete(OpenProject::Configuration["autologin_cookie_name"]) + cookies.delete(OpenProject::Configuration['autologin_cookie_name']) self.logged_user = nil # Don't render an error message for requests that appear to be API requests. @@ -105,7 +105,7 @@ def handle_unverified_request # Check whether user have cookies enabled, otherwise they'll only be # greeted with the CSRF error upon login. message = I18n.t(:error_token_authenticity) - message << (" " + I18n.t(:error_cookie_missing)) if openproject_cookie_missing? + message << (' ' + I18n.t(:error_cookie_missing)) if openproject_cookie_missing? log_csrf_failure @@ -148,7 +148,7 @@ def handle_unverified_request def default_url_options(_options = {}) { - layout: params["layout"], + layout: params['layout'], protocol: Setting.protocol } end @@ -159,7 +159,7 @@ def default_url_options(_options = {}) # https://websecuritytool.codeplex.com/wikipage?title=Checks#http-cache-control-header-no-store # http://stackoverflow.com/questions/711418/how-to-prevent-browser-page-caching-in-rails def set_cache_buster - if OpenProject::Configuration["disable_browser_cache"] + if OpenProject::Configuration['disable_browser_cache'] response.cache_control.merge!( max_age: 0, public: false, @@ -179,7 +179,7 @@ def reload_mailer_settings! # Checks if the session cookie is missing. # This is useful only on a second request def openproject_cookie_missing? - request.cookies[OpenProject::Configuration["session_cookie_name"]].nil? + request.cookies[OpenProject::Configuration['session_cookie_name']].nil? end helper_method :openproject_cookie_missing? @@ -187,8 +187,8 @@ def openproject_cookie_missing? ## # Create CSRF issue def log_csrf_failure - message = "CSRF validation error" - message << " (No session cookie present)" if openproject_cookie_missing? + message = 'CSRF validation error' + message << ' (No session cookie present)' if openproject_cookie_missing? op_handle_error message, reference: :csrf_validation_failed end @@ -208,7 +208,7 @@ def log_requesting_user # replaces all invalid characters with # def escape_for_logging(string) # only allow numbers, ASCII letters, space and the following characters: @.-"'!?=/ - string.gsub(/[^0-9a-zA-Z@._\-"'!?=\/ ]{1}/, "#") + string.gsub(/[^0-9a-zA-Z@._\-"'!?=\/ ]{1}/, '#') end def reset_i18n_fallbacks @@ -228,7 +228,7 @@ def set_localization user = RequestStore[:current_user] || (session[:authenticated_user_id].present? && User.find_by(id: session[:authenticated_user_id])) || User.anonymous - SetLocalizationService.new(user, request.env["HTTP_ACCEPT_LANGUAGE"]).call + SetLocalizationService.new(user, request.env['HTTP_ACCEPT_LANGUAGE']).call end def deny_access(not_found: false) @@ -413,7 +413,7 @@ def find_object_and_scope associated = find_belongs_to_chained_objects(associations, model_object) associated.each do |a| - instance_variable_set("@" + a.class.to_s.downcase, a) + instance_variable_set('@' + a.class.to_s.downcase, a) end rescue ActiveRecord::RecordNotFound render_404 @@ -452,7 +452,7 @@ def self.model_object(model, options = {}) def find_work_packages @work_packages = WorkPackage.includes(:project) .where(id: params[:work_package_id] || params[:ids]) - .order("id ASC") + .order('id ASC') fail ActiveRecord::RecordNotFound if @work_packages.empty? @projects = @work_packages.filter_map(&:project).uniq @@ -479,7 +479,7 @@ def check_project_privacy end def back_url - params[:back_url] || request.env["HTTP_REFERER"] + params[:back_url] || request.env['HTTP_REFERER'] end def redirect_back_or_default(default, use_escaped = true) @@ -497,7 +497,7 @@ def redirect_back_or_default(default, use_escaped = true) # # @return [boolean, string] name of the layout to use or false for no layout def use_layout - request.xhr? ? false : "no_menu" + request.xhr? ? false : 'no_menu' end def render_feed(items, options = {}) @@ -505,7 +505,7 @@ def render_feed(items, options = {}) @items = @items.sort { |x, y| y.event_datetime <=> x.event_datetime } @items = @items.slice(0, Setting.feeds_limit.to_i) @title = options[:title] || Setting.app_title - render template: "common/feed", layout: false, content_type: "application/atom+xml" + render template: 'common/feed', layout: false, content_type: 'application/atom+xml' end def self.accept_key_auth(*actions) @@ -519,7 +519,7 @@ def accept_key_auth_actions # Returns a string that can be used as filename value in Content-Disposition header def filename_for_content_disposition(name) - %r{(MSIE|Trident)}.match?(request.env["HTTP_USER_AGENT"]) ? ERB::Util.url_encode(name) : name + %r{(MSIE|Trident)}.match?(request.env['HTTP_USER_AGENT']) ? ERB::Util.url_encode(name) : name end def api_request? @@ -534,8 +534,8 @@ def api_request? def api_key_from_request if params[:key].present? params[:key] - elsif request.headers["X-OpenProject-API-Key"].present? - request.headers["X-OpenProject-API-Key"] + elsif request.headers['X-OpenProject-API-Key'].present? + request.headers['X-OpenProject-API-Key'] end end @@ -550,10 +550,10 @@ def object_errors_to_json(object) def render_validation_errors(object) options = { status: :unprocessable_entity, layout: false } errors = case params[:format] - when "xml" + when 'xml' { xml: object.errors } - when "json" - { json: { "errors" => object.errors } } # ActiveResource client compliance + when 'json' + { json: { 'errors' => object.errors } } # ActiveResource client compliance else fail "Unknown format #{params[:format]} in #render_validation_errors" end @@ -566,7 +566,7 @@ def render_validation_errors(object) def default_template(action_name = self.action_name) if api_request? begin - return view_paths.find_template(default_template_name(action_name), "api") + return view_paths.find_template(default_template_name(action_name), 'api') rescue ::ActionView::MissingTemplate # the api template was not found # fallback to the default behaviour @@ -584,7 +584,7 @@ def pick_layout(*args) def default_breadcrumb label = "label_#{controller_name.singularize}" - I18n.t(label + "_plural", + I18n.t(label + '_plural', default: label.to_sym) end @@ -607,8 +607,8 @@ def check_session_lifetime if session_expired? self.logged_user = nil - flash[:warning] = I18n.t("notice_forced_logout", ttl_time: Setting.session_ttl) - redirect_to(controller: "/account", action: "login", back_url: login_back_url) + flash[:warning] = I18n.t('notice_forced_logout', ttl_time: Setting.session_ttl) + redirect_to(controller: '/account', action: 'login', back_url: login_back_url) end session[:updated_at] = Time.now end @@ -623,7 +623,7 @@ def feed_request? def stop_if_feeds_disabled if feed_request? && !Setting.feeds_enabled? - render_404(message: I18n.t("label_disabled")) + render_404(message: I18n.t('label_disabled')) end end @@ -649,7 +649,7 @@ def login_back_url else url_params = params.permit(:action, :id, :project_id, :controller) - unless url_params[:controller].to_s.starts_with?("/") + unless url_params[:controller].to_s.starts_with?('/') url_params[:controller] = "/#{url_params[:controller]}" end diff --git a/app/controllers/attribute_help_texts_controller.rb b/app/controllers/attribute_help_texts_controller.rb index 50e759264db9..f9a5b2bbdf0b 100644 --- a/app/controllers/attribute_help_texts_controller.rb +++ b/app/controllers/attribute_help_texts_controller.rb @@ -27,7 +27,7 @@ #++ class AttributeHelpTextsController < ApplicationController - layout "admin" + layout 'admin' menu_item :attribute_help_texts before_action :authorize_global @@ -56,8 +56,8 @@ def create redirect_to attribute_help_texts_path(tab: call.result.attribute_scope) else @attribute_help_text = call.result - flash[:error] = call.message || I18n.t("notice_internal_server_error") - render action: "new" + flash[:error] = call.message || I18n.t('notice_internal_server_error') + render action: 'new' end end @@ -70,8 +70,8 @@ def update flash[:notice] = t(:notice_successful_update) redirect_to attribute_help_texts_path(tab: @attribute_help_text.attribute_scope) else - flash[:error] = call.message || I18n.t("notice_internal_server_error") - render action: "edit" + flash[:error] = call.message || I18n.t('notice_internal_server_error') + render action: 'edit' end end @@ -88,10 +88,10 @@ def destroy protected def default_breadcrumb - if action_name == "index" - t("attribute_help_texts.label_plural") + if action_name == 'index' + t('attribute_help_texts.label_plural') else - ActionController::Base.helpers.link_to(t("attribute_help_texts.label_plural"), attribute_help_texts_path) + ActionController::Base.helpers.link_to(t('attribute_help_texts.label_plural'), attribute_help_texts_path) end end @@ -122,7 +122,7 @@ def find_entry end def find_type_scope - name = params.fetch(:name, "WorkPackage") + name = params.fetch(:name, 'WorkPackage') submodule = AttributeHelpText.available_types.find { |mod| mod == name } if submodule.nil? diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 242abdc4b65a..1c9755f07c5a 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -70,7 +70,7 @@ def update flash[:notice] = I18n.t(:notice_successful_update) redirect_to project_settings_categories_path(@project) else - render action: "edit" + render action: 'edit' end end @@ -82,7 +82,7 @@ def destroy redirect_to project_settings_categories_path(@project) return elsif params[:todo] - reassign_to = @project.categories.find_by(id: params[:reassign_to_id]) if params[:todo] == "reassign" + reassign_to = @project.categories.find_by(id: params[:reassign_to_id]) if params[:todo] == 'reassign' @category.destroy(reassign_to) redirect_to project_settings_categories_path(@project) return diff --git a/app/controllers/colors_controller.rb b/app/controllers/colors_controller.rb index 018c6cbfaac1..5e671dc1ee5e 100644 --- a/app/controllers/colors_controller.rb +++ b/app/controllers/colors_controller.rb @@ -29,7 +29,7 @@ class ColorsController < ApplicationController before_action :require_admin_unless_readonly_api_request - layout "admin" + layout 'admin' menu_item :colors @@ -68,7 +68,7 @@ def create redirect_to colors_path else flash.now[:error] = I18n.t(:error_color_could_not_be_saved) - render action: "new" + render action: 'new' end end @@ -80,7 +80,7 @@ def update redirect_to colors_path else flash.now[:error] = I18n.t(:error_color_could_not_be_saved) - render action: "edit" + render action: 'edit' end end @@ -102,7 +102,7 @@ def destroy protected def default_breadcrumb - if action_name == "index" + if action_name == 'index' t(:label_color_plural) else ActionController::Base.helpers.link_to(t(:label_color_plural), colors_path) diff --git a/app/controllers/concerns/accounts/authentication_stages.rb b/app/controllers/concerns/accounts/authentication_stages.rb index 1d2dbb19b743..c2524f58e16d 100644 --- a/app/controllers/concerns/accounts/authentication_stages.rb +++ b/app/controllers/concerns/accounts/authentication_stages.rb @@ -65,7 +65,7 @@ def stage_success else flash[:error] = I18n.t( :notice_auth_stage_wrong_stage, - expected: stage || "(none)", + expected: stage || '(none)', actual: params[:stage] ) @@ -119,7 +119,7 @@ def init_authentication_stages(after_activation:) session[:back_url] ||= params[:back_url] # Remember the autologin cookie decision - session[:autologin_requested] = params[:autologin] == "1" + session[:autologin_requested] = params[:autologin] == '1' stages end diff --git a/app/controllers/concerns/accounts/omniauth_login.rb b/app/controllers/concerns/accounts/omniauth_login.rb index efb866c89664..3e882cc5d017 100644 --- a/app/controllers/concerns/accounts/omniauth_login.rb +++ b/app/controllers/concerns/accounts/omniauth_login.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "uri" +require 'uri' ## # Intended to be used by the AccountController to handle omniauth logins @@ -47,10 +47,10 @@ module Accounts::OmniauthLogin end def omniauth_login - params[:back_url] = request.env["omniauth.origin"] if remember_back_url? + params[:back_url] = request.env['omniauth.origin'] if remember_back_url? # Extract auth info and perform check / login or activate user - auth_hash = request.env["omniauth.auth"] + auth_hash = request.env['omniauth.auth'] handle_omniauth_authentication(auth_hash) end @@ -75,7 +75,7 @@ def redirect_omniauth_register_modal(user, auth_hash) # Avoid remembering the back_url if we're coming from the login page def remember_back_url? - provided_back_url = request.env["omniauth.origin"] + provided_back_url = request.env['omniauth.origin'] return if provided_back_url.blank? account_routes = /\/(login|account)/ @@ -84,7 +84,7 @@ def remember_back_url? def show_error(error) flash[:error] = error - redirect_to action: "login" + redirect_to action: 'login' end def register_via_omniauth(session, user_attributes) @@ -93,7 +93,7 @@ def register_via_omniauth(session, user_attributes) def handle_omniauth_authentication(auth_hash, user_params: nil) call = ::Authentication::OmniauthService - .new(strategy: request.env["omniauth.strategy"], auth_hash:, controller: self) + .new(strategy: request.env['omniauth.strategy'], auth_hash:, controller: self) .call(user_params) if call.success? diff --git a/app/controllers/concerns/accounts/user_consent.rb b/app/controllers/concerns/accounts/user_consent.rb index e3beee7a7de0..a2603dfae3ef 100644 --- a/app/controllers/concerns/accounts/user_consent.rb +++ b/app/controllers/concerns/accounts/user_consent.rb @@ -34,7 +34,7 @@ module Accounts::UserConsent def consent if user_consent_required? && consenting_user&.consent_expired? - render "account/consent" + render 'account/consent' else consent_finished end @@ -51,12 +51,12 @@ def confirm_consent end def decline_consent - message = I18n.t("consent.decline_warning_message") + "\n" + message = I18n.t('consent.decline_warning_message') + "\n" message << if Setting.consent_decline_mail.present? - I18n.t("consent.contact_this_mail_address", mail_address: Setting.consent_decline_mail) + I18n.t('consent.contact_this_mail_address', mail_address: Setting.consent_decline_mail) else - I18n.t("consent.contact_your_administrator") + I18n.t('consent.contact_your_administrator') end flash[:error] = message @@ -77,7 +77,7 @@ def consent_finished end def reject_consent! - flash[:error] = I18n.t("consent.failure_message") + flash[:error] = I18n.t('consent.failure_message') redirect_to authentication_stage_failure_path :consent end end diff --git a/app/controllers/concerns/accounts/user_password_change.rb b/app/controllers/concerns/accounts/user_password_change.rb index 1ce7f02cbd4e..00ccee1b98bf 100644 --- a/app/controllers/concerns/accounts/user_password_change.rb +++ b/app/controllers/concerns/accounts/user_password_change.rb @@ -70,7 +70,7 @@ def flash_and_log_invalid_credentials(flash_now: true, is_logged_in: false) return end - flash_error_message(log_reason: "invalid credentials", flash_now:) do + flash_error_message(log_reason: 'invalid credentials', flash_now:) do if Setting.brute_force_block_after_failed_logins.to_i > 0 :notice_account_invalid_credentials_or_blocked else @@ -83,7 +83,7 @@ def render_password_change(user, message, show_user_name: false) flash[:error] = message unless message.nil? @user = user @username = user.login - render "my/password", locals: { show_user_name: } + render 'my/password', locals: { show_user_name: } end ## @@ -91,15 +91,15 @@ def render_password_change(user, message, show_user_name: false) def redirect_if_password_change_not_allowed(user) if user and not user.change_password_allowed? logger.warn "Password change for user '#{user}' forced, but user is not allowed " + - "to change password" + 'to change password' flash[:error] = I18n.t(:notice_can_t_change_password) - redirect_to action: "login" + redirect_to action: 'login' return true end false end - def flash_error_message(log_reason: "", flash_now: true) + def flash_error_message(log_reason: '', flash_now: true) flash_hash = flash_now ? flash.now : flash logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} " \ diff --git a/app/controllers/concerns/auth_source_sso.rb b/app/controllers/concerns/auth_source_sso.rb index 3147ffa84455..dbfaef94258e 100644 --- a/app/controllers/concerns/auth_source_sso.rb +++ b/app/controllers/concerns/auth_source_sso.rb @@ -103,7 +103,7 @@ def get_validated_login!(value) def extract_from_header(value) if header_secret.present? valid_secret = value.end_with?(":#{header_secret}") - login = value.gsub(/:#{Regexp.escape(header_secret)}\z/, "") + login = value.gsub(/:#{Regexp.escape(header_secret)}\z/, '') [login, valid_secret] else diff --git a/app/controllers/concerns/layout.rb b/app/controllers/concerns/layout.rb index 47b8057307ca..c1efaadd2374 100644 --- a/app/controllers/concerns/layout.rb +++ b/app/controllers/concerns/layout.rb @@ -36,7 +36,7 @@ def layout_non_or_no_menu elsif @project true else - "no_menu" + 'no_menu' end end diff --git a/app/controllers/concerns/member_helper.rb b/app/controllers/concerns/member_helper.rb index 701b5b237721..93f15002b4e7 100644 --- a/app/controllers/concerns/member_helper.rb +++ b/app/controllers/concerns/member_helper.rb @@ -88,7 +88,7 @@ def transform_array_of_comma_separated_ids(array) return array if array.blank? each_comma_separated(array) do |elem| - elem.to_s.split(",") + elem.to_s.split(',') end end diff --git a/app/controllers/concerns/user_invitation.rb b/app/controllers/concerns/user_invitation.rb index 9d33dfaacdf6..f95192f48ff5 100644 --- a/app/controllers/concerns/user_invitation.rb +++ b/app/controllers/concerns/user_invitation.rb @@ -30,11 +30,11 @@ module UserInvitation module Events class << self def user_invited - "user_invited" + 'user_invited' end def user_reinvited - "user_reinvited" + 'user_reinvited' end end end diff --git a/app/controllers/custom_actions_controller.rb b/app/controllers/custom_actions_controller.rb index a676ef0410f9..50a017ce0247 100644 --- a/app/controllers/custom_actions_controller.rb +++ b/app/controllers/custom_actions_controller.rb @@ -35,7 +35,7 @@ class CustomActionsController < ApplicationController before_action :find_model_object, only: %i(edit update destroy) before_action :pad_params, only: %i(create update) - layout "admin" + layout 'admin' def index @custom_actions = CustomAction.order_by_position @@ -86,12 +86,12 @@ def require_enterprise_token return if EnterpriseToken.allows_to?(:custom_actions) if request.get? - render template: "common/upsale", + render template: 'common/upsale', locals: { - feature_title: I18n.t("custom_actions.upsale.title"), - feature_description: I18n.t("custom_actions.upsale.description"), - feature_reference: "custom_actions_admin", - feature_video: "enterprise/custom-actions.mp4" + feature_title: I18n.t('custom_actions.upsale.title'), + feature_description: I18n.t('custom_actions.upsale.description'), + feature_reference: 'custom_actions_admin', + feature_video: 'enterprise/custom-actions.mp4' } else render_403 @@ -110,10 +110,10 @@ def pad_params end def default_breadcrumb - if action_name == "index" - t("custom_actions.plural") + if action_name == 'index' + t('custom_actions.plural') else - ActionController::Base.helpers.link_to(t("custom_actions.plural"), custom_actions_path) + ActionController::Base.helpers.link_to(t('custom_actions.plural'), custom_actions_path) end end diff --git a/app/controllers/custom_styles_controller.rb b/app/controllers/custom_styles_controller.rb index 692a06ec23f1..3eacc1d00a7d 100644 --- a/app/controllers/custom_styles_controller.rb +++ b/app/controllers/custom_styles_controller.rb @@ -27,7 +27,7 @@ #++ class CustomStylesController < ApplicationController - layout "admin" + layout 'admin' menu_item :custom_style before_action :require_admin, @@ -154,7 +154,7 @@ def show_local_breadcrumb def options_for_theme_select options = OpenProject::CustomStyles::ColorThemes.themes.pluck(:theme) unless @current_theme.present? - options << [t("admin.custom_styles.color_theme_custom"), "", + options << [t('admin.custom_styles.color_theme_custom'), '', { selected: true, disabled: true }] end @@ -197,6 +197,7 @@ def file_delete(remove_method) end @custom_style.send(remove_method) + @custom_style.save redirect_to custom_style_path end end diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 836b5896ba49..ef36a889c0c6 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -28,7 +28,7 @@ class EnterprisesController < ApplicationController include EnterpriseTrialHelper - layout "admin" + layout 'admin' menu_item :enterprise before_action :chargebee_content_security_policy diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb index 8cc2a55280e0..6dee9f4253fe 100644 --- a/app/controllers/enumerations_controller.rb +++ b/app/controllers/enumerations_controller.rb @@ -27,7 +27,7 @@ #++ class EnumerationsController < ApplicationController - layout "admin" + layout 'admin' before_action :require_admin before_action :find_enumeration, only: %i[edit update move destroy] @@ -56,9 +56,9 @@ def create if @enumeration.save flash[:notice] = I18n.t(:notice_successful_create) - redirect_to action: "index", type: @enumeration.type + redirect_to action: 'index', type: @enumeration.type else - render action: "new" + render action: 'new' end end @@ -70,7 +70,7 @@ def update flash[:notice] = I18n.t(:notice_successful_update) redirect_to enumerations_path(type: @enumeration.type) else - render action: "edit" + render action: 'edit' end end @@ -78,12 +78,12 @@ def destroy if !@enumeration.in_use? # No associated objects @enumeration.destroy - redirect_to action: "index" + redirect_to action: 'index' return elsif params[:reassign_to_id] if reassign_to = @enumeration.class.find_by(id: params[:reassign_to_id]) @enumeration.destroy(reassign_to) - redirect_to action: "index" + redirect_to action: 'index' return end end @@ -96,14 +96,14 @@ def move redirect_to enumerations_path else flash.now[:error] = I18n.t(:error_type_could_not_be_saved) - render action: "edit" + render action: 'edit' end end protected def default_breadcrumb - if action_name == "index" + if action_name == 'index' t(:label_enumerations) else ActionController::Base.helpers.link_to(t(:label_enumerations), enumerations_path) diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb index aa7d59807d0e..d67db8c46e18 100644 --- a/app/controllers/errors_controller.rb +++ b/app/controllers/errors_controller.rb @@ -26,6 +26,6 @@ def error_options end def use_layout - "only_logo" + 'only_logo' end end diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb index f28372d7d7fb..b7795a503b42 100644 --- a/app/controllers/forums_controller.rb +++ b/app/controllers/forums_controller.rb @@ -47,26 +47,26 @@ def index end def show - sort_init "updated_at", "desc" - sort_update "created_at" => "#{Message.table_name}.created_at", - "replies" => "#{Message.table_name}.replies_count", - "updated_at" => "#{Message.table_name}.updated_at" + sort_init 'updated_at', 'desc' + sort_update 'created_at' => "#{Message.table_name}.created_at", + 'replies' => "#{Message.table_name}.replies_count", + 'updated_at' => "#{Message.table_name}.updated_at" respond_to do |format| format.html do set_topics @message = Message.new - render action: "show", layout: !request.xhr? + render action: 'show', layout: !request.xhr? end format.json do set_topics - render template: "messages/index" + render template: 'messages/index' end format.atom do @messages = @forum .messages - .order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(", ")) + .order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(', ')) .includes(:author, :forum) .limit(Setting.feeds_limit.to_i) @@ -78,7 +78,7 @@ def show def set_topics @topics = @forum .topics - .order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(", ")) + .order(["#{Message.table_name}.sticked_on ASC", sort_clause].compact.join(', ')) .includes(:author, last_reply: :author) .page(page_param) .per_page(per_page_param) @@ -91,7 +91,7 @@ def edit; end def create if @forum.save flash[:notice] = I18n.t(:notice_successful_create) - redirect_to action: "index" + redirect_to action: 'index' else render :new end @@ -100,7 +100,7 @@ def create def update if @forum.update(permitted_params.forum) flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "index" + redirect_to action: 'index' else render :edit end @@ -110,16 +110,16 @@ def move if @forum.update(permitted_params.forum_move) flash[:notice] = t(:notice_successful_update) else - flash.now[:error] = t("forum_could_not_be_saved") - render action: "edit" + flash.now[:error] = t('forum_could_not_be_saved') + render action: 'edit' end - redirect_to action: "index" + redirect_to action: 'index' end def destroy @forum.destroy flash[:notice] = I18n.t(:notice_successful_delete) - redirect_to action: "index" + redirect_to action: 'index' end private diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index c305bb1c7f78..ddd33e3cade7 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -28,19 +28,19 @@ class GroupsController < ApplicationController include GroupsHelper - layout "admin" + layout 'admin' before_action :require_admin, except: %i[show] before_action :find_group, only: %i[destroy update show create_memberships destroy_membership edit_membership add_users] def index - @groups = Group.order(Arel.sql("lastname ASC")) + @groups = Group.order(Arel.sql('lastname ASC')) end def show @group_users = group_members - render layout: "no_menu" + render layout: 'no_menu' end def new @@ -75,7 +75,7 @@ def update flash[:notice] = I18n.t(:notice_successful_update) redirect_to(groups_path) else - render action: "edit" + render action: 'edit' end end @@ -135,7 +135,7 @@ def destroy_membership .call flash[:notice] = I18n.t :notice_successful_delete - redirect_to controller: "/groups", action: "edit", id: @group, tab: redirected_to_tab(member) + redirect_to controller: '/groups', action: 'edit', id: @group, tab: redirected_to_tab(member) end protected @@ -158,10 +158,10 @@ def visible_group_members? end def default_breadcrumb - if action_name == "index" || !current_user.admin? - t("label_group_plural") + if action_name == 'index' || !current_user.admin? + t('label_group_plural') else - ActionController::Base.helpers.link_to(t("label_group_plural"), groups_path) + ActionController::Base.helpers.link_to(t('label_group_plural'), groups_path) end end @@ -176,14 +176,14 @@ def respond_membership_altered(service_call) flash[:error] = service_call.errors.full_messages.join("\n") end - redirect_to controller: "/groups", action: "edit", id: @group, tab: redirected_to_tab(service_call.result) + redirect_to controller: '/groups', action: 'edit', id: @group, tab: redirected_to_tab(service_call.result) end def redirected_to_tab(membership) if membership.project - "memberships" + 'memberships' else - "global_roles" + 'global_roles' end end @@ -194,6 +194,6 @@ def respond_users_altered(service_call) service_call.apply_flash_message!(flash) end - redirect_to controller: "/groups", action: "edit", id: @group, tab: "users" + redirect_to controller: '/groups', action: 'edit', id: @group, tab: 'users' end end diff --git a/app/controllers/highlighting_controller.rb b/app/controllers/highlighting_controller.rb index 6cd953a7f8f6..4a19f32904e1 100644 --- a/app/controllers/highlighting_controller.rb +++ b/app/controllers/highlighting_controller.rb @@ -36,8 +36,8 @@ def styles expires_in 1.year, public: true, must_revalidate: false if stale?(last_modified: Time.zone.parse(@max_updated_at), etag: @highlight_version_tag, public: true) - OpenProject::Cache.fetch("highlighting/styles", @highlight_version_tag) do - render template: "highlighting/styles", formats: [:css] + OpenProject::Cache.fetch('highlighting/styles', @highlight_version_tag) do + render template: 'highlighting/styles', formats: [:css] end end end diff --git a/app/controllers/homescreen_controller.rb b/app/controllers/homescreen_controller.rb index c4a3b1c53e57..686c1434e39f 100644 --- a/app/controllers/homescreen_controller.rb +++ b/app/controllers/homescreen_controller.rb @@ -29,7 +29,7 @@ class HomescreenController < ApplicationController skip_before_action :check_if_login_required, only: [:robots] - layout "global" + layout 'global' def index @newest_projects = Project.visible.newest.take(3) @@ -46,7 +46,7 @@ def index def robots if Setting.login_required? - render template: "homescreen/robots-login-required", format: :text + render template: 'homescreen/robots-login-required', format: :text else @projects = Project.active.public_projects end diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index 391c70863e12..c1725f4bdbc2 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -40,7 +40,7 @@ class JournalsController < ApplicationController def index @query = retrieve_query(@project) - sort_init "id", "desc" + sort_init 'id', 'desc' sort_update(@query.sortable_key_by_column_name) if @query.valid? @@ -51,7 +51,7 @@ def index respond_to do |format| format.atom do render layout: false, - content_type: "application/atom+xml", + content_type: 'application/atom+xml', locals: { title: journals_index_title, journals: @journals } end @@ -67,13 +67,13 @@ def diff return render_400 message: I18n.t(:error_journal_attribute_not_present, attribute: field_param) end - @activity_page = params["activity_page"] + @activity_page = params['activity_page'] @diff = Redmine::Helpers::Diff.new(to, from) respond_to do |format| format.html format.js do - render partial: "diff", locals: { diff: @diff } + render partial: 'diff', locals: { diff: @diff } end end end @@ -90,8 +90,8 @@ def find_journal def ensure_permitted permission = case @journal.journable_type - when "WorkPackage" then :view_work_packages - when "Project" then :view_project + when 'WorkPackage' then :view_work_packages + when 'Project' then :view_project end do_authorize(permission) diff --git a/app/controllers/ldap_auth_sources_controller.rb b/app/controllers/ldap_auth_sources_controller.rb index 172a358af681..286329269deb 100644 --- a/app/controllers/ldap_auth_sources_controller.rb +++ b/app/controllers/ldap_auth_sources_controller.rb @@ -29,7 +29,7 @@ class LdapAuthSourcesController < ApplicationController menu_item :ldap_authentication include PaginationHelper - layout "admin" + layout 'admin' before_action :require_admin before_action :block_if_password_login_disabled @@ -55,9 +55,9 @@ def create @ldap_auth_source = LdapAuthSource.new permitted_params.ldap_auth_source if @ldap_auth_source.save flash[:notice] = I18n.t(:notice_successful_create) - redirect_to action: "index" + redirect_to action: 'index' else - render "new" + render 'new' end end @@ -68,9 +68,9 @@ def update if @ldap_auth_source.update updated flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "index" + redirect_to action: 'index' else - render "edit" + render 'edit' end end @@ -82,7 +82,7 @@ def test_connection rescue StandardError => e flash[:error] = I18n.t(:error_unable_to_connect, value: e.message) end - redirect_to action: "index" + redirect_to action: 'index' end def destroy @@ -94,7 +94,7 @@ def destroy else flash[:warning] = t(:notice_wont_delete_auth_source) end - redirect_to action: "index" + redirect_to action: 'index' end protected @@ -107,7 +107,7 @@ def prevent_editing_when_seeded end def default_breadcrumb - if action_name == "index" + if action_name == 'index' t(:label_ldap_auth_source_plural) else ActionController::Base.helpers.link_to(t(:label_ldap_auth_source_plural), ldap_auth_sources_path) diff --git a/app/controllers/members/menus_controller.rb b/app/controllers/members/menus_controller.rb index ab205fc3aff0..6d0aeca4cc65 100644 --- a/app/controllers/members/menus_controller.rb +++ b/app/controllers/members/menus_controller.rb @@ -45,13 +45,13 @@ def first_level_menu_items def user_status_options [ - OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.all"), + OpenProject::Menu::MenuItem.new(title: I18n.t('members.menu.all'), href: project_members_path, selected: active_filter_count == 0), - OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.locked"), + OpenProject::Menu::MenuItem.new(title: I18n.t('members.menu.locked'), href: project_members_path(status: :locked), selected: selected?(:status, :locked)), - OpenProject::Menu::MenuItem.new(title: I18n.t("members.menu.invited"), + OpenProject::Menu::MenuItem.new(title: I18n.t('members.menu.invited'), href: project_members_path(status: :invited), selected: selected?(:status, :invited)) ] @@ -59,9 +59,9 @@ def user_status_options def nested_menu_items [ - OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.project_roles"), children: project_roles_entries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.wp_shares"), children: permission_menu_entries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("members.menu.groups"), children: project_group_entries) + OpenProject::Menu::MenuGroup.new(header: I18n.t('members.menu.project_roles'), children: project_roles_entries), + OpenProject::Menu::MenuGroup.new(header: I18n.t('members.menu.wp_shares'), children: permission_menu_entries), + OpenProject::Menu::MenuGroup.new(header: I18n.t('members.menu.groups'), children: project_group_entries) ] end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index efe9fcb66f33..24937ec88998 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -57,7 +57,7 @@ def show .per_page(per_page_param) @reply = Message.new(subject: "RE: #{@message.subject}", parent: @topic, forum: @topic.forum) - render action: "show", layout: !request.xhr? + render action: 'show', layout: !request.xhr? end # new topic @@ -87,7 +87,7 @@ def create redirect_to topic_path(@message) else - render action: "new" + render action: 'new' end end @@ -116,7 +116,7 @@ def update @message.reload redirect_to topic_path(@message.root, r: @message.parent_id && @message.id) else - render action: "edit" + render action: 'edit' end end @@ -128,9 +128,9 @@ def destroy @message.destroy flash[:notice] = t(:notice_successful_delete) redirect_target = if @message.parent.nil? - { controller: "/forums", action: "show", project_id: @project, id: @forum } + { controller: '/forums', action: 'show', project_id: @project, id: @forum } else - { action: "show", id: @message.parent, r: @message } + { action: 'show', id: @message.parent, r: @message } end redirect_to redirect_target @@ -140,10 +140,10 @@ def quote user = @message.author text = @message.content subject = @message.subject - subject = "RE: #{subject}" unless subject.starts_with?("RE:") + subject = "RE: #{subject}" unless subject.starts_with?('RE:') user_wrote = I18n.t(:text_user_wrote, value: ERB::Util.html_escape(user), locale: Setting.default_language) content = "#{user_wrote}\n> " - content << (text.to_s.strip.gsub(%r{

    (.+?)
    }m, "[...]").gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n") + content << (text.to_s.strip.gsub(%r{
    (.+?)
    }m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n") respond_to do |format| format.json { render json: { subject:, content: } } diff --git a/app/controllers/my/auto_login_tokens_controller.rb b/app/controllers/my/auto_login_tokens_controller.rb index 21de9f6f2214..058012090196 100644 --- a/app/controllers/my/auto_login_tokens_controller.rb +++ b/app/controllers/my/auto_login_tokens_controller.rb @@ -2,7 +2,7 @@ module My class AutoLoginTokensController < ::ApplicationController before_action :find_token, only: %i(destroy) - layout "my" + layout 'my' menu_item :sessions def destroy diff --git a/app/controllers/my/sessions_controller.rb b/app/controllers/my/sessions_controller.rb index b243be219a6d..7d244f9549bf 100644 --- a/app/controllers/my/sessions_controller.rb +++ b/app/controllers/my/sessions_controller.rb @@ -6,7 +6,7 @@ class SessionsController < ::ApplicationController before_action :find_model_object, only: %i(show destroy) before_action :prevent_current_session_deletion, only: %i(destroy) - layout "my" + layout 'my' menu_item :sessions def index @@ -18,7 +18,7 @@ def index .for_user(current_user) .order(expires_on: :asc) - token = cookies[OpenProject::Configuration["autologin_cookie_name"]] + token = cookies[OpenProject::Configuration['autologin_cookie_name']] if token @current_token = @autologin_tokens.find_by_plaintext_value(token) # rubocop:disable Rails/DynamicFindBy end @@ -37,7 +37,7 @@ def destroy def prevent_current_session_deletion if @session.current?(session) - render_400 message: I18n.t("users.sessions.may_not_delete_current") + render_400 message: I18n.t('users.sessions.may_not_delete_current') end end end diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb index 92d31cf6c088..56f9b39854ce 100644 --- a/app/controllers/news_controller.rb +++ b/app/controllers/news_controller.rb @@ -77,9 +77,9 @@ def create @news.attributes = permitted_params.news if @news.save flash[:notice] = I18n.t(:notice_successful_create) - redirect_to controller: "/news", action: "index", project_id: @project + redirect_to controller: '/news', action: 'index', project_id: @project else - render action: "new" + render action: 'new' end end @@ -87,16 +87,16 @@ def update @news.attributes = permitted_params.news if @news.save flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "show", id: @news + redirect_to action: 'show', id: @news else - render action: "edit" + render action: 'edit' end end def destroy @news.destroy flash[:notice] = I18n.t(:notice_successful_delete) - redirect_to action: "index", project_id: @project + redirect_to action: 'index', project_id: @project end private diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb index d77870eb8019..11610214d967 100644 --- a/app/controllers/oauth/applications_controller.rb +++ b/app/controllers/oauth/applications_controller.rb @@ -32,7 +32,7 @@ class ApplicationsController < ::ApplicationController before_action :new_app, only: %i[new create] before_action :find_app, only: %i[edit update show destroy] - layout "admin" + layout 'admin' menu_item :oauth_applications def index @@ -87,10 +87,10 @@ def destroy protected def default_breadcrumb - if action_name == "index" - t("oauth.application.plural") + if action_name == 'index' + t('oauth.application.plural') else - ActionController::Base.helpers.link_to(t("oauth.application.plural"), oauth_applications_path) + ActionController::Base.helpers.link_to(t('oauth.application.plural'), oauth_applications_path) end end diff --git a/app/controllers/oauth/auth_base_controller.rb b/app/controllers/oauth/auth_base_controller.rb index 1428e5230193..7da92dbfe624 100644 --- a/app/controllers/oauth/auth_base_controller.rb +++ b/app/controllers/oauth/auth_base_controller.rb @@ -37,7 +37,7 @@ class AuthBaseController < ::ApplicationController prepend_before_action :extend_content_security_policy skip_before_action :check_if_login_required - layout "only_logo" + layout 'only_logo' def extend_content_security_policy return unless pre_auth&.authorizable? @@ -51,13 +51,13 @@ def extend_content_security_policy def application_http_redirect_uris registered_redirect_uris - .select { |url| url.start_with?("http") } - .map { |url| URI.join(url, "/").to_s } + .select { |url| url.start_with?('http') } + .map { |url| URI.join(url, '/').to_s } end def application_native_redirect_uris registered_redirect_uris - .reject { |url| url.start_with?("http", "urn") } + .reject { |url| url.start_with?('http', 'urn') } .map(&method(:parse_native_redirect_uri)) .compact end diff --git a/app/controllers/oauth/grants_controller.rb b/app/controllers/oauth/grants_controller.rb index e38afe156b12..de59afa3ab57 100644 --- a/app/controllers/oauth/grants_controller.rb +++ b/app/controllers/oauth/grants_controller.rb @@ -30,7 +30,7 @@ module OAuth class GrantsController < ::ApplicationController before_action :require_login - layout "my" + layout 'my' menu_item :access_token def index @@ -49,8 +49,8 @@ def revoke_application current_user ) - flash[:notice] = I18n.t("oauth.grants.successful_application_revocation", application_name: application.name) - redirect_to controller: "/my", action: :access_token + flash[:notice] = I18n.t('oauth.grants.successful_application_revocation', application_name: application.name) + redirect_to controller: '/my', action: :access_token end private diff --git a/app/controllers/placeholder_users/memberships_controller.rb b/app/controllers/placeholder_users/memberships_controller.rb index b75532b9a878..346c8d91edbd 100644 --- a/app/controllers/placeholder_users/memberships_controller.rb +++ b/app/controllers/placeholder_users/memberships_controller.rb @@ -28,7 +28,7 @@ class PlaceholderUsers::MembershipsController < ApplicationController include IndividualPrincipals::MembershipControllerMethods - layout "admin" + layout 'admin' before_action :authorize_global before_action :find_individual_principal @@ -40,6 +40,6 @@ def find_individual_principal end def redirected_to_tab(_membership) - "memberships" + 'memberships' end end diff --git a/app/controllers/placeholder_users_controller.rb b/app/controllers/placeholder_users_controller.rb index 8ec919515c30..06ad095d445a 100644 --- a/app/controllers/placeholder_users_controller.rb +++ b/app/controllers/placeholder_users_controller.rb @@ -28,7 +28,7 @@ class PlaceholderUsersController < ApplicationController include EnterpriseTrialHelper - layout "admin" + layout 'admin' before_action :authorize_global, except: %i[show] before_action :find_placeholder_user, only: %i[show @@ -60,7 +60,7 @@ def show .where(id: Member.visible(current_user)) respond_to do |format| - format.html { render layout: "no_menu" } + format.html { render layout: 'no_menu' } end end @@ -153,20 +153,20 @@ def find_placeholder_user def authorize_deletion unless helpers.can_delete_placeholder_user?(@placeholder_user, current_user) - render_403 message: I18n.t("placeholder_users.right_to_manage_members_missing") + render_403 message: I18n.t('placeholder_users.right_to_manage_members_missing') end end def default_breadcrumb - if action_name == "index" - t("label_placeholder_user_plural") + if action_name == 'index' + t('label_placeholder_user_plural') else - ActionController::Base.helpers.link_to(t("label_placeholder_user_plural"), + ActionController::Base.helpers.link_to(t('label_placeholder_user_plural'), placeholder_users_path) end end def show_local_breadcrumb - action_name != "show" + action_name != 'show' end end diff --git a/app/controllers/projects/archive_controller.rb b/app/controllers/projects/archive_controller.rb index b18c6f86c44c..5ac441fa9c8d 100644 --- a/app/controllers/projects/archive_controller.rb +++ b/app/controllers/projects/archive_controller.rb @@ -48,7 +48,7 @@ def change_status_action(status) redirect_to(projects_path) else flash[:error] = t(:"error_can_not_#{status}_project", - errors: service_call.errors.full_messages.join(", ")) + errors: service_call.errors.full_messages.join(', ')) redirect_back fallback_location: projects_path end end diff --git a/app/controllers/projects/identifier_controller.rb b/app/controllers/projects/identifier_controller.rb index 5178dc0e94bf..9d640988e907 100644 --- a/app/controllers/projects/identifier_controller.rb +++ b/app/controllers/projects/identifier_controller.rb @@ -42,7 +42,7 @@ def update flash[:notice] = I18n.t(:notice_successful_update) redirect_to project_settings_general_path(@project) else - render action: "show" + render action: 'show' end end end diff --git a/app/controllers/projects/menus_controller.rb b/app/controllers/projects/menus_controller.rb index 78281abee108..9a99912c0168 100644 --- a/app/controllers/projects/menus_controller.rb +++ b/app/controllers/projects/menus_controller.rb @@ -41,9 +41,9 @@ def first_level_menu_items [ OpenProject::Menu::MenuGroup.new(header: nil, children: static_filters), - OpenProject::Menu::MenuGroup.new(header: I18n.t(:"projects.lists.my_private"), + OpenProject::Menu::MenuGroup.new(header: I18n.t(:'projects.lists.my_private'), children: my_filters), - OpenProject::Menu::MenuGroup.new(header: I18n.t(:"activerecord.attributes.project.status_code"), + OpenProject::Menu::MenuGroup.new(header: I18n.t(:'activerecord.attributes.project.status_code'), children: static_status_filters) ] end diff --git a/app/controllers/projects/queries_controller.rb b/app/controllers/projects/queries_controller.rb index b1e2d162eb79..35d87f7c9225 100644 --- a/app/controllers/projects/queries_controller.rb +++ b/app/controllers/projects/queries_controller.rb @@ -39,8 +39,8 @@ class Projects::QueriesController < ApplicationController end def new - render template: "/projects/index", - layout: "global", + render template: '/projects/index', + layout: 'global', locals: { query: @query, state: :edit } end @@ -52,8 +52,8 @@ def create if call.success? redirect_to projects_path(query_id: call.result.id) else - render template: "/projects/index", - layout: "global", + render template: '/projects/index', + layout: 'global', locals: { query: call.result, state: :edit } end end diff --git a/app/controllers/projects/settings/custom_fields_controller.rb b/app/controllers/projects/settings/custom_fields_controller.rb index 25cbac60b795..03f6a1acacaa 100644 --- a/app/controllers/projects/settings/custom_fields_controller.rb +++ b/app/controllers/projects/settings/custom_fields_controller.rb @@ -30,7 +30,7 @@ class Projects::Settings::CustomFieldsController < Projects::SettingsController menu_item :settings_custom_fields def show - @wp_custom_fields = WorkPackageCustomField.order("lower(name)") + @wp_custom_fields = WorkPackageCustomField.order('lower(name)') end def update @@ -39,7 +39,7 @@ def update flash[:notice] = t(:notice_successful_update) else flash[:error] = t(:notice_project_cannot_update_custom_fields, - errors: @project.errors.full_messages.join(", ")) + errors: @project.errors.full_messages.join(', ')) raise ActiveRecord::Rollback end end diff --git a/app/controllers/projects/settings/modules_controller.rb b/app/controllers/projects/settings/modules_controller.rb index c7f3dc070e10..1ef457ae26d1 100644 --- a/app/controllers/projects/settings/modules_controller.rb +++ b/app/controllers/projects/settings/modules_controller.rb @@ -39,7 +39,7 @@ def update redirect_to project_settings_modules_path(@project) else - render "show" + render 'show' end end end diff --git a/app/controllers/projects/templated_controller.rb b/app/controllers/projects/templated_controller.rb index c59e7c033144..6f74a5a77cc5 100644 --- a/app/controllers/projects/templated_controller.rb +++ b/app/controllers/projects/templated_controller.rb @@ -50,7 +50,7 @@ def change_templated_action(templated) flash[:notice] = t(:notice_successful_update) else messages = [ - t("activerecord.errors.template.header", model: Project.model_name.human, count: service_call.errors.count), + t('activerecord.errors.template.header', model: Project.model_name.human, count: service_call.errors.count), service_call.message ] diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 94e4281e5aef..de4617468a01 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -53,7 +53,7 @@ def index format.html do flash.now[:error] = @query.errors.full_messages if @query.errors.any? - render layout: "global", locals: { query: @query, state: :show } + render layout: 'global', locals: { query: @query, state: :show } end format.any(*supported_export_formats) do @@ -63,7 +63,7 @@ def index end def new - render layout: "no_menu" + render layout: 'no_menu' end def copy @@ -77,9 +77,9 @@ def destroy .call if service_call.success? - flash[:notice] = I18n.t("projects.delete.scheduled") + flash[:notice] = I18n.t('projects.delete.scheduled') else - flash[:error] = I18n.t("projects.delete.schedule_failed", errors: service_call.errors.full_messages.join("\n")) + flash[:error] = I18n.t('projects.delete.schedule_failed', errors: service_call.errors.full_messages.join("\n")) end redirect_to projects_path @@ -118,7 +118,7 @@ def export_list(query, mime_type) query: query.to_hash ) - if request.headers["Accept"]&.include?("application/json") + if request.headers['Accept']&.include?('application/json') render json: { job_id: job.job_id } else redirect_to job_status_path(job.job_id) diff --git a/app/controllers/queries/params_parser.rb b/app/controllers/queries/params_parser.rb index d93e5747b025..301d2dd15deb 100644 --- a/app/controllers/queries/params_parser.rb +++ b/app/controllers/queries/params_parser.rb @@ -49,7 +49,7 @@ def parse_orders_from_params(params) .to_h .map { |k, v| { attribute: k, direction: v } } rescue JSON::ParserError - [{ attribute: "invalid", direction: "asc" }] + [{ attribute: 'invalid', direction: 'asc' }] end def parse_columns_from_params(params) @@ -86,7 +86,7 @@ def parse_filter def consume_ampersand case @buffer.peek(1) - when "&", /\s/ + when '&', /\s/ @buffer.getch consume_ampersand end @@ -106,9 +106,9 @@ def parse_values parse_doublequoted_value when "'" parse_singlequoted_value - when "[" + when '[' parse_array_value - when "&" + when '&' [] else parse_unguarded_value @@ -128,7 +128,7 @@ def parse_singlequoted_value def parse_unguarded_value value = @buffer .scan_until(/&|\z/) - .delete_suffix("&") + .delete_suffix('&') [value] end @@ -136,8 +136,8 @@ def parse_unguarded_value def parse_array_value @buffer .scan_until(/]|\z/) - .delete_suffix("]") - .delete_prefix("[") + .delete_suffix(']') + .delete_prefix('[') .scan(/(?:'([^']*)')|(?:"([^"]*)")/) .flatten .compact diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 741493d32a1b..08cb4596df0c 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "SVG/Graph/Bar" -require "SVG/Graph/BarHorizontal" -require "digest/sha1" +require 'SVG/Graph/Bar' +require 'SVG/Graph/BarHorizontal' +require 'digest/sha1' class ChangesetNotFound < StandardError end @@ -63,7 +63,7 @@ def show if request.xhr? if @entries && @repository.valid? - render(partial: "dir_list_content") + render(partial: 'dir_list_content') else render(nothing: true) end @@ -72,7 +72,7 @@ def show else @changesets = @repository.latest_changesets(@path, @rev) @properties = @repository.properties(@path, @rev) - render action: "show" + render action: 'show' end end @@ -80,8 +80,8 @@ def create service = SCM::RepositoryFactoryService.new(@project, params) if service.build_and_save @repository = service.repository - flash[:notice] = I18n.t("repositories.create_successful") - flash[:notice] << (" " + I18n.t("repositories.create_managed_delay")) if @repository.managed? + flash[:notice] = I18n.t('repositories.create_successful') + flash[:notice] << (' ' + I18n.t('repositories.create_managed_delay')) if @repository.managed? else flash[:error] = service.build_error end @@ -111,7 +111,7 @@ def committers h end flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "committers", project_id: @project + redirect_to action: 'committers', project_id: @project end end @@ -123,7 +123,7 @@ def destroy_info def destroy repository = @project.repository if repository.destroy - flash[:notice] = I18n.t("repositories.delete_sucessful") + flash[:notice] = I18n.t('repositories.delete_sucessful') else flash[:error] = repository.errors.full_messages end @@ -146,7 +146,7 @@ def changes @properties = @repository.properties(@path, @rev) @changeset = @repository.find_changeset_by_name(@rev) - render "changes", formats: [:html] + render 'changes', formats: [:html] end def revisions @@ -203,7 +203,7 @@ def annotate @annotate = @repository.scm.annotate(@path, @rev) @changeset = @repository.find_changeset_by_name(@rev) - render "annotate", formats: [:html] + render 'annotate', formats: [:html] end def revision @@ -221,7 +221,7 @@ def revision end def diff - if params[:format] == "diff" + if params[:format] == 'diff' @diff = @repository.diff(@path, @rev, @rev_to) unless @diff @@ -233,8 +233,8 @@ def diff filename << "_r#{@rev_to}" if @rev_to send_data @diff.join, filename: "#{filename}.diff", - type: "text/x-patch", - disposition: "attachment" + type: 'text/x-patch', + disposition: 'attachment' else @diff_type = diff_type_persisted @@ -250,7 +250,7 @@ def diff @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to) - render "diff", formats: :html + render 'diff', formats: :html end end @@ -264,9 +264,9 @@ def stats def graph data = nil case params[:graph] - when "commits_per_month" + when 'commits_per_month' data = graph_commits_per_month(@repository) - when "commits_per_author" + when 'commits_per_author' unless current_user.allowed_in_project?(:view_commit_author_statistics, @project) return deny_access end @@ -275,8 +275,8 @@ def graph end if data - headers["Content-Type"] = "image/svg+xml" - send_data(data, type: "image/svg+xml", disposition: "inline") + headers['Content-Type'] = 'image/svg+xml' + send_data(data, type: 'image/svg+xml', disposition: 'inline') else render_404 end @@ -290,7 +290,7 @@ def update_repository(repo_params) @repository.attributes = @repository.class.permitted_params(repo_params) if @repository.save - flash[:notice] = I18n.t("repositories.update_settings_successful") + flash[:notice] = I18n.t('repositories.update_settings_successful') else flash[:error] = @repository.errors.full_messages.join('\n') end @@ -306,7 +306,7 @@ def find_repository # Prepare checkout instructions # available on all pages (even empty!) - @path = params[:repo_path] || "" + @path = params[:repo_path] || '' @instructions = ::SCM::CheckoutInstructionsService.new(@repository, path: @path) # Asserts repository availability, or renders an appropriate error @@ -319,7 +319,7 @@ def find_repository raise InvalidRevisionParam end rescue OpenProject::SCM::Exceptions::SCMEmpty - render "empty" + render 'empty' rescue ActiveRecord::RecordNotFound render_404 rescue InvalidRevisionParam @@ -339,7 +339,7 @@ def graph_commits_per_month(repository) @date_from = @date_to << 11 @date_from = Date.civil(@date_from.year, @date_from.month, 1) commits_by_day = Changeset.where( - ["repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to] + ['repository_id = ? AND commit_date BETWEEN ? AND ?', repository.id, @date_from, @date_to] ).group(:commit_date).size commits_by_month = [0] * 12 commits_by_day.each do |c| @@ -389,7 +389,7 @@ def graph_commits_per_month(repository) end def graph_commits_per_author(repository) - commits_by_author = Changeset.where(["repository_id = ?", repository.id]).group(:committer).size + commits_by_author = Changeset.where(['repository_id = ?', repository.id]).group(:committer).size commits_by_author.to_a.sort_by!(&:last) changes_by_author = Change.includes(:changeset) @@ -406,12 +406,12 @@ def graph_commits_per_author(repository) commits_data = commits_by_author.map(&:last) changes_data = commits_by_author.map { |r| h[r.first] || 0 } - fields = fields + ([""] * (10 - fields.length)) if fields.length < 10 + fields = fields + ([''] * (10 - fields.length)) if fields.length < 10 commits_data = commits_data + ([0] * (10 - commits_data.length)) if commits_data.length < 10 changes_data = changes_data + ([0] * (10 - changes_data.length)) if changes_data.length < 10 # Remove email address in usernames - fields = fields.map { |c| c.gsub(%r{<.+@.+>}, "") } + fields = fields.map { |c| c.gsub(%r{<.+@.+>}, '') } graph = SVG::Graph::BarHorizontal.new( height: 400, @@ -440,14 +440,14 @@ def login_back_url_params end def raw_or_to_large_or_non_text(content, path) - params[:format] == "raw" || + params[:format] == 'raw' || (content.size && content.size > Setting.file_max_size_displayed.to_i.kilobyte) || !entry_text_data?(content, path) end def send_raw(content, path) # Force the download - send_opt = { filename: filename_for_content_disposition(path.split("/").last) } + send_opt = { filename: filename_for_content_disposition(path.split('/').last) } send_type = OpenProject::MimeType.of(path) send_opt[:type] = send_type.to_s if send_type send_data content, send_opt @@ -462,14 +462,14 @@ def render_text_entry # Forcing html format here to avoid # rails looking for e.g text when .txt is asked for - render "entry", formats: [:html] + render 'entry', formats: [:html] end def diff_type_persisted preferences = current_user.pref diff_type = params[:type] || preferences.diff_type - diff_type = "inline" unless %w(inline sbs).include?(diff_type) + diff_type = 'inline' unless %w(inline sbs).include?(diff_type) # Save diff type as user preference if current_user.logged? && diff_type != preferences.diff_type @@ -485,7 +485,7 @@ def entry_text_data?(ent, path) # It is very strict that file contains less than 30% of ascii symbols # in non Western Europe. # TODO: need to handle edge cases of non-binary content that isn't UTF-8 - OpenProject::MimeType.is_type?("text", path) || - ent.dup.force_encoding("UTF-8") == ent.dup.force_encoding("BINARY") + OpenProject::MimeType.is_type?('text', path) || + ent.dup.force_encoding('UTF-8') == ent.dup.force_encoding('BINARY') end end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index 893c26866539..3fd874957eee 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -29,7 +29,7 @@ class RolesController < ApplicationController include PaginationHelper - layout "admin" + layout 'admin' before_action :require_admin @@ -41,7 +41,7 @@ def index .page(page_param) .per_page(per_page_param) - render action: "index", layout: false if request.xhr? + render action: 'index', layout: false if request.xhr? end def new @@ -52,7 +52,7 @@ def new def edit @role = Role.find(params[:id]) - @call = set_role_attributes(@role, "update") + @call = set_role_attributes(@role, 'update') end def create @@ -61,11 +61,11 @@ def create if @call.success? flash[:notice] = t(:notice_successful_create) - redirect_to action: "index" + redirect_to action: 'index' else @roles = roles_scope - render action: "new" + render action: 'new' end end @@ -75,9 +75,9 @@ def update if @call.success? flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "index" + redirect_to action: 'index' else - render action: "edit" + render action: 'edit' end end @@ -92,7 +92,7 @@ def destroy else flash[:error] = I18n.t(:error_can_not_remove_role) end - redirect_to action: "index" + redirect_to action: 'index' end def report @@ -107,11 +107,11 @@ def bulk_update if calls.all?(&:success?) flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "index" + redirect_to action: 'index' else @calls = calls @permissions = OpenProject::AccessControl.permissions.reject(&:public?) - render action: "report" + render action: 'report' end end @@ -144,10 +144,10 @@ def roles_scope end def default_breadcrumb - if action_name == "index" - t("label_role_plural") + if action_name == 'index' + t('label_role_plural') else - ActionController::Base.helpers.link_to(t("label_role_plural"), roles_path) + ActionController::Base.helpers.link_to(t('label_role_plural'), roles_path) end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index dbdf68110eb1..c71ef05ecbd4 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -53,12 +53,12 @@ def index private def prepare_tokens - @question = search_params[:q] || "" + @question = search_params[:q] || '' @question.strip! @tokens = scan_query_tokens(@question).uniq unless @tokens.any? - @question = "" + @question = '' end end @@ -92,7 +92,7 @@ def limit_results_subsequent_page # extract tokens from the question # eg. hello "bye bye" => ["hello", "bye bye"] def scan_query_tokens(query) - tokens = query.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).map { |m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, "") } + tokens = query.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).map { |m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '') } # no more than 5 tokens to search for tokens.slice! 5..-1 if tokens.size > 5 @@ -111,9 +111,9 @@ def offset def projects_to_search case search_params[:scope] - when "all" + when 'all' nil - when "current_project" + when 'current_project' @project else @project ? @project.self_and_descendants.active : nil @@ -149,7 +149,7 @@ def search_types if projects_to_search.is_a? Project # don't search projects - types.delete("projects") + types.delete('projects') # only show what the user is allowed to view types = types.select { |o| User.current.allowed_in_project?(:"view_#{o}", projects_to_search) } end @@ -162,7 +162,7 @@ def search_classes scope = if scope.empty? search_types - elsif scope & ["work_packages"] == scope + elsif scope & ['work_packages'] == scope [] else scope @@ -176,7 +176,7 @@ def scope_class(scope) end def provision_gon - available_search_types = search_types.dup.push("all") + available_search_types = search_types.dup.push('all') gon.global_search = { search_term: @question, @@ -187,7 +187,7 @@ def provision_gon name: OpenProject::GlobalSearch.tab_name(search_type) } end, - current_tab: available_search_types.detect { |search_type| search_params[search_type] } || "all" + current_tab: available_search_types.detect { |search_type| search_params[search_type] } || 'all' } end end diff --git a/app/controllers/statuses_controller.rb b/app/controllers/statuses_controller.rb index a9c83c066ed8..38e24b96c080 100644 --- a/app/controllers/statuses_controller.rb +++ b/app/controllers/statuses_controller.rb @@ -29,7 +29,7 @@ class StatusesController < ApplicationController include PaginationHelper - layout "admin" + layout 'admin' before_action :require_admin @@ -37,7 +37,7 @@ def index @statuses = Status.page(page_param) .per_page(per_page_param) - render action: "index", layout: false if request.xhr? + render action: 'index', layout: false if request.xhr? end def new @@ -52,9 +52,9 @@ def create @status = Status.new(permitted_params.status) if @status.save flash[:notice] = I18n.t(:notice_successful_create) - redirect_to action: "index" + redirect_to action: 'index' else - render action: "new" + render action: 'new' end end @@ -62,9 +62,9 @@ def update @status = Status.find(params[:id]) if @status.update(permitted_params.status) flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "index" + redirect_to action: 'index' else - render action: "edit" + render action: 'edit' end end @@ -76,10 +76,10 @@ def destroy status.destroy flash[:notice] = I18n.t(:notice_successful_delete) end - redirect_to action: "index" + redirect_to action: 'index' rescue StandardError flash[:error] = I18n.t(:error_unable_delete_status) - redirect_to action: "index" + redirect_to action: 'index' end def update_work_package_done_ratio @@ -88,13 +88,13 @@ def update_work_package_done_ratio else flash[:error] = I18n.t(:error_work_package_done_ratios_not_updated) end - redirect_to action: "index" + redirect_to action: 'index' end protected def default_breadcrumb - if action_name == "index" + if action_name == 'index' t(:label_work_package_status_plural) else ActionController::Base.helpers.link_to(t(:label_work_package_status_plural), statuses_path) diff --git a/app/controllers/sys_controller.rb b/app/controllers/sys_controller.rb index e709ef3b705f..a94c13e4ea1f 100644 --- a/app/controllers/sys_controller.rb +++ b/app/controllers/sys_controller.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/repository_authentication" +require 'open_project/repository_authentication' class SysController < ActionController::Base before_action :check_enabled @@ -38,7 +38,7 @@ def projects p = Project.active.has_module(:repository) .includes(:repository) .references(:repositories) - .order(Arel.sql("identifier")) + .order(Arel.sql('identifier')) respond_to do |format| format.json do render json: p.to_json(include: :repository) @@ -50,7 +50,7 @@ def projects end def update_required_storage - result = update_storage_information(@repository, params[:force] == "1") + result = update_storage_information(@repository, params[:force] == '1') render plain: "Updated: #{result}", status: :ok end @@ -75,9 +75,9 @@ def fetch_changesets def repo_auth project = Project.find_by(identifier: params[:repository]) if project && authorized?(project, @authenticated_user) - render plain: "Access granted" + render plain: 'Access granted' else - render plain: "Not allowed", status: :forbidden # default to deny + render plain: 'Not allowed', status: :forbidden # default to deny end end @@ -96,7 +96,7 @@ def authorized?(project, user) def check_enabled User.current = nil unless Setting.sys_api_enabled? && params[:key].to_s == Setting.sys_api_key - render plain: "Access denied. Repository management WS is disabled or key is invalid.", + render plain: 'Access denied. Repository management WS is disabled or key is invalid.', status: :forbidden false end @@ -125,7 +125,7 @@ def find_repository_with_storage else return true if @repository.scm.storage_available? - render plain: "repositories.storage.not_available", status: :bad_request + render plain: 'repositories.storage.not_available', status: :bad_request end false @@ -137,8 +137,8 @@ def require_basic_auth return true if @authenticated_user end - response.headers["WWW-Authenticate"] = 'Basic realm="Repository Authentication"' - render plain: "Authorization required", status: :unauthorized + response.headers['WWW-Authenticate'] = 'Basic realm="Repository Authentication"' + render plain: 'Authorization required', status: :unauthorized false end @@ -155,10 +155,10 @@ def cached_user_login(username, password) user_id = Rails.cache.fetch(OpenProject::RepositoryAuthentication::CACHE_PREFIX + Digest::SHA1.hexdigest("#{username}#{password}"), expires_in: OpenProject::RepositoryAuthentication::CACHE_EXPIRES_AFTER) do user = user_login(username, password) - user ? user.id.to_s : "-1" + user ? user.id.to_s : '-1' end - return nil if user_id.blank? or user_id == "-1" + return nil if user_id.blank? or user_id == '-1' user || User.find_by(id: user_id.to_i) end diff --git a/app/controllers/types_controller.rb b/app/controllers/types_controller.rb index 224593c207b2..43be056024b2 100644 --- a/app/controllers/types_controller.rb +++ b/app/controllers/types_controller.rb @@ -29,7 +29,7 @@ class TypesController < ApplicationController include PaginationHelper - layout "admin" + layout 'admin' before_action :require_admin before_action :find_type, only: %i[update move destroy] @@ -73,7 +73,7 @@ def create call.on_failure do |result| flash[:error] = result.errors.full_messages.join("\n") load_projects_and_types - render action: "new" + render action: 'new' end end end @@ -99,7 +99,7 @@ def move redirect_to types_path else flash.now[:error] = I18n.t(:error_type_could_not_be_saved) - render action: "edit" + render action: 'edit' end end @@ -113,7 +113,7 @@ def destroy else flash[:error] = destroy_error_message end - redirect_to action: "index" + redirect_to action: 'index' end protected @@ -129,7 +129,7 @@ def permitted_type_params end def load_projects_and_types - @types = ::Type.order(Arel.sql("position")) + @types = ::Type.order(Arel.sql('position')) @projects = Project.all end @@ -140,7 +140,7 @@ def redirect_to_type_tab_path(type, notice) end def default_breadcrumb - if action_name == "index" + if action_name == 'index' t(:label_work_package_types) else ActionController::Base.helpers.link_to(t(:label_work_package_types), types_path) @@ -152,7 +152,7 @@ def render_edit_tab(type) @projects = Project.all @type = type - render action: "edit" + render action: 'edit' end def show_local_breadcrumb @@ -173,7 +173,7 @@ def destroy_error_message else error_message = [ ApplicationController.helpers.sanitize( - t(:"error_can_not_delete_type.explanation", url: belonging_wps_url(@type.id)), + t(:'error_can_not_delete_type.explanation', url: belonging_wps_url(@type.id)), attributes: %w(href target) ) ] diff --git a/app/controllers/users/memberships_controller.rb b/app/controllers/users/memberships_controller.rb index 2e02321d568c..778675af5c07 100644 --- a/app/controllers/users/memberships_controller.rb +++ b/app/controllers/users/memberships_controller.rb @@ -28,7 +28,7 @@ class Users::MembershipsController < ApplicationController include IndividualPrincipals::MembershipControllerMethods - layout "admin" + layout 'admin' before_action :authorize_global before_action :find_individual_principal @@ -41,9 +41,9 @@ def find_individual_principal def redirected_to_tab(membership) if membership.project - "memberships" + 'memberships' else - "global_roles" + 'global_roles' end end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 1a599d96d232..bb332a605199 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -27,7 +27,7 @@ #++ class UsersController < ApplicationController - layout "admin" + layout 'admin' before_action :authorize_global, except: %i[show deletion_info destroy] @@ -76,7 +76,7 @@ def show if can_show_user? @events = events - render layout: (can_manage_or_create_users? ? "admin" : "no_menu") + render layout: (can_manage_or_create_users? ? 'admin' : 'no_menu') else render_404 end @@ -102,7 +102,7 @@ def create flash[:notice] = I18n.t(:notice_successful_create) redirect_to(params[:continue] ? new_user_path : helpers.allowed_management_user_profile_path(@user)) else - render action: "new" + render action: 'new' end end @@ -134,7 +134,7 @@ def update respond_to do |format| format.html do flash[:notice] = I18n.t(:notice_successful_update) - render action: :edit + redirect_back(fallback_location: edit_user_path(@user)) end end else @@ -160,14 +160,14 @@ def change_status_info def change_status if @user.id == current_user.id # user is not allowed to change own status - redirect_back_or_default(action: "edit", id: @user) + redirect_back_or_default(action: 'edit', id: @user) return end if (params[:unlock] || params[:activate]) && user_limit_reached? show_user_limit_error! - return redirect_back_or_default(action: "edit", id: @user) + return redirect_back_or_default(action: 'edit', id: @user) end if params[:unlock] @@ -182,7 +182,7 @@ def change_status was_activated = (@user.status_change == %w[registered active]) if params[:activate] && @user.missing_authentication_method? - flash[:error] = I18n.t("user.error_status_change_failed", + flash[:error] = I18n.t('user.error_status_change_failed', errors: I18n.t(:notice_user_missing_authentication_method)) elsif @user.save flash[:notice] = I18n.t(:notice_successful_update) @@ -190,10 +190,10 @@ def change_status UserMailer.account_activated(@user).deliver_later end else - flash[:error] = I18n.t("user.error_status_change_failed", - errors: @user.errors.full_messages.join(", ")) + flash[:error] = I18n.t('user.error_status_change_failed', + errors: @user.errors.full_messages.join(', ')) end - redirect_back_or_default(action: "edit", id: @user) + redirect_back_or_default(action: 'edit', id: @user) end def resend_invitation @@ -218,7 +218,7 @@ def destroy Users::DeleteService.new(model: @user, user: User.current).call - flash[:notice] = I18n.t("account.deletion_pending") + flash[:notice] = I18n.t('account.deletion_pending') respond_to do |format| format.html do @@ -228,7 +228,7 @@ def destroy end def deletion_info - render action: "deletion_info", layout: my_or_admin_layout + render action: 'deletion_info', layout: my_or_admin_layout end private @@ -267,9 +267,9 @@ def authorize_for_user respond_to do |format| format.html { render_403 } - format.xml { head :unauthorized, "WWW-Authenticate" => 'Basic realm="OpenProject API"' } - format.js { head :unauthorized, "WWW-Authenticate" => 'Basic realm="OpenProject API"' } - format.json { head :unauthorized, "WWW-Authenticate" => 'Basic realm="OpenProject API"' } + format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="OpenProject API"' } + format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="OpenProject API"' } + format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="OpenProject API"' } end false @@ -288,9 +288,9 @@ def my_or_admin_layout # TODO: how can this be done better: # check if the route used to call the action is in the 'my' namespace if url_for(:delete_my_account_info) == request.url - "my" + 'my' else - "admin" + 'admin' end end @@ -301,10 +301,10 @@ def set_password?(params) protected def default_breadcrumb - if action_name == "index" - t("label_user_plural") + if action_name == 'index' + t('label_user_plural') else - ActionController::Base.helpers.link_to(t("label_user_plural"), users_path) + ActionController::Base.helpers.link_to(t('label_user_plural'), users_path) end end diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index 9d4d4fd40ae1..8576812a74a0 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -37,7 +37,7 @@ class VersionsController < ApplicationController before_action :authorize def index - @types = @project.types.order(Arel.sql("position")) + @types = @project.types.order(Arel.sql('position')) retrieve_selected_type_ids(@types, @types.select(&:is_in_roadmap?)) @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_work_packages? : (params[:with_subprojects].to_i == 1) project_ids = @with_subprojects ? @project.self_and_descendants.includes(:wiki).map(&:id) : [@project.id] @@ -76,7 +76,7 @@ def create .new(user: current_user) .call(attributes) - render_cu(call, :notice_successful_create, "new") + render_cu(call, :notice_successful_create, 'new') end def update @@ -88,7 +88,7 @@ def update model: @version) .call(attributes) - render_cu(call, :notice_successful_update, "edit") + render_cu(call, :notice_successful_update, 'edit') end def close_completed @@ -146,7 +146,7 @@ def retrieve_selected_type_ids(selectable_types, default_types = nil) def selected_type_ids(selectable_types, default_types = nil) if (ids = params[:type_ids]) - ids.is_a?(Array) ? ids.map(&:to_s) : ids.split("/") + ids.is_a?(Array) ? ids.map(&:to_s) : ids.split('/') else (default_types || selectable_types).map { |t| t.id.to_s } end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index d0b646e7df9b..0babd91d5d37 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "htmldiff" +require 'htmldiff' # The WikiController follows the Rails REST controller pattern but with # a few differences @@ -76,10 +76,10 @@ class WikiController < ApplicationController # List of pages, sorted alphabetically and by parent (hierarchy) def index - slug = wiki_page_title.nil? ? "wiki" : WikiPage.slug(wiki_page_title) + slug = wiki_page_title.nil? ? 'wiki' : WikiPage.slug(wiki_page_title) @related_page = WikiPage.find_by(wiki_id: @wiki.id, slug:) - @pages = @wiki.pages.order(Arel.sql("title")).includes(wiki: :project) + @pages = @wiki.pages.order(Arel.sql('title')).includes(wiki: :project) @pages_by_parent_id = @pages.group_by(&:parent_id) end @@ -92,8 +92,8 @@ def show @page = ::WikiPages::AtVersion.new(@page, version) - if params[:format] == "markdown" && User.current.allowed_in_project?(:export_wiki_pages, @project) - send_data(@page.text, type: "text/plain", filename: "#{@page.title}.md") + if params[:format] == 'markdown' && User.current.allowed_in_project?(:export_wiki_pages, @project) + send_data(@page.text, type: 'text/plain', filename: "#{@page.title}.md") return end @@ -111,7 +111,7 @@ def new_child build_wiki_page @page.parent = old_page - render action: "new" + render action: 'new' end def menu @@ -144,7 +144,7 @@ def create flash[:notice] = I18n.t(:notice_successful_create) redirect_to_show else - render action: "new" + render action: 'new' end end @@ -170,12 +170,12 @@ def update flash[:notice] = I18n.t(:notice_successful_update) redirect_to_show else - render action: "edit" + render action: 'edit' end rescue ActiveRecord::StaleObjectError # Optimistic locking exception flash.now[:error] = I18n.t(:notice_locking_conflict) - render action: "edit" + render action: 'edit' end # rename a page @@ -237,7 +237,7 @@ def update_parent_page redirect_to_show else @parent_pages = @wiki.pages.includes(:parent) - @page.self_and_descendants - render "edit_parent_page" + render 'edit_parent_page' end end @@ -252,7 +252,7 @@ def history @versions = @page .journals .select(:id, :user_id, :notes, :created_at, :version) - .order(Arel.sql("version DESC")) + .order(Arel.sql('version DESC')) .page(page_param) .per_page(per_page_param) @@ -286,12 +286,12 @@ def destroy @descendants_count = @page.descendants.size if @descendants_count > 0 case params[:todo] - when "nullify" + when 'nullify' # Nothing to do - when "destroy" + when 'destroy' # Removes all its descendants @page.descendants.each(&:destroy) - when "reassign" + when 'reassign' # Reassign children to another parent page reassign_to = @wiki.pages.find_by(id: params[:reassign_to_id].presence) return unless reassign_to @@ -308,7 +308,7 @@ def destroy if page = @wiki.find_page(@wiki.start_page) || @wiki.pages.first flash[:notice] = I18n.t(:notice_successful_delete) - redirect_to action: "index", project_id: @project, id: page + redirect_to action: 'index', project_id: @project, id: page else flash[:notice] = I18n.t(:notice_successful_delete) redirect_to project_path(@project) @@ -318,11 +318,11 @@ def destroy # Export wiki to a single html file def export if User.current.allowed_in_project?(:export_wiki_pages, @project) - @pages = @wiki.pages.order(Arel.sql("title")) - export = render_to_string action: "export_multiple", layout: false - send_data(export, type: "text/html", filename: "wiki.html") + @pages = @wiki.pages.order(Arel.sql('title')) + export = render_to_string action: 'export_multiple', layout: false + send_data(export, type: 'text/html', filename: 'wiki.html') else - redirect_to action: "show", project_id: @project, id: nil + redirect_to action: 'show', project_id: @project, id: nil end end @@ -360,7 +360,7 @@ def page_for_menu_item(page) end def wiki_page_title - params[:title] || (action_name == "new_child" ? "" : params[:id].to_s.capitalize.tr("-", " ")) + params[:title] || (action_name == 'new_child' ? '' : params[:id].to_s.capitalize.tr('-', ' ')) end def find_wiki @@ -384,8 +384,8 @@ def handle_new_wiki_page if User.current.allowed_in_project?(:edit_wiki_pages, @project) && editable? edit render action: :new - elsif params[:id] == "wiki" - flash[:info] = I18n.t("wiki.page_not_editable_index") + elsif params[:id] == 'wiki' + flash[:info] = I18n.t('wiki.page_not_editable_index') redirect_to action: :index else render_404 diff --git a/app/controllers/wiki_menu_items_controller.rb b/app/controllers/wiki_menu_items_controller.rb index 6ac9c2358cc6..b3dcb8d87351 100644 --- a/app/controllers/wiki_menu_items_controller.rb +++ b/app/controllers/wiki_menu_items_controller.rb @@ -68,7 +68,7 @@ def update get_data_from_params(params) - if wiki_menu_setting == "no_item" + if wiki_menu_setting == 'no_item' unless @wiki_menu_item.nil? if @wiki_menu_item.is_only_main_item? if @page.only_wiki_page? @@ -86,9 +86,9 @@ def update @wiki_menu_item.name = @page.slug @wiki_menu_item.title = wiki_menu_item_params[:title] || @page_title - if wiki_menu_setting == "sub_item" + if wiki_menu_setting == 'sub_item' @wiki_menu_item.parent_id = parent_wiki_menu_item - elsif wiki_menu_setting == "main_item" + elsif wiki_menu_setting == 'main_item' @wiki_menu_item.parent_id = nil assign_wiki_menu_item_params @wiki_menu_item end @@ -101,11 +101,11 @@ def update flash[:notice] = t(:notice_successful_update) end - redirect_back_or_default(action: "edit", id: @page) + redirect_back_or_default(action: 'edit', id: @page) else respond_to do |format| format.html do - render action: "edit", id: @page + render action: 'edit', id: @page end end end @@ -163,15 +163,15 @@ def get_data_from_params(params) end def assign_wiki_menu_item_params(menu_item) - if wiki_menu_item_params[:new_wiki_page] == "1" + if wiki_menu_item_params[:new_wiki_page] == '1' menu_item.new_wiki_page = true - elsif wiki_menu_item_params[:new_wiki_page] == "0" + elsif wiki_menu_item_params[:new_wiki_page] == '0' menu_item.new_wiki_page = false end - if wiki_menu_item_params[:index_page] == "1" + if wiki_menu_item_params[:index_page] == '1' menu_item.index_page = true - elsif wiki_menu_item_params[:index_page] == "0" + elsif wiki_menu_item_params[:index_page] == '0' menu_item.index_page = false end end diff --git a/app/controllers/work_packages/auto_completes_controller.rb b/app/controllers/work_packages/auto_completes_controller.rb index 58152a1e5ff0..955140e59050 100644 --- a/app/controllers/work_packages/auto_completes_controller.rb +++ b/app/controllers/work_packages/auto_completes_controller.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rack/utils" +require 'rack/utils' class WorkPackages::AutoCompletesController < ApplicationController def index @@ -41,7 +41,7 @@ def index def work_packages_matching_query_prop Query.new.tap do |query| - query.add_filter(:typeahead, "**", params[:q]) + query.add_filter(:typeahead, '**', params[:q]) query.sort_criteria = [%i[updated_at desc]] query.include_subprojects = true end @@ -52,7 +52,7 @@ def work_packages_matching_query_prop def wp_hashes_with_string(work_packages) work_packages.map do |work_package| - work_package.attributes.merge("to_s" => work_package.to_s) + work_package.attributes.merge('to_s' => work_package.to_s) end end end diff --git a/app/controllers/work_packages/bulk_error_message.rb b/app/controllers/work_packages/bulk_error_message.rb index a0e5a9acf2ad..05df1e659b17 100644 --- a/app/controllers/work_packages/bulk_error_message.rb +++ b/app/controllers/work_packages/bulk_error_message.rb @@ -33,7 +33,7 @@ module WorkPackages::BulkErrorMessage private def bulk_error_message(selected_work_packages, service_result) - ApplicationController.renderer.render partial: "work_packages/bulk/errors", + ApplicationController.renderer.render partial: 'work_packages/bulk/errors', locals: { service_result:, selected_work_packages: } end diff --git a/app/controllers/work_packages/moves_controller.rb b/app/controllers/work_packages/moves_controller.rb index 42c65161fafa..3d0cc952d960 100644 --- a/app/controllers/work_packages/moves_controller.rb +++ b/app/controllers/work_packages/moves_controller.rb @@ -104,7 +104,7 @@ def default_breadcrumb def check_project_uniqueness unless @project # TODO: let users bulk move/copy work packages from different projects - render_error message: :"work_packages.move.unsupported_for_multiple_projects", status: 400 + render_error message: :'work_packages.move.unsupported_for_multiple_projects', status: 400 false end end @@ -118,7 +118,7 @@ def prepare_for_work_package_move @target_type = @types.find { |t| t.id.to_s == params[:new_type_id].to_s } @available_versions = @target_project.assignable_versions @available_statuses = Workflow.available_statuses(@project) - @notes = params[:notes] || "" + @notes = params[:notes] || '' end def attributes_for_create @@ -126,7 +126,7 @@ def attributes_for_create .move_work_package .compact_blank # 'none' is used in the frontend as a value to unset the property, e.g. the assignee. - .transform_values { |v| v == "none" ? nil : v } + .transform_values { |v| v == 'none' ? nil : v } .to_h end end diff --git a/app/controllers/work_packages/reports_controller.rb b/app/controllers/work_packages/reports_controller.rb index e1cb28000300..76be8b1393ac 100644 --- a/app/controllers/work_packages/reports_controller.rb +++ b/app/controllers/work_packages/reports_controller.rb @@ -34,16 +34,16 @@ def report reports_service = Reports::ReportsService.new(@project) @reports = [ - reports_service.report_for("type"), - reports_service.report_for("priority"), - reports_service.report_for("assigned_to"), - reports_service.report_for("responsible"), - reports_service.report_for("author"), - reports_service.report_for("version"), - reports_service.report_for("category") + reports_service.report_for('type'), + reports_service.report_for('priority'), + reports_service.report_for('assigned_to'), + reports_service.report_for('responsible'), + reports_service.report_for('author'), + reports_service.report_for('version'), + reports_service.report_for('category') ] - @reports << reports_service.report_for("subproject") if @project.children.any? + @reports << reports_service.report_for('subproject') if @project.children.any? end def report_details diff --git a/app/controllers/work_packages/shares/bulk_controller.rb b/app/controllers/work_packages/shares/bulk_controller.rb index 79db00e72854..ea553b7657f9 100644 --- a/app/controllers/work_packages/shares/bulk_controller.rb +++ b/app/controllers/work_packages/shares/bulk_controller.rb @@ -70,7 +70,7 @@ def respond_with_update_permission_buttons @selected_shares.each do |share| replace_via_turbo_stream( component: WorkPackages::Share::PermissionButtonComponent.new(share:, - data: { "test-selector": "op-share-wp-update-role" }) + data: { 'test-selector': 'op-share-wp-update-role' }) ) end diff --git a/app/controllers/work_packages/shares_controller.rb b/app/controllers/work_packages/shares_controller.rb index c539a7185685..8facf685413f 100644 --- a/app/controllers/work_packages/shares_controller.rb +++ b/app/controllers/work_packages/shares_controller.rb @@ -168,7 +168,7 @@ def respond_with_new_invite_form def respond_with_update_permission_button replace_via_turbo_stream( component: WorkPackages::Share::PermissionButtonComponent.new(share: @share, - data: { "test-selector": "op-share-wp-update-role" }) + data: { 'test-selector': 'op-share-wp-update-role' }) ) respond_with_turbo_streams @@ -223,9 +223,9 @@ def load_query .call(params) # Set default filter on the entity - @query.where("entity_id", "=", @work_package.id) - @query.where("entity_type", "=", WorkPackage.name) - @query.where("project_id", "=", @project.id) + @query.where('entity_id', '=', @work_package.id) + @query.where('entity_type', '=', WorkPackage.name) + @query.where('project_id', '=', @project.id) @query.order(name: :asc) unless params[:sortBy] diff --git a/app/controllers/work_packages_controller.rb b/app/controllers/work_packages_controller.rb index 8bbc4624afb4..2b0f2fbfce19 100644 --- a/app/controllers/work_packages_controller.rb +++ b/app/controllers/work_packages_controller.rb @@ -47,7 +47,7 @@ def index format.html do render :index, locals: { query: @query, project: @project, menu_name: project_or_global_menu }, - layout: "angular/angular" + layout: 'angular/angular' end format.any(*supported_list_formats) do @@ -65,7 +65,7 @@ def show format.html do render :show, locals: { work_package:, menu_name: project_or_global_menu }, - layout: "angular/angular" + layout: 'angular/angular' end format.any(*supported_single_formats) do @@ -90,7 +90,7 @@ def export_list(mime_type) .call(query: @query, mime_type:, params:) .result - if request.headers["Accept"]&.include?("application/json") + if request.headers['Accept']&.include?('application/json') render json: { job_id: } else redirect_to job_status_path(job_id) @@ -110,9 +110,9 @@ def export_single(mime_type) end def atom_journals - render template: "journals/index", + render template: 'journals/index', layout: false, - content_type: "application/atom+xml", + content_type: 'application/atom+xml', locals: { title: "#{Setting.app_title} - #{work_package}", journals: } end @@ -125,7 +125,7 @@ def authorize_on_work_package def per_page_param case params[:format] - when "atom" + when 'atom' Setting.feeds_limit.to_i else super @@ -144,9 +144,9 @@ def journals @journals ||= begin order = if current_user.wants_comments_in_reverse_order? - Journal.arel_table["created_at"].desc + Journal.arel_table['created_at'].desc else - Journal.arel_table["created_at"].asc + Journal.arel_table['created_at'].asc end work_package diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb index 26f94fb71b36..00a7ac3b7b0f 100644 --- a/app/controllers/workflows_controller.rb +++ b/app/controllers/workflows_controller.rb @@ -27,7 +27,7 @@ #++ class WorkflowsController < ApplicationController - layout "admin" + layout 'admin' before_action :require_admin @@ -45,7 +45,7 @@ def show end def edit - @used_statuses_only = params[:used_statuses_only] != "0" + @used_statuses_only = params[:used_statuses_only] != '0' statuses_for_form @@ -57,21 +57,21 @@ def edit def update call = Workflows::BulkUpdateService .new(role: @role, type: @type) - .call(params["status"]) + .call(params['status']) if call.success? flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "edit", role_id: @role, type_id: @type + redirect_to action: 'edit', role_id: @role, type_id: @type end end def copy - @source_type = if params[:source_type_id].blank? || params[:source_type_id] == "any" + @source_type = if params[:source_type_id].blank? || params[:source_type_id] == 'any' nil else ::Type.find(params[:source_type_id]) end - @source_role = if params[:source_role_id].blank? || params[:source_role_id] == "any" + @source_role = if params[:source_role_id].blank? || params[:source_role_id] == 'any' nil else eligible_roles.find(params[:source_role_id]) @@ -88,16 +88,16 @@ def copy else Workflow.copy(@source_type, @source_role, @target_types, @target_roles) flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "copy", source_type_id: @source_type, source_role_id: @source_role + redirect_to action: 'copy', source_type_id: @source_type, source_role_id: @source_role end end end def default_breadcrumb - if action_name == "edit" - t("label_workflow") + if action_name == 'edit' + t('label_workflow') else - ActionController::Base.helpers.link_to(t("label_workflow"), url_for(controller: "/workflows", action: "edit")) + ActionController::Base.helpers.link_to(t('label_workflow'), url_for(controller: '/workflows', action: 'edit')) end end @@ -118,9 +118,9 @@ def statuses_for_form def workflows_for_form workflows = Workflow.where(role_id: @role.id, type_id: @type.id) @workflows = {} - @workflows["always"] = workflows.select { |w| !w.author && !w.assignee } - @workflows["author"] = workflows.select(&:author) - @workflows["assignee"] = workflows.select(&:assignee) + @workflows['always'] = workflows.select { |w| !w.author && !w.assignee } + @workflows['author'] = workflows.select(&:author) + @workflows['assignee'] = workflows.select(&:assignee) end def find_roles diff --git a/app/forms/queries/projects/create.rb b/app/forms/queries/projects/create.rb index f6cc39ce1a29..c53f999538f1 100644 --- a/app/forms/queries/projects/create.rb +++ b/app/forms/queries/projects/create.rb @@ -35,9 +35,9 @@ class Queries::Projects::Create < ApplicationForm visually_hide_label: true, required: true, autofocus: true, - name: "name", + name: 'name', label: Queries::Projects::ProjectQuery.human_attribute_name(:name), - placeholder: I18n.t(:"projects.lists.new.placeholder") + placeholder: I18n.t(:'projects.lists.new.placeholder') ) group.submit( @@ -51,7 +51,7 @@ class Queries::Projects::Create < ApplicationForm scheme: :secondary, label: I18n.t(:button_cancel), tag: :a, - data: { "params-from-query-target": "anchor" }, + data: { 'params-from-query-target': 'anchor' }, href: OpenProject::StaticRouting::StaticUrlHelpers.new.projects_path ) end diff --git a/app/helpers/accessibility_helper.rb b/app/helpers/accessibility_helper.rb index 155fd8269faa..3568ac8ddc83 100644 --- a/app/helpers/accessibility_helper.rb +++ b/app/helpers/accessibility_helper.rb @@ -33,12 +33,12 @@ def you_are_here_info(condition = true, disabled = nil) elsif condition && disabled "".html_safe else - "" + '' end end def empty_element_tag - @empty_element_tag ||= ApplicationController.new.render_to_string(partial: "accessibility/empty_element_tag").html_safe + @empty_element_tag ||= ApplicationController.new.render_to_string(partial: 'accessibility/empty_element_tag').html_safe end # Returns the locale :en for the given menu item if the user locale is diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index d7578d9c5bb5..4c62e7e928b3 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -28,13 +28,13 @@ module AdminHelper def project_status_options_for_select(selected) - options_for_select([[I18n.t(:label_all), ""], + options_for_select([[I18n.t(:label_all), ''], [I18n.t(:status_active), 1]], selected) end def linked_sha_reference(sha, url) if sha && url - link_to sha, url, target: "_blank", rel: "noopener" + link_to sha, url, target: '_blank', rel: 'noopener' else sha end diff --git a/app/helpers/angular_helper.rb b/app/helpers/angular_helper.rb index a287f2b40aa1..be0fb75e6146 100644 --- a/app/helpers/angular_helper.rb +++ b/app/helpers/angular_helper.rb @@ -38,10 +38,10 @@ def angular_component_tag(component, options = {}) .transform_values(&:to_json) options[:data] = options.fetch(:data, {}).merge(inputs) - options[:class] ||= [options[:class], "op-angular-component"] + options[:class] ||= [options[:class], 'op-angular-component'] .compact - .join(" ") + .join(' ') - content_tag(component, "", options) + content_tag(component, '', options) end end diff --git a/app/helpers/announcements_helper.rb b/app/helpers/announcements_helper.rb index 891b354e69b5..ef727a2ddba7 100644 --- a/app/helpers/announcements_helper.rb +++ b/app/helpers/announcements_helper.rb @@ -1,9 +1,9 @@ module AnnouncementsHelper def notice_annoucement_active if @announcement.active_and_current? - I18n.t(:"announcements.is_active") + I18n.t(:'announcements.is_active') else - I18n.t(:"announcements.is_inactive") + I18n.t(:'announcements.is_inactive') end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5a1610f8a357..86113995dcac 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "forwardable" -require "cgi" +require 'forwardable' +require 'cgi' module ApplicationHelper include OpenProject::TextFormatting @@ -72,8 +72,8 @@ def link_to_if_authorized(*args, &) end end - def required_field_name(name = "") - safe_join [name, " ", content_tag("span", "*", class: "required")] + def required_field_name(name = '') + safe_join [name, ' ', content_tag('span', '*', class: 'required')] end def li_unless_nil(link, options = {}) @@ -82,12 +82,12 @@ def li_unless_nil(link, options = {}) # Show a sorted linkified (if active) comma-joined list of users def list_users(users, options = {}) - users.sort.map { |u| link_to_user(u, options) }.join(", ") + users.sort.map { |u| link_to_user(u, options) }.join(', ') end # returns a class name based on the user's status def user_status_class(user) - "status_" + user.status + 'status_' + user.status end def user_status_i18n(user) @@ -98,7 +98,7 @@ def delete_link(url, options = {}) options = { method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, - class: "icon icon-delete" + class: 'icon icon-delete' }.merge(options) link_to I18n.t(:button_delete), url, options @@ -123,7 +123,7 @@ def project_tree(projects, &) end def project_nested_ul(projects, &) - s = "" + s = '' if projects.any? ancestors = [] Project.project_tree(projects) do |project, _level| @@ -131,13 +131,13 @@ def project_nested_ul(projects, &) s << "\n" end end - s << "
  • " + s << '
  • ' s << yield(project).to_s ancestors << project end @@ -154,7 +154,7 @@ def principals_check_box_tags(name, principals) def labeled_check_box_tags(name, collection, options = {}) collection.sort.map do |object| - id = name.gsub(/[\[\]]+/, "_") + object.id.to_s + id = name.gsub(/[\[\]]+/, '_') + object.id.to_s object_options = options.inject({}) do |h, (k, v)| h[k] = v.is_a?(Symbol) ? send(v, object) : v @@ -163,7 +163,7 @@ def labeled_check_box_tags(name, collection, options = {}) object_options[:class] = Array(object_options[:class]) + %w(form--label-with-check-box) - content_tag :div, class: "form--field" do + content_tag :div, class: 'form--field' do label_tag(id, object, object_options) do styled_check_box_tag(name, object.id, false, id:) + object.to_s end @@ -185,7 +185,7 @@ def authoring(created, author, options = {}) def authoring_at(created, author) return if author.nil? - I18n.t(:"js.label_added_time_by", + I18n.t(:'js.label_added_time_by', author: html_escape(author.name), age: created, authorLink: user_path(author)).html_safe @@ -193,16 +193,16 @@ def authoring_at(created, author) def time_tag(time) text = distance_of_time_in_words(Time.now, time) - if @project and @project.module_enabled?("activity") - link_to(text, { controller: "/activities", - action: "index", + if @project and @project.module_enabled?('activity') + link_to(text, { controller: '/activities', + action: 'index', project_id: @project, from: time.to_date }, title: format_time(time)) else datetime = time.acts_like?(:time) ? time.xmlschema : time.iso8601 content_tag(:time, text, datetime:, - title: format_time(time), class: "timestamp") + title: format_time(time), class: 'timestamp') end end @@ -220,7 +220,7 @@ def to_path_param(path) def other_formats_links(&) formats = capture(Redmine::Views::OtherFormatsBuilder.new(self), &) unless formats.nil? || formats.strip.empty? - content_tag "p", class: "other-formats" do + content_tag 'p', class: 'other-formats' do (I18n.t(:label_export_to) + formats).html_safe end end @@ -229,11 +229,11 @@ def other_formats_links(&) # Returns the theme, controller name, and action as css classes for the # HTML body. def body_css_classes - css = ["theme-" + OpenProject::CustomStyles::Design.identifier.to_s] + css = ['theme-' + OpenProject::CustomStyles::Design.identifier.to_s] if params[:controller] && params[:action] - css << ("controller-" + params[:controller]) - css << ("action-" + params[:action]) + css << ('controller-' + params[:controller]) + css << ('action-' + params[:action]) end css << "ee-banners-#{EnterpriseToken.show_banners? ? 'visible' : 'hidden'}" @@ -243,7 +243,7 @@ def body_css_classes # Add browser specific classes to aid css fixes css += browser_specific_classes - css.join(" ") + css.join(' ') end def accesskey(s) @@ -254,14 +254,14 @@ def accesskey(s) def simple_format_without_paragraph(text) text.to_s .gsub(/\r\n?/, "\n") # \r\n and \r -> \n - .gsub(/\n\n+/, "

    ") # 2+ newline -> 2 br + .gsub(/\n\n+/, '

    ') # 2+ newline -> 2 br .gsub(/([^\n]\n)(?=[^\n])/, '\1
    ') # 1 newline -> br .html_safe end def lang_options_for_select(blank = true) auto = if blank && (valid_languages - all_languages) == (all_languages - valid_languages) - [["(auto)", ""]] + [['(auto)', '']] else [] end @@ -279,8 +279,8 @@ def all_lang_options_for_select def theme_options_for_select [ - [t("themes.light"), "light"], - [t("themes.light_high_contrast"), "light_high_contrast"] + [t('themes.light'), 'light'], + [t('themes.light_high_contrast'), 'light_high_contrast'] ] end @@ -292,7 +292,7 @@ def user_theme_data_attributes def highlight_default_language(lang_options) lang_options.map do |(language_name, code)| if code == Setting.default_language - [I18n.t("settings.language_name_being_default", language_name:), code, { disabled: true, checked: true }] + [I18n.t('settings.language_name_being_default', language_name:), code, { disabled: true, checked: true }] else [language_name, code] end @@ -301,14 +301,14 @@ def highlight_default_language(lang_options) def labelled_tabular_form_for(record, options = {}, &) options.reverse_merge!(builder: TabularFormBuilder, html: {}) - options[:html][:class] = "form" unless options[:html].has_key?(:class) + options[:html][:class] = 'form' unless options[:html].has_key?(:class) form_for(record, options, &) end def back_url_hidden_field_tag(use_referer: true) - back_url = params[:back_url] || (use_referer ? request.env["HTTP_REFERER"] : nil) + back_url = params[:back_url] || (use_referer ? request.env['HTTP_REFERER'] : nil) back_url = CGI.unescape(back_url.to_s) - hidden_field_tag("back_url", CGI.escape(back_url), id: nil) if back_url.present? + hidden_field_tag('back_url', CGI.escape(back_url), id: nil) if back_url.present? end def back_url_to_current_page_hidden_field_tag @@ -319,12 +319,12 @@ def back_url_to_current_page_hidden_field_tag back_url = request.url end - hidden_field_tag("back_url", back_url) if back_url.present? + hidden_field_tag('back_url', back_url) if back_url.present? end def check_all_links(form_name) link_to_function(t(:button_check_all), "OpenProject.helpers.checkAll('#{form_name}', true)") + - " | " + + ' | ' + link_to_function(t(:button_uncheck_all), "OpenProject.helpers.checkAll('#{form_name}', false)") end @@ -347,23 +347,23 @@ def progress_bar(pcts, options = {}) pcts = Array(pcts).map(&:round) closed = pcts[0] done = pcts[1] || 0 - width = options[:width] || "100px;" - legend = options[:legend] || "" - total_progress = options[:hide_total_progress] ? "" : t(:total_progress) - percent_sign = options[:hide_percent_sign] ? "" : "%" + width = options[:width] || '100px;' + legend = options[:legend] || '' + total_progress = options[:hide_total_progress] ? '' : t(:total_progress) + percent_sign = options[:hide_percent_sign] ? '' : '%' content_tag :span do - progress = content_tag :span, class: "progress-bar", style: "width: #{width}" do - concat content_tag(:span, "", class: "inner-progress closed", style: "width: #{closed}%") - concat content_tag(:span, "", class: "inner-progress done", style: "width: #{done}%") + progress = content_tag :span, class: 'progress-bar', style: "width: #{width}" do + concat content_tag(:span, '', class: 'inner-progress closed', style: "width: #{closed}%") + concat content_tag(:span, '', class: 'inner-progress done', style: "width: #{done}%") end - progress + content_tag(:span, "#{legend}#{percent_sign} #{total_progress}", class: "progress-bar-legend") + progress + content_tag(:span, "#{legend}#{percent_sign} #{total_progress}", class: 'progress-bar-legend') end end def checked_image(checked = true) if checked - icon_wrapper("icon-context icon-checkmark", t(:label_checked)) + icon_wrapper('icon-context icon-checkmark', t(:label_checked)) end end @@ -375,41 +375,41 @@ def calendar_for(*_args) def locale_first_day_of_week case Setting.start_of_week.to_i when 1 - "1" # Monday + '1' # Monday when 7 - "0" # Sunday + '0' # Sunday when 6 - "6" # Saturday + '6' # Saturday else # use language default (pass a blank string) and moment.js will reuse existing info # /frontend/src/main.ts - "" + '' end end def locale_first_week_of_year case Setting.first_week_of_year.to_i when 1 - "1" # Monday + '1' # Monday when 4 - "4" # Thursday + '4' # Thursday else # use language default (pass a blank string) and moment.js will reuse existing info # /frontend/src/main.ts - "" + '' end end # To avoid the menu flickering, disable it # by default unless we're in test mode def initial_menu_styles(side_displayed) - Rails.env.test? || !side_displayed ? "" : "display:none" + Rails.env.test? || !side_displayed ? '' : 'display:none' end def initial_menu_classes(side_displayed, show_decoration) - classes = "can-hide-navigation" - classes << " nosidebar" unless side_displayed - classes << " nomenus" unless show_decoration + classes = 'can-hide-navigation' + classes << ' nosidebar' unless side_displayed + classes << ' nomenus' unless show_decoration classes end @@ -418,7 +418,7 @@ def initial_menu_classes(side_displayed, show_decoration) # # @param [optional, String] content the content of the ROBOTS tag. # defaults to no index, follow, and no archive - def robot_exclusion_tag(content = "NOINDEX,FOLLOW,NOARCHIVE") + def robot_exclusion_tag(content = 'NOINDEX,FOLLOW,NOARCHIVE') "".html_safe end @@ -437,7 +437,7 @@ def translate_language(lang_code) ::I18n.locale != Redmine::I18n::IN_CONTEXT_TRANSLATION_CODE [Redmine::I18n::IN_CONTEXT_TRANSLATION_NAME, lang_code.to_s] else - [I18n.t("cldr.language_name", locale: lang_code), lang_code.to_s] + [I18n.t('cldr.language_name', locale: lang_code), lang_code.to_s] end end @@ -450,8 +450,8 @@ def password_complexity_requirements # use 0..0, so this doesn't fail if rules is an empty string rules[0] = rules[0..0].upcase - s = raw "" + OpenProject::Passwords::Evaluator.min_length_description + "" - s += raw "
    " + rules + "" unless rules.empty? + s = raw '' + OpenProject::Passwords::Evaluator.min_length_description + '' + s += raw '
    ' + rules + '' unless rules.empty? s end end diff --git a/app/helpers/appsignal_helper.rb b/app/helpers/appsignal_helper.rb index 592f1d7c0e17..9203f4878fc9 100644 --- a/app/helpers/appsignal_helper.rb +++ b/app/helpers/appsignal_helper.rb @@ -1,9 +1,9 @@ module AppsignalHelper def appsignal_frontend_tag - return "" unless OpenProject::Configuration.appsignal_frontend_key + return '' unless OpenProject::Configuration.appsignal_frontend_key tag :meta, - name: "openproject_appsignal", + name: 'openproject_appsignal', data: { push_key: OpenProject::Configuration.appsignal_frontend_key, version: OpenProject::VERSION.to_s diff --git a/app/helpers/archived_projects_helper.rb b/app/helpers/archived_projects_helper.rb index 20535782cba4..7246f0f8a2bb 100644 --- a/app/helpers/archived_projects_helper.rb +++ b/app/helpers/archived_projects_helper.rb @@ -31,19 +31,19 @@ def archived_projects_urls_for(projects) urls = projects.map do |project| link_to project.name, projects_path(filters: archived_project_filters_for(project)), - target: "_blank", - rel: "noopener" + target: '_blank', + rel: 'noopener' end - safe_join(urls, ", ") + safe_join(urls, ', ') end private def archived_project_filters_for(project) [ - { active: { operator: "=", values: ["f"] } }, - { name_and_identifier: { operator: "=", values: [html_escape(project.name)] } } + { active: { operator: '=', values: ['f'] } }, + { name_and_identifier: { operator: '=', values: [html_escape(project.name)] } } ].to_json end end diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb index 368ad7e253a3..9d71015f3b6b 100644 --- a/app/helpers/attachments_helper.rb +++ b/app/helpers/attachments_helper.rb @@ -29,10 +29,10 @@ module AttachmentsHelper def to_utf8_for_attachments(str) forced_str = str.dup - forced_str.force_encoding("UTF-8") + forced_str.force_encoding('UTF-8') return forced_str if forced_str.valid_encoding? - str.encode("UTF-8", invalid: :replace, undef: :replace, replace: "") # better replace: '?' + str.encode('UTF-8', invalid: :replace, undef: :replace, replace: '') # better replace: '?' end ## @@ -42,11 +42,11 @@ def to_utf8_for_attachments(str) # Within ckeditor-augmented-textarea-form, this attachment list is added automatically # when a resource is added. def list_attachments(resource, options = {}) - content_tag "op-attachments", - "", - "data-resource": resource.to_json, - "data-allow-uploading": false, - "data-destroy-immediately": true, + content_tag 'op-attachments', + '', + 'data-resource': resource.to_json, + 'data-allow-uploading': false, + 'data-destroy-immediately': true, **options end end diff --git a/app/helpers/augmenting_helper.rb b/app/helpers/augmenting_helper.rb index dd3f5ccf4b03..a86884220676 100644 --- a/app/helpers/augmenting_helper.rb +++ b/app/helpers/augmenting_helper.rb @@ -37,7 +37,7 @@ module AugmentingHelper # @param block [Block] A block that renders the section's body. def augmented_collapsible_section(title:, initiallyExpanded: true, &block) render( - partial: "/augmented/collapsible_section", + partial: '/augmented/collapsible_section', locals: { title:, initiallyExpanded: !!initiallyExpanded, block: } ) end diff --git a/app/helpers/browser_helper.rb b/app/helpers/browser_helper.rb index 73e076d21111..c3b3190eb06e 100644 --- a/app/helpers/browser_helper.rb +++ b/app/helpers/browser_helper.rb @@ -32,14 +32,14 @@ def unsupported_browser? # or mobile detection def browser_specific_classes [].tap do |classes| - classes << "-browser-chrome" if browser.chrome? - classes << "-browser-firefox" if browser.firefox? - classes << "-browser-safari" if browser.safari? - classes << "-browser-edge" if browser.edge? - - classes << "-browser-mobile" if browser.device.mobile? - classes << "-browser-windows" if browser.platform.windows? - classes << "-unsupported-browser" if unsupported_browser? + classes << '-browser-chrome' if browser.chrome? + classes << '-browser-firefox' if browser.firefox? + classes << '-browser-safari' if browser.safari? + classes << '-browser-edge' if browser.edge? + + classes << '-browser-mobile' if browser.device.mobile? + classes << '-browser-windows' if browser.platform.windows? + classes << '-unsupported-browser' if unsupported_browser? end end end diff --git a/app/helpers/calendars_helper.rb b/app/helpers/calendars_helper.rb index 8273fc5b3bff..4cdf772bb153 100644 --- a/app/helpers/calendars_helper.rb +++ b/app/helpers/calendars_helper.rb @@ -35,7 +35,7 @@ module CalendarsHelper # @return [String] link to the calendar def link_to_previous_month(year, month, options = {}) target_date = Date.new(year, month, 1) - 1.month - link_to_month(target_date, options.merge(class: "navigate-left", + link_to_month(target_date, options.merge(class: 'navigate-left', display_year: target_date.year != year)) end @@ -46,7 +46,7 @@ def link_to_previous_month(year, month, options = {}) # @return [String] link to the calendar def link_to_next_month(year, month, options = {}) target_date = Date.new(year, month, 1) + 1.month - link_to_month(target_date, options.merge(class: "navigate-right", + link_to_month(target_date, options.merge(class: 'navigate-right', display_year: target_date.year != year)) end @@ -57,7 +57,7 @@ def link_to_next_month(year, month, options = {}) # @return [String] link to the calendar def link_to_month(date_to_show, options = {}) date = date_to_show.to_date - name = ::I18n.l date, format: options.delete(:display_year) ? "%B %Y" : "%B" + name = ::I18n.l date, format: options.delete(:display_year) ? '%B %Y' : '%B' merged_params = permitted_params .calendar_filter diff --git a/app/helpers/colors_helper.rb b/app/helpers/colors_helper.rb index c2dfcd88511b..618eaa53b534 100644 --- a/app/helpers/colors_helper.rb +++ b/app/helpers/colors_helper.rb @@ -37,7 +37,7 @@ def options_for_colors(colored_thing) color: c.hexcode, bright: c.bright?, dark: c.dark?, - background: c.contrasting_color(light_color: "transparent") + background: c.contrasting_color(light_color: 'transparent') } options[:selected] = true if c.id == colored_thing.color_id @@ -51,9 +51,9 @@ def selected_color(colored_thing) end def colored_text(color) - background = color.contrasting_color(dark_color: "#333", light_color: "transparent") + background = color.contrasting_color(dark_color: '#333', light_color: 'transparent') style = "background-color: #{background}; color: #{color.hexcode}" - content_tag(:span, color.hexcode, class: "color--text-preview", style:) + content_tag(:span, color.hexcode, class: 'color--text-preview', style:) end # @@ -81,16 +81,16 @@ def resource_color_css(name, scope) end styles = color.color_styles - background_style = styles.map { |k, v| "#{k}:#{v} !important" }.join(";") + background_style = styles.map { |k, v| "#{k}:#{v} !important" }.join(';') - if name === "type" + if name === 'type' concat ".__hl_inline_#{name}_#{entry.id} { color: #{color.hexcode} !important;}" concat ".__hl_inline_#{name}_#{entry.id} { -webkit-text-stroke: 0.5px grey;}" if color.super_bright? - border_color = color.super_bright? ? "#555555" : color.hexcode + border_color = color.super_bright? ? '#555555' : color.hexcode concat ".__hl_background_#{name}_#{entry.id} { border-color: #{border_color} !important; }" else - border_color = color.bright? ? "#555555" : color.hexcode + border_color = color.bright? ? '#555555' : color.hexcode concat ".__hl_inline_#{name}_#{entry.id}::before { #{background_style}; border-color: #{border_color}; }\n" end @@ -107,11 +107,11 @@ def resource_color_css(name, scope) def icon_for_color(color, options = {}) return unless color - options.merge! class: "color--preview " + options[:class].to_s, + options.merge! class: 'color--preview ' + options[:class].to_s, title: color.name, style: "background-color: #{color.hexcode};" + options[:style].to_s - content_tag(:span, " ", options) + content_tag(:span, ' ', options) end def color_by_variable(variable) diff --git a/app/helpers/confirmation_dialog_helper.rb b/app/helpers/confirmation_dialog_helper.rb index a0f7eed4a362..a7e41f366328 100644 --- a/app/helpers/confirmation_dialog_helper.rb +++ b/app/helpers/confirmation_dialog_helper.rb @@ -45,7 +45,7 @@ def augmented_confirmation_dialog( passed_data: nil ) { - "augmented-confirm-dialog": { + 'augmented-confirm-dialog': { text: { title:, text:, diff --git a/app/helpers/error_message_helper.rb b/app/helpers/error_message_helper.rb index 1c435aafe894..6b3205e4f3ac 100644 --- a/app/helpers/error_message_helper.rb +++ b/app/helpers/error_message_helper.rb @@ -38,12 +38,12 @@ def error_messages_for(object) end def render_error_messages_partial(errors, object) - return "" if errors.empty? + return '' if errors.empty? base_error_messages = errors.full_messages_for(:base) fields_error_messages = errors.full_messages - base_error_messages - render partial: "common/validation_error", + render partial: 'common/validation_error', locals: { base_error_messages:, fields_error_messages:, object_name: object.class.model_name.human } @@ -52,7 +52,7 @@ def render_error_messages_partial(errors, object) def text_header_invalid_fields(base_error_messages, fields_error_messages) return if fields_error_messages.blank? - i18n_key = base_error_messages.present? ? "errors.header_additional_invalid_fields" : "errors.header_invalid_fields" + i18n_key = base_error_messages.present? ? 'errors.header_additional_invalid_fields' : 'errors.header_invalid_fields' t(i18n_key, count: fields_error_messages.count) end diff --git a/app/helpers/errors_helper.rb b/app/helpers/errors_helper.rb index a7c389dfe810..f1af78315794 100644 --- a/app/helpers/errors_helper.rb +++ b/app/helpers/errors_helper.rb @@ -94,7 +94,7 @@ def render_error(arg) @message_details = arg[:message_details] respond_to do |format| format.html do - render template: "common/error", layout: use_layout, status: @status + render template: 'common/error', layout: use_layout, status: @status end format.any do head @status diff --git a/app/helpers/flash_messages_helper.rb b/app/helpers/flash_messages_helper.rb index 0fc868657ed8..edd9139efb7d 100644 --- a/app/helpers/flash_messages_helper.rb +++ b/app/helpers/flash_messages_helper.rb @@ -50,7 +50,7 @@ def render_flash_messages return if render_primer_banner_message? messages = flash - .reject { |k, _| k.start_with? "_" } + .reject { |k, _| k.start_with? '_' } .map do |k, v| if k.to_sym == :modal component = v[:type].constantize @@ -65,31 +65,31 @@ def render_flash_messages def join_flash_messages(messages) if messages.respond_to?(:join) - safe_join(messages, "
    ".html_safe) + safe_join(messages, '
    '.html_safe) else messages end end def render_flash_message(type, message, html_options = {}) # rubocop:disable Metrics/AbcSize - if type.to_s == "notice" - type = "success" + if type.to_s == 'notice' + type = 'success' end toast_css_classes = ["op-toast -#{type}", html_options.delete(:class)] # Add autohide class to notice flashes if configured - if type.to_s == "success" && User.current.pref.auto_hide_popups? - toast_css_classes << "autohide-toaster" + if type.to_s == 'success' && User.current.pref.auto_hide_popups? + toast_css_classes << 'autohide-toaster' end - html_options = { class: toast_css_classes.join(" "), role: "alert" }.merge(html_options) - close_button = content_tag :a, "", class: "op-toast--close icon-context icon-close", - title: I18n.t("js.close_popup_title"), - tabindex: "0" - toast = content_tag(:div, join_flash_messages(message), class: "op-toast--content") - content_tag :div, "", class: "op-toast--wrapper" do - content_tag :div, "", class: "op-toast--casing" do + html_options = { class: toast_css_classes.join(' '), role: 'alert' }.merge(html_options) + close_button = content_tag :a, '', class: 'op-toast--close icon-context icon-close', + title: I18n.t('js.close_popup_title'), + tabindex: '0' + toast = content_tag(:div, join_flash_messages(message), class: 'op-toast--content') + content_tag :div, '', class: 'op-toast--wrapper' do + content_tag :div, '', class: 'op-toast--casing' do content_tag :div, html_options do concat(close_button) concat(toast) diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index f64b3ef16da7..24a0baddcb97 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -30,26 +30,26 @@ module GroupsHelper def group_settings_tabs(group) [ { - name: "general", - partial: "groups/general", + name: 'general', + partial: 'groups/general', path: edit_group_path(group), label: :label_general }, { - name: "users", - partial: "groups/users", + name: 'users', + partial: 'groups/users', path: edit_group_path(group, tab: :users), label: :label_user_plural }, { - name: "memberships", - partial: "groups/memberships", + name: 'memberships', + partial: 'groups/memberships', path: edit_group_path(group, tab: :memberships), label: :label_project_plural }, { - name: "global_roles", - partial: "principals/global_roles", + name: 'global_roles', + partial: 'principals/global_roles', path: edit_group_path(group, tab: :global_roles), label: :label_global_roles } @@ -58,8 +58,8 @@ def group_settings_tabs(group) def autocompleter_filters(group) [ - { name: "status", operator: "=", values: ["active", "invited"] }, - { name: "group", operator: "!", values: [group.id] } + { name: 'status', operator: '=', values: ['active', 'invited'] }, + { name: 'group', operator: '!', values: [group.id] } ] end end diff --git a/app/helpers/homescreen_helper.rb b/app/helpers/homescreen_helper.rb index e0c624877b78..06bdf8d6452a 100644 --- a/app/helpers/homescreen_helper.rb +++ b/app/helpers/homescreen_helper.rb @@ -36,7 +36,7 @@ def organization_name ## # Homescreen organization icon def organization_icon - op_icon("icon-context icon-enterprise") + op_icon('icon-context icon-enterprise') end ## @@ -48,7 +48,7 @@ def static_link_to(key) link_to label, link[:href], title: label, - target: "_blank", rel: "noopener" + target: '_blank', rel: 'noopener' end ## diff --git a/app/helpers/hook_helper.rb b/app/helpers/hook_helper.rb index 40e10e1e5dab..c4e4a81b86cd 100644 --- a/app/helpers/hook_helper.rb +++ b/app/helpers/hook_helper.rb @@ -27,7 +27,7 @@ def call_hook(hook, context = {}) default_context = { project: @project, hook_caller: self } default_context[:controller] = controller if respond_to?(:controller) default_context[:request] = request if respond_to?(:request) - OpenProject::Hook.call_hook(hook, default_context.merge(context)).join(" ").html_safe + OpenProject::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe end end end diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index b9b6db8386ab..33a794a2285d 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -43,7 +43,7 @@ def spot_icon(icon_name, title: nil, size: nil, inline: false, classnames: nil) inline ? "spot-icon_inline" : nil, "spot-icon_#{icon_name}", classnames - ].compact.join(" ") + ].compact.join(' ') content_tag(:span, title, class: classes) end @@ -52,7 +52,7 @@ def spot_icon(icon_name, title: nil, size: nil, inline: false, classnames: nil) # Icon wrapper with an invisible label def icon_wrapper(icon_class, label) content = op_icon(icon_class) - content << content_tag(:span, label, class: "hidden-for-sighted") + content << content_tag(:span, label, class: 'hidden-for-sighted') content end end diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb index 1fcd32af5b64..1682c1e96edc 100644 --- a/app/helpers/journals_helper.rb +++ b/app/helpers/journals_helper.rb @@ -30,14 +30,14 @@ module JournalsHelper def back_to_activity_page_url(activity_page) - case activity_page&.split("/") - in ["all"] + case activity_page&.split('/') + in ['all'] activities_url - in ["projects", project_id] + in ['projects', project_id] project_activities_url(project_id) - in ["users", user_id] + in ['users', user_id] user_url(user_id) - in ["work_packages", work_package_id] + in ['work_packages', work_package_id] work_package_url(work_package_id) else nil diff --git a/app/helpers/mail_digest_helper.rb b/app/helpers/mail_digest_helper.rb index a449114a15a1..a299e59289cc 100644 --- a/app/helpers/mail_digest_helper.rb +++ b/app/helpers/mail_digest_helper.rb @@ -28,8 +28,8 @@ module MailDigestHelper def digest_summary_text(notification_count, mentioned_count) - mentioned = mentioned_count > 1 ? "plural" : "singular" - notifications = notification_count > 1 ? "plural" : "singular" + mentioned = mentioned_count > 1 ? 'plural' : 'singular' + notifications = notification_count > 1 ? 'plural' : 'singular' summary = I18n.t(:"mail.digests.unread_notification_#{notifications}", number_unread: notification_count).to_s @@ -63,7 +63,7 @@ def digest_additional_author_text(notifications) number_of_additional_authors = number_of_authors(notifications) - 1 if notifications.length > 1 && number_of_additional_authors > 0 - amount = number_of_additional_authors === 1 ? "one" : "other" + amount = number_of_additional_authors === 1 ? 'one' : 'other' I18n.t(:"js.notifications.center.and_more_users.#{amount}", count: number_of_additional_authors) end end @@ -76,7 +76,7 @@ def timestamp_text(user, journal) I18n.t(:"mail.work_packages.#{value}_at", user:, timestamp: journal.created_at.strftime( - "#{I18n.t(:"date.formats.default")}, #{I18n.t(:"time.formats.time")}" + "#{I18n.t(:'date.formats.default')}, #{I18n.t(:'time.formats.time')}" )) ) end @@ -100,27 +100,27 @@ def text_modifiers_for(notification, value) end def build_property_text(notification, is_overdue, days_diff) - return I18n.t("js.notifications.date_alerts.overdue") if is_overdue && days_diff > 0 - return I18n.t("js.notifications.date_alerts.milestone_date") if notification.resource.milestone? - return I18n.t("js.work_packages.properties.startDate") if notification.reason == "date_alert_start_date" + return I18n.t('js.notifications.date_alerts.overdue') if is_overdue && days_diff > 0 + return I18n.t('js.notifications.date_alerts.milestone_date') if notification.resource.milestone? + return I18n.t('js.work_packages.properties.startDate') if notification.reason == "date_alert_start_date" - I18n.t("js.work_packages.properties.dueDate") + I18n.t('js.work_packages.properties.dueDate') end def build_alert_text(date_value, is_past, is_overdue, days_diff) - return I18n.t("js.notifications.date_alerts.property_is_deleted") unless date_value - return I18n.t("js.notifications.date_alerts.property_today") if days_diff == 0 + return I18n.t('js.notifications.date_alerts.property_is_deleted') unless date_value + return I18n.t('js.notifications.date_alerts.property_today') if days_diff == 0 - days_text = I18n.t("js.units.day", count: days_diff) - return I18n.t("js.notifications.date_alerts.overdue_since", difference_in_days: days_text) if is_overdue - return I18n.t("js.notifications.date_alerts.property_was", difference_in_days: days_text) if is_past + days_text = I18n.t('js.units.day', count: days_diff) + return I18n.t('js.notifications.date_alerts.overdue_since', difference_in_days: days_text) if is_overdue + return I18n.t('js.notifications.date_alerts.property_was', difference_in_days: days_text) if is_past - I18n.t("js.notifications.date_alerts.property_is", difference_in_days: days_text) + I18n.t('js.notifications.date_alerts.property_is', difference_in_days: days_text) end def highlight_overdue(text, is_overdue, html) return text unless html && is_overdue - content_tag :span, text, style: "color: #C92A2A" + content_tag :span, text, style: 'color: #C92A2A' end end diff --git a/app/helpers/mail_layout_helper.rb b/app/helpers/mail_layout_helper.rb index 911fe514f0d1..3ca91ed4817b 100644 --- a/app/helpers/mail_layout_helper.rb +++ b/app/helpers/mail_layout_helper.rb @@ -29,32 +29,32 @@ module MailLayoutHelper def placeholder_table_styles(options = {}) default_options = { - style: "table-layout:fixed;border-collapse:separate;border-spacing:0;font-family:Helvetica;" << - (options[:style].present? ? options.delete(:style) : ""), + style: 'table-layout:fixed;border-collapse:separate;border-spacing:0;font-family:Helvetica;' << + (options[:style].present? ? options.delete(:style) : ''), cellspacing: "0", cellpadding: "0" } - default_options.merge(options).map { |k, v| "#{k}=#{v}" }.join(" ") + default_options.merge(options).map { |k, v| "#{k}=#{v}" }.join(' ') end def placeholder_text_styles(**overwrites) { - color: "#878787", - "line-height": "24px", - "font-size": "14px", - "white-space": "normal", - overflow: "hidden", - "max-width": "100%", - width: "100%" + color: '#878787', + 'line-height': '24px', + 'font-size': '14px', + 'white-space': 'normal', + overflow: 'hidden', + 'max-width': '100%', + width: '100%' }.merge(overwrites) .map { |k, v| "#{k}: #{v}" } - .join("; ") + .join('; ') end def action_button(&block) render( - partial: "mailer/mailer_button", + partial: 'mailer/mailer_button', locals: { block: } ) end @@ -66,15 +66,15 @@ def placeholder_cell(number, vertical:) "line-height:#{number}; max-width:0; min-width:0; height:#{number}; width:0; font-size:#{number}" end - content_tag("td", " ".html_safe, style:) + content_tag('td', ' '.html_safe, style:) end def user_salutation(user) case Setting.emails_salutation when :name - I18n.t(:"mail.salutation", user: user.name) + I18n.t(:'mail.salutation', user: user.name) else - I18n.t(:"mail.salutation", user: user.firstname) + I18n.t(:'mail.salutation', user: user.firstname) end end end diff --git a/app/helpers/mail_notification_helper.rb b/app/helpers/mail_notification_helper.rb index 6adcbea006ef..ef987c475f8d 100644 --- a/app/helpers/mail_notification_helper.rb +++ b/app/helpers/mail_notification_helper.rb @@ -36,7 +36,7 @@ def unique_reasons_of_notifications(notifications) end def notifications_path(id) - notifications_center_url(["details", id, "activity"]) + notifications_center_url(['details', id, 'activity']) end def type_color(type, default_fallback) @@ -51,6 +51,6 @@ def type_color(type, default_fallback) def status_colors(status) color_id = selected_color(status) - Color.find(color_id).color_styles.map { |k, v| "#{k}:#{v};" }.join(" ") if color_id + Color.find(color_id).color_styles.map { |k, v| "#{k}:#{v};" }.join(' ') if color_id end end diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb index 464e87e9f315..16d9998b0ded 100644 --- a/app/helpers/members_helper.rb +++ b/app/helpers/members_helper.rb @@ -34,13 +34,13 @@ module MembersHelper # If it is the later, the ids of the non delete roles are appended to the url so that they are kept. def global_member_role_deletion_link(member, role) if member.roles.length == 1 - link_to("", + link_to('', principal_membership_path(member.principal, member), - { method: :delete, class: "icon icon-delete", title: t(:button_delete) }) + { method: :delete, class: 'icon icon-delete', title: t(:button_delete) }) else - link_to("", - principal_membership_path(member.principal, member, "membership[role_ids]" => member.roles - [role]), - { method: :patch, class: "icon icon-delete", title: t(:button_delete) }) + link_to('', + principal_membership_path(member.principal, member, 'membership[role_ids]' => member.roles - [role]), + { method: :patch, class: 'icon icon-delete', title: t(:button_delete) }) end end diff --git a/app/helpers/meta_tags_helper.rb b/app/helpers/meta_tags_helper.rb index 480d244e13bd..2f8b27616bd6 100644 --- a/app/helpers/meta_tags_helper.rb +++ b/app/helpers/meta_tags_helper.rb @@ -32,7 +32,7 @@ module MetaTagsHelper def output_title_and_meta_tags display_meta_tags site: Setting.app_title, title: html_title_parts, - separator: " | ", # Update the TitleService when changing this! + separator: ' | ', # Update the TitleService when changing this! reverse: true end @@ -47,7 +47,7 @@ def initializer_meta_tag firstDayOfWeek: locale_first_day_of_week, environment: Rails.env, edition: OpenProject::Configuration.edition, - "asset-host": OpenProject::Configuration.rails_asset_host.presence + 'asset-host': OpenProject::Configuration.rails_asset_host.presence }.compact end diff --git a/app/helpers/no_results_helper.rb b/app/helpers/no_results_helper.rb index 1e4e7f25a4b1..872690b0b8cd 100644 --- a/app/helpers/no_results_helper.rb +++ b/app/helpers/no_results_helper.rb @@ -53,15 +53,15 @@ def no_results_box(action_url: nil, display_action: false, custom_title: nil, custom_action_text: nil) - title_text = custom_title || t(".no_results_title_text", cascade: true) || "" + title_text = custom_title || t('.no_results_title_text', cascade: true) || '' action_text = if display_action - custom_action_text || t(".no_results_content_text") + custom_action_text || t('.no_results_content_text') else - "" + '' end - action_url = action_url || "" + action_url = action_url || '' - render partial: "/common/no_results", + render partial: '/common/no_results', locals: { title_text:, action_text:, diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb index 52b85a0a25fe..824be596f1a8 100644 --- a/app/helpers/oauth_helper.rb +++ b/app/helpers/oauth_helper.rb @@ -35,7 +35,7 @@ def oauth_scope_translations(application) if strings.empty? I18n.t("oauth.scopes.api_v3") else - safe_join(strings.map { |scope| I18n.t("oauth.scopes.#{scope}", default: scope) }, "
    ".html_safe) + safe_join(strings.map { |scope| I18n.t("oauth.scopes.#{scope}", default: scope) }, '
    '.html_safe) end end diff --git a/app/helpers/omniauth_helper.rb b/app/helpers/omniauth_helper.rb index b8507f9b8589..78904124ec5c 100644 --- a/app/helpers/omniauth_helper.rb +++ b/app/helpers/omniauth_helper.rb @@ -42,6 +42,6 @@ def omniauth_direct_login? # If this option is active /login will lead directly to the configured omniauth provider # and so will a click on 'Sign in' (as opposed to opening the drop down menu). def direct_login_provider - OpenProject::Configuration["omniauth_direct_login_provider"] + OpenProject::Configuration['omniauth_direct_login_provider'] end end diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb index 95793c3f7be0..72389977c074 100644 --- a/app/helpers/pagination_helper.rb +++ b/app/helpers/pagination_helper.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "will_paginate" +require 'will_paginate' module PaginationHelper def pagination_links_full(paginator, options = {}) @@ -34,10 +34,10 @@ def pagination_links_full(paginator, options = {}) pagination_options = default_options.merge(options) - content_tag(:div, class: "op-pagination") do + content_tag(:div, class: 'op-pagination') do content = content_tag(:nav, pagination_entries(paginator, pagination_options), - class: "op-pagination--pages") + class: 'op-pagination--pages') if pagination_options[:per_page_links] content << pagination_option_links(paginator, pagination_options) @@ -52,7 +52,7 @@ def pagination_option_links(paginator, pagination_options) pagination_options[:params] .merge(safe_query_params(%w{filters sortBy expand}))) - content_tag(:div, option_links, class: "op-pagination--options") + content_tag(:div, option_links, class: 'op-pagination--options') end ## @@ -62,12 +62,12 @@ def pagination_entries(paginator, options) page_last = paginator.offset + paginator.length total = paginator.total_entries - content_tag(:ul, class: "op-pagination--items op-pagination--items_start") do + content_tag(:ul, class: 'op-pagination--items op-pagination--items_start') do # will_paginate will return nil early when no pages available - content = will_paginate(paginator, options) || "" + content = will_paginate(paginator, options) || '' range = "(#{page_first} - #{page_last}/#{total})" - content << content_tag(:li, range, class: "op-pagination--range", title: range) + content << content_tag(:li, range, class: 'op-pagination--range', title: range) content.html_safe end @@ -80,8 +80,8 @@ def pagination_settings(paginator, options) if links.size > 1 label = I18n.t(:label_per_page) - content_tag(:ul, class: "op-pagination--items op-pagination--items_end") do - content_tag(:li, label + ":", class: "op-pagination--label", title: label) + links + content_tag(:ul, class: 'op-pagination--items op-pagination--items_end') do + content_tag(:li, label + ':', class: 'op-pagination--label', title: label) + links end end end @@ -90,12 +90,12 @@ def pagination_settings(paginator, options) # Constructs the 'n items per page' entries # determined from available options in the settings. def per_page_links(paginator, options) - Setting.per_page_options_array.inject("") do |html, n| + Setting.per_page_options_array.inject('') do |html, n| if n == paginator.per_page - html + content_tag(:li, n, class: "op-pagination--item op-pagination--item_current") + html + content_tag(:li, n, class: 'op-pagination--item op-pagination--item_current') else - link = link_to_content_update(n, options.merge(page: 1, per_page: n), { class: "op-pagination--item-link" }) - html + content_tag(:li, link.html_safe, class: "op-pagination--item") + link = link_to_content_update(n, options.merge(page: 1, per_page: n), { class: 'op-pagination--item-link' }) + html + content_tag(:li, link.html_safe, class: 'op-pagination--item') end end.html_safe end @@ -159,7 +159,7 @@ def per_page_param(options = params) class LinkRenderer < ::WillPaginate::ActionView::LinkRenderer def to_html - pagination.inject("") do |html, item| + pagination.inject('') do |html, item| html + (item.is_a?(Integer) ? page_number(item) : send(item)) end.html_safe end @@ -173,33 +173,33 @@ def merge_get_params(url_params) def page_number(page) if page == current_page - tag(:li, page, class: "op-pagination--item op-pagination--item_current") + tag(:li, page, class: 'op-pagination--item op-pagination--item_current') else - tag(:li, link(page, page, { class: "op-pagination--item-link" }), class: "op-pagination--item") + tag(:li, link(page, page, { class: 'op-pagination--item-link' }), class: 'op-pagination--item') end end def gap - tag(:li, "…", class: "op-pagination--space") + tag(:li, '…', class: 'op-pagination--space') end def previous_page num = @collection.current_page > 1 && (@collection.current_page - 1) - previous_or_next_page(num, I18n.t(:label_previous), "prev") + previous_or_next_page(num, I18n.t(:label_previous), 'prev') end def next_page num = @collection.current_page < total_pages && (@collection.current_page + 1) - previous_or_next_page(num, I18n.t(:label_next), "next") + previous_or_next_page(num, I18n.t(:label_next), 'next') end def previous_or_next_page(page, text, class_suffix) if page tag(:li, - link(text, page, { class: "op-pagination--item-link op-pagination--item-link_" + class_suffix }), - class: "op-pagination--item op-pagination--item_" + class_suffix) + link(text, page, { class: 'op-pagination--item-link op-pagination--item-link_' + class_suffix }), + class: 'op-pagination--item op-pagination--item_' + class_suffix) else - "" + '' end end diff --git a/app/helpers/password_helper.rb b/app/helpers/password_helper.rb index fb2f3cf47366..c210329a4f31 100644 --- a/app/helpers/password_helper.rb +++ b/app/helpers/password_helper.rb @@ -56,7 +56,7 @@ def password_confirmation_form_tag(url_for_options = {}, options = {}, &) def password_confirmation_data_attribute(with_data = {}) if password_confirmation_required? - with_data.merge("request-for-confirmation": true) + with_data.merge('request-for-confirmation': true) else with_data end @@ -84,7 +84,7 @@ def password_active_rules # Returns a text describing the active password complexity rules, # the minimum number of rules to adhere to and the total number of rules. def password_rules_description - return "" if OpenProject::Passwords::Evaluator.min_adhered_rules == 0 + return '' if OpenProject::Passwords::Evaluator.min_adhered_rules == 0 OpenProject::Passwords::Evaluator.rules_description_locale(password_active_rules) end diff --git a/app/helpers/project_status_helper.rb b/app/helpers/project_status_helper.rb index c919bb61c825..8510e2d43dbb 100644 --- a/app/helpers/project_status_helper.rb +++ b/app/helpers/project_status_helper.rb @@ -29,7 +29,7 @@ module ProjectStatusHelper def project_status_css_class(status_code) code = project_status_ensure_default_code(status_code) - "-" + code.tr("_", "-") + '-' + code.tr('_', '-') end def project_status_name(status_code) @@ -38,11 +38,11 @@ def project_status_name(status_code) end def project_status_name_for_code(code) - code ||= "not_set" - I18n.t("js.grid.widgets.project_status." + code) + code ||= 'not_set' + I18n.t('js.grid.widgets.project_status.' + code) end def project_status_ensure_default_code(status_code) - status_code || "not_set" + status_code || 'not_set' end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 25557a74abec..e69ab162878d 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -35,7 +35,7 @@ module ProjectsHelper def projects_sort_header_tag(*) former_criteria = @sort_criteria.criteria.dup - @sort_criteria.criteria.reject! { |a, _| a == "lft" } + @sort_criteria.criteria.reject! { |a, _| a == 'lft' } sort_header_tag(*) ensure @@ -44,7 +44,7 @@ def projects_sort_header_tag(*) def short_project_description(project, length = 255) if project.description.blank? - return "" + return '' end project.description.gsub(/\A(.{#{length}}[^\n\r]*).*\z/m, '\1...').strip diff --git a/app/helpers/removed_js_helpers_helper.rb b/app/helpers/removed_js_helpers_helper.rb index 1d0b68095e3a..0c29d1809af1 100644 --- a/app/helpers/removed_js_helpers_helper.rb +++ b/app/helpers/removed_js_helpers_helper.rb @@ -36,7 +36,7 @@ def link_to_function(content, function, html_options = {}) id = html_options.delete(:id) { "link-to-function-#{SecureRandom.uuid}" } csp_onclick(function, "##{id}") - content_tag(:a, content, html_options.merge(id:, href: "")) + content_tag(:a, content, html_options.merge(id:, href: '')) end ## diff --git a/app/helpers/reorder_links_helper.rb b/app/helpers/reorder_links_helper.rb index 85e48232cbda..efa2463f4787 100644 --- a/app/helpers/reorder_links_helper.rb +++ b/app/helpers/reorder_links_helper.rb @@ -31,19 +31,19 @@ def reorder_links(name, url, options = {}) method = options[:method] || :post content_tag(:span, - reorder_link(name, url, "highest", "icon-sort-up", t(:label_sort_highest), method) + - reorder_link(name, url, "higher", "icon-arrow-up2", t(:label_sort_higher), method) + - reorder_link(name, url, "lower", "icon-arrow-down2", t(:label_sort_lower), method) + - reorder_link(name, url, "lowest", "icon-sort-down", t(:label_sort_lowest), method), - class: "reorder-icons") + reorder_link(name, url, 'highest', 'icon-sort-up', t(:label_sort_highest), method) + + reorder_link(name, url, 'higher', 'icon-arrow-up2', t(:label_sort_higher), method) + + reorder_link(name, url, 'lower', 'icon-arrow-down2', t(:label_sort_lower), method) + + reorder_link(name, url, 'lowest', 'icon-sort-down', t(:label_sort_lowest), method), + class: 'reorder-icons') end def reorder_link(name, url, direction, icon_class, label, method) text = content_tag(:span, label, - class: "hidden-for-sighted") + class: 'hidden-for-sighted') icon = content_tag(:span, - "", + '', class: "icon-context #{icon_class} icon-small") link_to(text + icon, url.merge("#{name}[move_to]" => direction), diff --git a/app/helpers/reports_helper.rb b/app/helpers/reports_helper.rb index 13f30ad0b890..a2896d9f195f 100644 --- a/app/helpers/reports_helper.rb +++ b/app/helpers/reports_helper.rb @@ -32,10 +32,10 @@ module ReportsHelper def aggregate(data, criteria) data&.inject(0) do |sum, row| match = criteria&.all? do |k, v| - row[k].to_s == v.to_s || (k == "closed" && row[k] == ActiveRecord::Type::Boolean.new.cast(v)) + row[k].to_s == v.to_s || (k == 'closed' && row[k] == ActiveRecord::Type::Boolean.new.cast(v)) end - sum += row["total"].to_i if match + sum += row['total'].to_i if match sum end || 0 @@ -43,6 +43,6 @@ def aggregate(data, criteria) def aggregate_link(data, criteria, *) a = aggregate data, criteria - a.positive? ? link_to(h(a), *) : "-" + a.positive? ? link_to(h(a), *) : '-' end end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 0fd7366f5804..151811a6fad9 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -38,7 +38,7 @@ def format_revision(revision) ## # Format revision commits with plain formatter def format_revision_text(commit_message) - format_text(commit_message, format: "plain") + format_text(commit_message, format: 'plain') end def truncate_at_line_break(text, length = 255) @@ -47,25 +47,25 @@ def truncate_at_line_break(text, length = 255) def render_properties(properties) unless properties.nil? || properties.empty? - content = "" + content = '' properties.keys.sort.each do |property| - content << content_tag("li", raw("#{h property}: #{h properties[property]}")) + content << content_tag('li', raw("#{h property}: #{h properties[property]}")) end - content_tag("ul", content.html_safe, class: "properties") + content_tag('ul', content.html_safe, class: 'properties') end end def render_changeset_changes - changes = @changeset.file_changes.limit(1000).order(Arel.sql("path")).filter_map do |change| + changes = @changeset.file_changes.limit(1000).order(Arel.sql('path')).filter_map do |change| case change.action - when "A" + when 'A' # Detects moved/copied files if change.from_path.present? - action = @changeset.file_changes.detect { |c| c.action == "D" && c.path == change.from_path } - change.action = action ? "R" : "C" + action = @changeset.file_changes.detect { |c| c.action == 'D' && c.path == change.from_path } + change.action = action ? 'R' : 'C' end change - when "D" + when 'D' @changeset.file_changes.detect { |c| c.from_path == change.path } ? nil : change else change @@ -75,8 +75,8 @@ def render_changeset_changes tree = {} changes.each do |change| p = tree - dirs = change.path.to_s.split("/").select { |d| d.present? } - path = "" + dirs = change.path.to_s.split('/').select { |d| d.present? } + path = '' dirs.each do |dir| path += with_leading_slash(dir) p[:s] ||= {} @@ -93,8 +93,8 @@ def render_changeset_changes # Mapping from internal action to (folder|file)-icon type def change_action_mapping { - "A" => :add, - "B" => :remove + 'A' => :add, + 'B' => :remove } end @@ -112,14 +112,14 @@ def calculate_folder_action(tree) end def render_changes_tree(tree) - return "" if tree.nil? + return '' if tree.nil? - output = "' output.html_safe end @@ -166,7 +166,7 @@ def to_utf8_for_repositories(str) str = to_utf8_internal(str) if str.respond_to?(:force_encoding) - str.force_encoding("UTF-8") + str.force_encoding('UTF-8') end str end @@ -175,17 +175,17 @@ def to_utf8_internal(str) return str if str.nil? if str.respond_to?(:force_encoding) - str.force_encoding("ASCII-8BIT") + str.force_encoding('ASCII-8BIT') end return str if str.empty? return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match?(str) # for us-ascii if str.respond_to?(:force_encoding) - str.force_encoding("UTF-8") + str.force_encoding('UTF-8') end - @encodings ||= Setting.repositories_encodings.split(",").map(&:strip) + @encodings ||= Setting.repositories_encodings.split(',').map(&:strip) @encodings.each do |encoding| - return str.to_s.encode("UTF-8", encoding) + return str.to_s.encode('UTF-8', encoding) rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError # do nothing here and try the next encoding end @@ -198,15 +198,15 @@ def replace_invalid_utf8(str) return str if str.nil? if str.respond_to?(:force_encoding) - str.force_encoding("UTF-8") + str.force_encoding('UTF-8') if !str.valid_encoding? str = str.encode("US-ASCII", invalid: :replace, - undef: :replace, replace: "?").encode("UTF-8") + undef: :replace, replace: '?').encode("UTF-8") end else # removes invalid UTF8 sequences begin - (str + " ").encode("UTF-8", invalid: :replace, undef: :replace, replace: "?")[0..-3] + (str + ' ').encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')[0..-3] rescue Encoding::InvalidByteSequenceError, Encoding::UndefinedConversionError end end @@ -234,29 +234,29 @@ def scm_options(repository = nil) def default_selected_option [ "--- #{I18n.t(:actionview_instancetag_blank_option)} ---", - "", + '', { disabled: true, selected: true } ] end def scm_vendor_tag(repository) # rubocop:disable Rails/HelperInstanceVariable - url = url_for(controller: "/projects/settings/repository", action: "show", id: @project.id) + url = url_for(controller: '/projects/settings/repository', action: 'show', id: @project.id) # rubocop:enable Rails/HelperInstanceVariable # - select_tag("scm_vendor", + select_tag('scm_vendor', scm_options(repository), - class: "form--select", + class: 'form--select', data: { url:, - action: "repository-settings#updateSelectedType", - "repository-settings-target": "scmVendor" + action: 'repository-settings#updateSelectedType', + 'repository-settings-target': 'scmVendor' }, disabled: repository && !repository.new_record?) end def git_path_encoding_options(repository) - default = repository.new_record? ? "UTF-8" : repository.path_encoding + default = repository.new_record? ? 'UTF-8' : repository.path_encoding options_for_select(Setting::ENCODINGS, default) end @@ -270,22 +270,22 @@ def show_settings_save_button?(_repository) end def with_leading_slash(path) - path.to_s.starts_with?("/") ? path : "/#{path}" + path.to_s.starts_with?('/') ? path : "/#{path}" end def without_leading_slash(path) - path.gsub(%r{\A/+}, "") + path.gsub(%r{\A/+}, '') end def changes_tree_change_title(action) case action - when "A" + when 'A' I18n.t(:label_added) - when "D" + when 'D' I18n.t(:label_deleted) - when "C" + when 'C' I18n.t(:label_copied) - when "R" + when 'R' I18n.t(:label_renamed) else I18n.t(:label_modified) @@ -294,16 +294,16 @@ def changes_tree_change_title(action) def changes_tree_li_element(action, text, style) icon_name = case action - when "A" - "icon-add" - when "D" - "icon-delete" - when "C" - "icon-copy" - when "R" - "icon-rename" + when 'A' + 'icon-add' + when 'D' + 'icon-delete' + when 'C' + 'icon-copy' + when 'R' + 'icon-rename' else - "icon-arrow-left-right" + 'icon-arrow-left-right' end "
  • <%= link_to new_attribute_help_text_path(name: selected_tab(tabs)[:name]), - { class: 'attribute-help-texts--create-button button -primary', + { class: 'attribute-help-texts--create-button button -alt-highlight', aria: {label: t(:'attribute_help_texts.add_new')}, title: t(:'attribute_help_texts.add_new')} do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/attribute_help_texts/new.html.erb b/app/views/attribute_help_texts/new.html.erb index 32e6d3cf9056..03a17460fb43 100644 --- a/app/views/attribute_help_texts/new.html.erb +++ b/app/views/attribute_help_texts/new.html.erb @@ -38,5 +38,5 @@ See COPYRIGHT and LICENSE files for more details. html: {id: 'attribute_help_text_form'} do |f| %> <%= render partial: 'form', locals: { f: f } %> <%= f.hidden_field :type, value: @attribute_help_text.type %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/categories/destroy.html.erb b/app/views/categories/destroy.html.erb index 3c95064abc9b..62ba944e437d 100644 --- a/app/views/categories/destroy.html.erb +++ b/app/views/categories/destroy.html.erb @@ -48,6 +48,6 @@ See COPYRIGHT and LICENSE files for more details. <% end %> - <%= submit_tag t(:button_apply), class: 'button -primary' %> + <%= submit_tag t(:button_apply), class: 'button -highlight' %> <%= link_to t(:button_cancel), project_settings_categories_path(@project), class: 'button' %> <% end %> diff --git a/app/views/categories/edit.html.erb b/app/views/categories/edit.html.erb index 6cbc6aff4986..ad6e532836a0 100644 --- a/app/views/categories/edit.html.erb +++ b/app/views/categories/edit.html.erb @@ -29,5 +29,5 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: Category.model_name.human %> <%= labelled_tabular_form_for @category, as: :category do |f| %> <%= render partial: 'categories/form', locals: { f: f } %> - <%= f.button t(:button_save), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_save), class: 'button -highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/categories/new.html.erb b/app/views/categories/new.html.erb index 683d5d4f82df..aaa02e7a9f07 100644 --- a/app/views/categories/new.html.erb +++ b/app/views/categories/new.html.erb @@ -29,5 +29,5 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t(:label_work_package_category_new) %> <%= labelled_tabular_form_for [@project, @category], as: :category do |f| %> <%= render partial: 'categories/form', locals: { f: f } %> - <%= f.button t(:button_create), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_create), class: 'button -highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/colors/_form.html.erb b/app/views/colors/_form.html.erb index 182c71e26975..3d4cb7ae788b 100644 --- a/app/views/colors/_form.html.erb +++ b/app/views/colors/_form.html.erb @@ -64,5 +64,5 @@ See COPYRIGHT and LICENSE files for more details. -<%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> +<%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), colors_path, class: 'button -with-icon icon-cancel' %> diff --git a/app/views/colors/confirm_destroy.html.erb b/app/views/colors/confirm_destroy.html.erb index d61560857c9b..e66e15b680b1 100644 --- a/app/views/colors/confirm_destroy.html.erb +++ b/app/views/colors/confirm_destroy.html.erb @@ -47,6 +47,6 @@ See COPYRIGHT and LICENSE files for more details. - <%= submit_tag t(:button_delete), class: 'button -primary' %> + <%= submit_tag t(:button_delete), class: 'button -highlight' %> <%= link_to t(:button_cancel), colors_path, class: 'button' %> <% end %> diff --git a/app/views/colors/index.html.erb b/app/views/colors/index.html.erb index 9ab599846318..06dee2929b6b 100644 --- a/app/views/colors/index.html.erb +++ b/app/views/colors/index.html.erb @@ -32,7 +32,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t(:label_color_plural) do %>
  • <%= link_to new_color_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t('.label_new_color')}, title: t('.label_new_color')} do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/common/feed.atom.builder b/app/views/common/feed.atom.builder index 8faa7a4afe6c..a4681450af54 100644 --- a/app/views/common/feed.atom.builder +++ b/app/views/common/feed.atom.builder @@ -35,7 +35,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do xml.title truncate_single_line(@title, length: 100) xml.link "rel" => "self", "href" => url_for(only_path: false) xml.link "rel" => "alternate", "href" => url_for(only_path: false, format: nil, key: nil) - xml.id url_for(controller: "/homescreen", action: :index, only_path: false) + xml.id url_for(controller: '/homescreen', action: :index, only_path: false) xml.updated(updated_time.xmlschema) xml.author { xml.name Setting.app_title } xml.generator(uri: OpenProject::Info.url) { xml.text! OpenProject::Info.app_name } diff --git a/app/views/common/upsale.html.erb b/app/views/common/upsale.html.erb index 503f19ece9dd..956dae8ecbf6 100644 --- a/app/views/common/upsale.html.erb +++ b/app/views/common/upsale.html.erb @@ -49,7 +49,7 @@ <% end %> <%= link_to(OpenProject::Static::Links.links[:pricing][:href], - { class: 'button -primary', + { class: 'button -highlight', aria: {label: t('admin.enterprise.buttons.upgrade')}, target: '_blank', title: t('admin.enterprise.buttons.upgrade')}) do %> diff --git a/app/views/custom_actions/edit.html.erb b/app/views/custom_actions/edit.html.erb index 8497d6473bbd..cc30bcac8f8b 100644 --- a/app/views/custom_actions/edit.html.erb +++ b/app/views/custom_actions/edit.html.erb @@ -36,5 +36,5 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @custom_action do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/custom_actions/index.html.erb b/app/views/custom_actions/index.html.erb index 198a980abfd6..102406b6f627 100644 --- a/app/views/custom_actions/index.html.erb +++ b/app/views/custom_actions/index.html.erb @@ -2,7 +2,7 @@ <%= toolbar title: t('custom_actions.plural') do %>
  • <%= link_to new_custom_action_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: { label: t('custom_actions.new') }, title: t('custom_actions.new') } do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/custom_actions/new.html.erb b/app/views/custom_actions/new.html.erb index a836500870ea..a0111056ccc4 100644 --- a/app/views/custom_actions/new.html.erb +++ b/app/views/custom_actions/new.html.erb @@ -36,5 +36,5 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @custom_action do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/custom_fields/edit.html.erb b/app/views/custom_fields/edit.html.erb index 9281171675d5..563354707b13 100644 --- a/app/views/custom_fields/edit.html.erb +++ b/app/views/custom_fields/edit.html.erb @@ -44,5 +44,5 @@ See COPYRIGHT and LICENSE files for more details. url: custom_field_path(@custom_field), html: {method: :put, id: 'custom_field_form'} do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/custom_fields/index.html.erb b/app/views/custom_fields/index.html.erb index 8b87fbce3438..0466c66b52ab 100644 --- a/app/views/custom_fields/index.html.erb +++ b/app/views/custom_fields/index.html.erb @@ -29,7 +29,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t(:label_custom_field_plural) do %>
  • <%= link_to new_custom_field_path(type: selected_tab(custom_fields_tabs)[:name]), - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_custom_field_new)}, title: t(:label_custom_field_new)} do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/custom_fields/new.html.erb b/app/views/custom_fields/new.html.erb index 38820445911d..7bfb0bae8230 100644 --- a/app/views/custom_fields/new.html.erb +++ b/app/views/custom_fields/new.html.erb @@ -43,5 +43,5 @@ See COPYRIGHT and LICENSE files for more details. html: {id: 'custom_field_form', class: "-wide-labels"} do |f| %> <%= render partial: 'form', locals: { f: f } %> <%= hidden_field_tag 'type', @custom_field.type %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/custom_styles/_inline_css.erb b/app/views/custom_styles/_inline_css.erb index 7ab9ebb63089..4e2ca2f2af2f 100644 --- a/app/views/custom_styles/_inline_css.erb +++ b/app/views/custom_styles/_inline_css.erb @@ -37,14 +37,16 @@ See COPYRIGHT and LICENSE files for more details. <% if design_color.variable == "main-menu-border-color" %> --main-menu-border-width: 1px; <% end %> - <% if design_color.variable == "primary-button-color" %> - --primary-button-color--major1: <%= design_color.darken 0.18 %>; + <% if design_color.variable == "alternative-color" %> + --button--alt-highlight-background-hover-color: <%= design_color.darken 0.18 %>; <% end %> - <% if design_color.variable == "accent-color" %> - --accent-color--major1: <%= design_color.darken 0.2 %>; - --accent-color--major2: <%= design_color.darken 0.4 %>; - --accent-color--minor1: <%= design_color.lighten 0.8 %>; - --accent-color--minor2: <%= design_color.lighten 0.6 %>; + <% if design_color.variable == "primary-color" %> + --primary-color--minor1: <%= design_color.lighten 0.3 %>; + --primary-color--minor2: <%= design_color.lighten 0.6 %>; + --primary-color--minor3: <%= design_color.lighten 0.8 %>; + --primary-color--major1: <%= design_color.darken 0.2 %>; + --primary-color--major2: <%= design_color.darken 0.4 %>; + --primary-color--major3: <%= design_color.darken 0.6 %>; <% end %> <% end %> } diff --git a/app/views/custom_styles/_inline_css_logo.erb b/app/views/custom_styles/_inline_css_logo.erb index 9ac46c69ed8a..8059da75e50b 100644 --- a/app/views/custom_styles/_inline_css_logo.erb +++ b/app/views/custom_styles/_inline_css_logo.erb @@ -32,7 +32,6 @@ See COPYRIGHT and LICENSE files for more details. <% logo_url = asset_path("logo_openproject_white_big.png") high_contrast_logo_url = asset_path("logo_openproject.png") - high_contrast_bim_logo_url = asset_path("bim/logo_openproject_bim_big_coloured.png") if apply_custom_styles? if CustomStyle.current.logo.present? @@ -48,7 +47,7 @@ See COPYRIGHT and LICENSE files for more details. } .op-logo--link_high_contrast { - background-image: url(<%= OpenProject::Configuration.bim? ? high_contrast_bim_logo_url : high_contrast_logo_url %>); + background-image: url(<%= high_contrast_logo_url %>); } <% end %> diff --git a/app/views/custom_styles/_primer_color_mapping.erb b/app/views/custom_styles/_primer_color_mapping.erb index 424b9edb4199..0286ded552bf 100644 --- a/app/views/custom_styles/_primer_color_mapping.erb +++ b/app/views/custom_styles/_primer_color_mapping.erb @@ -8,10 +8,9 @@ /* Override Primer variable to ensure compatibility with currently configured design outside of high contrast mode */ [data-color-mode]:not([data-light-theme=light_high_contrast]) { - --color-accent-fg: var(--accent-color) !important; - --control-checked-bgColor-rest: var(--control-checked-color) !important; - --button-primary-bgColor-rest: var(--button--primary-background-color) !important; - --button-primary-bgColor-hover: var(--button--primary-background-hover-color) !important; + --color-accent-fg: var(--content-link-color) !important; + --button-primary-bgColor-rest: var(--button--alt-highlight-background-color); !important; + --button-primary-bgColor-hover: var(--button--alt-highlight-background-hover-color) !important; } [data-light-theme=light_high_contrast]{ --avatar-border-color: var(--color-avatar-border); @@ -42,13 +41,15 @@ --main-menu-fieldset-header-color: var(--color-fg-subtle) !important; --main-menu-border-width: 1px; --button--border-color: var(--color-border-default); - --button--primary-background-hover-color: var(--color-btn-primary-hover-bg); - --button--primary-background-color: var(--color-btn-primary-bg); + --button--alt-highlight-background-hover-color: var(--color-btn-primary-hover-bg); + --button--alt-highlight-background-color: var(--color-btn-primary-bg); --button--active-border-color: var(--color-border-default); --button--background-hover-color: var(--color-btn-hover-bg); --button--background-color: var(--color-btn-bg); - --accent-color: var(--color-accent-fg); - --primary-button-color: var(--color-btn-primary-bg); + --button--highlight-background-color: var(--color-btn-primary-bg); + --button--highlight-background-hover-color: var(--color-btn-primary-hover-bg); + --content-link-color: var(--color-accent-fg); + --alternative-color: var(--color-btn-primary-bg); --status-selector-border-color: var(--button--border-color); --link-text-decoration: underline; } diff --git a/app/views/doorkeeper/authorizations/new.html.erb b/app/views/doorkeeper/authorizations/new.html.erb index 4b9ec3090f7b..e8cb1f739c1f 100644 --- a/app/views/doorkeeper/authorizations/new.html.erb +++ b/app/views/doorkeeper/authorizations/new.html.erb @@ -34,7 +34,7 @@ <%= hidden_field_tag :scope, @pre_auth.scope %> <%= hidden_field_tag :code_challenge, @pre_auth.code_challenge %> <%= hidden_field_tag :code_challenge_method, @pre_auth.code_challenge_method %> - <%= submit_tag t('oauth.authorization_dialog.authorize'), class: "button -primary -expand" %> + <%= submit_tag t('oauth.authorization_dialog.authorize'), class: "button -highlight -expand" %> <% end %>
    <%= form_tag oauth_authorization_path, method: :delete do %> diff --git a/app/views/enterprises/_form.html.erb b/app/views/enterprises/_form.html.erb index 2da2486690f3..087ea215e4d3 100644 --- a/app/views/enterprises/_form.html.erb +++ b/app/views/enterprises/_form.html.erb @@ -19,7 +19,7 @@ spellcheck: false %>
    - <%= styled_button_tag t(:button_save), id: 'token-submit-button', class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), id: 'token-submit-button', class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { action: :show }, class: 'button -with-icon icon-cancel' %> <% end %> <% end %> diff --git a/app/views/enumerations/destroy.html.erb b/app/views/enumerations/destroy.html.erb index a7c8958518d7..587b6a1291a3 100644 --- a/app/views/enumerations/destroy.html.erb +++ b/app/views/enumerations/destroy.html.erb @@ -37,7 +37,7 @@ See COPYRIGHT and LICENSE files for more details. - <%= styled_submit_tag t(:button_apply), class: '-primary' %> + <%= styled_submit_tag t(:button_apply), class: '-highlight' %> <%= link_to t(:button_cancel), { controller: '/enumerations', action: 'index' }, class: 'button' %> <% end %> diff --git a/app/views/enumerations/edit.html.erb b/app/views/enumerations/edit.html.erb index ade18a3f67b4..2b23d1887b8e 100644 --- a/app/views/enumerations/edit.html.erb +++ b/app/views/enumerations/edit.html.erb @@ -34,7 +34,7 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @enumeration do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> <%= styled_form_tag(enumeration_path(@enumeration), method: :delete) do %> diff --git a/app/views/enumerations/new.html.erb b/app/views/enumerations/new.html.erb index 0f919ce7ee41..324203a1f22e 100644 --- a/app/views/enumerations/new.html.erb +++ b/app/views/enumerations/new.html.erb @@ -32,5 +32,5 @@ See COPYRIGHT and LICENSE files for more details. <%= breadcrumb_toolbar t(:label_enumeration_new) %> <%= labelled_tabular_form_for @enumeration do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/forums/edit.html.erb b/app/views/forums/edit.html.erb index 59d724ea6697..58cdd8a90048 100644 --- a/app/views/forums/edit.html.erb +++ b/app/views/forums/edit.html.erb @@ -30,6 +30,6 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for [@project, @forum] do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= f.button t(:button_save), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_save), class: 'button -highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), project_forums_path(@project), class: 'button -with-icon icon-cancel' %> <% end %> diff --git a/app/views/forums/index.html.erb b/app/views/forums/index.html.erb index 2f0d761762a5..d3add7f3a478 100644 --- a/app/views/forums/index.html.erb +++ b/app/views/forums/index.html.erb @@ -33,7 +33,7 @@ See COPYRIGHT and LICENSE files for more details. <%= link_to(new_project_forum_path(@project), { aria: { label: t(:label_forum_new) }, title: t(:label_forum_new), - class: 'button -primary' }) do %> + class: 'button -alt-highlight' }) do %> <%= op_icon('button--icon icon-add') %> <%= t('activerecord.models.forum') %> <% end %> diff --git a/app/views/forums/new.html.erb b/app/views/forums/new.html.erb index c17d6bc30a73..b46a46476b5f 100644 --- a/app/views/forums/new.html.erb +++ b/app/views/forums/new.html.erb @@ -31,6 +31,6 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for [@project, @forum] do |f| %> <%= render partial: 'form', locals: {f: f} %> - <%= f.button t(:button_create), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_create), class: 'button -highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), project_forums_path(@project), class: 'button -with-icon icon-cancel' %> <% end %> diff --git a/app/views/forums/show.html.erb b/app/views/forums/show.html.erb index cc1136287572..eed48f95f43e 100644 --- a/app/views/forums/show.html.erb +++ b/app/views/forums/show.html.erb @@ -38,7 +38,7 @@ See COPYRIGHT and LICENSE files for more details. <%= render partial: 'messages/form', locals: {f: f} %>
    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), '', class: 'cancel-add-message-button button -with-icon icon-cancel' %> <% csp_onclick('jQuery("#add-message").hide();', '.cancel-add-message-button') %> <% end %> @@ -50,7 +50,7 @@ See COPYRIGHT and LICENSE files for more details. <% if authorize_for(:messages, :new) %>
  • <%= link_to({controller: '/messages', action: 'new', forum_id: @forum}, - {class: 'add-message-button button -primary', + {class: 'add-message-button button -alt-highlight', aria: {label: t(:label_message_new)}, title: t(:label_message_new)}) do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/groups/_general.html.erb b/app/views/groups/_general.html.erb index 06238c28cab2..597256d4f5cf 100644 --- a/app/views/groups/_general.html.erb +++ b/app/views/groups/_general.html.erb @@ -29,5 +29,5 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @group, url: group_path(@group), html: {method: :put}, as: :group do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/groups/_memberships.html.erb b/app/views/groups/_memberships.html.erb index 03364ee2adc1..cbb4dd062039 100644 --- a/app/views/groups/_memberships.html.erb +++ b/app/views/groups/_memberships.html.erb @@ -95,7 +95,7 @@ See COPYRIGHT and LICENSE files for more details. <% end %>

    - <%= submit_tag t(:button_change), class: 'button -primary -small' %> + <%= submit_tag t(:button_change), class: 'button -highlight -small' %> <%= link_to_function t(:button_cancel), "jQuery('#member-#{membership.id}-roles').show(); jQuery('#member-#{membership.id}-roles-form').hide();", class: 'button -small' %>

    @@ -146,7 +146,7 @@ See COPYRIGHT and LICENSE files for more details. <%= labeled_check_box_tags 'membership[role_ids][]', roles %> -
    <%= styled_button_tag t(:button_add), class: '-primary -with-icon icon-checkmark' %>
    +
    <%= styled_button_tag t(:button_add), class: '-highlight -with-icon icon-checkmark' %>
    <% end %> <% end %> diff --git a/app/views/groups/_users.html.erb b/app/views/groups/_users.html.erb index cb511e6762d4..32fd094c0e8b 100644 --- a/app/views/groups/_users.html.erb +++ b/app/views/groups/_users.html.erb @@ -62,7 +62,7 @@ See COPYRIGHT and LICENSE files for more details.
    <%= styled_button_tag t(:button_add), - class: '-primary -with-icon icon-checkmark' %> + class: '-highlight -with-icon icon-checkmark' %>
    <% end %> diff --git a/app/views/groups/index.html.erb b/app/views/groups/index.html.erb index e0894b0a9918..5a6c29f31355 100644 --- a/app/views/groups/index.html.erb +++ b/app/views/groups/index.html.erb @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t(:label_group_plural) do %>
  • <%= link_to new_group_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_group_new)}, title: t(:label_group_new)} do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/groups/new.html.erb b/app/views/groups/new.html.erb index ef6c1e256e03..b4bbdf816a4c 100644 --- a/app/views/groups/new.html.erb +++ b/app/views/groups/new.html.erb @@ -33,5 +33,5 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for(@group) do |f| %> <%= render partial: 'form', locals: { f: f } %> -
    <%= f.button t(:button_create), class: 'button -primary -with-icon icon-checkmark' %>
    +
    <%= f.button t(:button_create), class: 'button -highlight -with-icon icon-checkmark' %>
    <% end %> diff --git a/app/views/homescreen/blocks/_projects.html.erb b/app/views/homescreen/blocks/_projects.html.erb index f8cfc7ebf327..59d6dc83d78e 100644 --- a/app/views/homescreen/blocks/_projects.html.erb +++ b/app/views/homescreen/blocks/_projects.html.erb @@ -19,7 +19,7 @@
    <% if User.current.allowed_globally?(:add_project) %> <%= link_to new_project_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_project_new)}, title: t(:label_project_new)} do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/homescreen/blocks/_upsale.html.erb b/app/views/homescreen/blocks/_upsale.html.erb index 5acad4a2b83b..826cec5ced76 100644 --- a/app/views/homescreen/blocks/_upsale.html.erb +++ b/app/views/homescreen/blocks/_upsale.html.erb @@ -30,7 +30,7 @@ <% end %> <%= link_to(OpenProject::Static::Links.links[:pricing][:href], - class: 'button -primary', + class: 'button -highlight', target: '_blank', rel: 'noopener') do %> <%= spot_icon('enterprise-addons') %> @@ -38,6 +38,6 @@ <% end %> <% if current_user.admin? %> - <%= link_to t('js.admin.enterprise.upsale.button_start_trial'), enterprise_path, class: 'button -primary' %> + <%= link_to t('js.admin.enterprise.upsale.button_start_trial'), enterprise_path, class: 'button -alt-highlight' %> <% end %>
    diff --git a/app/views/homescreen/blocks/_users.html.erb b/app/views/homescreen/blocks/_users.html.erb index 2bc2b31a58f4..26f040708c1e 100644 --- a/app/views/homescreen/blocks/_users.html.erb +++ b/app/views/homescreen/blocks/_users.html.erb @@ -15,7 +15,7 @@
    <% if User.current.admin? %> - <%= link_to new_user_path, class: 'button -primary' do %> + <%= link_to new_user_path, class: 'button -alt-highlight' do %> <%= op_icon('button--icon icon-add') %> <%= t(:label_invite_user) %> <% end %> diff --git a/app/views/individual_principals/_memberships.html.erb b/app/views/individual_principals/_memberships.html.erb index ae758fff8472..e931d16e6180 100644 --- a/app/views/individual_principals/_memberships.html.erb +++ b/app/views/individual_principals/_memberships.html.erb @@ -104,7 +104,7 @@ See COPYRIGHT and LICENSE files for more details. <% end %>
    -

    <%= submit_tag t(:button_change), class: 'memberships--edit-submit-button button -primary -small' %> +

    <%= submit_tag t(:button_change), class: 'memberships--edit-submit-button button -highlight -small' %> <%= link_to_function t(:button_cancel), "jQuery('.member-#{membership.id}--edit-toggle-item').toggle();", class: 'button -small' %>

    @@ -164,7 +164,7 @@ See COPYRIGHT and LICENSE files for more details. <%= labeled_check_box_tags 'membership[role_ids][]', roles %> -
    <%= styled_button_tag t(:button_add), class: '-primary -with-icon icon-checkmark' %>
    +
    <%= styled_button_tag t(:button_add), class: '-highlight -with-icon icon-checkmark' %>
    <% end %> <% end %> diff --git a/app/views/ldap_auth_sources/edit.html.erb b/app/views/ldap_auth_sources/edit.html.erb index 11c9bd88faad..2751fdb4cc28 100644 --- a/app/views/ldap_auth_sources/edit.html.erb +++ b/app/views/ldap_auth_sources/edit.html.erb @@ -34,6 +34,6 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @ldap_auth_source do |f| %> <%= render partial: 'form', locals: { f: f } %> <% unless @ldap_auth_source.seeded_from_env? %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> <% end %> diff --git a/app/views/ldap_auth_sources/index.html.erb b/app/views/ldap_auth_sources/index.html.erb index cf2501c8cf5c..6e4495f8bee3 100644 --- a/app/views/ldap_auth_sources/index.html.erb +++ b/app/views/ldap_auth_sources/index.html.erb @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t(:label_ldap_auth_source_plural) do %>
  • <%= link_to({ action: 'new' }, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_ldap_auth_source_new)}, title: t(:label_ldap_auth_source_new)}) do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/ldap_auth_sources/new.html.erb b/app/views/ldap_auth_sources/new.html.erb index 9440a214ac01..b16c9cb4057e 100644 --- a/app/views/ldap_auth_sources/new.html.erb +++ b/app/views/ldap_auth_sources/new.html.erb @@ -33,5 +33,5 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @ldap_auth_source, as: :ldap_auth_source do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/members/_autocomplete_for_member.html.erb b/app/views/members/_autocomplete_for_member.html.erb index 7b1dd229b007..6152432580a4 100644 --- a/app/views/members/_autocomplete_for_member.html.erb +++ b/app/views/members/_autocomplete_for_member.html.erb @@ -64,6 +64,6 @@ See COPYRIGHT and LICENSE files for more details. <%= styled_button_tag t(:button_add), id: 'member-add-submit', - class: 'button -primary -with-icon icon-checkmark', + class: 'button -highlight -with-icon icon-checkmark', style: roles.any? && (principals.any? && principals.size <= 20) ? "": "display:none" %> <%= link_to I18n.t('button_cancel'), '', class: 'button -with-icon icon-cancel hide-member-form-button', role: 'button' %> diff --git a/app/views/members/_member_form.html.erb b/app/views/members/_member_form.html.erb index 4831a7138396..53f64796c646 100644 --- a/app/views/members/_member_form.html.erb +++ b/app/views/members/_member_form.html.erb @@ -94,7 +94,7 @@ See COPYRIGHT and LICENSE files for more details.
    <%= f.button t(:button_add), - class: 'button -primary -with-icon icon-checkmark', + class: 'button -highlight -with-icon icon-checkmark', id: 'add-member--submit-button' %>
    diff --git a/app/views/messages/edit.html.erb b/app/views/messages/edit.html.erb index 887edb8f3190..b5ceb1997125 100644 --- a/app/views/messages/edit.html.erb +++ b/app/views/messages/edit.html.erb @@ -39,7 +39,7 @@ See COPYRIGHT and LICENSE files for more details.
    - <%= f.button t(:button_save), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_save), class: 'button -highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), topic_path(@message), class: 'button -with-icon icon-cancel' %> <% end %>
    diff --git a/app/views/messages/new.html.erb b/app/views/messages/new.html.erb index c46bfac6ed85..c28a1623eb8e 100644 --- a/app/views/messages/new.html.erb +++ b/app/views/messages/new.html.erb @@ -38,7 +38,7 @@ See COPYRIGHT and LICENSE files for more details.
    - <%= f.button t(:button_create), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_create), class: 'button -highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), project_forum_path(@project, @forum), class: 'button -with-icon icon-cancel' %> <% end %> diff --git a/app/views/messages/show.html.erb b/app/views/messages/show.html.erb index 885cd475b28f..1d8957ab75db 100644 --- a/app/views/messages/show.html.erb +++ b/app/views/messages/show.html.erb @@ -145,7 +145,7 @@ See COPYRIGHT and LICENSE files for more details.
    - <%= f.button t(:button_submit), class: 'button -primary -primary -with-icon icon-checkmark' %> + <%= f.button t(:button_submit), class: 'button -highlight -highlight -with-icon icon-checkmark' %> <% end %>
    diff --git a/app/views/my/account.html.erb b/app/views/my/account.html.erb index db4116c03a2d..ab609a78f434 100644 --- a/app/views/my/account.html.erb +++ b/app/views/my/account.html.erb @@ -49,31 +49,19 @@ See COPYRIGHT and LICENSE files for more details. <% login_via_provider = !!@user.identity_url %> - <% login_via_ldap = !!@user.ldap_auth_source_id %>
    - <%= f.text_field :firstname, required: true, container_class: '-middle', disabled: login_via_provider || login_via_ldap %> + <%= f.text_field :firstname, required: true, container_class: '-middle', disabled: login_via_provider %> <% if login_via_provider %> <%= t('user.text_change_disabled_for_provider_login') %> <% end %> - <% if login_via_ldap %> - <%= t('user.text_change_disabled_for_ldap_login') %> - <% end %>
    - <%= f.text_field :lastname, required: true, container_class: '-middle', disabled: login_via_provider || login_via_ldap %> + <%= f.text_field :lastname, required: true, container_class: '-middle', disabled: login_via_provider %> <% if login_via_provider %> <%= t('user.text_change_disabled_for_provider_login') %> <% end %> - <% if login_via_ldap %> - <%= t('user.text_change_disabled_for_ldap_login') %> - <% end %> -
    -
    - <%= f.text_field :mail, required: true, container_class: '-middle', disabled: login_via_ldap %> - <% if login_via_ldap %> - <%= t('user.text_change_disabled_for_ldap_login') %> - <% end %>
    +
    <%= f.text_field :mail, required: true, container_class: '-middle' %>
    <%= fields_for :pref, @user.pref, builder: TabularFormBuilder, lang: current_language do |pref_fields| %>
    <%= pref_fields.check_box :hide_mail %>
    @@ -85,5 +73,5 @@ See COPYRIGHT and LICENSE files for more details. locals: { form: f, all_fields: true, only_required: false, input_size: '-middle' } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/my/password.html.erb b/app/views/my/password.html.erb index 9fd43c65af52..f5c1057d333f 100644 --- a/app/views/my/password.html.erb +++ b/app/views/my/password.html.erb @@ -40,5 +40,5 @@ See COPYRIGHT and LICENSE files for more details. locals: { show_user_name: !!(defined? show_user_name) ? show_user_name : nil, input_size: :middle } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/my/settings.html.erb b/app/views/my/settings.html.erb index 39563fd12ef7..b0d30f73ab6a 100644 --- a/app/views/my/settings.html.erb +++ b/app/views/my/settings.html.erb @@ -41,5 +41,5 @@ See COPYRIGHT and LICENSE files for more details. <%= render partial: 'users/preferences', locals: { input_size: :middle } %> <%= call_hook(:view_my_settings, user: @user, form: f) %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/news/edit.html.erb b/app/views/news/edit.html.erb index 2ad405f686ba..75333d3ddcc0 100644 --- a/app/views/news/edit.html.erb +++ b/app/views/news/edit.html.erb @@ -33,7 +33,7 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @news, html: { id: 'news-form' } do |f| %> <%= render partial: 'form', locals: { f: f } %>
    - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), news_path(@news), class: 'button -with-icon icon-cancel' %> <% end %>
    diff --git a/app/views/news/index.html.erb b/app/views/news/index.html.erb index a0ddb1dfc774..0b6000e1374e 100644 --- a/app/views/news/index.html.erb +++ b/app/views/news/index.html.erb @@ -35,7 +35,7 @@ See COPYRIGHT and LICENSE files for more details. <% if managable %>
  • <%= link_to new_project_news_path(@project), - { class: 'button -primary', + { class: 'button -alt-highlight', id: 'new_news_link', aria: {label: t(:label_news_new)}, title: t(:label_news_new)} do %> diff --git a/app/views/news/new.html.erb b/app/views/news/new.html.erb index a9e0ee02f289..4153de7dd07c 100644 --- a/app/views/news/new.html.erb +++ b/app/views/news/new.html.erb @@ -33,7 +33,7 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for [@project, @news], html: { id: 'news-form' } do |f| %> <%= render partial: 'news/form', locals: { f: f } %> - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), project_news_index_path(@project), class: 'button -with-icon icon-cancel' %> <% end %>
    diff --git a/app/views/news/show.html.erb b/app/views/news/show.html.erb index dda0aad9e40f..4514b93ca7e8 100644 --- a/app/views/news/show.html.erb +++ b/app/views/news/show.html.erb @@ -59,7 +59,7 @@ See COPYRIGHT and LICENSE files for more details. @@ -103,7 +103,7 @@ See COPYRIGHT and LICENSE files for more details. <%= wikitoolbar_for 'comment_comments', preview_context: preview_context(@news) %>

    - <%= submit_tag t(:button_add_comment), class: 'button -primary' %> + <%= submit_tag t(:button_add_comment), class: 'button -highlight' %>

    <% end %> <% end %> diff --git a/app/views/oauth/applications/edit.html.erb b/app/views/oauth/applications/edit.html.erb index db35803c9adb..c56fe48382e8 100644 --- a/app/views/oauth/applications/edit.html.erb +++ b/app/views/oauth/applications/edit.html.erb @@ -39,6 +39,6 @@ See COPYRIGHT and LICENSE files for more details. <%= render partial: 'form', locals: { f: f } %>

    - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %>

    <% end %> diff --git a/app/views/oauth/applications/index.html.erb b/app/views/oauth/applications/index.html.erb index 20f3c4c732c6..47cb78921c1f 100644 --- a/app/views/oauth/applications/index.html.erb +++ b/app/views/oauth/applications/index.html.erb @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t('oauth.application.plural'), title_class: 'no-padding-bottom' do %>
  • <%= link_to new_oauth_application_path, - { class: 'button -primary', + { class: 'button -alt-highlight', title: t('oauth.application.new')} do %> <%= op_icon('button--icon icon-add') %> <%= t(:button_add) %> diff --git a/app/views/oauth/applications/new.html.erb b/app/views/oauth/applications/new.html.erb index c208d363ebcd..1ee51f8ec9ff 100644 --- a/app/views/oauth/applications/new.html.erb +++ b/app/views/oauth/applications/new.html.erb @@ -42,6 +42,6 @@ See COPYRIGHT and LICENSE files for more details. <%= render partial: 'form', locals: { f: f } %>

    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %>

    <% end %> diff --git a/app/views/onboarding/_configuration_modal.html.erb b/app/views/onboarding/_configuration_modal.html.erb index fd68e8b055a4..5ccd69bb4a5f 100644 --- a/app/views/onboarding/_configuration_modal.html.erb +++ b/app/views/onboarding/_configuration_modal.html.erb @@ -52,7 +52,7 @@ See COPYRIGHT and LICENSE files for more details. dynamic-content-modal-close-button title=<%= t(:button_close) %> ><%= t(:button_close) %> - <%= styled_button_tag t(:button_save), class: 'button_no-margin -primary -with-icon icon-checkmark spot-action-bar--action' %> + <%= styled_button_tag t(:button_save), class: 'button_no-margin -highlight -with-icon icon-checkmark spot-action-bar--action' %> <% end %> diff --git a/app/views/placeholder_users/_general.html.erb b/app/views/placeholder_users/_general.html.erb index 2a46d38c7c92..bafa6138d063 100644 --- a/app/views/placeholder_users/_general.html.erb +++ b/app/views/placeholder_users/_general.html.erb @@ -36,5 +36,5 @@ See COPYRIGHT and LICENSE files for more details. as: :placeholder_user do |f| %> <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <% end %> diff --git a/app/views/placeholder_users/deletion_info.html.erb b/app/views/placeholder_users/deletion_info.html.erb index bd1ff038554c..f21bd7365b50 100644 --- a/app/views/placeholder_users/deletion_info.html.erb +++ b/app/views/placeholder_users/deletion_info.html.erb @@ -58,7 +58,7 @@ See COPYRIGHT and LICENSE files for more details.

    - <%= styled_button_tag '', class: '-primary', disabled: true do + <%= styled_button_tag '', class: '-highlight', disabled: true do concat content_tag :i, '', class: 'button--icon icon-delete' concat content_tag :span, t(:button_delete), class: 'button--text' end %> diff --git a/app/views/placeholder_users/index.html.erb b/app/views/placeholder_users/index.html.erb index 541b8a89ab72..6e3b83a1cc95 100644 --- a/app/views/placeholder_users/index.html.erb +++ b/app/views/placeholder_users/index.html.erb @@ -34,7 +34,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t(:label_placeholder_user_plural), title_class: 'no-padding-bottom' do %>
  • <%= link_to new_placeholder_user_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: { label: t(:label_placeholder_user_new) }, title: t(:label_placeholder_user_new) } do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/placeholder_users/new.html.erb b/app/views/placeholder_users/new.html.erb index b8f1a4e4dffd..8d0a09cd206a 100644 --- a/app/views/placeholder_users/new.html.erb +++ b/app/views/placeholder_users/new.html.erb @@ -38,7 +38,7 @@ See COPYRIGHT and LICENSE files for more details. <%= render partial: 'form', locals: { f: f, placeholder_user: @placeholder_user } %>

    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> - <%= styled_button_tag t(:button_create_and_continue), name: 'continue', class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create_and_continue), name: 'continue', class: '-highlight -with-icon icon-checkmark' %>

    <% end %> diff --git a/app/views/projects/_toolbar.html.erb b/app/views/projects/_toolbar.html.erb index d31df7c88e3c..49fba78032ef 100644 --- a/app/views/projects/_toolbar.html.erb +++ b/app/views/projects/_toolbar.html.erb @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details. <% if User.current.allowed_in_project?(:add_subprojects, @project) %>
  • <%= link_to new_project_path(parent_id: @project.id), - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_subproject_new)}, title: t(:label_subproject_new)} do %> <%= op_icon('button--icon icon-add') %> diff --git a/app/views/projects/destroy_info.html.erb b/app/views/projects/destroy_info.html.erb index b1b8adbb862d..4f5191b94d2b 100644 --- a/app/views/projects/destroy_info.html.erb +++ b/app/views/projects/destroy_info.html.erb @@ -56,7 +56,7 @@ See COPYRIGHT and LICENSE files for more details.

    - <%= styled_button_tag title: t(:button_delete), class: '-primary', disabled: true do + <%= styled_button_tag title: t(:button_delete), class: '-highlight', disabled: true do concat content_tag :i, '', class: 'button--icon icon-delete' concat content_tag :span, t(:button_delete), class: 'button--text' end %> diff --git a/app/views/projects/identifier/show.html.erb b/app/views/projects/identifier/show.html.erb index 7c59b32a8ec3..ff4b7ecabe62 100644 --- a/app/views/projects/identifier/show.html.erb +++ b/app/views/projects/identifier/show.html.erb @@ -49,11 +49,11 @@ See COPYRIGHT and LICENSE files for more details.
    <%= f.text_field :identifier %> - <%= f.submit t(:button_update), class: 'button -primary -with-icon icon-checkmark' %> + <%= f.submit t(:button_update), class: 'button -highlight -with-icon icon-checkmark' %> <%= link_to project_settings_general_path(@project), class: 'button' do %> - <%= op_icon('button--icon icon-cancel') %> + <%= op_icon('button--icon icon-cancel') %> <%= t(:button_cancel) %> <% end %> diff --git a/app/views/projects/settings/categories/show.html.erb b/app/views/projects/settings/categories/show.html.erb index be486d0a4c87..69d2edca9210 100644 --- a/app/views/projects/settings/categories/show.html.erb +++ b/app/views/projects/settings/categories/show.html.erb @@ -33,7 +33,7 @@ See COPYRIGHT and LICENSE files for more details. <%= link_to_if_authorized({ controller: '/categories', action: 'new', project_id: @project }, { aria: { label: t(:label_work_package_category_new) }, title: t(:label_work_package_category_new), - class: 'button -primary'}) do %> + class: 'button -alt-highlight'}) do %> <%= op_icon('icon-add button--icon') %> <%= t('activerecord.models.category') %> <% end %> diff --git a/app/views/projects/settings/custom_fields/show.html.erb b/app/views/projects/settings/custom_fields/show.html.erb index 6c8e10459d8c..abe34a478c83 100644 --- a/app/views/projects/settings/custom_fields/show.html.erb +++ b/app/views/projects/settings/custom_fields/show.html.erb @@ -33,7 +33,7 @@ See COPYRIGHT and LICENSE files for more details. <% if current_user.admin? %>
  • <%= link_to new_custom_field_path(type: 'WorkPackageCustomField'), - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_custom_field_new)}, title: t(:label_custom_field_new)} do %> <%= op_icon('button--icon icon-add') %> @@ -56,7 +56,7 @@ See COPYRIGHT and LICENSE files for more details. } %>
    - <%= form.button t(:button_save), class: 'button -primary -with-icon icon-checkmark' %> + <%= form.button t(:button_save), class: 'button -highlight -with-icon icon-checkmark' %>
    <% end %> <% else %> diff --git a/app/views/projects/settings/modules/show.html.erb b/app/views/projects/settings/modules/show.html.erb index 817bb422b0de..769130a8dac1 100644 --- a/app/views/projects/settings/modules/show.html.erb +++ b/app/views/projects/settings/modules/show.html.erb @@ -39,5 +39,5 @@ See COPYRIGHT and LICENSE files for more details. <%= render partial: "form", locals: { form: form } %> -

    <%= form.button t(:button_save), class: 'button -primary -with-icon icon-checkmark' %>

    +

    <%= form.button t(:button_save), class: 'button -highlight -with-icon icon-checkmark' %>

    <% end %> diff --git a/app/views/projects/settings/repository/_submit.html.erb b/app/views/projects/settings/repository/_submit.html.erb index e7b640c461c3..8e6d4a114d6a 100644 --- a/app/views/projects/settings/repository/_submit.html.erb +++ b/app/views/projects/settings/repository/_submit.html.erb @@ -1,4 +1,4 @@ - diff --git a/docs/development/contribution-documentation/documentation-process/README.md b/docs/development/contribution-documentation/documentation-process/README.md index 1962c6a0c252..fb9b76e126af 100644 --- a/docs/development/contribution-documentation/documentation-process/README.md +++ b/docs/development/contribution-documentation/documentation-process/README.md @@ -32,7 +32,7 @@ You can download the installer from the [Typora website](https://typora.io). Fol You can install the software GitHub Desktop on any [supported operating systems](https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/overview/supported-operating-systems). To install GitHub Desktop navigate to [https://desktop.github.com](https://desktop.github.com) and download the appropriate version for your operating system. Follow the prompts to complete the installation. -## Step 4: Sign in into Github.com in GitHub Desktop +## Step 4: Sign in into GitHub.com in GitHub Desktop To exchange data between your local repository and remote repositories you need to first sign (File -> Options -> Sign in). @@ -196,7 +196,7 @@ In GitHub Desktop **at Current branch the old branch is visible [1]** . After yo #### C) Change remote repository back to the forked repository (ORIGIN) -In Github Desktop choose menu "Repository -> Repository settings". This will open a new window (screenshot below). Enter the URL of your forked OpenProject repository (e.g. https://github.com/adam-op/openproject.git). Confirm with **Save** +In GitHub Desktop choose menu "Repository -> Repository settings". This will open a new window (screenshot below). Enter the URL of your forked OpenProject repository (e.g. https://github.com/adam-op/openproject.git). Confirm with **Save** ![rebase-your-fork-step-3](rebase-your-fork-step-3.png) diff --git a/docs/development/development-environment-docker/README.md b/docs/development/development-environment-docker/README.md index dbfe1b08f6cb..191755e3dcf2 100644 --- a/docs/development/development-environment-docker/README.md +++ b/docs/development/development-environment-docker/README.md @@ -141,8 +141,15 @@ system's resources. ```shell # Start the worker service and let it run continuously docker compose up -d worker + +# Start the worker service to work off all delayed jobs and shut it down afterwards +docker compose run --rm worker rake jobs:workoff ``` +The testing containers are excluded as well, while they are harmless to start, but take up system resources again and +clog your logs while running. The delayed_job background worker reloads the application for every job in development +mode. This is a know issue and documented here: https://github.com/collectiveidea/delayed_job/issues/823 + This process can take quite a long time on the first run where all gems are installed for the first time. However, these are cached in a docker volume. Meaning that from the 2nd run onwards it will start a lot quicker. @@ -389,7 +396,7 @@ docker compose --project-directory docker/dev/tls up -d ## GitLab CE Service -Within `docker/dev/gitlab` a compose file is provided for running local Gitlab instance with TLS support. This provides +Within `docker/dev/gitlab` a compose file is provided for running local GitLab instance with TLS support. This provides a production like environment for testing the OpenProject GitLab integration against a community edition GitLab instance accessible on `https://gitlab.local`. diff --git a/docs/development/development-environment-osx/README.md b/docs/development/development-environment-osx/README.md index 8a6e2a77c9bd..c484e6ea84f3 100644 --- a/docs/development/development-environment-osx/README.md +++ b/docs/development/development-environment-osx/README.md @@ -250,7 +250,7 @@ You can then access the application either through `localhost:3000` (Rails serve ### Delayed Job background worker ```shell -RAILS_ENV=development bundle exec good_job start +RAILS_ENV=development bin/rails jobs:work ``` This will start a Delayed::Job worker to perform asynchronous jobs like sending emails. @@ -298,6 +298,12 @@ brew install git ## Known issues +### Memory management + +The delayed_job background worker reloads the application for every job in development mode. This is a know issue and documented here: https://github.com/collectiveidea/delayed_job/issues/823 + + + ### Spawning a lot of browser tabs If you haven't run this command for a while, chances are that a lot of background jobs have queued up and might cause a significant amount of open tabs (due to the way we deliver mails with the letter_opener gem). To get rid of the jobs before starting the worker, use the following command. **This will remove all currently scheduled jobs, never use this in a production setting.** diff --git a/docs/development/development-environment-ubuntu/README.md b/docs/development/development-environment-ubuntu/README.md index 52ed199ef6e6..25c551a6adb1 100644 --- a/docs/development/development-environment-ubuntu/README.md +++ b/docs/development/development-environment-ubuntu/README.md @@ -301,7 +301,7 @@ You can then access the application either through `localhost:3000` (Rails serve ### Background job worker ```shell -RAILS_ENV=development bundle exec good_job start +RAILS_ENV=development bin/rails jobs:work ``` This will start a Delayed::Job worker to perform asynchronous jobs like sending emails. @@ -310,6 +310,12 @@ This will start a Delayed::Job worker to perform asynchronous jobs like sending ## Known issues +### Memory management + +The delayed_job background worker reloads the application for every job in development mode. This is a know issue and documented here: https://github.com/collectiveidea/delayed_job/issues/823 + + + ### Spawning a lot of browser tabs If you haven't run this command for a while, chances are that a lot of background jobs have queued up and might cause a significant amount of open tabs (due to the way we deliver mails with the letter_opener gem). To get rid of the jobs before starting the worker, use the following command. **This will remove all currently scheduled jobs, never use this in a production setting.** diff --git a/docs/development/running-tests/README.md b/docs/development/running-tests/README.md index 0eebfa67defc..79e39b8fc71a 100644 --- a/docs/development/running-tests/README.md +++ b/docs/development/running-tests/README.md @@ -837,7 +837,7 @@ OPENPROJECT_CLI_PROXY='http://:4200' ./bin/rails s -b 0.0.0.0 -p # Now access your server from http://:3000 with code reloading ``` -You might have to also update your host name setting `bundle exec rake setting:set[host_name=yourip]`. +You might have to also update your host name setting `bundle exec rake setting:set[host_name=your-ip]`. ## Legacy LDAP tests diff --git a/docs/getting-started/gantt-chart-introduction/openproject-user-guide-create-project-plan.gif b/docs/getting-started/gantt-chart-introduction/openproject-user-guide-create-project-plan.gif index 86bdb3c00e5b..5a57e841797d 100644 Binary files a/docs/getting-started/gantt-chart-introduction/openproject-user-guide-create-project-plan.gif and b/docs/getting-started/gantt-chart-introduction/openproject-user-guide-create-project-plan.gif differ diff --git a/docs/getting-started/gantt-chart-introduction/openproject-user-guide-edit-project-plan.gif b/docs/getting-started/gantt-chart-introduction/openproject-user-guide-edit-project-plan.gif index 1e3e21b26a77..b95c45a764f0 100644 Binary files a/docs/getting-started/gantt-chart-introduction/openproject-user-guide-edit-project-plan.gif and b/docs/getting-started/gantt-chart-introduction/openproject-user-guide-edit-project-plan.gif differ diff --git a/docs/getting-started/gantt-chart-introduction/openproject-user-guide-select-gantt-charts-module.png b/docs/getting-started/gantt-chart-introduction/openproject-user-guide-select-gantt-charts-module.png index 138e078a430b..466e10d66b95 100644 Binary files a/docs/getting-started/gantt-chart-introduction/openproject-user-guide-select-gantt-charts-module.png and b/docs/getting-started/gantt-chart-introduction/openproject-user-guide-select-gantt-charts-module.png differ diff --git a/docs/getting-started/invite-members/create-project-button.png b/docs/getting-started/invite-members/create-project-button.png index 1e7579161468..be98dc258f64 100644 Binary files a/docs/getting-started/invite-members/create-project-button.png and b/docs/getting-started/invite-members/create-project-button.png differ diff --git a/docs/getting-started/invite-members/invite-new-member-email.png b/docs/getting-started/invite-members/invite-new-member-email.png index 9244cac0fd30..7e2611ffb631 100644 Binary files a/docs/getting-started/invite-members/invite-new-member-email.png and b/docs/getting-started/invite-members/invite-new-member-email.png differ diff --git a/docs/getting-started/invite-members/invite-new-member.png b/docs/getting-started/invite-members/invite-new-member.png index ca3187700312..7598a2717d33 100644 Binary files a/docs/getting-started/invite-members/invite-new-member.png and b/docs/getting-started/invite-members/invite-new-member.png differ diff --git a/docs/getting-started/invite-members/invite-user-over-assignment.png b/docs/getting-started/invite-members/invite-user-over-assignment.png index 2766aab005cf..ebb918fc7f8a 100644 Binary files a/docs/getting-started/invite-members/invite-user-over-assignment.png and b/docs/getting-started/invite-members/invite-user-over-assignment.png differ diff --git a/docs/getting-started/invite-members/invite-user-pop-up.png b/docs/getting-started/invite-members/invite-user-pop-up.png index b2c4bb75556c..5afcb4198ff5 100644 Binary files a/docs/getting-started/invite-members/invite-user-pop-up.png and b/docs/getting-started/invite-members/invite-user-pop-up.png differ diff --git a/docs/getting-started/invite-members/project-members-module.png b/docs/getting-started/invite-members/project-members-module.png index 2cd07dbbad43..ee6e5c648b73 100644 Binary files a/docs/getting-started/invite-members/project-members-module.png and b/docs/getting-started/invite-members/project-members-module.png differ diff --git a/docs/getting-started/my-account/openproject_my_account_2fa_overview.png b/docs/getting-started/my-account/openproject_my_account_2fa_overview.png index 161ca2b95701..89bd0c38fb53 100644 Binary files a/docs/getting-started/my-account/openproject_my_account_2fa_overview.png and b/docs/getting-started/my-account/openproject_my_account_2fa_overview.png differ diff --git a/docs/getting-started/my-account/openproject_my_account_authentication_options.png b/docs/getting-started/my-account/openproject_my_account_authentication_options.png index 465a6eaf7303..f0c5f0370da9 100644 Binary files a/docs/getting-started/my-account/openproject_my_account_authentication_options.png and b/docs/getting-started/my-account/openproject_my_account_authentication_options.png differ diff --git a/docs/getting-started/my-account/openproject_my_account_authenticator_app.png b/docs/getting-started/my-account/openproject_my_account_authenticator_app.png index f3cf1a9474d2..20bdf66034d5 100644 Binary files a/docs/getting-started/my-account/openproject_my_account_authenticator_app.png and b/docs/getting-started/my-account/openproject_my_account_authenticator_app.png differ diff --git a/docs/getting-started/my-account/openproject_my_account_authenticator_webauth.png b/docs/getting-started/my-account/openproject_my_account_authenticator_webauth.png index e02686fb1c9c..81e36f862af9 100644 Binary files a/docs/getting-started/my-account/openproject_my_account_authenticator_webauth.png and b/docs/getting-started/my-account/openproject_my_account_authenticator_webauth.png differ diff --git a/docs/getting-started/my-account/openproject_my_account_two_factor_authentication.png b/docs/getting-started/my-account/openproject_my_account_two_factor_authentication.png index 5a3c82644068..380de66d21b8 100644 Binary files a/docs/getting-started/my-account/openproject_my_account_two_factor_authentication.png and b/docs/getting-started/my-account/openproject_my_account_two_factor_authentication.png differ diff --git a/docs/getting-started/my-account/openproject_my_account_two_factor_authentication_mobile.png b/docs/getting-started/my-account/openproject_my_account_two_factor_authentication_mobile.png index 2ccc05254f5c..b38891250493 100644 Binary files a/docs/getting-started/my-account/openproject_my_account_two_factor_authentication_mobile.png and b/docs/getting-started/my-account/openproject_my_account_two_factor_authentication_mobile.png differ diff --git a/docs/getting-started/projects/create-a-new-project-landing-page.png b/docs/getting-started/projects/create-a-new-project-landing-page.png index d0fb8becb201..43859edcba1c 100644 Binary files a/docs/getting-started/projects/create-a-new-project-landing-page.png and b/docs/getting-started/projects/create-a-new-project-landing-page.png differ diff --git a/docs/getting-started/projects/create-project-header.png b/docs/getting-started/projects/create-project-header.png index 9ec6f351932e..ed89c62571f9 100644 Binary files a/docs/getting-started/projects/create-project-header.png and b/docs/getting-started/projects/create-project-header.png differ diff --git a/docs/getting-started/projects/openproject-landing-page.png b/docs/getting-started/projects/openproject-landing-page.png index 4392998684b5..d3d2736bf578 100644 Binary files a/docs/getting-started/projects/openproject-landing-page.png and b/docs/getting-started/projects/openproject-landing-page.png differ diff --git a/docs/getting-started/projects/project-overview-list.png b/docs/getting-started/projects/project-overview-list.png index e87b19b3dd2d..9a31c0706155 100644 Binary files a/docs/getting-started/projects/project-overview-list.png and b/docs/getting-started/projects/project-overview-list.png differ diff --git a/docs/getting-started/projects/view_all_projects.png b/docs/getting-started/projects/view_all_projects.png index 62a5f4f1be14..8240d050cfe3 100644 Binary files a/docs/getting-started/projects/view_all_projects.png and b/docs/getting-started/projects/view_all_projects.png differ diff --git a/docs/getting-started/projects/view_all_projects_options.png b/docs/getting-started/projects/view_all_projects_options.png index ad8cf874ccc7..5fa959b7f4b2 100644 Binary files a/docs/getting-started/projects/view_all_projects_options.png and b/docs/getting-started/projects/view_all_projects_options.png differ diff --git a/docs/glossary/README.md b/docs/glossary/README.md index bd18d288858d..3c3bd4d27dbf 100644 --- a/docs/glossary/README.md +++ b/docs/glossary/README.md @@ -274,7 +274,7 @@ Your activated plugins are listed together with your [modules](#module) in your ### Primer design system -OpenProject started adopting [Github's Primer Design System](https://primer.style/) in 2023. New features will be developed using Primer and existing features will will be gradually revised. Relevant reusable components from Primer as well as common patterns and compositions of these components will be documented in our [Lookbook](https://qa.openproject-edge.com/lookbook/pages/how_to_use). [Read more about OpenProject's decision to use Primer](https://www.openproject.org/blog/primer-design-system/). +OpenProject started adopting [GitHub's Primer Design System](https://primer.style/) in 2023. New features will be developed using Primer and existing features will will be gradually revised. Relevant reusable components from Primer as well as common patterns and compositions of these components will be documented in our [Lookbook](https://qa.openproject-edge.com/lookbook/pages/how_to_use). [Read more about OpenProject's decision to use Primer](https://www.openproject.org/blog/primer-design-system/). ### Project diff --git a/docs/installation-and-operations/configuration/README.md b/docs/installation-and-operations/configuration/README.md index 92e9234ecf47..3571d5935f80 100644 --- a/docs/installation-and-operations/configuration/README.md +++ b/docs/installation-and-operations/configuration/README.md @@ -758,7 +758,7 @@ OPENPROJECT_2FA_ENFORCED="true" **Setting available strategies** -By default, the TOTP and WebAuthn strategie are active. +By default, the TOTP and WebAuthn strategies are active. If you have a [MessageBird account](https://www.messagebird.com/), you can setup a SMS 2FA by activating that strategy like so: diff --git a/docs/installation-and-operations/configuration/plugins/README.md b/docs/installation-and-operations/configuration/plugins/README.md index 99faac1d6a5d..7282137ec9f7 100644 --- a/docs/installation-and-operations/configuration/plugins/README.md +++ b/docs/installation-and-operations/configuration/plugins/README.md @@ -24,7 +24,7 @@ group :opf_plugins do end ``` -**Note:** The Gitlab plugin is usually only compatible with the latest versions. For more information, please see the respective repository: https://github.com/btey/openproject-gitlab-integration/ +**Note:** The GitLab plugin is usually only compatible with the latest versions. For more information, please see the respective repository: https://github.com/btey/openproject-gitlab-integration/ The group `:opf_plugins` is generally recommended, but only required for plugins with custom frontend code that is picked up by webpack and output into their respective bundles. diff --git a/docs/installation-and-operations/installation-faq/README.md b/docs/installation-and-operations/installation-faq/README.md index a086e93eec30..802e11c602c6 100644 --- a/docs/installation-and-operations/installation-faq/README.md +++ b/docs/installation-and-operations/installation-faq/README.md @@ -124,7 +124,7 @@ Set a higher number of web workers to allow more processes to be handled at the There are two different types of emails in OpenProject: One sent directly within the request to the server (this includes the test mail) and one sent asynchronously, via a background job from the backend. The majority of mail sending jobs is run asynchronously to facilitate a faster response time for server request. -Use a browser to call your domain name followed by "health_checks/all" (e.g. `https://myopenproject.com/health_checks/all`). There should be entries about "worker" and "worker_backed_up". If PASSED is written behind it, everything is good. +Use a browser to call your domain name followed by "health_checks/all" (e.g. `https://myopenproject.com/health_checks/all`). There should be entries about "delayed_jobs_backed_up" and "delayed_jobs_never_ran". If PASSED is written behind it, everything is good. If the health check does not return satisfying results, have a look if the background worker is running by entering `ps aux | grep jobs` on the server. If it is not running, no entry is returned. If it is running an entry with "jobs:work" at the end is displayed. diff --git a/docs/installation-and-operations/operation/monitoring/README.md b/docs/installation-and-operations/operation/monitoring/README.md index 145dba04978c..40d740b33464 100644 --- a/docs/installation-and-operations/operation/monitoring/README.md +++ b/docs/installation-and-operations/operation/monitoring/README.md @@ -124,10 +124,8 @@ We provide the following health checks: - `https://your-hostname.example.tld/health_checks/default` - An application level check to ensure the web workers are running. - `https://your-hostname.example.tld/health_checks/database` - A database liveliness check. -- `https://your-hostname.example.tld/health_checks/mail` - SMTP configuration check. -- `https://your-hostname.example.tld/health_checks/puma` - A check on Puma web server. -- `https://your-hostname.example.tld/health_checks/worker` - A check to ensure background jobs are being processed. -- `https://your-hostname.example.tld/health_checks/worker_backed_up` - A check to determine whether background workers are at capacity and might need to be scaled up to provide timely processing of mails and other background work. +- `https://your-hostname.example.tld/health_checks/delayed_jobs_never_ran` - A check to ensure background jobs are being processed. +- `https://your-hostname.example.tld/health_checks/delayed_jobs_backed_up` - A check to determine whether background workers are at capacity and might need to be scaled up to provide timely processing of mails and other background work. - `https://your-hostname.example.tld/health_checks/all` - All of the above checks and additional checks combined as one. Not recommended as the liveliness check of a pod/container. ### Optional authentication diff --git a/docs/release-notes/11/11-0-0/README.md b/docs/release-notes/11/11-0-0/README.md index e3f569d5990b..1bfaa6c36e6c 100644 --- a/docs/release-notes/11/11-0-0/README.md +++ b/docs/release-notes/11/11-0-0/README.md @@ -229,7 +229,7 @@ There are lots and lots of new things we packed into 11.0 to tell you about. - Fixed: Error 500 when bulk-editing work packages \[[#34588](https://community.openproject.org/wp/34588)\] - Fixed: Year almost hidden in date picker for version \[[#34590](https://community.openproject.org/wp/34590)\] - Fixed: Onboarding tour broken in multiple places \[[#34597](https://community.openproject.org/wp/34597)\] -- Fixed: Github Integration \[[#34598](https://community.openproject.org/wp/34598)\] +- Fixed: GitHub Integration \[[#34598](https://community.openproject.org/wp/34598)\] - Fixed: Google OpenID provider image not shown in login form \[[#34601](https://community.openproject.org/wp/34601)\] - Fixed: Parent work package in manual scheduling mode without date cannot be scheduled from Gantt chart \[[#34710](https://community.openproject.org/wp/34710)\] - Fixed: Menu too small/completely hidden on Roadmap \[[#34712](https://community.openproject.org/wp/34712)\] @@ -291,7 +291,7 @@ There are lots and lots of new things we packed into 11.0 to tell you about. - Changed: Improve board creation modal \[[#34070](https://community.openproject.org/wp/34070)\] - Changed: Hide derived (Start/Finish) Date from work package forms \[[#34122](https://community.openproject.org/wp/34122)\] - Changed: Extend search autocompleter with useful information \[[#34132](https://community.openproject.org/wp/34132)\] -- Changed: [all projects overview] (Add option to) show status-text in expanded view. \[[#34191](https://community.openproject.org/wp/34191)\] +- Changed: \[all projects overview\] (Add option to) show status-text in expanded view. \[[#34191](https://community.openproject.org/wp/34191)\] - Changed: Map board subtasks columns when copying projects \[[#34238](https://community.openproject.org/wp/34238)\] - Changed: Having meetings as a linkable resource \[[#34256](https://community.openproject.org/wp/34256)\] - Changed: What's new teaser OpenProject BIM 11.0 \[[#34514](https://community.openproject.org/wp/34514)\] diff --git a/docs/release-notes/11/11-3-0/README.md b/docs/release-notes/11/11-3-0/README.md index 3bbf6d9b53a6..bac6cff9810b 100644 --- a/docs/release-notes/11/11-3-0/README.md +++ b/docs/release-notes/11/11-3-0/README.md @@ -124,7 +124,7 @@ Users now have the option to **create backups of their OpenProject installation* - Changed: Add copy project form to APIv3 \[[#37091](https://community.openproject.org/wp/37091)\] - Changed: Attribute help text on dynamic form \[[#37092](https://community.openproject.org/wp/37092)\] - Changed: Improve design of checkboxes in formly forms \[[#37105](https://community.openproject.org/wp/37105)\] -- Changed: Improve design of Github tab \[[#37108](https://community.openproject.org/wp/37108)\] +- Changed: Improve design of GitHub tab \[[#37108](https://community.openproject.org/wp/37108)\] - Changed: Allow inviting users from project member administration for non admins \[[#37126](https://community.openproject.org/wp/37126)\] - Changed: Handle duplicate project identifiers in the backend \[[#37140](https://community.openproject.org/wp/37140)\] - Fixed: Unable to enter Boards module when work package module is disabled \[[#34794](https://community.openproject.org/wp/34794)\] @@ -183,7 +183,7 @@ Users now have the option to **create backups of their OpenProject installation* - Fixed: "(None)" option missing for parent project drop down select \[[#37398](https://community.openproject.org/wp/37398)\] - Fixed: Multi-select fields do not adjust height (cannot see values) \[[#37404](https://community.openproject.org/wp/37404)\] - Fixed: OpenProject backup completes partially with file permission errors \[[#37440](https://community.openproject.org/wp/37440)\] -- Fixed: Github user avatar not rendered correctly \[[#37444](https://community.openproject.org/wp/37444)\] +- Fixed: GitHub user avatar not rendered correctly \[[#37444](https://community.openproject.org/wp/37444)\] - Fixed: Password confirmation during backup token reset not working \[[#37445](https://community.openproject.org/wp/37445)\] - Fixed: Several problem with the header in mobile view \[[#37452](https://community.openproject.org/wp/37452)\] - Fixed: allowedValues for project user custom fields result in 400 bad request \[[#37453](https://community.openproject.org/wp/37453)\] diff --git a/docs/release-notes/11/11-4-0/README.md b/docs/release-notes/11/11-4-0/README.md index d2690f702a75..5ba523517c25 100644 --- a/docs/release-notes/11/11-4-0/README.md +++ b/docs/release-notes/11/11-4-0/README.md @@ -28,7 +28,7 @@ OpenProject 11.4.0 adds packaged installation support for Debian 11 "Bullseye". - Fixed: Wiki menu item scrolling does not work with two main wiki items \[[#38878](https://community.openproject.org/wp/38878)\] - Fixed: Imminent user limit warning shown prematurely \[[#38893](https://community.openproject.org/wp/38893)\] - Fixed: Custom S3 compatible upload providers blocked by CSP \[[#38900](https://community.openproject.org/wp/38900)\] -- Fixed: [Github Integration] Webhook fails for pull_request event without body \[[#38919](https://community.openproject.org/wp/38919)\] +- Fixed: [GitHub Integration] Webhook fails for pull_request event without body \[[#38919](https://community.openproject.org/wp/38919)\] - Fixed: IFC upload not working since attachment whitelisting \[[#38954](https://community.openproject.org/wp/38954)\] - Fixed: BIM seed are missing snapshots \[[#39009](https://community.openproject.org/wp/39009)\] - Fixed: Regression: Typing S while focus in viewer opens the OP global search \[[#39029](https://community.openproject.org/wp/39029)\] diff --git a/docs/release-notes/12/12-1-0/README.md b/docs/release-notes/12/12-1-0/README.md index 8c457b75608c..90ce53533abb 100644 --- a/docs/release-notes/12/12-1-0/README.md +++ b/docs/release-notes/12/12-1-0/README.md @@ -150,7 +150,7 @@ We added a new “Files” tab in the work package details. This way, you will h - Fixed: Users can't select public template projects in new project dialog \[[#40918](https://community.openproject.org/wp/40918)\] - Fixed: Meeting Time in iCalendar is wrong \[[#40941](https://community.openproject.org/wp/40941)\] - Fixed: Toolbar icons should be rendered in the "old" style and not the new rounded style (which is a work in progress) \[[#40957](https://community.openproject.org/wp/40957)\] -- Fixed: [Docker] - Gitlab integration plugin \[[#40959](https://community.openproject.org/wp/40959)\] +- Fixed: [Docker] - GitLab integration plugin \[[#40959](https://community.openproject.org/wp/40959)\] - Fixed: Project dropdown no longer autofocused \[[#40978](https://community.openproject.org/wp/40978)\] - Fixed: Not possible to copy work package to another project \[[#41005](https://community.openproject.org/wp/41005)\] - Fixed: Changed calendar styles applied to time entries component \[[#41013](https://community.openproject.org/wp/41013)\] diff --git a/docs/release-notes/13-3-0/README.md b/docs/release-notes/13-3-0/README.md index c501e37adc3f..dcfbdb794101 100644 --- a/docs/release-notes/13-3-0/README.md +++ b/docs/release-notes/13-3-0/README.md @@ -56,7 +56,7 @@ With this release, admins of an Enterprise edition can choose between manually o - Bugfix: Lookbook is broken \[[#51787](https://community.openproject.org/wp/51787)\] - Bugfix: Anonymous Users (without signing in) cannot load board content \[[#51850](https://community.openproject.org/wp/51850)\] - Bugfix: Misalignment in the dropdown on searching work packages \[[#51948](https://community.openproject.org/wp/51948)\] -- Bugfix: Remove colour in share modal is not correct \[[#52012](https://community.openproject.org/wp/52012)\] +- Bugfix: Remove color in share modal is not correct \[[#52012](https://community.openproject.org/wp/52012)\] - Bugfix: Timeouts as non privileged users \[[#52022](https://community.openproject.org/wp/52022)\] - Bugfix: WorkPackage query with baseline filter takes too much time for non-admins \[[#52156](https://community.openproject.org/wp/52156)\] - Bugfix: Multi-select user custom field broken in table \[[#52289](https://community.openproject.org/wp/52289)\] diff --git a/docs/release-notes/13-3-0/openproject-13-3-sharepoint-onedrive-automatically-managed-project-folders-highlighted.png b/docs/release-notes/13-3-0/openproject-13-3-sharepoint-onedrive-automatically-managed-project-folders-highlighted.png index d2a002099aa0..c983ff779c48 100644 Binary files a/docs/release-notes/13-3-0/openproject-13-3-sharepoint-onedrive-automatically-managed-project-folders-highlighted.png and b/docs/release-notes/13-3-0/openproject-13-3-sharepoint-onedrive-automatically-managed-project-folders-highlighted.png differ diff --git a/docs/release-notes/13-3-0/openproject-filter-project-lists.png b/docs/release-notes/13-3-0/openproject-filter-project-lists.png index 0391b318eefc..b94140e02a09 100644 Binary files a/docs/release-notes/13-3-0/openproject-filter-project-lists.png and b/docs/release-notes/13-3-0/openproject-filter-project-lists.png differ diff --git a/docs/release-notes/13-3-0/openproject-user-guide-select-gantt-charts-global.png b/docs/release-notes/13-3-0/openproject-user-guide-select-gantt-charts-global.png index 3800c47c724a..d24e3625f174 100644 Binary files a/docs/release-notes/13-3-0/openproject-user-guide-select-gantt-charts-global.png and b/docs/release-notes/13-3-0/openproject-user-guide-select-gantt-charts-global.png differ diff --git a/docs/release-notes/13-4-0/GitLab_integration.png b/docs/release-notes/13-4-0/GitLab_integration.png index c140eaa0e9ee..a83ef84cfed7 100644 Binary files a/docs/release-notes/13-4-0/GitLab_integration.png and b/docs/release-notes/13-4-0/GitLab_integration.png differ diff --git a/docs/release-notes/13-4-0/README.md b/docs/release-notes/13-4-0/README.md index 813bc959c79c..ce75e15c7e43 100644 --- a/docs/release-notes/13-4-0/README.md +++ b/docs/release-notes/13-4-0/README.md @@ -88,7 +88,7 @@ Accessibility functionality: Convey to screenreaders when OAuth login has starte OpenProject version 13.4 now supports PDF exports with lists in table cells that are displayed correctly. Export a work package that contains a table with lists in it into a PDF. Here is an example of how this looks from now on: -![Work package with a table in the description field and how it looks when exportet as PDF](openproject-13-4-pdf-export-table-lists.png) +![Work package with a table in the description field and how it looks when exported as PDF](openproject-13-4-pdf-export-table-lists.png) ### WebAuthn/FIDO/U2F is added as a second factor @@ -139,13 +139,13 @@ Thanks to our great Community we can continuously offer more languages for OpenP - Bugfix: LDAP user can't be created if optional attributes are not mapped \[[#53327](https://community.openproject.org/wp/53327)\] - Bugfix: Page editor menu moves under the header \[[#53365](https://community.openproject.org/wp/53365)\] - Bugfix: Project folder is shown in the main menu based on the wrong permission for automatically managed project folders \[[#53367](https://community.openproject.org/wp/53367)\] -- Bugfix: Portuguese and Portuguese Brezilian should be distinct from each other \[[#53374](https://community.openproject.org/wp/53374)\] +- Bugfix: Portuguese and Portuguese Brazilian should be distinct from each other \[[#53374](https://community.openproject.org/wp/53374)\] - Bugfix: Blacklisted routes not working \[[#53399](https://community.openproject.org/wp/53399)\] - Bugfix: Incorrect spelling of GitLab module under project settings \[[#53434](https://community.openproject.org/wp/53434)\] - Bugfix: Webauthn fails on mobile Safari \[[#53442](https://community.openproject.org/wp/53442)\] - Bugfix: Rake secret task gone in 13.3.1 (breaking scripts & diverging from docs) \[[#53447](https://community.openproject.org/wp/53447)\] - Bugfix: WebAuth fails on iOS \[[#53494](https://community.openproject.org/wp/53494)\] -- Bugfix: WebAuthen not selectable on mobile \[[#53495](https://community.openproject.org/wp/53495)\] +- Bugfix: WebAuthn not selectable on mobile \[[#53495](https://community.openproject.org/wp/53495)\] - Bugfix: Cannot delete reports in time and costs \[[#52284](https://community.openproject.org/projects/openproject/work_packages/52284/activity)\] diff --git a/docs/release-notes/13-4-0/meetings-openproject-13-4-files.png b/docs/release-notes/13-4-0/meetings-openproject-13-4-files.png index e5cad2c41941..ea441c0d869f 100644 Binary files a/docs/release-notes/13-4-0/meetings-openproject-13-4-files.png and b/docs/release-notes/13-4-0/meetings-openproject-13-4-files.png differ diff --git a/docs/release-notes/13-4-0/openproject-13-4-intermediate-modal-nudging.jpg b/docs/release-notes/13-4-0/openproject-13-4-intermediate-modal-nudging.jpg index 8af812a1a3d4..fef763895545 100644 Binary files a/docs/release-notes/13-4-0/openproject-13-4-intermediate-modal-nudging.jpg and b/docs/release-notes/13-4-0/openproject-13-4-intermediate-modal-nudging.jpg differ diff --git a/docs/release-notes/13-4-0/openproject-13-4-meetings-copy-agenda-highlighted.png b/docs/release-notes/13-4-0/openproject-13-4-meetings-copy-agenda-highlighted.png index 45585cd7fd61..5ac4c67b1fa6 100644 Binary files a/docs/release-notes/13-4-0/openproject-13-4-meetings-copy-agenda-highlighted.png and b/docs/release-notes/13-4-0/openproject-13-4-meetings-copy-agenda-highlighted.png differ diff --git a/docs/release-notes/13-4-0/openproject-13-4-nudge-oauth.jpg b/docs/release-notes/13-4-0/openproject-13-4-nudge-oauth.jpg deleted file mode 100644 index 8c2d677f8f57..000000000000 Binary files a/docs/release-notes/13-4-0/openproject-13-4-nudge-oauth.jpg and /dev/null differ diff --git a/docs/release-notes/13-4-0/openproject-13-4-pdf-export-table-lists.png b/docs/release-notes/13-4-0/openproject-13-4-pdf-export-table-lists.png index 8e67103b32ec..0864c8a0fca7 100644 Binary files a/docs/release-notes/13-4-0/openproject-13-4-pdf-export-table-lists.png and b/docs/release-notes/13-4-0/openproject-13-4-pdf-export-table-lists.png differ diff --git a/docs/release-notes/13-4-0/openproject_system_settings_virus_scanning.png b/docs/release-notes/13-4-0/openproject_system_settings_virus_scanning.png deleted file mode 100644 index cee2c77825c2..000000000000 Binary files a/docs/release-notes/13-4-0/openproject_system_settings_virus_scanning.png and /dev/null differ diff --git a/docs/release-notes/13-4-0/openproject_virus_scanning.png b/docs/release-notes/13-4-0/openproject_virus_scanning.png index 52bebc987c66..9cae7c1d47f9 100644 Binary files a/docs/release-notes/13-4-0/openproject_virus_scanning.png and b/docs/release-notes/13-4-0/openproject_virus_scanning.png differ diff --git a/docs/release-notes/3/3-0-16/README.md b/docs/release-notes/3/3-0-16/README.md index ac8cd5306918..c5ab39238e14 100644 --- a/docs/release-notes/3/3-0-16/README.md +++ b/docs/release-notes/3/3-0-16/README.md @@ -28,6 +28,6 @@ bugs! For a complete list of changes, please refer to the [Changelog v3.0.16](https://community.openproject.org/versions/544) or have a look at -[Github](https://github.com/opf/openproject/tree/v3.0.16). +[GitHub](https://github.com/opf/openproject/tree/v3.0.16). diff --git a/docs/release-notes/4/4-0-2/README.md b/docs/release-notes/4/4-0-2/README.md index dc4c12179dca..b517b918ff79 100644 --- a/docs/release-notes/4/4-0-2/README.md +++ b/docs/release-notes/4/4-0-2/README.md @@ -36,4 +36,4 @@ A big thanks to everyone involved in fixing and reporting those bugs! For a complete list of changes, please refer to the [Changelog v4.0.2](https://community.openproject.org/versions/532) or to -[Github](https://github.com/opf/openproject/tree/v4.0.2). +[GitHub](https://github.com/opf/openproject/tree/v4.0.2). diff --git a/docs/release-notes/8/8-0-2/README.md b/docs/release-notes/8/8-0-2/README.md index ee9d09ba74b6..bb055bfa229c 100644 --- a/docs/release-notes/8/8-0-2/README.md +++ b/docs/release-notes/8/8-0-2/README.md @@ -45,7 +45,7 @@ newest version. #### Contributions -Thanks to Github users @storm2513 and @akasparas for providing bugfixes +Thanks to GitHub users @storm2513 and @akasparas for providing bugfixes as pull requests [on our GitHub project](https://github.com/opf/openproject). A big thanks to community members for reporting bugs and helping us identifying and providing diff --git a/docs/security-and-privacy/processing-of-personal-data/README.md b/docs/security-and-privacy/processing-of-personal-data/README.md index e56cc6be77b9..b361b802270e 100644 --- a/docs/security-and-privacy/processing-of-personal-data/README.md +++ b/docs/security-and-privacy/processing-of-personal-data/README.md @@ -580,7 +580,7 @@ flowchart LR subgraph openproject[OpenProject] direction TB - opgithubintegration[Github integration] --- workpackagesmodule[Work packages module] + opgithubintegration[GitHub integration] --- workpackagesmodule[Work packages module] end @@ -635,7 +635,7 @@ flowchart LR #### Purpose - Connect merge requests in GitLab with work packages in OpenProject. -- Connect issues in GitLab with work packages in OpenPrject. +- Connect issues in GitLab with work packages in OpenProject. - Show the status of merge requests in related work packages. #### Processed data diff --git a/docs/system-admin-guide/attachments/openproject_system_adminstration_attachment_settings.png b/docs/system-admin-guide/attachments/openproject_system_adminstration_attachment_settings.png index 9700924b171e..b59d032de6fe 100644 Binary files a/docs/system-admin-guide/attachments/openproject_system_adminstration_attachment_settings.png and b/docs/system-admin-guide/attachments/openproject_system_adminstration_attachment_settings.png differ diff --git a/docs/system-admin-guide/attachments/openproject_system_adminstration_attachments.png b/docs/system-admin-guide/attachments/openproject_system_adminstration_attachments.png index b976b79b392d..87eb08724f38 100644 Binary files a/docs/system-admin-guide/attachments/openproject_system_adminstration_attachments.png and b/docs/system-admin-guide/attachments/openproject_system_adminstration_attachments.png differ diff --git a/docs/system-admin-guide/attachments/virus-scanning/image-20240220-iedi.png b/docs/system-admin-guide/attachments/virus-scanning/image-20240220-iedi.png deleted file mode 100644 index 42f26c07fecc..000000000000 Binary files a/docs/system-admin-guide/attachments/virus-scanning/image-20240220-iedi.png and /dev/null differ diff --git a/docs/system-admin-guide/attachments/virus-scanning/openproject_system_settings_virus_scanning.png b/docs/system-admin-guide/attachments/virus-scanning/openproject_system_settings_virus_scanning.png index cee2c77825c2..ea4b533ad8bb 100644 Binary files a/docs/system-admin-guide/attachments/virus-scanning/openproject_system_settings_virus_scanning.png and b/docs/system-admin-guide/attachments/virus-scanning/openproject_system_settings_virus_scanning.png differ diff --git a/docs/system-admin-guide/design/Sys-admin-design-favicon-1579613889024.png b/docs/system-admin-guide/design/Sys-admin-design-favicon-1579613889024.png deleted file mode 100644 index 43972eabc841..000000000000 Binary files a/docs/system-admin-guide/design/Sys-admin-design-favicon-1579613889024.png and /dev/null differ diff --git a/docs/system-admin-guide/design/Sys-admin-design-favicon.png b/docs/system-admin-guide/design/Sys-admin-design-favicon.png index 25d42aa599a9..e0c4d6516e8a 100644 Binary files a/docs/system-admin-guide/design/Sys-admin-design-favicon.png and b/docs/system-admin-guide/design/Sys-admin-design-favicon.png differ diff --git a/docs/system-admin-guide/design/Sys-admin-design-upload-logo.png b/docs/system-admin-guide/design/Sys-admin-design-upload-logo.png index b577b6716eea..deee0aefa7ea 100644 Binary files a/docs/system-admin-guide/design/Sys-admin-design-upload-logo.png and b/docs/system-admin-guide/design/Sys-admin-design-upload-logo.png differ diff --git a/docs/system-admin-guide/design/System-admin-guide_color-theme.png b/docs/system-admin-guide/design/System-admin-guide_color-theme.png index ebe6e007c68e..6e0befe01cda 100644 Binary files a/docs/system-admin-guide/design/System-admin-guide_color-theme.png and b/docs/system-admin-guide/design/System-admin-guide_color-theme.png differ diff --git a/docs/system-admin-guide/design/System-admin-guide_design.png b/docs/system-admin-guide/design/System-admin-guide_design.png deleted file mode 100644 index 9557c4712363..000000000000 Binary files a/docs/system-admin-guide/design/System-admin-guide_design.png and /dev/null differ diff --git a/docs/system-admin-guide/design/image-20200121143402479.png b/docs/system-admin-guide/design/image-20200121143402479.png deleted file mode 100644 index 06225d6018fc..000000000000 Binary files a/docs/system-admin-guide/design/image-20200121143402479.png and /dev/null differ diff --git a/docs/system-admin-guide/design/image-20200211140615090.png b/docs/system-admin-guide/design/image-20200211140615090.png deleted file mode 100644 index f80c7c93cdc9..000000000000 Binary files a/docs/system-admin-guide/design/image-20200211140615090.png and /dev/null differ diff --git a/docs/system-admin-guide/design/openproject_system_guide_design.png b/docs/system-admin-guide/design/openproject_system_guide_design.png index 1fa57a9a2b7d..d5a8fc355f66 100644 Binary files a/docs/system-admin-guide/design/openproject_system_guide_design.png and b/docs/system-admin-guide/design/openproject_system_guide_design.png differ diff --git a/docs/system-admin-guide/design/openproject_system_guide_design_advanced_settings.png b/docs/system-admin-guide/design/openproject_system_guide_design_advanced_settings.png index 0e661eb519a2..ba6efe9d90d8 100644 Binary files a/docs/system-admin-guide/design/openproject_system_guide_design_advanced_settings.png and b/docs/system-admin-guide/design/openproject_system_guide_design_advanced_settings.png differ diff --git a/docs/system-admin-guide/design/system_admin_logo_updated.png b/docs/system-admin-guide/design/system_admin_logo_updated.png index b0d1f1468357..cb4768e1067a 100644 Binary files a/docs/system-admin-guide/design/system_admin_logo_updated.png and b/docs/system-admin-guide/design/system_admin_logo_updated.png differ diff --git a/docs/system-admin-guide/file-storages/README.md b/docs/system-admin-guide/file-storages/README.md index 5c36009d83d9..da8a50c8a7d6 100644 --- a/docs/system-admin-guide/file-storages/README.md +++ b/docs/system-admin-guide/file-storages/README.md @@ -3,7 +3,7 @@ sidebar_navigation: title: File storages priority: 830 description: File storages in OpenProject. -keywords: file storages, Nextcloud setup, Nextcloud integration, OneDrive setup, Sharepoint setup, OneDrive, Sharepoint +keywords: file storages, Nextcloud setup, Nextcloud integration, OneDrive setup, SharePoint setup, OneDrive, SharePoint --- # File storages diff --git a/docs/system-admin-guide/integrations/README.md b/docs/system-admin-guide/integrations/README.md index d4b645ad04b4..1285fe09def6 100644 --- a/docs/system-admin-guide/integrations/README.md +++ b/docs/system-admin-guide/integrations/README.md @@ -46,7 +46,7 @@ OpenProject offers integration with Nextcloud for file storage and collaboration ## OneDrive/SharePoint (Enterprise add-on) -OpenProject offers an integration with OneDrive/Sharepoint for file storage and collaboration. You can find more information about [setting up the integration with OneDrive/SharePoint](./one-drive) and [using the integration](../../user-guide/file-management/one-drive-integration/). +OpenProject offers an integration with OneDrive/SharePoint for file storage and collaboration. You can find more information about [setting up the integration with OneDrive/SharePoint](./one-drive) and [using the integration](../../user-guide/file-management/one-drive-integration/). > **Note**: OneDrive/SharePoint integration is an Enterprise add-on and can only be used with [Enterprise cloud](../../enterprise-guide/enterprise-cloud-guide/) or [Enterprise on-premises](../../enterprise-guide/enterprise-on-premises-guide/). An upgrade from the free Community edition is easy and helps support OpenProject. diff --git a/docs/system-admin-guide/integrations/github-integration/README.md b/docs/system-admin-guide/integrations/github-integration/README.md index fff564826bc6..8db04cc83cb0 100644 --- a/docs/system-admin-guide/integrations/github-integration/README.md +++ b/docs/system-admin-guide/integrations/github-integration/README.md @@ -28,7 +28,7 @@ Pull request activities will also show up in the Activity tab when the pull requ * merged * closed -![Github comments on work package](workpackage-github-comments.png) +![GitHub comments on work package](workpackage-github-comments.png) ## Create a pull request diff --git a/docs/system-admin-guide/integrations/gitlab-integration/README.md b/docs/system-admin-guide/integrations/gitlab-integration/README.md index de18ed91a139..d4a8e2d7ffc2 100644 --- a/docs/system-admin-guide/integrations/gitlab-integration/README.md +++ b/docs/system-admin-guide/integrations/gitlab-integration/README.md @@ -13,7 +13,7 @@ OpenProject offers an integration with GitLab merge requests to link software de OpenProject work packages will directly display information from GitLab in a separate tab. -![Gitlab tab in an OpenProject work package](gitlab-tab.png) +![GitLab tab in an OpenProject work package](gitlab-tab.png) The tab shows all merge requests (MR) linked to a work package with the corresponding status (e.g. 'Ready' or 'Merged') as well as the state (e.g. 'success' or 'queued') of the GitLab actions configured to run for a MR. MRs and work packages are in an n:m relationship, so a work package can be linked to multiple merge requests and a merge request can be linked to multiple work packages. @@ -100,7 +100,7 @@ You can now publish your branch (you can also do this later, after making the ch With the branch opened, you can start the actual development work using your preferred tool to alter your codebase. -![Gitlab changes in a merge request changes](gitlab-changes.png) +![GitLab changes in a merge request changes](gitlab-changes.png) Once you are satisfied with the changes you can create a commit. Within the 'Git snippets' menu, OpenProject suggests a commit message for you based on the title and the URL of the work package. diff --git a/docs/system-admin-guide/integrations/gitlab-integration/gitlab-changes.png b/docs/system-admin-guide/integrations/gitlab-integration/gitlab-changes.png index 8864c8dba762..efdd00b8cb1e 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/gitlab-changes.png and b/docs/system-admin-guide/integrations/gitlab-integration/gitlab-changes.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/gitlab-tab.png b/docs/system-admin-guide/integrations/gitlab-integration/gitlab-tab.png index b811186ef0a0..46f459406766 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/gitlab-tab.png and b/docs/system-admin-guide/integrations/gitlab-integration/gitlab-tab.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-activity-tab.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-activity-tab.png index 1681730da097..529031251afe 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-activity-tab.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-activity-tab.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-branch-name.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-branch-name.png index c65d82f32f31..681373ce2d9c 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-branch-name.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-branch-name.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-commit-message-in-client.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-commit-message-in-client.png index 9bac3fa1390a..f52498d3d488 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-commit-message-in-client.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-commit-message-in-client.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-branch.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-branch.png index 462dc662780e..f43910d175f7 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-branch.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-branch.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr-detail.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr-detail.png index 5d3f49e00246..afb68a3d78cd 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr-detail.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr-detail.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr.png index f04bf02f8423..4191b8d03c77 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-create-mr.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets-commit-message.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets-commit-message.png index 45eb212ce119..ffd2762e3842 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets-commit-message.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets-commit-message.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets.png index d78823fb8f9d..2337bf9395fa 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-git-snippets.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-actions.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-actions.png index e4e51696156b..300a3b5b4b39 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-actions.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-actions.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-issue.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-issue.png index 6ddd7402d8ad..b1dfdeba59ed 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-issue.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-issue.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-webhook.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-webhook.png index a4f751e00a68..df924dc1b4b1 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-webhook.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-gitlab-webhook.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-opened.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-opened.png index 166cc2070e4c..0e12505ea012 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-opened.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-opened.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-status.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-status.png index c5d95b69a498..f3b2f47d80c1 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-status.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-mr-status.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-new-issues.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-new-issues.png index b8377598f355..738f4be2aedf 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-new-issues.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-new-issues.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-no-issues.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-no-issues.png index b822b09415b0..fdb5b565babc 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-no-issues.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-no-issues.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-member.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-member.png index 4314b43eec37..3fac0b7a57e7 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-member.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-member.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-modules.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-modules.png index ed4b6aed38ad..f3934ff1cd09 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-modules.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-project-modules.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-publish-branch.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-publish-branch.png index 36326daaa118..d345eed58812 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-publish-branch.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-publish-branch.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-push-activity.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-push-activity.png index b7cb87b01cdb..662893a605d6 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-push-activity.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-push-activity.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-role.png b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-role.png index 5228926ea92e..3f2035d8279c 100644 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-role.png and b/docs/system-admin-guide/integrations/gitlab-integration/openproject-system-guide-gitlab-integration-role.png differ diff --git a/docs/system-admin-guide/integrations/gitlab-integration/workpackage-github-comments.png b/docs/system-admin-guide/integrations/gitlab-integration/workpackage-github-comments.png deleted file mode 100644 index 833b52931ae6..000000000000 Binary files a/docs/system-admin-guide/integrations/gitlab-integration/workpackage-github-comments.png and /dev/null differ diff --git a/docs/system-admin-guide/integrations/nextcloud/README.md b/docs/system-admin-guide/integrations/nextcloud/README.md index aa4ea7617d89..1fc9d5a245a0 100644 --- a/docs/system-admin-guide/integrations/nextcloud/README.md +++ b/docs/system-admin-guide/integrations/nextcloud/README.md @@ -348,9 +348,9 @@ You have setup the *Project folder* in both environments (Nextcloud and OpenProj a. If you have root access to the OpenProject server where your worker should be running, check if the worker processes are in fact present: `ps aux | grep job` - The result should show lines containing `bundle exec bundle exec good_job start` + The result should show lines containing `bundle exec rake jobs:work` - b. If you don't have root access to the OpenProject server then you can check the following URL in your browser: `https:///health_checks/all` (please insert the domain name of your OpenProject server). If your background workers are running, you should see a line like that `worker_backed_up: PASSED No jobs are waiting to be picked up.` + b. If you don't have root access to the OpenProject server then you can check the following URL in your browser: `https:///health_checks/all` (please insert the domain name of your OpenProject server). If your background workers are running, you should see a line like that `delayed_jobs_never_ran: PASSED All previous jobs have completed within the past 5 minutes` 2. Ensure that your project is setup correctly: 1. In your browser navigate to the project for which you want the **Project folders** feature to be working. diff --git a/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details.png b/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details.png deleted file mode 100644 index e7406bf8eb79..000000000000 Binary files a/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details.png and /dev/null differ diff --git a/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details_new.png b/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details_new.png index 9bcd1e54830f..638e0d98fcf9 100644 Binary files a/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details_new.png and b/docs/system-admin-guide/integrations/one-drive/openproject_system_guide_new_onedrive_storage_details_new.png differ diff --git a/docs/user-guide/file-management/README.md b/docs/user-guide/file-management/README.md index 9283527bd02c..e881b5bce977 100644 --- a/docs/user-guide/file-management/README.md +++ b/docs/user-guide/file-management/README.md @@ -12,7 +12,7 @@ keywords: files, attachment, Nextcloud, OneDrive, SharePoint |--------------------------------------------------------------------------------------|---------------------------------------------------------------------------| | [Manual upload](#manual-upload) | How to manually upload files to work packages in OpenProject. | | [Nextcloud integration](#nextcloud-integration) | How to manage files using Nextcloud integration in OpenProject. | -| [OneDrive/SharePoint integration](#onedrivesharepoint-integration-enterprise-add-on) | How to manage files using OneDrive/Sharepoint integration in OpenProject. | +| [OneDrive/SharePoint integration](#onedrivesharepoint-integration-enterprise-add-on) | How to manage files using OneDrive/SharePoint integration in OpenProject. | | [File management FAQs](./file-management-faq) | Frequently asked questions on file management in OpenProject. | There are several ways of adding or linking files to work packages in OpenProject. You can manually attach files directly to work packages or use one of the integrations with file management systems. diff --git a/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png b/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png index 062391e426ef..fd34461acbe0 100644 Binary files a/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png and b/docs/user-guide/file-management/nextcloud-integration/nc-new-work-package-created.png differ diff --git a/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png b/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png index a189c134f9a2..d6488081dc00 100644 Binary files a/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png and b/docs/user-guide/file-management/nextcloud-integration/nc_create_new_wp.png differ diff --git a/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png b/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png index f17bedc2f6d2..c48dce2e9953 100644 Binary files a/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png and b/docs/user-guide/file-management/nextcloud-integration/nc_select_multiple_files.png differ diff --git a/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png b/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png index d388e701ee9c..9201ad47bb23 100644 Binary files a/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png and b/docs/user-guide/file-management/nextcloud-integration/nc_select_wp_to_link.png differ diff --git a/docs/user-guide/file-management/one-drive-integration/README.md b/docs/user-guide/file-management/one-drive-integration/README.md index 9b29dce4242e..8344e260a66b 100644 --- a/docs/user-guide/file-management/one-drive-integration/README.md +++ b/docs/user-guide/file-management/one-drive-integration/README.md @@ -33,7 +33,7 @@ To begin using this integration, you will need to first connect your OpenProject 1. Select any work package. Go to the **Files tab** and, within the correct file storage section, click on **Storage login** button. - ![Login to Sharepoint storage from an OpenProject work package](openproject_onedrive_login_to_storage.png) + ![Login to SharePoint storage from an OpenProject work package](openproject_onedrive_login_to_storage.png) 2. You will see a Microsoft login prompt asking you to log in. Enter your credentials and log in. 3. Once you have logged in, you will automatically return to the work package in OpenProject and see that you can now start uploading and linking files. @@ -71,7 +71,7 @@ Once you have selected or dropped the files you would like to upload, you will n > **Info**: The default location that opens in the file picker is the file root of the configured OneDrive/SharePoint drive. -![Selection a Sharepoint location to upload a file from OpenProject](openproject_onedrive_select_location.png) +![Selection a SharePoint location to upload a file from OpenProject](openproject_onedrive_select_location.png) You can click on folders you see to navigate to them. Helpful breadcrumbs show you where you are in the folder hierarchy. @@ -83,7 +83,7 @@ To save the files you uploaded to the currently open folder, click on the **Choo The selected file is uploaded to your OneDrive/SharePoint instance and linked to the current work package. It appears under the name of the file storage. -![File successfully uploaded to Sharepoint storage](openproject_onedrive_file_uploaded.png) +![File successfully uploaded to SharePoint storage](openproject_onedrive_file_uploaded.png) If a file has been deleted on the OneDrive/SharePoint file storage it will still be displayed under the **Files** tab. However it will not be selectable. If you hover over a deleted file you will see the message indicating that the file could not be found. @@ -95,7 +95,7 @@ If a file has been deleted on the OneDrive/SharePoint file storage it will still If you wish to unlink any linked file or folder, hover it in the list of linked files and click on the **Unlink** icon. -![Unlink a linked Sharepoint file from an OpenProject work package](openproject_onedrive_download_file.png) +![Unlink a linked SharePoint file from an OpenProject work package](openproject_onedrive_download_file.png) Respectively in order to download a file, click on the **Download icon** in the context menu of the file link in the list of the linked files. diff --git a/docs/user-guide/gantt-chart/activate-gantt.gif b/docs/user-guide/gantt-chart/activate-gantt.gif deleted file mode 100644 index f7fb2ff6de7d..000000000000 Binary files a/docs/user-guide/gantt-chart/activate-gantt.gif and /dev/null differ diff --git a/docs/user-guide/gantt-chart/collapse-all-expand-all.png b/docs/user-guide/gantt-chart/collapse-all-expand-all.png deleted file mode 100644 index 1503ea060e78..000000000000 Binary files a/docs/user-guide/gantt-chart/collapse-all-expand-all.png and /dev/null differ diff --git a/docs/user-guide/gantt-chart/dependencies-gantt-chart-1566556144225.gif b/docs/user-guide/gantt-chart/dependencies-gantt-chart-1566556144225.gif deleted file mode 100644 index 4cfedbe4a203..000000000000 Binary files a/docs/user-guide/gantt-chart/dependencies-gantt-chart-1566556144225.gif and /dev/null differ diff --git a/docs/user-guide/gantt-chart/image-20201211020748715.png b/docs/user-guide/gantt-chart/image-20201211020748715.png deleted file mode 100644 index 1df2323bbb2d..000000000000 Binary files a/docs/user-guide/gantt-chart/image-20201211020748715.png and /dev/null differ diff --git a/docs/user-guide/gantt-chart/image-20201211131511543.png b/docs/user-guide/gantt-chart/image-20201211131511543.png deleted file mode 100644 index cf520a70c35b..000000000000 Binary files a/docs/user-guide/gantt-chart/image-20201211131511543.png and /dev/null differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-configure-gantt-chart.gif b/docs/user-guide/gantt-chart/openproject-user-guide-configure-gantt-chart.gif index db5c44f302fd..52e101ff55a6 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-configure-gantt-chart.gif and b/docs/user-guide/gantt-chart/openproject-user-guide-configure-gantt-chart.gif differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-auto-zoom.png b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-auto-zoom.png index ee499cca076d..9da602392d06 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-auto-zoom.png and b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-auto-zoom.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-collapse-all.png b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-collapse-all.png index 4b623faf9385..a218c8a38254 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-collapse-all.png and b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-collapse-all.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-filters.png b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-filters.png index f9ecfeb53596..14df5d466014 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-filters.png and b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-filters.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-views.png b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-views.png index d9de4df0a85f..e6617ee79d79 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-views.png and b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-views.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zen-mode.png b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zen-mode.png index 50ac0cbdf8d2..d4f2209c0735 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zen-mode.png and b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zen-mode.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zoom.png b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zoom.png index 8419fbf6fd25..b6e2991edbc1 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zoom.png and b/docs/user-guide/gantt-chart/openproject-user-guide-gantt-charts-zoom.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts-global.png b/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts-global.png index 3800c47c724a..d24e3625f174 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts-global.png and b/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts-global.png differ diff --git a/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts.png b/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts.png index f8706ea066eb..0d13b508bbeb 100644 Binary files a/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts.png and b/docs/user-guide/gantt-chart/openproject-user-guide-select-gantt-charts.png differ diff --git a/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu.png b/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu.png index 67359ff634b1..acdf764350e2 100644 Binary files a/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu.png and b/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu.png differ diff --git a/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu_grid_icon.png b/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu_grid_icon.png index 6b84f69164dc..917c54463bd4 100644 Binary files a/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu_grid_icon.png and b/docs/user-guide/home/global-modules/open_project_user_guide_global_modules_menu_grid_icon.png differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_boards.png b/docs/user-guide/home/global-modules/openproject_global_modules_boards.png index 224ef34f1153..9aa013f6258c 100644 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_boards.png and b/docs/user-guide/home/global-modules/openproject_global_modules_boards.png differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_calendars.png b/docs/user-guide/home/global-modules/openproject_global_modules_calendars.png index 413c8b7c868f..f2241a4086db 100644 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_calendars.png and b/docs/user-guide/home/global-modules/openproject_global_modules_calendars.png differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_gantt_charts.png b/docs/user-guide/home/global-modules/openproject_global_modules_gantt_charts.png index 310caf1e652a..2f8ea9291e52 100644 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_gantt_charts.png and b/docs/user-guide/home/global-modules/openproject_global_modules_gantt_charts.png differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_myprojects_filter.png b/docs/user-guide/home/global-modules/openproject_global_modules_myprojects_filter.png deleted file mode 100644 index 5314ccf0b749..000000000000 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_myprojects_filter.png and /dev/null differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_news.png b/docs/user-guide/home/global-modules/openproject_global_modules_news.png index c94eecab8fbc..11a381d68e0f 100644 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_news.png and b/docs/user-guide/home/global-modules/openproject_global_modules_news.png differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_projects.png b/docs/user-guide/home/global-modules/openproject_global_modules_projects.png index 453183be86f5..4e395fb51f78 100644 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_projects.png and b/docs/user-guide/home/global-modules/openproject_global_modules_projects.png differ diff --git a/docs/user-guide/home/global-modules/openproject_global_modules_team_planner.png b/docs/user-guide/home/global-modules/openproject_global_modules_team_planner.png index 7874b02d1b33..325b08e038b1 100644 Binary files a/docs/user-guide/home/global-modules/openproject_global_modules_team_planner.png and b/docs/user-guide/home/global-modules/openproject_global_modules_team_planner.png differ diff --git a/docs/user-guide/home/openproject_user_guide_home_page.png b/docs/user-guide/home/openproject_user_guide_home_page.png index 000650c687da..a8da1232609e 100644 Binary files a/docs/user-guide/home/openproject_user_guide_home_page.png and b/docs/user-guide/home/openproject_user_guide_home_page.png differ diff --git a/docs/user-guide/meetings/classic-meetings/copy-meeting.png b/docs/user-guide/meetings/classic-meetings/copy-meeting.png index 210c72a613d0..4c0c2432faa4 100644 Binary files a/docs/user-guide/meetings/classic-meetings/copy-meeting.png and b/docs/user-guide/meetings/classic-meetings/copy-meeting.png differ diff --git a/docs/user-guide/meetings/classic-meetings/create-new-classic-meeting.png b/docs/user-guide/meetings/classic-meetings/create-new-classic-meeting.png index afc12ea56009..60f43708da40 100644 Binary files a/docs/user-guide/meetings/classic-meetings/create-new-classic-meeting.png and b/docs/user-guide/meetings/classic-meetings/create-new-classic-meeting.png differ diff --git a/docs/user-guide/meetings/classic-meetings/delete-meeting.png b/docs/user-guide/meetings/classic-meetings/delete-meeting.png index 28875a5a8334..d4806a22dead 100644 Binary files a/docs/user-guide/meetings/classic-meetings/delete-meeting.png and b/docs/user-guide/meetings/classic-meetings/delete-meeting.png differ diff --git a/docs/user-guide/meetings/classic-meetings/download-a-meeting.png b/docs/user-guide/meetings/classic-meetings/download-a-meeting.png index 585a7417d634..a35f86043491 100644 Binary files a/docs/user-guide/meetings/classic-meetings/download-a-meeting.png and b/docs/user-guide/meetings/classic-meetings/download-a-meeting.png differ diff --git a/docs/user-guide/meetings/classic-meetings/edit-meeting-agenda.png b/docs/user-guide/meetings/classic-meetings/edit-meeting-agenda.png index 8985994db0a8..b16c132d2f07 100644 Binary files a/docs/user-guide/meetings/classic-meetings/edit-meeting-agenda.png and b/docs/user-guide/meetings/classic-meetings/edit-meeting-agenda.png differ diff --git a/docs/user-guide/meetings/classic-meetings/edit-meeting.png b/docs/user-guide/meetings/classic-meetings/edit-meeting.png index a337bbe740f6..94b50695f163 100644 Binary files a/docs/user-guide/meetings/classic-meetings/edit-meeting.png and b/docs/user-guide/meetings/classic-meetings/edit-meeting.png differ diff --git a/docs/user-guide/meetings/classic-meetings/edit-minutes.png b/docs/user-guide/meetings/classic-meetings/edit-minutes.png index 34cfc122a7fa..dafb27a6b89c 100644 Binary files a/docs/user-guide/meetings/classic-meetings/edit-minutes.png and b/docs/user-guide/meetings/classic-meetings/edit-minutes.png differ diff --git a/docs/user-guide/meetings/classic-meetings/meeting-participants.png b/docs/user-guide/meetings/classic-meetings/meeting-participants.png index 24832bd7a1d1..59eaaf0f77c4 100644 Binary files a/docs/user-guide/meetings/classic-meetings/meeting-participants.png and b/docs/user-guide/meetings/classic-meetings/meeting-participants.png differ diff --git a/docs/user-guide/meetings/classic-meetings/meetings.png b/docs/user-guide/meetings/classic-meetings/meetings.png index eae8071876cc..797bef102d9d 100644 Binary files a/docs/user-guide/meetings/classic-meetings/meetings.png and b/docs/user-guide/meetings/classic-meetings/meetings.png differ diff --git a/docs/user-guide/meetings/classic-meetings/send-email-to-participants.png b/docs/user-guide/meetings/classic-meetings/send-email-to-participants.png index 1ee9736e329d..c853a095234b 100644 Binary files a/docs/user-guide/meetings/classic-meetings/send-email-to-participants.png and b/docs/user-guide/meetings/classic-meetings/send-email-to-participants.png differ diff --git a/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting.png b/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting.png index 5caa45d31422..20287abc5bce 100644 Binary files a/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting.png and b/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting.png differ diff --git a/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting_details.png b/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting_details.png index a7c2620e650f..48991f2d121b 100644 Binary files a/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting_details.png and b/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_copy_meeting_details.png differ diff --git a/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_delete_meeting.png b/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_delete_meeting.png index 4d8b64a91135..e9ee987262d3 100644 Binary files a/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_delete_meeting.png and b/docs/user-guide/meetings/dynamic-meetings/openproject_dynamic_meetings_delete_meeting.png differ diff --git a/docs/user-guide/meetings/dynamic-meetings/openproject_userguid_dynamic_meeting_edit_title.png b/docs/user-guide/meetings/dynamic-meetings/openproject_userguid_dynamic_meeting_edit_title.png index ad9ad398bf2c..469cd761baa6 100644 Binary files a/docs/user-guide/meetings/dynamic-meetings/openproject_userguid_dynamic_meeting_edit_title.png and b/docs/user-guide/meetings/dynamic-meetings/openproject_userguid_dynamic_meeting_edit_title.png differ diff --git a/docs/user-guide/projects/delete-a-project.png b/docs/user-guide/projects/delete-a-project.png index ba6a37d14f34..0f93a047fb5c 100644 Binary files a/docs/user-guide/projects/delete-a-project.png and b/docs/user-guide/projects/delete-a-project.png differ diff --git a/docs/user-guide/projects/new-subproject-project-list.png b/docs/user-guide/projects/new-subproject-project-list.png deleted file mode 100644 index aa02969491a0..000000000000 Binary files a/docs/user-guide/projects/new-subproject-project-list.png and /dev/null differ diff --git a/docs/user-guide/projects/project-information-copy-project.png b/docs/user-guide/projects/project-information-copy-project.png index f7e0b1b60bd1..8e0854525fa2 100644 Binary files a/docs/user-guide/projects/project-information-copy-project.png and b/docs/user-guide/projects/project-information-copy-project.png differ diff --git a/docs/user-guide/projects/project-list-filter.png b/docs/user-guide/projects/project-list-filter.png index 816ec641625b..3f782e95d2c5 100644 Binary files a/docs/user-guide/projects/project-list-filter.png and b/docs/user-guide/projects/project-list-filter.png differ diff --git a/docs/user-guide/projects/project-lists/Filter-projects-list.png b/docs/user-guide/projects/project-lists/Filter-projects-list.png deleted file mode 100644 index 10151c4d2ed3..000000000000 Binary files a/docs/user-guide/projects/project-lists/Filter-projects-list.png and /dev/null differ diff --git a/docs/user-guide/projects/project-lists/Name-private-projects-filter.png b/docs/user-guide/projects/project-lists/Name-private-projects-filter.png index 6e3e89e4479c..0b228bf09c86 100644 Binary files a/docs/user-guide/projects/project-lists/Name-private-projects-filter.png and b/docs/user-guide/projects/project-lists/Name-private-projects-filter.png differ diff --git a/docs/user-guide/projects/project-lists/Project-list-button.png b/docs/user-guide/projects/project-lists/Project-list-button.png index 120e2c05128b..0c285f387e0c 100644 Binary files a/docs/user-guide/projects/project-lists/Project-list-button.png and b/docs/user-guide/projects/project-lists/Project-list-button.png differ diff --git a/docs/user-guide/projects/project-lists/activity-global-menu.png b/docs/user-guide/projects/project-lists/activity-global-menu.png index 8bbec85ab6a0..cb5e36fae9ee 100644 Binary files a/docs/user-guide/projects/project-lists/activity-global-menu.png and b/docs/user-guide/projects/project-lists/activity-global-menu.png differ diff --git a/docs/user-guide/projects/project-lists/actvity-global-filter.png b/docs/user-guide/projects/project-lists/actvity-global-filter.png index acec7c885314..78fa94d6291e 100644 Binary files a/docs/user-guide/projects/project-lists/actvity-global-filter.png and b/docs/user-guide/projects/project-lists/actvity-global-filter.png differ diff --git a/docs/user-guide/projects/project-lists/arrow-project-description.png b/docs/user-guide/projects/project-lists/arrow-project-description.png deleted file mode 100644 index 8ab28ed52d19..000000000000 Binary files a/docs/user-guide/projects/project-lists/arrow-project-description.png and /dev/null differ diff --git a/docs/user-guide/projects/project-lists/configure-project-list.png b/docs/user-guide/projects/project-lists/configure-project-list.png deleted file mode 100644 index 4f4a6f2d41e5..000000000000 Binary files a/docs/user-guide/projects/project-lists/configure-project-list.png and /dev/null differ diff --git a/docs/user-guide/projects/project-lists/configure-view-form-project-list.png b/docs/user-guide/projects/project-lists/configure-view-form-project-list.png index 3240d3b13de2..4ecd9566bca4 100644 Binary files a/docs/user-guide/projects/project-lists/configure-view-form-project-list.png and b/docs/user-guide/projects/project-lists/configure-view-form-project-list.png differ diff --git a/docs/user-guide/projects/project-lists/configure-view-project-list.png b/docs/user-guide/projects/project-lists/configure-view-project-list.png index 8ffa1b67f883..5ae98e35a78e 100644 Binary files a/docs/user-guide/projects/project-lists/configure-view-project-list.png and b/docs/user-guide/projects/project-lists/configure-view-project-list.png differ diff --git a/docs/user-guide/projects/project-lists/display-all-workpackages.png b/docs/user-guide/projects/project-lists/display-all-workpackages.png index b7beb129d259..8c42a507e028 100644 Binary files a/docs/user-guide/projects/project-lists/display-all-workpackages.png and b/docs/user-guide/projects/project-lists/display-all-workpackages.png differ diff --git a/docs/user-guide/projects/project-lists/expand-link-project-description.png b/docs/user-guide/projects/project-lists/expand-link-project-description.png index e59f128607bd..f27246010edb 100644 Binary files a/docs/user-guide/projects/project-lists/expand-link-project-description.png and b/docs/user-guide/projects/project-lists/expand-link-project-description.png differ diff --git a/docs/user-guide/projects/project-lists/export-project-list-formats.png b/docs/user-guide/projects/project-lists/export-project-list-formats.png index 3163ac310963..4f244ce916a3 100644 Binary files a/docs/user-guide/projects/project-lists/export-project-list-formats.png and b/docs/user-guide/projects/project-lists/export-project-list-formats.png differ diff --git a/docs/user-guide/projects/project-lists/export-projects.png b/docs/user-guide/projects/project-lists/export-projects.png index 16349d1031c3..c0c677e9d448 100644 Binary files a/docs/user-guide/projects/project-lists/export-projects.png and b/docs/user-guide/projects/project-lists/export-projects.png differ diff --git a/docs/user-guide/projects/project-lists/navigation-bar-modules-3923134.png b/docs/user-guide/projects/project-lists/navigation-bar-modules-3923134.png deleted file mode 100644 index 2ff03580934e..000000000000 Binary files a/docs/user-guide/projects/project-lists/navigation-bar-modules-3923134.png and /dev/null differ diff --git a/docs/user-guide/projects/project-lists/navigation-bar-modules.png b/docs/user-guide/projects/project-lists/navigation-bar-modules.png index 57fd78f478a5..f9b5ee2803da 100644 Binary files a/docs/user-guide/projects/project-lists/navigation-bar-modules.png and b/docs/user-guide/projects/project-lists/navigation-bar-modules.png differ diff --git a/docs/user-guide/projects/project-lists/new-subproject-project-list.png b/docs/user-guide/projects/project-lists/new-subproject-project-list.png index b0c06a445ed9..c1073b77af99 100644 Binary files a/docs/user-guide/projects/project-lists/new-subproject-project-list.png and b/docs/user-guide/projects/project-lists/new-subproject-project-list.png differ diff --git a/docs/user-guide/projects/project-lists/overall-activity-button-3922893.png b/docs/user-guide/projects/project-lists/overall-activity-button-3922893.png deleted file mode 100644 index cb059ccf32f5..000000000000 Binary files a/docs/user-guide/projects/project-lists/overall-activity-button-3922893.png and /dev/null differ diff --git a/docs/user-guide/projects/project-lists/overall-activity-link.png b/docs/user-guide/projects/project-lists/overall-activity-link.png index e4c8660ac84b..68103544d329 100644 Binary files a/docs/user-guide/projects/project-lists/overall-activity-link.png and b/docs/user-guide/projects/project-lists/overall-activity-link.png differ diff --git a/docs/user-guide/projects/project-lists/overall-activity-meeting-filter.png b/docs/user-guide/projects/project-lists/overall-activity-meeting-filter.png deleted file mode 100644 index d18c70cd455f..000000000000 Binary files a/docs/user-guide/projects/project-lists/overall-activity-meeting-filter.png and /dev/null differ diff --git a/docs/user-guide/projects/project-lists/private-project-filter-delete.png b/docs/user-guide/projects/project-lists/private-project-filter-delete.png index 8763b6a4c66c..5b1cefbd20fd 100644 Binary files a/docs/user-guide/projects/project-lists/private-project-filter-delete.png and b/docs/user-guide/projects/project-lists/private-project-filter-delete.png differ diff --git a/docs/user-guide/projects/project-lists/private-project-filter-saved.png b/docs/user-guide/projects/project-lists/private-project-filter-saved.png index b4f949284f5e..15e319e7e77e 100644 Binary files a/docs/user-guide/projects/project-lists/private-project-filter-saved.png and b/docs/user-guide/projects/project-lists/private-project-filter-saved.png differ diff --git a/docs/user-guide/projects/project-lists/projects-list.png b/docs/user-guide/projects/project-lists/projects-list.png index b1d14b79350e..7cdbfc27e201 100644 Binary files a/docs/user-guide/projects/project-lists/projects-list.png and b/docs/user-guide/projects/project-lists/projects-list.png differ diff --git a/docs/user-guide/projects/project-lists/projects-lists-default-filters.png b/docs/user-guide/projects/project-lists/projects-lists-default-filters.png index 2410bc230453..cba9c9942f6e 100644 Binary files a/docs/user-guide/projects/project-lists/projects-lists-default-filters.png and b/docs/user-guide/projects/project-lists/projects-lists-default-filters.png differ diff --git a/docs/user-guide/projects/project-lists/save-button-filtered-view.png b/docs/user-guide/projects/project-lists/save-button-filtered-view.png index d796ab07e08d..40811989537c 100644 Binary files a/docs/user-guide/projects/project-lists/save-button-filtered-view.png and b/docs/user-guide/projects/project-lists/save-button-filtered-view.png differ diff --git a/docs/user-guide/projects/project-lists/view_all_projects_options.png b/docs/user-guide/projects/project-lists/view_all_projects_options.png index 5ed573792fa8..42982648ded4 100644 Binary files a/docs/user-guide/projects/project-lists/view_all_projects_options.png and b/docs/user-guide/projects/project-lists/view_all_projects_options.png differ diff --git a/docs/user-guide/projects/project-settigns-copy-project.png b/docs/user-guide/projects/project-settigns-copy-project.png index 5aebfc01053f..2f8d85fe6ca2 100644 Binary files a/docs/user-guide/projects/project-settigns-copy-project.png and b/docs/user-guide/projects/project-settigns-copy-project.png differ diff --git a/docs/user-guide/projects/project-settings-archive-project.png b/docs/user-guide/projects/project-settings-archive-project.png index f7322de982de..4a6037380830 100644 Binary files a/docs/user-guide/projects/project-settings-archive-project.png and b/docs/user-guide/projects/project-settings-archive-project.png differ diff --git a/docs/user-guide/projects/project-settings-copy-project-advanced-settings.png b/docs/user-guide/projects/project-settings-copy-project-advanced-settings.png index 08d631c46d0a..1b73a9f43e00 100644 Binary files a/docs/user-guide/projects/project-settings-copy-project-advanced-settings.png and b/docs/user-guide/projects/project-settings-copy-project-advanced-settings.png differ diff --git a/docs/user-guide/projects/project-settings-information-change-hierarchy.png b/docs/user-guide/projects/project-settings-information-change-hierarchy.png index 589d9765b4f1..99c411f6261d 100644 Binary files a/docs/user-guide/projects/project-settings-information-change-hierarchy.png and b/docs/user-guide/projects/project-settings-information-change-hierarchy.png differ diff --git a/docs/user-guide/projects/project-settings-information-copy-project-copy-options.png b/docs/user-guide/projects/project-settings-information-copy-project-copy-options.png deleted file mode 100644 index 8a58e027a654..000000000000 Binary files a/docs/user-guide/projects/project-settings-information-copy-project-copy-options.png and /dev/null differ diff --git a/docs/user-guide/projects/project-settings-subproject.png b/docs/user-guide/projects/project-settings-subproject.png index 99853c293f10..26a4b244ae85 100644 Binary files a/docs/user-guide/projects/project-settings-subproject.png and b/docs/user-guide/projects/project-settings-subproject.png differ diff --git a/docs/user-guide/projects/project-settings/file-storages/file-storages-oauth-nudge-nextcloud.png b/docs/user-guide/projects/project-settings/file-storages/file-storages-oauth-nudge-nextcloud.png index 80a6224cb596..f46a9aaaa19e 100644 Binary files a/docs/user-guide/projects/project-settings/file-storages/file-storages-oauth-nudge-nextcloud.png and b/docs/user-guide/projects/project-settings/file-storages/file-storages-oauth-nudge-nextcloud.png differ diff --git a/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders-new.png b/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders-new.png index b6389a000168..30af3f740147 100644 Binary files a/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders-new.png and b/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders-new.png differ diff --git a/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders.png b/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders.png deleted file mode 100644 index 8baecfbfda15..000000000000 Binary files a/docs/user-guide/projects/project-settings/file-storages/onedrive-storage-add-folders.png and /dev/null differ diff --git a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-bulk-editing.png b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-bulk-editing.png index 9c777429b619..31d1699c57f7 100644 Binary files a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-bulk-editing.png and b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-bulk-editing.png differ diff --git a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-hierarchy-progress.png b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-hierarchy-progress.png index 86d768e55971..af129927740b 100644 Binary files a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-hierarchy-progress.png and b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-hierarchy-progress.png differ diff --git a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-two-progress-values.png b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-two-progress-values.png index 8f706abb987c..70b91d6a87b0 100644 Binary files a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-two-progress-values.png and b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-two-progress-values.png differ diff --git a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-50perc.png b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-50perc.png index e541f1f9bc74..f20245a3d7a7 100644 Binary files a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-50perc.png and b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-50perc.png differ diff --git a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-editor.png b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-editor.png index a8fdcb8cfb3d..25c68ac05f42 100644 Binary files a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-editor.png and b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field-editor.png differ diff --git a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field.png b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field.png index b084d798c6a0..2d302453d004 100644 Binary files a/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field.png and b/docs/user-guide/time-and-costs/progress-tracking/progress-tracking-wp-field.png differ diff --git a/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_share_button_wp_numbers.png b/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_share_button_wp_numbers.png index 237585a45f33..b20a3afb5125 100644 Binary files a/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_share_button_wp_numbers.png and b/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_share_button_wp_numbers.png differ diff --git a/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter.png b/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter.png deleted file mode 100644 index 603efe926a53..000000000000 Binary files a/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter.png and /dev/null differ diff --git a/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter_new.png b/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter_new.png index cd0c5dd20edd..88430a51ccf0 100644 Binary files a/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter_new.png and b/docs/user-guide/work-packages/share-work-packages/openproject_user_guide_shared_with_users_filter_new.png differ diff --git a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-full-screen-back-arrow.png b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-full-screen-back-arrow.png index 6e5f10d92d75..ec30bd878af2 100644 Binary files a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-full-screen-back-arrow.png and b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-full-screen-back-arrow.png differ diff --git a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-table-view.png b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-table-view.png index 9d15625eeab7..e3fdef54b432 100644 Binary files a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-table-view.png and b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-table-view.png differ diff --git a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-views.png b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-views.png index a281987eff86..a8ad0b3db68e 100644 Binary files a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-views.png and b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-package-views.png differ diff --git a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-full-screen-icon.png b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-full-screen-icon.png index ae1163344ca4..8681448b84bc 100644 Binary files a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-full-screen-icon.png and b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-full-screen-icon.png differ diff --git a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-icon.png b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-icon.png index df001234c60f..c8df03be200d 100644 Binary files a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-icon.png and b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-icon.png differ diff --git a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-view.png b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-view.png index 1e9412ca951f..17c1577f79f1 100644 Binary files a/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-view.png and b/docs/user-guide/work-packages/work-package-views/openproject-user-guide-work-packages-split-screen-view.png differ diff --git a/docs/user-guide/work-packages/work-package-views/work-package-views-default.png b/docs/user-guide/work-packages/work-package-views/work-package-views-default.png deleted file mode 100644 index 6886b97771a9..000000000000 Binary files a/docs/user-guide/work-packages/work-package-views/work-package-views-default.png and /dev/null differ diff --git a/docs/user-guide/work-packages/work-packages-faq/README.md b/docs/user-guide/work-packages/work-packages-faq/README.md index fa3a7715a8db..5ad656c8c6d3 100644 --- a/docs/user-guide/work-packages/work-packages-faq/README.md +++ b/docs/user-guide/work-packages/work-packages-faq/README.md @@ -236,7 +236,7 @@ The following factors can have an impact on the duration of the export: - Number of columns in the export (less of an impact) To identify how many background jobs have run or are delayed, enter "/health_checks/full" after the URL (e.g. myopenprojectinstance.com/health_checks/full). -This provides an overview of "worker_backed_up" which shows the number of background jobs that could not get ran within the last 5 minutes. If there are multiple entries, this can indicate that the number of web workers should be increased. +This provides an overview of "delayed_jobs_never_ran" which shows the number of background jobs that could not get ran within the last 10 minutes. If there are multiple entries, this can indicate that the number of web workers should be increased. For a documentation of how to do this, please refer to [these instructions](../../../installation-and-operations/operation/control) (see section "Scaling the number of web workers"). diff --git a/extra/mail_handler/rdm-mailhandler.rb b/extra/mail_handler/rdm-mailhandler.rb index a40d446ce0e7..80e2cf8ff7d0 100644 --- a/extra/mail_handler/rdm-mailhandler.rb +++ b/extra/mail_handler/rdm-mailhandler.rb @@ -77,11 +77,11 @@ # --type bug \\ # --allow-override type,priority -require "net/http" -require "net/https" -require "uri" -require "getoptlong" -require "rdoc/usage" +require 'net/http' +require 'net/https' +require 'uri' +require 'getoptlong' +require 'rdoc/usage' module Net class HTTPS < HTTP @@ -91,14 +91,14 @@ def self.post_form(url, params, headers) request.basic_auth url.user, url.password if url.user request.initialize_http_header(headers) http = new(url.host, url.port) - http.use_ssl = (url.scheme == "https") + http.use_ssl = (url.scheme == 'https') http.start { |h| h.request(request) } end end end class RedmineMailHandler - VERSION = "0.1" + VERSION = '0.1' attr_accessor :verbose, :issue_attributes, :allow_override, :unknown_user, :no_permission_check, :url, :key @@ -106,42 +106,42 @@ def initialize self.issue_attributes = {} opts = GetoptLong.new( - ["--help", "-h", GetoptLong::NO_ARGUMENT], - ["--version", "-V", GetoptLong::NO_ARGUMENT], - ["--verbose", "-v", GetoptLong::NO_ARGUMENT], - ["--url", "-u", GetoptLong::REQUIRED_ARGUMENT], - ["--key", "-k", GetoptLong::REQUIRED_ARGUMENT], - ["--project", "-p", GetoptLong::REQUIRED_ARGUMENT], - ["--status", "-s", GetoptLong::REQUIRED_ARGUMENT], - ["--type", "-t", GetoptLong::REQUIRED_ARGUMENT], - ["--category", GetoptLong::REQUIRED_ARGUMENT], - ["--priority", GetoptLong::REQUIRED_ARGUMENT], - ["--allow-override", "-o", GetoptLong::REQUIRED_ARGUMENT], - ["--unknown-user", GetoptLong::REQUIRED_ARGUMENT], - ["--no-permission-check", GetoptLong::NO_ARGUMENT] + ['--help', '-h', GetoptLong::NO_ARGUMENT], + ['--version', '-V', GetoptLong::NO_ARGUMENT], + ['--verbose', '-v', GetoptLong::NO_ARGUMENT], + ['--url', '-u', GetoptLong::REQUIRED_ARGUMENT], + ['--key', '-k', GetoptLong::REQUIRED_ARGUMENT], + ['--project', '-p', GetoptLong::REQUIRED_ARGUMENT], + ['--status', '-s', GetoptLong::REQUIRED_ARGUMENT], + ['--type', '-t', GetoptLong::REQUIRED_ARGUMENT], + ['--category', GetoptLong::REQUIRED_ARGUMENT], + ['--priority', GetoptLong::REQUIRED_ARGUMENT], + ['--allow-override', '-o', GetoptLong::REQUIRED_ARGUMENT], + ['--unknown-user', GetoptLong::REQUIRED_ARGUMENT], + ['--no-permission-check', GetoptLong::NO_ARGUMENT] ) opts.each do |opt, arg| case opt - when "--url" + when '--url' self.url = arg.dup - when "--key" + when '--key' self.key = arg.dup - when "--help" + when '--help' usage - when "--verbose" + when '--verbose' self.verbose = true - when "--version" + when '--version' puts VERSION exit - when "--project", "--status", "--type", "--category", "--priority" - issue_attributes[opt.gsub(%r{^--}, "")] = arg.dup - when "--allow-override" + when '--project', '--status', '--type', '--category', '--priority' + issue_attributes[opt.gsub(%r{^--}, '')] = arg.dup + when '--allow-override' self.allow_override = arg.dup - when "--unknown-user" + when '--unknown-user' self.unknown_user = arg.dup - when "--no-permission-check" - self.no_permission_check = "1" + when '--no-permission-check' + self.no_permission_check = '1' end end @@ -149,14 +149,14 @@ def initialize end def submit(email) - uri = url.gsub(%r{/*\z}, "") + "/mail_handler" + uri = url.gsub(%r{/*\z}, '') + '/mail_handler' - headers = { "User-Agent" => "Redmine mail handler/#{VERSION}" } + headers = { 'User-Agent' => "Redmine mail handler/#{VERSION}" } - data = { "key" => key, "email" => email, - "allow_override" => allow_override, - "unknown_user" => unknown_user, - "no_permission_check" => no_permission_check } + data = { 'key' => key, 'email' => email, + 'allow_override' => allow_override, + 'unknown_user' => unknown_user, + 'no_permission_check' => no_permission_check } issue_attributes.each { |attr, value| data["issue[#{attr}]"] = value } debug "Posting to #{uri}..." diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 887100db25d8..5cbab641ac6b 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -4586,21 +4586,21 @@ "integrity": "sha512-HWwz+6MrfK5NTWcg9GdKFpMBW/yrAV937oXiw2eDtsd88P3SRwoCt6ZO6QmKp9RP3nDU9cbqmuGZ0xBh0eIFeg==" }, "node_modules/@primer/css": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@primer/css/-/css-21.2.2.tgz", - "integrity": "sha512-Mcpt9CyajnPW8TJmZYIUhnctdLk7rfsoyvh8w4qDydu2C7HHOHa0wKQjf0zofQ+AyJOIW1Gfa9xvBfwAeNkgoQ==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/@primer/css/-/css-21.1.1.tgz", + "integrity": "sha512-1XRx8FwWxrr8SSZit2C9KxaofTi0CELKbGmHGpmYQmRIAECIa912Emp4BlAC7iQmf3Tb5oZOkke5zuAt+seDxg==", "dependencies": { - "@primer/primitives": "^7.15.12", - "@primer/view-components": "^0.19.0" + "@primer/primitives": "^7.12.0", + "@primer/view-components": "^0.14.0" }, "engines": { "node": ">=16.0.0" } }, "node_modules/@primer/primitives": { - "version": "7.15.12", - "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-7.15.12.tgz", - "integrity": "sha512-ujAsbRB5Xw6rrxizbTgv1bxpraZ091stPMsO6pqGxzc+zIyhrojpGVBuCKJ+RYkpbKK7T4bZzgOT/KyWBAFwwg==" + "version": "7.15.5", + "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-7.15.5.tgz", + "integrity": "sha512-tiJEMxy5hDi9a3YxgrBeJScLPUQSLuWsKDNuoXXiX7zLzejnYdxXXG3qOaNHzNyyn8TkSQkzmKx0ioaSLR2zNw==" }, "node_modules/@primer/view-components": { "name": "@openproject/primer-view-components", @@ -4912,9 +4912,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", - "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", "dev": true }, "node_modules/@types/mime": { @@ -8080,9 +8080,9 @@ } }, "node_modules/core-js": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.1.tgz", - "integrity": "sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA==", + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.0.tgz", + "integrity": "sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -9801,9 +9801,9 @@ "dev": true }, "node_modules/eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "version": "7.34.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz", + "integrity": "sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ==", "dev": true, "dependencies": { "array-includes": "^3.1.7", @@ -10776,9 +10776,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==", "funding": [ { "type": "individual", @@ -23899,18 +23899,18 @@ "integrity": "sha512-HWwz+6MrfK5NTWcg9GdKFpMBW/yrAV937oXiw2eDtsd88P3SRwoCt6ZO6QmKp9RP3nDU9cbqmuGZ0xBh0eIFeg==" }, "@primer/css": { - "version": "21.2.2", - "resolved": "https://registry.npmjs.org/@primer/css/-/css-21.2.2.tgz", - "integrity": "sha512-Mcpt9CyajnPW8TJmZYIUhnctdLk7rfsoyvh8w4qDydu2C7HHOHa0wKQjf0zofQ+AyJOIW1Gfa9xvBfwAeNkgoQ==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/@primer/css/-/css-21.1.1.tgz", + "integrity": "sha512-1XRx8FwWxrr8SSZit2C9KxaofTi0CELKbGmHGpmYQmRIAECIa912Emp4BlAC7iQmf3Tb5oZOkke5zuAt+seDxg==", "requires": { - "@primer/primitives": "^7.15.12", + "@primer/primitives": "^7.12.0", "@primer/view-components": "npm:@openproject/primer-view-components@^0.23.0" } }, "@primer/primitives": { - "version": "7.15.12", - "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-7.15.12.tgz", - "integrity": "sha512-ujAsbRB5Xw6rrxizbTgv1bxpraZ091stPMsO6pqGxzc+zIyhrojpGVBuCKJ+RYkpbKK7T4bZzgOT/KyWBAFwwg==" + "version": "7.15.5", + "resolved": "https://registry.npmjs.org/@primer/primitives/-/primitives-7.15.5.tgz", + "integrity": "sha512-tiJEMxy5hDi9a3YxgrBeJScLPUQSLuWsKDNuoXXiX7zLzejnYdxXXG3qOaNHzNyyn8TkSQkzmKx0ioaSLR2zNw==" }, "@primer/view-components": { "version": "npm:@openproject/primer-view-components@0.23.0", @@ -24194,9 +24194,9 @@ "dev": true }, "@types/lodash": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", - "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", "dev": true }, "@types/mime": { @@ -26528,9 +26528,9 @@ } }, "core-js": { - "version": "3.36.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.1.tgz", - "integrity": "sha512-BTvUrwxVBezj5SZ3f10ImnX2oRByMxql3EimVqMysepbC9EeMUOpLwdy6Eoili2x6E4kf+ZUB5k/+Jv55alPfA==" + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.36.0.tgz", + "integrity": "sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==" }, "core-js-compat": { "version": "3.33.1", @@ -27996,9 +27996,9 @@ } }, "eslint-plugin-react": { - "version": "7.34.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", - "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "version": "7.34.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.0.tgz", + "integrity": "sha512-MeVXdReleBTdkz/bvcQMSnCXGi+c9kvy51IpinjnJgutl3YTHWsDdke7Z1ufZpGfDG8xduBDKyjtB9JH1eBKIQ==", "dev": true, "requires": { "array-includes": "^3.1.7", @@ -28661,9 +28661,9 @@ "dev": true }, "follow-redirects": { - "version": "1.15.6", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", - "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz", + "integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==" }, "for-each": { "version": "0.3.3", diff --git a/frontend/src/app/core/global_search/input/global-search-input.component.sass b/frontend/src/app/core/global_search/input/global-search-input.component.sass index 85c46526661e..8a9c67005320 100644 --- a/frontend/src/app/core/global_search/input/global-search-input.component.sass +++ b/frontend/src/app/core/global_search/input/global-search-input.component.sass @@ -59,9 +59,6 @@ $search-input-height: 30px background: transparent border-color: var(--header-item-font-color) !important - &:focus-within - @include spot-focus - .ng-arrow-wrapper display: none @@ -129,15 +126,19 @@ $search-input-height: 30px background-color: unset &:last-child border-bottom: none + &.ng-option-marked + color: var(--header-drop-down-item-font-hover-color) &.ng-option-disabled display: none + &.ng-option-selected + color: var(--header-drop-down-item-font-hover-color) &.-markable .ng-option &.ng-option-marked background-color: var(--drop-down-hover-bg-color) &.ng-option-selected - background-color: unset + background-color: var(--drop-down-selected-bg-color) &--input // Fix position of the spinner diff --git a/frontend/src/app/core/setup/globals/components/admin/backup.component.html b/frontend/src/app/core/setup/globals/components/admin/backup.component.html index 669d35fa1816..e5e8a99e8c92 100644 --- a/frontend/src/app/core/setup/globals/components/admin/backup.component.html +++ b/frontend/src/app/core/setup/globals/components/admin/backup.component.html @@ -66,7 +66,7 @@

    diff --git a/frontend/src/app/features/boards/boards-sidebar/boards-menu.component.html b/frontend/src/app/features/boards/boards-sidebar/boards-menu.component.html index 9f431caa7df3..774abbe5d8e7 100644 --- a/frontend/src/app/features/boards/boards-sidebar/boards-menu.component.html +++ b/frontend/src/app/features/boards/boards-sidebar/boards-menu.component.html @@ -11,7 +11,7 @@ diff --git a/frontend/src/app/features/enterprise/enterprise-modal/enterprise-trial.modal.html b/frontend/src/app/features/enterprise/enterprise-modal/enterprise-trial.modal.html index ba1fdac3cad4..93a7434c7b35 100644 --- a/frontend/src/app/features/enterprise/enterprise-modal/enterprise-trial.modal.html +++ b/frontend/src/app/features/enterprise/enterprise-modal/enterprise-trial.modal.html @@ -45,7 +45,7 @@ [attr.title]="text.button_cancel" > diff --git a/frontend/src/app/features/invite-user-modal/project-selection/project-selection.component.html b/frontend/src/app/features/invite-user-modal/project-selection/project-selection.component.html index c22b84e449e5..7c6392fddd35 100644 --- a/frontend/src/app/features/invite-user-modal/project-selection/project-selection.component.html +++ b/frontend/src/app/features/invite-user-modal/project-selection/project-selection.component.html @@ -73,7 +73,7 @@ > diff --git a/frontend/src/app/features/invite-user-modal/success/success.component.html b/frontend/src/app/features/invite-user-modal/success/success.component.html index 130243299aff..728c90c37167 100644 --- a/frontend/src/app/features/invite-user-modal/success/success.component.html +++ b/frontend/src/app/features/invite-user-modal/success/success.component.html @@ -17,7 +17,7 @@
    diff --git a/frontend/src/app/features/invite-user-modal/summary/summary.component.html b/frontend/src/app/features/invite-user-modal/summary/summary.component.html index de8aff042040..f0178d0bcb45 100644 --- a/frontend/src/app/features/invite-user-modal/summary/summary.component.html +++ b/frontend/src/app/features/invite-user-modal/summary/summary.component.html @@ -49,7 +49,7 @@ >{{ text.cancelButton }}
    diff --git a/frontend/src/app/features/projects/components/new-project/new-project.component.html b/frontend/src/app/features/projects/components/new-project/new-project.component.html index bea81db1c3f1..4667b5356b89 100644 --- a/frontend/src/app/features/projects/components/new-project/new-project.component.html +++ b/frontend/src/app/features/projects/components/new-project/new-project.component.html @@ -2,7 +2,7 @@ class="op-form" [formGroup]="templateForm" > -
    +
    +> \ No newline at end of file diff --git a/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.html b/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.html index 71dbfb6e4431..cb48a50aa6ff 100644 --- a/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.html +++ b/frontend/src/app/features/team-planner/team-planner/planner/team-planner.component.html @@ -132,7 +132,7 @@

    -
    -

    {{ text.dateAlerts.title }}

    -

    {{ text.dateAlerts.description }}

    -
    - +
    {{ text.dateAlerts.title }}
    +

    {{ text.dateAlerts.description }}

    {{ text.dateAlerts.title }} class="op-date-alert-ee-banner"> - -
    -

    {{ text.alsoNotifyFor.title }}

    -

    {{ text.alsoNotifyFor.description }}

    -
    +
    {{ text.alsoNotifyFor.title }}
    +

    {{ text.alsoNotifyFor.description }}

    {{ text.alsoNotifyFor.title }} -
    -

    {{ text.projectSpecific.title }}

    -

    {{text.projectSpecific.description}}

    -
    +
    {{text.projectSpecific.title}}
    +

    {{text.projectSpecific.description}}

    {{ text.projectSpecific.title }}
    diff --git a/frontend/src/app/features/user-preferences/reminder-settings/email-alerts/email-alerts-settings.component.html b/frontend/src/app/features/user-preferences/reminder-settings/email-alerts/email-alerts-settings.component.html index caaa1a8ad110..f926ab098162 100644 --- a/frontend/src/app/features/user-preferences/reminder-settings/email-alerts/email-alerts-settings.component.html +++ b/frontend/src/app/features/user-preferences/reminder-settings/email-alerts/email-alerts-settings.component.html @@ -1,6 +1,6 @@
    -

    +

    diff --git a/frontend/src/app/features/user-preferences/reminder-settings/immediate-reminders/immediate-reminder-settings.component.html b/frontend/src/app/features/user-preferences/reminder-settings/immediate-reminders/immediate-reminder-settings.component.html index 3e85891c967f..2a3e27b52702 100644 --- a/frontend/src/app/features/user-preferences/reminder-settings/immediate-reminders/immediate-reminder-settings.component.html +++ b/frontend/src/app/features/user-preferences/reminder-settings/immediate-reminders/immediate-reminder-settings.component.html @@ -1,6 +1,6 @@
    -

    +
    -
    -
    -

    -
    -
    +
    +

    diff --git a/frontend/src/app/features/user-preferences/reminder-settings/reminder-time/reminder-settings-daily-time.component.html b/frontend/src/app/features/user-preferences/reminder-settings/reminder-time/reminder-settings-daily-time.component.html index 09c5e01ec363..004bb22a40f9 100644 --- a/frontend/src/app/features/user-preferences/reminder-settings/reminder-time/reminder-settings-daily-time.component.html +++ b/frontend/src/app/features/user-preferences/reminder-settings/reminder-time/reminder-settings-daily-time.component.html @@ -3,7 +3,7 @@ [formGroup]="form" >
    -

    +

    diff --git a/frontend/src/app/features/user-preferences/reminder-settings/workdays/workdays-settings.component.html b/frontend/src/app/features/user-preferences/reminder-settings/workdays/workdays-settings.component.html index d3c7e83d6802..df021fed3e3c 100644 --- a/frontend/src/app/features/user-preferences/reminder-settings/workdays/workdays-settings.component.html +++ b/frontend/src/app/features/user-preferences/reminder-settings/workdays/workdays-settings.component.html @@ -1,6 +1,6 @@
    -

    +
    diff --git a/frontend/src/app/features/work-packages/components/wp-buttons/wp-create-button/wp-create-button.html b/frontend/src/app/features/work-packages/components/wp-buttons/wp-create-button/wp-create-button.html index 032e66fcd211..92e9128adee9 100644 --- a/frontend/src/app/features/work-packages/components/wp-buttons/wp-create-button/wp-create-button.html +++ b/frontend/src/app/features/work-packages/components/wp-buttons/wp-create-button/wp-create-button.html @@ -1,6 +1,6 @@
    diff --git a/frontend/src/app/shared/components/datepicker/multi-date-picker/multi-date-picker.component.html b/frontend/src/app/shared/components/datepicker/multi-date-picker/multi-date-picker.component.html index 94987fef9375..0d9bd508289b 100644 --- a/frontend/src/app/shared/components/datepicker/multi-date-picker/multi-date-picker.component.html +++ b/frontend/src/app/shared/components/datepicker/multi-date-picker/multi-date-picker.component.html @@ -90,7 +90,7 @@ > diff --git a/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass b/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass index d7415f67f4e0..a87dcd706e26 100644 --- a/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass +++ b/frontend/src/app/shared/components/datepicker/styles/datepicker.modal.sass @@ -42,7 +42,7 @@ // because that would overwrite the focus outline when the input field is focused. // So we make a border 2px wide like the outline, and then reduce margins by 1px so the // size of the element does not change. - border: 2px solid var(--control-checked-color) + border: 2px solid var(--primary-color) margin: -1px &--date-container diff --git a/frontend/src/app/shared/components/datepicker/wp-multi-date-form/wp-multi-date-form.component.html b/frontend/src/app/shared/components/datepicker/wp-multi-date-form/wp-multi-date-form.component.html index 90d1fb365405..491a504ef80e 100644 --- a/frontend/src/app/shared/components/datepicker/wp-multi-date-form/wp-multi-date-form.component.html +++ b/frontend/src/app/shared/components/datepicker/wp-multi-date-form/wp-multi-date-form.component.html @@ -122,7 +122,7 @@ > diff --git a/frontend/src/app/shared/components/datepicker/wp-single-date-form/wp-single-date-form.component.html b/frontend/src/app/shared/components/datepicker/wp-single-date-form/wp-single-date-form.component.html index dc89ece75d05..de5972287bd4 100644 --- a/frontend/src/app/shared/components/datepicker/wp-single-date-form/wp-single-date-form.component.html +++ b/frontend/src/app/shared/components/datepicker/wp-single-date-form/wp-single-date-form.component.html @@ -67,7 +67,7 @@ > diff --git a/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.html b/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.html index 7cadce036721..ae998d61ac01 100644 --- a/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.html +++ b/frontend/src/app/shared/components/dynamic-forms/components/dynamic-form/dynamic-form.component.html @@ -16,7 +16,7 @@
    diff --git a/frontend/src/app/shared/components/enterprise-banner/enterprise-banner.component.html b/frontend/src/app/shared/components/enterprise-banner/enterprise-banner.component.html index 8c1bd9d5d09d..ef4fb5bacae6 100644 --- a/frontend/src/app/shared/components/enterprise-banner/enterprise-banner.component.html +++ b/frontend/src/app/shared/components/enterprise-banner/enterprise-banner.component.html @@ -36,14 +36,14 @@ [attr.href]="moreInfoLink" class="op-enterprise-banner--info-button" target=”_blank”> - + {{ text.more_info_text }} + class="button -highlight"> {{ text.upgrade }} @@ -51,7 +51,7 @@ + class="button -alt-highlight"> {{ text.button_trial }} diff --git a/frontend/src/app/shared/components/enterprise-page/enterprise-page.component.html b/frontend/src/app/shared/components/enterprise-page/enterprise-page.component.html index a048cfbd9c2d..81e712042936 100644 --- a/frontend/src/app/shared/components/enterprise-page/enterprise-page.component.html +++ b/frontend/src/app/shared/components/enterprise-page/enterprise-page.component.html @@ -1,4 +1,4 @@ -

    {{feature_description}}

    @@ -43,9 +43,10 @@

    + class="button -highlight"> {{ text.upgrade }}
    + diff --git a/frontend/src/app/shared/components/forms/form.sass b/frontend/src/app/shared/components/forms/form.sass index b0d640fddf39..0fe2a4e1da8e 100644 --- a/frontend/src/app/shared/components/forms/form.sass +++ b/frontend/src/app/shared/components/forms/form.sass @@ -20,18 +20,11 @@ > .spot-form-field, > .spot-selector-field, > .op-option-list, - > .op-primaryed-input, + > .op-highlighted-input, > .button &:not(:last-child) margin-bottom: 1rem - &--section-header - margin-top: 0.5rem - - &--section-header-title - @extend %form--fieldset-legend-or-section-title - margin-bottom: 0.25rem - &--field .spot-form-field margin-bottom: 1rem diff --git a/frontend/src/app/shared/components/forms/highlighted-input.sass b/frontend/src/app/shared/components/forms/highlighted-input.sass index bfc976f06ed5..fcd4c090d692 100644 --- a/frontend/src/app/shared/components/forms/highlighted-input.sass +++ b/frontend/src/app/shared/components/forms/highlighted-input.sass @@ -1,4 +1,4 @@ -.op-primaryed-input +.op-highlighted-input padding: 1rem 1rem 0.5rem 0.75rem display: flex flex-direction: column @@ -9,3 +9,4 @@ &_active border: 1px solid #90cdf4 background: #ebf8ff + diff --git a/frontend/src/app/shared/components/grids/widgets/members/members.component.html b/frontend/src/app/shared/components/grids/widgets/members/members.component.html index d833dabb03e0..5ed0e202c1aa 100644 --- a/frontend/src/app/shared/components/grids/widgets/members/members.component.html +++ b/frontend/src/app/shared/components/grids/widgets/members/members.component.html @@ -42,7 +42,7 @@
  • - <%= submit_tag t(:button_apply), class: 'button -primary -small' %> + <%= submit_tag t(:button_apply), class: 'button -highlight -small' %> <%= link_to t(:button_clear), cost_types_path, class: 'button -small -with-icon icon-undo' %>
  • diff --git a/modules/costs/app/views/projects/settings/time_entry_activities/_activities.html.erb b/modules/costs/app/views/projects/settings/time_entry_activities/_activities.html.erb index 0ea208d5e1ab..ed21f553fe0d 100644 --- a/modules/costs/app/views/projects/settings/time_entry_activities/_activities.html.erb +++ b/modules/costs/app/views/projects/settings/time_entry_activities/_activities.html.erb @@ -45,5 +45,5 @@ See COPYRIGHT and LICENSE files for more details. <% end %>
    - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %>
    diff --git a/modules/costs/config/routes.rb b/modules/costs/config/routes.rb index 9d08fbd15055..56ccfe3e607e 100644 --- a/modules/costs/config/routes.rb +++ b/modules/costs/config/routes.rb @@ -27,29 +27,29 @@ #++ Rails.application.routes.draw do - scope "projects/:project_id", as: "projects" do - resources :cost_entries, controller: "costlog", only: %i[new create] + scope 'projects/:project_id', as: 'projects' do + resources :cost_entries, controller: 'costlog', only: %i[new create] resources :hourly_rates, only: %i[show edit update] do post :set_rate, on: :member end end - scope "my" do - get "/timer" => "my/timer#show", as: "my_timers" + scope 'my' do + get '/timer' => 'my/timer#show', as: 'my_timers' end - scope "projects/:project_id", as: "project", module: "projects" do - namespace "settings" do + scope 'projects/:project_id', as: 'project', module: 'projects' do + namespace 'settings' do resource :time_entry_activities, only: %i[show update] end end - scope "work_packages/:work_package_id", as: "work_packages" do - resources :cost_entries, controller: "costlog", only: %i[new] + scope 'work_packages/:work_package_id', as: 'work_packages' do + resources :cost_entries, controller: 'costlog', only: %i[new] end - resources :cost_entries, controller: "costlog", only: %i[edit update destroy] + resources :cost_entries, controller: 'costlog', only: %i[edit update destroy] resources :cost_types, only: %i[index new edit update create destroy] do member do diff --git a/modules/costs/costs.gemspec b/modules/costs/costs.gemspec index 575f70c8b374..4b7ca373eb00 100644 --- a/modules/costs/costs.gemspec +++ b/modules/costs/costs.gemspec @@ -1,13 +1,13 @@ # Describe your gem and declare its dependencies: Gem::Specification.new do |s| - s.name = "costs" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject Costs" - s.description = "This module adds features for planning and tracking costs of projects." - s.license = "GPLv3" + s.name = 'costs' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject Costs' + s.description = 'This module adds features for planning and tracking costs of projects.' + s.license = 'GPLv3' - s.files = Dir["{app,config,db,lib,doc}/**/*", "README.md"] - s.metadata["rubygems_mfa_required"] = "true" + s.files = Dir['{app,config,db,lib,doc}/**/*', 'README.md'] + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/costs/db/migrate/20180323133404_to_v710_aggregated_costs_migrations.rb b/modules/costs/db/migrate/20180323133404_to_v710_aggregated_costs_migrations.rb index cef387e17900..8202b775909d 100644 --- a/modules/costs/db/migrate/20180323133404_to_v710_aggregated_costs_migrations.rb +++ b/modules/costs/db/migrate/20180323133404_to_v710_aggregated_costs_migrations.rb @@ -43,75 +43,75 @@ class ToV710AggregatedCostsMigrations < ActiveRecord::Migration[5.1] def up Migration::MigrationSquasher.squash(migrations) do - create_table "cost_entries", id: :integer do |t| - t.integer "user_id", null: false - t.integer "project_id", null: false - t.integer "work_package_id", null: false - t.integer "cost_type_id", null: false - t.float "units", null: false - t.date "spent_on", null: false - t.datetime "created_on", null: false - t.datetime "updated_on", null: false - t.string "comments", null: false - t.boolean "blocked", default: false, null: false - t.decimal "overridden_costs", precision: 15, scale: 4 - t.decimal "costs", precision: 15, scale: 4 - t.integer "rate_id" - t.integer "tyear", null: false - t.integer "tmonth", null: false - t.integer "tweek", null: false + create_table 'cost_entries', id: :integer do |t| + t.integer 'user_id', null: false + t.integer 'project_id', null: false + t.integer 'work_package_id', null: false + t.integer 'cost_type_id', null: false + t.float 'units', null: false + t.date 'spent_on', null: false + t.datetime 'created_on', null: false + t.datetime 'updated_on', null: false + t.string 'comments', null: false + t.boolean 'blocked', default: false, null: false + t.decimal 'overridden_costs', precision: 15, scale: 4 + t.decimal 'costs', precision: 15, scale: 4 + t.integer 'rate_id' + t.integer 'tyear', null: false + t.integer 'tmonth', null: false + t.integer 'tweek', null: false end - create_table "cost_objects", id: :integer do |t| - t.integer "project_id", null: false - t.integer "author_id", null: false - t.string "subject", null: false - t.text "description", null: false - t.string "type", null: false - t.date "fixed_date", null: false - t.datetime "created_on" - t.datetime "updated_on" + create_table 'cost_objects', id: :integer do |t| + t.integer 'project_id', null: false + t.integer 'author_id', null: false + t.string 'subject', null: false + t.text 'description', null: false + t.string 'type', null: false + t.date 'fixed_date', null: false + t.datetime 'created_on' + t.datetime 'updated_on' end add_index :cost_objects, %i[project_id updated_on] - create_table "cost_types", id: :integer do |t| - t.string "name", null: false - t.string "unit", null: false - t.string "unit_plural", null: false - t.boolean "default", default: false, null: false - t.datetime "deleted_at" + create_table 'cost_types', id: :integer do |t| + t.string 'name', null: false + t.string 'unit', null: false + t.string 'unit_plural', null: false + t.boolean 'default', default: false, null: false + t.datetime 'deleted_at' end - create_table "labor_budget_items", id: :integer do |t| - t.integer "cost_object_id", null: false - t.float "hours", null: false - t.integer "user_id" - t.string "comments", default: "", null: false - t.decimal "budget", precision: 15, scale: 4 + create_table 'labor_budget_items', id: :integer do |t| + t.integer 'cost_object_id', null: false + t.float 'hours', null: false + t.integer 'user_id' + t.string 'comments', default: '', null: false + t.decimal 'budget', precision: 15, scale: 4 end - create_table "material_budget_items", id: :integer do |t| - t.integer "cost_object_id", null: false - t.float "units", null: false - t.integer "cost_type_id" - t.string "comments", default: "", null: false - t.decimal "budget", precision: 15, scale: 4 + create_table 'material_budget_items', id: :integer do |t| + t.integer 'cost_object_id', null: false + t.float 'units', null: false + t.integer 'cost_type_id' + t.string 'comments', default: '', null: false + t.decimal 'budget', precision: 15, scale: 4 end - create_table "rates", id: :integer do |t| - t.date "valid_from", null: false - t.decimal "rate", precision: 15, scale: 4, null: false - t.string "type", null: false - t.integer "project_id" - t.integer "user_id" - t.integer "cost_type_id" + create_table 'rates', id: :integer do |t| + t.date 'valid_from', null: false + t.decimal 'rate', precision: 15, scale: 4, null: false + t.string 'type', null: false + t.integer 'project_id' + t.integer 'user_id' + t.integer 'cost_type_id' end - change_table "time_entries", id: :integer do |t| - t.decimal "overridden_costs", precision: 15, scale: 4 - t.decimal "costs", precision: 15, scale: 4 - t.integer "rate_id" + change_table 'time_entries', id: :integer do |t| + t.decimal 'overridden_costs', precision: 15, scale: 4 + t.decimal 'costs', precision: 15, scale: 4 + t.integer 'rate_id' end create_table :cost_object_journals, id: :integer do |t| @@ -136,18 +136,18 @@ def up end def down - drop_table "cost_entries" - drop_table "cost_objects" - drop_table "cost_types" - drop_table "labor_budget_items" - drop_table "material_budget_items" - drop_table "rates" - drop_table "cost_object_journals" - - change_table "time_entries" do |t| - t.remove_column "overridden_costs" - t.remove_column "costs" - t.remove_column "rate_id" + drop_table 'cost_entries' + drop_table 'cost_objects' + drop_table 'cost_types' + drop_table 'labor_budget_items' + drop_table 'material_budget_items' + drop_table 'rates' + drop_table 'cost_object_journals' + + change_table 'time_entries' do |t| + t.remove_column 'overridden_costs' + t.remove_column 'costs' + t.remove_column 'rate_id' end remove_column :work_packages, :cost_object_id @@ -162,7 +162,7 @@ def down def migrations MIGRATION_FILES.split.map do |m| - m.gsub(/_.*\z/, "") + m.gsub(/_.*\z/, '') end end end diff --git a/modules/costs/db/migrate/20200327074416_rename_fixed_version_in_cost_query.rb b/modules/costs/db/migrate/20200327074416_rename_fixed_version_in_cost_query.rb index ac85b07e689c..7951ed074c0f 100644 --- a/modules/costs/db/migrate/20200327074416_rename_fixed_version_in_cost_query.rb +++ b/modules/costs/db/migrate/20200327074416_rename_fixed_version_in_cost_query.rb @@ -28,11 +28,11 @@ class RenameFixedVersionInCostQuery < ActiveRecord::Migration[6.0] def up - rename_query_attributes("FixedVersion", "Version") + rename_query_attributes('FixedVersion', 'Version') end def down - rename_query_attributes("Version", "FixedVersion") + rename_query_attributes('Version', 'FixedVersion') end def rename_query_attributes(from, to) diff --git a/modules/costs/db/migrate/20200807083952_rename_time_and_cost_module.rb b/modules/costs/db/migrate/20200807083952_rename_time_and_cost_module.rb index e4f9a6e9a555..d5dbfea4dbec 100644 --- a/modules/costs/db/migrate/20200807083952_rename_time_and_cost_module.rb +++ b/modules/costs/db/migrate/20200807083952_rename_time_and_cost_module.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require Rails.root.to_s + "/db/migrate/migration_utils/module_renamer" -require Rails.root.to_s + "/db/migrate/migration_utils/setting_renamer" +require Rails.root.to_s + '/db/migrate/migration_utils/module_renamer' +require Rails.root.to_s + '/db/migrate/migration_utils/setting_renamer' class RenameTimeAndCostModule < ActiveRecord::Migration[6.0] def up - module_renamer.add_to_enabled("costs", %w[time_tracking costs_module reporting_module]) + module_renamer.add_to_enabled('costs', %w[time_tracking costs_module reporting_module]) module_renamer.remove_from_enabled(%w[time_tracking costs_module reporting_module]) - module_renamer.add_to_default("costs", %w[time_tracking costs_module reporting_module]) - setting_renamer.rename("plugin_costs", "plugin_costs") + module_renamer.add_to_default('costs', %w[time_tracking costs_module reporting_module]) + setting_renamer.rename('plugin_costs', 'plugin_costs') end def down # We do not know if all three where actually enabled but having them enabled will keep the functionality - module_renamer.add_to_enabled("time_tracking", "costs") - module_renamer.add_to_enabled("costs_module", "costs") - module_renamer.add_to_enabled("reporting_module", "costs") + module_renamer.add_to_enabled('time_tracking', 'costs') + module_renamer.add_to_enabled('costs_module', 'costs') + module_renamer.add_to_enabled('reporting_module', 'costs') - module_renamer.remove_from_enabled("costs") - module_renamer.add_to_default(%w[costs_module time_tracking reporting_module], "costs") - setting_renamer.rename("plugin_costs", "plugin_costs") + module_renamer.remove_from_enabled('costs') + module_renamer.add_to_default(%w[costs_module time_tracking reporting_module], 'costs') + setting_renamer.rename('plugin_costs', 'plugin_costs') end def module_renamer diff --git a/modules/costs/db/migrate/20210726065912_rename_cost_object_type.rb b/modules/costs/db/migrate/20210726065912_rename_cost_object_type.rb index e2b050aac8d7..9942367ff0a8 100644 --- a/modules/costs/db/migrate/20210726065912_rename_cost_object_type.rb +++ b/modules/costs/db/migrate/20210726065912_rename_cost_object_type.rb @@ -54,8 +54,8 @@ def up add_index :journals, %i[journable_type journable_id version], unique: true Journal - .where(journable_type: "CostObject") - .update_all(journable_type: "Budget") + .where(journable_type: 'CostObject') + .update_all(journable_type: 'Budget') end def down diff --git a/modules/costs/db/migrate/20230622074222_add_ongoing_to_time_entry.rb b/modules/costs/db/migrate/20230622074222_add_ongoing_to_time_entry.rb index 58f0515fe525..e10bb63438a9 100644 --- a/modules/costs/db/migrate/20230622074222_add_ongoing_to_time_entry.rb +++ b/modules/costs/db/migrate/20230622074222_add_ongoing_to_time_entry.rb @@ -4,7 +4,7 @@ def change t.boolean :ongoing, null: false, default: false, index: true end - add_index :time_entries, %i[user_id ongoing], unique: true, where: "ongoing = true" + add_index :time_entries, %i[user_id ongoing], unique: true, where: 'ongoing = true' change_column_null :time_entries, :activity_id, true change_column_null :time_entries, :hours, true diff --git a/modules/costs/lib/api/v3/cost_entries/aggregated_cost_entry_representer.rb b/modules/costs/lib/api/v3/cost_entries/aggregated_cost_entry_representer.rb index 17aab34ab110..ccba7dcb4ad3 100644 --- a/modules/costs/lib/api/v3/cost_entries/aggregated_cost_entry_representer.rb +++ b/modules/costs/lib/api/v3/cost_entries/aggregated_cost_entry_representer.rb @@ -70,7 +70,7 @@ def initialize(cost_type, units) end def _type - "AggregatedCostEntry" + 'AggregatedCostEntry' end def model_required? diff --git a/modules/costs/lib/api/v3/cost_entries/cost_entries_api.rb b/modules/costs/lib/api/v3/cost_entries/cost_entries_api.rb index 45a270518de2..60a1b7947032 100644 --- a/modules/costs/lib/api/v3/cost_entries/cost_entries_api.rb +++ b/modules/costs/lib/api/v3/cost_entries/cost_entries_api.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "api/v3/cost_types/cost_type_representer" +require 'api/v3/cost_types/cost_type_representer' module API module V3 module CostEntries class CostEntriesAPI < ::API::OpenProjectAPI resources :cost_entries do - route_param :id, type: Integer, desc: "Cost entry ID" do + route_param :id, type: Integer, desc: 'Cost entry ID' do after_validation do @cost_entry = CostEntry.find(params[:id]) diff --git a/modules/costs/lib/api/v3/cost_entries/cost_entries_by_work_package_api.rb b/modules/costs/lib/api/v3/cost_entries/cost_entries_by_work_package_api.rb index 2bec6bbe4721..bebfd695734a 100644 --- a/modules/costs/lib/api/v3/cost_entries/cost_entries_by_work_package_api.rb +++ b/modules/costs/lib/api/v3/cost_entries/cost_entries_by_work_package_api.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "api/v3/cost_types/cost_type_representer" +require 'api/v3/cost_types/cost_type_representer' module API module V3 diff --git a/modules/costs/lib/api/v3/cost_entries/cost_entry_representer.rb b/modules/costs/lib/api/v3/cost_entries/cost_entry_representer.rb index 31c496884894..0780180f09b1 100644 --- a/modules/costs/lib/api/v3/cost_entries/cost_entry_representer.rb +++ b/modules/costs/lib/api/v3/cost_entries/cost_entry_representer.rb @@ -52,7 +52,7 @@ class CostEntryRepresenter < ::API::Decorators::Single date_time_property :updated_at def _type - "CostEntry" + 'CostEntry' end end end diff --git a/modules/costs/lib/api/v3/cost_entries/work_package_costs_by_type_representer.rb b/modules/costs/lib/api/v3/cost_entries/work_package_costs_by_type_representer.rb index a2a33877faca..0acdbaba79e7 100644 --- a/modules/costs/lib/api/v3/cost_entries/work_package_costs_by_type_representer.rb +++ b/modules/costs/lib/api/v3/cost_entries/work_package_costs_by_type_representer.rb @@ -60,7 +60,7 @@ def cost_helper end def _type - "Collection" + 'Collection' end end end diff --git a/modules/costs/lib/api/v3/cost_types/cost_type_representer.rb b/modules/costs/lib/api/v3/cost_types/cost_type_representer.rb index 872fb1fcb400..7e55321621a2 100644 --- a/modules/costs/lib/api/v3/cost_types/cost_type_representer.rb +++ b/modules/costs/lib/api/v3/cost_types/cost_type_representer.rb @@ -41,7 +41,7 @@ class CostTypeRepresenter < ::API::Decorators::Single getter: ->(*) { default } def _type - "CostType" + 'CostType' end end end diff --git a/modules/costs/lib/api/v3/cost_types/cost_types_api.rb b/modules/costs/lib/api/v3/cost_types/cost_types_api.rb index ba35ef93294f..52f66ea1193a 100644 --- a/modules/costs/lib/api/v3/cost_types/cost_types_api.rb +++ b/modules/costs/lib/api/v3/cost_types/cost_types_api.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "api/v3/cost_types/cost_type_representer" +require 'api/v3/cost_types/cost_type_representer' module API module V3 @@ -37,7 +37,7 @@ class CostTypesAPI < ::API::OpenProjectAPI authorize_in_any_project(%i[view_cost_entries view_own_cost_entries]) end - route_param :id, type: Integer, desc: "Cost type ID" do + route_param :id, type: Integer, desc: 'Cost type ID' do after_validation do @cost_type = CostType.active.find(params[:id]) end diff --git a/modules/costs/lib/api/v3/time_entries/schemas/time_entry_schema_representer.rb b/modules/costs/lib/api/v3/time_entries/schemas/time_entry_schema_representer.rb index b07119fb7ca8..c81a30aefc92 100644 --- a/modules/costs/lib/api/v3/time_entries/schemas/time_entry_schema_representer.rb +++ b/modules/costs/lib/api/v3/time_entries/schemas/time_entry_schema_representer.rb @@ -39,26 +39,26 @@ def self.represented_class end schema :id, - type: "Integer" + type: 'Integer' schema :created_at, - type: "DateTime" + type: 'DateTime' schema :updated_at, - type: "DateTime" + type: 'DateTime' schema :spent_on, - type: "Date" + type: 'Date' schema :hours, - type: "Duration" + type: 'Duration' schema :comment, - type: "Formattable", + type: 'Formattable', required: false schema :ongoing, - type: "Boolean", + type: 'Boolean', required: false schema_with_allowed_link :user, @@ -83,7 +83,7 @@ def self.represented_class } schema_with_allowed_collection :activity, - type: "TimeEntriesActivity", + type: 'TimeEntriesActivity', value_representer: TimeEntriesActivityRepresenter, has_default: true, required: false, @@ -109,9 +109,9 @@ def allowed_projects_href def allowed_user_href api_v3_paths.path_for :principals, filters: [ - { status: { operator: "!", values: [Principal.statuses[:locked].to_s] } }, - { type: { operator: "=", values: ["User"] } }, - { member: { operator: "=", values: [represented.project_id] } } + { status: { operator: '!', values: [Principal.statuses[:locked].to_s] } }, + { type: { operator: '=', values: ['User'] } }, + { member: { operator: '=', values: [represented.project_id] } } ] end end diff --git a/modules/costs/lib/api/v3/time_entries/time_entries_activity_api.rb b/modules/costs/lib/api/v3/time_entries/time_entries_activity_api.rb index 93874fcca13b..bd50eab1b458 100644 --- a/modules/costs/lib/api/v3/time_entries/time_entries_activity_api.rb +++ b/modules/costs/lib/api/v3/time_entries/time_entries_activity_api.rb @@ -31,7 +31,7 @@ module V3 module TimeEntries class TimeEntriesActivityAPI < ::API::OpenProjectAPI resources :activities do - route_param :id, type: Integer, desc: "Time entry activity ID" do + route_param :id, type: Integer, desc: 'Time entry activity ID' do after_validation do authorize_in_any_work_package(:edit_own_time_entries) do authorize_in_any_project(%i(log_time diff --git a/modules/costs/lib/api/v3/time_entries/time_entries_activity_representer.rb b/modules/costs/lib/api/v3/time_entries/time_entries_activity_representer.rb index 9a90c9aaf474..39ec03c97d2a 100644 --- a/modules/costs/lib/api/v3/time_entries/time_entries_activity_representer.rb +++ b/modules/costs/lib/api/v3/time_entries/time_entries_activity_representer.rb @@ -59,7 +59,7 @@ class TimeEntriesActivityRepresenter < ::API::Decorators::Single } def _type - "TimeEntriesActivity" + 'TimeEntriesActivity' end def active_projects diff --git a/modules/costs/lib/api/v3/time_entries/time_entries_api.rb b/modules/costs/lib/api/v3/time_entries/time_entries_api.rb index 052dd537aefa..78ac7ade8588 100644 --- a/modules/costs/lib/api/v3/time_entries/time_entries_api.rb +++ b/modules/costs/lib/api/v3/time_entries/time_entries_api.rb @@ -43,7 +43,7 @@ class TimeEntriesAPI < ::API::OpenProjectAPI mount ::API::V3::TimeEntries::AvailableProjectsAPI mount ::API::V3::TimeEntries::AvailableWorkPackagesOnCreateAPI - route_param :id, type: Integer, desc: "Time entry ID" do + route_param :id, type: Integer, desc: 'Time entry ID' do after_validation do @time_entry = TimeEntry .visible diff --git a/modules/costs/lib/api/v3/time_entries/time_entry_representer.rb b/modules/costs/lib/api/v3/time_entries/time_entry_representer.rb index d9905964ead6..6dbf73a083fb 100644 --- a/modules/costs/lib/api/v3/time_entries/time_entry_representer.rb +++ b/modules/costs/lib/api/v3/time_entries/time_entry_representer.rb @@ -106,14 +106,14 @@ class TimeEntryRepresenter < ::API::Decorators::Single .new(represented, path: :time_entries_activity, property_name: :time_entries_activity, - namespace: "time_entries/activities", + namespace: 'time_entries/activities', getter: :activity_id, - setter: :"activity_id=") + setter: :'activity_id=') .from_hash(fragment) } def _type - "TimeEntry" + 'TimeEntry' end def update_allowed? @@ -125,7 +125,7 @@ def update_allowed? def hours=(value) represented.hours = datetime_formatter.parse_duration_to_hours(value, - "hours", + 'hours', allow_nil: true) end diff --git a/modules/costs/lib/costs.rb b/modules/costs/lib/costs.rb index cc281d9a4122..f9d947f3ee4c 100644 --- a/modules/costs/lib/costs.rb +++ b/modules/costs/lib/costs.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "costs/engine" +require 'costs/engine' diff --git a/modules/costs/lib/costs/engine.rb b/modules/costs/lib/costs/engine.rb index ef47fec7638d..a2aa49a45b7f 100644 --- a/modules/costs/lib/costs/engine.rb +++ b/modules/costs/lib/costs/engine.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/plugins" +require 'open_project/plugins' module Costs class Engine < ::Rails::Engine @@ -34,12 +34,12 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "costs", - author_url: "https://www.openproject.org", + register 'costs', + author_url: 'https://www.openproject.org', bundled: true, settings: { - default: { "costs_currency" => "EUR", "costs_currency_format" => "%n %u" }, - partial: "settings/costs", + default: { 'costs_currency' => 'EUR', 'costs_currency_format' => '%n %u' }, + partial: 'settings/costs', menu_item: :costs_setting } do project_module :costs do @@ -73,7 +73,7 @@ class Engine < ::Rails::Engine require: :member permission :manage_project_activities, - { "projects/settings/time_entry_activities": %i[show update] }, + { 'projects/settings/time_entry_activities': %i[show update] }, permissible_on: :project, require: :member @@ -122,21 +122,21 @@ class Engine < ::Rails::Engine # Menu extensions menu :admin_menu, :cost_types, - { controller: "/cost_types", action: "index" }, + { controller: '/cost_types', action: 'index' }, if: ->(*) { User.current.admin? }, parent: :admin_costs, caption: :label_cost_type_plural end - activity_provider :time_entries, class_name: "Activities::TimeEntryActivityProvider", default: false + activity_provider :time_entries, class_name: 'Activities::TimeEntryActivityProvider', default: false patches %i[Project User PermittedParams] patch_with_namespace :BasicData, :SettingSeeder patch_with_namespace :ActiveSupport, :NumberHelper, :NumberToCurrencyConverter add_tab_entry :user, - name: "rates", - partial: "users/rates", + name: 'rates', + partial: 'users/rates', path: ->(params) { edit_user_path(params[:user], tab: :rates) }, only_if: ->(*) { User.current.admin? }, label: :caption_rate_history @@ -157,13 +157,13 @@ class Engine < ::Rails::Engine "#{root}/cost_types/#{id}" end - add_api_endpoint "API::V3::Root" do + add_api_endpoint 'API::V3::Root' do mount ::API::V3::CostEntries::CostEntriesAPI mount ::API::V3::CostTypes::CostTypesAPI mount ::API::V3::TimeEntries::TimeEntriesAPI end - add_api_endpoint "API::V3::WorkPackages::WorkPackagesAPI", :id do + add_api_endpoint 'API::V3::WorkPackages::WorkPackagesAPI', :id do mount ::API::V3::CostEntries::CostEntriesByWorkPackageAPI end @@ -181,7 +181,7 @@ class Engine < ::Rails::Engine { href: new_work_packages_cost_entry_path(represented), - type: "text/html", + type: 'text/html', title: "Log costs on #{represented.subject}" } end @@ -195,11 +195,11 @@ class Engine < ::Rails::Engine { href: cost_reports_path(represented.project_id, - "fields[]": "WorkPackageId", - "operators[WorkPackageId]": "=", - "values[WorkPackageId]": represented.id, + 'fields[]': 'WorkPackageId', + 'operators[WorkPackageId]': '=', + 'values[WorkPackageId]': represented.id, set_filter: 1), - type: "text/html", + type: 'text/html', title: "Show cost entries" } end @@ -256,25 +256,25 @@ class Engine < ::Rails::Engine # N.B. in the long term we should have a type like "Currency", but that requires a proper # format and not a string like "10 EUR" schema :overall_costs, - type: "String", + type: 'String', required: false, writable: false, show_if: ->(*) { represented.project && represented.project.costs_enabled? } schema :labor_costs, - type: "String", + type: 'String', required: false, writable: false, show_if: ->(*) { represented.project && represented.project.costs_enabled? } schema :material_costs, - type: "String", + type: 'String', required: false, writable: false, show_if: ->(*) { represented.project && represented.project.costs_enabled? } schema :costs_by_type, - type: "Collection", + type: 'Collection', name_source: :spent_units, required: false, show_if: ->(*) { represented.project && represented.project.costs_enabled? }, @@ -282,7 +282,7 @@ class Engine < ::Rails::Engine end config.to_prepare do - OpenProject::ProjectLatestActivity.register on: "TimeEntry" + OpenProject::ProjectLatestActivity.register on: 'TimeEntry' Costs::Patches::MembersPatch.mixin! diff --git a/modules/costs/lib/costs/patches/members_patch.rb b/modules/costs/lib/costs/patches/members_patch.rb index 4eaef561ed03..9bc1aca8a33e 100644 --- a/modules/costs/lib/costs/patches/members_patch.rb +++ b/modules/costs/lib/costs/patches/members_patch.rb @@ -45,7 +45,7 @@ def members_table_options(_roles) module TableComponent def sort_collection(query, sort_clause, sort_columns) - q = super(query, sort_clause.gsub("current_rate", "COALESCE(rate, 0.0)"), sort_columns) + q = super(query, sort_clause.gsub("current_rate", 'COALESCE(rate, 0.0)'), sort_columns) if sort_columns.include? :current_rate join_rate q diff --git a/modules/costs/lib/costs/patches/number_to_currency_converter_patch.rb b/modules/costs/lib/costs/patches/number_to_currency_converter_patch.rb index 152e28c9072b..320d253298b9 100644 --- a/modules/costs/lib/costs/patches/number_to_currency_converter_patch.rb +++ b/modules/costs/lib/costs/patches/number_to_currency_converter_patch.rb @@ -33,8 +33,8 @@ def self.included(base) # :nodoc: module InstanceMethods def i18n_opts - super.merge(unit: ERB::Util.h(Setting.plugin_costs["costs_currency"]), - format: ERB::Util.h(Setting.plugin_costs["costs_currency_format"])) + super.merge(unit: ERB::Util.h(Setting.plugin_costs['costs_currency']), + format: ERB::Util.h(Setting.plugin_costs['costs_currency_format'])) end end end diff --git a/modules/costs/lib/costs/patches/project_patch.rb b/modules/costs/lib/costs/patches/project_patch.rb index ae29606f9b6f..971d7472b5f6 100644 --- a/modules/costs/lib/costs/patches/project_patch.rb +++ b/modules/costs/lib/costs/patches/project_patch.rb @@ -32,12 +32,12 @@ def self.included(base) # :nodoc: base.include(InstanceMethods) base.class_eval do - has_many :rates, class_name: "HourlyRate" + has_many :rates, class_name: 'HourlyRate' has_many :member_groups, -> { includes(:principal) .where("#{Principal.table_name}.type='Group'") - }, class_name: "Member" + }, class_name: 'Member' has_many :groups, through: :member_groups, source: :principal end end diff --git a/modules/costs/lib/costs/patches/setting_seeder_patch.rb b/modules/costs/lib/costs/patches/setting_seeder_patch.rb index fe6935d4b470..bd0f29a5f59d 100644 --- a/modules/costs/lib/costs/patches/setting_seeder_patch.rb +++ b/modules/costs/lib/costs/patches/setting_seeder_patch.rb @@ -35,8 +35,8 @@ module InstanceMethods def data original_data = super - unless original_data["default_projects_modules"].include? "costs" - original_data["default_projects_modules"] << "costs" + unless original_data['default_projects_modules'].include? 'costs' + original_data['default_projects_modules'] << 'costs' end original_data diff --git a/modules/costs/lib/costs/patches/user_patch.rb b/modules/costs/lib/costs/patches/user_patch.rb index 75f53eff7778..490ff6e270f0 100644 --- a/modules/costs/lib/costs/patches/user_patch.rb +++ b/modules/costs/lib/costs/patches/user_patch.rb @@ -31,8 +31,8 @@ def self.included(base) # :nodoc: base.send(:include, InstanceMethods) base.class_eval do - has_many :rates, class_name: "HourlyRate" - has_many :default_rates, class_name: "DefaultHourlyRate" + has_many :rates, class_name: 'HourlyRate' + has_many :default_rates, class_name: 'DefaultHourlyRate' before_save :save_rates end @@ -45,7 +45,7 @@ def allowed_to_condition_with_project_id(permission, projects = nil) ids = scope.pluck(:id) - ids.empty? ? "1=0" : "(#{Project.table_name}.id in (#{ids.join(', ')}))" + ids.empty? ? '1=0' : "(#{Project.table_name}.id in (#{ids.join(', ')}))" end def current_rate(project = nil, include_default = true) diff --git a/modules/costs/spec/contracts/time_entries/create_contract_spec.rb b/modules/costs/spec/contracts/time_entries/create_contract_spec.rb index 9048a5ab621d..3e9bf25bb55b 100644 --- a/modules/costs/spec/contracts/time_entries/create_contract_spec.rb +++ b/modules/costs/spec/contracts/time_entries/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe TimeEntries::CreateContract do - it_behaves_like "time entry contract" do + it_behaves_like 'time entry contract' do subject(:contract) do described_class.new(time_entry, current_user) end @@ -59,41 +59,41 @@ end end - context "if user is not allowed to log time" do + context 'if user is not allowed to log time' do let(:permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "when ongoing and different user" do + context 'when ongoing and different user' do let(:time_entry_user) { other_user } let(:time_entry_ongoing) { true } - it "is invalid" do + it 'is invalid' do expect_valid(false, ongoing: %i(not_current_user)) end end - context "if user has only permission to log own time" do + context 'if user has only permission to log own time' do let(:permissions) { %i[log_own_time] } - it "is valid" do + it 'is valid' do expect_valid(true) end - context "when trying to log for other user" do + context 'when trying to log for other user' do let(:time_entry_user) { build_stubbed(:user) } let(:changed_by_system) { {} } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end end - context "if time_entry user is not contract user" do + context 'if time_entry user is not contract user' do let(:other_user) { build_stubbed(:user) } let(:permissions) { [] } let(:time_entry_user) { other_user } @@ -104,12 +104,12 @@ end end - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if time_entry user was not set by system" do + context 'if time_entry user was not set by system' do let(:other_user) { build_stubbed(:user) } let(:time_entry_user) { other_user } let(:permissions) { [] } @@ -121,15 +121,15 @@ end end - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if the user is nil" do + context 'if the user is nil' do let(:time_entry_user) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, user_id: %i(blank)) end end diff --git a/modules/costs/spec/contracts/time_entries/delete_contract_spec.rb b/modules/costs/spec/contracts/time_entries/delete_contract_spec.rb index 16db88b65545..a4d979ba1167 100644 --- a/modules/costs/spec/contracts/time_entries/delete_contract_spec.rb +++ b/modules/costs/spec/contracts/time_entries/delete_contract_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntries::DeleteContract do let(:current_user) { build_stubbed(:user) } @@ -74,53 +74,53 @@ def expect_valid(valid, symbols = {}) end end - shared_examples "is valid" do - it "is valid" do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' - context "when user is not allowed to delete time entries" do + context 'when user is not allowed to delete time entries' do let(:permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "when time entry ongoing and user as log_time permission" do + context 'when time entry ongoing and user as log_time permission' do let(:time_entry_ongoing) { true } let(:permissions) { %i[log_own_time] } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when time entry not ongoing and user as log_time permission" do + context 'when time entry not ongoing and user as log_time permission' do let(:time_entry_ongoing) { false } let(:permissions) { %i[log_own_time] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "when time_entry user is not contract user" do + context 'when time_entry user is not contract user' do let(:time_entry_user) { other_user } - context "when has permission" do + context 'when has permission' do let(:permissions) { %i[edit_time_entries] } - it "is valid" do + it 'is valid' do expect_valid(true) end end - context "when has no permission" do + context 'when has no permission' do let(:permissions) { %i[edit_own_time_entries] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end diff --git a/modules/costs/spec/contracts/time_entries/shared_contract_examples.rb b/modules/costs/spec/contracts/time_entries/shared_contract_examples.rb index 8e62c50072ce..b1ea2d681cc0 100644 --- a/modules/costs/spec/contracts/time_entries/shared_contract_examples.rb +++ b/modules/costs/spec/contracts/time_entries/shared_contract_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "time entry contract" do +RSpec.shared_examples_for 'time entry contract' do let(:current_user) { build_stubbed(:user) } before do mock_permissions_for(current_user) do |mock| @@ -107,139 +107,139 @@ def expect_valid(valid, symbols = {}) end end - shared_examples "is valid" do - it "is valid" do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' - context "when the work_package is within a different project than the provided project" do + context 'when the work_package is within a different project than the provided project' do let(:time_entry_work_package) { build_stubbed(:work_package) } - it "is invalid" do + it 'is invalid' do expect_valid(false, work_package_id: %i(invalid)) end end - context "when the work_package is nil" do + context 'when the work_package is nil' do let(:time_entry_work_package) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the project is nil" do + context 'when the project is nil' do let(:time_entry_project) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, project_id: %i(invalid blank)) end end - context "when activity is nil" do + context 'when activity is nil' do let(:time_entry_activity) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the activity is disabled in the project" do + context 'if the activity is disabled in the project' do let(:time_entry_activity_active) { false } - it "is invalid" do + it 'is invalid' do expect_valid(false, activity_id: %i(inclusion)) end end - context "when spent_on is nil" do + context 'when spent_on is nil' do let(:time_entry_spent_on) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, spent_on: %i(blank)) end end - context "when spent_on is outside the year limits to prevent overflow in postgres" do + context 'when spent_on is outside the year limits to prevent overflow in postgres' do let(:time_entry_spent_on) { Date.new(10000) } - it "is invalid" do + it 'is invalid' do expect_valid(false, spent_on: %i(date_before_or_equal_to)) end end - context "when spent_on is in the future" do + context 'when spent_on is in the future' do let(:time_entry_spent_on) { Date.new(9999) } - it "is valid" do + it 'is valid' do expect_valid(true) end end - context "when spent_on is today" do + context 'when spent_on is today' do let(:time_entry_spent_on) { Time.zone.today } - it "is valid" do + it 'is valid' do expect_valid(true) end end - context "when spent_on is in the past" do + context 'when spent_on is in the past' do let(:time_entry_spent_on) { Time.zone.yesterday } - it "is valid" do + it 'is valid' do expect_valid(true) end end - context "when hours is nil" do + context 'when hours is nil' do let(:time_entry_hours) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, hours: %i(blank)) end end - context "when hours is negative" do + context 'when hours is negative' do let(:time_entry_hours) { -1 } - it "is invalid" do + it 'is invalid' do expect_valid(false, hours: %i(invalid)) end end - context "when comment is nil" do + context 'when comment is nil' do let(:time_entry_comments) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if more than 24 hours are booked for a day" do + context 'if more than 24 hours are booked for a day' do let(:time_entry_day_sum) { 24 - time_entry_hours + 1 } - it "is valid" do + it 'is valid' do expect_valid(true) end end - describe "assignable_activities" do - context "if no project is set" do + describe 'assignable_activities' do + context 'if no project is set' do let(:time_entry_project) { nil } - it "is empty" do + it 'is empty' do expect(contract.assignable_activities) .to be_empty end end - context "if a project is set" do - it "returns all activities active in the project" do + context 'if a project is set' do + it 'returns all activities active in the project' do expect(contract.assignable_activities) .to eql activities_scope end end end - describe "assignable_versions" do + describe 'assignable_versions' do let(:project_versions) { [instance_double(Version)] } let(:wp_versions) { [instance_double(Version)] } @@ -257,36 +257,36 @@ def expect_valid(valid, symbols = {}) end end - context "if no project and no work package is set" do + context 'if no project and no work package is set' do let(:time_entry_project) { nil } let(:time_entry_work_package) { nil } - it "is empty" do + it 'is empty' do expect(contract.assignable_versions) .to be_empty end end - context "if a project is set but no work package" do + context 'if a project is set but no work package' do let(:time_entry_work_package) { nil } - it "returns assignable_versions of the project" do + it 'returns assignable_versions of the project' do expect(contract.assignable_versions) .to eql project_versions end end - context "if a work_package is set but no project" do + context 'if a work_package is set but no project' do let(:time_entry_project) { nil } - it "returns assignable_versions of the project" do + it 'returns assignable_versions of the project' do expect(contract.assignable_versions) .to eql wp_versions end end - context "if both project and work_package are set" do - it "returns assignable_versions of the project" do + context 'if both project and work_package are set' do + it 'returns assignable_versions of the project' do expect(contract.assignable_versions) .to eql wp_versions end diff --git a/modules/costs/spec/contracts/time_entries/update_contract_spec.rb b/modules/costs/spec/contracts/time_entries/update_contract_spec.rb index 8996b418c987..bd25b934b069 100644 --- a/modules/costs/spec/contracts/time_entries/update_contract_spec.rb +++ b/modules/costs/spec/contracts/time_entries/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe TimeEntries::UpdateContract do - it_behaves_like "time entry contract" do + it_behaves_like 'time entry contract' do let(:time_entry) do build_stubbed(:time_entry, project: time_entry_project, @@ -45,15 +45,15 @@ let(:permissions) { %i(edit_time_entries) } - context "if user is not allowed to edit time entries" do + context 'if user is not allowed to edit time entries' do let(:permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if project changed" do + context 'if project changed' do let(:new_project) do build_stubbed(:project) do |new_project| allow(TimeEntryActivity) @@ -84,64 +84,64 @@ time_entry.project = new_project end - context "if user is not allowed to edit time entries in old project but in new" do + context 'if user is not allowed to edit time entries in old project but in new' do let(:permissions) { [] } let(:new_project_permissions) { %i(edit_time_entries) } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if user is allowed to edit time entries in old project but not in new" do + context 'if user is allowed to edit time entries in old project but not in new' do let(:new_project_permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if user is allowed to edit time entries in both projects" do + context 'if user is allowed to edit time entries in both projects' do let(:new_project_permissions) { %i(edit_time_entries) } - it "is valid" do + it 'is valid' do expect_valid(true) end end end - context "if the user is nil" do + context 'if the user is nil' do let(:time_entry_user) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, user_id: %i(blank)) end end - context "if the user is changed" do + context 'if the user is changed' do let(:permissions) { %i(edit_own_time_entries) } - it "is invalid" do + it 'is invalid' do time_entry.user = other_user expect_valid(false, base: %i(error_unauthorized)) end end - context "if time_entry user is not contract user" do + context 'if time_entry user is not contract user' do let(:time_entry_user) { other_user } - context "if has permission" do + context 'if has permission' do let(:permissions) { %i[edit_time_entries] } - it "is valid" do + it 'is valid' do expect_valid(true) end end - context "if has no permission" do + context 'if has no permission' do let(:permissions) { %i[edit_own_time_entries] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end diff --git a/modules/costs/spec/controllers/cost_types_controller_spec.rb b/modules/costs/spec/controllers/cost_types_controller_spec.rb index 10e1de3f769d..70e613e0883d 100644 --- a/modules/costs/spec/controllers/cost_types_controller_spec.rb +++ b/modules/costs/spec/controllers/cost_types_controller_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') RSpec.describe CostTypesController do let(:admin) { create(:admin) } let(:cost_type) { create(:cost_type) } - describe "DELETE destroy" do - it "allows an admin to delete" do + describe 'DELETE destroy' do + it 'allows an admin to delete' do as_logged_in_user admin do delete :destroy, params: { id: cost_type.id } end @@ -44,12 +44,12 @@ end end - describe "PATCH restore" do + describe 'PATCH restore' do before do cost_type.deleted_at = DateTime.now end - it "allows an admin to restore" do + it 'allows an admin to restore' do as_logged_in_user admin do patch :restore, params: { id: cost_type.id } end diff --git a/modules/costs/spec/controllers/costlog_controller_spec.rb b/modules/costs/spec/controllers/costlog_controller_spec.rb index 7f0782dae5d7..c108e8a6d913 100644 --- a/modules/costs/spec/controllers/costlog_controller_spec.rb +++ b/modules/costs/spec/controllers/costlog_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') RSpec.describe CostlogController do include Cost::PluginSpecHelper @@ -47,7 +47,7 @@ overridden_costs: 400, units: 100, user:, - comments: "") + comments: '') end let(:work_package_status) { create(:work_package_status, is_default: true) } @@ -65,7 +65,7 @@ def disable_flash_sweep allow(@controller.flash).to receive(:sweep) end - shared_examples_for "assigns" do + shared_examples_for 'assigns' do it do expect(assigns(:cost_entry).project).to eq(expected_project) expect(assigns(:cost_entry).work_package).to eq(expected_work_package) @@ -86,8 +86,8 @@ def disable_flash_sweep User.current = nil end - describe "GET new" do - let(:params) { { "work_package_id" => work_package.id.to_s } } + describe 'GET new' do + let(:params) { { 'work_package_id' => work_package.id.to_s } } let(:expected_project) { project } let(:expected_work_package) { work_package } @@ -97,18 +97,18 @@ def disable_flash_sweep let(:expected_overridden_costs) { nil } let(:expected_units) { nil } - shared_examples_for "successful new" do + shared_examples_for 'successful new' do before do get :new, params: end it { expect(response).to be_successful } - it_behaves_like "assigns" - it { expect(response).to render_template("edit") } + it_behaves_like 'assigns' + it { expect(response).to render_template('edit') } end - shared_examples_for "forbidden new" do + shared_examples_for 'forbidden new' do before do get :new, params: end @@ -116,12 +116,12 @@ def disable_flash_sweep it { expect(response.response_code).to eq(403) } end - describe "WHEN user allowed to create new cost_entry" do + describe 'WHEN user allowed to create new cost_entry' do before do grant_current_user_permissions user, [:log_costs] end - it_behaves_like "successful new" + it_behaves_like 'successful new' end describe "WHEN user allowed to create new cost_entry @@ -135,34 +135,34 @@ def disable_flash_sweep grant_current_user_permissions user, [:log_costs] end - it_behaves_like "successful new" + it_behaves_like 'successful new' end - describe "WHEN user is allowed to create new own cost_entry" do + describe 'WHEN user is allowed to create new own cost_entry' do before do grant_current_user_permissions user, [:log_own_costs] end - it_behaves_like "successful new" + it_behaves_like 'successful new' end - describe "WHEN user is not allowed to create new cost_entries" do + describe 'WHEN user is not allowed to create new cost_entries' do before do grant_current_user_permissions user, [] end - it_behaves_like "forbidden new" + it_behaves_like 'forbidden new' end end - describe "GET edit" do - let(:params) { { "id" => cost_entry.id.to_s } } + describe 'GET edit' do + let(:params) { { 'id' => cost_entry.id.to_s } } before do cost_entry.save(validate: false) end - shared_examples_for "successful edit" do + shared_examples_for 'successful edit' do before do get :edit, params: end @@ -170,10 +170,10 @@ def disable_flash_sweep it { expect(response).to be_successful } it { expect(assigns(:cost_entry)).to eq(cost_entry) } it { expect(assigns(:cost_entry)).not_to be_changed } - it { expect(response).to render_template("edit") } + it { expect(response).to render_template('edit') } end - shared_examples_for "forbidden edit" do + shared_examples_for 'forbidden edit' do before do get :edit, params: end @@ -181,12 +181,12 @@ def disable_flash_sweep it { expect(response.response_code).to eq(403) } end - describe "WHEN the user is allowed to edit cost_entries" do + describe 'WHEN the user is allowed to edit cost_entries' do before do grant_current_user_permissions user, [:edit_cost_entries] end - it_behaves_like "successful edit" + it_behaves_like 'successful edit' end describe "WHEN the user is allowed to edit cost_entries @@ -198,15 +198,15 @@ def disable_flash_sweep cost_entry.save(validate: false) end - it_behaves_like "successful edit" + it_behaves_like 'successful edit' end - describe "WHEN the user is allowed to edit own cost_entries" do + describe 'WHEN the user is allowed to edit own cost_entries' do before do grant_current_user_permissions user, [:edit_own_cost_entries] end - it_behaves_like "successful edit" + it_behaves_like 'successful edit' end describe "WHEN the user is allowed to edit own cost_entries @@ -218,15 +218,15 @@ def disable_flash_sweep cost_entry.save(validate: false) end - it_behaves_like "forbidden edit" + it_behaves_like 'forbidden edit' end - describe "WHEN the user is not allowed to edit cost_entries" do + describe 'WHEN the user is not allowed to edit cost_entries' do before do grant_current_user_permissions user, [] end - it_behaves_like "forbidden edit" + it_behaves_like 'forbidden edit' end describe "WHEN the user is allowed to edit cost_entries @@ -241,7 +241,7 @@ def disable_flash_sweep cost_entry.save! end - it_behaves_like "forbidden edit" + it_behaves_like 'forbidden edit' end describe "WHEN the user is allowed to edit cost_entries @@ -249,7 +249,7 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_cost_entries] - params["id"] = (cost_entry.id + 1).to_s + params['id'] = (cost_entry.id + 1).to_s get :edit, params: end @@ -258,16 +258,16 @@ def disable_flash_sweep end end - describe "POST create" do + describe 'POST create' do let (:params) do - { "project_id" => project.id.to_s, - "cost_entry" => { "user_id" => user.id.to_s, - "work_package_id" => (work_package.present? ? work_package.id.to_s : ""), - "units" => units.to_s, - "cost_type_id" => (cost_type.present? ? cost_type.id.to_s : ""), - "comments" => "lorem", - "spent_on" => date.to_s, - "overridden_costs" => overridden_costs.to_s } } + { 'project_id' => project.id.to_s, + 'cost_entry' => { 'user_id' => user.id.to_s, + 'work_package_id' => (work_package.present? ? work_package.id.to_s : ''), + 'units' => units.to_s, + 'cost_type_id' => (cost_type.present? ? cost_type.id.to_s : ''), + 'comments' => 'lorem', + 'spent_on' => date.to_s, + 'overridden_costs' => overridden_costs.to_s } } end let(:expected_project) { project } let(:expected_work_package) { work_package } @@ -278,7 +278,7 @@ def disable_flash_sweep let(:expected_units) { units } let(:user2) { create(:user) } - let(:date) { "2012-04-03".to_date } + let(:date) { '2012-04-03'.to_date } let(:overridden_costs) { 500.00 } let(:units) { 5.0 } @@ -286,7 +286,7 @@ def disable_flash_sweep cost_type.save! if cost_type.present? end - shared_examples_for "successful create" do + shared_examples_for 'successful create' do before do post :create, params: end @@ -294,22 +294,22 @@ def disable_flash_sweep it { expect(response).to be_redirect } it { expect(assigns(:cost_entry)).not_to be_new_record } - it_behaves_like "assigns" - it { expect(flash[:notice]).to eql("Unit cost logged successfully.") } + it_behaves_like 'assigns' + it { expect(flash[:notice]).to eql('Unit cost logged successfully.') } end - shared_examples_for "invalid create" do + shared_examples_for 'invalid create' do before do post :create, params: end it { expect(response).to be_successful } - it_behaves_like "assigns" + it_behaves_like 'assigns' it { expect(flash[:notice]).to be_nil } end - shared_examples_for "forbidden create" do + shared_examples_for 'forbidden create' do before do post :create, params: end @@ -317,20 +317,20 @@ def disable_flash_sweep it { expect(response.response_code).to eq(403) } end - describe "WHEN the user is allowed to create cost_entries" do + describe 'WHEN the user is allowed to create cost_entries' do before do grant_current_user_permissions user, [:log_costs] end - it_behaves_like "successful create" + it_behaves_like 'successful create' end - describe "WHEN the user is allowed to create own cost_entries" do + describe 'WHEN the user is allowed to create own cost_entries' do before do grant_current_user_permissions user, [:log_own_costs] end - it_behaves_like "successful create" + it_behaves_like 'successful create' end describe "WHEN the user is allowed to create cost_entries @@ -340,10 +340,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:log_costs] - params["cost_entry"].delete("spent_on") + params['cost_entry'].delete('spent_on') end - it_behaves_like "successful create" + it_behaves_like 'successful create' end describe "WHEN the user is allowed to create cost_entries @@ -353,10 +353,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:log_costs] - params["cost_entry"]["cost_type_id"] = (cost_type.id + 1).to_s + params['cost_entry']['cost_type_id'] = (cost_type.id + 1).to_s end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -368,10 +368,10 @@ def disable_flash_sweep create(:cost_type, default: true) grant_current_user_permissions user, [:log_costs] - params["cost_entry"]["cost_type_id"] = 1 + params['cost_entry']['cost_type_id'] = 1 end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -383,10 +383,10 @@ def disable_flash_sweep create(:cost_type, default: true) grant_current_user_permissions user, [:log_costs] - params["cost_entry"].delete("cost_type_id") + params['cost_entry'].delete('cost_type_id') end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -396,10 +396,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:log_costs] - params["cost_entry"].delete("cost_type_id") + params['cost_entry'].delete('cost_type_id') end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -410,7 +410,7 @@ def disable_flash_sweep cost_type.save! end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -420,10 +420,10 @@ def disable_flash_sweep grant_current_user_permissions user, [] grant_current_user_permissions user2, [:log_costs] - params["cost_entry"]["user_id"] = user.id.to_s + params['cost_entry']['user_id'] = user.id.to_s end - it_behaves_like "successful create" + it_behaves_like 'successful create' end describe "WHEN the user is allowed to create cost_entries @@ -432,10 +432,10 @@ def disable_flash_sweep before do grant_current_user_permissions user2, [:log_costs] - params["cost_entry"]["user_id"] = user.id.to_s + params['cost_entry']['user_id'] = user.id.to_s end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -451,10 +451,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:log_costs] - params["cost_entry"]["work_package_id"] = work_package2.id + params['cost_entry']['work_package_id'] = work_package2.id end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create cost_entries @@ -464,10 +464,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:log_costs] - params["cost_entry"].delete("work_package_id") + params['cost_entry'].delete('work_package_id') end - it_behaves_like "invalid create" + it_behaves_like 'invalid create' end describe "WHEN the user is allowed to create own cost_entries @@ -475,30 +475,30 @@ def disable_flash_sweep before do grant_current_user_permissions user2, [:log_own_costs] - params["cost_entry"]["user_id"] = user.id + params['cost_entry']['user_id'] = user.id end - it_behaves_like "forbidden create" + it_behaves_like 'forbidden create' end - describe "WHEN the user is not allowed to create cost_entries" do + describe 'WHEN the user is not allowed to create cost_entries' do before do grant_current_user_permissions user, [] end - it_behaves_like "forbidden create" + it_behaves_like 'forbidden create' end end - describe "PUT update" do + describe 'PUT update' do let(:params) do - { "id" => cost_entry.id.to_s, - "cost_entry" => { "comments" => "lorem", - "work_package_id" => cost_entry.work_package.id.to_s, - "units" => cost_entry.units.to_s, - "spent_on" => cost_entry.spent_on.to_s, - "user_id" => cost_entry.user.id.to_s, - "cost_type_id" => cost_entry.cost_type.id.to_s } } + { 'id' => cost_entry.id.to_s, + 'cost_entry' => { 'comments' => 'lorem', + 'work_package_id' => cost_entry.work_package.id.to_s, + 'units' => cost_entry.units.to_s, + 'spent_on' => cost_entry.spent_on.to_s, + 'user_id' => cost_entry.user.id.to_s, + 'cost_type_id' => cost_entry.cost_type.id.to_s } } end let(:expected_work_package) { cost_entry.work_package } let(:expected_user) { cost_entry.user } @@ -512,7 +512,7 @@ def disable_flash_sweep cost_entry.save(validate: false) end - shared_examples_for "successful update" do + shared_examples_for 'successful update' do before do put :update, params: end @@ -520,22 +520,22 @@ def disable_flash_sweep it { expect(response).to be_redirect } it { expect(assigns(:cost_entry)).to eq(cost_entry) } - it_behaves_like "assigns" + it_behaves_like 'assigns' it { expect(assigns(:cost_entry)).not_to be_changed } it { expect(flash[:notice]).to eql I18n.t(:notice_successful_update) } end - shared_examples_for "invalid update" do + shared_examples_for 'invalid update' do before do put :update, params: end - it_behaves_like "assigns" + it_behaves_like 'assigns' it { expect(response).to be_successful } it { expect(flash[:notice]).to be_nil } end - shared_examples_for "forbidden update" do + shared_examples_for 'forbidden update' do before do put :update, params: end @@ -566,15 +566,15 @@ def disable_flash_sweep grant_current_user_permissions expected_user, [] grant_current_user_permissions user, [:edit_cost_entries] - params["cost_entry"]["work_package_id"] = expected_work_package.id.to_s - params["cost_entry"]["user_id"] = expected_user.id.to_s - params["cost_entry"]["spent_on"] = expected_spent_on.to_s - params["cost_entry"]["units"] = expected_units.to_s - params["cost_entry"]["cost_type_id"] = expected_cost_type.id.to_s - params["cost_entry"]["overridden_costs"] = expected_overridden_costs.to_s + params['cost_entry']['work_package_id'] = expected_work_package.id.to_s + params['cost_entry']['user_id'] = expected_user.id.to_s + params['cost_entry']['spent_on'] = expected_spent_on.to_s + params['cost_entry']['units'] = expected_units.to_s + params['cost_entry']['cost_type_id'] = expected_cost_type.id.to_s + params['cost_entry']['overridden_costs'] = expected_overridden_costs.to_s end - it_behaves_like "successful update" + it_behaves_like 'successful update' end describe "WHEN the user is allowed to update cost_entries @@ -583,7 +583,7 @@ def disable_flash_sweep grant_current_user_permissions user, [:edit_cost_entries] end - it_behaves_like "successful update" + it_behaves_like 'successful update' end describe "WHEN the user is allowed to update own cost_entries @@ -593,10 +593,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_own_cost_entries] - params["cost_entry"]["units"] = expected_units.to_s + params['cost_entry']['units'] = expected_units.to_s end - it_behaves_like "successful update" + it_behaves_like 'successful update' end describe "WHEN the user is allowed to update cost_entries @@ -608,10 +608,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_cost_entries] - params["cost_entry"]["user_id"] = user2.id.to_s + params['cost_entry']['user_id'] = user2.id.to_s end - it_behaves_like "invalid update" + it_behaves_like 'invalid update' end describe "WHEN the user is allowed to update cost_entries @@ -627,10 +627,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_cost_entries] - params["cost_entry"]["work_package_id"] = work_package2.id.to_s + params['cost_entry']['work_package_id'] = work_package2.id.to_s end - it_behaves_like "invalid update" + it_behaves_like 'invalid update' end describe "WHEN the user is allowed to update cost_entries @@ -641,10 +641,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_cost_entries] - params["cost_entry"]["work_package_id"] = (work_package.id + 1).to_s + params['cost_entry']['work_package_id'] = (work_package.id + 1).to_s end - it_behaves_like "invalid update" + it_behaves_like 'invalid update' end describe "WHEN the user is allowed to update cost_entries @@ -655,10 +655,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_cost_entries] - params["cost_entry"]["cost_type_id"] = expected_cost_type.id.to_s + params['cost_entry']['cost_type_id'] = expected_cost_type.id.to_s end - it_behaves_like "invalid update" + it_behaves_like 'invalid update' end describe "WHEN the user is allowed to update cost_entries @@ -669,10 +669,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_cost_entries] - params["cost_entry"]["cost_type_id"] = "1234123512" + params['cost_entry']['cost_type_id'] = '1234123512' end - it_behaves_like "invalid update" + it_behaves_like 'invalid update' end describe "WHEN the user is allowed to update own cost_entries and not all @@ -683,10 +683,10 @@ def disable_flash_sweep before do grant_current_user_permissions user, [:edit_own_cost_entries] - params["cost_entry"]["user_id"] = user3.id + params['cost_entry']['user_id'] = user3.id end - it_behaves_like "forbidden update" + it_behaves_like 'forbidden update' end describe "WHEN the user is allowed to update own cost_entries and not all @@ -697,10 +697,10 @@ def disable_flash_sweep before do grant_current_user_permissions user3, [:edit_own_cost_entries] - params["cost_entry"]["units"] = (cost_entry.units + 20).to_s + params['cost_entry']['units'] = (cost_entry.units + 20).to_s end - it_behaves_like "forbidden update" + it_behaves_like 'forbidden update' end end end diff --git a/modules/costs/spec/controllers/hourly_rates_controller_spec.rb b/modules/costs/spec/controllers/hourly_rates_controller_spec.rb index 1ba6a81a9845..3f7df92323a8 100644 --- a/modules/costs/spec/controllers/hourly_rates_controller_spec.rb +++ b/modules/costs/spec/controllers/hourly_rates_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') RSpec.describe HourlyRatesController do shared_let(:admin) { create(:admin) } @@ -34,13 +34,13 @@ let(:user) { create(:user) } let(:default_rate) { create(:default_hourly_rate, user:) } - describe "PUT update" do - describe "WHEN trying to update with an invalid rate value" do + describe 'PUT update' do + describe 'WHEN trying to update with an invalid rate value' do let(:params) do { id: user.id, - user: { "existing_rate_attributes" => { default_rate.id.to_s => { "valid_from" => default_rate.valid_from.to_s, - "rate" => "2d5" } } } + user: { 'existing_rate_attributes' => { default_rate.id.to_s => { 'valid_from' => default_rate.valid_from.to_s, + 'rate' => '2d5' } } } } end @@ -50,13 +50,13 @@ end end - it "renders the edit template" do - expect(response).to render_template("edit") + it 'renders the edit template' do + expect(response).to render_template('edit') end - it "displays an error message" do + it 'displays an error message' do actual_message = assigns(:user).default_rates.first.errors.messages[:rate].first - expect(actual_message).to eq(I18n.t("activerecord.errors.messages.not_a_number")) + expect(actual_message).to eq(I18n.t('activerecord.errors.messages.not_a_number')) end end end diff --git a/modules/costs/spec/controllers/work_packages_bulk_controller_spec.rb b/modules/costs/spec/controllers/work_packages_bulk_controller_spec.rb index 689dc25c2041..5491e29772d5 100644 --- a/modules/costs/spec/controllers/work_packages_bulk_controller_spec.rb +++ b/modules/costs/spec/controllers/work_packages_bulk_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::BulkController do let(:project) { create(:project_with_types) } @@ -39,8 +39,8 @@ allow(User).to receive(:current).and_return user end - describe "#update" do - context "when a cost report is assigned" do + describe '#update' do + context 'when a cost report is assigned' do before do put :update, params: { ids: [work_package.id], work_package: { budget_id: budget.id } } diff --git a/modules/costs/spec/factories/cost_entry_factory.rb b/modules/costs/spec/factories/cost_entry_factory.rb index 3b4b00e02946..6764a000c000 100644 --- a/modules/costs/spec/factories/cost_entry_factory.rb +++ b/modules/costs/spec/factories/cost_entry_factory.rb @@ -34,7 +34,7 @@ cost_type spent_on { Date.today } units { 1 } - comments { "" } + comments { '' } before(:create) do |ce| ce.work_package.project = ce.project diff --git a/modules/costs/spec/factories/cost_type_factory.rb b/modules/costs/spec/factories/cost_type_factory.rb index 7e19c64609fe..7763c414d283 100644 --- a/modules/costs/spec/factories/cost_type_factory.rb +++ b/modules/costs/spec/factories/cost_type_factory.rb @@ -29,8 +29,8 @@ FactoryBot.define do factory :cost_type do sequence(:name) { |n| "ct no. #{n}" } - unit { "singular_unit" } - unit_plural { "plural_unit" } + unit { 'singular_unit' } + unit_plural { 'plural_unit' } trait :deleted do deleted_at { Time.now } diff --git a/modules/costs/spec/factories/journal/budget_journal_factory.rb b/modules/costs/spec/factories/journal/budget_journal_factory.rb index a366514f80e4..ea79035fac04 100644 --- a/modules/costs/spec/factories/journal/budget_journal_factory.rb +++ b/modules/costs/spec/factories/journal/budget_journal_factory.rb @@ -27,6 +27,6 @@ #++ FactoryBot.define do - factory :journal_budget_journal, class: "Journal::BudgetJournal" do + factory :journal_budget_journal, class: 'Journal::BudgetJournal' do end end diff --git a/modules/costs/spec/factories/journal/time_entry_journal_factory.rb b/modules/costs/spec/factories/journal/time_entry_journal_factory.rb index 07cb2a25a81a..d2adfe07b886 100644 --- a/modules/costs/spec/factories/journal/time_entry_journal_factory.rb +++ b/modules/costs/spec/factories/journal/time_entry_journal_factory.rb @@ -27,6 +27,6 @@ #++ FactoryBot.define do - factory :journal_time_entry_journal, class: "Journal::TimeEntryJournal" do + factory :journal_time_entry_journal, class: 'Journal::TimeEntryJournal' do end end diff --git a/modules/costs/spec/features/cost_entries/add_cost_entry_spec.rb b/modules/costs/spec/features/cost_entries/add_cost_entry_spec.rb index 2ade93e62604..a11bcf363249 100644 --- a/modules/costs/spec/features/cost_entries/add_cost_entry_spec.rb +++ b/modules/costs/spec/features/cost_entries/add_cost_entry_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../../spec_helper" +require_relative '../../spec_helper' -RSpec.describe "Work Package cost fields", :js do +RSpec.describe 'Work Package cost fields', :js do shared_let(:type_task) { create(:type_task) } shared_let(:status) { create(:status, is_default: true) } shared_let(:priority) { create(:priority, is_default: true) } @@ -50,13 +50,13 @@ member_with_roles: { project => role }) end shared_let(:cost_type1) do - type = create(:cost_type, name: "A", unit: "A single", unit_plural: "A plural") + type = create(:cost_type, name: 'A', unit: 'A single', unit_plural: 'A plural') create(:cost_rate, cost_type: type, rate: 1.00) type end shared_let(:cost_type2) do - type = create(:cost_type, name: "B", unit: "B single", unit_plural: "B plural") + type = create(:cost_type, name: 'B', unit: 'B single', unit_plural: 'B plural') create(:cost_rate, cost_type: type, rate: 2.00) type end @@ -68,38 +68,38 @@ login_as user end - it "does not show read-only fields" do + it 'does not show read-only fields' do full_view.visit! # Go to add cost entry page SeleniumHubWaiter.wait - find("#action-show-more-dropdown-menu .button").click - find(".menu-item", text: "Log unit costs").click + find('#action-show-more-dropdown-menu .button').click + find('.menu-item', text: 'Log unit costs').click SeleniumHubWaiter.wait # Set single value, should update suffix - select "A", from: "cost_entry_cost_type_id" - fill_in "cost_entry_units", with: "1" - expect(page).to have_css("#cost_entry_unit_name", text: "A single") - expect(page).to have_css("#cost_entry_costs", text: "1.00 EUR") + select 'A', from: 'cost_entry_cost_type_id' + fill_in 'cost_entry_units', with: '1' + expect(page).to have_css('#cost_entry_unit_name', text: 'A single') + expect(page).to have_css('#cost_entry_costs', text: '1.00 EUR') - fill_in "cost_entry_units", with: "2" - expect(page).to have_css("#cost_entry_unit_name", text: "A plural") - expect(page).to have_css("#cost_entry_costs", text: "2.00 EUR") + fill_in 'cost_entry_units', with: '2' + expect(page).to have_css('#cost_entry_unit_name', text: 'A plural') + expect(page).to have_css('#cost_entry_costs', text: '2.00 EUR') # Switch cost type - select "B", from: "cost_entry_cost_type_id" - expect(page).to have_css("#cost_entry_unit_name", text: "B plural") - expect(page).to have_css("#cost_entry_costs", text: "4.00 EUR") + select 'B', from: 'cost_entry_cost_type_id' + expect(page).to have_css('#cost_entry_unit_name', text: 'B plural') + expect(page).to have_css('#cost_entry_costs', text: '4.00 EUR') # Override costs - find_by_id("cost_entry_costs").click + find_by_id('cost_entry_costs').click SeleniumHubWaiter.wait - fill_in "cost_entry_overridden_costs", with: "15.52" + fill_in 'cost_entry_overridden_costs', with: '15.52' - click_on "Save" + click_on 'Save' # Expect correct costs - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_cost_logged_successfully)) + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_cost_logged_successfully)) entry = CostEntry.last expect(entry.cost_type_id).to eq(cost_type2.id) expect(entry.units).to eq(2.0) @@ -107,11 +107,11 @@ expect(entry.real_costs).to eq(15.52) visit edit_cost_entry_path(entry) - expect(page).to have_css("#cost_entry_costs", text: "15.52 EUR") + expect(page).to have_css('#cost_entry_costs', text: '15.52 EUR') end - context "with german locale" do - it "creates the budget including the given cost items with german locale" do + context 'with german locale' do + it 'creates the budget including the given cost items with german locale' do user.update!(language: :de) I18n.locale = :de @@ -119,24 +119,24 @@ # Go to add cost entry page SeleniumHubWaiter.wait - find("#action-show-more-dropdown-menu .button").click - find(".menu-item", text: I18n.t(:button_log_costs)).click + find('#action-show-more-dropdown-menu .button').click + find('.menu-item', text: I18n.t(:button_log_costs)).click SeleniumHubWaiter.wait - fill_in "cost_entry_units", with: "1,42" - select "B", from: "cost_entry_cost_type_id" - expect(page).to have_css("#cost_entry_unit_name", text: "B plural") - expect(page).to have_css("#cost_entry_costs", text: "2,84 EUR") + fill_in 'cost_entry_units', with: '1,42' + select 'B', from: 'cost_entry_cost_type_id' + expect(page).to have_css('#cost_entry_unit_name', text: 'B plural') + expect(page).to have_css('#cost_entry_costs', text: '2,84 EUR') # Override costs - find_by_id("cost_entry_costs").click + find_by_id('cost_entry_costs').click SeleniumHubWaiter.wait - fill_in "cost_entry_overridden_costs", with: "1.350,25" + fill_in 'cost_entry_overridden_costs', with: '1.350,25' click_on I18n.t(:button_save) # Expect correct costs - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_cost_logged_successfully)) + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_cost_logged_successfully)) entry = CostEntry.last expect(entry.cost_type_id).to eq(cost_type2.id) expect(entry.units).to eq(1.42) @@ -145,18 +145,18 @@ # Can edit the costs again visit edit_cost_entry_path(entry) - expect(page).to have_css("#cost_entry_costs", text: "1.350,25 EUR") + expect(page).to have_css('#cost_entry_costs', text: '1.350,25 EUR') # Toggle the cost button SeleniumHubWaiter.wait - find_by_id("cost_entry_costs").click + find_by_id('cost_entry_costs').click # Update the costs in german locale SeleniumHubWaiter.wait - fill_in "cost_entry_overridden_costs", with: "55.000,55" + fill_in 'cost_entry_overridden_costs', with: '55.000,55' click_on I18n.t(:button_save) - expect(page).to have_css("#cost_entry_costs", text: "55.000,55 EUR") + expect(page).to have_css('#cost_entry_costs', text: '55.000,55 EUR') entry.reload expect(entry.units).to eq(1.42) expect(entry.costs).to eq(2.84) @@ -164,25 +164,25 @@ end end - context "with an additional placeholder user in the project" do + context 'with an additional placeholder user in the project' do let!(:placeholder_user) do create(:placeholder_user, member_with_roles: { project => role }) end - it "does not allow to select them (Regression #36353)" do + it 'does not allow to select them (Regression #36353)' do expect(placeholder_user).to be_present expect(Principal.possible_assignee(project).to_a).to include placeholder_user full_view.visit! # Go to add cost entry page SeleniumHubWaiter.wait - find("#action-show-more-dropdown-menu .button").click - find(".menu-item", text: I18n.t(:button_log_costs)).click + find('#action-show-more-dropdown-menu .button').click + find('.menu-item', text: I18n.t(:button_log_costs)).click SeleniumHubWaiter.wait - expect(page).to have_no_css("#cost_entry_user_id option", text: placeholder_user.name, visible: :all) - expect(page).to have_css("#cost_entry_user_id option", text: user.name, visible: :all) + expect(page).to have_no_css('#cost_entry_user_id option', text: placeholder_user.name, visible: :all) + expect(page).to have_css('#cost_entry_user_id option', text: user.name, visible: :all) end end end diff --git a/modules/costs/spec/features/cost_entries/add_entry_without_rate_permission_spec.rb b/modules/costs/spec/features/cost_entries/add_entry_without_rate_permission_spec.rb index 7008b2ca0e69..111a666a5ee4 100644 --- a/modules/costs/spec/features/cost_entries/add_entry_without_rate_permission_spec.rb +++ b/modules/costs/spec/features/cost_entries/add_entry_without_rate_permission_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../../spec_helper" +require_relative '../../spec_helper' -RSpec.describe "Create cost entry without rate permissions", :js do +RSpec.describe 'Create cost entry without rate permissions', :js do shared_let(:type_task) { create(:type_task) } shared_let(:status) { create(:status, is_default: true) } shared_let(:priority) { create(:priority, is_default: true) } @@ -48,7 +48,7 @@ end shared_let(:cost_type) do - type = create(:cost_type, name: "A", unit: "A single", unit_plural: "A plural") + type = create(:cost_type, name: 'A', unit: 'A single', unit_plural: 'A plural') create(:cost_rate, cost_type: type, rate: 1.00) type end @@ -60,24 +60,24 @@ login_as user end - it "can create the item without seeing the costs" do + it 'can create the item without seeing the costs' do full_view.visit! # Go to add cost entry page SeleniumHubWaiter.wait - find("#action-show-more-dropdown-menu .button").click - find(".menu-item", text: "Log unit costs").click + find('#action-show-more-dropdown-menu .button').click + find('.menu-item', text: 'Log unit costs').click SeleniumHubWaiter.wait # Set single value, should update suffix - select "A", from: "cost_entry_cost_type_id" - fill_in "cost_entry_units", with: "1" - expect(page).to have_css("#cost_entry_unit_name", text: "A single") - expect(page).to have_no_css("#cost_entry_costs") + select 'A', from: 'cost_entry_cost_type_id' + fill_in 'cost_entry_units', with: '1' + expect(page).to have_css('#cost_entry_unit_name', text: 'A single') + expect(page).to have_no_css('#cost_entry_costs') - click_on "Save" + click_on 'Save' # Expect correct costs - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_cost_logged_successfully)) + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_cost_logged_successfully)) entry = CostEntry.last expect(entry.cost_type_id).to eq(cost_type.id) expect(entry.units).to eq(1.0) diff --git a/modules/costs/spec/features/cost_types/create_cost_type_spec.rb b/modules/costs/spec/features/cost_types/create_cost_type_spec.rb index b3039a017d1f..6f4cd437db83 100644 --- a/modules/costs/spec/features/cost_types/create_cost_type_spec.rb +++ b/modules/costs/spec/features/cost_types/create_cost_type_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "creating a cost type", :js do +RSpec.describe 'creating a cost type', :js do let!(:user) { create(:admin) } let!(:cost_type) do - type = create(:cost_type, name: "Translations") + type = create(:cost_type, name: 'Translations') create(:cost_rate, cost_type: type, rate: 1.00) type end @@ -40,61 +40,61 @@ login_as user end - it "can create a cost type" do + it 'can create a cost type' do visit "/cost_types/new" - fill_in "cost_type_name", with: "Test day rate" - fill_in "cost_type_unit", with: "dayUnit" - fill_in "cost_type_unit_plural", with: "dayUnitPlural" - fill_in "cost_type_new_rate_attributes_0_rate", with: "1,000.25" + fill_in 'cost_type_name', with: 'Test day rate' + fill_in 'cost_type_unit', with: 'dayUnit' + fill_in 'cost_type_unit_plural', with: 'dayUnitPlural' + fill_in 'cost_type_new_rate_attributes_0_rate', with: '1,000.25' sleep 1 - scroll_to_and_click(find("button.-with-icon.icon-checkmark")) + scroll_to_and_click(find('button.-with-icon.icon-checkmark')) expect_angular_frontend_initialized - expect(page).to have_css ".generic-table", wait: 10 + expect(page).to have_css '.generic-table', wait: 10 - cost_type_row = find("tr", text: "Test day rate") + cost_type_row = find('tr', text: 'Test day rate') - expect(cost_type_row).to have_css("td a", text: "Test day rate") - expect(cost_type_row).to have_css("td", text: "dayUnit") - expect(cost_type_row).to have_css("td", text: "dayUnitPlural") - expect(cost_type_row).to have_css("td.currency", text: "1,000.25") + expect(cost_type_row).to have_css('td a', text: 'Test day rate') + expect(cost_type_row).to have_css('td', text: 'dayUnit') + expect(cost_type_row).to have_css('td', text: 'dayUnitPlural') + expect(cost_type_row).to have_css('td.currency', text: '1,000.25') cost_type = CostType.last - expect(cost_type.name).to eq "Test day rate" + expect(cost_type.name).to eq 'Test day rate' cost_rate = cost_type.rates.last expect(cost_rate.rate).to eq 1000.25 end - context "with german locale" do + context 'with german locale' do let(:user) { create(:admin, language: :de) } - it "creates the entry with german number separators" do + it 'creates the entry with german number separators' do visit "/cost_types/new" - fill_in "cost_type_name", with: "Test day rate" - fill_in "cost_type_unit", with: "dayUnit" - fill_in "cost_type_unit_plural", with: "dayUnitPlural" - fill_in "cost_type_new_rate_attributes_0_rate", with: "1.000,25" + fill_in 'cost_type_name', with: 'Test day rate' + fill_in 'cost_type_unit', with: 'dayUnit' + fill_in 'cost_type_unit_plural', with: 'dayUnitPlural' + fill_in 'cost_type_new_rate_attributes_0_rate', with: '1.000,25' sleep 1 - scroll_to_and_click(find("button.-with-icon.icon-checkmark")) + scroll_to_and_click(find('button.-with-icon.icon-checkmark')) expect_angular_frontend_initialized - expect(page).to have_css ".generic-table", wait: 10 + expect(page).to have_css '.generic-table', wait: 10 - cost_type_row = find("tr", text: "Test day rate") + cost_type_row = find('tr', text: 'Test day rate') - expect(cost_type_row).to have_css("td a", text: "Test day rate") - expect(cost_type_row).to have_css("td", text: "dayUnit") - expect(cost_type_row).to have_css("td", text: "dayUnitPlural") - expect(cost_type_row).to have_css("td.currency", text: "1.000,25") + expect(cost_type_row).to have_css('td a', text: 'Test day rate') + expect(cost_type_row).to have_css('td', text: 'dayUnit') + expect(cost_type_row).to have_css('td', text: 'dayUnitPlural') + expect(cost_type_row).to have_css('td.currency', text: '1.000,25') cost_type = CostType.last - expect(cost_type.name).to eq "Test day rate" + expect(cost_type.name).to eq 'Test day rate' cost_rate = cost_type.rates.last expect(cost_rate.rate).to eq 1000.25 end diff --git a/modules/costs/spec/features/cost_types/delete_cost_type_spec.rb b/modules/costs/spec/features/cost_types/delete_cost_type_spec.rb index 3a98bed667f8..48f61847e2ab 100644 --- a/modules/costs/spec/features/cost_types/delete_cost_type_spec.rb +++ b/modules/costs/spec/features/cost_types/delete_cost_type_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "deleting a cost type", :js do +RSpec.describe 'deleting a cost type', :js do let!(:user) { create(:admin) } let!(:cost_type) do - type = create(:cost_type, name: "Translations") + type = create(:cost_type, name: 'Translations') create(:cost_rate, cost_type: type, rate: 1.00) type end @@ -40,26 +40,26 @@ login_as user end - it "can delete the cost type" do + it 'can delete the cost type' do visit cost_types_path within("#delete_cost_type_#{cost_type.id}") do - scroll_to_and_click(find("button.submit_cost_type")) + scroll_to_and_click(find('button.submit_cost_type')) end # Expect no results if not locked expect_angular_frontend_initialized - expect(page).to have_css ".generic-table--no-results-container", wait: 10 + expect(page).to have_css '.generic-table--no-results-container', wait: 10 SeleniumHubWaiter.wait # Show locked - find_by_id("include_deleted").set true - click_on "Apply" + find_by_id('include_deleted').set true + click_on 'Apply' # Expect no results if not locked expect(page).to have_text I18n.t(:label_locked_cost_types) - expect(page).to have_css(".restore_cost_type") - expect(page).to have_css(".cost-types--list-deleted td", text: "Translations") + expect(page).to have_css('.restore_cost_type') + expect(page).to have_css('.cost-types--list-deleted td', text: 'Translations') end end diff --git a/modules/costs/spec/features/costs_context_menu_spec.rb b/modules/costs/spec/features/costs_context_menu_spec.rb index f075b3d1484e..48ed7859e986 100644 --- a/modules/costs/spec/features/costs_context_menu_spec.rb +++ b/modules/costs/spec/features/costs_context_menu_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package table log unit costs", :js do +RSpec.describe 'Work package table log unit costs', :js do let(:user) { create(:admin) } let(:work_package) { create(:work_package) } @@ -24,8 +24,8 @@ def goto_context_menu goto_context_menu end - it "renders the log unit costs menu item" do + it 'renders the log unit costs menu item' do menu.choose(I18n.t(:label_log_costs)) - expect(page).to have_css("h2", text: I18n.t(:label_log_costs)) + expect(page).to have_css('h2', text: I18n.t(:label_log_costs)) end end diff --git a/modules/costs/spec/features/destroy_work_package_with_cost_entries_spec.rb b/modules/costs/spec/features/destroy_work_package_with_cost_entries_spec.rb index 54b1dcc0a582..66874c5d1cb0 100644 --- a/modules/costs/spec/features/destroy_work_package_with_cost_entries_spec.rb +++ b/modules/costs/spec/features/destroy_work_package_with_cost_entries_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') -RSpec.describe "Deleting time entries", :js do +RSpec.describe 'Deleting time entries', :js do let(:project) { work_package.project } let(:user) do create(:user, @@ -44,7 +44,7 @@ let(:work_package) { create(:work_package) } let(:destroy_modal) { Components::WorkPackages::DestroyModal.new } let(:cost_type) do - type = create(:cost_type, name: "Translations") + type = create(:cost_type, name: 'Translations') create(:cost_rate, cost_type: type, rate: 7.00) @@ -63,7 +63,7 @@ user:) end - it "allows to move the time entry to a different work package" do + it 'allows to move the time entry to a different work package' do login_as(user) work_package @@ -74,18 +74,18 @@ wp_page.visit! SeleniumHubWaiter.wait - find_by_id("action-show-more-dropdown-menu").click + find_by_id('action-show-more-dropdown-menu').click - click_link(I18n.t("js.button_delete")) + click_link(I18n.t('js.button_delete')) destroy_modal.expect_listed(work_package) destroy_modal.confirm_deletion SeleniumHubWaiter.wait - choose "to_do_action_reassign" - fill_in "to_do_reassign_to_id", with: other_work_package.id + choose 'to_do_action_reassign' + fill_in 'to_do_reassign_to_id', with: other_work_package.id - click_button(I18n.t("button_delete")) + click_button(I18n.t('button_delete')) table = Pages::WorkPackagesTable.new(project) table.expect_current_path @@ -93,6 +93,6 @@ other_wp_page = Pages::FullWorkPackage.new(other_work_package) other_wp_page.visit! - wp_page.expect_attributes costs_by_type: "2 Translations" + wp_page.expect_attributes costs_by_type: '2 Translations' end end diff --git a/modules/costs/spec/features/members_hourly_rates_spec.rb b/modules/costs/spec/features/members_hourly_rates_spec.rb index f989f2e1c6c8..9b37479230ea 100644 --- a/modules/costs/spec/features/members_hourly_rates_spec.rb +++ b/modules/costs/spec/features/members_hourly_rates_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') -RSpec.describe "hourly rates on a member", :js do +RSpec.describe 'hourly rates on a member', :js do let(:project) { build(:project) } let(:user) do create(:admin, member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) @@ -36,7 +36,7 @@ let(:member) { Member.find_by(project:, principal: user) } def view_rates - visit edit_user_path(user, tab: "rates") + visit edit_user_path(user, tab: 'rates') end def view_project_members @@ -54,13 +54,13 @@ def add_rate(rate:, date:) sleep(0.1) all("tr[id^='user_new_rate_attributes_'] .delete-row-button").each(&:click) sleep(0.1) - click_link_or_button "Add rate" + click_link_or_button 'Add rate' datepicker = Components::BasicDatepicker.new - datepicker.set_date(date.strftime("%Y-%m-%d")) + datepicker.set_date(date.strftime('%Y-%m-%d')) within "tr[id^='user_new_rate_attributes_']" do - fill_in "Rate", with: rate + fill_in 'Rate', with: rate end end @@ -68,7 +68,7 @@ def change_rate_date(from:, to:) input = find("table.rates .date input[data-value='#{from.strftime('%Y-%m-%d')}']") input.click datepicker = Components::BasicDatepicker.new - datepicker.set_date(to.strftime("%Y-%m-%d")) + datepicker.set_date(to.strftime('%Y-%m-%d')) end before do @@ -77,34 +77,34 @@ def change_rate_date(from:, to:) login_as(user) end - it "displays always the currently active rate" do - expect_current_rate_in_members_table("0.00 EUR") + it 'displays always the currently active rate' do + expect_current_rate_in_members_table('0.00 EUR') - click_link("0.00 EUR") + click_link('0.00 EUR') SeleniumHubWaiter.wait add_rate(date: Date.current, rate: 10) - click_button "Save" + click_button 'Save' - expect_current_rate_in_members_table("10.00 EUR") + expect_current_rate_in_members_table('10.00 EUR') SeleniumHubWaiter.wait - click_link("10.00 EUR") + click_link('10.00 EUR') add_rate(date: 3.days.ago, rate: 20) - click_button "Save" + click_button 'Save' - expect_current_rate_in_members_table("10.00 EUR") + expect_current_rate_in_members_table('10.00 EUR') SeleniumHubWaiter.wait - click_link("10.00 EUR") + click_link('10.00 EUR') change_rate_date(from: Date.current, to: 5.days.ago) - click_button "Save" + click_button 'Save' - expect_current_rate_in_members_table("20.00 EUR") + expect_current_rate_in_members_table('20.00 EUR') end end diff --git a/modules/costs/spec/features/time_entries_spec.rb b/modules/costs/spec/features/time_entries_spec.rb index 3d6002cc3689..661e3184ebc8 100644 --- a/modules/costs/spec/features/time_entries_spec.rb +++ b/modules/costs/spec/features/time_entries_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "Work Package table cost entries", :js do +RSpec.describe 'Work Package table cost entries', :js do shared_let(:project) { create(:project_with_types) } shared_let(:user) { create(:admin) } @@ -65,7 +65,7 @@ login_as(user) end - it "shows the correct sum of the time entries" do + it 'shows the correct sum of the time entries' do wp_table.visit_query(query) wp_table.expect_work_package_listed(parent) wp_table.expect_work_package_listed(work_package) @@ -73,20 +73,20 @@ parent_row = wp_table.row(parent) wp_row = wp_table.row(work_package) - expect(parent_row).to have_css(".inline-edit--container.spentTime", text: "12.5 h") - expect(wp_row).to have_css(".inline-edit--container.spentTime", text: "2.5 h") + expect(parent_row).to have_css('.inline-edit--container.spentTime', text: '12.5 h') + expect(wp_row).to have_css('.inline-edit--container.spentTime', text: '2.5 h') end - it "creates an activity" do + it 'creates an activity' do visit project_activities_path project # Activate the spent time filter - check("Spent time") - click_on "Apply" + check('Spent time') + click_on 'Apply' wp1 = time_entry1.work_package wp2 = time_entry2.work_package - expect(page).to have_css(".op-activity-list--item-title", text: "#{wp1.type.name} ##{wp1.id}: #{wp1.subject}") - expect(page).to have_css(".op-activity-list--item-title", text: "#{wp2.type.name} ##{wp2.id}: #{wp2.subject}") + expect(page).to have_css('.op-activity-list--item-title', text: "#{wp1.type.name} ##{wp1.id}: #{wp1.subject}") + expect(page).to have_css('.op-activity-list--item-title', text: "#{wp2.type.name} ##{wp2.id}: #{wp2.subject}") end end diff --git a/modules/costs/spec/features/time_entry/activity_spec.rb b/modules/costs/spec/features/time_entry/activity_spec.rb index c1fc24fa4132..cf05f0aae663 100644 --- a/modules/costs/spec/features/time_entry/activity_spec.rb +++ b/modules/costs/spec/features/time_entry/activity_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Time entry activity" do +RSpec.describe 'Time entry activity' do shared_let(:admin) { create(:admin) } let(:project) { create(:project) } @@ -36,35 +36,35 @@ login_as(admin) end - it "supports CRUD" do + it 'supports CRUD' do visit enumerations_path - page.find_test_selector("create-enumeration-time-entry-activity").click + page.find_test_selector('create-enumeration-time-entry-activity').click - fill_in "Name", with: "A new activity" - click_on("Create") + fill_in 'Name', with: 'A new activity' + click_on('Create') expect(page.current_path) .to eql enumerations_path expect(page) - .to have_content("A new activity") + .to have_content('A new activity') visit project_settings_general_path(project) click_on "Time tracking activities" expect(page) - .to have_field("A new activity", checked: true) + .to have_field('A new activity', checked: true) - uncheck "A new activity" + uncheck 'A new activity' - click_on "Save" + click_on 'Save' expect(page) .to have_content "Successful update." expect(page) - .to have_field("A new activity", checked: false) + .to have_field('A new activity', checked: false) end end diff --git a/modules/costs/spec/features/timer_spec.rb b/modules/costs/spec/features/timer_spec.rb index 03f4ee246f80..cdbdb22cc11d 100644 --- a/modules/costs/spec/features/timer_spec.rb +++ b/modules/costs/spec/features/timer_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "Work Package timer", :js do +RSpec.describe 'Work Package timer', :js do shared_let(:project) { create(:project_with_types) } - shared_let(:work_package_a) { create(:work_package, subject: "WP A", project:) } - shared_let(:work_package_b) { create(:work_package, subject: "WP B", project:) } + shared_let(:work_package_a) { create(:work_package, subject: 'WP A', project:) } + shared_let(:work_package_b) { create(:work_package, subject: 'WP B', project:) } let(:wp_view_a) { Pages::FullWorkPackage.new(work_package_a) } let(:wp_view_b) { Pages::FullWorkPackage.new(work_package_b) } @@ -45,8 +45,8 @@ login_as user end - shared_examples "allows time tracking" do - it "shows the timer and allows tracking time" do + shared_examples 'allows time tracking' do + it 'shows the timer and allows tracking time' do wp_view_a.visit! timer_button.expect_visible timer_button.start @@ -58,20 +58,20 @@ expect(timer_entry.work_package).to eq work_package_a expect(timer_entry.hours).to be_nil - page.find(".op-top-menu-user").click - expect(page).to have_css(".op-timer-account-menu", wait: 10) - expect(page).to have_css(".op-timer-account-menu--wp-details", text: "##{work_package_a.id}: WP A") - page.find_test_selector("op-timer-account-menu-stop").click + page.find('.op-top-menu-user').click + expect(page).to have_css('.op-timer-account-menu', wait: 10) + expect(page).to have_css('.op-timer-account-menu--wp-details', text: "##{work_package_a.id}: WP A") + page.find_test_selector('op-timer-account-menu-stop').click time_logging_modal.is_visible true - time_logging_modal.has_field_with_value "spentOn", Date.current.strftime - time_logging_modal.has_field_with_value "hours", /(\d\.)?\d+/ + time_logging_modal.has_field_with_value 'spentOn', Date.current.strftime + time_logging_modal.has_field_with_value 'hours', /(\d\.)?\d+/ time_logging_modal.work_package_is_missing false # wait for available_work_packages query to finish before saving time_logging_modal.expect_work_package(work_package_a.subject) - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' time_logging_modal.is_visible false wp_view_a.expect_and_dismiss_toaster message: I18n.t(:notice_successful_update) @@ -92,8 +92,8 @@ timer_button.start - expect(page).to have_css(".op-timer-stop-modal") - expect(page).to have_text("Tracking time:") + expect(page).to have_css('.op-timer-stop-modal') + expect(page).to have_text('Tracking time:') active_time_entries = TimeEntry.where(ongoing: true, user:) expect(active_time_entries.count).to eq 1 @@ -101,15 +101,15 @@ expect(timer_entry.work_package).to eq work_package_a expect(timer_entry.hours).to be_nil - page.within(".spot-modal") { click_button "Stop current timer" } + page.within('.spot-modal') { click_button 'Stop current timer' } time_logging_modal.is_visible true - time_logging_modal.has_field_with_value "spentOn", Date.current.strftime - time_logging_modal.has_field_with_value "hours", /(\d\.)?\d+/ + time_logging_modal.has_field_with_value 'spentOn', Date.current.strftime + time_logging_modal.has_field_with_value 'hours', /(\d\.)?\d+/ time_logging_modal.work_package_is_missing false # wait for available_work_packages query to finish before saving time_logging_modal.expect_work_package(work_package_a.subject) - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' # Closing the modal starts the next timer wp_view_b.expect_and_dismiss_toaster message: I18n.t(:notice_successful_update) @@ -129,26 +129,26 @@ end end - context "when user has permission to log time" do + context 'when user has permission to log time' do let(:permissions) { %i[log_own_time edit_own_time_entries view_own_time_entries view_work_packages] } - it_behaves_like "allows time tracking" + it_behaves_like 'allows time tracking' - context "when an old timer exists" do + context 'when an old timer exists' do let!(:active_timer) do Timecop.travel(2.days.ago) do create(:time_entry, project:, work_package: work_package_a, user:, ongoing: true) end end - it "correctly shows active timers > 24 hours" do + it 'correctly shows active timers > 24 hours' do wp_view_a.visit! timer_button.expect_visible timer_button.expect_time /48:0\d:\d+/ end end - it "correctly handles timers in multiple tabs" do + it 'correctly handles timers in multiple tabs' do wp_view_a.visit! timer_button.expect_visible @@ -163,31 +163,31 @@ timer_button.expect_inactive timer_button.start - expect(page).to have_css(".op-timer-stop-modal") - expect(page).to have_text("Tracking time:") + expect(page).to have_css('.op-timer-stop-modal') + expect(page).to have_text('Tracking time:') - page.within(".spot-modal") { click_button "Stop current timer" } + page.within('.spot-modal') { click_button 'Stop current timer' } time_logging_modal.is_visible true - time_logging_modal.has_field_with_value "spentOn", Date.current.strftime - time_logging_modal.has_field_with_value "hours", /(\d\.)?\d+/ + time_logging_modal.has_field_with_value 'spentOn', Date.current.strftime + time_logging_modal.has_field_with_value 'hours', /(\d\.)?\d+/ time_logging_modal.work_package_is_missing false # wait for available_work_packages query to finish before saving time_logging_modal.expect_work_package(work_package_a.subject) - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' wp_view_b.expect_and_dismiss_toaster message: I18n.t(:notice_successful_update) time_logging_modal.is_visible false timer_button.expect_active timer_button.stop time_logging_modal.is_visible true - time_logging_modal.has_field_with_value "spentOn", Date.current.strftime - time_logging_modal.has_field_with_value "hours", /(\d\.)?\d+/ + time_logging_modal.has_field_with_value 'spentOn', Date.current.strftime + time_logging_modal.has_field_with_value 'hours', /(\d\.)?\d+/ time_logging_modal.work_package_is_missing false # wait for available_work_packages query to finish before saving time_logging_modal.expect_work_package(work_package_a.subject) - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' wp_view_b.expect_and_dismiss_toaster message: I18n.t(:notice_successful_update) time_logging_modal.is_visible false timer_button.expect_inactive @@ -195,32 +195,32 @@ within_window(second_window) do timer_button.expect_active timer_button.stop - wp_view_b.expect_and_dismiss_toaster message: I18n.t("js.timer.timer_already_stopped"), type: :warning + wp_view_b.expect_and_dismiss_toaster message: I18n.t('js.timer.timer_already_stopped'), type: :warning end end end - context "when user has no permission to log time" do + context 'when user has no permission to log time' do let(:permissions) { %i[view_work_packages] } - it "does not show the timer" do + it 'does not show the timer' do wp_view_a.visit! # Wait for another button to be present - expect(page).to have_css("#watch-button", wait: 10) + expect(page).to have_css('#watch-button', wait: 10) timer_button.expect_visible visible: false end end - context "when user has permission to add, but not edit or view" do + context 'when user has permission to add, but not edit or view' do let(:permissions) { %i[view_work_packages log_own_time] } - it_behaves_like "allows time tracking" + it_behaves_like 'allows time tracking' end - context "when user has permission to add and view but not edit" do + context 'when user has permission to add and view but not edit' do let(:permissions) { %i[view_work_packages log_own_time view_own_logged_time] } - it_behaves_like "allows time tracking" + it_behaves_like 'allows time tracking' end end diff --git a/modules/costs/spec/features/users_hourly_rates_spec.rb b/modules/costs/spec/features/users_hourly_rates_spec.rb index 963c3ce5fcd3..7d0ab9012675 100644 --- a/modules/costs/spec/features/users_hourly_rates_spec.rb +++ b/modules/costs/spec/features/users_hourly_rates_spec.rb @@ -26,80 +26,80 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "hourly rates on user edit", :js do +RSpec.describe 'hourly rates on user edit', :js do let(:user) { create(:admin) } def view_rates - visit edit_user_path(user, tab: "rates") + visit edit_user_path(user, tab: 'rates') end before do login_as user end - context "with no rates" do + context 'with no rates' do before do view_rates end - it "shows no data message" do - expect(page).to have_text I18n.t("no_results_title_text") + it 'shows no data message' do + expect(page).to have_text I18n.t('no_results_title_text') end end - context "with rates" do + context 'with rates' do let!(:rate) { create(:default_hourly_rate, user:) } before do view_rates end - it "shows the rates" do - expect(page).to have_text "Current rate".upcase + it 'shows the rates' do + expect(page).to have_text 'Current rate'.upcase end - describe "deleting all rates" do + describe 'deleting all rates' do before do - click_link "Update" # go to update view for rates + click_link 'Update' # go to update view for rates SeleniumHubWaiter.wait - find(".icon-delete").click # delete last existing rate - click_on "Save" # save change + find('.icon-delete').click # delete last existing rate + click_on 'Save' # save change end # regression test: clicking save used to result in a error - it "leads back to the now empty rate overview" do + it 'leads back to the now empty rate overview' do expect(page).to have_text /rate history/i - expect(page).to have_text I18n.t("no_results_title_text") + expect(page).to have_text I18n.t('no_results_title_text') - expect(page).to have_no_text "Current rate" + expect(page).to have_no_text 'Current rate' end end end - describe "updating rates as German user", driver: :firefox_de do - let(:user) { create(:admin, language: "de") } + describe 'updating rates as German user', driver: :firefox_de do + let(:user) { create(:admin, language: 'de') } let!(:rate) { create(:default_hourly_rate, user:, rate: 1.0) } - it "allows editing without reinterpreting the number (Regression #42219)" do + it 'allows editing without reinterpreting the number (Regression #42219)' do visit edit_hourly_rate_path(user) # Expect the german locale output - expect(page).to have_field("user[existing_rate_attributes][#{rate.id}][rate]", with: "1,00") + expect(page).to have_field("user[existing_rate_attributes][#{rate.id}][rate]", with: '1,00') - click_link "Satz hinzufügen" + click_link 'Satz hinzufügen' fill_in "user_new_rate_attributes_1_valid_from", with: (Time.zone.today + 1.day).iso8601 find("input#user_new_rate_attributes_1_valid_from").send_keys :escape - fill_in "user_new_rate_attributes_1_rate", with: "5,12" + fill_in "user_new_rate_attributes_1_rate", with: '5,12' - click_button "Speichern" + click_button 'Speichern' view_rates - expect(page).to have_css(".currency", text: "1,00") - expect(page).to have_css(".currency", text: "5,12") + expect(page).to have_css('.currency', text: '1,00') + expect(page).to have_css('.currency', text: '5,12') end end end diff --git a/modules/costs/spec/features/view_own_rates_spec.rb b/modules/costs/spec/features/view_own_rates_spec.rb index ae9d5b4b798f..89cc003c5ed6 100644 --- a/modules/costs/spec/features/view_own_rates_spec.rb +++ b/modules/costs/spec/features/view_own_rates_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') -RSpec.describe "Only see your own rates", :js do +RSpec.describe 'Only see your own rates', :js do let(:project) { work_package.project } let(:user) do create(:user, @@ -56,7 +56,7 @@ hours: 1.00) end let(:cost_type) do - type = create(:cost_type, name: "Translations") + type = create(:cost_type, name: 'Translations') create(:cost_rate, cost_type: type, rate: 7.00) type @@ -107,12 +107,12 @@ wp_page.ensure_page_loaded end - it "only displays own entries and rates" do + it 'only displays own entries and rates' do # All the values do not include the entries made by the other user - wp_page.expect_attributes spent_time: "1 h", - costs_by_type: "2 Translations", - overall_costs: "24.00 EUR", - labor_costs: "10.00 EUR", - material_costs: "14.00 EUR" + wp_page.expect_attributes spent_time: '1 h', + costs_by_type: '2 Translations', + overall_costs: '24.00 EUR', + labor_costs: '10.00 EUR', + material_costs: '14.00 EUR' end end diff --git a/modules/costs/spec/helpers/costs/number_helper_spec.rb b/modules/costs/spec/helpers/costs/number_helper_spec.rb index 757029578f54..b730277cc94b 100644 --- a/modules/costs/spec/helpers/costs/number_helper_spec.rb +++ b/modules/costs/spec/helpers/costs/number_helper_spec.rb @@ -26,54 +26,54 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../../spec_helper" +require File.dirname(__FILE__) + '/../../spec_helper' RSpec.describe Costs::NumberHelper do - describe "#parse_number_string" do - context "with a german local" do - it "parses a string with delimiter and separator correctly" do + describe '#parse_number_string' do + context 'with a german local' do + it 'parses a string with delimiter and separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("123.456,78")) .to eql "123456.78" end end - it "parses a string with space delimiter and separator correctly" do + it 'parses a string with space delimiter and separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("123 456,78")) .to eql "123456.78" end end - it "parses a string without delimiter and separator correctly" do + it 'parses a string without delimiter and separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("12345678")) .to eql "12345678" end end - it "parses a string without delimiter and with separator correctly" do + it 'parses a string without delimiter and with separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("123456,78")) .to eql "123456.78" end end - it "parses a string with delimiter and without separator correctly" do + it 'parses a string with delimiter and without separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("12.345.678")) .to eql "12345678" end end - it "parses a string with space delimiter and without separator correctly" do + it 'parses a string with space delimiter and without separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("12 345 678")) .to eql "12345678" end end - it "returns alphabetical values instead of a delimiter unchanged" do + it 'returns alphabetical values instead of a delimiter unchanged' do I18n.with_locale(:de) do expect(helper.parse_number_string("123456a78")) .to eql "123456a78" @@ -81,50 +81,50 @@ end end - context "with an english local" do - it "parses a string with delimiter and separator correctly" do + context 'with an english local' do + it 'parses a string with delimiter and separator correctly' do I18n.with_locale(:en) do expect(helper.parse_number_string("123,456.78")) .to eql "123456.78" end end - it "parses a string with space delimiter and separator correctly" do + it 'parses a string with space delimiter and separator correctly' do I18n.with_locale(:en) do expect(helper.parse_number_string("123 456.78")) .to eql "123456.78" end end - it "parses a string without delimiter and separator correctly" do + it 'parses a string without delimiter and separator correctly' do I18n.with_locale(:en) do expect(helper.parse_number_string("12345678")) .to eql "12345678" end end - it "parses a string without delimiter and with separator correctly" do + it 'parses a string without delimiter and with separator correctly' do I18n.with_locale(:en) do expect(helper.parse_number_string("123456.78")) .to eql "123456.78" end end - it "parses a string with delimiter and without separator correctly" do + it 'parses a string with delimiter and without separator correctly' do I18n.with_locale(:en) do expect(helper.parse_number_string("12,345,678")) .to eql "12345678" end end - it "parses a string with space delimiter and without separator correctly" do + it 'parses a string with space delimiter and without separator correctly' do I18n.with_locale(:en) do expect(helper.parse_number_string("12 345 678")) .to eql "12345678" end end - it "returns alphabetical values instead of a delimiter unchanged" do + it 'returns alphabetical values instead of a delimiter unchanged' do I18n.with_locale(:en) do expect(helper.parse_number_string("123456a78")) .to eql "123456a78" @@ -132,57 +132,57 @@ end end - context "for nil" do - it "is nil" do + context 'for nil' do + it 'is nil' do expect(helper.parse_number_string(nil)) .to be_nil end end - context "with a russian locale (Regression #37859)" do - it "parses a string with delimiter and separator correctly" do + context 'with a russian locale (Regression #37859)' do + it 'parses a string with delimiter and separator correctly' do I18n.with_locale(:ru) do expect(helper.parse_number_string("123.456,78")) .to eql "123456.78" end end - it "parses a string with space delimiter and separator correctly" do + it 'parses a string with space delimiter and separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("123 456,78")) .to eql "123456.78" end end - it "parses a string without delimiter and separator correctly" do + it 'parses a string without delimiter and separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("12345678")) .to eql "12345678" end end - it "parses a string without delimiter and with separator correctly" do + it 'parses a string without delimiter and with separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("123456,78")) .to eql "123456.78" end end - it "parses a string with delimiter and without separator correctly" do + it 'parses a string with delimiter and without separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("12.345.678")) .to eql "12345678" end end - it "parses a string with space delimiter and without separator correctly" do + it 'parses a string with space delimiter and without separator correctly' do I18n.with_locale(:de) do expect(helper.parse_number_string("12 345 678")) .to eql "12345678" end end - it "returns alphabetical values instead of a delimiter unchanged" do + it 'returns alphabetical values instead of a delimiter unchanged' do I18n.with_locale(:de) do expect(helper.parse_number_string("123456a78")) .to eql "123456a78" diff --git a/modules/costs/spec/lib/api/v3/cost_entries/aggregated_cost_entry_representer_spec.rb b/modules/costs/spec/lib/api/v3/cost_entries/aggregated_cost_entry_representer_spec.rb index 90b8a41f6429..e8c9084cf3bf 100644 --- a/modules/costs/spec/lib/api/v3/cost_entries/aggregated_cost_entry_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/cost_entries/aggregated_cost_entry_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CostEntries::AggregatedCostEntryRepresenter do include API::V3::Utilities::PathHelper @@ -36,17 +36,17 @@ subject { representer.to_json } - it "has a type" do - expect(subject).to be_json_eql("AggregatedCostEntry".to_json).at_path("_type") + it 'has a type' do + expect(subject).to be_json_eql('AggregatedCostEntry'.to_json).at_path('_type') end - it_behaves_like "has a titled link" do - let(:link) { "costType" } + it_behaves_like 'has a titled link' do + let(:link) { 'costType' } let(:href) { api_v3_paths.cost_type cost_entry.cost_type.id } let(:title) { cost_entry.cost_type.name } end - it "has spent units" do - expect(subject).to be_json_eql(cost_entry.units.to_json).at_path("spentUnits") + it 'has spent units' do + expect(subject).to be_json_eql(cost_entry.units.to_json).at_path('spentUnits') end end diff --git a/modules/costs/spec/lib/api/v3/cost_entries/cost_entry_representer_spec.rb b/modules/costs/spec/lib/api/v3/cost_entries/cost_entry_representer_spec.rb index 4a2c101bf9ca..0ca7ee6cd398 100644 --- a/modules/costs/spec/lib/api/v3/cost_entries/cost_entry_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/cost_entries/cost_entry_representer_spec.rb @@ -26,69 +26,69 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CostEntries::CostEntryRepresenter do include API::V3::Utilities::PathHelper let(:cost_entry) { build_stubbed(:cost_entry) } - let(:representer) { described_class.new(cost_entry, current_user: double("current_user")) } + let(:representer) { described_class.new(cost_entry, current_user: double('current_user')) } subject { representer.to_json } - it "has a type" do - expect(subject).to be_json_eql("CostEntry".to_json).at_path("_type") + it 'has a type' do + expect(subject).to be_json_eql('CostEntry'.to_json).at_path('_type') end - it_behaves_like "has an untitled link" do - let(:link) { "self" } + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.cost_entry cost_entry.id } end - it_behaves_like "has a titled link" do - let(:link) { "project" } + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project cost_entry.project.id } let(:title) { cost_entry.project.name } end - it_behaves_like "has a titled link" do - let(:link) { "user" } + it_behaves_like 'has a titled link' do + let(:link) { 'user' } let(:href) { api_v3_paths.user cost_entry.user_id } let(:title) { cost_entry.user.name } end - it_behaves_like "has a titled link" do - let(:link) { "costType" } + it_behaves_like 'has a titled link' do + let(:link) { 'costType' } let(:href) { api_v3_paths.cost_type cost_entry.cost_type.id } let(:title) { cost_entry.cost_type.name } end - it_behaves_like "has a titled link" do - let(:link) { "workPackage" } + it_behaves_like 'has a titled link' do + let(:link) { 'workPackage' } let(:href) { api_v3_paths.work_package cost_entry.work_package.id } let(:title) { cost_entry.work_package.subject } end - it "has an id" do - expect(subject).to be_json_eql(cost_entry.id.to_json).at_path("id") + it 'has an id' do + expect(subject).to be_json_eql(cost_entry.id.to_json).at_path('id') end - it "has spent units" do - expect(subject).to be_json_eql(cost_entry.units.to_json).at_path("spentUnits") + it 'has spent units' do + expect(subject).to be_json_eql(cost_entry.units.to_json).at_path('spentUnits') end - it_behaves_like "has ISO 8601 date only" do + it_behaves_like 'has ISO 8601 date only' do let(:date) { cost_entry.spent_on } - let(:json_path) { "spentOn" } + let(:json_path) { 'spentOn' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { cost_entry.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { cost_entry.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end diff --git a/modules/costs/spec/lib/api/v3/cost_entries/work_package_costs_by_type_representer_spec.rb b/modules/costs/spec/lib/api/v3/cost_entries/work_package_costs_by_type_representer_spec.rb index 728e7cc2704b..a12c4df90c56 100644 --- a/modules/costs/spec/lib/api/v3/cost_entries/work_package_costs_by_type_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/cost_entries/work_package_costs_by_type_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CostEntries::WorkPackageCostsByTypeRepresenter do include API::V3::Utilities::PathHelper @@ -66,25 +66,25 @@ cost_entries_B end - it "has a type" do - expect(subject).to be_json_eql("Collection".to_json).at_path("_type") + it 'has a type' do + expect(subject).to be_json_eql('Collection'.to_json).at_path('_type') end - it "has one element per type" do - expect(subject).to have_json_size(2).at_path("_embedded/elements") + it 'has one element per type' do + expect(subject).to have_json_size(2).at_path('_embedded/elements') end - it "indicates the cost types" do - elements = JSON.parse(subject)["_embedded"]["elements"] - types = elements.map { |entry| entry["_links"]["costType"]["href"] } + it 'indicates the cost types' do + elements = JSON.parse(subject)['_embedded']['elements'] + types = elements.map { |entry| entry['_links']['costType']['href'] } expect(types).to include(api_v3_paths.cost_type(cost_type_A.id)) expect(types).to include(api_v3_paths.cost_type(cost_type_B.id)) end - it "aggregates the units" do - elements = JSON.parse(subject)["_embedded"]["elements"] + it 'aggregates the units' do + elements = JSON.parse(subject)['_embedded']['elements'] units_by_type = elements.inject({}) do |hash, entry| - hash[entry["_links"]["costType"]["href"]] = entry["spentUnits"] + hash[entry['_links']['costType']['href']] = entry['spentUnits'] hash end diff --git a/modules/costs/spec/lib/api/v3/cost_types/cost_type_representer_spec.rb b/modules/costs/spec/lib/api/v3/cost_types/cost_type_representer_spec.rb index 26366d1ff24c..4ff5b4b3aa06 100644 --- a/modules/costs/spec/lib/api/v3/cost_types/cost_type_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/cost_types/cost_type_representer_spec.rb @@ -26,43 +26,43 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CostTypes::CostTypeRepresenter do include API::V3::Utilities::PathHelper let(:cost_type) { build_stubbed(:cost_type) } - let(:representer) { described_class.new(cost_type, current_user: double("current_user")) } + let(:representer) { described_class.new(cost_type, current_user: double('current_user')) } subject { representer.to_json } - it "has a type" do - expect(subject).to be_json_eql("CostType".to_json).at_path("_type") + it 'has a type' do + expect(subject).to be_json_eql('CostType'.to_json).at_path('_type') end - it_behaves_like "has a titled link" do - let(:link) { "self" } + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.cost_type cost_type.id } let(:title) { cost_type.name } end - it "has an id" do - expect(subject).to be_json_eql(cost_type.id.to_json).at_path("id") + it 'has an id' do + expect(subject).to be_json_eql(cost_type.id.to_json).at_path('id') end - it "has a name" do - expect(subject).to be_json_eql(cost_type.name.to_json).at_path("name") + it 'has a name' do + expect(subject).to be_json_eql(cost_type.name.to_json).at_path('name') end - it "has a unit" do - expect(subject).to be_json_eql(cost_type.unit.to_json).at_path("unit") + it 'has a unit' do + expect(subject).to be_json_eql(cost_type.unit.to_json).at_path('unit') end - it "has a pluralized unit" do - expect(subject).to be_json_eql(cost_type.unit_plural.to_json).at_path("unitPlural") + it 'has a pluralized unit' do + expect(subject).to be_json_eql(cost_type.unit_plural.to_json).at_path('unitPlural') end - it "indicates if it is the default" do - expect(subject).to be_json_eql(cost_type.default.to_json).at_path("isDefault") + it 'indicates if it is the default' do + expect(subject).to be_json_eql(cost_type.default.to_json).at_path('isDefault') end end diff --git a/modules/costs/spec/lib/api/v3/costs_api_user_permission_check_spec.rb b/modules/costs/spec/lib/api/v3/costs_api_user_permission_check_spec.rb index 97bbd1ff7878..fd9ae5bf6b41 100644 --- a/modules/costs/spec/lib/api/v3/costs_api_user_permission_check_spec.rb +++ b/modules/costs/spec/lib/api/v3/costs_api_user_permission_check_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CostsApiUserPermissionCheck do class CostsApiUserPermissionCheckTestClass @@ -69,188 +69,188 @@ def view_time_entries_allowed? subject { CostsApiUserPermissionCheckTestClass.new } - describe "#overall_costs_visible?" do + describe '#overall_costs_visible?' do describe :overall_costs_visible? do - shared_examples_for "not visible" do - it "is not visible" do + shared_examples_for 'not visible' do + it 'is not visible' do expect(subject).not_to be_overall_costs_visible end end - shared_examples_for "is visible" do - it "is not visible" do + shared_examples_for 'is visible' do + it 'is not visible' do expect(subject).to be_overall_costs_visible end end - context "lacks permissions" do - it_behaves_like "not visible" + context 'lacks permissions' do + it_behaves_like 'not visible' end - context "has view_time_entries and view_hourly_rates" do + context 'has view_time_entries and view_hourly_rates' do let(:view_time_entries) { true } let(:view_hourly_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_time_entries and view_own_hourly_rate" do + context 'has view_time_entries and view_own_hourly_rate' do let(:view_time_entries) { true } let(:view_own_hourly_rate) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_time_entries and view_own_hourly_rate" do + context 'has view_own_time_entries and view_own_hourly_rate' do let(:view_own_time_entries) { true } let(:view_own_hourly_rate) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_time_entries and view_hourly_rates" do + context 'has view_own_time_entries and view_hourly_rates' do let(:view_own_time_entries) { true } let(:view_hourly_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_cost_entries and view_cost_rates" do + context 'has view_cost_entries and view_cost_rates' do let(:view_cost_entries) { true } let(:view_cost_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_cost_entries and view_cost_rates" do + context 'has view_own_cost_entries and view_cost_rates' do let(:view_cost_entries) { true } let(:view_cost_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end end describe :labor_costs_visible? do - shared_examples_for "not visible" do - it "is not visible" do + shared_examples_for 'not visible' do + it 'is not visible' do expect(subject).not_to be_labor_costs_visible end end - shared_examples_for "is visible" do - it "is not visible" do + shared_examples_for 'is visible' do + it 'is not visible' do expect(subject).to be_labor_costs_visible end end - context "lacks permissions" do - it_behaves_like "not visible" + context 'lacks permissions' do + it_behaves_like 'not visible' end - context "has view_time_entries and view_hourly_rates" do + context 'has view_time_entries and view_hourly_rates' do let(:view_time_entries) { true } let(:view_hourly_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_time_entries and view_hourly_rates" do + context 'has view_own_time_entries and view_hourly_rates' do let(:view_own_time_entries) { true } let(:view_hourly_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end end describe :material_costs_visible? do - shared_examples_for "not visible" do - it "is not visible" do + shared_examples_for 'not visible' do + it 'is not visible' do expect(subject).not_to be_material_costs_visible end end - shared_examples_for "is visible" do - it "is not visible" do + shared_examples_for 'is visible' do + it 'is not visible' do expect(subject).to be_material_costs_visible end end - context "lacks permissions" do - it_behaves_like "not visible" + context 'lacks permissions' do + it_behaves_like 'not visible' end - context "has view_cost_entries and view_cost_rates" do + context 'has view_cost_entries and view_cost_rates' do let(:view_cost_entries) { true } let(:view_cost_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_cost_entries and view_own_cost_rates" do + context 'has view_own_cost_entries and view_own_cost_rates' do let(:view_own_cost_entries) { true } let(:view_cost_rates) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end end describe :costs_by_type_visible? do - shared_examples_for "not visible" do - it "is not visible" do + shared_examples_for 'not visible' do + it 'is not visible' do expect(subject).not_to be_costs_by_type_visible end end - shared_examples_for "is visible" do - it "is not visible" do + shared_examples_for 'is visible' do + it 'is not visible' do expect(subject).to be_costs_by_type_visible end end - context "lacks permissions" do - it_behaves_like "not visible" + context 'lacks permissions' do + it_behaves_like 'not visible' end - context "has view_costs_entries" do + context 'has view_costs_entries' do let(:view_cost_entries) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_time_entries" do + context 'has view_own_time_entries' do let(:view_own_cost_entries) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end end context :spent_time_visible do - shared_examples_for "not visible" do - it "is not visible" do + shared_examples_for 'not visible' do + it 'is not visible' do expect(subject).not_to be_spent_time_visible end end - shared_examples_for "is visible" do - it "is not visible" do + shared_examples_for 'is visible' do + it 'is not visible' do expect(subject).to be_spent_time_visible end end - context "lacks permissions" do - it_behaves_like "not visible" + context 'lacks permissions' do + it_behaves_like 'not visible' end - context "has view_costs_entries" do + context 'has view_costs_entries' do let(:view_time_entries) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end - context "has view_own_time_entries" do + context 'has view_own_time_entries' do let(:view_own_time_entries) { true } - it_behaves_like "is visible" + it_behaves_like 'is visible' end end end diff --git a/modules/costs/spec/lib/api/v3/path_helper_spec.rb b/modules/costs/spec/lib/api/v3/path_helper_spec.rb index b2273ad712bf..9b82261da053 100644 --- a/modules/costs/spec/lib/api/v3/path_helper_spec.rb +++ b/modules/costs/spec/lib/api/v3/path_helper_spec.rb @@ -26,32 +26,32 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::PathHelper do let(:helper) { Class.new.tap { |c| c.extend(described_class) }.api_v3_paths } - describe "#cost_entry" do + describe '#cost_entry' do subject { helper.cost_entry 42 } - it { is_expected.to eql("/api/v3/cost_entries/42") } + it { is_expected.to eql('/api/v3/cost_entries/42') } end - describe "#cost_entries_by_work_package" do + describe '#cost_entries_by_work_package' do subject { helper.cost_entries_by_work_package 42 } - it { is_expected.to eql("/api/v3/work_packages/42/cost_entries") } + it { is_expected.to eql('/api/v3/work_packages/42/cost_entries') } end - describe "#summarized_work_package_costs_by_type" do + describe '#summarized_work_package_costs_by_type' do subject { helper.summarized_work_package_costs_by_type 42 } - it { is_expected.to eql("/api/v3/work_packages/42/summarized_costs_by_type") } + it { is_expected.to eql('/api/v3/work_packages/42/summarized_costs_by_type') } end - describe "#cost_type" do + describe '#cost_type' do subject { helper.cost_type 42 } - it { is_expected.to eql("/api/v3/cost_types/42") } + it { is_expected.to eql('/api/v3/cost_types/42') } end end diff --git a/modules/costs/spec/lib/api/v3/time_entries/schemas/time_entry_schema_representer_spec.rb b/modules/costs/spec/lib/api/v3/time_entries/schemas/time_entry_schema_representer_spec.rb index 5cfe128a9ce8..2d07ba07d455 100644 --- a/modules/costs/spec/lib/api/v3/time_entries/schemas/time_entry_schema_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/time_entries/schemas/time_entry_schema_representer_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::TimeEntries::Schemas::TimeEntrySchemaRepresenter do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } - let(:self_link) { "/a/self/link" } + let(:self_link) { '/a/self/link' } let(:embedded) { true } let(:new_record) { true } let(:project) { build_stubbed(:project) } @@ -77,121 +77,121 @@ current_user:) end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do - expect(subject).to be_json_eql("Schema".to_json).at_path("_type") + describe '_type' do + it 'is indicated as Schema' do + expect(subject).to be_json_eql('Schema'.to_json).at_path('_type') end end - describe "id" do - let(:path) { "id" } + describe 'id' do + let(:path) { 'id' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } - let(:name) { I18n.t("attributes.id") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } + let(:name) { I18n.t('attributes.id') } let(:required) { true } let(:writable) { false } end end - describe "spentOn" do - let(:path) { "spentOn" } + describe 'spentOn' do + let(:path) { 'spentOn' } - it_behaves_like "has basic schema properties" do - let(:type) { "Date" } - let(:name) { TimeEntry.human_attribute_name("spent_on") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Date' } + let(:name) { TimeEntry.human_attribute_name('spent_on') } let(:required) { true } let(:writable) { true } end end - describe "hours" do - let(:path) { "hours" } + describe 'hours' do + let(:path) { 'hours' } - it_behaves_like "has basic schema properties" do - let(:type) { "Duration" } - let(:name) { TimeEntry.human_attribute_name("hours") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Duration' } + let(:name) { TimeEntry.human_attribute_name('hours') } let(:required) { true } let(:writable) { true } end end - describe "comment" do - let(:path) { "comment" } + describe 'comment' do + let(:path) { 'comment' } - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } - let(:name) { TimeEntry.human_attribute_name("comment") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } + let(:name) { TimeEntry.human_attribute_name('comment') } let(:required) { false } let(:writable) { true } end end - describe "createdAt" do - let(:path) { "createdAt" } + describe 'createdAt' do + let(:path) { 'createdAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { TimeEntry.human_attribute_name("created_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { TimeEntry.human_attribute_name('created_at') } let(:required) { true } let(:writable) { false } end end - describe "updatedAt" do - let(:path) { "updatedAt" } + describe 'updatedAt' do + let(:path) { 'updatedAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { TimeEntry.human_attribute_name("updated_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { TimeEntry.human_attribute_name('updated_at') } let(:required) { true } let(:writable) { false } end end - describe "user" do - let(:path) { "user" } + describe 'user' do + let(:path) { 'user' } - it_behaves_like "has basic schema properties" do - let(:type) { "User" } - let(:name) { TimeEntry.human_attribute_name("user") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'User' } + let(:name) { TimeEntry.human_attribute_name('user') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end end - describe "work_package" do - let(:path) { "workPackage" } + describe 'work_package' do + let(:path) { 'workPackage' } - it_behaves_like "has basic schema properties" do - let(:type) { "WorkPackage" } - let(:name) { TimeEntry.human_attribute_name("work_package") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'WorkPackage' } + let(:name) { TimeEntry.human_attribute_name('work_package') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - context "if being a new record" do + context 'if being a new record' do let(:new_record) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.time_entries_available_work_packages_on_create end end end - context "if being an existing record" do + context 'if being an existing record' do let(:new_record) { false } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.time_entries_available_work_packages_on_edit(contract.id) end @@ -200,41 +200,41 @@ end end - describe "activity" do - let(:path) { "activity" } + describe 'activity' do + let(:path) { 'activity' } - it_behaves_like "has basic schema properties" do - let(:type) { "TimeEntriesActivity" } - let(:name) { TimeEntry.human_attribute_name("activity") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'TimeEntriesActivity' } + let(:name) { TimeEntry.human_attribute_name('activity') } let(:has_default) { true } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "links to and embeds allowed values directly" do + it_behaves_like 'links to and embeds allowed values directly' do let(:hrefs) { [activity].map { |value| "/api/v3/time_entries/activities/#{value.id}" } } end end - describe "project" do - let(:path) { "project" } + describe 'project' do + let(:path) { 'project' } - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { TimeEntry.human_attribute_name("project") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { TimeEntry.human_attribute_name('project') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.time_entries_available_projects end @@ -242,27 +242,27 @@ end end - describe "user" do - let(:path) { "user" } + describe 'user' do + let(:path) { 'user' } - it_behaves_like "has basic schema properties" do - let(:type) { "User" } - let(:name) { TimeEntry.human_attribute_name("user") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'User' } + let(:name) { TimeEntry.human_attribute_name('user') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.path_for :principals, filters: [ - { status: { operator: "!", values: [Principal.statuses[:locked].to_s] } }, - { type: { operator: "=", values: ["User"] } }, - { member: { operator: "=", values: [project.id] } } + { status: { operator: '!', values: [Principal.statuses[:locked].to_s] } }, + { type: { operator: '=', values: ['User'] } }, + { member: { operator: '=', values: [project.id] } } ] end end @@ -270,7 +270,7 @@ end end - context "for a custom value" do + context 'for a custom value' do let(:custom_field) { build_stubbed(:time_entry_custom_field) } let(:path) { "customField#{custom_field.id}" } let(:writable_attributes) { [custom_field.attribute_name] } @@ -281,18 +281,18 @@ .and_return([custom_field]) end - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } let(:name) { custom_field.name } let(:required) { false } let(:writable) { true } end - context "with schema not writable" do + context 'with schema not writable' do let(:writable_attributes) { [] } - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } let(:name) { custom_field.name } let(:required) { false } let(:writable) { false } diff --git a/modules/costs/spec/lib/api/v3/time_entries/time_entries_activity_representer_rendering_spec.rb b/modules/costs/spec/lib/api/v3/time_entries/time_entries_activity_representer_rendering_spec.rb index 70059edac66a..35a6dc56128b 100644 --- a/modules/costs/spec/lib/api/v3/time_entries/time_entries_activity_representer_rendering_spec.rb +++ b/modules/costs/spec/lib/api/v3/time_entries/time_entries_activity_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::TimeEntries::TimeEntriesActivityRepresenter, "rendering" do +RSpec.describe API::V3::TimeEntries::TimeEntriesActivityRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:activity) do @@ -41,15 +41,15 @@ subject { representer.to_json } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.time_entries_activity activity.id } let(:title) { activity.name } end # returns the projects where it (and it's children) is active - it_behaves_like "has a link collection" do + it_behaves_like 'has a link collection' do let(:project1) { build_stubbed(:project) } let(:project2) { build_stubbed(:project) } @@ -61,7 +61,7 @@ project2]) end - let(:link) { "projects" } + let(:link) { 'projects' } let(:hrefs) do [ { @@ -77,24 +77,24 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "TimeEntriesActivity" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'TimeEntriesActivity' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { activity.id } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { activity.name } end - it_behaves_like "property", :position do + it_behaves_like 'property', :position do let(:value) { activity.position } end - it_behaves_like "property", :default do + it_behaves_like 'property', :default do let(:value) { activity.is_default } end end diff --git a/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_parsing_spec.rb b/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_parsing_spec.rb index e58f737819b2..a3c236f5b7bc 100644 --- a/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_parsing_spec.rb +++ b/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_parsing_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::TimeEntries::TimeEntryRepresenter, "parsing" do +RSpec.describe API::V3::TimeEntries::TimeEntryRepresenter, 'parsing' do include API::V3::Utilities::PathHelper let(:time_entry) do build_stubbed(:time_entry, - comments: "blubs", + comments: 'blubs', spent_on: Date.today - 3.days, created_at: DateTime.now - 6.hours, updated_at: DateTime.now - 3.hours, @@ -76,7 +76,7 @@ "href" => api_v3_paths.user(user2.id) } }, - "hours" => "PT5H", + "hours" => 'PT5H', "comment" => { "raw" => "some comment" }, @@ -93,33 +93,33 @@ .and_return([text_custom_field, user_custom_field]) end - describe "_links" do - context "activity" do - it "updates the activity" do + describe '_links' do + context 'activity' do + it 'updates the activity' do time_entry = representer.from_hash(hash) expect(time_entry.activity_id) .to eql(activity2.id) end end - context "project" do - it "updates the project" do + context 'project' do + it 'updates the project' do time_entry = representer.from_hash(hash) expect(time_entry.project_id) .to eql(project2.id) end end - context "workPackage" do - it "updates the work_package" do + context 'workPackage' do + it 'updates the work_package' do time_entry = representer.from_hash(hash) expect(time_entry.work_package_id) .to eql(work_package2.id) end end - context "linked custom field" do - it "updates the custom value" do + context 'linked custom field' do + it 'updates the custom value' do time_entry = representer.from_hash(hash) expect(time_entry.custom_field_values.detect { |cv| cv.custom_field_id == user_custom_field.id }.value) @@ -128,30 +128,30 @@ end end - describe "properties" do - context "spentOn" do - it "updates spent_on" do + describe 'properties' do + context 'spentOn' do + it 'updates spent_on' do time_entry = representer.from_hash(hash) expect(time_entry.spent_on) .to eql(Date.parse("2017-07-28")) end end - context "hours" do - it "updates hours" do + context 'hours' do + it 'updates hours' do time_entry = representer.from_hash(hash) expect(time_entry.hours) .to be(5.0) end - context "with null value" do + context 'with null value' do let(:hash) do { "hours" => nil } end - it "updates hours" do + it 'updates hours' do time_entry = representer.from_hash(hash) expect(time_entry.hours) .to be_nil @@ -159,16 +159,16 @@ end end - context "comment" do - it "updates comment" do + context 'comment' do + it 'updates comment' do time_entry = representer.from_hash(hash) expect(time_entry.comments) - .to eql("some comment") + .to eql('some comment') end end - context "property custom field" do - it "updates the custom value" do + context 'property custom field' do + it 'updates the custom value' do time_entry = representer.from_hash(hash) expect(time_entry.custom_field_values.detect { |cv| cv.custom_field_id == text_custom_field.id }.value) diff --git a/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_rendering_spec.rb b/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_rendering_spec.rb index 14a31c07a416..156c53449aa3 100644 --- a/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_rendering_spec.rb +++ b/modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_rendering_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::TimeEntries::TimeEntryRepresenter, "rendering" do +RSpec.describe API::V3::TimeEntries::TimeEntryRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:time_entry) do build_stubbed(:time_entry, - comments: "blubs", + comments: 'blubs', spent_on: Date.today, created_at: DateTime.now - 6.hours, updated_at: DateTime.now - 3.hours, @@ -68,52 +68,52 @@ .and_return([]) end - include_context "eager loaded work package representer" + include_context 'eager loaded work package representer' - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.time_entry time_entry.id } end - it_behaves_like "has a titled link" do - let(:link) { "project" } + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project project.id } let(:title) { project.name } end - it_behaves_like "has a titled link" do - let(:link) { "workPackage" } + it_behaves_like 'has a titled link' do + let(:link) { 'workPackage' } let(:href) { api_v3_paths.work_package work_package.id } let(:title) { work_package.subject } end - it_behaves_like "has a titled link" do - let(:link) { "user" } + it_behaves_like 'has a titled link' do + let(:link) { 'user' } let(:href) { api_v3_paths.user user.id } let(:title) { user.name } end - it_behaves_like "has a titled link" do - let(:link) { "activity" } + it_behaves_like 'has a titled link' do + let(:link) { 'activity' } let(:href) { api_v3_paths.time_entries_activity activity.id } let(:title) { activity.name } end - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) { api_v3_paths.time_entry_schema } end - context "custom value" do + context 'custom value' do let(:custom_field) do build_stubbed(:time_entry_custom_field, :user) end let(:custom_value) do - double("CustomValue", + double('CustomValue', custom_field:, customized: time_entry, - value: "1", + value: '1', typed_value: user) end let(:user) do @@ -135,131 +135,131 @@ .and_return(custom_value) end - it "has the user linked" do + it 'has the user linked' do expect(subject) .to be_json_eql(api_v3_paths.user(custom_value.value).to_json) .at_path("_links/customField#{custom_field.id}/href") end end - context "when allowed to update" do - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + context 'when allowed to update' do + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.time_entry(time_entry.id) } let(:method) { :patch } end - it_behaves_like "has an untitled link" do - let(:link) { "update" } + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.time_entry_form(time_entry.id) } let(:method) { :post } end - it_behaves_like "has an untitled link" do - let(:link) { "delete" } + it_behaves_like 'has an untitled link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.time_entry(time_entry.id) } let(:method) { :delete } end end - context "when not allowed to update" do + context 'when not allowed to update' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end - it_behaves_like "has no link" do - let(:link) { "update" } + it_behaves_like 'has no link' do + let(:link) { 'update' } end - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end - context "when allowed to edit own and it is own" do + context 'when allowed to edit own and it is own' do let(:permissions) { [:edit_own_time_entries] } - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.time_entry(time_entry.id) } let(:method) { :patch } end - it_behaves_like "has an untitled link" do - let(:link) { "delete" } + it_behaves_like 'has an untitled link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.time_entry(time_entry.id) } let(:method) { :delete } end end - context "when allowed to edit own and it is not own" do + context 'when allowed to edit own and it is not own' do let(:permissions) { [:edit_own_time_entries] } let(:current_user) { build_stubbed(:user) } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "TimeEntry" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'TimeEntry' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { time_entry.id } end - it_behaves_like "formattable property", :comment do + it_behaves_like 'formattable property', :comment do let(:value) { time_entry.comments } end - context "with an empty comment" do + context 'with an empty comment' do let(:time_entry) { build_stubbed(:time_entry) } - it_behaves_like "formattable property", :comment do + it_behaves_like 'formattable property', :comment do let(:value) { time_entry.comments } end end - it_behaves_like "date property", :spentOn do + it_behaves_like 'date property', :spentOn do let(:value) { time_entry.spent_on } end - context "hours" do - it_behaves_like "property", :hours do - let(:value) { "PT5H" } + context 'hours' do + it_behaves_like 'property', :hours do + let(:value) { 'PT5H' } end - context "if hours are nil" do + context 'if hours are nil' do let(:hours) { nil } - it_behaves_like "property", :hours do + it_behaves_like 'property', :hours do let(:value) { nil } end end end - it_behaves_like "datetime property", :createdAt do + it_behaves_like 'datetime property', :createdAt do let(:value) { time_entry.created_at } end - it_behaves_like "datetime property", :updatedAt do + it_behaves_like 'datetime property', :updatedAt do let(:value) { time_entry.updated_at } end - context "custom value" do + context 'custom value' do let(:custom_field) { build_stubbed(:time_entry_custom_field) } let(:custom_value) do CustomValue.new(custom_field:, - value: "1234", + value: '1234', customized: time_entry) end diff --git a/modules/costs/spec/lib/api/v3/work_packages/work_package_representer_spec.rb b/modules/costs/spec/lib/api/v3/work_packages/work_package_representer_spec.rb index 0023e618db17..2ac6a0fee9d6 100644 --- a/modules/costs/spec/lib/api/v3/work_packages/work_package_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/work_packages/work_package_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::WorkPackageRepresenter do include API::V3::Utilities::PathHelper @@ -51,7 +51,7 @@ units: 3, spent_on: Time.zone.today, user:, - comments: "Entry 1") + comments: 'Entry 1') end let(:cost_entry_2) do create(:cost_entry, @@ -60,7 +60,7 @@ units: 3, spent_on: Time.zone.today, user:, - comments: "Entry 2") + comments: 'Entry 2') end let(:work_package) do @@ -79,31 +79,31 @@ subject(:generated) { representer.to_json } - describe "generation" do + describe 'generation' do before do cost_entry_1 cost_entry_2 end - describe "work_package" do + describe 'work_package' do # specifying as it used to be different - it { is_expected.to have_json_path("spentTime") } + it { is_expected.to have_json_path('spentTime') } - it { is_expected.not_to have_json_path("spentHours") } + it { is_expected.not_to have_json_path('spentHours') } - it { is_expected.to have_json_path("overallCosts") } + it { is_expected.to have_json_path('overallCosts') } - it_behaves_like "has an untitled link" do - let(:link) { "costsByType" } + it_behaves_like 'has an untitled link' do + let(:link) { 'costsByType' } let(:href) { api_v3_paths.summarized_work_package_costs_by_type work_package.id } end - it "embeds the costsByType" do - expect(subject).to have_json_path("_embedded/costsByType") + it 'embeds the costsByType' do + expect(subject).to have_json_path('_embedded/costsByType') end - describe "spentTime" do - context "time entry with single hour" do + describe 'spentTime' do + context 'time entry with single hour' do let(:time_entry) do create(:time_entry, project: work_package.project, @@ -113,10 +113,10 @@ before { time_entry } - it { is_expected.to be_json_eql("PT1H".to_json).at_path("spentTime") } + it { is_expected.to be_json_eql('PT1H'.to_json).at_path('spentTime') } end - context "time entry with multiple hours" do + context 'time entry with multiple hours' do let(:time_entry) do create(:time_entry, project: work_package.project, @@ -126,16 +126,16 @@ before { time_entry } - it { is_expected.to be_json_eql("P1DT18H30M".to_json).at_path("spentTime") } + it { is_expected.to be_json_eql('P1DT18H30M'.to_json).at_path('spentTime') } end - context "no view_time_entries permission" do + context 'no view_time_entries permission' do let(:additional_permissions) { [] } - it { is_expected.not_to have_json_path("spentTime") } + it { is_expected.not_to have_json_path('spentTime') } end - context "only view_own_time_entries permission" do + context 'only view_own_time_entries permission' do let(:user2) do create(:user, member_with_permissions: { project => %i[view_own_time_entries view_work_packages] }) end @@ -160,166 +160,166 @@ allow(User).to receive(:current).and_return(user2) end - it { is_expected.to be_json_eql("PT2H".to_json).at_path("spentTime") } + it { is_expected.to be_json_eql('PT2H'.to_json).at_path('spentTime') } end - context "no time entry" do - it { is_expected.to be_json_eql("PT0S".to_json).at_path("spentTime") } + context 'no time entry' do + it { is_expected.to be_json_eql('PT0S'.to_json).at_path('spentTime') } end end - describe "laborCosts" do + describe 'laborCosts' do before do allow(work_package).to receive(:labor_costs).and_return(6000.0) end - context "with the :view_hourly_rates and :view_time_entries permission" do + context 'with the :view_hourly_rates and :view_time_entries permission' do let(:additional_permissions) { %i[view_hourly_rates view_time_entries] } - it "is expected to have a laborCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("laborCosts") + it 'is expected to have a laborCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('laborCosts') end end - context "with the :view_own_hourly_rate and :view_own_time_entries permission" do + context 'with the :view_own_hourly_rate and :view_own_time_entries permission' do let(:additional_permissions) { %i[view_own_hourly_rate view_own_time_entries] } - it "is expected to have a laborCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("laborCosts") + it 'is expected to have a laborCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('laborCosts') end end - context "without the user having permission" do - it "has no attribute" do - expect(subject).not_to have_json_path("laborCosts") + context 'without the user having permission' do + it 'has no attribute' do + expect(subject).not_to have_json_path('laborCosts') end end end - describe "materialCosts" do + describe 'materialCosts' do before do allow(work_package).to receive(:material_costs).and_return(6000.0) end - context "with the :view_own_cost_entries and :view_cost_rates permission" do + context 'with the :view_own_cost_entries and :view_cost_rates permission' do let(:additional_permissions) { %i[view_own_cost_entries view_cost_rates] } - it "is expected to have a materialCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("materialCosts") + it 'is expected to have a materialCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('materialCosts') end end - context "with the :view_cost_entries and :view_cost_rates permission" do + context 'with the :view_cost_entries and :view_cost_rates permission' do let(:additional_permissions) { %i[view_cost_entries view_cost_rates] } - it "is expected to have a materialCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("materialCosts") + it 'is expected to have a materialCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('materialCosts') end end - context "without the user having permission" do + context 'without the user having permission' do let(:additional_permissions) { [] } - it "has no attribute" do - expect(subject).not_to have_json_path("materialCosts") + it 'has no attribute' do + expect(subject).not_to have_json_path('materialCosts') end end end - describe "overallCosts" do + describe 'overallCosts' do before do allow(work_package).to receive(:overall_costs).and_return(6000.0) end - context "with the :view_hourly_rates and :view_time_entries permission" do + context 'with the :view_hourly_rates and :view_time_entries permission' do let(:additional_permissions) { %i[view_hourly_rates view_time_entries] } - it "is expected to have a overallCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("overallCosts") + it 'is expected to have a overallCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('overallCosts') end end - context "with the :view_own_hourly_rate and :view_own_time_entries permission" do + context 'with the :view_own_hourly_rate and :view_own_time_entries permission' do let(:additional_permissions) { %i[view_own_time_entries view_own_hourly_rate] } - it "is expected to have a overallCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("overallCosts") + it 'is expected to have a overallCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('overallCosts') end end - context "with the :view_own_cost_entries and :view_cost_rates permission" do + context 'with the :view_own_cost_entries and :view_cost_rates permission' do let(:additional_permissions) { %i[view_own_cost_entries view_cost_rates] } - it "is expected to have a overallCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("overallCosts") + it 'is expected to have a overallCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('overallCosts') end end - context "with the :view_cost_entries and :view_cost_rates permission" do + context 'with the :view_cost_entries and :view_cost_rates permission' do let(:additional_permissions) { %i[view_cost_entries view_cost_rates] } - it "is expected to have a overallCosts attribute" do - expect(subject).to be_json_eql("6,000.00 EUR".to_json).at_path("overallCosts") + it 'is expected to have a overallCosts attribute' do + expect(subject).to be_json_eql('6,000.00 EUR'.to_json).at_path('overallCosts') end end - context "without the user having permission" do + context 'without the user having permission' do let(:additional_permissions) { [] } - it "has no attribute" do - expect(subject).not_to have_json_path("overallCosts") + it 'has no attribute' do + expect(subject).not_to have_json_path('overallCosts') end end end end end - describe "_links" do - describe "move" do - it_behaves_like "has a titled action link" do - let(:link) { "logCosts" } + describe '_links' do + describe 'move' do + it_behaves_like 'has a titled action link' do + let(:link) { 'logCosts' } let(:href) { new_work_packages_cost_entry_path(work_package) } let(:permission) { %i(log_costs log_own_costs) } let(:title) { "Log costs on #{work_package.subject}" } end end - describe "timeEntries" do - context "with the :view_time_entries permission" do + describe 'timeEntries' do + context 'with the :view_time_entries permission' do let(:additional_permissions) { %i[view_time_entries] } - it "has timeEntries link" do - expect(subject).to have_json_path("_links/timeEntries/href") + it 'has timeEntries link' do + expect(subject).to have_json_path('_links/timeEntries/href') end end - context "with the :view_own_time_entries permission" do + context 'with the :view_own_time_entries permission' do let(:additional_permissions) { %i[view_own_time_entries] } - it "has timeEnries link" do - expect(subject).to have_json_path("_links/timeEntries/href") + it 'has timeEnries link' do + expect(subject).to have_json_path('_links/timeEntries/href') end end end end - describe "costs module disabled" do + describe 'costs module disabled' do before do allow(work_package).to receive(:costs_enabled?).and_return false end - describe "work_package" do - it { is_expected.to have_json_path("spentTime") } + describe 'work_package' do + it { is_expected.to have_json_path('spentTime') } - it { is_expected.not_to have_json_path("spentHours") } + it { is_expected.not_to have_json_path('spentHours') } - describe "embedded" do - it { is_expected.not_to have_json_path("_embedded/summarizedCostEntries") } + describe 'embedded' do + it { is_expected.not_to have_json_path('_embedded/summarizedCostEntries') } end end - describe "_links" do - it { is_expected.not_to have_json_path("_links/log_costs") } + describe '_links' do + it { is_expected.not_to have_json_path('_links/log_costs') } end end end diff --git a/modules/costs/spec/lib/api/v3/work_packages/work_package_schema_representer_spec.rb b/modules/costs/spec/lib/api/v3/work_packages/work_package_schema_representer_spec.rb index 6604f7bf71e1..a13c2887d09b 100644 --- a/modules/costs/spec/lib/api/v3/work_packages/work_package_schema_representer_spec.rb +++ b/modules/costs/spec/lib/api/v3/work_packages/work_package_schema_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::Schema::WorkPackageSchemaRepresenter do let(:custom_field) { build(:custom_field) } @@ -54,115 +54,115 @@ subject { representer.to_json } - describe "overallCosts" do - context "has the permissions" do + describe 'overallCosts' do + context 'has the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(true) end - it_behaves_like "has basic schema properties" do - let(:path) { "overallCosts" } - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.work_package.overall_costs") } + it_behaves_like 'has basic schema properties' do + let(:path) { 'overallCosts' } + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.work_package.overall_costs') } let(:required) { false } let(:writable) { false } end end - context "lacks the permissions" do + context 'lacks the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(false) end - it { is_expected.not_to have_json_path("overallCosts") } + it { is_expected.not_to have_json_path('overallCosts') } end end - describe "laborCosts" do - context "has the permissions" do + describe 'laborCosts' do + context 'has the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(true) end - it_behaves_like "has basic schema properties" do - let(:path) { "laborCosts" } - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.work_package.labor_costs") } + it_behaves_like 'has basic schema properties' do + let(:path) { 'laborCosts' } + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.work_package.labor_costs') } let(:required) { false } let(:writable) { false } end end - context "lacks the permissions" do + context 'lacks the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(false) end - it { is_expected.not_to have_json_path("laborCosts") } + it { is_expected.not_to have_json_path('laborCosts') } end end - describe "materialCosts" do - context "has the permissions" do + describe 'materialCosts' do + context 'has the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(true) end - it_behaves_like "has basic schema properties" do - let(:path) { "materialCosts" } - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.work_package.material_costs") } + it_behaves_like 'has basic schema properties' do + let(:path) { 'materialCosts' } + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.work_package.material_costs') } let(:required) { false } let(:writable) { false } end end - context "lacks the permissions" do + context 'lacks the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(false) end - it { is_expected.not_to have_json_path("materialCosts") } + it { is_expected.not_to have_json_path('materialCosts') } end end - describe "costsByType" do - context "has the permissions" do + describe 'costsByType' do + context 'has the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(true) end - it_behaves_like "has basic schema properties" do - let(:path) { "costsByType" } - let(:type) { "Collection" } - let(:name) { I18n.t("activerecord.attributes.work_package.spent_units") } + it_behaves_like 'has basic schema properties' do + let(:path) { 'costsByType' } + let(:type) { 'Collection' } + let(:name) { I18n.t('activerecord.attributes.work_package.spent_units') } let(:required) { false } let(:writable) { false } end end - context "lacks the permissions" do + context 'lacks the permissions' do before do allow(project) .to receive(:costs_enabled?) .and_return(false) end - it { is_expected.not_to have_json_path("costsByType") } + it { is_expected.not_to have_json_path('costsByType') } end end end diff --git a/modules/costs/spec/lib/costs/query_currency_select_spec.rb b/modules/costs/spec/lib/costs/query_currency_select_spec.rb index 7973c40df8ed..dd706c91a10b 100644 --- a/modules/costs/spec/lib/costs/query_currency_select_spec.rb +++ b/modules/costs/spec/lib/costs/query_currency_select_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Costs::QueryCurrencySelect, type: :model do let(:project) do @@ -40,51 +40,51 @@ let(:costs_enabled) { true } let(:column_name) { :material_costs } - describe ".instances" do + describe '.instances' do subject { described_class.instances(project).map(&:name) } - context "with costs enabled" do - it "returns the four costs columns" do + context 'with costs enabled' do + it 'returns the four costs columns' do expect(subject) .to match_array %i[budget material_costs labor_costs overall_costs] end end - context "with costs disabled" do + context 'with costs disabled' do let(:costs_enabled) { false } - it "returns no columns" do + it 'returns no columns' do expect(subject) .to be_empty end end - context "with no context" do - it "returns the four costs columns" do + context 'with no context' do + it 'returns the four costs columns' do expect(subject) .to match_array %i[budget material_costs labor_costs overall_costs] end end end - context "material_costs" do - describe "#summable?" do - it "is true" do + context 'material_costs' do + describe '#summable?' do + it 'is true' do expect(instance) .to be_summable end end - describe "#summable" do - it "is callable" do + describe '#summable' do + it 'is callable' do expect(instance.summable) .to respond_to(:call) end # Not testing the results here, this is done by an integration test - it "returns an AR scope that has an id and a material_costs column" do - query = double("query") - result = double("result") + it 'returns an AR scope that has an id and a material_costs column' do + query = double('query') + result = double('result') allow(query) .to receive(:results) @@ -96,7 +96,7 @@ allow(query) .to receive(:group_by_statement) - .and_return("author_id") + .and_return('author_id') expect(ActiveRecord::Base.connection.select_all(instance.summable.(query, true).to_sql).columns) .to match_array %w(id material_costs) @@ -104,26 +104,26 @@ end end - context "labor_costs" do + context 'labor_costs' do let(:column_name) { :labor_costs } - describe "#summable?" do - it "is true" do + describe '#summable?' do + it 'is true' do expect(instance) .to be_summable end end - describe "#summable" do - it "is callable" do + describe '#summable' do + it 'is callable' do expect(instance.summable) .to respond_to(:call) end # Not testing the results here, this is done by an integration test - it "returns an AR scope that has an id and a labor_costs column" do - query = double("query") - result = double("result") + it 'returns an AR scope that has an id and a labor_costs column' do + query = double('query') + result = double('result') allow(query) .to receive(:results) @@ -135,7 +135,7 @@ allow(query) .to receive(:group_by_statement) - .and_return("author_id") + .and_return('author_id') expect(ActiveRecord::Base.connection.select_all(instance.summable.(query, true).to_sql).columns) .to match_array %w(id labor_costs) diff --git a/modules/costs/spec/models/cost_entry_spec.rb b/modules/costs/spec/models/cost_entry_spec.rb index b1b593679186..9bcccb733a3a 100644 --- a/modules/costs/spec/models/cost_entry_spec.rb +++ b/modules/costs/spec/models/cost_entry_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') RSpec.describe CostEntry do include Cost::PluginSpecHelper @@ -54,7 +54,7 @@ spent_on: date, units:, user:, - comments: "lorem") + comments: 'lorem') end let(:cost_entry2) do @@ -64,7 +64,7 @@ spent_on: date, units:, user:, - comments: "lorem") + comments: 'lorem') end let(:cost_type) do @@ -97,8 +97,8 @@ let(:units) { 5.0 } let(:date) { Date.today } - describe "class" do - describe "#visible" do + describe 'class' do + describe '#visible' do describe "WHEN having the view_cost_entries permission WHEN querying for a project WHEN a cost entry from another user is defined" do @@ -149,20 +149,20 @@ end end - describe "instance" do - describe "#costs" do + describe 'instance' do + describe '#costs' do let(:fourth_rate) do build(:cost_rate, valid_from: date - 1.day, rate: 10000.0, cost_type:) end - describe "WHEN updating the number of units" do + describe 'WHEN updating the number of units' do before do cost_entry.spent_on = first_rate.valid_from + 1.day end - it "updates costs" do + it 'updates costs' do 6.times do |units| cost_entry.units = units cost_entry.save! @@ -171,7 +171,7 @@ end end - describe "WHEN a new rate is added at the end" do + describe 'WHEN a new rate is added at the end' do before do cost_entry.save! fourth_rate.save! @@ -181,7 +181,7 @@ it { expect(cost_entry.costs).to eq(fourth_rate.rate * cost_entry.units) } end - describe "WHEN a new rate is added for the future" do + describe 'WHEN a new rate is added for the future' do before do cost_entry.save! fourth_rate.valid_from = date + 1.day @@ -192,7 +192,7 @@ it { expect(cost_entry.costs).to eq(third_rate.rate * cost_entry.units) } end - describe "WHEN a new rate is added in between" do + describe 'WHEN a new rate is added in between' do before do cost_entry.save! fourth_rate.valid_from = date - 3.days @@ -203,7 +203,7 @@ it { expect(cost_entry.costs).to eq(third_rate.rate * cost_entry.units) } end - describe "WHEN a rate is destroyed" do + describe 'WHEN a rate is destroyed' do before do cost_entry.save! third_rate.destroy @@ -223,29 +223,29 @@ it { expect(cost_entry.costs).to eq(cost_entry.units * first_rate.rate) } end - describe "WHEN spent on is changed" do + describe 'WHEN spent on is changed' do before do cost_type.save! cost_entry.save! end - it "takes the then active rate to calculate" do + it 'takes the then active rate to calculate' do (5.days.ago.to_date..Date.today).each do |time| cost_entry.spent_on = time cost_entry.save! rate = CostRate - .where(["cost_type_id = ? AND valid_from <= ?", + .where(['cost_type_id = ? AND valid_from <= ?', cost_entry.cost_type.id, cost_entry.spent_on]) - .order(Arel.sql("valid_from DESC")).first.rate + .order(Arel.sql('valid_from DESC')).first.rate expect(cost_entry.costs).to eq(cost_entry.units * rate) end end end end - describe "#overridden_costs" do - describe "WHEN overridden costs are seet" do + describe '#overridden_costs' do + describe 'WHEN overridden costs are seet' do let(:value) { rand(500) } before do @@ -256,8 +256,8 @@ end end - describe "#real_costs" do - describe "WHEN overridden cost are set" do + describe '#real_costs' do + describe 'WHEN overridden cost are set' do let(:value) { rand(500) } before do @@ -268,20 +268,20 @@ end end - describe "#valid" do + describe '#valid' do before do cost_entry.save! end it { expect(cost_entry).to be_valid } - describe "WHEN no cost_type is provided" do + describe 'WHEN no cost_type is provided' do before { cost_entry.cost_type = nil } it { expect(cost_entry).not_to be_valid } end - describe "WHEN no project is provided" do + describe 'WHEN no project is provided' do before do cost_entry.project = nil # unfortunately the project get's set to the work_package's project if no project is provided @@ -292,31 +292,31 @@ it { expect(cost_entry).not_to be_valid } end - describe "WHEN no work_package is provided" do + describe 'WHEN no work_package is provided' do before { cost_entry.work_package = nil } it { expect(cost_entry).not_to be_valid } end - describe "WHEN the work_package is not in the project" do + describe 'WHEN the work_package is not in the project' do before { cost_entry.work_package = work_package2 } it { expect(cost_entry).not_to be_valid } end - describe "WHEN no units are provided" do + describe 'WHEN no units are provided' do before { cost_entry.units = nil } it { expect(cost_entry).not_to be_valid } end - describe "WHEN no spent_on is provided" do + describe 'WHEN no spent_on is provided' do before { cost_entry.spent_on = nil } it { expect(cost_entry).not_to be_valid } end - describe "WHEN no user is provided" do + describe 'WHEN no user is provided' do before { cost_entry.user = nil } it { expect(cost_entry).not_to be_valid } @@ -339,15 +339,15 @@ it { expect(cost_entry).not_to be_valid } end - describe "WHEN the cost_type is deleted" do + describe 'WHEN the cost_type is deleted' do before { cost_type.deleted_at = Date.new } it { expect(cost_entry).not_to be_valid } end end - describe "#user" do - describe "WHEN a non existing user is provided (i.e. the user has been deleted)" do + describe '#user' do + describe 'WHEN a non existing user is provided (i.e. the user has been deleted)' do before do cost_entry.save! user.destroy @@ -356,25 +356,25 @@ it { expect(cost_entry.reload.user).to eq(DeletedUser.first) } end - describe "WHEN an existing user is provided" do + describe 'WHEN an existing user is provided' do it { expect(cost_entry.user).to eq(user) } end end - describe "#logged_by" do - it "validates" do + describe '#logged_by' do + it 'validates' do cost_entry.logged_by = nil expect(cost_entry).not_to be_valid expect(cost_entry.errors[:logged_by_id]).to be_present end - it "sets logged_by from current user" do + it 'sets logged_by from current user' do entry = User.execute_as(user2) { described_class.new logged_by: user } expect(entry.logged_by).to eq(user2) end end - describe "#editable_by?" do + describe '#editable_by?' do describe "WHEN the user has the edit_cost_entries permission WHEN the cost entry is not created by the user" do before do @@ -429,7 +429,7 @@ end end - describe "#creatable_by?" do + describe '#creatable_by?' do describe "WHEN the user has the log costs permission WHEN the cost entry is not associated to the user" do before do @@ -476,7 +476,7 @@ end end - describe "#costs_visible_by?" do + describe '#costs_visible_by?' do describe "WHEN the user has the view_cost_rates permission WHEN the cost entry is not associated to the user" do before do diff --git a/modules/costs/spec/models/cost_type_spec.rb b/modules/costs/spec/models/cost_type_spec.rb index 2197cfc536fd..3a75cace79a7 100644 --- a/modules/costs/spec/models/cost_type_spec.rb +++ b/modules/costs/spec/models/cost_type_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') RSpec.describe CostType do let(:klass) { CostType } let(:cost_type) do - klass.new name: "ct1", - unit: "singular", - unit_plural: "plural" + klass.new name: 'ct1', + unit: 'singular', + unit_plural: 'plural' end before do @@ -44,9 +44,9 @@ CostType.destroy_all end - describe "class" do - describe "active" do - describe "WHEN a CostType instance is deleted" do + describe 'class' do + describe 'active' do + describe 'WHEN a CostType instance is deleted' do before do cost_type.deleted_at = Time.now cost_type.save! @@ -55,7 +55,7 @@ it { expect(klass.active.size).to eq(0) } end - describe "WHEN a CostType instance is not deleted" do + describe 'WHEN a CostType instance is not deleted' do before do cost_type.save! end diff --git a/modules/costs/spec/models/default_hourly_rate_spec.rb b/modules/costs/spec/models/default_hourly_rate_spec.rb index cded19f96852..f562c0150b80 100644 --- a/modules/costs/spec/models/default_hourly_rate_spec.rb +++ b/modules/costs/spec/models/default_hourly_rate_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe DefaultHourlyRate do let(:project) { create(:project) } @@ -36,8 +36,8 @@ user:) end - describe "#user" do - describe "WHEN an existing user is provided" do + describe '#user' do + describe 'WHEN an existing user is provided' do before do rate.user = user rate.save! @@ -46,7 +46,7 @@ it { expect(rate.user).to eq(user) } end - describe "WHEN a non existing user is provided (i.e. the user is deleted)" do + describe 'WHEN a non existing user is provided (i.e. the user is deleted)' do before do rate.user = user rate.save! diff --git a/modules/costs/spec/models/hourly_rate_spec.rb b/modules/costs/spec/models/hourly_rate_spec.rb index 24d1c776c455..f877145e702b 100644 --- a/modules/costs/spec/models/hourly_rate_spec.rb +++ b/modules/costs/spec/models/hourly_rate_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe HourlyRate do let(:project) { create(:project) } @@ -36,8 +36,8 @@ user:) end - describe "#user" do - describe "WHEN an existing user is provided" do + describe '#user' do + describe 'WHEN an existing user is provided' do before do rate.user = user rate.save! @@ -46,7 +46,7 @@ it { expect(rate.user).to eq(user) } end - describe "WHEN a non existing user is provided (i.e. the user is deleted)" do + describe 'WHEN a non existing user is provided (i.e. the user is deleted)' do before do rate.user = user rate.save! diff --git a/modules/costs/spec/models/permitted_params_spec.rb b/modules/costs/spec/models/permitted_params_spec.rb index 8f9e6bf185f7..ab68171bcb49 100644 --- a/modules/costs/spec/models/permitted_params_spec.rb +++ b/modules/costs/spec/models/permitted_params_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../spec_helper", __dir__) +require File.expand_path('../spec_helper', __dir__) RSpec.describe PermittedParams do let(:user) { build(:user) } - shared_examples_for "allows params" do + shared_examples_for 'allows params' do let(:params_key) { defined?(hash_key) ? hash_key : attribute } let(:params) do nested_params = if defined?(nested_key) @@ -57,115 +57,115 @@ end end - describe "#cost_entry" do + describe '#cost_entry' do let(:attribute) { :cost_entry } - context "comments" do - let(:hash) { { "comments" => "blubs" } } + context 'comments' do + let(:hash) { { 'comments' => 'blubs' } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "units" do - let(:hash) { { "units" => "5.0" } } + context 'units' do + let(:hash) { { 'units' => '5.0' } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "overridden_costs" do - let(:hash) { { "overridden_costs" => "5.0" } } + context 'overridden_costs' do + let(:hash) { { 'overridden_costs' => '5.0' } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "spent_on" do - let(:hash) { { "spent_on" => Date.today.to_s } } + context 'spent_on' do + let(:hash) { { 'spent_on' => Date.today.to_s } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "project_id" do - let(:hash) { { "project_id" => 42 } } + context 'project_id' do + let(:hash) { { 'project_id' => 42 } } - it_behaves_like "allows params" do + it_behaves_like 'allows params' do let(:allowed_params) { {} } end end end - describe "#cost_type" do + describe '#cost_type' do let(:attribute) { :cost_type } - context "name" do - let(:hash) { { "name" => "name_test" } } + context 'name' do + let(:hash) { { 'name' => 'name_test' } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "unit" do - let(:hash) { { "unit" => "unit_test" } } + context 'unit' do + let(:hash) { { 'unit' => 'unit_test' } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "unit_plural" do - let(:hash) { { "unit_plural" => "unit_plural_test" } } + context 'unit_plural' do + let(:hash) { { 'unit_plural' => 'unit_plural_test' } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "default" do - let(:hash) { { "default" => 7 } } + context 'default' do + let(:hash) { { 'default' => 7 } } - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "new_rate_attributes" do + context 'new_rate_attributes' do let(:hash) do - { "new_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" }, - "1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } } + { 'new_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' }, + '1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } } end - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "existing_rate_attributes" do + context 'existing_rate_attributes' do let(:hash) do - { "existing_rate_attributes" => { "9" => { "valid_from" => "2013-05-05", "rate" => "50.0" } } } + { 'existing_rate_attributes' => { '9' => { 'valid_from' => '2013-05-05', 'rate' => '50.0' } } } end - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "project_id" do - let(:hash) { { "project_id" => 42 } } + context 'project_id' do + let(:hash) { { 'project_id' => 42 } } - it_behaves_like "allows params" do + it_behaves_like 'allows params' do let(:allowed_params) { {} } end end end - describe "#user_rates" do + describe '#user_rates' do let(:attribute) { :user_rates } let(:hash_key) { :user } - context "new_rate_attributes" do + context 'new_rate_attributes' do let(:hash) do - { "new_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" }, - "1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } } + { 'new_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' }, + '1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } } end - it_behaves_like "allows params" + it_behaves_like 'allows params' end - context "existing_rate_attributes" do + context 'existing_rate_attributes' do let(:hash) do - { "existing_rate_attributes" => { "0" => { "valid_from" => "2013-05-08", "rate" => "5002" }, - "1" => { "valid_from" => "2013-05-10", "rate" => "5004" } } } + { 'existing_rate_attributes' => { '0' => { 'valid_from' => '2013-05-08', 'rate' => '5002' }, + '1' => { 'valid_from' => '2013-05-10', 'rate' => '5004' } } } end - it_behaves_like "allows params" + it_behaves_like 'allows params' end end end diff --git a/modules/costs/spec/models/project/activity_spec.rb b/modules/costs/spec/models/project/activity_spec.rb index 2a3f92ac209d..85b2fefc0d4c 100644 --- a/modules/costs/spec/models/project/activity_spec.rb +++ b/modules/costs/spec/models/project/activity_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::Activity, "costs" do +RSpec.describe Projects::Activity, 'costs' do shared_let(:project) do create(:project, :updated_a_long_time_ago) end @@ -54,8 +54,8 @@ def latest_activity Project.with_latest_activity.find(project.id).latest_activity_at end - describe ".with_latest_activity" do - it "set project.latest_activity_at to the latest updated budget time" do + describe '.with_latest_activity' do + it 'set project.latest_activity_at to the latest updated budget time' do budget.update(updated_at: initial_time - 10.seconds) budget2.update(updated_at: initial_time - 20.seconds) @@ -63,7 +63,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(budget.updated_at) end - it "takes the time stamp of the latest activity across models" do + it 'takes the time stamp of the latest activity across models' do work_package.update(updated_at: initial_time - 10.seconds) budget.update(updated_at: initial_time - 20.seconds) diff --git a/modules/costs/spec/models/projects/scopes/activated_time_activity_spec.rb b/modules/costs/spec/models/projects/scopes/activated_time_activity_spec.rb index 766d1e34ee69..15c170ec234e 100644 --- a/modules/costs/spec/models/projects/scopes/activated_time_activity_spec.rb +++ b/modules/costs/spec/models/projects/scopes/activated_time_activity_spec.rb @@ -26,55 +26,55 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::Scopes::ActivatedTimeActivity do let!(:activity) { create(:time_entry_activity) } let!(:project) { create(:project) } let!(:other_project) { create(:project) } - describe ".activated_time_activity" do + describe '.activated_time_activity' do subject { Project.activated_time_activity(activity) } - context "without project specific overrides" do - context "and being active" do - it "returns all projects" do + context 'without project specific overrides' do + context 'and being active' do + it 'returns all projects' do expect(subject) .to contain_exactly(project, other_project) end end - context "and not being active" do + context 'and not being active' do before do activity.update_attribute(:active, false) end - it "returns no projects" do + it 'returns no projects' do expect(subject) .to be_empty end end end - context "with project specific overrides" do + context 'with project specific overrides' do before do TimeEntryActivitiesProject.insert({ activity_id: activity.id, project_id: project.id, active: true }) TimeEntryActivitiesProject.insert({ activity_id: activity.id, project_id: other_project.id, active: false }) end - context "and being active" do - it "returns the project the activity is activated in" do + context 'and being active' do + it 'returns the project the activity is activated in' do expect(subject) .to contain_exactly(project) end end - context "and not being active" do + context 'and not being active' do before do activity.update_attribute(:active, false) end - it "returns only the projects the activity is activated in" do + it 'returns only the projects the activity is activated in' do expect(subject) .to contain_exactly(project) end diff --git a/modules/costs/spec/models/projects/scopes/visible_with_activated_time_activity_spec.rb b/modules/costs/spec/models/projects/scopes/visible_with_activated_time_activity_spec.rb index a40590eb3ec0..e8e900addbed 100644 --- a/modules/costs/spec/models/projects/scopes/visible_with_activated_time_activity_spec.rb +++ b/modules/costs/spec/models/projects/scopes/visible_with_activated_time_activity_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::Scopes::VisibleWithActivatedTimeActivity do let!(:activity) { create(:time_entry_activity) } @@ -54,68 +54,68 @@ login_as(current_user) end - describe ".fetch" do + describe '.fetch' do subject { Project.visible_with_activated_time_activity(activity) } - context "without project specific overrides" do - context "and being active" do - it "returns all projects" do + context 'without project specific overrides' do + context 'and being active' do + it 'returns all projects' do expect(subject) .to contain_exactly(project, other_project) end end - context "and not being active" do + context 'and not being active' do before do activity.update_attribute(:active, false) end - it "returns no projects" do + it 'returns no projects' do expect(subject) .to be_empty end end - context "and having only view_own_time_entries_permission" do + context 'and having only view_own_time_entries_permission' do let(:project_permissions) { [:view_own_time_entries] } let(:other_project_permissions) { [:view_own_time_entries] } - it "returns all projects" do + it 'returns all projects' do expect(subject) .to contain_exactly(project, other_project) end end - context "and having no view permission" do + context 'and having no view permission' do let(:project_permissions) { [] } let(:other_project_permissions) { [] } - it "returns all projects" do + it 'returns all projects' do expect(subject) .to be_empty end end end - context "with project specific overrides" do + context 'with project specific overrides' do before do TimeEntryActivitiesProject.insert({ activity_id: activity.id, project_id: project.id, active: true }) TimeEntryActivitiesProject.insert({ activity_id: activity.id, project_id: other_project.id, active: false }) end - context "and being active" do - it "returns the project the activity is activated in" do + context 'and being active' do + it 'returns the project the activity is activated in' do expect(subject) .to contain_exactly(project) end end - context "and not being active" do + context 'and not being active' do before do activity.update_attribute(:active, false) end - it "returns only the projects the activity is activated in" do + it 'returns only the projects the activity is activated in' do expect(subject) .to contain_exactly(project) end diff --git a/modules/costs/spec/models/queries/time_entries/filters/activity_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/activity_filter_spec.rb index 666387bd0723..ac46eced1358 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/activity_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/activity_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::ActivityFilter do let(:time_entry_activity1) { build_stubbed(:time_entry_activity) } @@ -60,18 +60,18 @@ .and_return(activities.map { |x| [x.name, x.id] }) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :activity_id } let(:type) { :list_optional } let(:name) { TimeEntry.human_attribute_name(:activity) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expect(instance.allowed_values).to match_array(activities.map { |x| [x.name, x.id] }) end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :activity_id } let(:model) { TimeEntry } let(:valid_values) { activities.map { |a| a.id.to_s } } diff --git a/modules/costs/spec/models/queries/time_entries/filters/created_at_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/created_at_filter_spec.rb index ec36d25d9d1b..ba476e6dc20f 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/created_at_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/created_at_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::CreatedAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :datetime_past } let(:class_key) { :created_at } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/modules/costs/spec/models/queries/time_entries/filters/ongoing_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/ongoing_filter_spec.rb index 59c5e8b6d58b..4c53179f433f 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/ongoing_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/ongoing_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::OngoingFilter do - it_behaves_like "boolean query filter" do + it_behaves_like 'boolean query filter' do let(:model) { TimeEntry } let(:attribute) { :ongoing } end diff --git a/modules/costs/spec/models/queries/time_entries/filters/project_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/project_filter_spec.rb index 383f3651ab32..e788e562df3f 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/project_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/project_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::ProjectFilter do let(:project1) { build_stubbed(:project) } @@ -39,13 +39,13 @@ .and_return([project1.id, project2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :project_id } let(:type) { :list_optional } let(:name) { TimeEntry.human_attribute_name(:project) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[project1.id, project1.id.to_s], [project2.id, project2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :project_id } let(:model) { TimeEntry } let(:valid_values) { [project1.id.to_s] } diff --git a/modules/costs/spec/models/queries/time_entries/filters/spent_on_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/spent_on_filter_spec.rb index 22fc82ba1b8d..2893d2ff1bd7 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/spent_on_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/spent_on_filter_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::SpentOnFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :date } let(:class_key) { :spent_on } let(:human_name) { TimeEntry.human_attribute_name :spent_on } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/modules/costs/spec/models/queries/time_entries/filters/updated_at_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/updated_at_filter_spec.rb index 596a965b5bc0..e473154b70fa 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/updated_at_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/updated_at_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::UpdatedAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :datetime_past } let(:class_key) { :updated_at } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/modules/costs/spec/models/queries/time_entries/filters/user_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/user_filter_spec.rb index 113fbeeb8c67..aeea4cedeb29 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/user_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/user_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::UserFilter do let(:user1) { build_stubbed(:user) } @@ -39,13 +39,13 @@ .and_return([user1.id, user2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :user_id } let(:type) { :list_optional } let(:name) { TimeEntry.human_attribute_name(:user) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[user1.id, user1.id.to_s], [user2.id, user2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :user_id } let(:model) { TimeEntry } let(:instance_key) { :user_id } diff --git a/modules/costs/spec/models/queries/time_entries/filters/work_package_filter_spec.rb b/modules/costs/spec/models/queries/time_entries/filters/work_package_filter_spec.rb index 339bb7ae7a9a..1fe0c4162d4d 100644 --- a/modules/costs/spec/models/queries/time_entries/filters/work_package_filter_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/filters/work_package_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::Filters::WorkPackageFilter do let(:work_package1) { build_stubbed(:work_package) } @@ -39,13 +39,13 @@ .and_return([work_package1.id, work_package2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :work_package_id } let(:type) { :list_optional } let(:name) { TimeEntry.human_attribute_name(:work_package) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[work_package1.id, work_package1.id.to_s], [work_package2.id, work_package2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :work_package_id } let(:model) { TimeEntry } let(:valid_values) { [work_package1.id.to_s] } diff --git a/modules/costs/spec/models/queries/time_entries/time_entry_query_integration_spec.rb b/modules/costs/spec/models/queries/time_entries/time_entry_query_integration_spec.rb index 4878dfc0611f..f98ddcfda3c0 100644 --- a/modules/costs/spec/models/queries/time_entries/time_entry_query_integration_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/time_entry_query_integration_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Queries::TimeEntries::TimeEntryQuery, "integration" do +RSpec.describe Queries::TimeEntries::TimeEntryQuery, 'integration' do let(:instance) { described_class.new(user:) } before do login_as(user) end - context "when using ongoing filter" do + context 'when using ongoing filter' do let(:project) { create(:project, enabled_module_names: %w[costs]) } let(:user) { create(:user, member_with_permissions: { project => %i[log_own_time] }) } let(:work_package) { create(:work_package, project:) } @@ -45,21 +45,21 @@ let!(:user_timer) { create(:time_entry, user:, work_package:, ongoing: true) } let!(:other_user_timer) { create(:time_entry, user: other_user, work_package: other_work_package, ongoing: true) } - describe "#results" do + describe '#results' do subject { instance.results } before do - instance.where("ongoing", "=", ["t"]) + instance.where('ongoing', '=', ['t']) end - it "only returns the users own time entries" do + it 'only returns the users own time entries' do expect(subject).to contain_exactly(user_timer) end - context "when user has log_time permission" do + context 'when user has log_time permission' do let(:user) { create(:user, member_with_permissions: { project => %i[log_time] }) } - it "still returns the users own time entries" do + it 'still returns the users own time entries' do expect(subject).to contain_exactly(user_timer) end end diff --git a/modules/costs/spec/models/queries/time_entries/time_entry_query_spec.rb b/modules/costs/spec/models/queries/time_entries/time_entry_query_spec.rb index 6bdf58284a91..5ab24076ad51 100644 --- a/modules/costs/spec/models/queries/time_entries/time_entry_query_spec.rb +++ b/modules/costs/spec/models/queries/time_entries/time_entry_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::TimeEntries::TimeEntryQuery do let(:user) { build_stubbed(:user) } @@ -37,16 +37,16 @@ login_as(user) end - context "without a filter" do - describe "#results" do - it "is the same as getting all the time entries" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the time entries' do expect(instance.results.to_sql).to eql base_scope.to_sql end end end - context "with a user filter" do - let(:values) { ["1"] } + context 'with a user filter' do + let(:values) { ['1'] } before do allow(Principal) @@ -56,22 +56,22 @@ end subject do - instance.where("user_id", "=", values) + instance.where('user_id', '=', values) instance end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope .where(["time_entries.user_id IN (?)", values]) expect(subject.results.to_sql).to eql expected.to_sql end - context "with a me value" do - let(:values) { ["me"] } + context 'with a me value' do + let(:values) { ['me'] } - it "replaces the value to produce the query" do + it 'replaces the value to produce the query' do expected = base_scope .where(["time_entries.user_id IN (?)", [user.id.to_s]]) @@ -80,92 +80,92 @@ end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(subject).to be_valid end - context "with a me value and being logged in" do - let(:values) { ["me"] } + context 'with a me value and being logged in' do + let(:values) { ['me'] } - it "is valid" do + it 'is valid' do expect(subject).to be_valid end end - context "with not existing values" do - let(:values) { [""] } + context 'with not existing values' do + let(:values) { [''] } - it "is invalid" do + it 'is invalid' do expect(subject).to be_invalid end end end end - context "with a project filter" do + context 'with a project filter' do before do allow(Project) .to receive_message_chain(:visible, :pluck) .with(:id) .and_return([1]) - instance.where("project_id", "=", ["1"]) + instance.where('project_id', '=', ['1']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope - .where(["time_entries.project_id IN (?)", ["1"]]) + .where(["time_entries.project_id IN (?)", ['1']]) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("project_id", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('project_id', '=', ['']) expect(instance).to be_invalid end end end - context "with a work_package filter" do + context 'with a work_package filter' do before do allow(WorkPackage) .to receive_message_chain(:visible, :pluck) .with(:id) .and_return([1]) - instance.where("work_package_id", "=", ["1"]) + instance.where('work_package_id', '=', ['1']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope - .where(["time_entries.work_package_id IN (?)", ["1"]]) + .where(["time_entries.work_package_id IN (?)", ['1']]) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("work_package_id", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('work_package_id', '=', ['']) expect(instance).to be_invalid end end end - context "with an order by id asc" do - describe "#results" do - it "returns all visible time entries ordered by id asc" do + context 'with an order by id asc' do + describe '#results' do + it 'returns all visible time entries ordered by id asc' do expect(instance.order(id: :asc).results.to_sql) .to eql base_scope.except(:order).order(id: :asc).to_sql end diff --git a/modules/costs/spec/models/rate_spec.rb b/modules/costs/spec/models/rate_spec.rb index 08c81878c32e..42941ea18e9f 100644 --- a/modules/costs/spec/models/rate_spec.rb +++ b/modules/costs/spec/models/rate_spec.rb @@ -26,35 +26,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe Rate do let(:rate) { build(:rate) } - describe "#valid?" do - describe "WHEN no rate is supplied" do + describe '#valid?' do + describe 'WHEN no rate is supplied' do before do rate.rate = nil end - it "is not valid" do + it 'is not valid' do expect(rate).not_to be_valid - expect(rate.errors[:rate]).to eq([I18n.t("activerecord.errors.messages.not_a_number")]) + expect(rate.errors[:rate]).to eq([I18n.t('activerecord.errors.messages.not_a_number')]) end end - describe "WHEN no number is supplied" do + describe 'WHEN no number is supplied' do before do - rate.rate = "test" + rate.rate = 'test' end - it "is not valid" do + it 'is not valid' do expect(rate).not_to be_valid - expect(rate.errors[:rate]).to eq([I18n.t("activerecord.errors.messages.not_a_number")]) + expect(rate.errors[:rate]).to eq([I18n.t('activerecord.errors.messages.not_a_number')]) end end - describe "WHEN a rate is supplied" do + describe 'WHEN a rate is supplied' do before do rate.rate = 5.0 end @@ -62,7 +62,7 @@ it { expect(rate).to be_valid } end - describe "WHEN a date is supplied" do + describe 'WHEN a date is supplied' do before do rate.valid_from = Date.today end @@ -70,33 +70,33 @@ it { expect(rate).to be_valid } end - describe "WHEN a transformable string is supplied for date" do + describe 'WHEN a transformable string is supplied for date' do before do - rate.valid_from = "2012-03-04" + rate.valid_from = '2012-03-04' end it { expect(rate).to be_valid } end - describe "WHEN a nontransformable string is supplied for date" do + describe 'WHEN a nontransformable string is supplied for date' do before do - rate.valid_from = "2012-02-30" + rate.valid_from = '2012-02-30' end - it "is not valid" do + it 'is not valid' do expect(rate).not_to be_valid - expect(rate.errors[:valid_from]).to eq([I18n.t("activerecord.errors.messages.not_a_date")]) + expect(rate.errors[:valid_from]).to eq([I18n.t('activerecord.errors.messages.not_a_date')]) end end - describe "WHEN no value is supplied for date" do + describe 'WHEN no value is supplied for date' do before do rate.valid_from = nil end - it "is not valid" do + it 'is not valid' do expect(rate).not_to be_valid - expect(rate.errors[:valid_from]).to eq([I18n.t("activerecord.errors.messages.not_a_date")]) + expect(rate.errors[:valid_from]).to eq([I18n.t('activerecord.errors.messages.not_a_date')]) end end end diff --git a/modules/costs/spec/models/time_entries/scopes/of_user_and_day_spec.rb b/modules/costs/spec/models/time_entries/scopes/of_user_and_day_spec.rb index 971c84543c3d..3629d96f1db5 100644 --- a/modules/costs/spec/models/time_entries/scopes/of_user_and_day_spec.rb +++ b/modules/costs/spec/models/time_entries/scopes/of_user_and_day_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntries::Scopes::OfUserAndDay do let(:user) { create(:user) } @@ -52,18 +52,18 @@ spent_on: spent_on - 3.days) end - describe ".of_user_and_day" do + describe '.of_user_and_day' do subject { TimeEntry.of_user_and_day(user, spent_on) } - it "are all the time entries of the user on the date" do + it 'are all the time entries of the user on the date' do expect(subject) .to contain_exactly(time_entry, other_time_entry) end - context "if excluding a time entry" do + context 'if excluding a time entry' do subject { TimeEntry.of_user_and_day(user, spent_on, excluding: other_time_entry) } - it "does not include the time entry" do + it 'does not include the time entry' do expect(subject) .to contain_exactly(time_entry) end diff --git a/modules/costs/spec/models/time_entries/scopes/visible_spec.rb b/modules/costs/spec/models/time_entries/scopes/visible_spec.rb index 4074492b062d..cb142c4ea694 100644 --- a/modules/costs/spec/models/time_entries/scopes/visible_spec.rb +++ b/modules/costs/spec/models/time_entries/scopes/visible_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntry, "visible scope" do let(:project) { create(:project) } @@ -59,22 +59,22 @@ user:) end - describe ".visible" do + describe '.visible' do subject { TimeEntry.visible(user) } - context "for a user having the view_time_entries permission" do + context 'for a user having the view_time_entries permission' do let(:user) { create(:user, member_with_permissions: { project => [:view_time_entries] }) } - it "retrieves all the time entries of projects the user has the permissions in" do + it 'retrieves all the time entries of projects the user has the permissions in' do expect(subject) .to contain_exactly(own_project_time_entry, project_time_entry) end end - context "for a user having the view_own_time_entries permission on a work package" do + context 'for a user having the view_own_time_entries permission on a work package' do let(:user) { create(:user, member_with_permissions: { work_package => [:view_own_time_entries] }) } - it "retrieves all the time entries of the user in projects the user has the permissions in" do + it 'retrieves all the time entries of the user in projects the user has the permissions in' do expect(subject) .to contain_exactly(own_project_time_entry) end diff --git a/modules/costs/spec/models/time_entry_activities/scopes/active_in_project_spec.rb b/modules/costs/spec/models/time_entry_activities/scopes/active_in_project_spec.rb index 7178530473d2..0bdd14257c83 100644 --- a/modules/costs/spec/models/time_entry_activities/scopes/active_in_project_spec.rb +++ b/modules/costs/spec/models/time_entry_activities/scopes/active_in_project_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntryActivities::Scopes::ActiveInProject do let!(:activity) { create(:time_entry_activity) } @@ -34,78 +34,78 @@ let(:project) { create(:project) } let(:other_project) { create(:project) } - describe ".active_in_project" do + describe '.active_in_project' do subject { TimeEntryActivity.active_in_project(project) } - context "without a project configuration" do - context "with the activity being active" do - it "includes the activity" do + context 'without a project configuration' do + context 'with the activity being active' do + it 'includes the activity' do expect(subject) .to contain_exactly(activity, other_activity) end end - context "with the activity being inactive" do + context 'with the activity being inactive' do before do activity.update_attribute(:active, false) end - it "excludes the activity" do + it 'excludes the activity' do expect(subject) .to contain_exactly(other_activity) end end end - context "with a project configuration configured to true" do + context 'with a project configuration configured to true' do before do activity.time_entry_activities_projects.create(project:, active: true) end - it "includes the activity" do + it 'includes the activity' do expect(subject) .to contain_exactly(activity, other_activity) end - context "with the activity being inactive" do + context 'with the activity being inactive' do before do activity.update_attribute(:active, false) end - it "includes the activity" do + it 'includes the activity' do expect(subject) .to contain_exactly(activity, other_activity) end end end - context "with a project configuration configured to false but for a different project" do + context 'with a project configuration configured to false but for a different project' do before do activity.time_entry_activities_projects.create(project: other_project, active: false) end - it "includes the activity" do + it 'includes the activity' do expect(subject) .to contain_exactly(activity, other_activity) end end - context "with a project configuration configured to false" do + context 'with a project configuration configured to false' do before do activity.time_entry_activities_projects.create(project:, active: false) end - it "excludes the activity" do + it 'excludes the activity' do expect(subject) .to contain_exactly(other_activity) end - context "with a project configuration configured to true but for a different project" do + context 'with a project configuration configured to true but for a different project' do before do activity.time_entry_activities_projects.create(project: other_project, active: true) end - it "excludes the activity" do + it 'excludes the activity' do expect(subject) .to contain_exactly(other_activity) end diff --git a/modules/costs/spec/models/time_entry_activity_spec.rb b/modules/costs/spec/models/time_entry_activity_spec.rb index aab0ab419c92..3ab3cb3c1534 100644 --- a/modules/costs/spec/models/time_entry_activity_spec.rb +++ b/modules/costs/spec/models/time_entry_activity_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntryActivity do let(:new_activity) { described_class.new } - let(:saved_activity) { described_class.create name: "Design" } + let(:saved_activity) { described_class.create name: 'Design' } - it "is an enumeration" do + it 'is an enumeration' do expect(new_activity) .to be_a(Enumeration) end - describe "#objects_count" do - it "represents the count of time entries of that activity" do + describe '#objects_count' do + it 'represents the count of time entries of that activity' do expect { create(:time_entry, activity: saved_activity) } .to change(saved_activity, :objects_count) .from(0) @@ -46,8 +46,8 @@ end end - describe "#option_name" do - it "is enumeration_activities" do + describe '#option_name' do + it 'is enumeration_activities' do expect(new_activity.option_name) .to eq :enumeration_activities end diff --git a/modules/costs/spec/models/time_entry_spec.rb b/modules/costs/spec/models/time_entry_spec.rb index 075d6f9956b0..71233c2f72e7 100644 --- a/modules/costs/spec/models/time_entry_spec.rb +++ b/modules/costs/spec/models/time_entry_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntry do let(:project) { create(:project_with_types, public: false) } @@ -60,7 +60,7 @@ hours:, user:, rate: hourly_one, - comments: "lorem") + comments: 'lorem') end let(:time_entry2) do @@ -71,7 +71,7 @@ hours:, user:, rate: hourly_one, - comments: "lorem") + comments: 'lorem') end def is_member(project, user, permissions) @@ -81,23 +81,23 @@ def is_member(project, user, permissions) roles: [create(:project_role, permissions:)]) end - describe "#hours" do - formats = { "2" => 2.0, - "21.1" => 21.1, - "2,1" => 2.1, - "1,5h" => 1.5, - "7:12" => 7.2, - "10h" => 10.0, - "10 h" => 10.0, - "45m" => 0.75, - "45 m" => 0.75, - "3h15" => 3.25, - "3h 15" => 3.25, - "3 h 15" => 3.25, - "3 h 15m" => 3.25, - "3 h 15 m" => 3.25, - "3 hours" => 3.0, - "12min" => 0.2 } + describe '#hours' do + formats = { '2' => 2.0, + '21.1' => 21.1, + '2,1' => 2.1, + '1,5h' => 1.5, + '7:12' => 7.2, + '10h' => 10.0, + '10 h' => 10.0, + '45m' => 0.75, + '45 m' => 0.75, + '3h15' => 3.25, + '3h 15' => 3.25, + '3 h 15' => 3.25, + '3 h 15m' => 3.25, + '3 h 15 m' => 3.25, + '3 hours' => 3.0, + '12min' => 0.2 } formats.each do |from, to| it "formats '#{from}'" do @@ -108,7 +108,7 @@ def is_member(project, user, permissions) end end - it "always prefers overridden_costs" do + it 'always prefers overridden_costs' do allow(User).to receive(:current).and_return(user) value = rand(500) @@ -118,13 +118,13 @@ def is_member(project, user, permissions) time_entry.save! end - describe "given rate" do + describe 'given rate' do before do allow(User).to receive(:current).and_return(user) @default_example = time_entry2 end - it "returns the current costs depending on the number of hours" do + it 'returns the current costs depending on the number of hours' do 101.times do |hours| time_entry.hours = hours time_entry.save! @@ -132,7 +132,7 @@ def is_member(project, user, permissions) end end - it "updates cost if a new rate is added at the end" do + it 'updates cost if a new rate is added at the end' do time_entry.user = User.current time_entry.spent_on = Time.now time_entry.hours = 1 @@ -149,7 +149,7 @@ def is_member(project, user, permissions) expect(time_entry.costs).to eq(hourly.rate) end - it "updates cost if a new rate is added in between" do + it 'updates cost if a new rate is added in between' do time_entry.user = User.current time_entry.spent_on = 3.days.ago.to_date time_entry.hours = 1 @@ -166,7 +166,7 @@ def is_member(project, user, permissions) expect(time_entry.costs).to eq(hourly.rate) end - it "updates cost if a spent_on changes" do + it 'updates cost if a spent_on changes' do time_entry.hours = 1 (5.days.ago.to_date..Date.today).each do |time| time_entry.spent_on = time.to_date @@ -175,7 +175,7 @@ def is_member(project, user, permissions) end end - it "updates cost if a rate is removed" do + it 'updates cost if a rate is removed' do time_entry.spent_on = hourly_one.valid_from time_entry.hours = 1 time_entry.save! @@ -188,7 +188,7 @@ def is_member(project, user, permissions) expect(time_entry.costs).to eq(hourly_five.rate) end - it "is able to change order of rates (sorted by valid_from)" do + it 'is able to change order of rates (sorted by valid_from)' do time_entry.spent_on = hourly_one.valid_from time_entry.save! expect(time_entry.rate).to eq(hourly_one) @@ -199,13 +199,13 @@ def is_member(project, user, permissions) end end - describe "default rate" do + describe 'default rate' do before do allow(User).to receive(:current).and_return(user) @default_example = time_entry2 end - it "returns the current costs depending on the number of hours" do + it 'returns the current costs depending on the number of hours' do 101.times do |hours| @default_example.hours = hours @default_example.save! @@ -213,7 +213,7 @@ def is_member(project, user, permissions) end end - it "updates cost if a new rate is added at the end" do + it 'updates cost if a new rate is added at the end' do @default_example.user = user2 @default_example.spent_on = Time.now.to_date @default_example.hours = 1 @@ -229,7 +229,7 @@ def is_member(project, user, permissions) expect(@default_example.costs).to eq(hourly.rate) end - it "updates cost if a new rate is added in between" do + it 'updates cost if a new rate is added in between' do @default_example.user = user2 @default_example.spent_on = 3.days.ago.to_date @default_example.hours = 1 @@ -245,7 +245,7 @@ def is_member(project, user, permissions) expect(@default_example.costs).to eq(hourly.rate) end - it "updates cost if a spent_on changes" do + it 'updates cost if a spent_on changes' do @default_example.hours = 1 (5.days.ago.to_date..Date.today).each do |time| @default_example.spent_on = time.to_date @@ -254,7 +254,7 @@ def is_member(project, user, permissions) end end - it "updates cost if a rate is removed" do + it 'updates cost if a rate is removed' do @default_example.spent_on = default_hourly_one.valid_from @default_example.hours = 1 @default_example.save! @@ -267,7 +267,7 @@ def is_member(project, user, permissions) expect(@default_example.costs).to eq(default_hourly_five.rate) end - it "is able to switch between default hourly rate and hourly rate" do + it 'is able to switch between default hourly rate and hourly rate' do @default_example.user = user2 @default_example.rate = default_hourly_one @default_example.save! @@ -288,9 +288,9 @@ def is_member(project, user, permissions) expect(@default_example.rate).to eq(default_hourly_one) end - describe "#costs_visible_by?" do + describe '#costs_visible_by?' do before do - project.enabled_module_names = project.enabled_module_names << "costs" + project.enabled_module_names = project.enabled_module_names << 'costs' end describe "WHEN the time_entry is assigned to the user @@ -339,49 +339,49 @@ def is_member(project, user, permissions) end end - describe "visible_by?" do - context "when not having the necessary permissions" do + describe 'visible_by?' do + context 'when not having the necessary permissions' do before do is_member(project, user, []) end - it "is visible" do + it 'is visible' do expect(time_entry.visible_by?(user)).to be_falsey end end - context "when having the view_time_entries permission" do + context 'when having the view_time_entries permission' do before do is_member(project, user, [:view_time_entries]) end - it "is visible" do + it 'is visible' do expect(time_entry.visible_by?(user)).to be_truthy end end - context "when having the view_own_time_entries permission " + - "and being the owner of the time entry" do + context 'when having the view_own_time_entries permission ' + + 'and being the owner of the time entry' do before do is_member(project, user, [:view_own_time_entries]) time_entry.user = user end - it "is visible" do + it 'is visible' do expect(time_entry.visible_by?(user)).to be_truthy end end - context "when having the view_own_time_entries permission " + - "and not being the owner of the time entry" do + context 'when having the view_own_time_entries permission ' + + 'and not being the owner of the time entry' do before do is_member(project, user, [:view_own_time_entries]) time_entry.user = build :user end - it "is visible" do + it 'is visible' do expect(time_entry.visible_by?(user)).to be_falsey end end diff --git a/modules/costs/spec/models/user_spec.rb b/modules/costs/spec/models/user_spec.rb index a46458f25834..841f5df2d148 100644 --- a/modules/costs/spec/models/user_spec.rb +++ b/modules/costs/spec/models/user_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe User do include Cost::PluginSpecHelper @@ -40,7 +40,7 @@ end let(:default_hourly_rate) { build(:default_hourly_rate, user:) } - describe "#allowed_to_condition_with_project_id" do + describe '#allowed_to_condition_with_project_id' do let(:permission) { :view_own_time_entries } before do @@ -54,7 +54,7 @@ is_member(project, user, [permission]) end - it "returns a sql condition where the project id the user has the permission in is enforced" do + it 'returns a sql condition where the project id the user has the permission in is enforced' do expect(user.allowed_to_condition_with_project_id(permission)).to eq("(projects.id in (#{project.id}))") end end @@ -66,7 +66,7 @@ is_member(project2, user, [permission]) end - it "returns a sql condition where all the project ids the user has the permission in is enforced" do + it 'returns a sql condition where all the project ids the user has the permission in is enforced' do # as order is not guaranteed and in fact does not matter # we have to check for both valid options valid_conditions = ["(projects.id in (#{project.id}, #{project2.id}))", @@ -82,8 +82,8 @@ user.save! end - it "returns a neutral (for an or operation) sql condition" do - expect(user.allowed_to_condition_with_project_id(permission)).to eq("1=0") + it 'returns a neutral (for an or operation) sql condition' do + expect(user.allowed_to_condition_with_project_id(permission)).to eq('1=0') end end @@ -94,13 +94,13 @@ is_member(project2, user, [permission]) end - it "returns a sql condition where all the project ids the user has the permission in is enforced" do + it 'returns a sql condition where all the project ids the user has the permission in is enforced' do expect(user.allowed_to_condition_with_project_id(permission, project)).to eq("(projects.id in (#{project.id}))") end end end - describe "#set_existing_rates" do + describe '#set_existing_rates' do before do user.save project.save @@ -120,19 +120,19 @@ user.set_existing_rates(project, new_attributes) end - it "updates the rate" do + it 'updates the rate' do expect(user.rates.detect do |r| r.id == project_hourly_rate.id end.rate).to eq(new_attributes[project_hourly_rate.id.to_s][:rate].to_i) end - it "updates valid_from" do + it 'updates valid_from' do expect(user.rates.detect do |r| r.id == project_hourly_rate.id end.valid_from).to eq(new_attributes[project_hourly_rate.id.to_s][:valid_from].to_date) end - it "does not create a rate" do + it 'does not create a rate' do expect(user.rates.size).to eq(1) end end @@ -153,15 +153,15 @@ user.set_existing_rates(project2, new_attributes) end - it "does not update the rate" do + it 'does not update the rate' do expect(user.rates.detect { |r| r.id == project_hourly_rate.id }.rate).to eq(@original_rate) end - it "does not update valid_from" do + it 'does not update valid_from' do expect(user.rates.detect { |r| r.id == project_hourly_rate.id }.valid_from).to eq(@original_valid_from) end - it "does not create a rate" do + it 'does not create a rate' do expect(user.rates.size).to eq(1) end end @@ -175,7 +175,7 @@ user.set_existing_rates(project, {}) end - it "deletes the hourly rate" do + it 'deletes the hourly rate' do expect(user.rates.reload).to be_empty end end @@ -189,7 +189,7 @@ user.set_existing_rates(nil, {}) end - it "deletes the default hourly rate" do + it 'deletes the default hourly rate' do expect(user.default_rates.reload).to be_empty end end diff --git a/modules/costs/spec/models/work_package/ask_before_destruction_spec.rb b/modules/costs/spec/models/work_package/ask_before_destruction_spec.rb index 1d9f64935906..2d933e057959 100644 --- a/modules/costs/spec/models/work_package/ask_before_destruction_spec.rb +++ b/modules/costs/spec/models/work_package/ask_before_destruction_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do let(:work_package) do @@ -67,43 +67,43 @@ cost_type:) end - describe "#cleanup_action_required_before_destructing?" do - describe "w/ the work package having a cost entry" do + describe '#cleanup_action_required_before_destructing?' do + describe 'w/ the work package having a cost entry' do before do work_package cost_entry end - it "is true" do + it 'is true' do expect(WorkPackage.cleanup_action_required_before_destructing?(work_package)).to be_truthy end end - describe "w/ two work packages having a cost entry" do + describe 'w/ two work packages having a cost entry' do before do work_package cost_entry cost_entry2 end - it "is true" do + it 'is true' do expect(WorkPackage.cleanup_action_required_before_destructing?([work_package, work_package2])).to be_truthy end end - describe "w/o the work package having a cost entry" do + describe 'w/o the work package having a cost entry' do before do work_package end - it "is false" do + it 'is false' do expect(WorkPackage.cleanup_action_required_before_destructing?(work_package)).to be_falsey end end end - describe "#associated_classes_to_address_before_destructing?" do - describe "w/ the work package having a cost entry" do + describe '#associated_classes_to_address_before_destructing?' do + describe 'w/ the work package having a cost entry' do before do work_package cost_entry @@ -114,44 +114,44 @@ end end - describe "w/o the work package having a cost entry" do + describe 'w/o the work package having a cost entry' do before do work_package end - it "is empty" do + it 'is empty' do expect(WorkPackage.associated_classes_to_address_before_destruction_of(work_package)).to be_empty end end end - describe "#cleanup_associated_before_destructing_if_required" do + describe '#cleanup_associated_before_destructing_if_required' do before do work_package.save! cost_entry end - describe "w/o a cleanup being necessary" do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "reassign") } + describe 'w/o a cleanup being necessary' do + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'reassign') } before do cost_entry.destroy end - it "returns true" do + it 'returns true' do expect(action).to be_truthy end end describe 'w/ "destroy" as action' do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "destroy") } + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'destroy') } - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "does not touch the cost_entry" do + it 'does not touch the cost_entry' do action cost_entry.reload @@ -159,14 +159,14 @@ end end - describe "w/o an action" do + describe 'w/o an action' do let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user) } - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "does not touch the cost_entry" do + it 'does not touch the cost_entry' do action cost_entry.reload @@ -175,30 +175,30 @@ end describe 'w/ "nullify" as action' do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "nullify") } + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'nullify') } - it "returns false" do + it 'returns false' do expect(action).to be_falsey end - it "does not alter the work_package_id of all cost entries" do + it 'does not alter the work_package_id of all cost entries' do action cost_entry.reload expect(cost_entry.work_package_id).to eq(work_package.id) end - it "sets an error on work packages" do + it 'sets an error on work packages' do action - expect(work_package.errors[:base]).to eq([I18n.t(:"activerecord.errors.models.work_package.nullify_is_not_valid_for_cost_entries")]) + expect(work_package.errors[:base]).to eq([I18n.t(:'activerecord.errors.models.work_package.nullify_is_not_valid_for_cost_entries')]) end end describe 'w/ "reassign" as action w/ reassigning to a valid work_package' do let(:action) do - WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "reassign", + WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'reassign', reassign_to_id: work_package2.id) end @@ -209,11 +209,11 @@ member2.save! end - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "sets the work_package_id of all cost entries to the new work package" do + it 'sets the work_package_id of all cost entries to the new work package' do action cost_entry.reload @@ -231,7 +231,7 @@ describe 'w/ "reassign" as action w/ reassigning to a work_package the user is not allowed to see' do let(:action) do - WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "reassign", + WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'reassign', reassign_to_id: work_package2.id) end @@ -239,11 +239,11 @@ work_package2.save! end - it "returns true" do + it 'returns true' do expect(action).to be_falsey end - it "does not alter the work_package_id of all cost entries" do + it 'does not alter the work_package_id of all cost entries' do action cost_entry.reload @@ -254,14 +254,14 @@ describe 'w/ "reassign" as action w/ reassigning to a non existing work package' do let(:action) do - WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "reassign", reassign_to_id: 0) + WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'reassign', reassign_to_id: 0) end - it "returns true" do + it 'returns true' do expect(action).to be_falsey end - it "does not alter the work_package_id of all cost entries" do + it 'does not alter the work_package_id of all cost entries' do action cost_entry.reload @@ -271,13 +271,13 @@ describe 'w/ "reassign" as action w/o providing a reassignment id' do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "reassign") } + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'reassign') } - it "returns true" do + it 'returns true' do expect(action).to be_falsey end - it "does not alter the work_package_id of all cost entries" do + it 'does not alter the work_package_id of all cost entries' do action cost_entry.reload @@ -285,18 +285,18 @@ end end - describe "w/ an invalid option" do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: "bogus") } + describe 'w/ an invalid option' do + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, action: 'bogus') } - it "returns false" do + it 'returns false' do expect(action).to be_falsey end end - describe "w/ nil as invalid option" do + describe 'w/ nil as invalid option' do let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, nil) } - it "returns false" do + it 'returns false' do expect(action).to be_falsey end end diff --git a/modules/costs/spec/models/work_package_spec.rb b/modules/costs/spec/models/work_package_spec.rb index b86036bfd538..dc4cf0f0e4aa 100644 --- a/modules/costs/spec/models/work_package_spec.rb +++ b/modules/costs/spec/models/work_package_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper") +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') RSpec.describe WorkPackage do let(:user) { create(:admin) } @@ -43,7 +43,7 @@ end let!(:cost_entry) do create(:cost_entry, work_package:, project:, units: 3, spent_on: Date.today, user:, - comments: "test entry") + comments: 'test entry') end let!(:budget) { create(:budget, project:) } @@ -53,13 +53,13 @@ def move_to_project(work_package, project) .call(project:) end - it "updates cost entries on move" do + it 'updates cost entries on move' do expect(work_package.project_id).to eql project.id expect(move_to_project(work_package, project2)).not_to be_falsey expect(cost_entry.reload.project_id).to eql project2.id end - it "allows to set budget to nil" do + it 'allows to set budget to nil' do work_package.budget = budget work_package.save! expect(work_package.budget).to eql budget diff --git a/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb b/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb index 8c98d9a5b70e..96aa91cfd585 100644 --- a/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb +++ b/modules/costs/spec/requests/api/attachments/attachments_by_budget_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "requests/api/v3/attachments/attachment_resource_shared_examples" +require 'spec_helper' +require 'requests/api/v3/attachments/attachment_resource_shared_examples' RSpec.describe "budget attachments" do it_behaves_like "an APIv3 attachment resource" do diff --git a/modules/costs/spec/requests/api/cost_entries/cost_entries_by_work_package_resource_spec.rb b/modules/costs/spec/requests/api/cost_entries/cost_entries_by_work_package_resource_spec.rb index ea7587e9c5e5..f3b28c961fc4 100644 --- a/modules/costs/spec/requests/api/cost_entries/cost_entries_by_work_package_resource_spec.rb +++ b/modules/costs/spec/requests/api/cost_entries/cost_entries_by_work_package_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Cost Entry resource" do +RSpec.describe 'API v3 Cost Entry resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -57,57 +57,57 @@ get get_path end - describe "work_packages/:id/cost_entries" do + describe 'work_packages/:id/cost_entries' do let(:get_path) { api_v3_paths.cost_entries_by_work_package work_package.id } - context "user can see any cost entries" do - it "returns HTTP 200" do + context 'user can see any cost entries' do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "user can see own cost entries" do + context 'user can see own cost entries' do let(:cost_entry_permissions) { [:view_own_cost_entries] } - it "returns HTTP 200" do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "user has no cost entry permissions" do + context 'user has no cost entry permissions' do let(:cost_entry_permissions) { [] } - it_behaves_like "error response", + it_behaves_like 'error response', 403, - "MissingPermission", - I18n.t("api_v3.errors.code_403") + 'MissingPermission', + I18n.t('api_v3.errors.code_403') end end - describe "work_packages/:id/summarized_costs_by_type" do + describe 'work_packages/:id/summarized_costs_by_type' do let(:get_path) { api_v3_paths.summarized_work_package_costs_by_type work_package.id } - context "user can see any cost entries" do - it "returns HTTP 200" do + context 'user can see any cost entries' do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "user can see own cost entries" do + context 'user can see own cost entries' do let(:cost_entry_permissions) { [:view_own_cost_entries] } - it "returns HTTP 200" do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "user has no cost entry permissions" do + context 'user has no cost entry permissions' do let(:cost_entry_permissions) { [] } - it_behaves_like "error response", + it_behaves_like 'error response', 403, - "MissingPermission", - I18n.t("api_v3.errors.code_403") + 'MissingPermission', + I18n.t('api_v3.errors.code_403') end end end diff --git a/modules/costs/spec/requests/api/cost_entries/cost_entry_resource_spec.rb b/modules/costs/spec/requests/api/cost_entries/cost_entry_resource_spec.rb index 5d7c81755513..0a0c970cf9bf 100644 --- a/modules/costs/spec/requests/api/cost_entries/cost_entry_resource_spec.rb +++ b/modules/costs/spec/requests/api/cost_entries/cost_entry_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Cost Entry resource" do +RSpec.describe 'API v3 Cost Entry resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -49,54 +49,54 @@ get get_path end - describe "cost_entries/:id" do + describe 'cost_entries/:id' do let(:get_path) { api_v3_paths.cost_entry cost_entry.id } - context "user can see cost entries" do - context "valid id" do - it "returns HTTP 200" do + context 'user can see cost entries' do + context 'valid id' do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "invalid id" do - let(:get_path) { api_v3_paths.cost_type "bogus" } + context 'invalid id' do + let(:get_path) { api_v3_paths.cost_type 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } end end end - context "user can only see own cost entries" do + context 'user can only see own cost entries' do let(:permissions) { [:view_own_cost_entries] } - context "cost entry is not his own" do - it_behaves_like "error response", + context 'cost entry is not his own' do + it_behaves_like 'error response', 403, - "MissingPermission", - I18n.t("api_v3.errors.code_403") + 'MissingPermission', + I18n.t('api_v3.errors.code_403') end - context "cost entry is his own" do + context 'cost entry is his own' do let(:cost_entry) { create(:cost_entry, project:, user: current_user) } - it "returns HTTP 200" do + it 'returns HTTP 200' do expect(response.status).to be(200) end end end - context "user has no cost entry permissions" do + context 'user has no cost entry permissions' do let(:permissions) { [] } - describe "he can't even see own cost entries" do + describe 'he can\'t even see own cost entries' do let(:cost_entry) { create(:cost_entry, project:, user: current_user) } - it_behaves_like "error response", + it_behaves_like 'error response', 403, - "MissingPermission", - I18n.t("api_v3.errors.code_403") + 'MissingPermission', + I18n.t('api_v3.errors.code_403') end end end diff --git a/modules/costs/spec/requests/api/cost_types/cost_type_resource_spec.rb b/modules/costs/spec/requests/api/cost_types/cost_type_resource_spec.rb index 763b914271eb..b57fd00b17fc 100644 --- a/modules/costs/spec/requests/api/cost_types/cost_type_resource_spec.rb +++ b/modules/costs/spec/requests/api/cost_types/cost_type_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Cost Type resource" do +RSpec.describe 'API v3 Cost Type resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -48,38 +48,38 @@ get get_path end - describe "cost_types/:id" do + describe 'cost_types/:id' do let(:get_path) { api_v3_paths.cost_type cost_type.id } - context "user can see cost entries" do - context "valid id" do - it "returns HTTP 200" do + context 'user can see cost entries' do + context 'valid id' do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "cost type deleted" do + context 'cost type deleted' do let!(:cost_type) { create(:cost_type, :deleted) } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "invalid id" do - let(:get_path) { api_v3_paths.cost_type "bogus" } + context 'invalid id' do + let(:get_path) { api_v3_paths.cost_type 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } end end end - context "user can't see cost entries" do + context 'user can\'t see cost entries' do let(:current_user) { create(:user) } - it_behaves_like "error response", + it_behaves_like 'error response', 403, - "MissingPermission", - I18n.t("api_v3.errors.code_403") + 'MissingPermission', + I18n.t('api_v3.errors.code_403') end end end diff --git a/modules/costs/spec/requests/api/time_entries/available_projects_resource_spec.rb b/modules/costs/spec/requests/api/time_entries/available_projects_resource_spec.rb index a78a0f94f092..6a5e452e1afc 100644 --- a/modules/costs/spec/requests/api/time_entries/available_projects_resource_spec.rb +++ b/modules/costs/spec/requests/api/time_entries/available_projects_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 time entries available projects resource" do +RSpec.describe 'API v3 time entries available projects resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -87,7 +87,7 @@ subject(:response) { last_response } - describe "GET api/v3/time_entries/available_projects" do + describe 'GET api/v3/time_entries/available_projects' do let(:projects) do [project_with_log_permission, project_with_edit_permission, @@ -106,40 +106,40 @@ get path end - it "responds 200 OK" do + it 'responds 200 OK' do expect(subject.status).to eq(200) end - it "returns a collection of projects containing only the ones for which the user has the necessary permissions" do + it 'returns a collection of projects containing only the ones for which the user has the necessary permissions' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("3") - .at_path("total") + .to be_json_eql('3') + .at_path('total') expect(subject.body) .to be_json_eql(project_with_log_permission.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(project_with_edit_permission.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') expect(subject.body) .to be_json_eql(project_with_edit_own_permission.id.to_json) - .at_path("_embedded/elements/2/id") + .at_path('_embedded/elements/2/id') end - context "without permissions" do + context 'without permissions' do let(:projects) do [project_with_view_permission, project_without_permission, project_without_membership] end - it "returns a 403" do + it 'returns a 403' do expect(subject.status) .to eq(403) end diff --git a/modules/costs/spec/requests/api/time_entries/create_form_resource_spec.rb b/modules/costs/spec/requests/api/time_entries/create_form_resource_spec.rb index fc326820b9ff..039f11e48472 100644 --- a/modules/costs/spec/requests/api/time_entries/create_form_resource_spec.rb +++ b/modules/costs/spec/requests/api/time_entries/create_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::TimeEntries::CreateFormAPI, content_type: :json do include Rack::Test::Methods @@ -61,46 +61,46 @@ subject(:response) { last_response } - describe "#POST /api/v3/time_entries/form" do - it "returns 200 OK" do + describe '#POST /api/v3/time_entries/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - it "does not create a time_entry" do + it 'does not create a time_entry' do expect(TimeEntry.count) .to be 0 end - context "with empty parameters" do - it "has 4 validation errors" do - expect(subject.body).to have_json_size(3).at_path("_embedded/validationErrors") + context 'with empty parameters' do + it 'has 4 validation errors' do + expect(subject.body).to have_json_size(3).at_path('_embedded/validationErrors') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end - it "has a validation error on spentOn" do - expect(subject.body).to have_json_path("_embedded/validationErrors/spentOn") + it 'has a validation error on spentOn' do + expect(subject.body).to have_json_path('_embedded/validationErrors/spentOn') end - it "has a validation error on hours" do - expect(subject.body).to have_json_path("_embedded/validationErrors/hours") + it 'has a validation error on hours' do + expect(subject.body).to have_json_path('_embedded/validationErrors/hours') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with all parameters" do + context 'with all parameters' do let(:parameters) do { _links: { @@ -115,38 +115,38 @@ } }, spentOn: Date.today.to_s, - hours: "PT5H", + hours: 'PT5H', comment: { raw: "some comment" }, custom_field.attribute_name(:camel_case) => { - raw: "some cf text" + raw: 'some cf text' } } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/payload/_links/project/href") + .at_path('_embedded/payload/_links/project/href') expect(body) .to be_json_eql(api_v3_paths.work_package(work_package.id).to_json) - .at_path("_embedded/payload/_links/workPackage/href") + .at_path('_embedded/payload/_links/workPackage/href') expect(body) .to be_json_eql(api_v3_paths.time_entries_activity(active_activity.id).to_json) - .at_path("_embedded/payload/_links/activity/href") + .at_path('_embedded/payload/_links/activity/href') expect(body) .to be_json_eql(api_v3_paths.user(user.id).to_json) - .at_path("_embedded/payload/_links/user/href") + .at_path('_embedded/payload/_links/user/href') expect(body) .to be_json_eql("some comment".to_json) @@ -154,52 +154,52 @@ expect(body) .to be_json_eql(Date.today.to_s.to_json) - .at_path("_embedded/payload/spentOn") + .at_path('_embedded/payload/spentOn') expect(body) .to be_json_eql("PT5H".to_json) - .at_path("_embedded/payload/hours") + .at_path('_embedded/payload/hours') expect(body) .to be_json_eql("some cf text".to_json) .at_path("_embedded/payload/customField#{custom_field.id}/raw") end - it "has the available values listed in the schema" do + it 'has the available values listed in the schema' do body = subject.body wp_path = api_v3_paths.time_entries_available_work_packages_on_create expect(body) .to be_json_eql(wp_path.to_json) - .at_path("_embedded/schema/workPackage/_links/allowedValues/href") + .at_path('_embedded/schema/workPackage/_links/allowedValues/href') expect(body) .to be_json_eql(api_v3_paths.time_entries_available_projects.to_json) - .at_path("_embedded/schema/project/_links/allowedValues/href") + .at_path('_embedded/schema/project/_links/allowedValues/href') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.time_entries.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:permissions) { [] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end - context "without the log_time permisson" do + context 'without the log_time permisson' do let(:permissions) { %i[log_own_time view_work_packages] } - it "does not render the user href" do + it 'does not render the user href' do expect(body) - .not_to have_json_path("_embedded/payload/_links/user/href") + .not_to have_json_path('_embedded/payload/_links/user/href') end end end diff --git a/modules/costs/spec/requests/api/time_entries/schemas/time_entry_schema_resource_spec.rb b/modules/costs/spec/requests/api/time_entries/schemas/time_entry_schema_resource_spec.rb index eb3bac336d47..868538ebeb03 100644 --- a/modules/costs/spec/requests/api/time_entries/schemas/time_entry_schema_resource_spec.rb +++ b/modules/costs/spec/requests/api/time_entries/schemas/time_entry_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Time entry schema resource", content_type: :json do +RSpec.describe 'API v3 Time entry schema resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -49,30 +49,30 @@ subject(:response) { last_response } - describe "#GET /time_entries/schema" do + describe '#GET /time_entries/schema' do before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns a schema" do + it 'returns a schema' do expect(subject.body) - .to be_json_eql("Schema".to_json) - .at_path "_type" + .to be_json_eql('Schema'.to_json) + .at_path '_type' end - it "does not embed" do + it 'does not embed' do expect(subject.body) - .not_to have_json_path("project/_links/allowedValues") + .not_to have_json_path('project/_links/allowedValues') end - context "if lacking permissions" do + context 'if lacking permissions' do let(:permissions) { [] } - it "responds with 403" do + it 'responds with 403' do expect(subject.status).to eq(403) end end diff --git a/modules/costs/spec/requests/api/time_entries/update_form_resource_spec.rb b/modules/costs/spec/requests/api/time_entries/update_form_resource_spec.rb index 2b5166332a31..d226973ba544 100644 --- a/modules/costs/spec/requests/api/time_entries/update_form_resource_spec.rb +++ b/modules/costs/spec/requests/api/time_entries/update_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::TimeEntries::UpdateFormAPI, content_type: :json do include Rack::Test::Methods @@ -62,18 +62,18 @@ subject(:response) { last_response } - describe "#POST /api/v3/time_entries/:id/form" do - it "returns 200 OK" do + describe '#POST /api/v3/time_entries/:id/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - context "with all parameters" do + context 'with all parameters' do let(:parameters) do { _links: { @@ -88,39 +88,39 @@ } }, spentOn: Date.today.to_s, - hours: "PT5H", + hours: 'PT5H', comment: { raw: "some comment" }, custom_field.attribute_name(:camel_case) => { - raw: "some cf text" + raw: 'some cf text' } } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "does not alter the entry" do + it 'does not alter the entry' do expect(time_entry.work_package) .not_to eql work_package end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/payload/_links/project/href") + .at_path('_embedded/payload/_links/project/href') expect(body) .to be_json_eql(api_v3_paths.work_package(work_package.id).to_json) - .at_path("_embedded/payload/_links/workPackage/href") + .at_path('_embedded/payload/_links/workPackage/href') expect(body) .to be_json_eql(api_v3_paths.time_entries_activity(active_activity.id).to_json) - .at_path("_embedded/payload/_links/activity/href") + .at_path('_embedded/payload/_links/activity/href') expect(body) .to be_json_eql("some comment".to_json) @@ -128,11 +128,11 @@ expect(body) .to be_json_eql(Date.today.to_s.to_json) - .at_path("_embedded/payload/spentOn") + .at_path('_embedded/payload/spentOn') expect(body) .to be_json_eql("PT5H".to_json) - .at_path("_embedded/payload/hours") + .at_path('_embedded/payload/hours') expect(body) .to be_json_eql("some cf text".to_json) @@ -143,28 +143,28 @@ .at_path("_embedded/payload/_links/user/href") end - it "has the available values listed in the schema" do + it 'has the available values listed in the schema' do body = subject.body wp_path = api_v3_paths.time_entries_available_work_packages_on_edit(time_entry.id) expect(body) .to be_json_eql(wp_path.to_json) - .at_path("_embedded/schema/workPackage/_links/allowedValues/href") + .at_path('_embedded/schema/workPackage/_links/allowedValues/href') expect(body) .to be_json_eql(api_v3_paths.time_entries_available_projects.to_json) - .at_path("_embedded/schema/project/_links/allowedValues/href") + .at_path('_embedded/schema/project/_links/allowedValues/href') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.time_entry(time_entry.id).to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "with an invalid parameter" do + context 'with an invalid parameter' do let(:parameters) do { _links: { @@ -175,24 +175,24 @@ } end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on workPackage" do - expect(subject.body).to have_json_path("_embedded/validationErrors/workPackage") + it 'has a validation error on workPackage' do + expect(subject.body).to have_json_path('_embedded/validationErrors/workPackage') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit/href") + .not_to have_json_path('_links/commit/href') end end - context "with permissions to edit own time entries" do + context 'with permissions to edit own time entries' do let(:permissions) { %i[view_time_entries edit_own_time_entries] } - context "with the time_entry being of the user" do + context 'with the time_entry being of the user' do let(:user) do user = time_entry.user @@ -204,22 +204,22 @@ user end - it "returns 200 OK" do + it 'returns 200 OK' do expect(response.status).to eq(200) end end - context "with the time_entry being of a different user" do - it "returns 403 Not Authorized" do + context 'with the time_entry being of a different user' do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:permissions) { %i[view_time_entries] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end diff --git a/modules/costs/spec/requests/api/time_entry_activity_resource_spec.rb b/modules/costs/spec/requests/api/time_entry_activity_resource_spec.rb index 04ce1d7d4fe1..95760f2ef7d9 100644 --- a/modules/costs/spec/requests/api/time_entry_activity_resource_spec.rb +++ b/modules/costs/spec/requests/api/time_entry_activity_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 time_entry_activity resource" do +RSpec.describe 'API v3 time_entry_activity resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -47,33 +47,33 @@ login_as(current_user) end - describe "GET /api/v3/time_entries/activities/:id" do + describe 'GET /api/v3/time_entries/activities/:id' do let(:path) { api_v3_paths.time_entries_activity(activity.id) } - context "for a visible root activity" do + context 'for a visible root activity' do before do activity get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the time entry" do + it 'returns the time entry' do expect(subject.body) - .to be_json_eql("TimeEntriesActivity".to_json) - .at_path("_type") + .to be_json_eql('TimeEntriesActivity'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(activity.id.to_json) - .at_path("id") + .at_path('id') end end - context "for non shared activities" do + context 'for non shared activities' do before do activity.project_id = 234 activity.save(validate: false) @@ -81,13 +81,13 @@ get path end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { [] } before do @@ -96,7 +96,7 @@ get path end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end diff --git a/modules/costs/spec/requests/api/time_entry_resource_spec.rb b/modules/costs/spec/requests/api/time_entry_resource_spec.rb index 077ad55f5074..979045ec4725 100644 --- a/modules/costs/spec/requests/api/time_entry_resource_spec.rb +++ b/modules/costs/spec/requests/api/time_entry_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 time_entry resource" do +RSpec.describe 'API v3 time_entry resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -57,7 +57,7 @@ let(:custom_field) { create(:time_entry_custom_field) } let(:custom_value) do CustomValue.create(custom_field:, - value: "1234", + value: '1234', customized: time_entry) end let(:activity) do @@ -72,10 +72,10 @@ OpenProject::Cache.clear end - describe "GET api/v3/time_entries" do + describe 'GET api/v3/time_entries' do let(:path) { api_v3_paths.time_entries } - context "without params" do + context 'without params' do before do time_entry invisible_time_entry @@ -84,22 +84,22 @@ get path end - it "responds 200 OK" do + it 'responds 200 OK' do expect(subject.status).to eq(200) end - it "returns a collection of time entries containing only the visible time entries" do + it 'returns a collection of time entries containing only the visible time entries' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(time_entry.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(custom_value.value.to_json) @@ -107,7 +107,7 @@ end end - context "with pageSize, offset and sortBy" do + context 'with pageSize, offset and sortBy' do let(:path) { "#{api_v3_paths.time_entries}?pageSize=1&offset=2&sortBy=#{[%i(id asc)].to_json}" } before do @@ -118,33 +118,33 @@ get path end - it "returns a slice of the visible time entries" do + it 'returns a slice of the visible time entries' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) - .to be_json_eql("1") - .at_path("count") + .to be_json_eql('1') + .at_path('count') expect(subject.body) .to be_json_eql(other_time_entry.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "filtering by user" do + context 'filtering by user' do let(:invisible_time_entry) do create(:time_entry, project: other_project, work_package: other_work_package, user: other_user) end let(:path) do - filter = [{ "user" => { - "operator" => "=", - "values" => [other_user.id] + filter = [{ 'user' => { + 'operator' => '=', + 'values' => [other_user.id] } }] "#{api_v3_paths.time_entries}?#{{ filters: filter.to_json }.to_query}" @@ -158,18 +158,18 @@ get path end - it "contains only the filtered time entries in the response" do + it 'contains only the filtered time entries in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(other_time_entry.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "filtering by work package" do + context 'filtering by work package' do let(:unwanted_work_package) do create(:work_package, project:, type: project.types.first) end @@ -179,9 +179,9 @@ end let(:path) do - filter = [{ "work_package" => { - "operator" => "=", - "values" => [work_package.id] + filter = [{ 'work_package' => { + 'operator' => '=', + 'values' => [work_package.id] } }] "#{api_v3_paths.time_entries}?#{{ filters: filter.to_json }.to_query}" @@ -195,25 +195,25 @@ get path end - it "contains only the filtered time entries in the response" do + it 'contains only the filtered time entries in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(time_entry.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "filtering by project" do + context 'filtering by project' do let(:other_time_entry) do create(:time_entry, project: other_project, work_package: other_work_package, user: current_user) end let(:path) do - filter = [{ "project" => { - "operator" => "=", - "values" => [other_project.id] + filter = [{ 'project' => { + 'operator' => '=', + 'values' => [other_project.id] } }] "#{api_v3_paths.time_entries}?#{{ filters: filter.to_json }.to_query}" @@ -231,27 +231,27 @@ get path end - it "contains only the filtered time entries in the response" do + it 'contains only the filtered time entries in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(other_time_entry.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "filtering by global activity" do + context 'filtering by global activity' do let(:activity) do create(:time_entry_activity) end let(:path) do filter = [ { - "activity_id" => { - "operator" => "=", - "values" => [activity.id] + 'activity_id' => { + 'operator' => '=', + 'values' => [activity.id] } } ] @@ -291,26 +291,26 @@ get path end - it "contains only the filtered time entries in the response" do + it 'contains only the filtered time entries in the response' do expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) .to be_json_eql(time_entry.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(other_time_entry.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') end end - context "invalid filter" do + context 'invalid filter' do let(:path) do - filter = [{ "bogus" => { - "operator" => "=", - "values" => ["1"] + filter = [{ 'bogus' => { + 'operator' => '=', + 'values' => ['1'] } }] "#{api_v3_paths.time_entries}?#{{ filters: filter.to_json }.to_query}" @@ -322,17 +322,17 @@ get path end - it "returns an error" do + it 'returns an error' do expect(subject.status).to eq(400) expect(subject.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:InvalidQuery'.to_json) + .at_path('errorIdentifier') end end end - describe "GET /api/v3/time_entries/:id" do + describe 'GET /api/v3/time_entries/:id' do let(:path) { api_v3_paths.time_entry(time_entry.id) } before do @@ -342,36 +342,36 @@ get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the time entry" do + it 'returns the time entry' do expect(subject.body) - .to be_json_eql("TimeEntry".to_json) - .at_path("_type") + .to be_json_eql('TimeEntry'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(time_entry.id.to_json) - .at_path("id") + .at_path('id') expect(subject.body) .to be_json_eql(custom_value.value.to_json) .at_path("customField#{custom_field.id}/raw") end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { [] } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end end end - describe "POST api/v3/time_entries" do + describe 'POST api/v3/time_entries' do let(:permissions) { %i(view_time_entries log_time view_work_packages) } let(:path) { api_v3_paths.time_entries } let(:params) do @@ -387,13 +387,13 @@ href: api_v3_paths.work_package(work_package.id) } }, - hours: "PT5H", + hours: 'PT5H', comment: { raw: "some comment" }, spentOn: "2017-07-28", custom_field.attribute_name(:camel_case) => { - raw: "some cf text" + raw: 'some cf text' } } end @@ -404,14 +404,14 @@ additional_setup.call - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "responds 201 CREATED" do + it 'responds 201 CREATED' do expect(subject.status).to eq(201) end - it "creates another time entry with the provided values" do + it 'creates another time entry with the provided values' do expect(TimeEntry.count) .to be 1 @@ -439,26 +439,26 @@ .to eql Date.parse("2017-07-28") expect(new_entry.send(custom_field.attribute_getter)) - .to eql "some cf text" + .to eql 'some cf text' end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { %i(view_time_entries view_work_packages) } - it "returns 403" do + it 'returns 403' do expect(subject.status) .to be(403) end end - context "if sending an activity the project disables" do + context 'if sending an activity the project disables' do let(:disable_activity) do TimeEntryActivitiesProject.insert({ activity_id: activity.id, project_id: project.id, active: false }) end let(:additional_setup) { -> { disable_activity } } - it "returns 422 and complains about the activity" do + it 'returns 422 and complains about the activity' do expect(subject.status) .to be(422) @@ -468,7 +468,7 @@ end end - context "when sending invalid params" do + context 'when sending invalid params' do let(:params) do { _links: { @@ -482,16 +482,16 @@ href: api_v3_paths.work_package(work_package.id + 1) } }, - hours: "PT5H", + hours: 'PT5H', comment: "some comment", spentOn: "2017-07-28", custom_field.attribute_name(:camel_case) => { - raw: "some cf text" + raw: 'some cf text' } } end - it "returns 422 and complains about work packages" do + it 'returns 422 and complains about work packages' do expect(subject.status) .to be(422) @@ -502,13 +502,13 @@ end end - describe "PATCH api/v3/time_entries/:id" do + describe 'PATCH api/v3/time_entries/:id' do let(:path) { api_v3_paths.time_entry(time_entry.id) } let(:permissions) { %i(edit_time_entries view_time_entries view_work_packages) } let(:params) do { - hours: "PT10H", + hours: 'PT10H', activity: { href: api_v3_paths.time_entries_activity(activity.id) } @@ -523,10 +523,10 @@ additional_setup.call - patch path, params.to_json, "CONTENT_TYPE" => "application/json" + patch path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "updates the time entry" do + it 'updates the time entry' do expect(subject.status).to eq(200) time_entry.reload @@ -535,23 +535,23 @@ expect(time_entry.activity).to eq activity end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { %i(view_time_entries) } - it "returns 403" do + it 'returns 403' do expect(subject.status) .to be(403) end end - context "if sending an activity the project disables" do + context 'if sending an activity the project disables' do let(:disable_activity) do TimeEntryActivitiesProject.insert({ activity_id: activity.id, project_id: project.id, active: false }) end let(:additional_setup) { -> { disable_activity } } - it "returns 422 and complains about the activity" do + it 'returns 422 and complains about the activity' do expect(subject.status) .to be(422) @@ -561,7 +561,7 @@ end end - context "when sending invalid params" do + context 'when sending invalid params' do let(:params) do { _links: { @@ -572,7 +572,7 @@ } end - it "returns 422 and complains about work packages" do + it 'returns 422 and complains about work packages' do expect(subject.status) .to be(422) @@ -583,7 +583,7 @@ end end - describe "DELETE api/v3/time_entries/:id" do + describe 'DELETE api/v3/time_entries/:id' do let(:path) { api_v3_paths.time_entry(time_entry.id) } let(:permissions) { %i(edit_own_time_entries view_time_entries view_work_packages) } let(:params) {} @@ -593,17 +593,17 @@ other_time_entry custom_value - delete path, params.to_json, "CONTENT_TYPE" => "application/json" + delete path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "deleted the time entry" do + it 'deleted the time entry' do expect(subject.status).to eq(204) end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { %i(view_time_entries) } - it "returns 403" do + it 'returns 403' do expect(subject.status) .to be(403) end @@ -611,41 +611,41 @@ subject(:response) { last_response } - shared_examples_for "deletes the time_entry" do - it "responds with HTTP No Content" do + shared_examples_for 'deletes the time_entry' do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "removes the time_entry from the DB" do + it 'removes the time_entry from the DB' do expect(TimeEntry.exists?(time_entry.id)).to be_falsey end end - shared_examples_for "does not delete the time_entry" do |status = 403| + shared_examples_for 'does not delete the time_entry' do |status = 403| it "responds with #{status}" do expect(subject.status).to eq status end - it "does not delete the time_entry" do + it 'does not delete the time_entry' do expect(TimeEntry.exists?(time_entry.id)).to be_truthy end end - context "with the user being the author" do - it_behaves_like "deletes the time_entry" + context 'with the user being the author' do + it_behaves_like 'deletes the time_entry' end - context "with the user not being the author" do + context 'with the user not being the author' do let(:time_entry) { other_time_entry } - context "but permission to edit all time entries" do + context 'but permission to edit all time entries' do let(:permissions) { %i(edit_time_entries view_time_entries view_work_packages) } - it_behaves_like "deletes the time_entry" + it_behaves_like 'deletes the time_entry' end - context "with permission to delete own time entries" do - it_behaves_like "does not delete the time_entry", 403 + context 'with permission to delete own time entries' do + it_behaves_like 'does not delete the time_entry', 403 end end end diff --git a/modules/costs/spec/routing/cost_objects_routing_spec.rb b/modules/costs/spec/routing/cost_objects_routing_spec.rb index 23c495914f19..57a28c568335 100644 --- a/modules/costs/spec/routing/cost_objects_routing_spec.rb +++ b/modules/costs/spec/routing/cost_objects_routing_spec.rb @@ -26,62 +26,62 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BudgetsController do - describe "routing" do + describe 'routing' do it { - expect(get("/projects/blubs/budgets/new")).to route_to(controller: "budgets", - action: "new", - project_id: "blubs") + expect(get('/projects/blubs/budgets/new')).to route_to(controller: 'budgets', + action: 'new', + project_id: 'blubs') } it { - expect(post("/projects/blubs/budgets")).to route_to(controller: "budgets", - action: "create", - project_id: "blubs") + expect(post('/projects/blubs/budgets')).to route_to(controller: 'budgets', + action: 'create', + project_id: 'blubs') } it { - expect(get("/projects/blubs/budgets")).to route_to(controller: "budgets", - action: "index", - project_id: "blubs") + expect(get('/projects/blubs/budgets')).to route_to(controller: 'budgets', + action: 'index', + project_id: 'blubs') } it { - expect(get("/budgets/5")).to route_to(controller: "budgets", - action: "show", - id: "5") + expect(get('/budgets/5')).to route_to(controller: 'budgets', + action: 'show', + id: '5') } it { - expect(put("/budgets/5")).to route_to(controller: "budgets", - action: "update", - id: "5") + expect(put('/budgets/5')).to route_to(controller: 'budgets', + action: 'update', + id: '5') } it { - expect(delete("/budgets/5")).to route_to(controller: "budgets", - action: "destroy", - id: "5") + expect(delete('/budgets/5')).to route_to(controller: 'budgets', + action: 'destroy', + id: '5') } it { - expect(post("/projects/42/budgets/update_material_budget_item")).to route_to(controller: "budgets", - action: "update_material_budget_item", - project_id: "42") + expect(post('/projects/42/budgets/update_material_budget_item')).to route_to(controller: 'budgets', + action: 'update_material_budget_item', + project_id: '42') } it { - expect(post("/projects/42/budgets/update_labor_budget_item")).to route_to(controller: "budgets", - action: "update_labor_budget_item", - project_id: "42") + expect(post('/projects/42/budgets/update_labor_budget_item')).to route_to(controller: 'budgets', + action: 'update_labor_budget_item', + project_id: '42') } it { - expect(get("/budgets/5/copy")).to route_to(controller: "budgets", - action: "copy", - id: "5") + expect(get('/budgets/5/copy')).to route_to(controller: 'budgets', + action: 'copy', + id: '5') } end end diff --git a/modules/costs/spec/routing/cost_types_routing_spec.rb b/modules/costs/spec/routing/cost_types_routing_spec.rb index 3a000910ad94..816f12344f36 100644 --- a/modules/costs/spec/routing/cost_types_routing_spec.rb +++ b/modules/costs/spec/routing/cost_types_routing_spec.rb @@ -26,53 +26,53 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CostTypesController do - describe "routing" do + describe 'routing' do it { - expect(get("/cost_types")).to route_to(controller: "cost_types", - action: "index") + expect(get('/cost_types')).to route_to(controller: 'cost_types', + action: 'index') } it { - expect(post("/cost_types")).to route_to(controller: "cost_types", - action: "create") + expect(post('/cost_types')).to route_to(controller: 'cost_types', + action: 'create') } it { - expect(get("/cost_types/new")).to route_to(controller: "cost_types", - action: "new") + expect(get('/cost_types/new')).to route_to(controller: 'cost_types', + action: 'new') } it { - expect(get("/cost_types/5/edit")).to route_to(controller: "cost_types", - action: "edit", - id: "5") + expect(get('/cost_types/5/edit')).to route_to(controller: 'cost_types', + action: 'edit', + id: '5') } it { - expect(put("/cost_types/5")).to route_to(controller: "cost_types", - action: "update", - id: "5") + expect(put('/cost_types/5')).to route_to(controller: 'cost_types', + action: 'update', + id: '5') } it { - expect(put("/cost_types/5/set_rate")).to route_to(controller: "cost_types", - action: "set_rate", - id: "5") + expect(put('/cost_types/5/set_rate')).to route_to(controller: 'cost_types', + action: 'set_rate', + id: '5') } it { - expect(delete("/cost_types/5")).to route_to(controller: "cost_types", - action: "destroy", - id: "5") + expect(delete('/cost_types/5')).to route_to(controller: 'cost_types', + action: 'destroy', + id: '5') } it { - expect(patch("/cost_types/5/restore")).to route_to(controller: "cost_types", - action: "restore", - id: "5") + expect(patch('/cost_types/5/restore')).to route_to(controller: 'cost_types', + action: 'restore', + id: '5') } end end diff --git a/modules/costs/spec/routing/costlog_routing_spec.rb b/modules/costs/spec/routing/costlog_routing_spec.rb index d41d6b005571..1c0dfbe7345a 100644 --- a/modules/costs/spec/routing/costlog_routing_spec.rb +++ b/modules/costs/spec/routing/costlog_routing_spec.rb @@ -26,44 +26,44 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CostlogController do - describe "routing" do + describe 'routing' do it { - expect(get("/projects/blubs/cost_entries/new")).to route_to(controller: "costlog", - action: "new", - project_id: "blubs") + expect(get('/projects/blubs/cost_entries/new')).to route_to(controller: 'costlog', + action: 'new', + project_id: 'blubs') } it { - expect(post("/projects/blubs/cost_entries")).to route_to(controller: "costlog", - action: "create", - project_id: "blubs") + expect(post('/projects/blubs/cost_entries')).to route_to(controller: 'costlog', + action: 'create', + project_id: 'blubs') } it { - expect(get("/work_packages/5/cost_entries/new")).to route_to(controller: "costlog", - action: "new", - work_package_id: "5") + expect(get('/work_packages/5/cost_entries/new')).to route_to(controller: 'costlog', + action: 'new', + work_package_id: '5') } it { - expect(get("/cost_entries/5/edit")).to route_to(controller: "costlog", - action: "edit", - id: "5") + expect(get('/cost_entries/5/edit')).to route_to(controller: 'costlog', + action: 'edit', + id: '5') } it { - expect(put("/cost_entries/5")).to route_to(controller: "costlog", - action: "update", - id: "5") + expect(put('/cost_entries/5')).to route_to(controller: 'costlog', + action: 'update', + id: '5') } it { - expect(delete("/cost_entries/5")).to route_to(controller: "costlog", - action: "destroy", - id: "5") + expect(delete('/cost_entries/5')).to route_to(controller: 'costlog', + action: 'destroy', + id: '5') } end end diff --git a/modules/costs/spec/routing/hourly_rates_routing_spec.rb b/modules/costs/spec/routing/hourly_rates_routing_spec.rb index 1d1296561167..a9d89cf8d879 100644 --- a/modules/costs/spec/routing/hourly_rates_routing_spec.rb +++ b/modules/costs/spec/routing/hourly_rates_routing_spec.rb @@ -26,42 +26,42 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe HourlyRatesController do - describe "routing" do + describe 'routing' do it { - expect(get("/projects/blubs/hourly_rates/5")).to route_to(controller: "hourly_rates", - action: "show", - project_id: "blubs", - id: "5") + expect(get('/projects/blubs/hourly_rates/5')).to route_to(controller: 'hourly_rates', + action: 'show', + project_id: 'blubs', + id: '5') } it { - expect(get("/projects/blubs/hourly_rates/5/edit")).to route_to(controller: "hourly_rates", - action: "edit", - project_id: "blubs", - id: "5") + expect(get('/projects/blubs/hourly_rates/5/edit')).to route_to(controller: 'hourly_rates', + action: 'edit', + project_id: 'blubs', + id: '5') } it { - expect(get("/hourly_rates/5/edit")).to route_to(controller: "hourly_rates", - action: "edit", - id: "5") + expect(get('/hourly_rates/5/edit')).to route_to(controller: 'hourly_rates', + action: 'edit', + id: '5') } it { - expect(put("/projects/blubs/hourly_rates/5")).to route_to(controller: "hourly_rates", - action: "update", - project_id: "blubs", - id: "5") + expect(put('/projects/blubs/hourly_rates/5')).to route_to(controller: 'hourly_rates', + action: 'update', + project_id: 'blubs', + id: '5') } it { - expect(post("/projects/blubs/hourly_rates/5/set_rate")).to route_to(controller: "hourly_rates", - action: "set_rate", - project_id: "blubs", - id: "5") + expect(post('/projects/blubs/hourly_rates/5/set_rate')).to route_to(controller: 'hourly_rates', + action: 'set_rate', + project_id: 'blubs', + id: '5') } end end diff --git a/modules/costs/spec/services/time_entries/set_attributes_service_integration_spec.rb b/modules/costs/spec/services/time_entries/set_attributes_service_integration_spec.rb index 968992569fab..bdb3155be31f 100644 --- a/modules/costs/spec/services/time_entries/set_attributes_service_integration_spec.rb +++ b/modules/costs/spec/services/time_entries/set_attributes_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe TimeEntries::SetAttributesService, "integration", type: :model do +RSpec.describe TimeEntries::SetAttributesService, 'integration', type: :model do let(:project) { create(:project) } let(:user) do create(:user, @@ -52,14 +52,14 @@ subject { instance.call(params) } - context "default activity not active in project" do + context 'default activity not active in project' do let!(:default_activity) { create(:time_entry_activity, is_default: true) } before do project.time_entry_activities_projects.create(activity_id: default_activity.id, active: false) end - it "does not assign the default activity" do + it 'does not assign the default activity' do expect(subject).to be_success expect(subject.result.activity).to be_nil end diff --git a/modules/costs/spec/services/time_entries/set_attributes_service_spec.rb b/modules/costs/spec/services/time_entries/set_attributes_service_spec.rb index 6339b66221c1..34b82bfd6c4d 100644 --- a/modules/costs/spec/services/time_entries/set_attributes_service_spec.rb +++ b/modules/costs/spec/services/time_entries/set_attributes_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntries::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } @@ -36,9 +36,9 @@ let(:project) { build_stubbed(:project) } let(:spent_on) { Time.zone.today.to_s } let(:hours) { 5.0 } - let(:comments) { "some comment" } + let(:comments) { 'some comment' } let(:contract_instance) do - contract = double("contract_instance") # rubocop:disable RSpec/VerifiedDoubles + contract = double('contract_instance') # rubocop:disable RSpec/VerifiedDoubles allow(contract) .to receive(:validate) .and_return(contract_valid) @@ -48,7 +48,7 @@ contract end - let(:contract_errors) { double("contract_errors") } # rubocop:disable RSpec/VerifiedDoubles + let(:contract_errors) { double('contract_errors') } # rubocop:disable RSpec/VerifiedDoubles let(:contract_valid) { true } let(:time_entry_valid) { true } @@ -77,12 +77,12 @@ subject { instance.call(params) } - it "creates a new time entry" do + it 'creates a new time entry' do expect(subject.result) .to eql time_entry_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end @@ -94,14 +94,14 @@ .to eql user end - it "notes the user to be system changed" do + it 'notes the user to be system changed' do subject - expect(time_entry_instance.changed_by_system["user_id"]) + expect(time_entry_instance.changed_by_system['user_id']) .to eql [nil, user.id] end - it "assigns the default TimeEntryActivity" do + it 'assigns the default TimeEntryActivity' do allow(TimeEntryActivity) .to receive(:default) .and_return(default_activity) @@ -112,7 +112,7 @@ .to eql default_activity end - context "with params" do + context 'with params' do let(:params) do { work_package:, @@ -136,7 +136,7 @@ }.with_indifferent_access end - it "assigns the params" do + it 'assigns the params' do subject attributes_of_interest = time_entry_instance @@ -148,14 +148,14 @@ end end - context "with hours == 0" do + context 'with hours == 0' do let(:params) do { hours: 0 } end - it "sets hours to nil" do + it 'sets hours to nil' do subject expect(time_entry_instance.hours) @@ -163,14 +163,14 @@ end end - context "with project not specified" do + context 'with project not specified' do let(:params) do { work_package: } end - it "sets the project to the work_package's project" do + it 'sets the project to the work_package\'s project' do subject expect(time_entry_instance.project) @@ -178,7 +178,7 @@ end end - context "with another user setting logged by" do + context 'with another user setting logged by' do let(:other_user) { create(:user) } let(:time_entry_instance) { create(:time_entry, user: other_user, logged_by: other_user, hours: 1) } @@ -188,7 +188,7 @@ } end - it "updates the entry, and updates the logged by" do + it 'updates the entry, and updates the logged by' do expect { subject } .to change(time_entry_instance, :hours).from(1).to(1234) .and change(time_entry_instance, :logged_by).from(other_user).to(user) @@ -197,13 +197,13 @@ end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } let(:expect_time_instance_save) do expect(time_entry_instance).not_to receive(:save) # rubocop:disable RSpec/MessageSpies end - it "returns failure" do + it 'returns failure' do expect(subject) .not_to be_success end diff --git a/modules/costs/spec/spec_helper.rb b/modules/costs/spec/spec_helper.rb index 1b8d73a3e5a1..073c6827c8e1 100644 --- a/modules/costs/spec/spec_helper.rb +++ b/modules/costs/spec/spec_helper.rb @@ -27,8 +27,8 @@ #++ # -- load spec_helper from OpenProject core -require "spec_helper" +require 'spec_helper' -require File.join(File.dirname(__FILE__), "plugin_spec_helper") +require File.join(File.dirname(__FILE__), 'plugin_spec_helper') -Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].sort.each { |f| require f } +Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].sort.each { |f| require f } diff --git a/modules/dashboards/config/routes.rb b/modules/dashboards/config/routes.rb index 2abbb2a31737..1f17b0e4336e 100644 --- a/modules/dashboards/config/routes.rb +++ b/modules/dashboards/config/routes.rb @@ -1,3 +1,3 @@ Rails.application.routes.draw do - get "/projects/:project_id/dashboards", to: "dashboards/dashboards#show", as: :project_dashboards + get '/projects/:project_id/dashboards', to: 'dashboards/dashboards#show', as: :project_dashboards end diff --git a/modules/dashboards/dashboards.gemspec b/modules/dashboards/dashboards.gemspec index 0bbc19a888f5..84657708333e 100644 --- a/modules/dashboards/dashboards.gemspec +++ b/modules/dashboards/dashboards.gemspec @@ -1,11 +1,11 @@ Gem::Specification.new do |s| s.name = "dashboards" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = ["OpenProject"] s.summary = "OpenProject Dashboards" s.files = Dir["{app,config,db,lib}/**/*"] - s.add_dependency "grids" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'grids' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/dashboards/lib/dashboards/engine.rb b/modules/dashboards/lib/dashboards/engine.rb index c516b2039dcf..86c70fabc9c4 100644 --- a/modules/dashboards/lib/dashboards/engine.rb +++ b/modules/dashboards/lib/dashboards/engine.rb @@ -1,6 +1,6 @@ # Prevent load-order problems in case openproject-plugins is listed after a plugin in the Gemfile # or not at all -require "open_project/plugins" +require 'open_project/plugins' module Dashboards class Engine < ::Rails::Engine @@ -8,36 +8,36 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - initializer "dashboards.menu" do + initializer 'dashboards.menu' do ::Redmine::MenuManager.map(:project_menu) do |menu| menu.push(:dashboards, - { controller: "/dashboards/dashboards", action: "show" }, - caption: :"dashboards.label", + { controller: '/dashboards/dashboards', action: 'show' }, + caption: :'dashboards.label', after: :work_packages, - icon: "status", - badge: "label_menu_badge.alpha") + icon: 'status', + badge: 'label_menu_badge.alpha') end end - initializer "dashboards.permissions" do + initializer 'dashboards.permissions' do Rails.application.reloader.to_prepare do OpenProject::AccessControl.map do |ac_map| ac_map.project_module(:dashboards) do |pm_map| pm_map.permission(:view_dashboards, - { "dashboards/dashboards": %i[show] }, + { 'dashboards/dashboards': %i[show] }, permissible_on: :project) pm_map.permission(:manage_dashboards, - { "dashboards/dashboards": %i[show] }, + { 'dashboards/dashboards': %i[show] }, permissible_on: :project) end end end end - initializer "dashboards.conversion" do - require Rails.root.join("config/constants/ar_to_api_conversions") + initializer 'dashboards.conversion' do + require Rails.root.join('config/constants/ar_to_api_conversions') - Constants::ARToAPIConversions.add("grids/dashboard": "grid") + Constants::ARToAPIConversions.add('grids/dashboard': 'grid') end config.to_prepare do diff --git a/modules/dashboards/lib/dashboards/grid_registration.rb b/modules/dashboards/lib/dashboards/grid_registration.rb index d6ec9da8d864..aa65572d09fe 100644 --- a/modules/dashboards/lib/dashboards/grid_registration.rb +++ b/modules/dashboards/lib/dashboards/grid_registration.rb @@ -1,6 +1,6 @@ module Dashboards class GridRegistration < ::Grids::Configuration::InProjectBaseRegistration - grid_class "Grids::Dashboard" + grid_class 'Grids::Dashboard' to_scope :project_dashboards_path defaults -> { @@ -9,15 +9,15 @@ class GridRegistration < ::Grids::Configuration::InProjectBaseRegistration column_count: 2, widgets: [ { - identifier: "work_packages_table", + identifier: 'work_packages_table', start_row: 1, end_row: 2, start_column: 1, end_column: 2, options: { - name: I18n.t("js.grid.widgets.work_packages_table.title"), + name: I18n.t('js.grid.widgets.work_packages_table.title'), queryProps: { - "columns[]": %w(id project type subject), + 'columns[]': %w(id project type subject), filters: JSON.dump([{ status: { operator: "o", values: [] } }]) } } @@ -28,6 +28,6 @@ class GridRegistration < ::Grids::Configuration::InProjectBaseRegistration view_permission :view_dashboards edit_permission :manage_dashboards - in_project_scope_path ["dashboards"] + in_project_scope_path ['dashboards'] end end diff --git a/modules/dashboards/spec/contracts/grids/create_contract_spec.rb b/modules/dashboards/spec/contracts/grids/create_contract_spec.rb index 68e768f6db08..0da26fb03238 100644 --- a/modules/dashboards/spec/contracts/grids/create_contract_spec.rb +++ b/modules/dashboards/spec/contracts/grids/create_contract_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe Grids::CreateContract do - include_context "grid contract" - include_context "model contract" + include_context 'grid contract' + include_context 'model contract' - it_behaves_like "shared grid contract attributes" + it_behaves_like 'shared grid contract attributes' - describe "user_id" do - context "for a Grids::Dashboard" do + describe 'user_id' do + context 'for a Grids::Dashboard' do let(:grid) { build_stubbed(:dashboard, default_values) } - it_behaves_like "is not writable" do + it_behaves_like 'is not writable' do let(:attribute) { :user_id } let(:value) { 5 } end end end - describe "project_id" do - context "for a Grids::Dashboard" do + describe 'project_id' do + context 'for a Grids::Dashboard' do let(:grid) { build_stubbed(:dashboard, default_values) } - it_behaves_like "is writable" do + it_behaves_like 'is writable' do let(:attribute) { :project_id } let(:value) { 5 } end diff --git a/modules/dashboards/spec/contracts/grids/shared_examples.rb b/modules/dashboards/spec/contracts/grids/shared_examples.rb index 21b73f51533e..ad853a8e648a 100644 --- a/modules/dashboards/spec/contracts/grids/shared_examples.rb +++ b/modules/dashboards/spec/contracts/grids/shared_examples.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "grid contract" do +RSpec.shared_context 'grid contract' do let(:user) { build_stubbed(:user) } let(:instance) { described_class.new(grid, user) } let(:project) { build_stubbed(:project) } @@ -51,32 +51,32 @@ end end -RSpec.shared_examples_for "shared grid contract attributes" do - include_context "model contract" +RSpec.shared_examples_for 'shared grid contract attributes' do + include_context 'model contract' let(:model) { grid } - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end - context "if not having the manage_dashbaords permission" do + context 'if not having the manage_dashbaords permission' do let(:permissions) { %i[save_queries] } - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:scope]) .to contain_exactly({ error: :inclusion }) end end - describe "widgets" do - it_behaves_like "is writable" do + describe 'widgets' do + it_behaves_like 'is writable' do let(:attribute) { :widgets } let(:value) do [ @@ -84,233 +84,233 @@ end_row: 4, start_column: 2, end_column: 5, - identifier: "work_packages_table") + identifier: 'work_packages_table') ] end end - context "invalid identifier" do + context 'invalid identifier' do before do grid.widgets.build(start_row: 1, end_row: 4, start_column: 2, end_column: 5, - identifier: "bogus_identifier") + identifier: 'bogus_identifier') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :inclusion }) end end - context "collisions between widgets" do + context 'collisions between widgets' do before do grid.widgets.build(start_row: 1, end_row: 3, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') grid.widgets.build(start_row: 2, end_row: 4, start_column: 2, end_column: 4, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :overlaps }, { error: :overlaps }) end end - context "widgets having the same start column as another's end column" do + context 'widgets having the same start column as another\'s end column' do before do grid.widgets.build(start_row: 1, end_row: 3, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') grid.widgets.build(start_row: 1, end_row: 3, start_column: 3, end_column: 4, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "widgets having the same start row as another's end row" do + context 'widgets having the same start row as another\'s end row' do before do grid.widgets.build(start_row: 1, end_row: 3, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') grid.widgets.build(start_row: 3, end_row: 4, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "widgets being outside (max) of the grid" do + context 'widgets being outside (max) of the grid' do before do grid.widgets.build(start_row: 1, end_row: grid.row_count + 2, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :outside }) end end - context "widgets being outside (min) of the grid" do + context 'widgets being outside (min) of the grid' do before do grid.widgets.build(start_row: 1, end_row: 2, start_column: -1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :outside }) end end - context "widgets spanning the whole grid" do + context 'widgets spanning the whole grid' do before do grid.widgets.build(start_row: 1, end_row: grid.row_count + 1, start_column: 1, end_column: grid.column_count + 1, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "widgets having start after end column" do + context 'widgets having start after end column' do before do grid.widgets.build(start_row: 1, end_row: 2, start_column: 4, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) end end - context "widgets having start after end row" do + context 'widgets having start after end row' do before do grid.widgets.build(start_row: 4, end_row: 2, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) end end - context "widgets having start equals end column" do + context 'widgets having start equals end column' do before do grid.widgets.build(start_row: 1, end_row: 2, start_column: 4, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) end end - context "widgets having start equals end row" do + context 'widgets having start equals end row' do before do grid.widgets.build(start_row: 2, end_row: 2, start_column: 1, end_column: 3, - identifier: "work_packages_table") + identifier: 'work_packages_table') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) diff --git a/modules/dashboards/spec/factories/grid_factory.rb b/modules/dashboards/spec/factories/grid_factory.rb index 691119b01e68..3db88797b30c 100644 --- a/modules/dashboards/spec/factories/grid_factory.rb +++ b/modules/dashboards/spec/factories/grid_factory.rb @@ -1,12 +1,12 @@ FactoryBot.define do - factory :dashboard, class: "Grids::Dashboard" do + factory :dashboard, class: 'Grids::Dashboard' do project row_count { 7 } column_count { 4 } widgets do [ Grids::Widget.new( - identifier: "work_packages_table", + identifier: 'work_packages_table', start_row: 1, end_row: 7, start_column: 1, @@ -16,7 +16,7 @@ end end - factory :dashboard_with_table, class: "Grids::Dashboard" do + factory :dashboard_with_table, class: 'Grids::Dashboard' do project row_count { 7 } column_count { 4 } @@ -25,13 +25,13 @@ query = create(:query, project: dashboard.project, public: true) widget = build(:grid_widget, - identifier: "work_packages_table", + identifier: 'work_packages_table', start_row: 1, end_row: 7, start_column: 1, end_column: 3, options: { - name: "Work package table", + name: 'Work package table', queryId: query.id }) @@ -39,21 +39,21 @@ end end - factory :dashboard_with_custom_text, class: "Grids::Dashboard" do + factory :dashboard_with_custom_text, class: 'Grids::Dashboard' do project row_count { 7 } column_count { 4 } callback(:after_build) do |dashboard| widget = build(:grid_widget, - identifier: "custom_text", + identifier: 'custom_text', start_row: 1, end_row: 7, start_column: 1, end_column: 3, options: { - name: "Custom text", - text: "Lorem ipsum" + name: 'Custom text', + text: 'Lorem ipsum' }) dashboard.widgets = [widget] diff --git a/modules/dashboards/spec/features/custom_text_spec.rb b/modules/dashboards/spec/features/custom_text_spec.rb index 92de98472e98..764a90d5df3f 100644 --- a/modules/dashboards/spec/features/custom_text_spec.rb +++ b/modules/dashboards/spec/features/custom_text_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Project description widget on dashboard", :js do - let!(:type) { create(:type_task, name: "Task") } +RSpec.describe 'Project description widget on dashboard', :js do + let!(:type) { create(:type_task, name: 'Task') } let!(:project) do create(:project, types: [type]) end @@ -52,109 +52,109 @@ let(:dashboard_page) do Pages::Dashboard.new(project) end - let(:image_fixture) { UploadedFile.load_from("spec/fixtures/files/image.png") } - let(:editor) { Components::WysiwygEditor.new "body" } - let(:field) { TextEditorField.new(page, "description", selector: ".inline-edit--active-field") } + let(:image_fixture) { UploadedFile.load_from('spec/fixtures/files/image.png') } + let(:editor) { Components::WysiwygEditor.new 'body' } + let(:field) { TextEditorField.new(page, 'description', selector: '.inline-edit--active-field') } before do login_as user end - context "for a user having edit permissions" do + context 'for a user having edit permissions' do before do dashboard_page.visit! end - it "can use the wp create button macro within it" do + it 'can use the wp create button macro within it' do dashboard_page.add_widget(1, 1, :within, "Custom text") sleep(0.1) # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - custom_text_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + custom_text_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within custom_text_widget.area do - find(".inplace-editing--container").click + find('.inplace-editing--container').click end - editor.insert_macro "Insert create work package button" + editor.insert_macro 'Insert create work package button' - expect(page).to have_css(".spot-modal") - select "Task", from: "selected-type" - find(".spot-modal--submit-button").click + expect(page).to have_css('.spot-modal') + select 'Task', from: 'selected-type' + find('.spot-modal--submit-button').click field.save! - dashboard_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') - within("#content") do + within('#content') do expect(page).to have_css("a[href=\"/projects/#{project.identifier}/work_packages/new?type=#{type.id}\"]") end end - it "can add the widget set custom text and upload attachments" do + it 'can add the widget set custom text and upload attachments' do dashboard_page.add_widget(1, 1, :within, "Custom text") sleep(0.1) # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - custom_text_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + custom_text_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within custom_text_widget.area do - find(".inplace-editing--container").click + find('.inplace-editing--container').click - field.set_value("My own little text") + field.set_value('My own little text') field.save! end - dashboard_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') within custom_text_widget.area do expect(page) - .to have_css(".inline-edit--display-field", text: "My own little text") + .to have_css('.inline-edit--display-field', text: 'My own little text') - find(".inplace-editing--container").click + find('.inplace-editing--container').click - field.set_value("My new text") + field.set_value('My new text') field.cancel_by_click expect(page) - .to have_css(".inline-edit--display-field", text: "My own little text") + .to have_css('.inline-edit--display-field', text: 'My own little text') end - dashboard_page.expect_no_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_no_toaster message: I18n.t('js.notice_successful_update') within custom_text_widget.area do # adding an image - find(".inplace-editing--container").click + find('.inplace-editing--container').click sleep(0.1) end # The drag_attachment is written in a way that it requires to be executed with page on body # so we cannot have it wrapped in the within block. - editor.drag_attachment image_fixture.path, "Image uploaded" + editor.drag_attachment image_fixture.path, 'Image uploaded' within custom_text_widget.area do - expect(page).to have_test_selector("op-attachment-list-item", text: "image.png") - expect(page).to have_no_css("notifications-upload-progress") + expect(page).to have_test_selector('op-attachment-list-item', text: 'image.png') + expect(page).to have_no_css('notifications-upload-progress') field.save! end - dashboard_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') within custom_text_widget.area do expect(page) - .to have_css("#content img", count: 1) + .to have_css('#content img', count: 1) expect(page) - .not_to have_test_selector("op-attachment-list-item", text: "image.png") + .not_to have_test_selector('op-attachment-list-item', text: 'image.png') end end end - context "for a user lacking edit permissions" do + context 'for a user lacking edit permissions' do let!(:dashboard) do create(:dashboard_with_custom_text, project:) end @@ -167,15 +167,15 @@ dashboard_page.visit! end - it "allows reading but not editing the custom text" do - custom_text_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + it 'allows reading but not editing the custom text' do + custom_text_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within custom_text_widget.area do expect(page) .to have_content(dashboard.widgets.first.options[:text]) expect(page) - .to have_no_css(".inplace-editing--container") + .to have_no_css('.inplace-editing--container') end end end diff --git a/modules/dashboards/spec/features/docments_spec.rb b/modules/dashboards/spec/features/docments_spec.rb index 55d63695cbff..adc46559269f 100644 --- a/modules/dashboards/spec/features/docments_spec.rb +++ b/modules/dashboards/spec/features/docments_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Documents widget on dashboard", :js do +RSpec.describe 'Documents widget on dashboard', :js do let!(:project) { create(:project) } let!(:other_project) { create(:project) } let!(:visible_document) do create(:document, project:, - description: "blubs") + description: 'blubs') end let!(:invisible_document) do create(:document, @@ -64,11 +64,11 @@ dashboard.visit! end - it "can add the widget and see the visible documents" do + it 'can add the widget and see the visible documents' do # within top-right area, add an additional widget - dashboard.add_widget(1, 1, :within, "Documents") + dashboard.add_widget(1, 1, :within, 'Documents') - document_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + document_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within document_widget.area do expect(page) @@ -76,7 +76,7 @@ expect(page) .to have_content visible_document.description expect(page) - .to have_content visible_document.created_at.strftime("%m/%d/%Y") + .to have_content visible_document.created_at.strftime('%m/%d/%Y') expect(page) .to have_no_content invisible_document.title diff --git a/modules/dashboards/spec/features/members_principals_spec.rb b/modules/dashboards/spec/features/members_principals_spec.rb index b40184e3431b..bed0d1f449bc 100644 --- a/modules/dashboards/spec/features/members_principals_spec.rb +++ b/modules/dashboards/spec/features/members_principals_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Dashboard page members", :js do +RSpec.describe 'Dashboard page members', :js do shared_let(:type) { create(:type) } - shared_let(:project) { create(:project, types: [type], description: "My **custom** description") } + shared_let(:project) { create(:project, types: [type], description: 'My **custom** description') } shared_let(:permissions) do %i[manage_dashboards @@ -42,20 +42,20 @@ shared_let(:user) do create(:user, - firstname: "Foo", - lastname: "Bar", + firstname: 'Foo', + lastname: 'Bar', member_with_permissions: { project => permissions }) end shared_let(:group) do create(:group, - name: "DEV Team", + name: 'DEV Team', member_with_permissions: { project => permissions }) end shared_let(:placeholder) do create(:placeholder_user, - name: "DEVELOPER PLACEHOLDER", + name: 'DEVELOPER PLACEHOLDER', member_with_permissions: { project => permissions }) end @@ -69,21 +69,21 @@ dashboard_page.visit! end - it "renders the default view, allows altering and saving" do + it 'renders the default view, allows altering and saving' do # within top-right area, add an additional widget - dashboard_page.add_widget(1, 1, :within, "Members") + dashboard_page.add_widget(1, 1, :within, 'Members') - members_block = page.find(".widget-box", text: "MEMBERS") + members_block = page.find('.widget-box', text: 'MEMBERS') within(members_block) do - user_link = find("op-principal a", text: user.name) - expect(user_link["href"]).to end_with user_path(user.id) + user_link = find('op-principal a', text: user.name) + expect(user_link['href']).to end_with user_path(user.id) - group_link = find("op-principal a", text: group.name) - expect(group_link["href"]).to end_with show_group_path(group.id) + group_link = find('op-principal a', text: group.name) + expect(group_link['href']).to end_with show_group_path(group.id) - placeholder_link = find("op-principal a", text: placeholder.name) - expect(placeholder_link["href"]).to end_with placeholder_user_path(placeholder.id) + placeholder_link = find('op-principal a', text: placeholder.name) + expect(placeholder_link['href']).to end_with placeholder_user_path(placeholder.id) end end end diff --git a/modules/dashboards/spec/features/members_spec.rb b/modules/dashboards/spec/features/members_spec.rb index 816a126c347e..4271a970c33b 100644 --- a/modules/dashboards/spec/features/members_spec.rb +++ b/modules/dashboards/spec/features/members_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Members widget on dashboard", :js do +RSpec.describe 'Members widget on dashboard', :js do let!(:project) { create(:project) } let!(:other_project) { create(:project) } @@ -99,11 +99,11 @@ def expect_all_members_visible(area) end end - it "can add the widget and see the members if the permissions suffice" do + it 'can add the widget and see the members if the permissions suffice' do # within top-right area, add an additional widget - dashboard.add_widget(1, 1, :within, "Members") + dashboard.add_widget(1, 1, :within, 'Members') - members_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + members_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') expect_all_members_visible(members_area.area) @@ -112,7 +112,7 @@ def expect_all_members_visible(area) within members_area.area do expect(page) - .to have_link("Member") + .to have_link('Member') end # A user without edit permission will see the members but cannot add one @@ -125,7 +125,7 @@ def expect_all_members_visible(area) within members_area.area do expect(page) - .to have_no_link("Member") + .to have_no_link('Member') end # A user without view permission will not see any members @@ -140,13 +140,13 @@ def expect_all_members_visible(area) .to have_no_content manager_user.name expect(page) - .to have_content("No visible members") + .to have_content('No visible members') expect(page) - .to have_no_link("Member") + .to have_no_link('Member') expect(page) - .to have_no_link("View all members") + .to have_no_link('View all members') end end end diff --git a/modules/dashboards/spec/features/modifying_with_unallowed_spec.rb b/modules/dashboards/spec/features/modifying_with_unallowed_spec.rb index 92f730188cc9..fa7a1d0a8aee 100644 --- a/modules/dashboards/spec/features/modifying_with_unallowed_spec.rb +++ b/modules/dashboards/spec/features/modifying_with_unallowed_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Modifying a dashboard which already has widgets for which permissions are lacking", :js do +RSpec.describe 'Modifying a dashboard which already has widgets for which permissions are lacking', :js do let!(:project) do create(:project) end @@ -60,12 +60,12 @@ dashboard_page.visit! end - it "can add and modify widgets" do + it 'can add and modify widgets' do dashboard_page.add_widget(dashboard.row_count, dashboard.column_count, :row, "News") sleep(0.1) - news_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + news_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') within news_widget.area do expect(page) @@ -76,7 +76,7 @@ dashboard_page.visit! - news_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + news_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') within news_widget.area do expect(page) @@ -90,6 +90,6 @@ dashboard_page.visit! expect(page) - .to have_no_css(".grid--area.-widgeted:nth-of-type(2)") + .to have_no_css('.grid--area.-widgeted:nth-of-type(2)') end end diff --git a/modules/dashboards/spec/features/navigation_spec.rb b/modules/dashboards/spec/features/navigation_spec.rb index 67a771cb5606..eabaca0e1bce 100644 --- a/modules/dashboards/spec/features/navigation_spec.rb +++ b/modules/dashboards/spec/features/navigation_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Navigate to dashboard", :js do +RSpec.describe 'Navigate to dashboard', :js do let(:project) { create(:project) } let(:permissions) { [:view_dashboards] } let(:user) do @@ -40,16 +40,16 @@ login_as user end - it "can visit the dashboard" do + it 'can visit the dashboard' do visit project_path(project) - within "#menu-sidebar" do + within '#menu-sidebar' do click_link "Dashboard" end - within "#content" do + within '#content' do expect(page) - .to have_content("Dashboard") + .to have_content('Dashboard') end end end diff --git a/modules/dashboards/spec/features/news_spec.rb b/modules/dashboards/spec/features/news_spec.rb index ffb7cdc4451d..1c395aa6b68a 100644 --- a/modules/dashboards/spec/features/news_spec.rb +++ b/modules/dashboards/spec/features/news_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "News widget on dashboard", :js do +RSpec.describe 'News widget on dashboard', :js do let!(:project) { create(:project) } let!(:other_project) { create(:project) } let!(:visible_news) do create(:news, project:, - description: "blubs") + description: 'blubs') end let!(:invisible_news) do create(:news, @@ -65,11 +65,11 @@ dashboard.visit! end - it "can add the widget and see the visible news" do + it 'can add the widget and see the visible news' do # within top-right area, add an additional widget - dashboard.add_widget(1, 1, :within, "News") + dashboard.add_widget(1, 1, :within, 'News') - news_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + news_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within news_widget.area do expect(page) @@ -79,7 +79,7 @@ expect(page) .to have_content visible_news.project.name expect(page) - .to have_content visible_news.created_at.strftime("%m/%d/%Y") + .to have_content visible_news.created_at.strftime('%m/%d/%Y') expect(page) .to have_no_content invisible_news.title diff --git a/modules/dashboards/spec/features/project_description_spec.rb b/modules/dashboards/spec/features/project_description_spec.rb index 0ecb4cd62105..f52f5f925273 100644 --- a/modules/dashboards/spec/features/project_description_spec.rb +++ b/modules/dashboards/spec/features/project_description_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Project description widget on dashboard", :js do +RSpec.describe 'Project description widget on dashboard', :js do let(:project_description) { "Some text I like to write" } let!(:project) do create(:project, description: project_description) @@ -63,7 +63,7 @@ def add_project_description_widget dashboard_page.visit! dashboard_page.add_widget(1, 1, :within, "Project description") - dashboard_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') end before do @@ -71,12 +71,12 @@ def add_project_description_widget add_project_description_widget end - context "without editing permissions" do + context 'without editing permissions' do let(:current_user) { read_only_user } - it "can add the widget, but not edit the description" do + it 'can add the widget, but not edit the description' do # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - description_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + description_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within(description_widget.area) do # The description is visible @@ -84,41 +84,41 @@ def add_project_description_widget .to have_content(project_description) # The description is not editable - field = TextEditorField.new dashboard_page, "description" + field = TextEditorField.new dashboard_page, 'description' field.expect_read_only field.activate! expect_open: false end end end - context "with editing permissions" do + context 'with editing permissions' do let(:current_user) { editing_user } - it "can edit the description" do + it 'can edit the description' do # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - description_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + description_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within(description_widget.area) do # Open description field - field = TextEditorField.new dashboard_page, "description" + field = TextEditorField.new dashboard_page, 'description' field.activate! sleep(0.1) # Change the value field.expect_value(project_description) - field.set_value "A completely new description which is super cool." + field.set_value 'A completely new description which is super cool.' field.save! # The edit field is toggled and the value saved. - expect(page).to have_content("A completely new description which is super cool.") + expect(page).to have_content('A completely new description which is super cool.') expect(page).to have_selector(field.selector) expect(page).to have_no_selector(field.input_selector) end end end - context "with editing and wp add permissions" do - let!(:type) { create(:type_task, name: "Task") } + context 'with editing and wp add permissions' do + let!(:type) { create(:type_task, name: 'Task') } let!(:project) do create(:project, types: [type]) end @@ -126,26 +126,26 @@ def add_project_description_widget let(:current_user) do create(:user, member_with_permissions: { project => editing_permissions + %i[add_work_packages] }) end - let(:editor) { Components::WysiwygEditor.new "body" } + let(:editor) { Components::WysiwygEditor.new 'body' } - it "can create a button macro for work packages" do + it 'can create a button macro for work packages' do # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - description_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + description_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') - field = TextEditorField.new dashboard_page, "description" + field = TextEditorField.new dashboard_page, 'description' field.activate! - editor.insert_macro "Insert create work package button" + editor.insert_macro 'Insert create work package button' - expect(page).to have_css(".spot-modal") - select "Task", from: "selected-type" - find(".spot-modal--submit-button").click + expect(page).to have_css('.spot-modal') + select 'Task', from: 'selected-type' + find('.spot-modal--submit-button').click field.save! - dashboard_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') - within("#content") do + within('#content') do expect(page).to have_css("a[href=\"/projects/#{project.identifier}/work_packages/new?type=#{type.id}\"]") end end diff --git a/modules/dashboards/spec/features/project_status_spec.rb b/modules/dashboards/spec/features/project_status_spec.rb index e98f642bcf13..c21de976426a 100644 --- a/modules/dashboards/spec/features/project_status_spec.rb +++ b/modules/dashboards/spec/features/project_status_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Project status widget on dashboard", :js do +RSpec.describe 'Project status widget on dashboard', :js do let!(:project) do create(:project, - status_code: "on_track", - status_explanation: "some explanation") + status_code: 'on_track', + status_explanation: 'some explanation') end let(:read_only_permissions) do @@ -65,7 +65,7 @@ def add_project_status_widget dashboard_page.visit! dashboard_page.add_widget(1, 1, :within, "Project status") - dashboard_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + dashboard_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') end before do @@ -73,77 +73,77 @@ def add_project_status_widget add_project_status_widget end - context "without editing permissions" do + context 'without editing permissions' do let(:current_user) { read_only_user } - it "can add the widget, but not edit the status" do + it 'can add the widget, but not edit the status' do # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - status_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + status_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within(status_widget.area) do # The description is visible expect(page) - .to have_content("ON TRACK") + .to have_content('ON TRACK') expect(page) .to have_content(project.status_explanation) # The status selector does not open - field = EditField.new(dashboard_page, "status") + field = EditField.new(dashboard_page, 'status') field.expect_read_only field.activate! expect_open: false # The explanation is not editable - field = TextEditorField.new(dashboard_page, "statusExplanation") + field = TextEditorField.new(dashboard_page, 'statusExplanation') field.expect_read_only field.activate! expect_open: false end end end - context "with editing permissions" do + context 'with editing permissions' do let(:current_user) { editing_user } - it "can edit the status and its explanation" do + it 'can edit the status and its explanation' do # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - status_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + status_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within(status_widget.area) do # Open status selector - field = ProjectStatusField.new(dashboard_page, "status") + field = ProjectStatusField.new(dashboard_page, 'status') field.activate! sleep(0.1) # Change the value - field.set_to("AT RISK") + field.set_to('AT RISK') # The edit field is toggled and the value saved. - expect(page).to have_content("AT RISK", wait: 5) + expect(page).to have_content('AT RISK', wait: 5) expect(page).to have_selector(field.selector) expect(page).to have_no_selector(field.input_selector) # Unset the project status field.activate! sleep(0.1) - field.set_to("NOT SET") + field.set_to('NOT SET') # The edit field is toggled and the value saved. - expect(page).to have_content("NOT SET", wait: 5) + expect(page).to have_content('NOT SET', wait: 5) expect(page).to have_selector(field.selector) expect(page).to have_no_selector(field.input_selector) # Open explanation field - field = TextEditorField.new dashboard_page, "statusExplanation" + field = TextEditorField.new dashboard_page, 'statusExplanation' field.activate! sleep(0.1) # Change the value field.expect_value(project.status_explanation) - field.set_value "A completely new explanation which is super cool." + field.set_value 'A completely new explanation which is super cool.' field.save! # The edit field is toggled and the value saved. - expect(page).to have_content("A completely new explanation which is super cool.") + expect(page).to have_content('A completely new explanation which is super cool.') expect(page).to have_selector(field.selector) expect(page).to have_no_selector(field.input_selector) end diff --git a/modules/dashboards/spec/features/read_only_allowed_spec.rb b/modules/dashboards/spec/features/read_only_allowed_spec.rb index 1e40c8eb5376..200fce2baa35 100644 --- a/modules/dashboards/spec/features/read_only_allowed_spec.rb +++ b/modules/dashboards/spec/features/read_only_allowed_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Read only mode when user lacks edit permission on dashboard", :js do +RSpec.describe 'Read only mode when user lacks edit permission on dashboard', :js do let!(:type) { create(:type) } let!(:project) { create(:project, types: [type]) } let!(:work_package) do @@ -71,11 +71,11 @@ dashboard_page.visit! end - it "can not modify the dashboard but can still use it" do + it 'can not modify the dashboard but can still use it' do dashboard_page.expect_unable_to_add_widget(dashboard.row_count, dashboard.column_count, :row) dashboard_page.expect_no_help_mode - table_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + table_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') table_widget.expect_not_resizable diff --git a/modules/dashboards/spec/features/subprojects_spec.rb b/modules/dashboards/spec/features/subprojects_spec.rb index a1ed89d18890..998df3e57fe9 100644 --- a/modules/dashboards/spec/features/subprojects_spec.rb +++ b/modules/dashboards/spec/features/subprojects_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Subprojects widget on dashboard", :js do +RSpec.describe 'Subprojects widget on dashboard', :js do let!(:project) do create(:project, parent: parent_project) end @@ -73,14 +73,14 @@ Pages::Dashboard.new(project) end - context "as a user" do + context 'as a user' do current_user { user } - it "can add the widget listing active subprojects the user is member of", :aggregate_failures do + it 'can add the widget listing active subprojects the user is member of', :aggregate_failures do dashboard_page.visit! dashboard_page.add_widget(1, 1, :within, "Subprojects") - subprojects_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + subprojects_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') expect(page) .to have_link(child_project.name) @@ -102,14 +102,14 @@ end end - context "as an admin" do + context 'as an admin' do current_user { create(:admin) } - it "can add the widget listing all active subprojects", :aggregate_failures do + it 'can add the widget listing all active subprojects', :aggregate_failures do dashboard_page.visit! dashboard_page.add_widget(1, 2, :within, "Subprojects") - subprojects_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + subprojects_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') within(subprojects_widget.area) do expect(page) diff --git a/modules/dashboards/spec/features/time_entries_spec.rb b/modules/dashboards/spec/features/time_entries_spec.rb index 07a09423d623..8a0216cbe64c 100644 --- a/modules/dashboards/spec/features/time_entries_spec.rb +++ b/modules/dashboards/spec/features/time_entries_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Time entries widget on dashboard", :js do +RSpec.describe 'Time entries widget on dashboard', :js do let!(:type) { create(:type) } let!(:project) { create(:project, types: [type]) } let!(:other_project) { create(:project, types: [type]) } @@ -47,7 +47,7 @@ user:, spent_on: Date.today, hours: 6, - comments: "My comment") + comments: 'My comment') end let!(:other_visible_time_entry) do create(:time_entry, @@ -56,7 +56,7 @@ user: other_user, spent_on: Date.today - 1.day, hours: 5, - comments: "Another`s comment") + comments: 'Another`s comment') end let!(:invisible_time_entry) do create(:time_entry, @@ -95,37 +95,37 @@ dashboard.visit! end - it "adds the widget and checks the displayed entries" do + it 'adds the widget and checks the displayed entries' do # within top-right area, add an additional widget dashboard.add_widget(1, 1, :within, 'Spent time \(last 7 days\)') - spent_time_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + spent_time_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within spent_time_widget.area do expect(page) .to have_content "Total: 11 h" expect(page) - .to have_content Date.today.strftime("%m/%d/%Y") + .to have_content Date.today.strftime('%m/%d/%Y') expect(page) - .to have_css(".activity", text: visible_time_entry.activity.name) + .to have_css('.activity', text: visible_time_entry.activity.name) expect(page) - .to have_css(".subject", text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") + .to have_css('.subject', text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") expect(page) - .to have_css(".comments", text: visible_time_entry.comments) + .to have_css('.comments', text: visible_time_entry.comments) expect(page) - .to have_css(".hours", text: visible_time_entry.hours) + .to have_css('.hours', text: visible_time_entry.hours) expect(page) - .to have_content((Date.today - 1.day).strftime("%m/%d/%Y")) + .to have_content((Date.today - 1.day).strftime('%m/%d/%Y')) expect(page) - .to have_css(".activity", text: other_visible_time_entry.activity.name) + .to have_css('.activity', text: other_visible_time_entry.activity.name) expect(page) - .to have_css(".subject", text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") + .to have_css('.subject', text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") expect(page) - .to have_css(".comments", text: other_visible_time_entry.comments) + .to have_css('.comments', text: other_visible_time_entry.comments) expect(page) - .to have_css(".hours", text: other_visible_time_entry.hours) + .to have_css('.hours', text: other_visible_time_entry.hours) # Allows to edit page.find_test_selector("edit-time-entry-#{visible_time_entry.id}").click @@ -135,15 +135,15 @@ time_logging_modal.expect_work_package work_package.subject - time_logging_modal.update_field "hours", 4 + time_logging_modal.update_field 'hours', 4 sleep(0.1) - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' time_logging_modal.is_visible false within spent_time_widget.area do - expect(page).to have_css(".hours", text: 4) + expect(page).to have_css('.hours', text: 4) end visible_time_entry.reload diff --git a/modules/dashboards/spec/features/work_package_calendar_spec.rb b/modules/dashboards/spec/features/work_package_calendar_spec.rb index 7732d798f142..f217ef8b7f06 100644 --- a/modules/dashboards/spec/features/work_package_calendar_spec.rb +++ b/modules/dashboards/spec/features/work_package_calendar_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Work package calendar widget on dashboard", :js do +RSpec.describe 'Work package calendar widget on dashboard', :js do let!(:type) { create(:type) } let!(:priority) { create(:default_priority) } let!(:project) { create(:project, types: [type]) } @@ -38,7 +38,7 @@ let!(:open_status) { create(:default_status) } let!(:spanning_work_package) do create(:work_package, - subject: "Spanning work package", + subject: 'Spanning work package', project:, start_date: Date.today - 8.days, due_date: Date.today + 8.days, @@ -48,7 +48,7 @@ end let!(:starting_work_package) do create(:work_package, - subject: "Starting work package", + subject: 'Starting work package', project:, start_date: Date.today, due_date: Date.today + 8.days, @@ -58,7 +58,7 @@ end let!(:ending_work_package) do create(:work_package, - subject: "Ending work package", + subject: 'Ending work package', project:, start_date: Date.today - 8.days, due_date: Date.today, @@ -68,7 +68,7 @@ end let!(:outdated_work_package) do create(:work_package, - subject: "Outdated work package", + subject: 'Outdated work package', project:, start_date: Date.today - 9.days, due_date: Date.today - 7.days, @@ -78,7 +78,7 @@ end let!(:other_project_work_package) do create(:work_package, - subject: "Other project work package", + subject: 'Other project work package', project: other_project, start_date: Date.today - 9.days, due_date: Date.today + 7.days, @@ -114,29 +114,29 @@ dashboard.visit! end - it "can add the widget and see the work packages of the project" do + it 'can add the widget and see the work packages of the project' do dashboard.add_widget(1, 1, :within, "Calendar") sleep(0.1) # As the user lacks the necessary permissions, no widget is preconfigured - calendar_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + calendar_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') within(calendar_widget.area) do expect(page) - .to have_css(".fc-event-title", text: spanning_work_package.subject) + .to have_css('.fc-event-title', text: spanning_work_package.subject) expect(page) - .to have_css(".fc-event-title", text: starting_work_package.subject) + .to have_css('.fc-event-title', text: starting_work_package.subject) expect(page) - .to have_css(".fc-event-title", text: ending_work_package.subject) + .to have_css('.fc-event-title', text: ending_work_package.subject) expect(page) - .to have_no_css(".fc-event-title", text: outdated_work_package.subject) + .to have_no_css('.fc-event-title', text: outdated_work_package.subject) expect(page) - .to have_no_css(".fc-event-title", text: other_project_work_package.subject) + .to have_no_css('.fc-event-title', text: other_project_work_package.subject) end end end diff --git a/modules/dashboards/spec/features/work_package_graph_overview_spec.rb b/modules/dashboards/spec/features/work_package_graph_overview_spec.rb index 10346966bbe8..d4ce90faaf70 100644 --- a/modules/dashboards/spec/features/work_package_graph_overview_spec.rb +++ b/modules/dashboards/spec/features/work_package_graph_overview_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Work package overview graph widget on dashboard", :js do +RSpec.describe 'Work package overview graph widget on dashboard', :js do let!(:type) { create(:type) } let!(:priority) { create(:default_priority) } let!(:project) { create(:project, types: [type]) } @@ -38,7 +38,7 @@ let!(:closed_status) { create(:closed_status) } let!(:open_work_package) do create(:work_package, - subject: "Spanning work package", + subject: 'Spanning work package', project:, status: open_status, type:, @@ -47,7 +47,7 @@ end let!(:closed) do create(:work_package, - subject: "Starting work package", + subject: 'Starting work package', project:, status: closed_status, type:, @@ -82,13 +82,13 @@ end # As a graph is rendered as a canvas, we have limited abilities to test the widget - it "can add the widget" do + it 'can add the widget' do sleep(0.1) dashboard.add_widget(1, 1, :within, "Work packages overview") # As the user lacks the necessary permissions, no widget is preconfigured - overview_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + overview_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') overview_widget.expect_to_span(1, 1, 2, 2) end diff --git a/modules/dashboards/spec/features/work_package_graph_spec.rb b/modules/dashboards/spec/features/work_package_graph_spec.rb index 179378f9abcf..e92115db6a30 100644 --- a/modules/dashboards/spec/features/work_package_graph_spec.rb +++ b/modules/dashboards/spec/features/work_package_graph_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Arbitrary WorkPackage query graph widget dashboard", :js, with_ee: %i[grid_widget_wp_graph] do +RSpec.describe 'Arbitrary WorkPackage query graph widget dashboard', :js, with_ee: %i[grid_widget_wp_graph] do let!(:type) { create(:type) } let!(:other_type) { create(:type) } let!(:priority) { create(:default_priority) } @@ -96,8 +96,8 @@ dashboard_page.visit! end - context "with the permission to save queries" do - it "can add the widget and see the work packages of the filtered for types" do + context 'with the permission to save queries' do + it 'can add the widget and see the work packages of the filtered for types' do expect(page) .to have_content(type_work_package.subject) @@ -105,7 +105,7 @@ sleep(1) - filter_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + filter_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') filter_area.expect_to_span(1, 1, 2, 2) @@ -114,15 +114,15 @@ # User has the ability to modify the query filter_area.configure_wp_table - modal.switch_to("Filters") + modal.switch_to('Filters') filters.expect_filter_count(2) - filters.add_filter_by("Type", "is (OR)", type.name) + filters.add_filter_by('Type', 'is (OR)', type.name) modal.save filter_area.configure_wp_table - modal.switch_to("General") - general.set_axis "Type" - general.set_type "Bar" + modal.switch_to('General') + general.set_axis 'Type' + general.set_type 'Bar' modal.save sleep(0.5) @@ -137,36 +137,36 @@ .to have_content(type_work_package.subject) filter_area.configure_wp_table - modal.switch_to("Filters") + modal.switch_to('Filters') filters.expect_filter_count(3) - modal.switch_to("General") - general.expect_axis "Type" - general.expect_type "Bar" + modal.switch_to('General') + general.expect_axis 'Type' + general.expect_type 'Bar' # A notification is displayed if no work package is returned for the graph - modal.switch_to("Filters") - filters.add_filter_by("Subject", "contains", "!!!!!!!!!!!!!!!!!") + modal.switch_to('Filters') + filters.add_filter_by('Subject', 'contains', '!!!!!!!!!!!!!!!!!') modal.save within filter_area.area do expect(page) - .to have_content(I18n.t("js.work_packages.no_results.title")) + .to have_content(I18n.t('js.work_packages.no_results.title')) end end end - context "without the permission to save queries" do + context 'without the permission to save queries' do let(:permissions) { %i[view_work_packages add_work_packages view_dashboards manage_dashboards] } - it "cannot add the widget" do + it 'cannot add the widget' do dashboard_page.expect_unable_to_add_widget(1, 1, :within, "Work packages graph") end end - context "without an enterprise edition", with_ee: false do - it "cannot add the widget and receives an enterprise edition notice" do + context 'without an enterprise edition', with_ee: false do + it 'cannot add the widget and receives an enterprise edition notice' do dashboard_page.expect_add_widget_enterprise_edition_notice(1, 2, :within) # At this point the add widget modal is open diff --git a/modules/dashboards/spec/features/work_package_table_spec.rb b/modules/dashboards/spec/features/work_package_table_spec.rb index 1c56ca645313..26165c9f61cd 100644 --- a/modules/dashboards/spec/features/work_package_table_spec.rb +++ b/modules/dashboards/spec/features/work_package_table_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/dashboard" +require_relative '../support/pages/dashboard' -RSpec.describe "Arbitrary WorkPackage query table widget dashboard", :js do +RSpec.describe 'Arbitrary WorkPackage query table widget dashboard', :js do let!(:type) { create(:type) } let!(:other_type) { create(:type) } let!(:priority) { create(:default_priority) } @@ -92,63 +92,63 @@ dashboard_page.visit! end - context "with the permission to save queries" do - it "can add the widget and see the work packages of the filtered for types" do + context 'with the permission to save queries' do + it 'can add the widget and see the work packages of the filtered for types' do # This one always exists by default. # Using it here as a safeguard to govern speed. - wp_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + wp_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') expect(wp_area) - .to have_css(".subject", text: type_work_package.subject) + .to have_css('.subject', text: type_work_package.subject) dashboard_page.add_widget(1, 1, :row, "Work packages table") - filter_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + filter_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') filter_area.expect_to_span(1, 1, 2, 3) # At the beginning, the default query is displayed expect(filter_area.area) - .to have_css(".subject", text: type_work_package.subject, wait: 30) + .to have_css('.subject', text: type_work_package.subject, wait: 30) expect(filter_area.area) - .to have_css(".subject", text: other_type_work_package.subject) + .to have_css('.subject', text: other_type_work_package.subject) # Work packages from other projects are not displayed as the query is project scoped expect(filter_area.area) - .to have_no_css(".subject", text: other_project_work_package.subject) + .to have_no_css('.subject', text: other_project_work_package.subject) # User has the ability to modify the query filter_area.configure_wp_table - modal.switch_to("Filters") + modal.switch_to('Filters') filters.expect_filter_count(2) - filters.add_filter_by("Type", "is (OR)", type.name) + filters.add_filter_by('Type', 'is (OR)', type.name) modal.save filter_area.configure_wp_table - modal.switch_to("Columns") + modal.switch_to('Columns') columns.assume_opened - columns.remove "Subject" + columns.remove 'Subject' expect(filter_area.area) - .to have_css(".id", text: type_work_package.id) + .to have_css('.id', text: type_work_package.id) # as the Subject column is disabled expect(filter_area.area) - .to have_no_css(".subject", text: type_work_package.subject) + .to have_no_css('.subject', text: type_work_package.subject) # As other_type is filtered out expect(filter_area.area) - .to have_no_css(".id", text: other_type_work_package.id) + .to have_no_css('.id', text: other_type_work_package.id) # Work packages from other projects are not displayed as the query is project scoped expect(filter_area.area) - .to have_no_css(".subject", text: other_project_work_package.subject) + .to have_no_css('.subject', text: other_project_work_package.subject) scroll_to_element(filter_area.area) within filter_area.area do - input = find(".editable-toolbar-title--input") - input.set("My WP Filter") + input = find('.editable-toolbar-title--input') + input.set('My WP Filter') input.native.send_keys(:return) end @@ -160,32 +160,32 @@ visit root_path dashboard_page.visit! - filter_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + filter_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') expect(filter_area.area) - .to have_css(".id", text: type_work_package.id) + .to have_css('.id', text: type_work_package.id) # as the Subject column is disabled expect(filter_area.area) - .to have_no_css(".subject", text: type_work_package.subject) + .to have_no_css('.subject', text: type_work_package.subject) # As other_type is filtered out expect(filter_area.area) - .to have_no_css(".id", text: other_type_work_package.id) + .to have_no_css('.id', text: other_type_work_package.id) # Work packages from other projects are not displayed as the query is project scoped expect(filter_area.area) - .to have_no_css(".subject", text: other_project_work_package.subject) + .to have_no_css('.subject', text: other_project_work_package.subject) within filter_area.area do - expect(page).to have_field("editable-toolbar-title", with: "My WP Filter", wait: 10) + expect(page).to have_field('editable-toolbar-title', with: 'My WP Filter', wait: 10) end end end - context "without the permission to save queries" do + context 'without the permission to save queries' do let(:permissions) { %i[view_work_packages add_work_packages view_dashboards manage_dashboards] } - it "cannot add the widget" do + it 'cannot add the widget' do dashboard_page.expect_unable_to_add_widget(1, 1, :within, "Work packages table") end end diff --git a/modules/dashboards/spec/lib/dashboards/grid_registration_spec.rb b/modules/dashboards/spec/lib/dashboards/grid_registration_spec.rb index 7977315b04d0..2ea18b0b7386 100644 --- a/modules/dashboards/spec/lib/dashboards/grid_registration_spec.rb +++ b/modules/dashboards/spec/lib/dashboards/grid_registration_spec.rb @@ -1,60 +1,60 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Dashboards::GridRegistration do let(:user) { build_stubbed(:user) } let(:project) { build_stubbed(:project) } let(:grid) { build_stubbed(:dashboard, project:) } - describe "from_scope" do - context "with a relative URL root", with_config: { rails_relative_url_root: "/foobar" } do - subject { described_class.from_scope "/foobar/projects/an_id/dashboards" } + describe 'from_scope' do + context 'with a relative URL root', with_config: { rails_relative_url_root: '/foobar' } do + subject { described_class.from_scope '/foobar/projects/an_id/dashboards' } - it "returns the class" do + it 'returns the class' do expect(subject[:class]).to eq(Grids::Dashboard) end - it "returns the project_id" do - expect(subject[:project_id]).to eq("an_id") + it 'returns the project_id' do + expect(subject[:project_id]).to eq('an_id') end - context "with a different route" do - subject { described_class.from_scope "/barfoo/projects/an_id/dashboards" } + context 'with a different route' do + subject { described_class.from_scope '/barfoo/projects/an_id/dashboards' } - it "returns nil" do + it 'returns nil' do expect(subject).to be_nil end end end - context "without a relative URL root" do - subject { described_class.from_scope "/projects/an_id/dashboards" } + context 'without a relative URL root' do + subject { described_class.from_scope '/projects/an_id/dashboards' } - it "returns the class" do + it 'returns the class' do expect(subject[:class]).to eq(Grids::Dashboard) end - it "returns the project_id" do - expect(subject[:project_id]).to eq("an_id") + it 'returns the project_id' do + expect(subject[:project_id]).to eq('an_id') end - context "with a different route" do - subject { described_class.from_scope "/projects/an_id/boards" } + context 'with a different route' do + subject { described_class.from_scope '/projects/an_id/boards' } - it "returns nil" do + it 'returns nil' do expect(subject).to be_nil end end end end - describe "defaults" do - it "returns the initialized widget" do + describe 'defaults' do + it 'returns the initialized widget' do expect(described_class.defaults[:widgets].map(&:identifier)) .to contain_exactly("work_packages_table") end end - describe "writable?" do + describe 'writable?' do let(:permissions) { [:manage_dashboards] } let(:allowed) { true } @@ -64,17 +64,17 @@ end end - context "if the user has the :manage_dashboards permission" do - it "is truthy" do + context 'if the user has the :manage_dashboards permission' do + it 'is truthy' do expect(described_class) .to be_writable(grid, user) end end - context "if the user lacks the :manage_dashboards permission" do + context 'if the user lacks the :manage_dashboards permission' do let(:permissions) { [] } - it "is falsey" do + it 'is falsey' do expect(described_class) .not_to be_writable(grid, user) end diff --git a/modules/dashboards/spec/requests/api/v3/attachments/grid_spec.rb b/modules/dashboards/spec/requests/api/v3/attachments/grid_spec.rb index 4db064491bfa..3a22d712079b 100644 --- a/modules/dashboards/spec/requests/api/v3/attachments/grid_spec.rb +++ b/modules/dashboards/spec/requests/api/v3/attachments/grid_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("spec/requests/api/v3/attachments/attachment_resource_shared_examples").to_s RSpec.describe "grid attachments" do diff --git a/modules/dashboards/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb b/modules/dashboards/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb index 060d3fc02db4..995b414361d5 100644 --- a/modules/dashboards/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb +++ b/modules/dashboards/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "POST /api/v3/grids/form for Dashboard Grids", content_type: :json do include Rack::Test::Methods @@ -62,15 +62,15 @@ login_as(current_user) end - describe "#post" do + describe '#post' do before do post path, params.to_json end - context "with a valid boards scope" do + context 'with a valid boards scope' do let(:params) do { - name: "foo", + name: 'foo', _links: { scope: { href: project_dashboards_path(project) @@ -79,7 +79,7 @@ } end - it "contains default data in the payload" do + it 'contains default data in the payload' do expected = { rowCount: 1, columnCount: 2, @@ -91,14 +91,14 @@ options: { name: "Work packages table", queryProps: { - "columns[]": %w(id project type subject), + 'columns[]': %w(id project type subject), filters: "[{\"status\":{\"operator\":\"o\",\"values\":[]}}]" } }, startColumn: 1, startRow: 1 }], - name: "foo", + name: 'foo', options: {}, _links: { attachments: [], @@ -111,23 +111,23 @@ expect(subject.body) .to be_json_eql(expected.to_json) - .at_path("_embedded/payload") + .at_path('_embedded/payload') end - it "has no validationErrors" do + it 'has no validationErrors' do expect(subject.body) .to be_json_eql({}.to_json) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.grids.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "with boards scope for which the user does not have the necessary permissions" do + context 'with boards scope for which the user does not have the necessary permissions' do let(:current_user) { prohibited_user } let(:params) do { @@ -139,14 +139,14 @@ } end - it "has a validationError on scope" do + it 'has a validationError on scope' do expect(subject.body) .to be_json_eql("Scope is not set to one of the allowed values.".to_json) - .at_path("_embedded/validationErrors/scope/message") + .at_path('_embedded/validationErrors/scope/message') end end - context "with an invalid scope" do + context 'with an invalid scope' do let(:params) do { _links: { @@ -157,17 +157,17 @@ } end - it "has a validationError on scope" do + it 'has a validationError on scope' do expect(subject.body) .to be_json_eql("Scope is not set to one of the allowed values.".to_json) - .at_path("_embedded/validationErrors/scope/message") + .at_path('_embedded/validationErrors/scope/message') end end - context "with an unsupported widget identifier" do + context 'with an unsupported widget identifier' do let(:params) do { - name: "foo", + name: 'foo', _links: { attachments: [], scope: { @@ -187,18 +187,18 @@ } end - it "has a validationError on widget" do + it 'has a validationError on widget' do expect(subject.body) .to be_json_eql("Widgets is not set to one of the allowed values.".to_json) - .at_path("_embedded/validationErrors/widgets/message") + .at_path('_embedded/validationErrors/widgets/message') end end - context "for a user not allowed to save queries" do + context 'for a user not allowed to save queries' do let(:current_user) { no_save_query_user } let(:params) do { - name: "foo", + name: 'foo', _links: { scope: { href: project_dashboards_path(project) @@ -207,12 +207,12 @@ } end - it "contains default data in the payload that lacks the work_packages_table widget" do + it 'contains default data in the payload that lacks the work_packages_table widget' do expected = { rowCount: 1, columnCount: 2, widgets: [], - name: "foo", + name: 'foo', options: {}, _links: { attachments: [], @@ -225,19 +225,19 @@ expect(subject.body) .to be_json_eql(expected.to_json) - .at_path("_embedded/payload") + .at_path('_embedded/payload') end - it "has no validationErrors" do + it 'has no validationErrors' do expect(subject.body) .to be_json_eql({}.to_json) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.grids.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end end diff --git a/modules/dashboards/spec/requests/api/v3/grids/grids_resource_spec.rb b/modules/dashboards/spec/requests/api/v3/grids/grids_resource_spec.rb index 8c72a2cf752d..75f72d85e9ce 100644 --- a/modules/dashboards/spec/requests/api/v3/grids/grids_resource_spec.rb +++ b/modules/dashboards/spec/requests/api/v3/grids/grids_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Grids resource", content_type: :json do +RSpec.describe 'API v3 Grids resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -46,7 +46,7 @@ end let(:widgets) do [create(:grid_widget, - identifier: "custom_text", + identifier: 'custom_text', start_column: 1, end_column: 3, start_row: 1, @@ -63,7 +63,7 @@ subject(:response) { last_response } - describe "#get" do + describe '#get' do let(:path) { api_v3_paths.grid(grid.id) } let(:stored_grids) do @@ -76,42 +76,42 @@ get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "sends a grid block" do + it 'sends a grid block' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') end - it "identifies the url the grid is stored for" do + it 'identifies the url the grid is stored for' do expect(subject.body) .to be_json_eql(project_dashboards_path(project).to_json) - .at_path("_links/scope/href") + .at_path('_links/scope/href') end - it "has a widget that renders custom text" do + it 'has a widget that renders custom text' do expect(subject.body) - .to be_json_eql("custom_text".to_json) - .at_path("widgets/0/identifier") + .to be_json_eql('custom_text'.to_json) + .at_path('widgets/0/identifier') expect(subject.body) .to be_json_eql(custom_text.to_json) - .at_path("widgets/0/options/text/raw") + .at_path('widgets/0/options/text/raw') end - context "with the grid not existing" do + context 'with the grid not existing' do let(:path) { api_v3_paths.grid(grid.id + 1) } - it "responds with 404 NOT FOUND" do + it 'responds with 404 NOT FOUND' do expect(subject.status).to be 404 end end end - describe "#patch" do + describe '#patch' do let(:path) { api_v3_paths.grid(grid.id) } let(:stored_grids) do @@ -123,7 +123,7 @@ let(:params) do { rowCount: 10, - name: "foo", + name: 'foo', columnCount: 15, widgets: widget_params }.with_indifferent_access @@ -135,7 +135,7 @@ patch path, params.to_json end - context "with an added custom_text widget" do + context 'with an added custom_text widget' do let(:widget_params) do [ { @@ -157,38 +157,38 @@ end let(:widgets) { [] } - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns the altered grid block with the added widget" do + it 'returns the altered grid block with the added widget' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("foo".to_json) - .at_path("name") + .to be_json_eql('foo'.to_json) + .at_path('name') expect(subject.body) - .to be_json_eql(params["rowCount"].to_json) - .at_path("rowCount") + .to be_json_eql(params['rowCount'].to_json) + .at_path('rowCount') expect(subject.body) - .to be_json_eql(params["widgets"][0]["identifier"].to_json) - .at_path("widgets/0/identifier") + .to be_json_eql(params['widgets'][0]['identifier'].to_json) + .at_path('widgets/0/identifier') expect(subject.body) - .to be_json_eql(params["widgets"][0]["options"]["text"]["raw"].to_json) - .at_path("widgets/0/options/text/raw") + .to be_json_eql(params['widgets'][0]['options']['text']['raw'].to_json) + .at_path('widgets/0/options/text/raw') expect(subject.body) - .to be_json_eql(params["widgets"][0]["options"]["name"].to_json) - .at_path("widgets/0/options/name") + .to be_json_eql(params['widgets'][0]['options']['name'].to_json) + .at_path('widgets/0/options/name') end - it "perists the changes" do + it 'perists the changes' do expect(grid.reload.row_count) - .to eql params["rowCount"] - expect(grid.reload.widgets[0].options["text"]) - .to eql params["widgets"][0]["options"]["text"]["raw"] - expect(grid.reload.widgets[0].options["name"]) - .to eql params["widgets"][0]["options"]["name"] + .to eql params['rowCount'] + expect(grid.reload.widgets[0].options['text']) + .to eql params['widgets'][0]['options']['text']['raw'] + expect(grid.reload.widgets[0].options['name']) + .to eql params['widgets'][0]['options']['name'] end end end diff --git a/modules/dashboards/spec/support/pages/dashboard.rb b/modules/dashboards/spec/support/pages/dashboard.rb index e9d52806b797..e3e5039aea9d 100644 --- a/modules/dashboards/spec/support/pages/dashboard.rb +++ b/modules/dashboards/spec/support/pages/dashboard.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' -require_relative "../../../../grids/spec/support/pages/grid" +require_relative '../../../../grids/spec/support/pages/grid' module Pages class Dashboard < ::Pages::Grid diff --git a/modules/documents/app/controllers/documents_controller.rb b/modules/documents/app/controllers/documents_controller.rb index e61fb96387a4..a0ed79f2645a 100644 --- a/modules/documents/app/controllers/documents_controller.rb +++ b/modules/documents/app/controllers/documents_controller.rb @@ -36,15 +36,15 @@ class DocumentsController < ApplicationController before_action :authorize def index - @group_by = %w(category date title author).include?(params[:group_by]) ? params[:group_by] : "category" + @group_by = %w(category date title author).include?(params[:group_by]) ? params[:group_by] : 'category' documents = @project.documents @grouped = case @group_by - when "date" + when 'date' documents.group_by { |d| d.updated_at.to_date } - when "title" + when 'title' documents.group_by { |d| d.title.first.upcase } - when "author" + when 'author' documents.with_attachments.group_by { |d| d.attachments.last.author } else documents.includes(:category).group_by(&:category) @@ -54,7 +54,7 @@ def index end def show - @attachments = @document.attachments.order(Arel.sql("created_at DESC")) + @attachments = @document.attachments.order(Arel.sql('created_at DESC')) end def new @@ -71,7 +71,7 @@ def create redirect_to project_documents_path(@project) else @document = call.result - render action: "new" + render action: 'new' end end @@ -86,21 +86,21 @@ def update if call.success? flash[:notice] = I18n.t(:notice_successful_update) - redirect_to action: "show", id: @document + redirect_to action: 'show', id: @document else @document = call.result - render action: "edit" + render action: 'edit' end end def destroy @document.destroy - redirect_to controller: "/documents", action: "index", project_id: @project + redirect_to controller: '/documents', action: 'index', project_id: @project end private def document_params - params.fetch(:document, {}).permit("category_id", "title", "description") + params.fetch(:document, {}).permit('category_id', 'title', 'description') end end diff --git a/modules/documents/app/mailers/documents_mailer.rb b/modules/documents/app/mailers/documents_mailer.rb index f1a98d95ef77..ba5526449800 100644 --- a/modules/documents/app/mailers/documents_mailer.rb +++ b/modules/documents/app/mailers/documents_mailer.rb @@ -30,8 +30,8 @@ class DocumentsMailer < UserMailer def document_added(user, document) @document = document - open_project_headers "Project" => @document.project.identifier, - "Type" => "Document" + open_project_headers 'Project' => @document.project.identifier, + 'Type' => 'Document' send_localized_mail(user) do "[#{@document.project.name}] #{t(:label_document_new)}: #{@document.title}" @@ -42,7 +42,7 @@ def attachments_added(user, attachments) container = attachments.first.container @added_to = "#{Document.model_name.human}: #{container.title}" - @added_to_url = url_for(controller: "/documents", action: "show", id: container.id) + @added_to_url = url_for(controller: '/documents', action: 'show', id: container.id) super end diff --git a/modules/documents/app/models/activities/document_activity_provider.rb b/modules/documents/app/models/activities/document_activity_provider.rb index 00e073aac164..529beb841482 100644 --- a/modules/documents/app/models/activities/document_activity_provider.rb +++ b/modules/documents/app/models/activities/document_activity_provider.rb @@ -27,13 +27,13 @@ #++ class Activities::DocumentActivityProvider < Activities::BaseActivityProvider - activity_provider_for type: "documents", + activity_provider_for type: 'documents', permission: :view_documents def event_query_projection [ - activity_journal_projection_statement(:title, "document_title"), - activity_journal_projection_statement(:project_id, "project_id") + activity_journal_projection_statement(:title, 'document_title'), + activity_journal_projection_statement(:project_id, 'project_id') ] end @@ -42,7 +42,7 @@ def event_title(event) end def event_type(_event) - "document" + 'document' end def event_path(event) @@ -56,6 +56,6 @@ def event_url(event) private def url_helper_parameter(event) - event["journable_id"] + event['journable_id'] end end diff --git a/modules/documents/app/models/document.rb b/modules/documents/app/models/document.rb index 7acb4e0c3d0a..c0e89f874bd9 100644 --- a/modules/documents/app/models/document.rb +++ b/modules/documents/app/models/document.rb @@ -34,12 +34,12 @@ class Document < ApplicationRecord acts_as_journalized acts_as_event title: Proc.new { |o| "#{Document.model_name.human}: #{o.title}" }, - url: Proc.new { |o| { controller: "/documents", action: "show", id: o.id } }, + url: Proc.new { |o| { controller: '/documents', action: 'show', id: o.id } }, author: Proc.new { |o| o.attachments.find(:first, order: "#{Attachment.table_name}.created_at ASC").try(:author) } - acts_as_searchable columns: ["title", "#{table_name}.description"], + acts_as_searchable columns: ['title', "#{table_name}.description"], include: :project, references: :projects, date_column: "#{table_name}.created_at" diff --git a/modules/documents/app/models/document_category.rb b/modules/documents/app/models/document_category.rb index 30892b81cf8d..c5c41f7d92ea 100644 --- a/modules/documents/app/models/document_category.rb +++ b/modules/documents/app/models/document_category.rb @@ -27,7 +27,7 @@ #++ class DocumentCategory < Enumeration - has_many :documents, foreign_key: "category_id" + has_many :documents, foreign_key: 'category_id' OptionName = :enumeration_doc_categories diff --git a/modules/documents/app/seeders/basic_data/documents/enumeration_seeder.rb b/modules/documents/app/seeders/basic_data/documents/enumeration_seeder.rb index 6a5669ebf134..f3953d577be3 100644 --- a/modules/documents/app/seeders/basic_data/documents/enumeration_seeder.rb +++ b/modules/documents/app/seeders/basic_data/documents/enumeration_seeder.rb @@ -30,11 +30,11 @@ module BasicData module Documents class EnumerationSeeder < ModelSeeder self.model_class = DocumentCategory - self.seed_data_model_key = "document_categories" + self.seed_data_model_key = 'document_categories' def model_attributes(category_data) { - name: category_data["name"] + name: category_data['name'] } end end diff --git a/modules/documents/app/views/documents/edit.html.erb b/modules/documents/app/views/documents/edit.html.erb index e655fb9e427f..b1b1dc1f18dc 100644 --- a/modules/documents/app/views/documents/edit.html.erb +++ b/modules/documents/app/views/documents/edit.html.erb @@ -31,5 +31,5 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @document, url: document_path(@document), method: 'PATCH' do |f| -%> <%= render partial: "documents/form", locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %> + <%= styled_button_tag t(:button_save), class: "-highlight -with-icon icon-checkmark" %> <% end %> diff --git a/modules/documents/app/views/documents/index.html.erb b/modules/documents/app/views/documents/index.html.erb index f99adea29b2d..d7542150c4df 100644 --- a/modules/documents/app/views/documents/index.html.erb +++ b/modules/documents/app/views/documents/index.html.erb @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details. <% if authorize_for(:documents, :new) %>
  • <%= link_to({:controller => '/documents', :action => 'new', :project_id => @project}, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t(:label_document_new)}, title: t(:label_document_new)}) do %> <%= op_icon('button--icon icon-add') %> diff --git a/modules/documents/app/views/documents/new.html.erb b/modules/documents/app/views/documents/new.html.erb index bfc00062e3c5..45df1d2214f9 100644 --- a/modules/documents/app/views/documents/new.html.erb +++ b/modules/documents/app/views/documents/new.html.erb @@ -30,5 +30,7 @@ See COPYRIGHT and LICENSE files for more details. <%= labelled_tabular_form_for @document, url: project_documents_path(@project), html: { multipart: true } do |f| -%> <%= render :partial => 'documents/form', locals: { f: f } %> - <%= styled_button_tag t(:button_create), class: "-primary -with-icon icon-checkmark" %> + <%= styled_button_tag t(:button_create), class: "-highlight -with-icon icon-checkmark" %> <% end %> + + diff --git a/modules/documents/db/migrate/20180323140208_to_v710_aggregated_documents_migrations.rb b/modules/documents/db/migrate/20180323140208_to_v710_aggregated_documents_migrations.rb index 60682f012a09..0fb548865ca1 100644 --- a/modules/documents/db/migrate/20180323140208_to_v710_aggregated_documents_migrations.rb +++ b/modules/documents/db/migrate/20180323140208_to_v710_aggregated_documents_migrations.rb @@ -68,7 +68,7 @@ def down def migrations MIGRATION_FILES.split.map do |m| - m.gsub(/_.*\z/, "") + m.gsub(/_.*\z/, '') end end end diff --git a/modules/documents/lib/api/v3/documents/document_representer.rb b/modules/documents/lib/api/v3/documents/document_representer.rb index 155b76ec6ae0..99a78bb0ed74 100644 --- a/modules/documents/lib/api/v3/documents/document_representer.rb +++ b/modules/documents/lib/api/v3/documents/document_representer.rb @@ -59,7 +59,7 @@ class DocumentRepresenter < ::API::Decorators::Single end def _type - "Document" + 'Document' end end end diff --git a/modules/documents/lib/api/v3/documents/documents_api.rb b/modules/documents/lib/api/v3/documents/documents_api.rb index 85b87473a32b..5314ba6c9c6c 100644 --- a/modules/documents/lib/api/v3/documents/documents_api.rb +++ b/modules/documents/lib/api/v3/documents/documents_api.rb @@ -49,7 +49,7 @@ class DocumentsAPI < ::API::OpenProjectAPI end end - route_param :id, type: Integer, desc: "Document ID" do + route_param :id, type: Integer, desc: 'Document ID' do helpers do def document Document.visible.find(params[:id]) diff --git a/modules/documents/lib/open_project/documents/engine.rb b/modules/documents/lib/open_project/documents/engine.rb index c6a248ca2bb4..4d30387356e2 100644 --- a/modules/documents/lib/open_project/documents/engine.rb +++ b/modules/documents/lib/open_project/documents/engine.rb @@ -32,15 +32,15 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-documents", + register 'openproject-documents', author_url: "http://www.openproject.org", bundled: true do menu :project_menu, :documents, - { controller: "/documents", action: "index" }, + { controller: '/documents', action: 'index' }, caption: :label_document_plural, before: :members, - icon: "notes" + icon: 'notes' project_module :documents do |_map| permission :view_documents, @@ -55,7 +55,7 @@ class Engine < ::Rails::Engine Redmine::Search.register :documents end - activity_provider :documents, class_name: "Activities::DocumentActivityProvider", default: false + activity_provider :documents, class_name: 'Activities::DocumentActivityProvider', default: false patches %i[Project] @@ -71,7 +71,7 @@ class Engine < ::Rails::Engine "#{document(id)}/attachments" end - add_api_endpoint "API::V3::Root" do + add_api_endpoint 'API::V3::Root' do mount ::API::V3::Documents::DocumentsAPI end diff --git a/modules/documents/lib/openproject-documents.rb b/modules/documents/lib/openproject-documents.rb index 6eacc169126d..9288d1d36f86 100644 --- a/modules/documents/lib/openproject-documents.rb +++ b/modules/documents/lib/openproject-documents.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/documents" +require 'open_project/documents' diff --git a/modules/documents/openproject-documents.gemspec b/modules/documents/openproject-documents.gemspec index c00b215e8315..df9722eddf22 100644 --- a/modules/documents/openproject-documents.gemspec +++ b/modules/documents/openproject-documents.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "openproject-documents" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" s.summary = "OpenProject Documents" @@ -8,5 +8,5 @@ Gem::Specification.new do |s| s.license = "GPLv3" s.files = Dir["{app,config,db,lib,doc}/**/*", "README.md"] - s.metadata["rubygems_mfa_required"] = "true" + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/documents/spec/api/v3/documents/document_representer_rendering_spec.rb b/modules/documents/spec/api/v3/documents/document_representer_rendering_spec.rb index 7d5057ea54e3..68d8524ba021 100644 --- a/modules/documents/spec/api/v3/documents/document_representer_rendering_spec.rb +++ b/modules/documents/spec/api/v3/documents/document_representer_rendering_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Documents::DocumentRepresenter, "rendering" do +RSpec.describe API::V3::Documents::DocumentRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:document) do build_stubbed(:document, - description: "Some description") do |document| + description: 'Some description') do |document| allow(document) .to receive(:project) .and_return(project) @@ -49,25 +49,25 @@ subject { representer.to_json } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.document document.id } let(:title) { document.title } end - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:link) { :attachments } let(:href) { api_v3_paths.attachments_by_document document.id } end - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { :project } let(:title) { project.name } let(:href) { api_v3_paths.project project.id } end - it_behaves_like "has an untitled action link" do + it_behaves_like 'has an untitled action link' do let(:link) { :addAttachment } let(:href) { api_v3_paths.attachments_by_document document.id } let(:method) { :post } @@ -75,41 +75,41 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Document" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Document' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { document.id } end - it_behaves_like "property", :title do + it_behaves_like 'property', :title do let(:value) { document.title } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { document.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { document.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end - it_behaves_like "API V3 formattable", "description" do - let(:format) { "markdown" } + it_behaves_like 'API V3 formattable', 'description' do + let(:format) { 'markdown' } let(:raw) { document.description } - let(:html) { '

    ' + document.description + "

    " } + let(:html) { '

    ' + document.description + '

    ' } end end - describe "_embedded" do - it "has project embedded" do + describe '_embedded' do + it 'has project embedded' do expect(subject) .to be_json_eql(project.name.to_json) - .at_path("_embedded/project/name") + .at_path('_embedded/project/name') end end end diff --git a/modules/documents/spec/application_helper_spec.rb b/modules/documents/spec/application_helper_spec.rb index 573fb119be1b..2e18111bd57a 100644 --- a/modules/documents/spec/application_helper_spec.rb +++ b/modules/documents/spec/application_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ApplicationHelper do include ApplicationHelper @@ -47,7 +47,7 @@ end let(:document) do create(:document, - title: "Test document", + title: 'Test document', project:) end @@ -62,10 +62,10 @@ context "Simple Document links" do let(:document_link) do - link_to("Test document", - { controller: "documents", action: "show", id: document.id }, - class: "document op-uc-link", - target: "_top") + link_to('Test document', + { controller: 'documents', action: 'show', id: document.id }, + class: 'document op-uc-link', + target: '_top') end context "Plain link" do @@ -93,7 +93,7 @@ end end - context "Cross-Project Document Links" do + context 'Cross-Project Document Links' do let(:the_other_project) { create(:valid_project) } context "By name without project" do diff --git a/modules/documents/spec/controllers/documents_controller_spec.rb b/modules/documents/spec/controllers/documents_controller_spec.rb index bb7c3914e6d2..85f4f470465a 100644 --- a/modules/documents/spec/controllers/documents_controller_spec.rb +++ b/modules/documents/spec/controllers/documents_controller_spec.rb @@ -62,13 +62,13 @@ end end - describe "new" do + describe 'new' do before do get :new, params: { project_id: project.id } end - it "show the new document form" do - expect(response).to render_template(partial: "documents/_form") + it 'show the new document form' do + expect(response).to render_template(partial: 'documents/_form') end end @@ -99,7 +99,7 @@ end.to change(Document, :count).by 1 end - it "does trigger a workflow job for the document" do + it 'does trigger a workflow job for the document' do expect(Notifications::WorkflowJob) .to have_been_enqueued .with(:create_notifications, document.journals.last, true) @@ -119,7 +119,7 @@ title: "New Document", project_id: notify_project.id, category_id: default_category.id), - attachments: { "1" => { id: uncontainered.id } } + attachments: { '1' => { id: uncontainered.id } } } end @@ -137,7 +137,7 @@ end end - describe "show" do + describe 'show' do before do document get :show, params: { id: document.id } @@ -145,7 +145,7 @@ it "shows the attachment" do expect(response).to be_successful - expect(response).to render_template("show") + expect(response).to render_template('show') end end diff --git a/modules/documents/spec/factories/journal/document_journal_factory.rb b/modules/documents/spec/factories/journal/document_journal_factory.rb index b735949d0992..0f01b316bc83 100644 --- a/modules/documents/spec/factories/journal/document_journal_factory.rb +++ b/modules/documents/spec/factories/journal/document_journal_factory.rb @@ -27,6 +27,6 @@ #++ FactoryBot.define do - factory :journal_document_journal, class: "Journal::DocumentJournal" do + factory :journal_document_journal, class: 'Journal::DocumentJournal' do end end diff --git a/modules/documents/spec/features/attachment_upload_spec.rb b/modules/documents/spec/features/attachment_upload_spec.rb index 3b1a08c508e6..9c72ba18152d 100644 --- a/modules/documents/spec/features/attachment_upload_spec.rb +++ b/modules/documents/spec/features/attachment_upload_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" +require 'spec_helper' +require 'features/page_objects/notification' -RSpec.describe "Upload attachment to documents", :js, +RSpec.describe 'Upload attachment to documents', :js, with_settings: { journal_aggregation_time_minutes: 0 } do @@ -47,7 +47,7 @@ end let(:project) { create(:project) } let(:attachments) { Components::Attachments.new } - let(:image_fixture) { UploadedFile.load_from("spec/fixtures/files/image.png") } + let(:image_fixture) { UploadedFile.load_from('spec/fixtures/files/image.png') } let(:editor) { Components::WysiwygEditor.new } let(:attachments_list) { Components::AttachmentsList.new } @@ -55,43 +55,43 @@ login_as(user) end - shared_examples "can upload an image" do - it "can upload an image" do + shared_examples 'can upload an image' do + it 'can upload an image' do visit new_project_document_path(project) - expect(page).to have_css("#new_document", wait: 10) + expect(page).to have_css('#new_document', wait: 10) SeleniumHubWaiter.wait - select(category.name, from: "Category") - fill_in "Title", with: "New documentation" + select(category.name, from: 'Category') + fill_in "Title", with: 'New documentation' # adding an image via the attachments-list find_test_selector("op-attachments--drop-box").drop(image_fixture.path) - editor.attachments_list.expect_attached("image.png") + editor.attachments_list.expect_attached('image.png') # adding an image - editor.drag_attachment image_fixture.path, "Image uploaded on creation" - editor.attachments_list.expect_attached("image.png", count: 2) + editor.drag_attachment image_fixture.path, 'Image uploaded on creation' + editor.attachments_list.expect_attached('image.png', count: 2) editor.wait_until_upload_progress_toaster_cleared perform_enqueued_jobs do - click_on "Create" + click_on 'Create' # Expect it to be present on the index page - expect(page).to have_css(".document-category-elements--header", text: "New documentation") - expect(page).to have_css("#content img", count: 1) - expect(page).to have_content("Image uploaded on creation") + expect(page).to have_css('.document-category-elements--header', text: 'New documentation') + expect(page).to have_css('#content img', count: 1) + expect(page).to have_content('Image uploaded on creation') end document = Document.last - expect(document.title).to eq "New documentation" + expect(document.title).to eq 'New documentation' # Expect it to be present on the show page SeleniumHubWaiter.wait - find(".document-category-elements--header a", text: "New documentation").click + find('.document-category-elements--header a', text: 'New documentation').click expect(page).to have_current_path "/documents/#{document.id}", wait: 10 - expect(page).to have_css("#content img", count: 1) - expect(page).to have_content("Image uploaded on creation") + expect(page).to have_css('#content img', count: 1) + expect(page).to have_content('Image uploaded on creation') # Adding a second image # We should be using the 'Edit' button at the top but that leads to flickering specs @@ -101,27 +101,27 @@ # editor.click_and_type_slowly 'abc' SeleniumHubWaiter.wait - editor.attachments_list.expect_attached("image.png", count: 2) + editor.attachments_list.expect_attached('image.png', count: 2) - editor.drag_attachment image_fixture.path, "Image uploaded the second time" + editor.drag_attachment image_fixture.path, 'Image uploaded the second time' - editor.attachments_list.expect_attached("image.png", count: 3) + editor.attachments_list.expect_attached('image.png', count: 3) editor.attachments_list.drag_enter editor.attachments_list.drop(image_fixture) - editor.attachments_list.expect_attached("image.png", count: 4) + editor.attachments_list.expect_attached('image.png', count: 4) editor.wait_until_upload_progress_toaster_cleared perform_enqueued_jobs do - click_on "Save" + click_on 'Save' # Expect both images to be present on the show page - expect(page).to have_css("#content img", count: 2) - expect(page).to have_content("Image uploaded on creation") - expect(page).to have_content("Image uploaded the second time") - attachments_list.expect_attached("image.png", count: 4) + expect(page).to have_css('#content img', count: 2) + expect(page).to have_content('Image uploaded on creation') + expect(page).to have_content('Image uploaded the second time') + attachments_list.expect_attached('image.png', count: 4) end # Expect a mail to be sent to the user having subscribed to all notifications @@ -132,19 +132,19 @@ .to contain_exactly(other_user.mail) expect(ActionMailer::Base.deliveries.last.subject) - .to include "New documentation" + .to include 'New documentation' end end - context "with direct uploads (Regression #34285)", :with_direct_uploads do + context 'with direct uploads (Regression #34285)', :with_direct_uploads do before do allow_any_instance_of(Attachment).to receive(:diskfile).and_return image_fixture # rubocop:disable RSpec/AnyInstance end - it_behaves_like "can upload an image" + it_behaves_like 'can upload an image' end - context "for internal uploads", with_direct_uploads: false do - it_behaves_like "can upload an image" + context 'for internal uploads', with_direct_uploads: false do + it_behaves_like 'can upload an image' end end diff --git a/modules/documents/spec/lib/open_project/markdown_formatting_spec.rb b/modules/documents/spec/lib/open_project/markdown_formatting_spec.rb index bdc7b175c29d..7e5e61e7aa5c 100644 --- a/modules/documents/spec/lib/open_project/markdown_formatting_spec.rb +++ b/modules/documents/spec/lib/open_project/markdown_formatting_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::TextFormatting, - "Document links" do + 'Document links' do include ActionView::Helpers::UrlHelper # soft-dependency include ActionView::Context include OpenProject::StaticRouting::UrlHelpers @@ -43,7 +43,7 @@ def controller end shared_let(:document) do - create(:document, project:, title: "My document") + create(:document, project:, title: 'My document') end subject do @@ -62,7 +62,7 @@ def controller TEXT end - context "when visible" do + context 'when visible' do let(:role) { create(:project_role, permissions: %i[view_documents view_project]) } let(:user) { create(:user, member_with_roles: { project => role }) } @@ -76,19 +76,19 @@ def controller let(:document_link) do link_to( - "My document", - { controller: "/documents", action: "show", id: document.id, only_path: true }, - class: "document op-uc-link", - target: "_top" + 'My document', + { controller: '/documents', action: 'show', id: document.id, only_path: true }, + class: 'document op-uc-link', + target: '_top' ) end - it "renders the links" do + it 'renders the links' do expect(subject).to be_html_eql(expected) end end - context "when not visible" do + context 'when not visible' do let(:user) { create(:user) } let(:expected) do @@ -99,7 +99,7 @@ def controller HTML end - it "renders the raw text" do + it 'renders the raw text' do expect(subject).to be_html_eql(expected) end end diff --git a/modules/documents/spec/lib/redmine/access_control_spec.rb b/modules/documents/spec/lib/redmine/access_control_spec.rb index 130ee4439e73..bc484b4b3e3f 100644 --- a/modules/documents/spec/lib/redmine/access_control_spec.rb +++ b/modules/documents/spec/lib/redmine/access_control_spec.rb @@ -25,19 +25,19 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../../spec_helper" +require File.dirname(__FILE__) + '/../../spec_helper' RSpec.describe OpenProject::AccessControl do - describe "manage documents permission" do - it "is part of the documents project module" do + describe 'manage documents permission' do + it 'is part of the documents project module' do permission = OpenProject::AccessControl.permission(:manage_documents) expect(permission.project_module).to be(:documents) end end - describe "view documents permission" do - it "is part of the documents project module" do + describe 'view documents permission' do + it 'is part of the documents project module' do permission = OpenProject::AccessControl.permission(:view_documents) expect(permission.project_module).to be(:documents) diff --git a/modules/documents/spec/mailers/documents_mailer_spec.rb b/modules/documents/spec/mailers/documents_mailer_spec.rb index d7add0f09d12..d5509447c0f1 100644 --- a/modules/documents/spec/mailers/documents_mailer_spec.rb +++ b/modules/documents/spec/mailers/documents_mailer_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe DocumentsMailer do let(:user) do - create(:user, firstname: "Test", lastname: "User", mail: "test@test.com") + create(:user, firstname: 'Test', lastname: "User", mail: 'test@test.com') end let(:project) { create(:project, name: "TestProject") } let(:document) do @@ -37,9 +37,9 @@ end let(:mail) { DocumentsMailer.document_added(user, document) } - describe "document added-mail", with_settings: { host_name: "my.openproject.com" } do + describe "document added-mail", with_settings: { host_name: 'my.openproject.com' } do it "renders the subject" do - expect(mail.subject).to eql "[TestProject] New document: Test Title" + expect(mail.subject).to eql '[TestProject] New document: Test Title' end it "renders the receivers mail" do diff --git a/modules/documents/spec/models/document_category_spec.rb b/modules/documents/spec/models/document_category_spec.rb index 0fd70473b658..ff645858504e 100644 --- a/modules/documents/spec/models/document_category_spec.rb +++ b/modules/documents/spec/models/document_category_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe DocumentCategory do let(:project) { create(:project) } diff --git a/modules/documents/spec/models/document_spec.rb b/modules/documents/spec/models/document_spec.rb index 5a37f1b432f6..1889677ccd89 100644 --- a/modules/documents/spec/models/document_spec.rb +++ b/modules/documents/spec/models/document_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe Document do - let(:documentation_category) { create(:document_category, name: "User documentation") } + let(:documentation_category) { create(:document_category, name: 'User documentation') } let(:project) { create(:project) } let(:user) { create(:user) } let(:admin) { create(:admin) } @@ -55,7 +55,7 @@ end it "sets a default-category, if none is given" do - default_category = create(:document_category, name: "Technical documentation", is_default: true) + default_category = create(:document_category, name: 'Technical documentation', is_default: true) document = Document.new(project:, title: "New Document") expect(document.category).to eql default_category expect do @@ -69,7 +69,7 @@ expect do Attachments::CreateService .new(user: admin) - .call(container: valid_document, file: attributes_for(:attachment)[:file], filename: "foo") + .call(container: valid_document, file: attributes_for(:attachment)[:file], filename: 'foo') expect(valid_document.attachments.size).to be 1 end.to(change do diff --git a/modules/documents/spec/models/queries/documents/document_query_spec.rb b/modules/documents/spec/models/queries/documents/document_query_spec.rb index a2bf0a80c56a..1ac9dfb330b4 100644 --- a/modules/documents/spec/models/queries/documents/document_query_spec.rb +++ b/modules/documents/spec/models/queries/documents/document_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Documents::DocumentQuery do let(:user) { build_stubbed(:user) } @@ -37,39 +37,39 @@ login_as(user) end - context "without a filter" do - describe "#results" do - it "is the same as getting all the visible documents" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the visible documents' do expect(instance.results.to_sql).to eql base_scope.to_sql end end end - context "with a project filter" do + context 'with a project filter' do before do allow(Project) .to receive_message_chain(:visible, :pluck) .with(:id) .and_return([1]) - instance.where("project_id", "=", ["1"]) + instance.where('project_id', '=', ['1']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope - .where(["documents.project_id IN (?)", ["1"]]) + .where(["documents.project_id IN (?)", ['1']]) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("project_id", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('project_id', '=', ['']) expect(instance).to be_invalid end end diff --git a/modules/documents/spec/models/queries/documents/filters/project_filter_spec.rb b/modules/documents/spec/models/queries/documents/filters/project_filter_spec.rb index b138ac307895..26cfdd7d9920 100644 --- a/modules/documents/spec/models/queries/documents/filters/project_filter_spec.rb +++ b/modules/documents/spec/models/queries/documents/filters/project_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Documents::Filters::ProjectFilter do let(:project1) { build_stubbed(:project) } @@ -39,13 +39,13 @@ .and_return([project1.id, project2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :project_id } let(:type) { :list_optional } let(:name) { Document.human_attribute_name(:project) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[project1.id, project1.id.to_s], [project2.id, project2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :project_id } let(:model) { Document } let(:valid_values) { [project1.id.to_s] } diff --git a/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb b/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb index cfa95920e895..ea08c72fb03f 100644 --- a/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb +++ b/modules/documents/spec/requests/api/v3/attachments/attachments_by_documents_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "requests/api/v3/attachments/attachment_resource_shared_examples" +require 'spec_helper' +require 'requests/api/v3/attachments/attachment_resource_shared_examples' RSpec.describe "document attachments" do it_behaves_like "an APIv3 attachment resource" do diff --git a/modules/documents/spec/requests/api/v3/documents/documents_resource_spec.rb b/modules/documents/spec/requests/api/v3/documents/documents_resource_spec.rb index 5af45b06d6ef..59a3372702ef 100644 --- a/modules/documents/spec/requests/api/v3/documents/documents_resource_spec.rb +++ b/modules/documents/spec/requests/api/v3/documents/documents_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 documents resource" do +RSpec.describe 'API v3 documents resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -49,7 +49,7 @@ login_as(current_user) end - describe "GET /api/v3/documents" do + describe 'GET /api/v3/documents' do let(:path) { api_v3_paths.documents } before do @@ -59,56 +59,56 @@ get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns a Collection of visible documents" do + it 'returns a Collection of visible documents' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(1.to_json) - .at_path("total") + .at_path('total') expect(subject.body) - .to be_json_eql("Document".to_json) - .at_path("_embedded/elements/0/_type") + .to be_json_eql('Document'.to_json) + .at_path('_embedded/elements/0/_type') expect(subject.body) .to be_json_eql(document.title.to_json) - .at_path("_embedded/elements/0/title") + .at_path('_embedded/elements/0/title') end end - describe "GET /api/v3/documents/:id" do + describe 'GET /api/v3/documents/:id' do let(:path) { api_v3_paths.document(document.id) } before do get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the document" do + it 'returns the document' do expect(subject.body) - .to be_json_eql("Document".to_json) - .at_path("_type") + .to be_json_eql('Document'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(document.id.to_json) - .at_path("id") + .at_path('id') end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { [] } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end diff --git a/modules/documents/spec/routing/documents_routing_spec.rb b/modules/documents/spec/routing/documents_routing_spec.rb index 6edd5f059f69..34cc47cde187 100644 --- a/modules/documents/spec/routing/documents_routing_spec.rb +++ b/modules/documents/spec/routing/documents_routing_spec.rb @@ -26,50 +26,50 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DocumentsController do describe "routing" do it { - expect(get("/projects/567/documents")).to route_to(controller: "documents", - action: "index", - project_id: "567") + expect(get('/projects/567/documents')).to route_to(controller: 'documents', + action: 'index', + project_id: '567') } it { - expect(get("/projects/567/documents/new")).to route_to(controller: "documents", - action: "new", - project_id: "567") + expect(get('/projects/567/documents/new')).to route_to(controller: 'documents', + action: 'new', + project_id: '567') } it { - expect(get("/documents/22")).to route_to(controller: "documents", - action: "show", - id: "22") + expect(get('/documents/22')).to route_to(controller: 'documents', + action: 'show', + id: '22') } it { - expect(get("/documents/22/edit")).to route_to(controller: "documents", - action: "edit", - id: "22") + expect(get('/documents/22/edit')).to route_to(controller: 'documents', + action: 'edit', + id: '22') } it { - expect(post("/projects/567/documents")).to route_to(controller: "documents", - action: "create", - project_id: "567") + expect(post('/projects/567/documents')).to route_to(controller: 'documents', + action: 'create', + project_id: '567') } it { - expect(put("/documents/567")).to route_to(controller: "documents", - action: "update", - id: "567") + expect(put('/documents/567')).to route_to(controller: 'documents', + action: 'update', + id: '567') } it { - expect(delete("/documents/567")).to route_to(controller: "documents", - action: "destroy", - id: "567") + expect(delete('/documents/567')).to route_to(controller: 'documents', + action: 'destroy', + id: '567') } end end diff --git a/modules/documents/spec/services/notifications/create_from_model_service_document_spec.rb b/modules/documents/spec/services/notifications/create_from_model_service_document_spec.rb index e26002b48909..93abebff329b 100644 --- a/modules/documents/spec/services/notifications/create_from_model_service_document_spec.rb +++ b/modules/documents/spec/services/notifications/create_from_model_service_document_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require Rails.root.join("spec/services/notifications/create_from_journal_job_shared") +require 'spec_helper' +require Rails.root.join('spec/services/notifications/create_from_journal_job_shared') -RSpec.describe Notifications::CreateFromModelService, "document", with_settings: { journal_aggregation_time_minutes: 0 } do +RSpec.describe Notifications::CreateFromModelService, 'document', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) do described_class.new(journal).call(send_notifications) end - include_context "with CreateFromJournalJob context" + include_context 'with CreateFromJournalJob context' shared_let(:project) { create(:project) } @@ -53,10 +53,10 @@ recipient end - describe "#perform" do - context "with a newly created document" do - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + describe '#perform' do + context 'with a newly created document' do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -68,53 +68,53 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do before do recipient.members.destroy_all end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "with an updated document" do + context 'with an updated document' do before do - resource.title = "A new subject" + resource.title = 'A new subject' resource.save! end - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -126,42 +126,42 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do before do recipient.members.destroy_all end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end end diff --git a/modules/documents/spec/services/notifications/mail_service_spec.rb b/modules/documents/spec/services/notifications/mail_service_spec.rb index 14b9ac829915..5f6ad1063cb0 100644 --- a/modules/documents/spec/services/notifications/mail_service_spec.rb +++ b/modules/documents/spec/services/notifications/mail_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::MailService, type: :model do subject(:call) { instance.call } @@ -39,7 +39,7 @@ end let(:instance) { described_class.new(notification) } - context "with a document journal notification" do + context 'with a document journal notification' do let(:journal) do build_stubbed(:journal, journable: build_stubbed(:document)).tap do |j| @@ -76,7 +76,7 @@ mail end - it "sends a mail" do + it 'sends a mail' do call expect(DocumentsMailer) @@ -88,10 +88,10 @@ .to have_received(:deliver_later) end - context "with the notification read in app already" do + context 'with the notification read in app already' do let(:read_ian) { true } - it "sends no mail" do + it 'sends no mail' do call expect(DocumentsMailer) @@ -99,10 +99,10 @@ end end - context "with the journal not being the initial one" do + context 'with the journal not being the initial one' do let(:initial_journal) { false } - it "sends no mail" do + it 'sends no mail' do call expect(DocumentsMailer) diff --git a/modules/gantt/app/controllers/gantt/gantt_controller.rb b/modules/gantt/app/controllers/gantt/gantt_controller.rb index 62424595cb77..198a5033c6d0 100644 --- a/modules/gantt/app/controllers/gantt/gantt_controller.rb +++ b/modules/gantt/app/controllers/gantt/gantt_controller.rb @@ -32,7 +32,7 @@ def index format.html do render :index, locals: { query: @query, project: @project, menu_name: project_or_global_menu }, - layout: "angular/angular" + layout: 'angular/angular' end format.any(*supported_list_formats) do diff --git a/modules/gantt/app/controllers/gantt/menus_controller.rb b/modules/gantt/app/controllers/gantt/menus_controller.rb index 8b99b082b8fc..01c119e5b485 100644 --- a/modules/gantt/app/controllers/gantt/menus_controller.rb +++ b/modules/gantt/app/controllers/gantt/menus_controller.rb @@ -38,16 +38,16 @@ def show def menu_items [ - OpenProject::Menu::MenuGroup.new(header: I18n.t("js.label_starred_queries"), children: starred_queries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("js.label_default_queries"), children: default_queries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("js.label_global_queries"), children: global_queries), - OpenProject::Menu::MenuGroup.new(header: I18n.t("js.label_custom_queries"), children: custom_queries) + OpenProject::Menu::MenuGroup.new(header: I18n.t('js.label_starred_queries'), children: starred_queries), + OpenProject::Menu::MenuGroup.new(header: I18n.t('js.label_default_queries'), children: default_queries), + OpenProject::Menu::MenuGroup.new(header: I18n.t('js.label_global_queries'), children: global_queries), + OpenProject::Menu::MenuGroup.new(header: I18n.t('js.label_custom_queries'), children: custom_queries) ] end def starred_queries base_query - .where("starred" => "t") + .where('starred' => 't') .pluck(:id, :name) .map { |id, name| menu_item({ query_id: id }, name) } end @@ -67,16 +67,16 @@ def default_queries def global_queries base_query - .where("starred" => "f") - .where("public" => "t") + .where('starred' => 'f') + .where('public' => 't') .pluck(:id, :name) .map { |id, name| menu_item({ query_id: id }, name) } end def custom_queries base_query - .where("starred" => "f") - .where("public" => "f") + .where('starred' => 'f') + .where('public' => 'f') .pluck(:id, :name) .map { |id, name| menu_item({ query_id: id }, name) } end @@ -86,12 +86,12 @@ def base_query .visible(current_user) .includes(:project) .joins(:views) - .where("views.type" => "gantt") + .where('views.type' => 'gantt') if @project.present? - base_query.where("queries.project_id" => @project.id) + base_query.where('queries.project_id' => @project.id) else - base_query.where("queries.project_id" => nil) + base_query.where('queries.project_id' => nil) end end diff --git a/modules/gantt/app/services/gantt/default_query_generator_service.rb b/modules/gantt/app/services/gantt/default_query_generator_service.rb index c4a548f07d57..9e2f67194e4e 100644 --- a/modules/gantt/app/services/gantt/default_query_generator_service.rb +++ b/modules/gantt/app/services/gantt/default_query_generator_service.rb @@ -43,7 +43,7 @@ class DefaultQueryGeneratorService tzl: "auto", tv: true, hi: true, - t: "start_date:asc" + t: 'start_date:asc' }.to_json.freeze attr_reader :project @@ -70,7 +70,7 @@ class << self def all_open_query(project) default_with_filter = add_columns(project) - default_with_filter["f"] = [{ "n" => "status", "o" => "o", "v" => [] }] + default_with_filter['f'] = [{ 'n' => 'status', 'o' => 'o', 'v' => [] }] default_with_filter end @@ -81,7 +81,7 @@ def milestones_query(project) milestones = milestone_ids(project) return if milestones.empty? - default_with_filter["f"] = [{ "n" => "type", "o" => "=", "v" => milestones }] + default_with_filter['f'] = [{ 'n' => 'type', 'o' => '=', 'v' => milestones }] default_with_filter end @@ -89,7 +89,7 @@ def add_columns(project) default_with_filter = JSON .parse(Gantt::DefaultQueryGeneratorService::DEFAULT_PARAMS) - default_with_filter["c"] = if project.present? + default_with_filter['c'] = if project.present? Gantt::DefaultQueryGeneratorService::PROJECT_DEFAULT_COLUMNS else Gantt::DefaultQueryGeneratorService::GLOBAL_DEFAULT_COLUMNS @@ -110,11 +110,11 @@ def phase_ids(project) if project.present? ::Type .enabled_in(project.id) - .where(name: I18n.t("seeds.standard.types.item_2.name", default: "Phase")) + .where(name: I18n.t('seeds.standard.types.item_2.name', default: 'Phase')) .pluck(:id) .map(&:to_s) else - ::Type.where(name: "Phase").pluck(:id).map(&:to_s) + ::Type.where(name: 'Phase').pluck(:id).map(&:to_s) end end end diff --git a/modules/gantt/config/routes.rb b/modules/gantt/config/routes.rb index 261a2b35b7ec..ec21074b0afd 100644 --- a/modules/gantt/config/routes.rb +++ b/modules/gantt/config/routes.rb @@ -1,24 +1,24 @@ Rails.application.routes.draw do - scope "projects/:project_id", as: "project" do - resources :gantt, controller: "gantt/gantt", only: [:index] do + scope 'projects/:project_id', as: 'project' do + resources :gantt, controller: 'gantt/gantt', only: [:index] do collection do # The menu route has to be above the state routes! Otherwise, the menu will be interpreted as another state - get "menu" => "gantt/menus#show" + get 'menu' => 'gantt/menus#show' # states managed by client-side routing on work_package#index - get "(/*state)" => "gantt/gantt#index", as: "" - get "/create_new" => "gantt/gantt#index", as: "new_split" + get '(/*state)' => 'gantt/gantt#index', as: '' + get '/create_new' => 'gantt/gantt#index', as: 'new_split' end end end - resources :gantt, controller: "gantt/gantt", only: [:index] do + resources :gantt, controller: 'gantt/gantt', only: [:index] do collection do # states managed by client-side routing on work_package#index - get "details/*state" => "gantt/gantt#index", as: :details + get 'details/*state' => 'gantt/gantt#index', as: :details # states managed by client-side (angular) routing on work_package#show - get "/" => "gantt/gantt#index", as: "index" + get '/' => 'gantt/gantt#index', as: 'index' end end diff --git a/modules/gantt/lib/open_project/gantt.rb b/modules/gantt/lib/open_project/gantt.rb index 71ecc00e6f7d..d6eba8e7d10d 100644 --- a/modules/gantt/lib/open_project/gantt.rb +++ b/modules/gantt/lib/open_project/gantt.rb @@ -28,6 +28,6 @@ module OpenProject module Gantt - require "open_project/gantt/engine" + require 'open_project/gantt/engine' end end diff --git a/modules/gantt/lib/open_project/gantt/engine.rb b/modules/gantt/lib/open_project/gantt/engine.rb index e3b223cdae26..384b5379b0bd 100644 --- a/modules/gantt/lib/open_project/gantt/engine.rb +++ b/modules/gantt/lib/open_project/gantt/engine.rb @@ -32,8 +32,8 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-gantt", - author_url: "https://www.openproject.org", + register 'openproject-gantt', + author_url: 'https://www.openproject.org', bundled: true, settings: {} do Rails.application.reloader.to_prepare do @@ -42,9 +42,9 @@ class Engine < ::Rails::Engine end OpenProject::AccessControl.permission(:view_work_packages).tap do |add| - add.controller_actions << "gantt/gantt/index" - add.controller_actions << "gantt/gantt/menu" - add.controller_actions << "gantt/menus/show" + add.controller_actions << 'gantt/gantt/index' + add.controller_actions << 'gantt/gantt/menu' + add.controller_actions << 'gantt/menus/show' end end @@ -59,51 +59,51 @@ class Engine < ::Rails::Engine menu :global_menu, :gantt, - { controller: "/gantt/gantt", action: "index", project_id: nil }, + { controller: '/gantt/gantt', action: 'index', project_id: nil }, caption: :label_gantt_chart_plural, after: :work_packages, - icon: "view-timeline", + icon: 'view-timeline', if: should_render_global_menu_item menu :global_menu, :global_gantt_query_select, - { controller: "/gantt/gantt", action: "index" }, + { controller: '/gantt/gantt', action: 'index' }, parent: :gantt, - partial: "gantt/menus/menu", + partial: 'gantt/menus/menu', last: true, caption: :label_gantt_chart_plural, if: should_render_global_menu_item menu :project_menu, :gantt, - { controller: "/gantt/gantt", action: "index" }, + { controller: '/gantt/gantt', action: 'index' }, caption: :label_gantt_chart_plural, after: :work_packages, if: ->(project) { should_render_project_menu.call(project) }, - icon: "view-timeline", + icon: 'view-timeline', html: { - id: "main-menu-gantt" + id: 'main-menu-gantt' } menu :project_menu, :gantt_query_select, - { controller: "/gantt/gantt", action: "index" }, + { controller: '/gantt/gantt', action: 'index' }, parent: :gantt, - partial: "gantt/menus/menu", + partial: 'gantt/menus/menu', last: true, caption: :label_gantt_chart_plural, if: ->(project) { should_render_project_menu.call(project) } menu :top_menu, :gantt, - { controller: "/gantt/gantt", action: "index", project_id: nil }, + { controller: '/gantt/gantt', action: 'index', project_id: nil }, caption: :label_gantt_chart_plural, after: :work_packages, - icon: "view-timeline", + icon: 'view-timeline', if: should_render_global_menu_item end add_view :Gantt, - contract_strategy: "Gantt::Views::ContractStrategy" + contract_strategy: 'Gantt::Views::ContractStrategy' end end diff --git a/modules/gantt/lib/openproject-gantt.rb b/modules/gantt/lib/openproject-gantt.rb index 79d73374978b..95933c137e09 100644 --- a/modules/gantt/lib/openproject-gantt.rb +++ b/modules/gantt/lib/openproject-gantt.rb @@ -1 +1 @@ -require "open_project/gantt" +require 'open_project/gantt' diff --git a/modules/gantt/openproject-gantt.gemspec b/modules/gantt/openproject-gantt.gemspec index 8c95def17015..bf96d10b96c4 100644 --- a/modules/gantt/openproject-gantt.gemspec +++ b/modules/gantt/openproject-gantt.gemspec @@ -1,12 +1,12 @@ Gem::Specification.new do |s| - s.name = "openproject-gantt" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject Gantt" - s.description = "Provides gantt views" - s.license = "GPLv3" + s.name = 'openproject-gantt' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject Gantt' + s.description = 'Provides gantt views' + s.license = 'GPLv3' - s.files = Dir["{app,config,db,lib}/**/*"] - s.metadata["rubygems_mfa_required"] = "true" + s.files = Dir['{app,config,db,lib}/**/*'] + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/gantt/spec/controllers/gantt/gantt_controller_spec.rb b/modules/gantt/spec/controllers/gantt/gantt_controller_spec.rb index ba6c3753e2f3..836f13594637 100644 --- a/modules/gantt/spec/controllers/gantt/gantt_controller_spec.rb +++ b/modules/gantt/spec/controllers/gantt/gantt_controller_spec.rb @@ -28,27 +28,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Gantt::GanttController do - shared_let(:project) { create(:project, identifier: "test_project", public: false) } + shared_let(:project) { create(:project, identifier: 'test_project', public: false) } current_user do create(:user, member_with_permissions: { project => %i[view_work_packages export_work_packages] }) end - describe "index" do + describe 'index' do let(:default_gantt_params) { Gantt::DefaultQueryGeneratorService.new(with_project: project).call } - context "for atom format" do - let(:params) { default_gantt_params.merge(project_id: project.id, format: "atom") } + context 'for atom format' do + let(:params) { default_gantt_params.merge(project_id: project.id, format: 'atom') } - it "returns the atom feed" do - get("index", params:) + it 'returns the atom feed' do + get('index', params:) expect(response).to have_http_status(:success) - expect(response.content_type).to include("application/atom+xml") + expect(response.content_type).to include('application/atom+xml') end end end diff --git a/modules/gantt/spec/features/menu/global_gantt_menu_spec.rb b/modules/gantt/spec/features/menu/global_gantt_menu_spec.rb index 8d0631b0620d..bad2b9959e39 100644 --- a/modules/gantt/spec/features/menu/global_gantt_menu_spec.rb +++ b/modules/gantt/spec/features/menu/global_gantt_menu_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Gantt charts menu", +RSpec.describe 'Gantt charts menu', :js, :selenium do let(:user) { create(:admin) } @@ -84,29 +84,29 @@ login_as(user) end - describe "on the global Gantt charts page" do - it "shows all queries without a project" do + describe 'on the global Gantt charts page' do + it 'shows all queries without a project' do wp_global_timeline.visit! loading_indicator_saveguard # Show global queries only - expect(page).to have_css(".op-sidemenu--item-action", text: global_starred_query) - expect(page).to have_css(".op-sidemenu--item-action", text: global_public_query) - expect(page).to have_css(".op-sidemenu--item-action", text: global_private_query) - expect(page).to have_no_css(".op-sidemenu--item-action", text: private_project_query) + expect(page).to have_css('.op-sidemenu--item-action', text: global_starred_query) + expect(page).to have_css('.op-sidemenu--item-action', text: global_public_query) + expect(page).to have_css('.op-sidemenu--item-action', text: global_private_query) + expect(page).to have_no_css('.op-sidemenu--item-action', text: private_project_query) end end - describe "on the project Gantt charts page" do - it "shows all queries that belong to the project" do + describe 'on the project Gantt charts page' do + it 'shows all queries that belong to the project' do wp_project_timeline.visit! loading_indicator_saveguard # Show project queries only - expect(page).to have_no_css(".op-sidemenu--item-action", text: global_starred_query) - expect(page).to have_no_css(".op-sidemenu--item-action", text: global_public_query) - expect(page).to have_no_css(".op-sidemenu--item-action", text: global_private_query) - expect(page).to have_css(".op-sidemenu--item-action", text: private_project_query) + expect(page).to have_no_css('.op-sidemenu--item-action', text: global_starred_query) + expect(page).to have_no_css('.op-sidemenu--item-action', text: global_public_query) + expect(page).to have_no_css('.op-sidemenu--item-action', text: global_private_query) + expect(page).to have_css('.op-sidemenu--item-action', text: private_project_query) end end end diff --git a/modules/gantt/spec/features/timeline/timeline_dates_spec.rb b/modules/gantt/spec/features/timeline/timeline_dates_spec.rb index 4334c328c507..50f87f8d9554 100644 --- a/modules/gantt/spec/features/timeline/timeline_dates_spec.rb +++ b/modules/gantt/spec/features/timeline/timeline_dates_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package timeline date formatting", +RSpec.describe 'Work package timeline date formatting', :js, :selenium, - with_settings: { date_format: "%Y-%m-%d" } do + with_settings: { date_format: '%Y-%m-%d' } do shared_let(:type) { create(:type_bug, color: create(:color_green)) } shared_let(:project) { create(:project, types: [type], enabled_module_names: %i[work_package_tracking gantt]) } - shared_let(:start_date) { Date.parse("2020-12-31") } - shared_let(:due_date) { Date.parse("2021-01-01") } + shared_let(:start_date) { Date.parse('2020-12-31') } + shared_let(:due_date) { Date.parse('2021-01-01') } shared_let(:duration) { due_date - start_date + 1 } shared_let(:work_package) do @@ -45,7 +45,7 @@ start_date:, due_date:, duration:, - subject: "My subject") + subject: 'My subject') end shared_let(:work_package_with_non_working_days) do @@ -53,7 +53,7 @@ project:, type:, duration: 5, - subject: "My Subject 2") + subject: 'My Subject 2') end shared_let(:work_package_without_non_working_days) do @@ -62,17 +62,17 @@ type:, duration: 5, ignore_non_working_days: true, - subject: "Work Package ignoring non working days") + subject: 'Work Package ignoring non working days') end let(:wp_timeline) { Pages::WorkPackagesTimeline.new(project) } let!(:query_tl) do query = build(:query_with_view_gantt, user: current_user, project:) - query.column_names = ["id", "type", "subject"] + query.column_names = ['id', 'type', 'subject'] query.filters.clear query.timeline_visible = true - query.timeline_zoom_level = "days" - query.name = "Query with Timeline" + query.timeline_zoom_level = 'days' + query.name = 'Query with Timeline' query.save! query @@ -92,69 +92,69 @@ def expect_date_week(date, expected_week) wp_timeline.visit_query query_tl end - describe "with default settings", - with_settings: { start_of_week: "", first_week_of_year: "" } do + describe 'with default settings', + with_settings: { start_of_week: '', first_week_of_year: '' } do before do wp_timeline.expect_timeline! end - context "with german locale user" do - let(:current_user) { create(:admin, language: "de") } + context 'with german locale user' do + let(:current_user) { create(:admin, language: 'de') } - it "shows german ISO dates" do + it 'shows german ISO dates' do # expect moment to return week 53 for start date - expect_date_week work_package.start_date.iso8601, "53" - expect_date_week work_package.due_date.iso8601, "53" + expect_date_week work_package.start_date.iso8601, '53' + expect_date_week work_package.due_date.iso8601, '53' # Monday, 4th of january is the first week - expect_date_week "2021-01-04", "01" + expect_date_week '2021-01-04', '01' end end - context "with english locale user" do - let(:current_user) { create(:admin, language: "en") } + context 'with english locale user' do + let(:current_user) { create(:admin, language: 'en') } - it "shows english ISO dates" do + it 'shows english ISO dates' do # expect moment to return week 01 for start date - expect_date_week work_package.start_date.iso8601, "01" - expect_date_week work_package.due_date.iso8601, "01" + expect_date_week work_package.start_date.iso8601, '01' + expect_date_week work_package.due_date.iso8601, '01' # Monday, 4th of january is the second week - expect_date_week "2021-01-04", "02" + expect_date_week '2021-01-04', '02' end end - context "with weekdays defined" do - let(:current_user) { create(:admin, language: "en") } + context 'with weekdays defined' do + let(:current_user) { create(:admin, language: 'en') } shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } shared_let(:non_working_day) do create(:non_working_day, - date: "28-12-2020") + date: '28-12-2020') end - it "shows them as disabled" do - expect_date_week work_package.start_date.iso8601, "01" + it 'shows them as disabled' do + expect_date_week work_package.start_date.iso8601, '01' - expect(page).to have_test_selector("wp-timeline--non-working-day_27-12-2020") - expect(page).to have_test_selector("wp-timeline--non-working-day_2-1-2021") - expect(page).to have_test_selector("wp-timeline--non-working-day_28-12-2020") + expect(page).to have_test_selector('wp-timeline--non-working-day_27-12-2020') + expect(page).to have_test_selector('wp-timeline--non-working-day_2-1-2021') + expect(page).to have_test_selector('wp-timeline--non-working-day_28-12-2020') - expect(page).not_to have_test_selector("wp-timeline--non-working-day_29-12-2020") - expect(page).not_to have_test_selector("wp-timeline--non-working-day_30-12-2020") - expect(page).not_to have_test_selector("wp-timeline--non-working-day_31-12-2020") - expect(page).not_to have_test_selector("wp-timeline--non-working-day_1-1-2021") + expect(page).not_to have_test_selector('wp-timeline--non-working-day_29-12-2020') + expect(page).not_to have_test_selector('wp-timeline--non-working-day_30-12-2020') + expect(page).not_to have_test_selector('wp-timeline--non-working-day_31-12-2020') + expect(page).not_to have_test_selector('wp-timeline--non-working-day_1-1-2021') end end end - describe "with US/CA settings", + describe 'with US/CA settings', # According to our documentation: # https://www.openproject.org/docs/system-admin-guide/calendars-and-dates/#date-format - with_settings: { start_of_week: "7", first_week_of_year: "6" } do + with_settings: { start_of_week: '7', first_week_of_year: '6' } do let(:current_user) { create(:admin) } - it "shows english ISO dates" do - expect(page).to have_css(".wp-timeline--header-element", text: "01") - expect(page).to have_css(".wp-timeline--header-element", text: "02") + it 'shows english ISO dates' do + expect(page).to have_css('.wp-timeline--header-element', text: '01') + expect(page).to have_css('.wp-timeline--header-element', text: '02') # The last weekday determines whether there are 52 or 53 weeks # Only if the last day in the year is exactly the day before the day configured to be @@ -166,23 +166,23 @@ def expect_date_week(date, expected_week) 53 end - expect(page).to have_css(".wp-timeline--header-element", text: number_of_weeks) - expect(page).to have_no_css(".wp-timeline--header-element", text: number_of_weeks + 1) + expect(page).to have_css('.wp-timeline--header-element', text: number_of_weeks) + expect(page).to have_no_css('.wp-timeline--header-element', text: number_of_weeks + 1) # expect moment to return week 01 for start date and due date - expect_date_week work_package.start_date.iso8601, "01" - expect_date_week work_package.due_date.iso8601, "01" + expect_date_week work_package.start_date.iso8601, '01' + expect_date_week work_package.due_date.iso8601, '01' # First sunday in january is in second week - expect_date_week "2021-01-03", "02" + expect_date_week '2021-01-03', '02' end end - describe "setting dates" do + describe 'setting dates' do shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } let(:current_user) { create(:admin) } let(:row) { wp_timeline.timeline_row work_package_with_non_working_days.id } - it "today_line is in view" do + it 'today_line is in view' do row.wait_until_hoverable today_line_offsetLeft = page.evaluate_script <<~JS document.getElementById('wp-timeline-static-element-today-line').offsetLeft @@ -198,11 +198,11 @@ def expect_date_week(date, expected_week) shared_let(:non_working_day) do create(:non_working_day, - date: "06-01-2021") + date: '06-01-2021') end shared_examples "sets dates, duration and displays bar" do - it "sets dates, duration and duration bar" do + it 'sets dates, duration and duration bar' do subject row.expect_bar(duration: expected_bar_duration) @@ -221,13 +221,13 @@ def expect_date_week(date, expected_week) end end - context "with an existing duration only" do + context 'with an existing duration only' do before do # Reset dates on each run work_package_with_non_working_days.update({ start_date: nil, due_date: nil, duration: 5 }) end - it "displays the hover bar correctly" do + it 'displays the hover bar correctly' do # Expect no hover bar when hovering over a non working day row.hover_bar(offset_days: -1) row.expect_no_hovered_bar @@ -246,72 +246,72 @@ def expect_date_week(date, expected_week) row.expect_hovered_bar(duration: work_package_with_non_working_days.duration + 2) end - describe "set the start, due date while preserving duration" do + describe 'set the start, due date while preserving duration' do subject { row.click_bar } - it_behaves_like "sets dates, duration and displays bar" do + it_behaves_like 'sets dates, duration and displays bar' do let(:target_wp) { work_package_with_non_working_days } let(:expected_bar_duration) { work_package_with_non_working_days.duration } - let(:expected_start_date) { Date.parse("2021-01-04") } - let(:expected_due_date) { Date.parse("2021-01-08") } + let(:expected_start_date) { Date.parse('2021-01-04') } + let(:expected_due_date) { Date.parse('2021-01-08') } let(:expected_duration) { 4 } let(:expected_label) { work_package_with_non_working_days.subject } end end - describe "set the start, due date while preserving duration over the weekend" do + describe 'set the start, due date while preserving duration over the weekend' do subject { row.click_bar(offset_days: 1) } - it_behaves_like "sets dates, duration and displays bar" do + it_behaves_like 'sets dates, duration and displays bar' do let(:target_wp) { work_package_with_non_working_days } let(:expected_bar_duration) { work_package_with_non_working_days.duration + 2 } - let(:expected_start_date) { Date.parse("2021-01-05") } - let(:expected_due_date) { Date.parse("2021-01-11") } + let(:expected_start_date) { Date.parse('2021-01-05') } + let(:expected_due_date) { Date.parse('2021-01-11') } let(:expected_duration) { 4 } let(:expected_label) { work_package_with_non_working_days.subject } end end - describe "sets the start, due dates while preserving duration on a drag and drop create" do + describe 'sets the start, due dates while preserving duration on a drag and drop create' do subject { row.drag_and_drop(days: 5) } - it_behaves_like "sets dates, duration and displays bar" do + it_behaves_like 'sets dates, duration and displays bar' do let(:target_wp) { work_package_with_non_working_days } let(:expected_bar_duration) { work_package_with_non_working_days.duration } - let(:expected_start_date) { Date.parse("2021-01-04") } - let(:expected_due_date) { Date.parse("2021-01-08") } + let(:expected_start_date) { Date.parse('2021-01-04') } + let(:expected_due_date) { Date.parse('2021-01-08') } let(:expected_duration) { 4 } let(:expected_label) { work_package_with_non_working_days.subject } end end - describe "sets the start, due dates while preserving duration on a drag and drop create over the weekend" do + describe 'sets the start, due dates while preserving duration on a drag and drop create over the weekend' do subject { row.drag_and_drop(offset_days: 1, days: 7) } - it_behaves_like "sets dates, duration and displays bar" do + it_behaves_like 'sets dates, duration and displays bar' do let(:target_wp) { work_package_with_non_working_days } let(:expected_bar_duration) { work_package_with_non_working_days.duration + 2 } - let(:expected_start_date) { Date.parse("2021-01-05") } - let(:expected_due_date) { Date.parse("2021-01-11") } + let(:expected_start_date) { Date.parse('2021-01-05') } + let(:expected_due_date) { Date.parse('2021-01-11') } let(:expected_duration) { 4 } let(:expected_label) { work_package_with_non_working_days.subject } end end - describe "sets the start, due dates and duration on a drag and drop create over the weekend" do + describe 'sets the start, due dates and duration on a drag and drop create over the weekend' do subject { row.drag_and_drop(offset_days: 1, days: 8) } - it_behaves_like "sets dates, duration and displays bar" do + it_behaves_like 'sets dates, duration and displays bar' do let(:target_wp) { work_package_with_non_working_days } let(:expected_bar_duration) { work_package_with_non_working_days.duration + 3 } - let(:expected_start_date) { Date.parse("2021-01-05") } - let(:expected_due_date) { Date.parse("2021-01-12") } + let(:expected_start_date) { Date.parse('2021-01-05') } + let(:expected_due_date) { Date.parse('2021-01-12') } let(:expected_duration) { 5 } let(:expected_label) { work_package_with_non_working_days.subject } end end - it "cancels when the drag starts or finishes on a weekend" do + it 'cancels when the drag starts or finishes on a weekend' do # Finish on the weekend row.drag_and_drop(offset_days: 1, days: 5) @@ -325,17 +325,17 @@ def expect_date_week(date, expected_week) expect { work_package_with_non_working_days.reload }.not_to change { work_package_with_non_working_days } end - context "when ignore_non_working_days is true" do + context 'when ignore_non_working_days is true' do let(:row) { wp_timeline.timeline_row work_package_without_non_working_days.id } - describe "sets the start, due dates and duration on a drag and drop create over the weekend" do + describe 'sets the start, due dates and duration on a drag and drop create over the weekend' do subject { row.drag_and_drop(offset_days: 1, days: 8) } - it_behaves_like "sets dates, duration and displays bar" do + it_behaves_like 'sets dates, duration and displays bar' do let(:target_wp) { work_package_without_non_working_days } let(:expected_bar_duration) { work_package_without_non_working_days.duration + 3 } - let(:expected_start_date) { Date.parse("2021-01-05") } - let(:expected_due_date) { Date.parse("2021-01-12") } + let(:expected_start_date) { Date.parse('2021-01-05') } + let(:expected_due_date) { Date.parse('2021-01-12') } let(:expected_duration) { 8 } let(:expected_label) { work_package_without_non_working_days.subject } end diff --git a/modules/gantt/spec/features/timeline/timeline_hierarchy_spec.rb b/modules/gantt/spec/features/timeline/timeline_hierarchy_spec.rb index 702362f2722b..6d07707c9549 100644 --- a/modules/gantt/spec/features/timeline/timeline_hierarchy_spec.rb +++ b/modules/gantt/spec/features/timeline/timeline_hierarchy_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package timeline hierarchies", +RSpec.describe 'Work package timeline hierarchies', :js, :selenium do let(:user) { create(:admin) } @@ -45,7 +45,7 @@ end let!(:query) do query = build(:query_with_view_gantt, user:, project:) - query.column_names = ["subject"] + query.column_names = ['subject'] query.filters.clear query.show_hierarchies = true query.timeline_visible = true @@ -64,7 +64,7 @@ login_as(user) end - it "hides the row in both hierarchy and timeline" do + it 'hides the row in both hierarchy and timeline' do wp_timeline.visit_query query # Expect root and leaf visible in table and timeline @@ -84,10 +84,10 @@ wp_timeline.expect_hidden_row(wp_leaf) # Should now have exactly two rows (one in each split view) - expect(page).to have_css(".wp--row", count: 2) + expect(page).to have_css('.wp--row', count: 2) end - context "with a relation being rendered to a hidden row" do + context 'with a relation being rendered to a hidden row' do let!(:wp_other) do create(:work_package, project:, @@ -101,7 +101,7 @@ relation_type: Relation::TYPE_FOLLOWS) end - it "does not render the relation when hierarchy is collapsed" do + it 'does not render the relation when hierarchy is collapsed' do wp_timeline.visit_query query # Expect root and leaf visible in table and timeline diff --git a/modules/gantt/spec/features/timeline/timeline_labels_spec.rb b/modules/gantt/spec/features/timeline/timeline_labels_spec.rb index 0ba9d1be6ad1..4b27ed354572 100644 --- a/modules/gantt/spec/features/timeline/timeline_labels_spec.rb +++ b/modules/gantt/spec/features/timeline/timeline_labels_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package timeline labels", +RSpec.describe 'Work package timeline labels', :js, :selenium, - with_settings: { date_format: "%Y-%m-%d" } do + with_settings: { date_format: '%Y-%m-%d' } do let(:user) { create(:admin) } let(:today) { Time.zone.today } let(:tomorrow) { Time.zone.tomorrow } @@ -43,8 +43,8 @@ assigned_to: user, start_date: today, due_date: tomorrow, - subject: "My subject", - custom_field_values: { custom_field.id => custom_value_for("onions") }) + subject: 'My subject', + custom_field_values: { custom_field.id => custom_value_for('onions') }) end let(:milestone_work_package) do create(:work_package, @@ -52,7 +52,7 @@ type: milestone_type, start_date: future, due_date: future, - subject: "My milestone") + subject: 'My milestone') end let(:type) { create(:type_bug) } let(:milestone_type) { create(:type, is_milestone: true) } @@ -77,7 +77,7 @@ query = build(:query_with_view_gantt, user:, project:) query.filters.clear query.timeline_visible = true - query.name = "Query with Timeline" + query.name = 'Query with Timeline' query.save! @@ -98,12 +98,12 @@ def custom_value_for(str) wp_timeline.expect_timeline! end - it "shows and allows to configure labels" do + it 'shows and allows to configure labels' do # Check default labels (bar type) row = wp_timeline.timeline_row work_package.id row.expect_labels left: nil, right: nil, - farRight: "My subject" + farRight: 'My subject' row.expect_hovered_labels left: today.iso8601, right: tomorrow.iso8601 @@ -111,18 +111,18 @@ def custom_value_for(str) row = wp_timeline.timeline_row milestone_work_package.id row.expect_labels left: nil, right: nil, - farRight: "My milestone" + farRight: 'My milestone' row.expect_hovered_labels left: nil, right: future.iso8601 # Modify label configuration config_modal.open! - config_modal.expect_labels! left: "(none)", - right: "(none)", - farRight: "Subject" + config_modal.expect_labels! left: '(none)', + right: '(none)', + farRight: 'Subject' - config_modal.update_labels left: "Assignee", - right: "Type", - farRight: "Status" + config_modal.update_labels left: 'Assignee', + right: 'Type', + farRight: 'Status' # Check overridden labels row = wp_timeline.timeline_row work_package.id @@ -132,19 +132,19 @@ def custom_value_for(str) # Check default labels (milestone) row = wp_timeline.timeline_row milestone_work_package.id - row.expect_labels left: "-", + row.expect_labels left: '-', right: milestone_type.name.upcase, farRight: milestone_work_package.status.name # Save the query - settings_menu.open_and_save_query_as "changed labels" - wp_timeline.expect_title "changed labels" + settings_menu.open_and_save_query_as 'changed labels' + wp_timeline.expect_title 'changed labels' # Check the query query = Query.last - expect(query.timeline_labels).to eq left: "assignee", - right: "type", - farRight: "status" + expect(query.timeline_labels).to eq left: 'assignee', + right: 'type', + farRight: 'status' # Revisit page wp_timeline.visit_query query @@ -159,19 +159,19 @@ def custom_value_for(str) # Check overridden labels (milestone) row = wp_timeline.timeline_row milestone_work_package.id - row.expect_labels left: "-", + row.expect_labels left: '-', right: milestone_type.name.upcase, farRight: milestone_work_package.status.name # Set labels to start|due|subject config_modal.open! - config_modal.expect_labels! left: "Assignee", - right: "Type", - farRight: "Status" + config_modal.expect_labels! left: 'Assignee', + right: 'Type', + farRight: 'Status' - config_modal.update_labels left: "Start date", - right: "Finish date", - farRight: "Subject" + config_modal.update_labels left: 'Start date', + right: 'Finish date', + farRight: 'Subject' # Check overridden labels row = wp_timeline.timeline_row work_package.id diff --git a/modules/gantt/spec/features/timeline/timeline_navigation_spec.rb b/modules/gantt/spec/features/timeline/timeline_navigation_spec.rb index 6664d1f43dcb..abf15eec2f29 100644 --- a/modules/gantt/spec/features/timeline/timeline_navigation_spec.rb +++ b/modules/gantt/spec/features/timeline/timeline_navigation_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package timeline navigation", +RSpec.describe 'Work package timeline navigation', :js, :selenium do let(:user) { create(:admin) } @@ -61,7 +61,7 @@ login_as(user) end - describe "with multiple queries" do + describe 'with multiple queries' do let(:type) { create(:type) } let(:type2) { create(:type) } let(:project) { create(:project, enabled_module_names:, types: [type, type2]) } @@ -80,11 +80,11 @@ let!(:query) do query = build(:query_with_view_work_packages_table, user:, project:) - query.column_names = ["id", "type", "subject"] + query.column_names = ['id', 'type', 'subject'] query.filters.clear query.timeline_visible = false - query.add_filter("type_id", "=", [type.id]) - query.name = "Query without Timeline" + query.add_filter('type_id', '=', [type.id]) + query.name = 'Query without Timeline' query.save! create(:view_work_packages_table, @@ -95,11 +95,11 @@ let!(:query_tl) do query = build(:query_with_view_gantt, user:, project:) - query.column_names = ["id", "type", "subject"] + query.column_names = ['id', 'type', 'subject'] query.filters.clear - query.add_filter("type_id", "=", [type2.id]) + query.add_filter('type_id', '=', [type2.id]) query.timeline_visible = true - query.name = "Query with Timeline" + query.name = 'Query with Timeline' query.save! create(:view_gantt, @@ -108,7 +108,7 @@ query end - it "can move from and to the timeline query (Regression test #26086)" do + it 'can move from and to the timeline query (Regression test #26086)' do # Visit timeline query wp_timeline.visit_query query_tl @@ -117,8 +117,8 @@ wp_timeline.ensure_work_package_not_listed! work_package # Navigate to the WP module - find(".main-menu--arrow-left-to-project").click - find("#main-menu-work-packages-wrapper .main-menu-toggler").click + find('.main-menu--arrow-left-to-project').click + find('#main-menu-work-packages-wrapper .main-menu-toggler').click # Select other query query_menu.select query @@ -127,8 +127,8 @@ wp_table.ensure_work_package_not_listed! work_package2 # Navigate to the Gantt module agin - find(".main-menu--arrow-left-to-project").click - find("#main-menu-gantt-wrapper .main-menu-toggler").click + find('.main-menu--arrow-left-to-project').click + find('#main-menu-gantt-wrapper .main-menu-toggler').click # Select first query again query_menu.click_item query_tl.name @@ -138,7 +138,7 @@ wp_timeline.ensure_work_package_not_listed! work_package end - it "can open a context menu in the timeline (Regression #30761)" do + it 'can open a context menu in the timeline (Regression #30761)' do # Visit timeline query wp_timeline.visit_query query_tl @@ -148,14 +148,14 @@ retry_block do find(".wp-row-#{work_package2.id}-timeline").right_click - find(".menu-item", text: "Add predecessor") - find(".menu-item", text: "Add follower") + find('.menu-item', text: 'Add predecessor') + find('.menu-item', text: 'Add follower') end end end - describe "with the default query" do - let(:closed_status) { create(:closed_status, name: "Closed") } + describe 'with the default query' do + let(:closed_status) { create(:closed_status, name: 'Closed') } let(:project) { create(:project, types: [milestone_type], enabled_module_names:) } let!(:wp_milestone) do @@ -169,7 +169,7 @@ status: closed_status) end - it "shows the timeline open initially" do + it 'shows the timeline open initially' do wp_timeline.visit! loading_indicator_saveguard @@ -183,7 +183,7 @@ end end - it "can save the open state and zoom of timeline" do + it 'can save the open state and zoom of timeline' do wp_timeline.visit_query query wp_timeline.expect_work_package_listed(work_package) @@ -202,13 +202,13 @@ wp_timeline.expect_zoom_at :weeks # Save the query - settings_menu.open_and_save_query_as "foobar" - wp_timeline.expect_title "foobar" + settings_menu.open_and_save_query_as 'foobar' + wp_timeline.expect_title 'foobar' # Check the query query = Query.last expect(query.timeline_visible).to be_truthy - expect(query.timeline_zoom_level).to eq "weeks" + expect(query.timeline_zoom_level).to eq 'weeks' # Revisit page wp_timeline.visit_query query @@ -225,13 +225,13 @@ # Save wp_timeline.save - wp_timeline.expect_and_dismiss_toaster message: "Successful update" + wp_timeline.expect_and_dismiss_toaster message: 'Successful update' query.reload - expect(query.timeline_zoom_level).to eq "auto" + expect(query.timeline_zoom_level).to eq 'auto' end - describe "with a hierarchy being shown" do + describe 'with a hierarchy being shown' do let!(:child_work_package) do create(:work_package, project:, @@ -250,7 +250,7 @@ query end - it "toggles the hierarchy in both views" do + it 'toggles the hierarchy in both views' do wp_timeline.visit_query query loading_indicator_saveguard wp_timeline.expect_work_package_listed(work_package) @@ -273,10 +273,10 @@ end end - describe "when table is grouped" do + describe 'when table is grouped' do let(:project) { create(:project) } - let(:category) { create(:category, project:, name: "Foo") } - let(:category2) { create(:category, project:, name: "Bar") } + let(:category) { create(:category, project:, name: 'Foo') } + let(:category2) { create(:category, project:, name: 'Bar') } let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:relations) { Components::WorkPackages::Relations.new(wp_cat1) } @@ -301,7 +301,7 @@ type: milestone_type, start_date: Date.current - 10.days, due_date: Date.current - 10.days, - subject: "My milestone") + subject: 'My milestone') end let!(:wp_none) do @@ -318,7 +318,7 @@ let!(:query) do query = build(:query_with_view_gantt, user:, project:) - query.column_names = ["id", "subject", "category"] + query.column_names = ['id', 'subject', 'category'] query.show_hierarchies = false query.timeline_visible = true @@ -326,33 +326,33 @@ query end - it "mirrors group handling when grouping by category" do + it 'mirrors group handling when grouping by category' do wp_table.visit_query(query) wp_table.expect_work_package_listed(wp_cat1, wp_cat2, wp_none) - group_by.enable_via_menu "Category" + group_by.enable_via_menu 'Category' # Expect table to be grouped as WP created above - expect(page).to have_css(".group--value .count", count: 3) + expect(page).to have_css('.group--value .count', count: 3) # Expect timeline to have relation between first and second group wp_timeline.expect_timeline_relation(wp_cat1, wp_cat2) # Collapse Foo section - header = find(".wp-table--group-header", text: "Foo (1)") - header.find(".expander").click + header = find('.wp-table--group-header', text: 'Foo (1)') + header.find('.expander').click wp_timeline.ensure_work_package_not_listed!(wp_cat1) # Relation should be hidden wp_timeline.expect_no_timeline_relation(wp_cat1, wp_cat2) end - it "removes the relation element when removed in split screen" do + it 'removes the relation element when removed in split screen' do wp_table.visit_query(query) wp_table.expect_work_package_listed(wp_cat1, wp_cat2, wp_none) # Expect timeline to have relation between first and second group - within(".work-packages-split-view--tabletimeline-side") do + within('.work-packages-split-view--tabletimeline-side') do wp_timeline.expect_timeline_relation(wp_cat1, wp_cat2) wp_timeline.expect_timeline_element(wp_cat1) wp_timeline.expect_timeline_element(wp_cat2) @@ -364,32 +364,32 @@ relations.remove_relation(wp_cat2) # Relation should be removed in TL - within(".work-packages-split-view--tabletimeline-side") do + within('.work-packages-split-view--tabletimeline-side') do wp_timeline.expect_timeline_element(wp_cat1) wp_timeline.expect_timeline_element(wp_cat2) wp_timeline.expect_no_timeline_relation(wp_cat1, wp_cat2) end end - it "shows milestone icons on collapsed project group rows but not on expanded ones" do + it 'shows milestone icons on collapsed project group rows but not on expanded ones' do wp_table.visit_query(query) # The button to fold/expand all groups is only present when grouping expect(page) - .to have_no_button("wp-fold-toggle-button") + .to have_no_button('wp-fold-toggle-button') - group_by.enable_via_menu "Project" + group_by.enable_via_menu 'Project' # Collapse Foo section - find(".wp-table--group-header", text: "My Project No.") - .find(".expander") + find('.wp-table--group-header', text: 'My Project No.') + .find('.expander') .click # Folding will lead to having milestones presented within the group row - expect(page).to have_css(".-group-row .timeline-element.milestone") + expect(page).to have_css('.-group-row .timeline-element.milestone') # Check hover labels (milestone) - milestone = find(".timeline-element.milestone") + milestone = find('.timeline-element.milestone') milestone.hover expect(milestone).to have_css(".labelHoverLeft.not-empty") @@ -399,17 +399,17 @@ expect(milestone).to have_css(".labelFarRight", visible: :hidden) # Unfold Group rows - find(".wp-table--group-header", text: "My Project No.") - .find(".expander") + find('.wp-table--group-header', text: 'My Project No.') + .find('.expander') .click - expect(page).to have_no_css(".-group-row .timeline-element") + expect(page).to have_no_css('.-group-row .timeline-element') - click_button("wp-fold-toggle-button") - click_button(I18n.t("js.button_collapse_all")) + click_button('wp-fold-toggle-button') + click_button(I18n.t('js.button_collapse_all')) # Will again fold all rows so the milestone elements should again be present - expect(page).to have_css(".-group-row .timeline-element.milestone") + expect(page).to have_css('.-group-row .timeline-element.milestone') end end end diff --git a/modules/gantt/spec/migrations/change_view_of_queries_with_timeline_to_gantt_spec.rb b/modules/gantt/spec/migrations/change_view_of_queries_with_timeline_to_gantt_spec.rb index 4b5965f7a2ec..4f8cd7c1f843 100644 --- a/modules/gantt/spec/migrations/change_view_of_queries_with_timeline_to_gantt_spec.rb +++ b/modules/gantt/spec/migrations/change_view_of_queries_with_timeline_to_gantt_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("db/migrate/20231201085450_change_view_of_queries_with_timeline_to_gantt.rb") RSpec.describe ChangeViewOfQueriesWithTimelineToGantt, type: :model do @@ -55,13 +55,13 @@ query end - context "when migrating up" do + context 'when migrating up' do # Silencing migration logs, since we are not interested in that during testing subject { ActiveRecord::Migration.suppress_messages { described_class.new.up } } it "changes the view type for (work package table) queries with enabled timeline" do expect { subject } - .to change { View.where(query_id: wp_query_with_timeline.id).first.type }.from("work_packages_table").to("gantt") + .to change { View.where(query_id: wp_query_with_timeline.id).first.type }.from('work_packages_table').to('gantt') expect { subject } .not_to change { View.where(query_id: wp_query_without_timeline.id).first.type } expect { subject } @@ -69,7 +69,7 @@ end end - context "when migrating down" do + context 'when migrating down' do let!(:gantt_query) do query = create(:query_with_view_gantt) query.timeline_visible = true @@ -83,7 +83,7 @@ it "changes the view type for (gantt table) queries" do expect { subject } - .to change { View.where(query_id: gantt_query.id).first.type }.from("gantt").to("work_packages_table") + .to change { View.where(query_id: gantt_query.id).first.type }.from('gantt').to('work_packages_table') expect { subject } .not_to change { View.where(query_id: wp_query_with_timeline.id).first.type } expect { subject } diff --git a/modules/gantt/spec/routing/gantt_routing_spec.rb b/modules/gantt/spec/routing/gantt_routing_spec.rb index e592c27df9b4..d64644bf8c6f 100644 --- a/modules/gantt/spec/routing/gantt_routing_spec.rb +++ b/modules/gantt/spec/routing/gantt_routing_spec.rb @@ -26,46 +26,46 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Gantt routing" do - context "with :project_id" do - it "routes to gantt#index" do +RSpec.describe 'Gantt routing' do + context 'with :project_id' do + it 'routes to gantt#index' do expect(subject) - .to route(:get, "/projects/foobar/gantt") - .to(controller: "gantt/gantt", action: :index, project_id: "foobar") + .to route(:get, '/projects/foobar/gantt') + .to(controller: 'gantt/gantt', action: :index, project_id: 'foobar') end - it "connects GET /projects/:project_id/gantt/create_new to gantt#index" do - expect(get("/projects/1/gantt/create_new")) - .to route_to(controller: "gantt/gantt", - action: "index", - project_id: "1", - state: "create_new") + it 'connects GET /projects/:project_id/gantt/create_new to gantt#index' do + expect(get('/projects/1/gantt/create_new')) + .to route_to(controller: 'gantt/gantt', + action: 'index', + project_id: '1', + state: 'create_new') end - it "connects GET /projects/:project_id/gantt/details/:id/:state" + - " to gantt#index" do - expect(get("/projects/1/gantt/details/2/overview")) - .to route_to(controller: "gantt/gantt", - action: "index", - project_id: "1", - state: "details/2/overview") + it 'connects GET /projects/:project_id/gantt/details/:id/:state' + + ' to gantt#index' do + expect(get('/projects/1/gantt/details/2/overview')) + .to route_to(controller: 'gantt/gantt', + action: 'index', + project_id: '1', + state: 'details/2/overview') end end - context "without :project_id" do - it "routes to gantt#index" do + context 'without :project_id' do + it 'routes to gantt#index' do expect(subject) - .to route(:get, "/gantt") - .to(controller: "gantt/gantt", action: :index) + .to route(:get, '/gantt') + .to(controller: 'gantt/gantt', action: :index) end - it "connects GET /gantt/details/:state to gantt#index" do - expect(get("/gantt/details/5/overview")) - .to route_to(controller: "gantt/gantt", - action: "index", - state: "5/overview") + it 'connects GET /gantt/details/:state to gantt#index' do + expect(get('/gantt/details/5/overview')) + .to route_to(controller: 'gantt/gantt', + action: 'index', + state: '5/overview') end end end diff --git a/modules/github_integration/app/models/github_check_run.rb b/modules/github_integration/app/models/github_check_run.rb index c214004f8917..38c10ead37d0 100644 --- a/modules/github_integration/app/models/github_check_run.rb +++ b/modules/github_integration/app/models/github_check_run.rb @@ -30,20 +30,20 @@ class GithubCheckRun < ApplicationRecord belongs_to :github_pull_request, touch: true enum status: { - completed: "completed", - in_progress: "in_progress", - queued: "queued" + completed: 'completed', + in_progress: 'in_progress', + queued: 'queued' } enum conclusion: { - action_required: "action_required", - cancelled: "cancelled", - failure: "failure", - neutral: "neutral", - skipped: "skipped", - stale: "stale", - success: "success", - timed_out: "timed_out" + action_required: 'action_required', + cancelled: 'cancelled', + failure: 'failure', + neutral: 'neutral', + skipped: 'skipped', + stale: 'stale', + success: 'success', + timed_out: 'timed_out' } validates_presence_of :github_app_owner_avatar_url, diff --git a/modules/github_integration/app/models/github_pull_request.rb b/modules/github_integration/app/models/github_pull_request.rb index 4b53509d7ba1..32c16ae749a4 100644 --- a/modules/github_integration/app/models/github_pull_request.rb +++ b/modules/github_integration/app/models/github_pull_request.rb @@ -32,11 +32,11 @@ class GithubPullRequest < ApplicationRecord has_and_belongs_to_many :work_packages has_many :github_check_runs, dependent: :destroy belongs_to :github_user, optional: true - belongs_to :merged_by, optional: true, class_name: "GithubUser" + belongs_to :merged_by, optional: true, class_name: 'GithubUser' enum state: { - open: "open", - closed: "closed" + open: 'open', + closed: 'closed' } validates_presence_of :github_html_url, @@ -92,6 +92,6 @@ def validate_labels_schema return if labels.nil? return if labels.all? { |label| label.keys.sort == LABEL_KEYS } - errors.add(:labels, "invalid schema") + errors.add(:labels, 'invalid schema') end end diff --git a/modules/github_integration/app/workers/cron/clear_old_pull_requests_job.rb b/modules/github_integration/app/workers/cron/clear_old_pull_requests_job.rb index 242892c5e321..f43df184e8e6 100644 --- a/modules/github_integration/app/workers/cron/clear_old_pull_requests_job.rb +++ b/modules/github_integration/app/workers/cron/clear_old_pull_requests_job.rb @@ -27,9 +27,12 @@ #++ module Cron - class ClearOldPullRequestsJob < ApplicationJob + class ClearOldPullRequestsJob < CronJob priority_number :low + # runs at 1:25 nightly + self.cron_expression = '25 1 * * *' + def perform GithubPullRequest.without_work_package .find_each(&:destroy!) diff --git a/modules/github_integration/db/migrate/20210407110000_github_integration_models.rb b/modules/github_integration/db/migrate/20210407110000_github_integration_models.rb index 4e23b65f2a62..cc7367112505 100644 --- a/modules/github_integration/db/migrate/20210407110000_github_integration_models.rb +++ b/modules/github_integration/db/migrate/20210407110000_github_integration_models.rb @@ -55,7 +55,7 @@ def change end create_join_table :github_pull_requests, :work_packages do |t| - t.index :github_pull_request_id, name: "github_pr_wp_pr_id" + t.index :github_pull_request_id, name: 'github_pr_wp_pr_id' t.index %i[github_pull_request_id work_package_id], unique: true, name: "unique_index_gh_prs_wps_on_gh_pr_id_and_wp_id" diff --git a/modules/github_integration/lib/api/v3/github_pull_requests/github_check_run_representer.rb b/modules/github_integration/lib/api/v3/github_pull_requests/github_check_run_representer.rb index ae9f039d140d..3b37b8856f6f 100644 --- a/modules/github_integration/lib/api/v3/github_pull_requests/github_check_run_representer.rb +++ b/modules/github_integration/lib/api/v3/github_pull_requests/github_check_run_representer.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -52,7 +52,7 @@ class GithubCheckRunRepresenter < ::API::Decorators::Single date_time_property :completed_at def _type - "GithubCheckRun" + 'GithubCheckRun' end end end diff --git a/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_request_representer.rb b/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_request_representer.rb index afd486e7c455..dd1443aa749a 100644 --- a/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_request_representer.rb +++ b/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_request_representer.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -115,7 +115,7 @@ def initialize(model, current_user:, **_opts) date_time_property :updated_at def _type - "GithubPullRequest" + 'GithubPullRequest' end self.to_eager_load = %i[github_user merged_by] diff --git a/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_requests_api.rb b/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_requests_api.rb index 35bf8f7bdcfb..ced6c95cca5e 100644 --- a/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_requests_api.rb +++ b/modules/github_integration/lib/api/v3/github_pull_requests/github_pull_requests_api.rb @@ -31,7 +31,7 @@ module V3 module GithubPullRequests class GithubPullRequestsAPI < ::API::OpenProjectAPI resources :github_pull_requests do - route_param :id, type: Integer, desc: "Pull Request ID" do + route_param :id, type: Integer, desc: 'Pull Request ID' do after_validation do @pull_request = GithubPullRequest.find(declared_params[:id]) diff --git a/modules/github_integration/lib/api/v3/github_pull_requests/github_user_representer.rb b/modules/github_integration/lib/api/v3/github_pull_requests/github_user_representer.rb index 153eb7e15cc7..8adf219b7be3 100644 --- a/modules/github_integration/lib/api/v3/github_pull_requests/github_user_representer.rb +++ b/modules/github_integration/lib/api/v3/github_pull_requests/github_user_representer.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -43,7 +43,7 @@ class GithubUserRepresenter < ::API::Decorators::Single property :github_avatar_url, as: :avatarUrl def _type - "GithubUser" + 'GithubUser' end end end diff --git a/modules/github_integration/lib/open_project/github_integration/engine.rb b/modules/github_integration/lib/open_project/github_integration/engine.rb index 75950c7d335a..baede67326cb 100644 --- a/modules/github_integration/lib/open_project/github_integration/engine.rb +++ b/modules/github_integration/lib/open_project/github_integration/engine.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/plugins" -require_relative "patches/api/work_package_representer" +require 'open_project/plugins' +require_relative 'patches/api/work_package_representer' module OpenProject::GithubIntegration class Engine < ::Rails::Engine @@ -35,8 +35,8 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-github_integration", - author_url: "https://www.openproject.org/", + register 'openproject-github_integration', + author_url: 'https://www.openproject.org/', bundled: true do project_module(:github, dependencies: :work_package_tracking) do permission(:show_github_content, @@ -45,19 +45,19 @@ class Engine < ::Rails::Engine end end - initializer "github.register_hook" do - ::OpenProject::Webhooks.register_hook "github" do |hook, environment, params, user| + initializer 'github.register_hook' do + ::OpenProject::Webhooks.register_hook 'github' do |hook, environment, params, user| HookHandler.new.process(hook, environment, params, user) end end - initializer "github.subscribe_to_notifications" do |app| + initializer 'github.subscribe_to_notifications' do |app| app.config.after_initialize do - ::OpenProject::Notifications.subscribe("github.check_run", + ::OpenProject::Notifications.subscribe('github.check_run', &NotificationHandler.method(:check_run)) - ::OpenProject::Notifications.subscribe("github.issue_comment", + ::OpenProject::Notifications.subscribe('github.issue_comment', &NotificationHandler.method(:issue_comment)) - ::OpenProject::Notifications.subscribe("github.pull_request", + ::OpenProject::Notifications.subscribe('github.pull_request', &NotificationHandler.method(:pull_request)) end end @@ -77,21 +77,17 @@ class Engine < ::Rails::Engine "github_check_run/#{id}" end - add_api_endpoint "API::V3::WorkPackages::WorkPackagesAPI", :id do + add_api_endpoint 'API::V3::WorkPackages::WorkPackagesAPI', :id do mount ::API::V3::GithubPullRequests::GithubPullRequestsByWorkPackageAPI end - add_api_endpoint "API::V3::Root" do + add_api_endpoint 'API::V3::Root' do mount ::API::V3::GithubPullRequests::GithubPullRequestsAPI end - add_cron_jobs do - { - "Cron::ClearOldPullRequestsJob": { - cron: "25 1 * * *", # runs at 1:25 nightly - class: ::Cron::ClearOldPullRequestsJob.name - } - } + config.to_prepare do + # Register the cron job to clean up old github pull requests + ::Cron::CronJob.register! ::Cron::ClearOldPullRequestsJob end end end diff --git a/modules/github_integration/lib/open_project/github_integration/hook_handler.rb b/modules/github_integration/lib/open_project/github_integration/hook_handler.rb index 15e90a3efa52..4a70fbfd7315 100644 --- a/modules/github_integration/lib/open_project/github_integration/hook_handler.rb +++ b/modules/github_integration/lib/open_project/github_integration/hook_handler.rb @@ -40,8 +40,8 @@ class HookHandler # We need to check validity of the data and send a Notification # to be processed in our `NotificationHandler`. def process(_hook, request, params, user) - event_type = request.env["HTTP_X_GITHUB_EVENT"] - event_delivery = request.env["HTTP_X_GITHUB_DELIVERY"] + event_type = request.env['HTTP_X_GITHUB_EVENT'] + event_delivery = request.env['HTTP_X_GITHUB_DELIVERY'] Rails.logger.debug { "Received github webhook #{event_type} (#{event_delivery})" } @@ -51,9 +51,9 @@ def process(_hook, request, params, user) payload = params[:payload] .permit! .to_h - .merge("open_project_user_id" => user.id, - "github_event" => event_type, - "github_delivery" => event_delivery) + .merge('open_project_user_id' => user.id, + 'github_event' => event_type, + 'github_delivery' => event_delivery) event_name = "github.#{event_type}" OpenProject::Notifications.send(event_name, payload) diff --git a/modules/github_integration/lib/open_project/github_integration/notification_handler.rb b/modules/github_integration/lib/open_project/github_integration/notification_handler.rb index 6ad0941c0ca9..8efd1e5a51a3 100644 --- a/modules/github_integration/lib/open_project/github_integration/notification_handler.rb +++ b/modules/github_integration/lib/open_project/github_integration/notification_handler.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "notification_handler/helper" -require_relative "notification_handler/issue_comment" -require_relative "notification_handler/pull_request" +require_relative 'notification_handler/helper' +require_relative 'notification_handler/issue_comment' +require_relative 'notification_handler/pull_request' module OpenProject::GithubIntegration ## diff --git a/modules/github_integration/lib/open_project/github_integration/notification_handler/check_run.rb b/modules/github_integration/lib/open_project/github_integration/notification_handler/check_run.rb index 84c7fa546203..f1be1b910a81 100644 --- a/modules/github_integration/lib/open_project/github_integration/notification_handler/check_run.rb +++ b/modules/github_integration/lib/open_project/github_integration/notification_handler/check_run.rb @@ -58,7 +58,7 @@ def find_pull_request github_id = payload.check_run .pull_requests .first - .fetch("id") + .fetch('id') GithubPullRequest.find_by(github_id:) end end diff --git a/modules/github_integration/lib/open_project/github_integration/notification_handler/helper.rb b/modules/github_integration/lib/open_project/github_integration/notification_handler/helper.rb index 8f7a602e10a9..e0b75382136a 100644 --- a/modules/github_integration/lib/open_project/github_integration/notification_handler/helper.rb +++ b/modules/github_integration/lib/open_project/github_integration/notification_handler/helper.rb @@ -107,7 +107,7 @@ def to_h def method_missing(name, *args, &block) super unless args.empty? && block.nil? - value = if name.end_with?("?") + value = if name.end_with?('?') @payload.fetch(name.to_s[..-2], nil) else @payload.fetch(name.to_s) diff --git a/modules/github_integration/lib/open_project/github_integration/notification_handler/issue_comment.rb b/modules/github_integration/lib/open_project/github_integration/notification_handler/issue_comment.rb index 3fa198d16e17..19d4f0e8c4cf 100644 --- a/modules/github_integration/lib/open_project/github_integration/notification_handler/issue_comment.rb +++ b/modules/github_integration/lib/open_project/github_integration/notification_handler/issue_comment.rb @@ -83,11 +83,11 @@ def upsert_partial_pull_request(work_packages) def journal_entry(pull_request, payload) return unless COMMENT_ACTIONS.include?(payload.action) - angular_component_tag "macro", - class: "github_pull_request", + angular_component_tag 'macro', + class: 'github_pull_request', inputs: { pullRequestId: pull_request.id, - pullRequestState: "referenced" + pullRequestState: 'referenced' } end end diff --git a/modules/github_integration/lib/open_project/github_integration/notification_handler/pull_request.rb b/modules/github_integration/lib/open_project/github_integration/notification_handler/pull_request.rb index 2dcb25dc8f4b..efc162d3733e 100644 --- a/modules/github_integration/lib/open_project/github_integration/notification_handler/pull_request.rb +++ b/modules/github_integration/lib/open_project/github_integration/notification_handler/pull_request.rb @@ -63,7 +63,7 @@ def process(params) private def work_packages_to_comment_on(action, work_packages, already_referenced) - if action == "edited" + if action == 'edited' without_already_referenced(work_packages, already_referenced) else COMMENT_ACTIONS.include?(action) ? work_packages : [] @@ -85,8 +85,8 @@ def upsert_pull_request(payload, work_packages) end def journal_entry(pull_request, payload) - angular_component_tag "macro", - class: "github_pull_request", + angular_component_tag 'macro', + class: 'github_pull_request', inputs: { pullRequestId: pull_request.id, pullRequestState: pull_request_state(payload) @@ -95,16 +95,16 @@ def journal_entry(pull_request, payload) def pull_request_state(payload) key = { - "opened" => "opened", - "reopened" => "opened", - "closed" => "closed", - "edited" => "referenced", - "referenced" => "referenced", - "ready_for_review" => "ready_for_review" + 'opened' => 'opened', + 'reopened' => 'opened', + 'closed' => 'closed', + 'edited' => 'referenced', + 'referenced' => 'referenced', + 'ready_for_review' => 'ready_for_review' }[payload.action] - return "merged" if key == "closed" && payload.pull_request.merged - return "draft" if key == "open" && payload.pull_request.draft + return 'merged' if key == 'closed' && payload.pull_request.merged + return 'draft' if key == 'open' && payload.pull_request.draft key end diff --git a/modules/github_integration/lib/open_project/github_integration/services.rb b/modules/github_integration/lib/open_project/github_integration/services.rb index a0c6e6f31bc6..edecc0f94e13 100644 --- a/modules/github_integration/lib/open_project/github_integration/services.rb +++ b/modules/github_integration/lib/open_project/github_integration/services.rb @@ -26,6 +26,6 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "services/upsert_check_run" -require_relative "services/upsert_github_user" -require_relative "services/upsert_pull_request" +require_relative 'services/upsert_check_run' +require_relative 'services/upsert_github_user' +require_relative 'services/upsert_pull_request' diff --git a/modules/github_integration/lib/open_project/github_integration/services/upsert_check_run.rb b/modules/github_integration/lib/open_project/github_integration/services/upsert_check_run.rb index 3f4fa904a1ce..ed9365b6876e 100644 --- a/modules/github_integration/lib/open_project/github_integration/services/upsert_check_run.rb +++ b/modules/github_integration/lib/open_project/github_integration/services/upsert_check_run.rb @@ -36,7 +36,7 @@ module OpenProject::GithubIntegration::Services # See: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#check_run class UpsertCheckRun def call(payload, pull_request:) - GithubCheckRun.find_or_initialize_by(github_id: payload.fetch("id")) + GithubCheckRun.find_or_initialize_by(github_id: payload.fetch('id')) .tap do |check_run| check_run.update!(github_pull_request: pull_request, **extract_params(payload)) end @@ -48,23 +48,23 @@ def call(payload, pull_request:) # to our internal representation. # See: https://docs.github.com/en/rest/reference/checks def extract_params(payload) - output = payload.fetch("output") - app = payload.fetch("app") + output = payload.fetch('output') + app = payload.fetch('app') { - github_id: payload.fetch("id"), - github_html_url: payload.fetch("html_url"), - app_id: app.fetch("id"), - github_app_owner_avatar_url: app.fetch("owner") - .fetch("avatar_url"), - name: payload.fetch("name"), - status: payload.fetch("status"), - conclusion: payload["conclusion"], - output_title: output.fetch("title"), - output_summary: output.fetch("summary"), - details_url: payload["details_url"], - started_at: payload["started_at"], - completed_at: payload["completed_at"] + github_id: payload.fetch('id'), + github_html_url: payload.fetch('html_url'), + app_id: app.fetch('id'), + github_app_owner_avatar_url: app.fetch('owner') + .fetch('avatar_url'), + name: payload.fetch('name'), + status: payload.fetch('status'), + conclusion: payload['conclusion'], + output_title: output.fetch('title'), + output_summary: output.fetch('summary'), + details_url: payload['details_url'], + started_at: payload['started_at'], + completed_at: payload['completed_at'] } end end diff --git a/modules/github_integration/lib/open_project/github_integration/services/upsert_github_user.rb b/modules/github_integration/lib/open_project/github_integration/services/upsert_github_user.rb index e863a5936260..e473dc205091 100644 --- a/modules/github_integration/lib/open_project/github_integration/services/upsert_github_user.rb +++ b/modules/github_integration/lib/open_project/github_integration/services/upsert_github_user.rb @@ -36,7 +36,7 @@ module OpenProject::GithubIntegration::Services # See: https://docs.github.com/en/developers/webhooks-and-events/webhook-events-and-payloads#pull_request class UpsertGithubUser def call(payload) - GithubUser.find_or_initialize_by(github_id: payload.fetch("id")) + GithubUser.find_or_initialize_by(github_id: payload.fetch('id')) .tap do |github_user| github_user.update!(extract_params(payload)) end @@ -50,10 +50,10 @@ def call(payload) # See: https://docs.github.com/en/rest/reference/users def extract_params(payload) { - github_id: payload.fetch("id"), - github_login: payload.fetch("login"), - github_html_url: payload.fetch("html_url"), - github_avatar_url: payload.fetch("avatar_url") + github_id: payload.fetch('id'), + github_login: payload.fetch('login'), + github_html_url: payload.fetch('html_url'), + github_avatar_url: payload.fetch('avatar_url') } end end diff --git a/modules/github_integration/lib/open_project/github_integration/services/upsert_pull_request.rb b/modules/github_integration/lib/open_project/github_integration/services/upsert_pull_request.rb index 2ed0ea027f78..cca0d4d20277 100644 --- a/modules/github_integration/lib/open_project/github_integration/services/upsert_pull_request.rb +++ b/modules/github_integration/lib/open_project/github_integration/services/upsert_pull_request.rb @@ -44,8 +44,8 @@ def call(payload, work_packages: []) private def find_or_initialize(payload) - GithubPullRequest.find_by_github_identifiers(id: payload.fetch("id"), - url: payload.fetch("html_url"), + GithubPullRequest.find_by_github_identifiers(id: payload.fetch('id'), + url: payload.fetch('html_url'), initialize: true) end @@ -55,38 +55,38 @@ def find_or_initialize(payload) # rubocop:disable Metrics/AbcSize def extract_params(payload) { - github_id: payload.fetch("id"), - github_user: github_user_id(payload.fetch("user")), - number: payload.fetch("number"), - github_html_url: payload.fetch("html_url"), - github_updated_at: payload.fetch("updated_at"), - state: payload.fetch("state"), - title: payload.fetch("title"), - body: payload.fetch("body"), - repository: payload.fetch("base") - .fetch("repo") - .fetch("full_name"), - repository_html_url: payload.fetch("base") - .fetch("repo") - .fetch("html_url"), - draft: payload.fetch("draft"), - merged: payload.fetch("merged"), - merged_by: github_user_id(payload["merged_by"]), - merged_at: payload["merged_at"], - comments_count: payload.fetch("comments"), - review_comments_count: payload.fetch("review_comments"), - additions_count: payload.fetch("additions"), - deletions_count: payload.fetch("deletions"), - changed_files_count: payload.fetch("changed_files"), - labels: payload.fetch("labels").map { |values| extract_label_values(values) } + github_id: payload.fetch('id'), + github_user: github_user_id(payload.fetch('user')), + number: payload.fetch('number'), + github_html_url: payload.fetch('html_url'), + github_updated_at: payload.fetch('updated_at'), + state: payload.fetch('state'), + title: payload.fetch('title'), + body: payload.fetch('body'), + repository: payload.fetch('base') + .fetch('repo') + .fetch('full_name'), + repository_html_url: payload.fetch('base') + .fetch('repo') + .fetch('html_url'), + draft: payload.fetch('draft'), + merged: payload.fetch('merged'), + merged_by: github_user_id(payload['merged_by']), + merged_at: payload['merged_at'], + comments_count: payload.fetch('comments'), + review_comments_count: payload.fetch('review_comments'), + additions_count: payload.fetch('additions'), + deletions_count: payload.fetch('deletions'), + changed_files_count: payload.fetch('changed_files'), + labels: payload.fetch('labels').map { |values| extract_label_values(values) } } end # rubocop:enable Metrics/AbcSize def extract_label_values(payload) { - name: payload.fetch("name"), - color: payload.fetch("color") + name: payload.fetch('name'), + color: payload.fetch('color') } end diff --git a/modules/github_integration/lib/openproject-github_integration.rb b/modules/github_integration/lib/openproject-github_integration.rb index b04577a0bf17..21f70ed8aa7a 100644 --- a/modules/github_integration/lib/openproject-github_integration.rb +++ b/modules/github_integration/lib/openproject-github_integration.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/github_integration" +require 'open_project/github_integration' diff --git a/modules/github_integration/openproject-github_integration.gemspec b/modules/github_integration/openproject-github_integration.gemspec index d1b9590ddcdc..73f82bb1834a 100644 --- a/modules/github_integration/openproject-github_integration.gemspec +++ b/modules/github_integration/openproject-github_integration.gemspec @@ -1,15 +1,15 @@ Gem::Specification.new do |s| s.name = "openproject-github_integration" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" s.homepage = "https://www.openproject.org/docs/system-admin-guide/integrations/github-integration/" - s.summary = "OpenProject Github Integration" - s.description = "Integrates OpenProject and Github for a better workflow" - s.license = "GPLv3" + s.summary = 'OpenProject Github Integration' + s.description = 'Integrates OpenProject and Github for a better workflow' + s.license = 'GPLv3' s.files = Dir["{app,config,db,frontend,lib}/**/*"] + %w(README.md) s.add_dependency "openproject-webhooks" - s.metadata["rubygems_mfa_required"] = "true" + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/github_integration/spec/factories/github_check_run_factory.rb b/modules/github_integration/spec/factories/github_check_run_factory.rb index 144fa4696ab7..aa32b6d84494 100644 --- a/modules/github_integration/spec/factories/github_check_run_factory.rb +++ b/modules/github_integration/spec/factories/github_check_run_factory.rb @@ -33,12 +33,12 @@ sequence(:github_id) github_html_url { "https://github.com/check_runs/#{github_id}" } github_app_owner_avatar_url { "https://github.com/apps/#{github_id}/owner.jpg" } - name { "test" } + name { 'test' } app_id { 12345 } - status { "completed" } - conclusion { "success" } - output_title { "an output title" } - output_summary { "an output summary" } + status { 'completed' } + conclusion { 'success' } + output_title { 'an output title' } + output_summary { 'an output summary' } details_url { "https://github.com/check_runs/#{github_id}/details" } started_at { 1.hour.ago } completed_at { 1.minute.ago } diff --git a/modules/github_integration/spec/factories/github_pull_request_factory.rb b/modules/github_integration/spec/factories/github_pull_request_factory.rb index 8210467bc870..624f2a722137 100644 --- a/modules/github_integration/spec/factories/github_pull_request_factory.rb +++ b/modules/github_integration/spec/factories/github_pull_request_factory.rb @@ -32,7 +32,7 @@ sequence(:number) sequence(:github_id) - state { "open" } + state { 'open' } github_html_url { "https://github.com/test_user/test_repo/pull/#{number}" } labels { [] } @@ -77,11 +77,11 @@ trait :open trait :closed_unmerged do - state { "closed" } + state { 'closed' } end trait :closed_merged do - state { "closed" } + state { 'closed' } merged { true } merged_by { association :github_user } merged_at { Time.current } diff --git a/modules/github_integration/spec/features/work_package_activity_spec.rb b/modules/github_integration/spec/features/work_package_activity_spec.rb index 4110d1a79282..108889c1cdd0 100644 --- a/modules/github_integration/spec/features/work_package_activity_spec.rb +++ b/modules/github_integration/spec/features/work_package_activity_spec.rb @@ -1,19 +1,19 @@ # frozen_string_literal: true -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package Activity Tab", - "Comments by Github", +RSpec.describe 'Work Package Activity Tab', + 'Comments by Github', :js, :with_cuprite do - shared_let(:github_system_user) { create(:admin, firstname: "Github", lastname: "System User") } + shared_let(:github_system_user) { create(:admin, firstname: 'Github', lastname: 'System User') } shared_let(:admin) { create(:admin) } shared_let(:project) { create(:project, enabled_module_names: Setting.default_projects_modules + %w[activity]) } shared_let(:work_package) { create(:work_package, project:) } - shared_let(:pull_request_author) { create(:github_user, github_login: "i_am_the_author") } - shared_let(:pull_request_merging_user) { create(:github_user, github_login: "i_merged") } + shared_let(:pull_request_author) { create(:github_user, github_login: 'i_am_the_author') } + shared_let(:pull_request_merging_user) { create(:github_user, github_login: 'i_merged') } shared_let(:pull_request) do create(:github_pull_request, github_user: pull_request_author) @@ -28,42 +28,42 @@ def trigger_pull_request_action let(:payload) do { - "action" => action, - "open_project_user_id" => github_system_user.id, - "pull_request" => pull_request_hash, - "sender" => sender_section_hash + 'action' => action, + 'open_project_user_id' => github_system_user.id, + 'pull_request' => pull_request_hash, + 'sender' => sender_section_hash } end let(:pull_request_hash) do { - "id" => pull_request.id, - "number" => pull_request.number, - "body" => "Mentioning OP##{work_package.id}", - "title" => pull_request.title, - "html_url" => pull_request.github_html_url, - "updated_at" => Time.current.iso8601, - "state" => state, - "draft" => false, - "merged" => merged, - "merged_by" => merged_by_section_hash, - "merged_at" => merged_at, - "comments" => pull_request.comments_count + 1, - "review_comments" => pull_request.review_comments_count, - "additions" => pull_request.additions_count, - "deletions" => pull_request.deletions_count, - "changed_files" => pull_request.changed_files_count, - "labels" => pull_request.labels, - "user" => { - "id" => pull_request_author.github_id, - "login" => pull_request_author.github_login, - "html_url" => pull_request_author.github_html_url, - "avatar_url" => pull_request_author.github_avatar_url + 'id' => pull_request.id, + 'number' => pull_request.number, + 'body' => "Mentioning OP##{work_package.id}", + 'title' => pull_request.title, + 'html_url' => pull_request.github_html_url, + 'updated_at' => Time.current.iso8601, + 'state' => state, + 'draft' => false, + 'merged' => merged, + 'merged_by' => merged_by_section_hash, + 'merged_at' => merged_at, + 'comments' => pull_request.comments_count + 1, + 'review_comments' => pull_request.review_comments_count, + 'additions' => pull_request.additions_count, + 'deletions' => pull_request.deletions_count, + 'changed_files' => pull_request.changed_files_count, + 'labels' => pull_request.labels, + 'user' => { + 'id' => pull_request_author.github_id, + 'login' => pull_request_author.github_login, + 'html_url' => pull_request_author.github_html_url, + 'avatar_url' => pull_request_author.github_avatar_url }, - "base" => { - "repo" => { - "full_name" => "author_user/repo", - "html_url" => "github.com/author_user/repo" + 'base' => { + 'repo' => { + 'full_name' => 'author_user/repo', + 'html_url' => 'github.com/author_user/repo' } } } @@ -71,15 +71,15 @@ def trigger_pull_request_action let(:sender_section_hash) do { - "login" => "test_user", - "html_url" => "github.com/test_user" + 'login' => 'test_user', + 'html_url' => 'github.com/test_user' } end let(:work_package_page) { Pages::SplitWorkPackage.new(work_package, project) } - context "when the pull request is merged" do - let(:action) { "closed" } + context 'when the pull request is merged' do + let(:action) { 'closed' } before do trigger_pull_request_action @@ -90,21 +90,21 @@ def trigger_pull_request_action let(:merged) { true } let(:merged_by_section_hash) do { - "id" => pull_request_merging_user.github_id, - "login" => pull_request_merging_user.github_login, - "html_url" => pull_request_merging_user.github_html_url, - "avatar_url" => pull_request_merging_user.github_avatar_url + 'id' => pull_request_merging_user.github_id, + 'login' => pull_request_merging_user.github_login, + 'html_url' => pull_request_merging_user.github_html_url, + 'avatar_url' => pull_request_merging_user.github_avatar_url } end let(:merged_at) { Time.current.iso8601 } - let(:state) { "closed" } + let(:state) { 'closed' } before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded end - it "renders a comment stating the Pull Request was merged by the merge actor" do + it 'renders a comment stating the Pull Request was merged by the merge actor' do expected_merge_comment = <<~GITHUB_MERGE_COMMENT.squish Merged#{I18n.t('js.github_integration.pull_requests.merged_message', pr_number: pull_request.number, @@ -114,18 +114,18 @@ def trigger_pull_request_action github_user_link: pull_request_merging_user.github_login)} GITHUB_MERGE_COMMENT - expect(page).to have_css(".user-comment > .message", text: expected_merge_comment) + expect(page).to have_css('.user-comment > .message', text: expected_merge_comment) end end end - context "when the Work Package is referenced in a Pull Request" do - let(:action) { "referenced" } + context 'when the Work Package is referenced in a Pull Request' do + let(:action) { 'referenced' } let(:merged) { false } let(:merged_by_section_hash) { {} } let(:merged_at) { nil } - let(:state) { "open" } + let(:state) { 'open' } before do trigger_pull_request_action @@ -134,11 +134,11 @@ def trigger_pull_request_action context "and I visit the work package's activity tab" do before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded end - it "renders a comment stating the Work Package was referenced in the Pull Request" do + it 'renders a comment stating the Work Package was referenced in the Pull Request' do expected_referenced_comment = <<~GITHUB_REFERENCED_COMMENT.squish Referenced#{I18n.t('js.github_integration.pull_requests.referenced_message', pr_number: pull_request.number, @@ -148,18 +148,18 @@ def trigger_pull_request_action github_user_link: pull_request_author.github_login)} GITHUB_REFERENCED_COMMENT - expect(page).to have_css(".user-comment > .message", text: expected_referenced_comment) + expect(page).to have_css('.user-comment > .message', text: expected_referenced_comment) end end end - context "when any non-edge-case action is performed on a pull request" do - let(:action) { "ready_for_review" } + context 'when any non-edge-case action is performed on a pull request' do + let(:action) { 'ready_for_review' } let(:merged) { false } let(:merged_by_section_hash) { {} } let(:merged_at) { nil } - let(:state) { "open" } + let(:state) { 'open' } before do trigger_pull_request_action @@ -168,11 +168,11 @@ def trigger_pull_request_action context "and I visit the work package's activity tab" do before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded end - it "renders a comment stating that said action was performed on the Pull Request" do + it 'renders a comment stating that said action was performed on the Pull Request' do expected_action_comment = <<~GITHUB_READY_FOR_REVIEW_COMMENT.squish Marked Ready For Review#{I18n.t('js.github_integration.pull_requests.message', pr_number: pull_request.number, @@ -182,7 +182,7 @@ def trigger_pull_request_action github_user_link: pull_request_author.github_login)} GITHUB_READY_FOR_REVIEW_COMMENT - expect(page).to have_css(".user-comment > .message", text: expected_action_comment) + expect(page).to have_css('.user-comment > .message', text: expected_action_comment) end end end diff --git a/modules/github_integration/spec/features/work_package_github_tab_spec.rb b/modules/github_integration/spec/features/work_package_github_tab_spec.rb index 82b53eb47f58..d035f53baaab 100644 --- a/modules/github_integration/spec/features/work_package_github_tab_spec.rb +++ b/modules/github_integration/spec/features/work_package_github_tab_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/pages/work_package_github_tab" +require 'spec_helper' +require_relative '../support/pages/work_package_github_tab' -RSpec.describe "Open the GitHub tab", :js do +RSpec.describe 'Open the GitHub tab', :js do let(:user) do create(:user, member_with_roles: { project => role }) @@ -41,13 +41,13 @@ show_github_content)) end let(:project) { create(:project) } - let(:work_package) { create(:work_package, project:, subject: "A test work_package") } + let(:work_package) { create(:work_package, project:, subject: 'A test work_package') } let(:github_tab) { Pages::GitHubTab.new(work_package.id) } - let(:pull_request) { create(:github_pull_request, :open, work_packages: [work_package], title: "A Test PR title") } - let(:check_run) { create(:github_check_run, github_pull_request: pull_request, name: "a check run name") } + let(:pull_request) { create(:github_pull_request, :open, work_packages: [work_package], title: 'A Test PR title') } + let(:check_run) { create(:github_check_run, github_pull_request: pull_request, name: 'a check run name') } let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } - let(:github_tab_element) { find(".op-tab-row--link_selected", text: "GITHUB") } + let(:github_tab_element) { find('.op-tab-row--link_selected', text: 'GITHUB') } shared_examples_for "a github tab" do before do @@ -58,62 +58,62 @@ # compares the clipboard content by drafting a new comment, pressing ctrl+v and # comparing the pasted content against the provided text def expect_clipboard_content(text) - work_package_page.switch_to_tab(tab: "activity") + work_package_page.switch_to_tab(tab: 'activity') work_package_page.trigger_edit_comment - work_package_page.update_comment(" ") # ensure the comment editor is fully loaded + work_package_page.update_comment(' ') # ensure the comment editor is fully loaded github_tab.paste_clipboard_content expect(work_package_page.add_comment_container).to have_content(text) - work_package_page.switch_to_tab(tab: "github") + work_package_page.switch_to_tab(tab: 'github') end - it "shows the github tab when the user is allowed to see it" do + it 'shows the github tab when the user is allowed to see it' do work_package_page.visit! - work_package_page.switch_to_tab(tab: "github") + work_package_page.switch_to_tab(tab: 'github') tabs.expect_counter(github_tab_element, 1) github_tab.git_actions_menu_button.click github_tab.git_actions_copy_branch_name_button.click - expect(page).to have_text("Copied!") + expect(page).to have_text('Copied!') expect_clipboard_content("#{work_package.type.name.downcase}/#{work_package.id}-a-test-work_package") - expect(page).to have_text("A Test PR title") - expect(page).to have_text("a check run name") + expect(page).to have_text('A Test PR title') + expect(page).to have_text('a check run name') end - context "when there are no pull requests" do + context 'when there are no pull requests' do let(:check_run) {} let(:pull_request) {} - it "shows the github tab with an empty-pull-requests message" do + it 'shows the github tab with an empty-pull-requests message' do work_package_page.visit! - work_package_page.switch_to_tab(tab: "github") + work_package_page.switch_to_tab(tab: 'github') tabs.expect_no_counter(github_tab_element) - expect(page).to have_content("There are no pull requests") + expect(page).to have_content('There are no pull requests') expect(page).to have_content("Link an existing PR by using the code OP##{work_package.id}") end end - context "when the user does not have the permissions to see the github tab" do + context 'when the user does not have the permissions to see the github tab' do let(:role) do create(:project_role, permissions: %i(view_work_packages add_work_package_notes)) end - it "does not show the github tab" do + it 'does not show the github tab' do work_package_page.visit! github_tab.expect_tab_not_present end end - context "when the github integration is not enabled for the project" do - let(:project) { create(:project, disable_modules: "github") } + context 'when the github integration is not enabled for the project' do + let(:project) { create(:project, disable_modules: 'github') } - it "does not show the github tab" do + it 'does not show the github tab' do work_package_page.visit! github_tab.expect_tab_not_present @@ -121,15 +121,15 @@ def expect_clipboard_content(text) end end - describe "work package full view" do + describe 'work package full view' do let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "a github tab" + it_behaves_like 'a github tab' end - describe "work package split view" do + describe 'work package split view' do let(:work_package_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "a github tab" + it_behaves_like 'a github tab' end end diff --git a/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_check_run_representer_spec.rb b/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_check_run_representer_spec.rb index 4ba21ecc94d3..a72c8c67a1cd 100644 --- a/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_check_run_representer_spec.rb +++ b/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_check_run_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::GithubPullRequests::GithubCheckRunRepresenter do include API::V3::Utilities::PathHelper @@ -37,62 +37,62 @@ let(:representer) { described_class.create(check_run, current_user: user) } let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GithubCheckRun".to_json).at_path("_type") } + it { is_expected.to include_json('GithubCheckRun'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GithubCheckRun" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GithubCheckRun' } end - it_behaves_like "property", :htmlUrl do + it_behaves_like 'property', :htmlUrl do let(:value) { check_run.github_html_url } end - it_behaves_like "property", :appOwnerAvatarUrl do + it_behaves_like 'property', :appOwnerAvatarUrl do let(:value) { check_run.github_app_owner_avatar_url } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { check_run.name } end - it_behaves_like "property", :status do + it_behaves_like 'property', :status do let(:value) { check_run.status } end - it_behaves_like "property", :conclusion do + it_behaves_like 'property', :conclusion do let(:value) { check_run.conclusion } end - it_behaves_like "property", :outputTitle do + it_behaves_like 'property', :outputTitle do let(:value) { check_run.output_title } end - it_behaves_like "property", :outputSummary do + it_behaves_like 'property', :outputSummary do let(:value) { check_run.output_summary } end - it_behaves_like "property", :detailsUrl do + it_behaves_like 'property', :detailsUrl do let(:value) { check_run.details_url } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { check_run.started_at } - let(:json_path) { "startedAt" } + let(:json_path) { 'startedAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { check_run.completed_at } - let(:json_path) { "completedAt" } + let(:json_path) { 'completedAt' } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } - it { is_expected.to have_json_path("_links/self/href") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } + it { is_expected.to have_json_path('_links/self/href') } end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -105,22 +105,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GithubPullRequests", "GithubCheckRunRepresenter") + .to include('API', 'V3', 'GithubPullRequests', 'GithubCheckRunRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the check run is updated" do + it 'changes when the check run is updated' do check_run.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_pull_request_representer_spec.rb b/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_pull_request_representer_spec.rb index c704977f8480..0d2840056b78 100644 --- a/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_pull_request_representer_spec.rb +++ b/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_pull_request_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::GithubPullRequests::GithubPullRequestRepresenter do include API::V3::Utilities::PathHelper @@ -35,7 +35,7 @@ let(:github_pull_request) do build_stubbed(:github_pull_request, - state: "open", + state: 'open', labels:, github_user:, merged_by:).tap do |pr| @@ -47,8 +47,8 @@ let(:labels) do [ { - "name" => "grey", - "color" => "#666" + 'name' => 'grey', + 'color' => '#666' } ] end @@ -60,118 +60,118 @@ let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GithubPullRequest".to_json).at_path("_type") } + it { is_expected.to include_json('GithubPullRequest'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GithubPullRequest" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GithubPullRequest' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { github_pull_request.id } end - it_behaves_like "property", :number do + it_behaves_like 'property', :number do let(:value) { github_pull_request.number } end - it_behaves_like "property", :htmlUrl do + it_behaves_like 'property', :htmlUrl do let(:value) { github_pull_request.github_html_url } end - it_behaves_like "property", :state do + it_behaves_like 'property', :state do let(:value) { github_pull_request.state } end - it_behaves_like "property", :repository do + it_behaves_like 'property', :repository do let(:value) { github_pull_request.repository } end - it_behaves_like "property", :title do + it_behaves_like 'property', :title do let(:value) { github_pull_request.title } end - it_behaves_like "formattable property", :body do + it_behaves_like 'formattable property', :body do let(:value) { github_pull_request.body } end - it_behaves_like "property", :draft do + it_behaves_like 'property', :draft do let(:value) { github_pull_request.draft } end - it_behaves_like "property", :merged do + it_behaves_like 'property', :merged do let(:value) { github_pull_request.merged } end - it_behaves_like "property", :commentsCount do + it_behaves_like 'property', :commentsCount do let(:value) { github_pull_request.comments_count } end - it_behaves_like "property", :reviewCommentsCount do + it_behaves_like 'property', :reviewCommentsCount do let(:value) { github_pull_request.review_comments_count } end - it_behaves_like "property", :additionsCount do + it_behaves_like 'property', :additionsCount do let(:value) { github_pull_request.additions_count } end - it_behaves_like "property", :deletionsCount do + it_behaves_like 'property', :deletionsCount do let(:value) { github_pull_request.deletions_count } end - it_behaves_like "property", :changedFilesCount do + it_behaves_like 'property', :changedFilesCount do let(:value) { github_pull_request.changed_files_count } end - it_behaves_like "property", :labels do + it_behaves_like 'property', :labels do let(:value) { github_pull_request.labels } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { github_pull_request.github_updated_at } - let(:json_path) { "githubUpdatedAt" } + let(:json_path) { 'githubUpdatedAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { github_pull_request.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { github_pull_request.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - it_behaves_like "has a titled link" do - let(:link) { "githubUser" } + it_behaves_like 'has a titled link' do + let(:link) { 'githubUser' } let(:href) { api_v3_paths.github_user(github_user.id) } let(:title) { github_user.github_login } end - it_behaves_like "has a titled link" do - let(:link) { "mergedBy" } + it_behaves_like 'has a titled link' do + let(:link) { 'mergedBy' } let(:href) { api_v3_paths.github_user(merged_by.id) } let(:title) { merged_by.github_login } end - it_behaves_like "has a link collection" do - let(:link) { "checkRuns" } + it_behaves_like 'has a link collection' do + let(:link) { 'checkRuns' } let(:hrefs) do [ { - "href" => api_v3_paths.github_check_run(check_run.id), - "title" => check_run.name + 'href' => api_v3_paths.github_check_run(check_run.id), + 'title' => check_run.name } ] end end end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -184,36 +184,36 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GithubPullRequests", "GithubPullRequestRepresenter") + .to include('API', 'V3', 'GithubPullRequests', 'GithubPullRequestRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the github_pull_request is updated" do + it 'changes when the github_pull_request is updated' do github_pull_request.updated_at = 20.seconds.from_now expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the github_user is updated" do + it 'changes when the github_user is updated' do github_pull_request.github_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the merged_by user is updated" do + it 'changes when the merged_by user is updated' do github_pull_request.merged_by.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_user_representer_spec.rb b/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_user_representer_spec.rb index 40d5e23b328c..639d66b0dd7e 100644 --- a/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_user_representer_spec.rb +++ b/modules/github_integration/spec/lib/api/v3/github_pull_requests/github_user_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::GithubPullRequests::GithubUserRepresenter do include API::V3::Utilities::PathHelper @@ -38,32 +38,32 @@ let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GithubUser".to_json).at_path("_type") } + it { is_expected.to include_json('GithubUser'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GithubUser" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GithubUser' } end - it_behaves_like "property", :login do + it_behaves_like 'property', :login do let(:value) { github_user.github_login } end - it_behaves_like "property", :htmlUrl do + it_behaves_like 'property', :htmlUrl do let(:value) { github_user.github_html_url } end - it_behaves_like "property", :avatarUrl do + it_behaves_like 'property', :avatarUrl do let(:value) { github_user.github_avatar_url } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } - it { is_expected.to have_json_path("_links/self/href") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } + it { is_expected.to have_json_path('_links/self/href') } end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -76,22 +76,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GithubPullRequests", "GithubUserRepresenter") + .to include('API', 'V3', 'GithubPullRequests', 'GithubUserRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the github_user is updated" do + it 'changes when the github_user is updated' do github_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/github_integration/spec/lib/open_project/github_integration/hook_handler_integration_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/hook_handler_integration_spec.rb index 3373f1583085..109e0c5f0ee1 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/hook_handler_integration_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/hook_handler_integration_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../spec_helper", __dir__) +require File.expand_path('../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::HookHandler do subject(:process_webhook) do described_class.new .tap { journal_counts_before } - .process("github", OpenStruct.new(env: environment), ActionController::Parameters.new(payload), user) + .process('github', OpenStruct.new(env: environment), ActionController::Parameters.new(payload), user) .tap { [work_packages[0], work_packages[1], work_packages[2], work_packages[3]].map(&:reload) } end @@ -42,11 +42,11 @@ let(:environment) do { - "HTTP_X_GITHUB_EVENT" => event, - "HTTP_X_GITHUB_DELIVERY" => "test delivery" + 'HTTP_X_GITHUB_EVENT' => event, + 'HTTP_X_GITHUB_DELIVERY' => 'test delivery' } end - let(:host_name) { "example.net" } + let(:host_name) { 'example.net' } let(:user) { create(:user) } let(:role) do create(:project_role, @@ -62,21 +62,21 @@ let(:pr_merged) { false } let(:pr_draft) { false } - let(:pr_state) { "open" } + let(:pr_state) { 'open' } let(:pr_labels) { [] } - shared_examples_for "it does not comment on any work package" do + shared_examples_for 'it does not comment on any work package' do let(:created_journals) { journal_counts_after.sum - journal_counts_before.sum } - it "consumes the webhook without commenting on any work package" do + it 'consumes the webhook without commenting on any work package' do process_webhook expect(created_journals).to be 0 end end - shared_examples_for "it comments on the first work_package" do - it "comments only on the first work package" do + shared_examples_for 'it comments on the first work_package' do + it 'comments only on the first work package' do process_webhook expect(work_packages[0].journals.count).to be(journal_counts_before[0] + 1) @@ -88,8 +88,8 @@ end end - shared_examples_for "it does not create a pull request" do - it "creates no GithubPullRequest or GithubUser" do + shared_examples_for 'it does not create a pull request' do + it 'creates no GithubPullRequest or GithubUser' do expect { process_webhook }.to( change(GithubPullRequest, :count).by(0).and( change(GithubUser, :count).by(0) @@ -98,14 +98,14 @@ end end - shared_examples_for "it creates a pull request and github user" do - it "creates a GithubPullRequest and a GithubUser" do + shared_examples_for 'it creates a pull request and github user' do + it 'creates a GithubPullRequest and a GithubUser' do expect { process_webhook }.to(change(GithubPullRequest, :count).by(1).and(change(GithubUser, :count).by(1))) pull_request = GithubPullRequest.last github_user = GithubUser.last expect(pull_request).to have_attributes( - title: "A PR title", + title: 'A PR title', body: "A PR body mentioning OP##{work_packages[0].id}", merged: pr_merged, draft: pr_draft, @@ -117,21 +117,21 @@ comments_count: 22, review_comments_count: 33, changed_files_count: 12, - repository: "test_user/webhooks_playground", + repository: 'test_user/webhooks_playground', github_user_id: github_user.id ) expect(pull_request.work_packages).to eq [work_packages[0]] expect(github_user).to have_attributes( - github_login: "test_user", - github_html_url: "https://github.com/test_user", - github_avatar_url: "https://avatars.githubusercontent.com/u/206108?v=4" + github_login: 'test_user', + github_html_url: 'https://github.com/test_user', + github_avatar_url: 'https://avatars.githubusercontent.com/u/206108?v=4' ) end end - shared_examples_for "it creates a partial pull request" do - it "creates a partial GithubPullRequest" do + shared_examples_for 'it creates a partial pull request' do + it 'creates a partial GithubPullRequest' do expect { process_webhook }.to( change(GithubPullRequest, :count).by(1).and( change(GithubUser, :count).by(1) @@ -159,66 +159,66 @@ expect(pull_request.work_packages).to eq [work_packages[0]] expect(github_user).to have_attributes( - github_login: "test_user", - github_html_url: "https://github.com/test_user", - github_avatar_url: "https://avatars.githubusercontent.com/u/206108?v=4" + github_login: 'test_user', + github_html_url: 'https://github.com/test_user', + github_avatar_url: 'https://avatars.githubusercontent.com/u/206108?v=4' ) end end - context "when receiving a webhook for a pull_request event" do - let(:event) { "pull_request" } + context 'when receiving a webhook for a pull_request event' do + let(:event) { 'pull_request' } - context "when opened without mentioning any work package" do + context 'when opened without mentioning any work package' do let(:payload) do webhook_payload( - "pull_request", - "opened", - title: "A PR title", - body: "A PR body" + 'pull_request', + 'opened', + title: 'A PR title', + body: 'A PR body' ) end - it_behaves_like "it does not comment on any work package" - it_behaves_like "it does not create a pull request" + it_behaves_like 'it does not comment on any work package' + it_behaves_like 'it does not create a pull request' end - context "when opened and mentioning a work package in the PR title" do + context 'when opened and mentioning a work package in the PR title' do let(:payload) do webhook_payload( - "pull_request", - "opened", + 'pull_request', + 'opened', title: "A PR title mentioning OP##{work_packages[0].id}", - body: "A PR body" + body: 'A PR body' ) end let(:created_journals) { journal_counts_after.sum - journal_counts_before.sum } - it_behaves_like "it does not comment on any work package" - it_behaves_like "it does not create a pull request" + it_behaves_like 'it does not comment on any work package' + it_behaves_like 'it does not create a pull request' end - context "when opened and mentioning a work package using its code in the PR body" do + context 'when opened and mentioning a work package using its code in the PR body' do let(:payload) do webhook_payload( - "pull_request", - "opened", - title: "A PR title", + 'pull_request', + 'opened', + title: 'A PR title', body: "A PR body mentioning OP##{work_packages[0].id}" ) end let(:journal_entry) { / "value" } }) } + let(:hook) { 'fake hook' } + let(:params) { ActionController::Parameters.new({ payload: { 'fake' => 'value' } }) } let(:environment) do - { "HTTP_X_GITHUB_EVENT" => "pull_request", - "HTTP_X_GITHUB_DELIVERY" => "veryuniqueid" } + { 'HTTP_X_GITHUB_EVENT' => 'pull_request', + 'HTTP_X_GITHUB_DELIVERY' => 'veryuniqueid' } end let(:request) { OpenStruct.new(env: environment) } let(:user) do @@ -44,34 +44,34 @@ user end - context "with an unsupported event" do + context 'with an unsupported event' do let(:environment) do - { "HTTP_X_GITHUB_EVENT" => "X-unspupported", - "HTTP_X_GITHUB_DELIVERY" => "veryuniqueid2" } + { 'HTTP_X_GITHUB_EVENT' => 'X-unspupported', + 'HTTP_X_GITHUB_DELIVERY' => 'veryuniqueid2' } end - it "returns 404" do + it 'returns 404' do result = handler.process(hook, request, params, user) expect(result).to eq(404) end end - context "with a supported event and without user" do + context 'with a supported event and without user' do let(:user) { nil } - it "returns 403" do + it 'returns 403' do result = handler.process(hook, request, params, user) expect(result).to eq(403) end end - context "with a supported event and a user" do + context 'with a supported event and a user' do let(:expected_params) do { - "fake" => "value", - "open_project_user_id" => 12, - "github_event" => "pull_request", - "github_delivery" => "veryuniqueid" + 'fake' => 'value', + 'open_project_user_id' => 12, + 'github_event' => 'pull_request', + 'github_delivery' => 'veryuniqueid' } end @@ -79,12 +79,12 @@ allow(OpenProject::Notifications).to receive(:send) end - it "sends a notification with the correct contents" do + it 'sends a notification with the correct contents' do handler.process(hook, request, params, user) expect(OpenProject::Notifications).to have_received(:send).with("github.pull_request", expected_params) end - it "returns 200" do + it 'returns 200' do result = handler.process(hook, request, params, user) expect(result).to eq(200) end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/check_run_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/check_run_spec.rb index 91bbbdf84f66..2dcbf8f43503 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/check_run_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/check_run_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::NotificationHandler::CheckRun do subject(:process) { described_class.new.process(payload) } @@ -36,8 +36,8 @@ end let(:payload) do { - "check_run" => { - "pull_requests" => pull_requests_payload + 'check_run' => { + 'pull_requests' => pull_requests_payload } } end @@ -49,31 +49,31 @@ allow(upsert_check_run_service).to receive(:call).and_return(nil) end - it "does not call the UpsertCheckRun service when the check_run is not associated to a PR" do + it 'does not call the UpsertCheckRun service when the check_run is not associated to a PR' do process expect(upsert_check_run_service).not_to have_received(:call) end - context "when the check_run is not associated to a known GithubPullRequest" do + context 'when the check_run is not associated to a known GithubPullRequest' do let(:pull_requests_payload) do [ { - "id" => 123 + 'id' => 123 } ] end - it "does not call the UpsertCheckRun service" do + it 'does not call the UpsertCheckRun service' do process expect(upsert_check_run_service).not_to have_received(:call) end end - context "when the check_run is associated to a known GithubPullRequest" do + context 'when the check_run is associated to a known GithubPullRequest' do let(:pull_requests_payload) do [ { - "id" => 123 + 'id' => 123 } ] end @@ -81,10 +81,10 @@ before { github_pull_request } - it "does not call the UpsertCheckRun service" do + it 'does not call the UpsertCheckRun service' do process expect(upsert_check_run_service).to have_received(:call).with( - payload["check_run"], + payload['check_run'], pull_request: github_pull_request ) end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/helper_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/helper_spec.rb index 6cff504c4418..f15d26e1db91 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/helper_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/helper_spec.rb @@ -26,56 +26,56 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::NotificationHandler::Helper do subject(:handler) { Class.new.include(described_class).new } before do - allow(Setting).to receive(:host_name).and_return("example.net") + allow(Setting).to receive(:host_name).and_return('example.net') end - describe "#extract_work_package_ids" do - it "returns an empty array for an empty source" do - expect(handler.extract_work_package_ids("")).to eq([]) + describe '#extract_work_package_ids' do + it 'returns an empty array for an empty source' do + expect(handler.extract_work_package_ids('')).to eq([]) end - it "returns an empty array for a null source" do + it 'returns an empty array for a null source' do expect(handler.extract_work_package_ids(nil)).to eq([]) end - it "finds a work package by code" do + it 'finds a work package by code' do source = "Blabla\nOP#1234\n" expect(handler.extract_work_package_ids(source)).to eq([1234]) end - it "finds a plain work package url" do + it 'finds a plain work package url' do source = 'Blabla\nhttps://example.net/work_packages/234\n' expect(handler.extract_work_package_ids(source)).to eq([234]) end - it "finds a work package url in markdown link syntax" do + it 'finds a work package url in markdown link syntax' do source = 'Blabla\n[WP 234](https://example.net/work_packages/234)\n' expect(handler.extract_work_package_ids(source)).to eq([234]) end - it "finds multiple work package urls" do + it 'finds multiple work package urls' do source = "I reference https://example.net/work_packages/434\n and Blabla\n[WP 234](https://example.net/wp/234)\n" expect(handler.extract_work_package_ids(source)).to eq([434, 234]) end - it "finds multiple occurrences of a work package only once" do + it 'finds multiple occurrences of a work package only once' do source = "I reference https://example.net/work_packages/434\n and Blabla\n[WP 234](https://example.net/work_packages/434)\n" expect(handler.extract_work_package_ids(source)).to eq([434]) end end - describe "#find_visible_work_packages" do + describe '#find_visible_work_packages' do let(:user) { build_stubbed(:user) } let(:visible_wp) { instance_double(WorkPackage, project: :project_with_permissions) } let(:invisible_wp) { instance_double(WorkPackage, project: :project_without_permissions) } - shared_examples_for "it finds visible work packages" do + shared_examples_for 'it finds visible work packages' do subject(:find_visible_work_packages) { handler.find_visible_work_packages(ids, user) } before do @@ -87,41 +87,41 @@ end end - it "finds work packages visible to the user" do + it 'finds work packages visible to the user' do expect(find_visible_work_packages).to eql(expected) end end - describe "should find an existing work package" do + describe 'should find an existing work package' do let(:work_packages) { [visible_wp] } let(:ids) { [0] } let(:expected) { work_packages } - it_behaves_like "it finds visible work packages" + it_behaves_like 'it finds visible work packages' end - describe "should not find a non-existing work package" do + describe 'should not find a non-existing work package' do let(:work_packages) { [invisible_wp] } let(:ids) { [0] } let(:expected) { [] } - it_behaves_like "it finds visible work packages" + it_behaves_like 'it finds visible work packages' end - describe "should find multiple existing work packages" do + describe 'should find multiple existing work packages' do let(:work_packages) { [visible_wp, visible_wp] } let(:ids) { [0, 1] } let(:expected) { work_packages } - it_behaves_like "it finds visible work packages" + it_behaves_like 'it finds visible work packages' end - describe "should not find work package which the user shall not see" do + describe 'should not find work package which the user shall not see' do let(:work_packages) { [visible_wp, invisible_wp, visible_wp, invisible_wp] } let(:ids) { [0, 1, 2, 3] } let(:expected) { [visible_wp, visible_wp] } - it_behaves_like "it finds visible work packages" + it_behaves_like 'it finds visible work packages' end end end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/issue_comment_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/issue_comment_spec.rb index 5c778c424e75..c37347687531 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/issue_comment_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/issue_comment_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::NotificationHandler::IssueComment do subject(:process) { handler_instance.process(payload) } @@ -37,40 +37,40 @@ end let(:payload) do { - "action" => action, - "comment" => { - "body" => comment_body, - "html_url" => "https://comment.url", - "user" => { - "login" => "test_user", - "html_url" => "https://github.com/test_user" + 'action' => action, + 'comment' => { + 'body' => comment_body, + 'html_url' => 'https://comment.url', + 'user' => { + 'login' => 'test_user', + 'html_url' => 'https://github.com/test_user' } }, - "issue" => { - "state" => "open", - "number" => pr_number, - "title" => "PR or issue title", - "updated_at" => Time.current.iso8601, - "pull_request" => pr_payload, - "user" => { - "id" => 345, - "login" => "test_user", - "html_url" => "https://github.com/test_user", - "avatar_url" => "https://github.com/test_user.jpg" + 'issue' => { + 'state' => 'open', + 'number' => pr_number, + 'title' => 'PR or issue title', + 'updated_at' => Time.current.iso8601, + 'pull_request' => pr_payload, + 'user' => { + 'id' => 345, + 'login' => 'test_user', + 'html_url' => 'https://github.com/test_user', + 'avatar_url' => 'https://github.com/test_user.jpg' } }, - "repository" => { - "full_name" => repo_full_name, - "html_url" => "https://github.com/test_user/repo" + 'repository' => { + 'full_name' => repo_full_name, + 'html_url' => 'https://github.com/test_user/repo' }, - "open_project_user_id" => github_system_user.id + 'open_project_user_id' => github_system_user.id } end let(:comment_body) { "a comment about OP##{work_package.id}" } - let(:pr_payload) { { "html_url" => pr_html_url } } - let(:pr_html_url) { "https://github.com/test_user/repo/pull/123" } + let(:pr_payload) { { 'html_url' => pr_html_url } } + let(:pr_html_url) { 'https://github.com/test_user/repo/pull/123' } let(:pr_number) { 123 } - let(:repo_full_name) { "test_user/repo" } + let(:repo_full_name) { 'test_user/repo' } let(:github_system_user) { create(:admin) } let(:work_package) { create(:work_package) } let(:github_pull_request) { GithubPullRequest.find_by(github_html_url: pr_html_url) } @@ -87,8 +87,8 @@ .and_call_original end - shared_examples_for "upserting a GithubPullRequest" do - it "calls the UpsertPartialPullRequest service" do + shared_examples_for 'upserting a GithubPullRequest' do + it 'calls the UpsertPartialPullRequest service' do process expect(upsert_partial_pull_request_service) .to have_received(:call) do |received_payload, work_packages:| @@ -100,15 +100,15 @@ end end - shared_examples_for "not upserting a GithubPullRequest" do - it "does not call the UpsertPartialPullRequest service" do + shared_examples_for 'not upserting a GithubPullRequest' do + it 'does not call the UpsertPartialPullRequest service' do process expect(upsert_partial_pull_request_service).not_to have_received(:call) end end - shared_examples_for "creating a comment on the work package" do - it "adds a comment to work packages" do + shared_examples_for 'creating a comment on the work package' do + it 'adds a comment to work packages' do process expect(handler_instance) .to have_received(:comment_on_referenced_work_packages) @@ -116,97 +116,97 @@ end end - shared_examples_for "not creating comments on work packages" do - it "does not add comments to work packages" do + shared_examples_for 'not creating comments on work packages' do + it 'does not add comments to work packages' do process expect(handler_instance).not_to have_received(:comment_on_referenced_work_packages) end end - context "when a comment was created" do - let(:action) { "created" } + context 'when a comment was created' do + let(:action) { 'created' } - context "when commented on an issue" do + context 'when commented on an issue' do let(:pr_payload) { nil } - it_behaves_like "not creating comments on work packages" - it_behaves_like "not upserting a GithubPullRequest" + it_behaves_like 'not creating comments on work packages' + it_behaves_like 'not upserting a GithubPullRequest' end - context "when commented on a PR" do + context 'when commented on a PR' do let(:comment) do %().squish end - it_behaves_like "creating a comment on the work package" - it_behaves_like "upserting a GithubPullRequest" + it_behaves_like 'creating a comment on the work package' + it_behaves_like 'upserting a GithubPullRequest' end - context "when we already have a GithubPullRequest for the commented PR" do + context 'when we already have a GithubPullRequest for the commented PR' do let!(:github_pull_request) { create(:github_pull_request, github_html_url: pr_html_url) } let(:comment) do %().squish end - it_behaves_like "creating a comment on the work package" - it_behaves_like "upserting a GithubPullRequest" + it_behaves_like 'creating a comment on the work package' + it_behaves_like 'upserting a GithubPullRequest' end - context "when we already have a GithubPullRequest with that work_package" do + context 'when we already have a GithubPullRequest with that work_package' do let!(:github_pull_request) do create(:github_pull_request, github_html_url: pr_html_url, work_packages: [work_package]) end - it_behaves_like "not creating comments on work packages" + it_behaves_like 'not creating comments on work packages' - it "calls the UpsertPartialPullRequest service without adding already known work_packages" do + it 'calls the UpsertPartialPullRequest service without adding already known work_packages' do process expect(upsert_partial_pull_request_service).not_to have_received(:call) end end end - context "when a comment was edited" do - let(:action) { "edited" } + context 'when a comment was edited' do + let(:action) { 'edited' } - context "when editing an issue comment" do + context 'when editing an issue comment' do let(:pr_payload) { nil } - it_behaves_like "not creating comments on work packages" - it_behaves_like "not upserting a GithubPullRequest" + it_behaves_like 'not creating comments on work packages' + it_behaves_like 'not upserting a GithubPullRequest' end - context "when editing a PR comment with a new work package reference" do + context 'when editing a PR comment with a new work package reference' do let(:comment) do %().squish end - it_behaves_like "creating a comment on the work package" - it_behaves_like "upserting a GithubPullRequest" + it_behaves_like 'creating a comment on the work package' + it_behaves_like 'upserting a GithubPullRequest' end - context "when we already have a GithubPullRequest for the commented PR" do + context 'when we already have a GithubPullRequest for the commented PR' do let!(:github_pull_request) { create(:github_pull_request, github_html_url: pr_html_url) } let(:comment) do %().squish end - it_behaves_like "creating a comment on the work package" - it_behaves_like "upserting a GithubPullRequest" + it_behaves_like 'creating a comment on the work package' + it_behaves_like 'upserting a GithubPullRequest' end - context "when we already have a GithubPullRequest with that work_package" do + context 'when we already have a GithubPullRequest with that work_package' do let!(:github_pull_request) do create(:github_pull_request, github_html_url: pr_html_url, work_packages: [work_package]) end - it_behaves_like "not creating comments on work packages" + it_behaves_like 'not creating comments on work packages' - it "calls the UpsertPartialPullRequest service without adding already known work_packages" do + it 'calls the UpsertPartialPullRequest service without adding already known work_packages' do process expect(upsert_partial_pull_request_service) .not_to have_received(:call) diff --git a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/pull_request_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/pull_request_spec.rb index 289fad06664b..ec04497a1715 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/pull_request_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler/pull_request_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::NotificationHandler::PullRequest do subject(:process) { handler_instance.process(payload) } @@ -37,42 +37,42 @@ let(:payload) do { - "action" => action, - "open_project_user_id" => github_system_user.id, - "pull_request" => { - "id" => 123, - "number" => 1, - "body" => pr_body, - "title" => "A PR title", - "html_url" => "http://pr.url", - "updated_at" => Time.current.iso8601, - "state" => "open", - "draft" => pr_draft, - "merged" => pr_merged, - "merged_by" => nil, - "merged_at" => nil, - "comments" => 1, - "review_comments" => 2, - "additions" => 3, - "deletions" => 4, - "changed_files" => 5, - "labels" => [], - "user" => { - "id" => 345, - "login" => "test_user", - "html_url" => "https://github.com/test_user", - "avatar_url" => "https://github.com/test_user.jpg" + 'action' => action, + 'open_project_user_id' => github_system_user.id, + 'pull_request' => { + 'id' => 123, + 'number' => 1, + 'body' => pr_body, + 'title' => 'A PR title', + 'html_url' => 'http://pr.url', + 'updated_at' => Time.current.iso8601, + 'state' => 'open', + 'draft' => pr_draft, + 'merged' => pr_merged, + 'merged_by' => nil, + 'merged_at' => nil, + 'comments' => 1, + 'review_comments' => 2, + 'additions' => 3, + 'deletions' => 4, + 'changed_files' => 5, + 'labels' => [], + 'user' => { + 'id' => 345, + 'login' => 'test_user', + 'html_url' => 'https://github.com/test_user', + 'avatar_url' => 'https://github.com/test_user.jpg' }, - "base" => { - "repo" => { - "full_name" => "test_user/repo", - "html_url" => "github.com/test_user/repo" + 'base' => { + 'repo' => { + 'full_name' => 'test_user/repo', + 'html_url' => 'github.com/test_user/repo' } } }, - "sender" => { - "login" => "test_user", - "html_url" => "github.com/test_user" + 'sender' => { + 'login' => 'test_user', + 'html_url' => 'github.com/test_user' } } end @@ -88,8 +88,8 @@ allow(upsert_service).to receive(:call).and_call_original end - shared_examples_for "not adding a comment" do - it "does not add comments to work packages" do + shared_examples_for 'not adding a comment' do + it 'does not add comments to work packages' do process expect(handler_instance).to have_received(:comment_on_referenced_work_packages).with( [], @@ -99,8 +99,8 @@ end end - shared_examples_for "adding a comment" do - it "adds a comment to the work packages" do + shared_examples_for 'adding a comment' do + it 'adds a comment to the work packages' do process expect(handler_instance).to have_received(:comment_on_referenced_work_packages).with( [work_package], @@ -110,101 +110,101 @@ end end - shared_examples_for "calls the pull request upsert service" do - it "calls the pull request upsert service" do + shared_examples_for 'calls the pull request upsert service' do + it 'calls the pull request upsert service' do process - expect(upsert_service).to have_received(:call).with(payload["pull_request"], work_packages: [work_package]) + expect(upsert_service).to have_received(:call).with(payload['pull_request'], work_packages: [work_package]) end - context "when no work_package was mentioned" do - let(:pr_body) { "some text that does not mention any work package" } + context 'when no work_package was mentioned' do + let(:pr_body) { 'some text that does not mention any work package' } - it "does not call the pull request upsert service" do + it 'does not call the pull request upsert service' do process expect(upsert_service).not_to have_received(:call) end end end - context "with a closed action" do - let(:action) { "closed" } + context 'with a closed action' do + let(:action) { 'closed' } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with a closed action when the PR was merged" do - let(:action) { "closed" } + context 'with a closed action when the PR was merged' do + let(:action) { 'closed' } let(:pr_merged) { true } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' - context "when the work package is already known to the GithubPullRequest" do + context 'when the work package is already known to the GithubPullRequest' do let!(:github_pull_request) { create(:github_pull_request, github_id: 123, work_packages: [work_package]) } - it_behaves_like "adding a comment" + it_behaves_like 'adding a comment' - it "calls the pull request upsert service" do + it 'calls the pull request upsert service' do process - expect(upsert_service).to have_received(:call).with(payload["pull_request"], work_packages: [work_package]) + expect(upsert_service).to have_received(:call).with(payload['pull_request'], work_packages: [work_package]) end end end - context "with a converted_to_draft action" do - let(:action) { "converted_to_draft" } + context 'with a converted_to_draft action' do + let(:action) { 'converted_to_draft' } - it_behaves_like "not adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'not adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with an edited action" do - let(:action) { "edited" } + context 'with an edited action' do + let(:action) { 'edited' } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' - context "when a GithubPullRequest exists that is not linked to the mentioned work package yet" do + context 'when a GithubPullRequest exists that is not linked to the mentioned work package yet' do let!(:github_pull_request) { create(:github_pull_request, github_id: 123) } - it_behaves_like "adding a comment" + it_behaves_like 'adding a comment' - it "calls the pull request upsert service" do + it 'calls the pull request upsert service' do process - expect(upsert_service).to have_received(:call).with(payload["pull_request"], work_packages: [work_package]) + expect(upsert_service).to have_received(:call).with(payload['pull_request'], work_packages: [work_package]) end end - context "when the work package is already known to the GithubPullRequest" do + context 'when the work package is already known to the GithubPullRequest' do let!(:github_pull_request) { create(:github_pull_request, github_id: 123, work_packages: [work_package]) } - it_behaves_like "not adding a comment" + it_behaves_like 'not adding a comment' - it "calls the pull request upsert service" do + it 'calls the pull request upsert service' do process - expect(upsert_service).to have_received(:call).with(payload["pull_request"], work_packages: [work_package]) + expect(upsert_service).to have_received(:call).with(payload['pull_request'], work_packages: [work_package]) end end - context "when the a work package is already known to the GithubPullRequest but another work package is new" do + context 'when the a work package is already known to the GithubPullRequest but another work package is new' do let!(:github_pull_request) { create(:github_pull_request, github_id: 123, work_packages: [work_package]) } let!(:other_work_package) { create(:work_package) } let(:pr_body) { "Mentioning OP##{work_package.id} and OP##{other_work_package.id}" } - it "adds a comment only for the other_work_package" do + it 'adds a comment only for the other_work_package' do process expect(handler_instance).to have_received(:comment_on_referenced_work_packages).with( [other_work_package], @@ -213,70 +213,70 @@ ) end - it "calls the pull request upsert service with all work_packages" do + it 'calls the pull request upsert service with all work_packages' do process - expect(upsert_service).to have_received(:call).with(payload["pull_request"], + expect(upsert_service).to have_received(:call).with(payload['pull_request'], work_packages: [work_package, other_work_package]) end end end - context "with a labeled action" do - let(:action) { "labeled" } + context 'with a labeled action' do + let(:action) { 'labeled' } - it_behaves_like "not adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'not adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with an opened action" do - let(:action) { "opened" } + context 'with an opened action' do + let(:action) { 'opened' } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with an opened action when the PR is a draft" do - let(:action) { "opened" } + context 'with an opened action when the PR is a draft' do + let(:action) { 'opened' } let(:pr_draft) { true } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with a ready_for_review action" do - let(:action) { "ready_for_review" } + context 'with a ready_for_review action' do + let(:action) { 'ready_for_review' } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with a reopened action" do - let(:action) { "reopened" } + context 'with a reopened action' do + let(:action) { 'reopened' } let(:comment) do %().squish end - it_behaves_like "adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the pull request upsert service' end - context "with a synchronize action" do - let(:action) { "synchronize" } + context 'with a synchronize action' do + let(:action) { 'synchronize' } - it_behaves_like "not adding a comment" - it_behaves_like "calls the pull request upsert service" + it_behaves_like 'not adding a comment' + it_behaves_like 'calls the pull request upsert service' end end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler_spec.rb index 6a50893a4c1c..d84ddb1104ff 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/notification_handler_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/notification_handler_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../spec_helper", __dir__) +require File.expand_path('../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::NotificationHandler do let(:payload) { {} } - shared_examples_for "a notification handler" do + shared_examples_for 'a notification handler' do let(:handler) { instance_double(handler_class) } before do @@ -39,45 +39,45 @@ allow(handler).to receive(:process).and_return(nil) end - it "forwards the payload to a new handler instance" do + it 'forwards the payload to a new handler instance' do process expect(handler).to have_received(:process).with(payload) end - context "when the handler throws an error" do + context 'when the handler throws an error' do before do allow(handler).to receive(:process).and_raise("oops") allow(Rails.logger).to receive(:error) end - it "logs the error message" do + it 'logs the error message' do expect { process }.to raise_error("oops") expect(Rails.logger).to have_received(:error) end end end - describe ".check_run" do + describe '.check_run' do subject(:process) { described_class.check_run(payload) } let(:handler_class) { described_class::CheckRun } - it_behaves_like "a notification handler" + it_behaves_like 'a notification handler' end - describe ".issue_comment" do + describe '.issue_comment' do subject(:process) { described_class.issue_comment(payload) } let(:handler_class) { described_class::IssueComment } - it_behaves_like "a notification handler" + it_behaves_like 'a notification handler' end - describe ".pull_request" do + describe '.pull_request' do subject(:process) { described_class.pull_request(payload) } let(:handler_class) { described_class::PullRequest } - it_behaves_like "a notification handler" + it_behaves_like 'a notification handler' end end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_check_run_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_check_run_spec.rb index 5ddab3219948..c3d48dafaa03 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_check_run_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_check_run_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::Services::UpsertCheckRun do subject(:upsert) { described_class.new.call(params, pull_request: github_pull_request) } @@ -34,50 +34,50 @@ let(:github_pull_request) { create(:github_pull_request) } let(:params) do { - "id" => 123, - "html_url" => "https://github.com/check_runs/123", - "name" => "test", - "status" => "completed", - "conclusion" => "success", - "details_url" => "https://github.com/details", - "started_at" => 1.hour.ago.iso8601, - "completed_at" => 1.minute.ago.iso8601, - "output" => { - "title" => "a title", - "summary" => "a summary" + 'id' => 123, + 'html_url' => 'https://github.com/check_runs/123', + 'name' => 'test', + 'status' => 'completed', + 'conclusion' => 'success', + 'details_url' => 'https://github.com/details', + 'started_at' => 1.hour.ago.iso8601, + 'completed_at' => 1.minute.ago.iso8601, + 'output' => { + 'title' => 'a title', + 'summary' => 'a summary' }, - "app" => { - "id" => 456, - "owner" => { - "avatar_url" => "https:://github.com/apps/456/avatar.png" + 'app' => { + 'id' => 456, + 'owner' => { + 'avatar_url' => 'https:://github.com/apps/456/avatar.png' } } } end - it "creates a new check run for the given pull request" do + it 'creates a new check run for the given pull request' do expect { upsert }.to change(GithubCheckRun, :count).by(1) expect(GithubCheckRun.last).to have_attributes( github_id: 123, - github_html_url: "https://github.com/check_runs/123", + github_html_url: 'https://github.com/check_runs/123', app_id: 456, - github_app_owner_avatar_url: "https:://github.com/apps/456/avatar.png", - name: "test", - status: "completed", - conclusion: "success", - output_title: "a title", - output_summary: "a summary", - details_url: "https://github.com/details", + github_app_owner_avatar_url: 'https:://github.com/apps/456/avatar.png', + name: 'test', + status: 'completed', + conclusion: 'success', + output_title: 'a title', + output_summary: 'a summary', + details_url: 'https://github.com/details', github_pull_request: ) end - context "when a check run with that id already exists" do - let(:check_run) { create(:github_check_run, github_id: 123, status: "queued") } + context 'when a check run with that id already exists' do + let(:check_run) { create(:github_check_run, github_id: 123, status: 'queued') } - it "updates the check run" do - expect { upsert }.to change { check_run.reload.status }.from("queued").to("completed") + it 'updates the check run' do + expect { upsert }.to change { check_run.reload.status }.from('queued').to('completed') end end end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_github_user_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_github_user_spec.rb index e6c1d2afd987..d7111f9fcf53 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_github_user_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_github_user_spec.rb @@ -26,38 +26,38 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::Services::UpsertGithubUser do subject(:upsert) { described_class.new.call(params) } let(:params) do { - "id" => 123, - "login" => "test_user", - "html_url" => "https://github.com/test_user", - "avatar_url" => "https://github.com/test_user/avatar.jpg" + 'id' => 123, + 'login' => 'test_user', + 'html_url' => 'https://github.com/test_user', + 'avatar_url' => 'https://github.com/test_user/avatar.jpg' } end - it "creates a new github user" do + it 'creates a new github user' do expect { upsert }.to change(GithubUser, :count).by(1) expect(GithubUser.last).to have_attributes( github_id: 123, - github_login: "test_user", - github_html_url: "https://github.com/test_user", - github_avatar_url: "https://github.com/test_user/avatar.jpg" + github_login: 'test_user', + github_html_url: 'https://github.com/test_user', + github_avatar_url: 'https://github.com/test_user/avatar.jpg' ) end - context "when a github user with that id already exists" do + context 'when a github user with that id already exists' do let(:github_user) do - create(:github_user, github_id: 123, github_avatar_url: "https://github.com/test_user/old_avatar.jpg") + create(:github_user, github_id: 123, github_avatar_url: 'https://github.com/test_user/old_avatar.jpg') end - it "updates the github user" do - expect { upsert }.to change { github_user.reload.github_avatar_url }.from("https://github.com/test_user/old_avatar.jpg").to("https://github.com/test_user/avatar.jpg") + it 'updates the github user' do + expect { upsert }.to change { github_user.reload.github_avatar_url }.from('https://github.com/test_user/old_avatar.jpg').to('https://github.com/test_user/avatar.jpg') end end end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_partial_pull_request_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_partial_pull_request_spec.rb index bdf495e5867e..4fcfb9ddfbd6 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_partial_pull_request_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_partial_pull_request_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::Services::UpsertPartialPullRequest do subject(:upsert) do @@ -49,11 +49,11 @@ { "issue" => { "number" => 23, - "title" => "Some title", + "title" => 'Some title', "updated_at" => "2021-04-06T15:16:03Z", - "state" => "closed", + "state" => 'closed', "pull_request" => { - "html_url" => "https://github.com/pulls/1" + "html_url" => 'https://github.com/pulls/1' }, "user" => { "login" => "test_user", @@ -62,61 +62,61 @@ } }, "repository" => { - "full_name" => "test_user/repo" + "full_name" => 'test_user/repo' } } end let(:work_packages) { create_list(:work_package, 1) } - it "creates a new github pull request" do + it 'creates a new github pull request' do expect { upsert }.to change(GithubPullRequest, :count).by(1) expect(GithubPullRequest.last).to have_attributes( github_id: nil, - state: "closed", + state: 'closed', number: 23, - title: "Some title", - github_html_url: "https://github.com/pulls/1", + title: 'Some title', + github_html_url: 'https://github.com/pulls/1', github_updated_at: DateTime.parse("2021-04-06T15:16:03Z"), github_user_id: 12345, - repository: "test_user/repo", + repository: 'test_user/repo', work_packages: ) end - context "when a github pull request with that html_url already exists" do + context 'when a github pull request with that html_url already exists' do let(:github_pull_request) do create(:github_pull_request, - github_html_url: "https://github.com/pulls/1") + github_html_url: 'https://github.com/pulls/1') end - it "updates the github pull request" do + it 'updates the github pull request' do expect { upsert }.to change { github_pull_request.reload.work_packages }.from([]).to(work_packages) end end - context "when a github pull request with that html_url and work_package exists" do + context 'when a github pull request with that html_url and work_package exists' do let(:github_pull_request) do create(:github_pull_request, - github_html_url: "https://github.com/pulls/1", + github_html_url: 'https://github.com/pulls/1', work_packages:) end - it "does not change the associated work packages" do + it 'does not change the associated work packages' do expect { upsert }.not_to(change { github_pull_request.reload.work_packages.to_a }) end end - context "when a github pull request with that html_url and work_package exists and a new work_package is referenced" do + context 'when a github pull request with that html_url and work_package exists and a new work_package is referenced' do let(:github_pull_request) do create(:github_pull_request, - github_html_url: "https://github.com/pulls/1", + github_html_url: 'https://github.com/pulls/1', work_packages: already_known_work_packages) end let(:work_packages) { create_list(:work_package, 2) } let(:already_known_work_packages) { [work_packages[0]] } - it "adds the new work package" do + it 'adds the new work package' do expect { upsert } .to change { github_pull_request.reload.work_packages } .from(already_known_work_packages) @@ -124,19 +124,19 @@ end end - context "when an open github pull request with that html_url and work_package exists and a new work_package is referenced" do + context 'when an open github pull request with that html_url and work_package exists and a new work_package is referenced' do let(:github_pull_request) do create(:github_pull_request, - github_html_url: "https://github.com/pulls/1", - repository: "some_user/a_repository", - state: "open", + github_html_url: 'https://github.com/pulls/1', + repository: 'some_user/a_repository', + state: 'open', github_id: 1, work_packages: already_known_work_packages) end let(:work_packages) { create_list(:work_package, 2) } let(:already_known_work_packages) { [work_packages[0]] } - it "adds the new work package and updates attributes" do + it 'adds the new work package and updates attributes' do expect { upsert } .to change { github_pull_request.reload.work_packages } .from(already_known_work_packages) @@ -144,13 +144,13 @@ expect(github_pull_request).to have_attributes( github_id: 1, - state: "closed", + state: 'closed', number: 23, - title: "Some title", + title: 'Some title', github_user_id: 12345, - github_html_url: "https://github.com/pulls/1", + github_html_url: 'https://github.com/pulls/1', github_updated_at: DateTime.parse("2021-04-06T15:16:03Z"), - repository: "test_user/repo" + repository: 'test_user/repo' ) end end diff --git a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_pull_request_spec.rb b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_pull_request_spec.rb index afc97f1b655c..2c6afed38fa3 100644 --- a/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_pull_request_spec.rb +++ b/modules/github_integration/spec/lib/open_project/github_integration/services/upsert_pull_request_spec.rb @@ -26,52 +26,52 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../../../../spec_helper", __dir__) +require File.expand_path('../../../../spec_helper', __dir__) RSpec.describe OpenProject::GithubIntegration::Services::UpsertPullRequest do subject(:upsert) { described_class.new.call(params, work_packages:) } let(:params) do { - "id" => 123, - "number" => 5, - "html_url" => "https://github.com/test_user/repo", - "updated_at" => "20210409T12:13:14Z", - "state" => pr_state, - "title" => "The PR title", - "body" => "The PR body", - "draft" => false, - "comments" => 12, - "review_comments" => 13, - "additions" => 14, - "deletions" => 15, - "changed_files" => 16, - "labels" => labels_payload, - "base" => { - "repo" => { - "full_name" => "test_user/repo", - "html_url" => "https://github.com/test_user/repo" + 'id' => 123, + 'number' => 5, + 'html_url' => 'https://github.com/test_user/repo', + 'updated_at' => '20210409T12:13:14Z', + 'state' => pr_state, + 'title' => 'The PR title', + 'body' => 'The PR body', + 'draft' => false, + 'comments' => 12, + 'review_comments' => 13, + 'additions' => 14, + 'deletions' => 15, + 'changed_files' => 16, + 'labels' => labels_payload, + 'base' => { + 'repo' => { + 'full_name' => 'test_user/repo', + 'html_url' => 'https://github.com/test_user/repo' } }, - "user" => user_payload, + 'user' => user_payload, **merged_payload } end let(:labels_payload) { [] } - let(:pr_state) { "open" } + let(:pr_state) { 'open' } let(:merged_payload) do { - "merged" => false, - "merged_by" => nil, - "merged_at" => nil + 'merged' => false, + 'merged_by' => nil, + 'merged_at' => nil } end let(:user_payload) do { - "id" => 456, - "login" => "test_user", - "html_url" => "https://github.com/test_user", - "avatar_url" => "https://github.com/test_user/avatar.jpg" + 'id' => 456, + 'login' => 'test_user', + 'html_url' => 'https://github.com/test_user', + 'avatar_url' => 'https://github.com/test_user/avatar.jpg' } end let(:work_packages) { create_list(:work_package, 1) } @@ -83,7 +83,7 @@ allow(upsert_github_user_service).to receive(:call).and_return(github_user) end - it "creates a new github pull request and calls the upsert github user service" do + it 'creates a new github pull request and calls the upsert github user service' do expect { upsert }.to change(GithubPullRequest, :count).by(1) expect(upsert_github_user_service).to have_received(:call).with(user_payload) @@ -91,11 +91,11 @@ expect(GithubPullRequest.last).to have_attributes( github_id: 123, number: 5, - github_html_url: "https://github.com/test_user/repo", - github_updated_at: Time.zone.parse("20210409T12:13:14Z"), - state: "open", - title: "The PR title", - body: "The PR body", + github_html_url: 'https://github.com/test_user/repo', + github_updated_at: Time.zone.parse('20210409T12:13:14Z'), + state: 'open', + title: 'The PR title', + body: 'The PR body', draft: false, merged: false, merged_by: nil, @@ -106,23 +106,23 @@ deletions_count: 15, changed_files_count: 16, labels: [], - repository: "test_user/repo", + repository: 'test_user/repo', github_user:, work_packages: ) end - context "when a github pull request with that id already exists" do + context 'when a github pull request with that id already exists' do let(:github_pull_request) do - create(:github_pull_request, github_id: 123, title: "old title") + create(:github_pull_request, github_id: 123, title: 'old title') end - it "updates the github pull request" do - expect { upsert }.to change { github_pull_request.reload.title }.from("old title").to("The PR title") + it 'updates the github pull request' do + expect { upsert }.to change { github_pull_request.reload.title }.from('old title').to('The PR title') end end - context "when a partial github pull request with that html_url already exists" do + context 'when a partial github pull request with that html_url already exists' do let(:github_pull_request) do create(:github_pull_request, github_id: nil, @@ -132,37 +132,37 @@ review_comments_count: nil, additions_count: nil, deletions_count: nil, - github_html_url: "https://github.com/test_user/repo", - state: "closed") + github_html_url: 'https://github.com/test_user/repo', + state: 'closed') end - it "updates the github pull request" do - expect { upsert }.to change { github_pull_request.reload.state }.from("closed").to("open") + it 'updates the github pull request' do + expect { upsert }.to change { github_pull_request.reload.state }.from('closed').to('open') expect(github_pull_request).to have_attributes( github_id: 123, - state: "open", + state: 'open', number: 5, - title: "The PR title", - body: "The PR body", - github_html_url: "https://github.com/test_user/repo", - github_updated_at: DateTime.parse("20210409T12:13:14Z"), - repository: "test_user/repo" + title: 'The PR title', + body: 'The PR body', + github_html_url: 'https://github.com/test_user/repo', + github_updated_at: DateTime.parse('20210409T12:13:14Z'), + repository: 'test_user/repo' ) end end - context "when a github pull request with that id and work_package exists" do + context 'when a github pull request with that id and work_package exists' do let(:github_pull_request) do create(:github_pull_request, github_id: 123, work_packages:) end - it "does not change the associated work packages" do + it 'does not change the associated work packages' do expect { upsert }.not_to(change { github_pull_request.reload.work_packages.to_a }) end end - context "when a github pull request with that id and work_package exists and a new work_package is referenced" do + context 'when a github pull request with that id and work_package exists and a new work_package is referenced' do let(:github_pull_request) do create(:github_pull_request, github_id: 123, work_packages: already_known_work_packages) @@ -170,22 +170,22 @@ let(:work_packages) { create_list(:work_package, 2) } let(:already_known_work_packages) { [work_packages[0]] } - it "adds the new work package" do + it 'adds the new work package' do expect { upsert }.to change { github_pull_request.reload.work_packages }.from(already_known_work_packages).to(work_packages) end end - context "when the pr is merged" do - let(:pr_state) { "open" } + context 'when the pr is merged' do + let(:pr_state) { 'open' } let(:merged_payload) do { - "merged" => true, - "merged_by" => user_payload, - "merged_at" => "20210410T09:45:03Z" + 'merged' => true, + 'merged_by' => user_payload, + 'merged_at' => '20210410T09:45:03Z' } end - it "sets the merge attributes" do + it 'sets the merge attributes' do expect { upsert }.to change(GithubPullRequest, :count).by(1) expect(upsert_github_user_service).to have_received(:call).with(user_payload).twice @@ -195,42 +195,42 @@ github_user:, merged: true, merged_by: github_user, - merged_at: Time.zone.parse("20210410T09:45:03Z") + merged_at: Time.zone.parse('20210410T09:45:03Z') ) end end - context "when the pull request payload contains label data" do + context 'when the pull request payload contains label data' do let(:labels_payload) do [ { - "id" => 123456789, - "name" => "grey", - "color" => "#666", - "description" => "An evil'ish gray tone" + 'id' => 123456789, + 'name' => 'grey', + 'color' => '#666', + 'description' => "An evil'ish gray tone" }, { - "id" => 987654321, - "name" => "white", - "color" => "#fff", - "description" => "A haven'ish white tone" + 'id' => 987654321, + 'name' => 'white', + 'color' => '#fff', + 'description' => "A haven'ish white tone" } ] end - it "stores the label attributes" do + it 'stores the label attributes' do expect { upsert }.to change(GithubPullRequest, :count).by(1) expect(GithubPullRequest.last).to have_attributes( github_id: 123, labels: [ { - "name" => "grey", - "color" => "#666" + 'name' => 'grey', + 'color' => '#666' }, { - "name" => "white", - "color" => "#fff" + 'name' => 'white', + 'color' => '#fff' } ] ) diff --git a/modules/github_integration/spec/models/github_pull_request_spec.rb b/modules/github_integration/spec/models/github_pull_request_spec.rb index f0185d5eb68b..f8da27d15658 100644 --- a/modules/github_integration/spec/models/github_pull_request_spec.rb +++ b/modules/github_integration/spec/models/github_pull_request_spec.rb @@ -36,10 +36,10 @@ it { is_expected.to validate_presence_of :title } it { is_expected.to validate_presence_of :github_updated_at } - context "when it is not a partial pull request" do + context 'when it is not a partial pull request' do subject do described_class.new(changed_files_count: 5, - body: "something", + body: 'something', comments_count: 4, review_comments_count: 3, additions_count: 2, @@ -54,16 +54,16 @@ it { is_expected.to validate_presence_of :changed_files_count } end - describe "labels" do + describe 'labels' do it { is_expected.to allow_value(nil).for(:labels) } it { is_expected.to allow_value([]).for(:labels) } - it { is_expected.to allow_value([{ "color" => "#666", "name" => "grey" }]).for(:labels) } - it { is_expected.not_to allow_value([{ "name" => "grey" }]).for(:labels) } + it { is_expected.to allow_value([{ 'color' => '#666', 'name' => 'grey' }]).for(:labels) } + it { is_expected.not_to allow_value([{ 'name' => 'grey' }]).for(:labels) } it { is_expected.not_to allow_value([{}]).for(:labels) } end end - describe ".without_work_package" do + describe '.without_work_package' do subject { described_class.without_work_package } let(:pull_request) { create(:github_pull_request, work_packages:) } @@ -73,92 +73,92 @@ it { is_expected.to contain_exactly(pull_request) } - context "when the pr is linked to a work_package" do + context 'when the pr is linked to a work_package' do let(:work_packages) { create_list(:work_package, 1) } it { is_expected.to be_empty } end end - describe ".find_by_github_identifiers" do + describe '.find_by_github_identifiers' do let(:github_id) { 5 } - let(:github_url) { "https://github.com/opf/openproject/pull/123" } + let(:github_url) { 'https://github.com/opf/openproject/pull/123' } let(:pull_request) do create(:github_pull_request, github_id:, github_html_url: github_url) end - context "when the github_id attribute matches" do - it "finds by github_id" do + context 'when the github_id attribute matches' do + it 'finds by github_id' do expect(described_class.find_by_github_identifiers(id: pull_request.github_id)) .to eql pull_request end end - context "when the github_html_url attribute matches" do - it "finds by github_html_url" do + context 'when the github_html_url attribute matches' do + it 'finds by github_html_url' do expect(described_class.find_by_github_identifiers(url: pull_request.github_html_url)) .to eql pull_request end end - context "when the provided github_id does not match" do - it "is nil" do + context 'when the provided github_id does not match' do + it 'is nil' do expect(described_class.find_by_github_identifiers(id: pull_request.github_id + 1)) .to be_nil end end - context "when the provided github_html_url does not match" do - it "is nil" do + context 'when the provided github_html_url does not match' do + it 'is nil' do expect(described_class.find_by_github_identifiers(url: "#{pull_request.github_html_url}zzzz")) .to be_nil end end - context "when neither match" do - it "is nil" do + context 'when neither match' do + it 'is nil' do expect(described_class.find_by_github_identifiers(id: pull_request.github_id + 1, url: "#{pull_request.github_html_url}zzzz")) .to be_nil end end - context "when the provided github_html_url does not match but the github_id does" do - it "is nil" do + context 'when the provided github_html_url does not match but the github_id does' do + it 'is nil' do expect(described_class.find_by_github_identifiers(id: pull_request.github_id, url: "#{pull_request.github_html_url}zzzz")) .to eql pull_request end end - context "when the provided github_html_url does match but the github_id does not" do - it "is nil" do + context 'when the provided github_html_url does match but the github_id does not' do + it 'is nil' do expect(described_class.find_by_github_identifiers(id: pull_request.github_id + 1, url: pull_request.github_html_url)) .to eql pull_request end end - context "when neither match but initialize is true" do + context 'when neither match but initialize is true' do subject(:finder) do described_class.find_by_github_identifiers(id: pull_request.github_id + 1, url: "#{pull_request.github_html_url}zzzz", initialize: true) end - it "returns a pull reqeust" do + it 'returns a pull reqeust' do expect(finder) .to be_a(described_class) end - it "returns a new record" do + it 'returns a new record' do expect(finder) .to be_new_record end - it "has the provided attributes initialized" do + it 'has the provided attributes initialized' do expect(finder.attributes.compact) .to eql("github_id" => pull_request.github_id + 1, "github_html_url" => "#{pull_request.github_html_url}zzzz") @@ -166,41 +166,41 @@ end end - describe "#latest_check_runs" do + describe '#latest_check_runs' do subject { pull_request.reload.latest_check_runs } let(:pull_request) { create(:github_pull_request) } it { is_expected.to be_empty } - context "when multiple check_runs from different apps with different names exist" do + context 'when multiple check_runs from different apps with different names exist' do let(:latest_check_runs) do [ create( :github_check_run, app_id: 123, - name: "test", + name: 'test', started_at: 1.minute.ago, github_pull_request: pull_request ), create( :github_check_run, app_id: 123, - name: "lint", + name: 'lint', started_at: 1.minute.ago, github_pull_request: pull_request ), create( :github_check_run, app_id: 456, - name: "test", + name: 'test', started_at: 1.minute.ago, github_pull_request: pull_request ), create( :github_check_run, app_id: 789, - name: "test", + name: 'test', started_at: 1.minute.ago, github_pull_request: pull_request ) @@ -211,21 +211,21 @@ create( :github_check_run, app_id: 123, - name: "test", + name: 'test', started_at: 2.minutes.ago, github_pull_request: pull_request ), create( :github_check_run, app_id: 123, - name: "test", + name: 'test', started_at: 3.minutes.ago, github_pull_request: pull_request ), create( :github_check_run, app_id: 123, - name: "lint", + name: 'lint', started_at: 5.minutes.ago, github_pull_request: pull_request ) diff --git a/modules/github_integration/spec/spec_helper.rb b/modules/github_integration/spec/spec_helper.rb index d5f21fe45533..11d3b4668f94 100644 --- a/modules/github_integration/spec/spec_helper.rb +++ b/modules/github_integration/spec/spec_helper.rb @@ -26,6 +26,6 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].sort.each { |f| require f } +Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].sort.each { |f| require f } diff --git a/modules/github_integration/spec/support/pages/work_package_github_tab.rb b/modules/github_integration/spec/support/pages/work_package_github_tab.rb index e2d97d0affe0..d4657329b7bd 100644 --- a/modules/github_integration/spec/support/pages/work_package_github_tab.rb +++ b/modules/github_integration/spec/support/pages/work_package_github_tab.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rbconfig" -require "support/pages/page" +require 'rbconfig' +require 'support/pages/page' module Pages class GitHubTab < Page @@ -43,26 +43,26 @@ def path end def git_actions_menu_button - find(".github-git-copy:not([disabled])", text: "Git") + find('.github-git-copy:not([disabled])', text: 'Git') end def git_actions_copy_branch_name_button - find(".git-actions-menu .copy-button:not([disabled])", match: :first) + find('.git-actions-menu .copy-button:not([disabled])', match: :first) end def paste_clipboard_content meta_key = osx? ? :command : :control - page.send_keys(meta_key, "v") + page.send_keys(meta_key, 'v') end def expect_tab_not_present - expect(page).to have_no_css(".op-tab-row--link", text: "GITHUB") + expect(page).to have_no_css('.op-tab-row--link', text: 'GITHUB') end private def osx? - RbConfig::CONFIG["host_os"].include?("darwin") + RbConfig::CONFIG['host_os'].include?('darwin') end end end diff --git a/modules/github_integration/spec/support/webhook_fixture_helpers.rb b/modules/github_integration/spec/support/webhook_fixture_helpers.rb index 4fe554143d35..bea8c36b3eb2 100644 --- a/modules/github_integration/spec/support/webhook_fixture_helpers.rb +++ b/modules/github_integration/spec/support/webhook_fixture_helpers.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "json" +require 'json' module WebhookFixtureHelpers - FIXTURES_PATH = File.join(File.dirname(__FILE__), "../fixtures/github_webhooks") + FIXTURES_PATH = File.join(File.dirname(__FILE__), '../fixtures/github_webhooks') # Params: # * replacements: A `Hash` containing replacement values for placeholders in the fixture files, diff --git a/modules/github_integration/spec/workers/cron/clear_old_pull_requests_job_spec.rb b/modules/github_integration/spec/workers/cron/clear_old_pull_requests_job_spec.rb index 62cf2d600d7a..beb5cc6fbbd2 100644 --- a/modules/github_integration/spec/workers/cron/clear_old_pull_requests_job_spec.rb +++ b/modules/github_integration/spec/workers/cron/clear_old_pull_requests_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Cron::ClearOldPullRequestsJob, type: :job do let(:pull_request_without_work_package) do @@ -44,7 +44,7 @@ pull_request_with_work_package end - it "removes pull request without work packages attached" do + it 'removes pull request without work packages attached' do expect { job.perform }.to change(GithubPullRequest, :count).by(-1).and(change(GithubCheckRun, :count).by(-1)) expect(GithubPullRequest.all) diff --git a/modules/gitlab_integration/README.md b/modules/gitlab_integration/README.md index f48a136354f4..436546b2bf6d 100644 --- a/modules/gitlab_integration/README.md +++ b/modules/gitlab_integration/README.md @@ -2,7 +2,7 @@
    -Based on the OpenProject Github Integration, this plugin offers the same functionalities plus other new features. This is the first version that includes the visualization of the status of the *Pipelines* (by now, it is considered in Beta status). You can test it by activating the Pipelines event in the GitLab webhook. Just keep in mind that not all pipelines will be reflected in OpenProject, only Merge Request type pipelines (for more information see the GitLab issue https://gitlab.com/gitlab-org/gitlab/-/issues/345028). Any feedback about the pipelines feature would be very appreciated, whether it works or if issues arise (you can use this ticket https://github.com/btey/openproject-gitlab-integration/issues/43). +Based on the OpenProject GitHub Integration, this plugin offers the same functionalities plus other new features. This is the first version that includes the visualization of the status of the *Pipelines* (by now, it is considered in Beta status). You can test it by activating the Pipelines event in the GitLab webhook. Just keep in mind that not all pipelines will be reflected in OpenProject, only Merge Request type pipelines (for more information see the GitLab issue https://gitlab.com/gitlab-org/gitlab/-/issues/345028). Any feedback about the pipelines feature would be very appreciated, whether it works or if issues arise (you can use this ticket https://github.com/btey/openproject-gitlab-integration/issues/43). In this version it has also been implemented that **all linked or referenced** Issues appear in the GitLab tab (https://github.com/btey/openproject-gitlab-integration/issues/34). The opportunity has also been taken to redesign how the information is presented so that it is visually easy to read and at the same time can continue to provide all the information, including labels and pipeline status. @@ -15,7 +15,7 @@ If there are labels related to the Issue or MR, a button with the label icon wil ## Overview OpenProject module for integration with GitLab: -* Latest Gitlab release tested: **16.6.2** +* Latest GitLab release tested: **16.6.2** * Latest OpenProject release tested: **13.1.2** (for OP v13.0.X use v2.1.2) The reference system is based on the same system as for GitHub integration. You can use a link to the work package or just use “OP#87” or "PP#87" in the title/description of the Issue/MR in GitLab. @@ -136,7 +136,7 @@ A typical workflow on GitLab side would be: ## Configuration -You will have to configure both **OpenProject** and **Gitlab** for the integration to work. +You will have to configure both **OpenProject** and **GitLab** for the integration to work. In case of **Docker** installation, follow the official OpenProject documentation [here](https://www.openproject.org/docs/installation-and-operations/installation/docker/#openproject-plugins). If for some reason the installation with Docker described in the official documentation does not work for you, you can try building your own docker image: * Clone from the Openproject Repo: `git clone https://github.com/opf/openproject.git --branch=stable/13 --depth=1 .` @@ -147,11 +147,11 @@ In case of **Docker** installation, follow the official OpenProject documentatio In case of **DEB/RPM** based instalation, follow the official OpenProject documentation [here](https://www.openproject.org/docs/installation-and-operations/configuration/plugins/). -In case of [**manual**](https://www.openproject.org/docs/installation-and-operations/installation/manual/) installation, this plugin should be installed in the same place as the Github plugin that comes bundled with OpenProject. +In case of [**manual**](https://www.openproject.org/docs/installation-and-operations/installation/manual/) installation, this plugin should be installed in the same place as the GitHub plugin that comes bundled with OpenProject. -- **Github plugin path:** `modules/github_integration` +- **GitHub plugin path:** `modules/github_integration` -- **Path to put Gitlab plugin:** `modules/gitlab_integration` +- **Path to put GitLab plugin:** `modules/gitlab_integration` But first you must modify **Gemfile.lock** and **Gemfile.modules** so that OpenProject detects the new module. @@ -198,13 +198,13 @@ bundle config set deployment First you will need to create a user in OpenProject that will make the comments. The user will have to be added to each project with a role that allows them to comment on work packages and change status. -Once the user is created you need to generate an OpenProject API token for it to use later on the Gitlab side: +Once the user is created you need to generate an OpenProject API token for it to use later on the GitLab side: * Login as the newly created user. * Go to My Account (click on Avatar in top right corner). * Go to Access Token. * Click on generate in the API row. -* Copy the generated key. You can now configure the necessary webhook in Gitlab. +* Copy the generated key. You can now configure the necessary webhook in GitLab. ### The webhook in GitLab @@ -227,7 +227,7 @@ You need to configure just two things in the webhook: Now the integration is set up on both sides and you can use it. -> **Note:** If you are installing and configuring OpenProject on the same server as GitLab you will need to enable in Gitlab the option [`Allow requests to the local network from web hooks and services`](https://docs.gitlab.com/ee/security/webhooks.html#allow-requests-to-the-local-network-from-webhooks-and-integrations) so that it can send the data locally to the OpenProject webhook since they will be on the same machine. +> **Note:** If you are installing and configuring OpenProject on the same server as GitLab you will need to enable in GitLab the option [`Allow requests to the local network from web hooks and services`](https://docs.gitlab.com/ee/security/webhooks.html#allow-requests-to-the-local-network-from-webhooks-and-integrations) so that it can send the data locally to the OpenProject webhook since they will be on the same machine. ## How to report bugs or issues diff --git a/modules/gitlab_integration/app/models/gitlab_issue.rb b/modules/gitlab_integration/app/models/gitlab_issue.rb index 31f5927fd21b..61ad3c59f112 100644 --- a/modules/gitlab_integration/app/models/gitlab_issue.rb +++ b/modules/gitlab_integration/app/models/gitlab_issue.rb @@ -36,8 +36,8 @@ class GitlabIssue < ApplicationRecord belongs_to :gitlab_user, optional: true enum state: { - opened: "opened", - closed: "closed" + opened: 'opened', + closed: 'closed' } validates_presence_of :gitlab_html_url, diff --git a/modules/gitlab_integration/app/models/gitlab_merge_request.rb b/modules/gitlab_integration/app/models/gitlab_merge_request.rb index 77724d3b534b..ae02a147a74a 100644 --- a/modules/gitlab_integration/app/models/gitlab_merge_request.rb +++ b/modules/gitlab_integration/app/models/gitlab_merge_request.rb @@ -35,12 +35,12 @@ class GitlabMergeRequest < ApplicationRecord has_and_belongs_to_many :work_packages has_many :gitlab_pipelines, dependent: :destroy belongs_to :gitlab_user, optional: true - belongs_to :merged_by, optional: true, class_name: "GitlabUser" + belongs_to :merged_by, optional: true, class_name: 'GitlabUser' enum state: { - opened: "opened", - merged: "merged", - closed: "closed" + opened: 'opened', + merged: 'merged', + closed: 'closed' } validates_presence_of :gitlab_html_url, diff --git a/modules/gitlab_integration/app/models/gitlab_pipeline.rb b/modules/gitlab_integration/app/models/gitlab_pipeline.rb index e663c3bf8c34..24b4c1633122 100644 --- a/modules/gitlab_integration/app/models/gitlab_pipeline.rb +++ b/modules/gitlab_integration/app/models/gitlab_pipeline.rb @@ -34,17 +34,17 @@ class GitlabPipeline < ApplicationRecord # TODO: confirm with the gitlab documentation what are the different statuses. enum status: { - created: "created", - running: "running", - success: "success", - waiting: "waiting", - preparing: "preparing", - failed: "failed", - pending: "pending", - canceled: "canceled", - skipped: "skipped", - manual: "manual", - scheduled: "scheduled" + created: 'created', + running: 'running', + success: 'success', + waiting: 'waiting', + preparing: 'preparing', + failed: 'failed', + pending: 'pending', + canceled: 'canceled', + skipped: 'skipped', + manual: 'manual', + scheduled: 'scheduled' } validates_presence_of :gitlab_user_avatar_url, diff --git a/modules/gitlab_integration/app/workers/cron/clear_old_merge_requests_job.rb b/modules/gitlab_integration/app/workers/cron/clear_old_merge_requests_job.rb index fa30113be3af..bfd79e16c5b6 100644 --- a/modules/gitlab_integration/app/workers/cron/clear_old_merge_requests_job.rb +++ b/modules/gitlab_integration/app/workers/cron/clear_old_merge_requests_job.rb @@ -30,7 +30,9 @@ #++ module Cron - class ClearOldMergeRequestsJob < ApplicationJob + class ClearOldMergeRequestsJob < CronJob + self.cron_expression = '25 1 * * *' # runs at 1:25 nightly + priority_number :low def perform diff --git a/modules/gitlab_integration/config/locales/crowdin/zh-CN.yml b/modules/gitlab_integration/config/locales/crowdin/zh-CN.yml index daf7d33d559c..21dc519abdc8 100644 --- a/modules/gitlab_integration/config/locales/crowdin/zh-CN.yml +++ b/modules/gitlab_integration/config/locales/crowdin/zh-CN.yml @@ -36,32 +36,32 @@ zh-CN: permission_show_gitlab_content: "Show GitLab content" gitlab_integration: merge_request_opened_comment: > - **合并请求已打开:** [%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 打开。 + **合并请求已打开**:[%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 打开。 merge_request_closed_comment: > - **合并请求已关闭:** [%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 关闭。 + **合并请求已关闭**:[%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 关闭。 merge_request_merged_comment: > - **合并请求已合并:** [%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 合并。 + **合并请求已合并**:[%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 合并。 merge_request_reopened_comment: > - **合并请求已重新打开:** [%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 重新打开。 + **合并请求已重新打开**:[%{repository}](%{repository_url}) 的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 重新打开。 note_commit_referenced_comment: > - **已在提交中引用:** [%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的提交备注 [%{commit_id}](%{commit_url}) 中引用了此工作包: %{commit_note} + **在提交中引用**:[%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的提交备注 [%{commit_id}](%{commit_url}) 中引用了此工作包: %{commit_note} note_mr_referenced_comment: > - **已在合并请求中引用:** [%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 中引用了此工作包:%{mr_note} + **在合并请求中引用**:[%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 中引用了此工作包: %{mr_note} note_mr_commented_comment: > - **已在合并请求中添加注释:** [%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 中对此工作包添加了注释:%{mr_note} + **在合并请求中添加注释**:[%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的合并请求 %{mr_number} [%{mr_title}](%{mr_url}) 中对此工作包添加了注释:%{mr_note} note_issue_referenced_comment: > - **已在问题中引用:** [%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的问题 %{issue_number} [%{issue_title}](%{issue_url}) 中引用了此工作包:%{issue_note} + **在问题中引用**:[%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的问题 %{issue_number} [%{issue_title}](%{issue_url}) 中引用了此工作包:%{issue_note} note_issue_commented_comment: > - **已在问题中添加注释:** [%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的问题 %{issue_number} [%{issue_title}](%{issue_url}) 中对此工作包添加了注释:%{issue_note} + **在问题中添加注释**:[%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的问题 %{issue_number} [%{issue_title}](%{issue_url}) 中对此工作包添加了注释:%{issue_note} note_snippet_referenced_comment: > - **已在代码段中引用:** [%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的代码段 %{snippet_number} [%{snippet_title}](%{snippet_url}) 中引用了此工作包:%{snippet_note} + **在代码段中引用**:[%{gitlab_user}](%{gitlab_user_url}) 在 [%{repository}](%{repository_url}) 上的代码段 %{snippet_number} [%{snippet_title}](%{snippet_url}) 中引用了此工作包:%{snippet_note} issue_opened_referenced_comment: > - **问题已打开:** [%{repository}](%{repository_url}) 的问题 %{issue_number} [%{issue_title}](%{issue_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 打开。 + **问题已打开**:[%{repository}](%{repository_url}) 的问题 %{issue_number} [%{issue_title}](%{issue_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 打开。 issue_closed_referenced_comment: > - **问题已关闭:** [%{repository}](%{repository_url}) 的问题 %{issue_number} [%{issue_title}](%{issue_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 关闭。 + **问题已关闭**:[%{repository}](%{repository_url}) 的问题 %{issue_number} [%{issue_title}](%{issue_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 关闭。 issue_reopened_referenced_comment: > - **问题已重新打开:** [%{repository}](%{repository_url}) 的问题 %{issue_number} [%{issue_title}](%{issue_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 重新打开。 + **问题已重新打开**:[%{repository}](%{repository_url}) 的问题 %{issue_number} [%{issue_title}](%{issue_url}) 已由 [%{gitlab_user}](%{gitlab_user_url}) 重新打开。 push_single_commit_comment: > - **已在合并请求中推送:** [%{gitlab_user}](%{gitlab_user_url}) 已在 %{commit_timestamp} 将 [%{commit_number}](%{commit_url}) 推送到 [%{repository}](%{repository_url}):%{commit_note} + **在合并请求中推送**:[%{gitlab_user}](%{gitlab_user_url}) 在 %{commit_timestamp} 将 [%{commit_number}](%{commit_url}) 推送到 [%{repository}](%{repository_url}):%{commit_note} push_multiple_commits_comment: > - **已在合并请求中推送:** [%{gitlab_user}](%{gitlab_user_url}) 已在 %{commit_timestamp} 将多个提交 [%{commit_number}](%{commit_url}) 推送到 [%{repository}](%{repository_url}):%{commit_note} + **在合并请求中推送**:[%{gitlab_user}](%{gitlab_user_url}) 在 %{commit_timestamp} 将多个提交 [%{commit_number}](%{commit_url}) 推送到 [%{repository}](%{repository_url}):%{commit_note} diff --git a/modules/gitlab_integration/db/migrate/20211015110000_gitlab_integration_models.rb b/modules/gitlab_integration/db/migrate/20211015110000_gitlab_integration_models.rb index ef2af3f83da7..847183710ae5 100644 --- a/modules/gitlab_integration/db/migrate/20211015110000_gitlab_integration_models.rb +++ b/modules/gitlab_integration/db/migrate/20211015110000_gitlab_integration_models.rb @@ -50,7 +50,7 @@ def change end create_join_table :gitlab_merge_requests, :work_packages do |t| - t.index :gitlab_merge_request_id, name: "gitlab_mr_wp_mr_id" + t.index :gitlab_merge_request_id, name: 'gitlab_mr_wp_mr_id' t.index %i[gitlab_merge_request_id work_package_id], unique: true, name: "unique_index_gl_mrs_wps_on_gl_mr_id_and_wp_id" diff --git a/modules/gitlab_integration/db/migrate/20211015110002_add_gitlab_issues.rb b/modules/gitlab_integration/db/migrate/20211015110002_add_gitlab_issues.rb index e5a893195518..6256a34212fe 100644 --- a/modules/gitlab_integration/db/migrate/20211015110002_add_gitlab_issues.rb +++ b/modules/gitlab_integration/db/migrate/20211015110002_add_gitlab_issues.rb @@ -45,7 +45,7 @@ def change end create_join_table :gitlab_issues, :work_packages do |t| - t.index :gitlab_issue_id, name: "gitlab_issues_wp_issue_id" + t.index :gitlab_issue_id, name: 'gitlab_issues_wp_issue_id' t.index %i[gitlab_issue_id work_package_id], unique: true, name: "unique_index_gl_issues_wps_on_gl_issue_id_and_wp_id" diff --git a/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_issue_representer.rb b/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_issue_representer.rb index a27aa56ed3b8..5ed0b8dd4cca 100644 --- a/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_issue_representer.rb +++ b/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_issue_representer.rb @@ -27,8 +27,8 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -80,7 +80,7 @@ def initialize(model, current_user:, **_opts) date_time_property :updated_at def _type - "GitlabIssue" + 'GitlabIssue' end self.to_eager_load = %i[gitlab_user] diff --git a/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_user_representer.rb b/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_user_representer.rb index 4f2e48db0c19..535b9ddb49aa 100644 --- a/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_user_representer.rb +++ b/modules/gitlab_integration/lib/api/v3/gitlab_issues/gitlab_user_representer.rb @@ -27,8 +27,8 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -44,7 +44,7 @@ class GitlabUserRepresenter < ::API::Decorators::Single property :gitlab_avatar_url, as: :avatarUrl def _type - "GitlabUser" + 'GitlabUser' end end end diff --git a/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer.rb b/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer.rb index f9650185840c..7286b080bcfd 100644 --- a/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer.rb +++ b/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer.rb @@ -27,8 +27,8 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -98,7 +98,7 @@ def initialize(model, current_user:, **_opts) date_time_property :updated_at def _type - "GitlabMergeRequest" + 'GitlabMergeRequest' end self.to_eager_load = %i[gitlab_user merged_by] diff --git a/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer.rb b/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer.rb index 858f816abaca..a52c5700d9ca 100644 --- a/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer.rb +++ b/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer.rb @@ -27,8 +27,8 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -53,7 +53,7 @@ class GitlabPipelineRepresenter < ::API::Decorators::Single date_time_property :completed_at def _type - "GitlabPipeline" + 'GitlabPipeline' end end end diff --git a/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_user_representer.rb b/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_user_representer.rb index 361f8651f18a..63ef95738b6a 100644 --- a/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_user_representer.rb +++ b/modules/gitlab_integration/lib/api/v3/gitlab_merge_requests/gitlab_user_representer.rb @@ -27,8 +27,8 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "roar/decorator" -require "roar/json/hal" +require 'roar/decorator' +require 'roar/json/hal' module API module V3 @@ -44,7 +44,7 @@ class GitlabUserRepresenter < ::API::Decorators::Single property :gitlab_avatar_url, as: :avatarUrl def _type - "GitlabUser" + 'GitlabUser' end end end diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/engine.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/engine.rb index 48b2c0b84582..68520a33b8c2 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/engine.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/engine.rb @@ -27,12 +27,12 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "open_project/plugins" +require 'open_project/plugins' -require_relative "patches/api/work_package_representer" -require_relative "notification_handlers" -require_relative "hook_handler" -require_relative "services" +require_relative 'patches/api/work_package_representer' +require_relative 'notification_handlers' +require_relative 'hook_handler' +require_relative 'services' module OpenProject::GitlabIntegration class Engine < ::Rails::Engine @@ -40,8 +40,8 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-gitlab_integration", - author_url: "https://github.com/btey/openproject", + register 'openproject-gitlab_integration', + author_url: 'https://github.com/btey/openproject', bundled: true do project_module(:gitlab, dependencies: :work_package_tracking) do permission(:show_gitlab_content, @@ -52,24 +52,24 @@ class Engine < ::Rails::Engine patches %w[WorkPackage] - initializer "gitlab.register_hook" do - ::OpenProject::Webhooks.register_hook "gitlab" do |hook, environment, params, user| + initializer 'gitlab.register_hook' do + ::OpenProject::Webhooks.register_hook 'gitlab' do |hook, environment, params, user| HookHandler.new.process(hook, environment, params, user) end end - initializer "gitlab.subscribe_to_notifications" do - ::OpenProject::Notifications.subscribe("gitlab.merge_request_hook", + initializer 'gitlab.subscribe_to_notifications' do + ::OpenProject::Notifications.subscribe('gitlab.merge_request_hook', &NotificationHandlers.method(:merge_request_hook)) - ::OpenProject::Notifications.subscribe("gitlab.note_hook", + ::OpenProject::Notifications.subscribe('gitlab.note_hook', &NotificationHandlers.method(:note_hook)) - ::OpenProject::Notifications.subscribe("gitlab.issue_hook", + ::OpenProject::Notifications.subscribe('gitlab.issue_hook', &NotificationHandlers.method(:issue_hook)) - ::OpenProject::Notifications.subscribe("gitlab.push_hook", + ::OpenProject::Notifications.subscribe('gitlab.push_hook', &NotificationHandlers.method(:push_hook)) - ::OpenProject::Notifications.subscribe("gitlab.pipeline_hook", + ::OpenProject::Notifications.subscribe('gitlab.pipeline_hook', &NotificationHandlers.method(:pipeline_hook)) - ::OpenProject::Notifications.subscribe("gitlab.system_hook", + ::OpenProject::Notifications.subscribe('gitlab.system_hook', &NotificationHandlers.method(:system_hook)) end @@ -92,21 +92,14 @@ class Engine < ::Rails::Engine "gitlab_pipeline/#{id}" end - add_api_endpoint "API::V3::WorkPackages::WorkPackagesAPI", :id do + add_api_endpoint 'API::V3::WorkPackages::WorkPackagesAPI', :id do mount ::API::V3::GitlabMergeRequests::GitlabMergeRequestsByWorkPackageAPI end - add_api_endpoint "API::V3::WorkPackages::WorkPackagesAPI", :id do + add_api_endpoint 'API::V3::WorkPackages::WorkPackagesAPI', :id do mount ::API::V3::GitlabIssues::GitlabIssuesByWorkPackageAPI end - add_cron_jobs do - { - "Cron::ClearOldMergeRequestsJob": { - cron: "25 1 * * *", # runs at 1:25 nightly - class: ::Cron::ClearOldMergeRequestsJob.name - } - } - end + add_cron_jobs { ::Cron::ClearOldMergeRequestsJob } end end diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/hook_handler.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/hook_handler.rb index 8c0de711fc61..5c8900bbcbb5 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/hook_handler.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/hook_handler.rb @@ -43,8 +43,8 @@ class HookHandler # We need to check validity of the data and send a Notification # which we process in our NotificationHandler. def process(_hook, request, params, user) - event_type = request.env["HTTP_X_GITLAB_EVENT"] - event_type.tr!(" ", "_") + event_type = request.env['HTTP_X_GITLAB_EVENT'] + event_type.tr!(' ', '_') event_type = event_type.to_s.downcase Rails.logger.debug { "Received gitlab webhook #{event_type}" } @@ -55,8 +55,8 @@ def process(_hook, request, params, user) payload = params[:payload] .permit! .to_h - .merge("open_project_user_id" => user.id, - "gitlab_event" => event_type) + .merge('open_project_user_id' => user.id, + 'gitlab_event' => event_type) event_name = :"gitlab.#{event_type}" OpenProject::Notifications.send(event_name, payload) diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/helper.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/helper.rb index 50b55c372330..cf715d0bb69c 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/helper.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/helper.rb @@ -48,9 +48,9 @@ def extract_work_package_ids(text, kind = "") # e.g.,: This is a reference to OP#1234 # For private comments you can use the prefix: PP# host_name = Regexp.escape(Setting.host_name) - wp_regex = if kind == "private" + wp_regex = if kind == 'private' /PP#(\d+)/ - elsif kind != "note" + elsif kind != 'note' /OP#(\d+)|PP#(\d+)|http(?:s?):\/\/#{host_name}\/(?:\S+?\/)*(?:work_packages|wp)\/([0-9]+)/ else /OP#(\d+)|http(?:s?):\/\/#{host_name}\/(?:\S+?\/)*(?:work_packages|wp)\/([0-9]+)/ @@ -84,7 +84,7 @@ def find_mentioned_work_packages(text, user, kind = "") # Returns a list of `WorkPackage`s that were excluded in the `text`. def find_excluded_work_packages(text, user) - find_visible_work_packages(extract_work_package_ids(text, "private"), user) + find_visible_work_packages(extract_work_package_ids(text, 'private'), user) end ## @@ -126,7 +126,7 @@ def to_h def method_missing(name, *args, &block) super unless args.empty? && block.nil? - value = if name.end_with?("?") + value = if name.end_with?('?') @payload.fetch(name.to_s[..-2], nil) else @payload.fetch(name.to_s) diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/issue_hook.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/issue_hook.rb index 97c77136d748..53b4148f6ea2 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/issue_hook.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/issue_hook.rb @@ -37,7 +37,7 @@ class IssueHook def process(payload_params) @payload = wrap_payload(payload_params) user = User.find_by_id(payload.open_project_user_id) - text = payload.object_attributes.title + " - " + payload.object_attributes.description + text = payload.object_attributes.title + ' - ' + payload.object_attributes.description work_packages = find_mentioned_work_packages(text, user) notes = generate_notes(payload) comment_on_referenced_work_packages(work_packages, user, notes) @@ -52,9 +52,9 @@ def generate_notes(payload) accepted_actions = %w[open reopen close] key_action = { - "open" => "opened", - "reopen" => "reopened", - "close" => "closed" + 'open' => 'opened', + 'reopen' => 'reopened', + 'close' => 'closed' }[payload.object_attributes.action] return nil unless accepted_actions.include? payload.object_attributes.action diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/merge_request_hook.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/merge_request_hook.rb index 943a289d77fe..cc409d2f4c72 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/merge_request_hook.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/merge_request_hook.rb @@ -48,15 +48,15 @@ def process(payload_params) return unless (accepted_actions.include? payload.object_attributes.action) || (accepted_states.include? payload.object_attributes.state) user = User.find_by_id(payload.open_project_user_id) - text = payload.object_attributes.title + " - " + payload.object_attributes.description + text = payload.object_attributes.title + ' - ' + payload.object_attributes.description work_packages = find_mentioned_work_packages(text, user) notes = generate_notes(payload) if (accepted_actions_for_comments.include? payload.object_attributes.action) || (accepted_states.include? payload.object_attributes.state) comment_on_referenced_work_packages(work_packages, user, notes) - if payload.object_attributes.state == "opened" && update_status_on_new_mr + if payload.object_attributes.state == 'opened' && update_status_on_new_mr status_on_referenced_work_packages(work_packages, user, wp_status_id_on_new_mr) - elsif payload.object_attributes.state == "merged" && update_status_on_merged + elsif payload.object_attributes.state == 'merged' && update_status_on_merged status_on_referenced_work_packages(work_packages, user, wp_status_id_on_merged) end end @@ -69,16 +69,16 @@ def process(payload_params) def generate_notes(payload) key = { - "opened" => "opened", - "reopened" => "reopened", - "closed" => "closed", - "merged" => "merged", - "edited" => "referenced", - "referenced" => "referenced" + 'opened' => 'opened', + 'reopened' => 'reopened', + 'closed' => 'closed', + 'merged' => 'merged', + 'edited' => 'referenced', + 'referenced' => 'referenced' }[payload.object_attributes.state] key_action = { - "reopen" => "reopened" + 'reopen' => 'reopened' }[payload.object_attributes.action] return nil unless key diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/note_hook.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/note_hook.rb index 8a6aab36b35a..3bffd2683413 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/note_hook.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/note_hook.rb @@ -40,35 +40,35 @@ def process(payload_params) user = User.find_by(id: payload.open_project_user_id) text = payload.object_attributes.note work_packages = find_mentioned_work_packages(text, user, payload.object_kind) - if work_packages.empty? && payload.object_attributes.noteable_type == "Issue" + if work_packages.empty? && payload.object_attributes.noteable_type == 'Issue' text = "#{payload.issue.title} - #{payload.object_attributes.note}" work_packages = find_mentioned_work_packages(text, user, payload.object_kind) work_packages_excluded = find_excluded_work_packages(text, user) work_packages = work_packages - work_packages_excluded unless work_packages_excluded.empty? return if work_packages.empty? - notes = generate_notes(payload, "comment") - elsif work_packages.empty? && payload.object_attributes.noteable_type == "Snippet" + notes = generate_notes(payload, 'comment') + elsif work_packages.empty? && payload.object_attributes.noteable_type == 'Snippet' text = "#{payload.snippet.title} - #{payload.object_attributes.note}" work_packages = find_mentioned_work_packages(text, user, payload.object_kind) work_packages_excluded = find_excluded_work_packages(text, user) work_packages = work_packages - work_packages_excluded unless work_packages_excluded.empty? return if work_packages.empty? - notes = generate_notes(payload, "reference") - elsif work_packages.empty? && payload.object_attributes.noteable_type == "MergeRequest" + notes = generate_notes(payload, 'reference') + elsif work_packages.empty? && payload.object_attributes.noteable_type == 'MergeRequest' text = "#{payload.merge_request.title} - #{payload.object_attributes.note}" work_packages = find_mentioned_work_packages(text, user, payload.object_kind) work_packages_excluded = find_excluded_work_packages(text, user) work_packages = work_packages - work_packages_excluded unless work_packages_excluded.empty? return if work_packages.empty? - notes = generate_notes(payload, "comment") + notes = generate_notes(payload, 'comment') else - notes = generate_notes(payload, "reference") + notes = generate_notes(payload, 'reference') end comment_on_referenced_work_packages(work_packages, user, notes) - if payload.object_attributes.noteable_type == "Issue" + if payload.object_attributes.noteable_type == 'Issue' upsert_issue(work_packages) end end @@ -80,7 +80,7 @@ def process(payload_params) # TODO: add key list to simplify the code... def generate_notes(payload, note_type) case payload.object_attributes.noteable_type - when "Commit" + when 'Commit' commit_id = payload.commit.id I18n.t("gitlab_integration.note_commit_referenced_comment", commit_id: commit_id[0, 8], @@ -90,8 +90,8 @@ def generate_notes(payload, note_type) repository_url: payload.repository.homepage, gitlab_user: payload.user.name, gitlab_user_url: payload.user.avatar_url) - when "MergeRequest" - if note_type == "comment" + when 'MergeRequest' + if note_type == 'comment' I18n.t("gitlab_integration.note_mr_commented_comment", mr_number: payload.merge_request.iid, mr_title: payload.merge_request.title, @@ -101,7 +101,7 @@ def generate_notes(payload, note_type) repository_url: payload.repository.homepage, gitlab_user: payload.user.name, gitlab_user_url: payload.user.avatar_url) - elsif note_type == "reference" + elsif note_type == 'reference' I18n.t("gitlab_integration.note_mr_referenced_comment", mr_number: payload.merge_request.iid, mr_title: payload.merge_request.title, @@ -112,8 +112,8 @@ def generate_notes(payload, note_type) gitlab_user: payload.user.name, gitlab_user_url: payload.user.avatar_url) end - when "Issue" - if note_type == "comment" + when 'Issue' + if note_type == 'comment' I18n.t("gitlab_integration.note_issue_commented_comment", issue_number: payload.issue.iid, issue_title: payload.issue.title, @@ -123,7 +123,7 @@ def generate_notes(payload, note_type) repository_url: payload.repository.homepage, gitlab_user: payload.user.name, gitlab_user_url: payload.user.avatar_url) - elsif note_type == "reference" + elsif note_type == 'reference' I18n.t("gitlab_integration.note_issue_referenced_comment", issue_number: payload.issue.iid, issue_title: payload.issue.title, @@ -134,7 +134,7 @@ def generate_notes(payload, note_type) gitlab_user: payload.user.name, gitlab_user_url: payload.user.avatar_url) end - when "Snippet" + when 'Snippet' I18n.t("gitlab_integration.note_snippet_referenced_comment", snippet_number: payload.snippet.id, snippet_title: payload.snippet.title, diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/push_hook.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/push_hook.rb index 5a8ea57ea41f..772b8e625625 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/push_hook.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/push_hook.rb @@ -36,11 +36,11 @@ class PushHook def process(payload_params) @payload = wrap_payload(payload_params) - return nil unless payload.object_kind == "push" + return nil unless payload.object_kind == 'push' payload.commits.each do |commit| user = User.find_by_id(payload.open_project_user_id) - text = commit["title"] + " - " + commit["message"] + text = commit['title'] + " - " + commit['message'] work_packages = find_mentioned_work_packages(text, user) notes = generate_notes(commit, payload) comment_on_referenced_work_packages(work_packages, user, notes) @@ -52,12 +52,12 @@ def process(payload_params) attr_reader :payload def generate_notes(commit, payload) - commit_id = commit["id"] + commit_id = commit['id'] I18n.t("gitlab_integration.push_single_commit_comment", commit_number: commit_id[0, 8], - commit_note: commit["message"], - commit_url: commit["url"], - commit_timestamp: commit["timestamp"], + commit_note: commit['message'], + commit_url: commit['url'], + commit_timestamp: commit['timestamp'], repository: payload.repository.name, repository_url: payload.repository.homepage, gitlab_user: payload.user_name, diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/system_hook.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/system_hook.rb index 5e91993c0f4d..72a56f1fb63d 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/system_hook.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handler/system_hook.rb @@ -36,11 +36,11 @@ class SystemHook def process(payload_params) @payload = wrap_payload(payload_params) - return nil unless payload.object_kind == "push" + return nil unless payload.object_kind == 'push' payload.commits.each do |commit| user = User.find_by_id(payload.open_project_user_id) - text = commit["title"] + " - " + commit["message"] + text = commit['title'] + " - " + commit['message'] work_packages = find_mentioned_work_packages(text, user) notes = generate_notes(commit, payload) comment_on_referenced_work_packages(work_packages, user, notes) @@ -52,12 +52,12 @@ def process(payload_params) attr_reader :payload def generate_notes(commit, payload) - commit_id = commit["id"] + commit_id = commit['id'] I18n.t("gitlab_integration.push_single_commit_comment", commit_number: commit_id[0, 8], - commit_note: commit["message"], - commit_url: commit["url"], - commit_timestamp: commit["timestamp"], + commit_note: commit['message'], + commit_url: commit['url'], + commit_timestamp: commit['timestamp'], repository: payload.repository.name, repository_url: payload.repository.homepage, gitlab_user: payload.user_name, diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handlers.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handlers.rb index 5492be055cb9..e157bbddf651 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handlers.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/notification_handlers.rb @@ -27,12 +27,12 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require_relative "notification_handler/helper" -require_relative "notification_handler/issue_hook" -require_relative "notification_handler/merge_request_hook" -require_relative "notification_handler/note_hook" -require_relative "notification_handler/push_hook" -require_relative "notification_handler/system_hook" +require_relative 'notification_handler/helper' +require_relative 'notification_handler/issue_hook' +require_relative 'notification_handler/merge_request_hook' +require_relative 'notification_handler/note_hook' +require_relative 'notification_handler/push_hook' +require_relative 'notification_handler/system_hook' module OpenProject::GitlabIntegration ## @@ -40,37 +40,37 @@ module OpenProject::GitlabIntegration module NotificationHandlers class << self def merge_request_hook(payload) - with_logging("merge_request_hook") do + with_logging('merge_request_hook') do OpenProject::GitlabIntegration::NotificationHandler::MergeRequestHook.new.process(payload) end end def note_hook(payload) - with_logging("note_hook") do + with_logging('note_hook') do OpenProject::GitlabIntegration::NotificationHandler::NoteHook.new.process(payload) end end def push_hook(payload) - with_logging("push_hook") do + with_logging('push_hook') do OpenProject::GitlabIntegration::NotificationHandler::PushHook.new.process(payload) end end def issue_hook(payload) - with_logging("issue_hook") do + with_logging('issue_hook') do OpenProject::GitlabIntegration::NotificationHandler::IssueHook.new.process(payload) end end def pipeline_hook(payload) - with_logging("pipeline_hook") do + with_logging('pipeline_hook') do OpenProject::GitlabIntegration::NotificationHandler::PipelineHook.new.process(payload) end end def system_hook(payload) - with_logging("system_hook") do + with_logging('system_hook') do OpenProject::GitlabIntegration::NotificationHandler::SystemHook.new.process(payload) end end diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/services.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/services.rb index f8e9d5526fc2..ea44e1735213 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/services.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/services.rb @@ -27,7 +27,7 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require_relative "services/params_helper" -require_relative "services/upsert_pipeline" -require_relative "services/upsert_gitlab_user" -require_relative "services/upsert_merge_request" +require_relative 'services/params_helper' +require_relative 'services/upsert_pipeline' +require_relative 'services/upsert_gitlab_user' +require_relative 'services/upsert_merge_request' diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/params_helper.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/params_helper.rb index 0769492f72b1..ef7a9355c03e 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/params_helper.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/params_helper.rb @@ -34,8 +34,8 @@ module Services module ParamsHelper private - EMPTY_AVATAR_URL = "https://www.gravatar.com/avatar/?d=mp" - EMPTY_DESCRIPTION = "No description provided" + EMPTY_AVATAR_URL = 'https://www.gravatar.com/avatar/?d=mp' + EMPTY_DESCRIPTION = 'No description provided' def avatar_url(raw_url) raw_url.presence || EMPTY_AVATAR_URL diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue.rb index 5d70838cb1ff..6eb2298d5f9c 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue.rb @@ -69,8 +69,8 @@ def extract_params(payload) def extract_label_values(payload) { - title: payload["title"], - color: payload["color"] + title: payload['title'], + color: payload['color'] } end diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue_note.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue_note.rb index 8516896740b2..eb58b8e83e33 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue_note.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_issue_note.rb @@ -69,8 +69,8 @@ def extract_params(payload) def extract_label_values(payload) { - title: payload["title"], - color: payload["color"] + title: payload['title'], + color: payload['color'] } end diff --git a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_merge_request.rb b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_merge_request.rb index d81edc88e7dd..78c8c0ccfa00 100644 --- a/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_merge_request.rb +++ b/modules/gitlab_integration/lib/open_project/gitlab_integration/services/upsert_merge_request.rb @@ -63,9 +63,9 @@ def extract_params(payload) body: description(payload.object_attributes.description), repository: payload.repository.name, draft: payload.object_attributes.work_in_progress, - merged: payload.object_attributes.state == "merged", + merged: payload.object_attributes.state == 'merged', merged_by: gitlab_user_id(payload.user), - merged_at: payload.object_attributes.state == "merged" ? payload.object_attributes.updated_at : nil, + merged_at: payload.object_attributes.state == 'merged' ? payload.object_attributes.updated_at : nil, labels: payload.labels.map { |values| extract_label_values(values) } } end @@ -73,8 +73,8 @@ def extract_params(payload) def extract_label_values(payload) { - title: payload["title"], - color: payload["color"] + title: payload['title'], + color: payload['color'] } end diff --git a/modules/gitlab_integration/lib/openproject-gitlab_integration.rb b/modules/gitlab_integration/lib/openproject-gitlab_integration.rb index e7499bfa3211..146bd94ac4ef 100644 --- a/modules/gitlab_integration/lib/openproject-gitlab_integration.rb +++ b/modules/gitlab_integration/lib/openproject-gitlab_integration.rb @@ -27,4 +27,4 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "open_project/gitlab_integration" +require 'open_project/gitlab_integration' diff --git a/modules/gitlab_integration/openproject-gitlab_integration.gemspec b/modules/gitlab_integration/openproject-gitlab_integration.gemspec index 2bc97fd50061..11f7f31bebe8 100644 --- a/modules/gitlab_integration/openproject-gitlab_integration.gemspec +++ b/modules/gitlab_integration/openproject-gitlab_integration.gemspec @@ -31,17 +31,17 @@ #++ Gem::Specification.new do |s| - s.name = "openproject-gitlab_integration" - s.version = "3.0.0" - s.authors = "OpenProject GmbH, Ben Tey" + s.name = 'openproject-gitlab_integration' + s.version = '3.0.0' + s.authors = 'OpenProject GmbH, Ben Tey' s.email = "info@openproject.com" s.homepage = "https://www.openproject.org/docs/system-admin-guide/integrations/gitlab-integration/" - s.summary = "OpenProject GitLab Integration" - s.description = "Integrates OpenProject and GitLab for a better workflow" - s.license = "GPLv3" + s.summary = 'OpenProject GitLab Integration' + s.description = 'Integrates OpenProject and GitLab for a better workflow' + s.license = 'GPLv3' - s.files = Dir["{app,config,db,frontend,lib}/**/*"] + %w[README.md] + s.files = Dir['{app,config,db,frontend,lib}/**/*'] + %w[README.md] - s.add_dependency "openproject-webhooks" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'openproject-webhooks' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/gitlab_integration/spec/factories/gitlab_issues.rb b/modules/gitlab_integration/spec/factories/gitlab_issues.rb index 663d77eee093..46516f3481f1 100644 --- a/modules/gitlab_integration/spec/factories/gitlab_issues.rb +++ b/modules/gitlab_integration/spec/factories/gitlab_issues.rb @@ -32,7 +32,7 @@ sequence(:number) sequence(:gitlab_id) - state { "opened" } + state { 'opened' } gitlab_html_url { "https://gitlab.com/test_user/test_repo/issues/#{number}" } labels { [] } @@ -46,11 +46,11 @@ end trait :open do - state { "opened" } + state { 'opened' } end trait :closed do - state { "closed" } + state { 'closed' } end end end diff --git a/modules/gitlab_integration/spec/factories/gitlab_merge_requests.rb b/modules/gitlab_integration/spec/factories/gitlab_merge_requests.rb index 0a35a33ba3fc..d8a137fde4cb 100644 --- a/modules/gitlab_integration/spec/factories/gitlab_merge_requests.rb +++ b/modules/gitlab_integration/spec/factories/gitlab_merge_requests.rb @@ -32,7 +32,7 @@ sequence(:number) sequence(:gitlab_id) - state { "opened" } + state { 'opened' } gitlab_html_url { "https://gitlab.com/test_user/test_repo/merge/#{number}" } labels { [] } @@ -57,11 +57,11 @@ trait :open trait :closed_unmerged do - state { "closed" } + state { 'closed' } end trait :closed_merged do - state { "merged" } + state { 'merged' } merged { true } merged_by { association :gitlab_user } merged_at { Time.current } diff --git a/modules/gitlab_integration/spec/factories/gitlab_pipelines.rb b/modules/gitlab_integration/spec/factories/gitlab_pipelines.rb index ea626aa24796..523c03721f57 100644 --- a/modules/gitlab_integration/spec/factories/gitlab_pipelines.rb +++ b/modules/gitlab_integration/spec/factories/gitlab_pipelines.rb @@ -38,7 +38,7 @@ details_url { "https://gitlab.com/test_user/test_repo/commit/#{commit_id}" } gitlab_html_url { "https://gitlab.com/test_user/test_repo/pipelines/#{gitlab_id}" } gitlab_user_avatar_url { "https://www.gravatar.com/avatar/#{gitlab_id}/owner.jpg" } - status { "pending" } + status { 'pending' } started_at { 1.hour.ago } completed_at { nil } project_id { 1 } @@ -48,7 +48,7 @@ end trait :complete do - status { "success" } + status { 'success' } completed_at { 1.minute.ago } end @@ -61,14 +61,14 @@ end end - factory :gitlab_pipeline_ci_detail, class: "Hash" do + factory :gitlab_pipeline_ci_detail, class: 'Hash' do skip_create initialize_with { attributes } stage { %w[test build deploy].sample } sequence(:name) { |n| "job_#{n}" } - status { "success" } + status { 'success' } started_at { 1.hour.ago } created_at { started_at } finished_at { nil } diff --git a/modules/gitlab_integration/spec/features/work_package_gitlab_issue_activity_spec.rb b/modules/gitlab_integration/spec/features/work_package_gitlab_issue_activity_spec.rb index 858596c24570..536e5ecfc622 100644 --- a/modules/gitlab_integration/spec/features/work_package_gitlab_issue_activity_spec.rb +++ b/modules/gitlab_integration/spec/features/work_package_gitlab_issue_activity_spec.rb @@ -1,19 +1,19 @@ # frozen_string_literal: true -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package Activity Tab", - "Comments by Gitlab", +RSpec.describe 'Work Package Activity Tab', + 'Comments by Gitlab', :js, :with_cuprite do - shared_let(:gitlab_system_user) { create(:admin, firstname: "Gitlab", lastname: "System User") } + shared_let(:gitlab_system_user) { create(:admin, firstname: 'Gitlab', lastname: 'System User') } shared_let(:admin) { create(:admin) } shared_let(:project) { create(:project, enabled_module_names: Setting.default_projects_modules + %w[activity]) } shared_let(:work_package) { create(:work_package, project:) } - shared_let(:issue_author) { create(:gitlab_user, gitlab_username: "i_am_the_author") } - shared_let(:issue_closing_user) { create(:gitlab_user, gitlab_username: "i_closed") } + shared_let(:issue_author) { create(:gitlab_user, gitlab_username: 'i_am_the_author') } + shared_let(:issue_closing_user) { create(:gitlab_user, gitlab_username: 'i_closed') } shared_let(:issue) do create(:gitlab_issue, @@ -28,51 +28,51 @@ def trigger_issue_action end let(:mr_description) { "Mentioning OP##{work_package.id}" } - let(:gitlab_action) { "close" } - let(:issue_state) { "closed" } + let(:gitlab_action) { 'close' } + let(:issue_state) { 'closed' } let(:labels) { [] } let(:payload) do { - "open_project_user_id" => gitlab_system_user.id, - "object_kind" => "issue", - "event_type" => "issue", - "user" => { - "id" => issue_closing_user.gitlab_id, - "name" => issue_closing_user.gitlab_name, - "username" => issue_closing_user.gitlab_username, - "avatar_url" => issue_closing_user.gitlab_avatar_url, - "email" => issue_closing_user.gitlab_email + 'open_project_user_id' => gitlab_system_user.id, + 'object_kind' => "issue", + 'event_type' => "issue", + 'user' => { + 'id' => issue_closing_user.gitlab_id, + 'name' => issue_closing_user.gitlab_name, + 'username' => issue_closing_user.gitlab_username, + 'avatar_url' => issue_closing_user.gitlab_avatar_url, + 'email' => issue_closing_user.gitlab_email }, - "object_attributes" => { - "action" => gitlab_action, - "assignee_id" => nil, - "author_id" => 1, - "created_at" => "2024-03-04 16:09:08 UTC", - "title" => "An Issue title", - "description" => mr_description, - "draft" => false, - "work_in_progress" => false, - "state" => issue_state, - "id" => issue.gitlab_id, - "iid" => issue.gitlab_id, - "head_pipeline_id" => nil, - "url" => "http://79dfcd98b723/root/hot_do/-/issues/4", - "updated_at" => Time.current.iso8601 + 'object_attributes' => { + 'action' => gitlab_action, + 'assignee_id' => nil, + 'author_id' => 1, + 'created_at' => '2024-03-04 16:09:08 UTC', + 'title' => 'An Issue title', + 'description' => mr_description, + 'draft' => false, + 'work_in_progress' => false, + 'state' => issue_state, + 'id' => issue.gitlab_id, + 'iid' => issue.gitlab_id, + 'head_pipeline_id' => nil, + 'url' => 'http://79dfcd98b723/root/hot_do/-/issues/4', + 'updated_at' => Time.current.iso8601 }, - "labels" => labels, - "repository" => { - "name" => "Hot Do", - "url" => "git@79dfcd98b723:root/hot_do.git", - "description" => nil, - "homepage" => "http://79dfcd98b723/root/hot_do/-/issues/4" + 'labels' => labels, + 'repository' => { + 'name' => "Hot Do", + 'url' => "git@79dfcd98b723:root/hot_do.git", + 'description' => nil, + 'homepage' => 'http://79dfcd98b723/root/hot_do/-/issues/4' } } end let(:work_package_page) { Pages::SplitWorkPackage.new(work_package, project) } - context "when there is an issue event" do + context 'when there is an issue event' do before do trigger_issue_action login_as admin @@ -80,7 +80,7 @@ def trigger_issue_action context "and I visit the work package's activity tab" do before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded end @@ -89,8 +89,8 @@ def trigger_issue_action "has been closed by #{issue_closing_user.gitlab_name}." end - it "renders a comment referencing the issue" do - expect(page).to have_css(".user-comment > .message", text: expected_comment) + it 'renders a comment referencing the issue' do + expect(page).to have_css('.user-comment > .message', text: expected_comment) end end end diff --git a/modules/gitlab_integration/spec/features/work_package_gitlab_merge_request_activity_spec.rb b/modules/gitlab_integration/spec/features/work_package_gitlab_merge_request_activity_spec.rb index 76ec3815e85a..c018ba365879 100644 --- a/modules/gitlab_integration/spec/features/work_package_gitlab_merge_request_activity_spec.rb +++ b/modules/gitlab_integration/spec/features/work_package_gitlab_merge_request_activity_spec.rb @@ -1,19 +1,19 @@ # frozen_string_literal: true -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package Activity Tab", - "Comments by Gitlab", +RSpec.describe 'Work Package Activity Tab', + 'Comments by Gitlab', :js, :with_cuprite do - shared_let(:gitlab_system_user) { create(:admin, firstname: "Gitlab", lastname: "System User") } + shared_let(:gitlab_system_user) { create(:admin, firstname: 'Gitlab', lastname: 'System User') } shared_let(:admin) { create(:admin) } shared_let(:project) { create(:project, enabled_module_names: Setting.default_projects_modules + %w[activity]) } shared_let(:work_package) { create(:work_package, project:) } - shared_let(:merge_request_author) { create(:gitlab_user, gitlab_username: "i_am_the_author") } - shared_let(:merge_request_merging_user) { create(:gitlab_user, gitlab_username: "i_merged") } + shared_let(:merge_request_author) { create(:gitlab_user, gitlab_username: 'i_am_the_author') } + shared_let(:merge_request_merging_user) { create(:gitlab_user, gitlab_username: 'i_merged') } shared_let(:merge_request) do create(:gitlab_merge_request, gitlab_user: merge_request_author) @@ -27,51 +27,51 @@ def trigger_merge_request_action end let(:mr_description) { "Mentioning OP##{work_package.id}" } - let(:gitlab_action) { "merge" } - let(:mr_state) { "merged" } + let(:gitlab_action) { 'merge' } + let(:mr_state) { 'merged' } let(:mr_draft) { false } let(:payload) do { - "open_project_user_id" => gitlab_system_user.id, - "object_kind" => "merge_request", - "event_type" => "merge_request", - "user" => { - "id" => merge_request_merging_user.gitlab_id, - "name" => merge_request_merging_user.gitlab_name, - "username" => merge_request_merging_user.gitlab_username, - "avatar_url" => merge_request_merging_user.gitlab_avatar_url, - "email" => merge_request_merging_user.gitlab_email + 'open_project_user_id' => gitlab_system_user.id, + 'object_kind' => "merge_request", + 'event_type' => "merge_request", + 'user' => { + 'id' => merge_request_merging_user.gitlab_id, + 'name' => merge_request_merging_user.gitlab_name, + 'username' => merge_request_merging_user.gitlab_username, + 'avatar_url' => merge_request_merging_user.gitlab_avatar_url, + 'email' => merge_request_merging_user.gitlab_email }, - "object_attributes" => { - "action" => gitlab_action, - "assignee_id" => nil, - "author_id" => 1, - "created_at" => "2024-03-04 16:09:08 UTC", - "title" => "A MR title", - "description" => mr_description, - "draft" => mr_draft, - "work_in_progress" => mr_draft, - "state" => mr_state, - "head_pipeline_id" => nil, - "id" => merge_request.gitlab_id, - "iid" => merge_request.gitlab_id, - "url" => "http://79dfcd98b723/root/hot_do/-/merge_requests/4", - "updated_at" => Time.current.iso8601 + 'object_attributes' => { + 'action' => gitlab_action, + 'assignee_id' => nil, + 'author_id' => 1, + 'created_at' => '2024-03-04 16:09:08 UTC', + 'title' => 'A MR title', + 'description' => mr_description, + 'draft' => mr_draft, + 'work_in_progress' => mr_draft, + 'state' => mr_state, + 'head_pipeline_id' => nil, + 'id' => merge_request.gitlab_id, + 'iid' => merge_request.gitlab_id, + 'url' => 'http://79dfcd98b723/root/hot_do/-/merge_requests/4', + 'updated_at' => Time.current.iso8601 }, - "labels" => [], - "repository" => { - "name" => "Hot Do", - "url" => "git@79dfcd98b723:root/hot_do.git", - "description" => nil, - "homepage" => "http://79dfcd98b723/root/hot_do/-/merge_requests/4" + 'labels' => [], + 'repository' => { + 'name' => "Hot Do", + 'url' => "git@79dfcd98b723:root/hot_do.git", + 'description' => nil, + 'homepage' => 'http://79dfcd98b723/root/hot_do/-/merge_requests/4' } } end let(:work_package_page) { Pages::SplitWorkPackage.new(work_package, project) } - context "when there is a merge request event" do + context 'when there is a merge request event' do before do trigger_merge_request_action login_as admin @@ -79,7 +79,7 @@ def trigger_merge_request_action context "and I visit the work package's activity tab" do before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded end @@ -89,8 +89,8 @@ def trigger_merge_request_action "#{merge_request_merging_user.gitlab_name}." end - it "renders a comment referencing the Merge Request" do - expect(page).to have_css(".user-comment > .message", text: expected_comment) + it 'renders a comment referencing the Merge Request' do + expect(page).to have_css('.user-comment > .message', text: expected_comment) end end end diff --git a/modules/gitlab_integration/spec/features/work_package_gitlab_tab_spec.rb b/modules/gitlab_integration/spec/features/work_package_gitlab_tab_spec.rb index 60ad20ef554b..dc9d8f35015c 100644 --- a/modules/gitlab_integration/spec/features/work_package_gitlab_tab_spec.rb +++ b/modules/gitlab_integration/spec/features/work_package_gitlab_tab_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "../support/pages/work_package_gitlab_tab" +require_relative '../support/pages/work_package_gitlab_tab' -RSpec.describe "Open the Gitlab tab", :js do +RSpec.describe 'Open the Gitlab tab', :js do let(:user) { create(:user, member_with_roles: { project => role }) } let(:role) do @@ -45,17 +45,17 @@ enabled_module_names: %i[work_package_tracking gitlab]) end - let(:work_package) { create(:work_package, project:, subject: "A test work_package") } + let(:work_package) { create(:work_package, project:, subject: 'A test work_package') } let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } - let(:gitlab_tab_element) { find(".op-tab-row--link_selected", text: "GITLAB") } + let(:gitlab_tab_element) { find('.op-tab-row--link_selected', text: 'GITLAB') } let(:gitlab_tab) { Pages::GitlabTab.new(work_package.id) } - let(:issue) { create(:gitlab_issue, :open, work_packages: [work_package], title: "A Test Issue title") } - let(:merge_request) { create(:gitlab_merge_request, :open, work_packages: [work_package], title: "A Test MR title") } + let(:issue) { create(:gitlab_issue, :open, work_packages: [work_package], title: 'A Test Issue title') } + let(:merge_request) { create(:gitlab_merge_request, :open, work_packages: [work_package], title: 'A Test MR title') } let(:pipeline) do - create(:gitlab_pipeline, gitlab_merge_request: merge_request, name: "a pipeline name") + create(:gitlab_pipeline, gitlab_merge_request: merge_request, name: 'a pipeline name') end shared_examples_for "a gitlab tab" do @@ -68,72 +68,72 @@ # compares the clipboard content by drafting a new comment, pressing ctrl+v and # comparing the pasted content against the provided text def expect_clipboard_content(text) - work_package_page.switch_to_tab(tab: "activity") + work_package_page.switch_to_tab(tab: 'activity') work_package_page.trigger_edit_comment - work_package_page.update_comment(" ") # ensure the comment editor is fully loaded + work_package_page.update_comment(' ') # ensure the comment editor is fully loaded gitlab_tab.paste_clipboard_content expect(work_package_page.add_comment_container).to have_content(text) - work_package_page.switch_to_tab(tab: "gitlab") + work_package_page.switch_to_tab(tab: 'gitlab') end - it "shows the gitlab tab when the user is allowed to see it" do + it 'shows the gitlab tab when the user is allowed to see it' do work_package_page.visit! - work_package_page.switch_to_tab(tab: "gitlab") + work_package_page.switch_to_tab(tab: 'gitlab') tabs.expect_counter(gitlab_tab_element, 2) gitlab_tab.git_actions_menu_button.click gitlab_tab.git_actions_copy_branch_name_button.click - expect(page).to have_text("Copied!") + expect(page).to have_text('Copied!') expect_clipboard_content("#{work_package.type.name.downcase}/#{work_package.id}-a-test-work_package") - expect(page).to have_text("A Test Issue title") - expect(page).to have_text("Open") + expect(page).to have_text('A Test Issue title') + expect(page).to have_text('Open') - expect(page).to have_text("A Test MR title") - expect(page).to have_text("Pending") + expect(page).to have_text('A Test MR title') + expect(page).to have_text('Pending') end - context "when there are no merge requests or issues" do + context 'when there are no merge requests or issues' do let(:pipeline) { nil } let(:merge_request) { nil } let(:issue) { nil } - it "shows the gitlab tab with an empty message" do + it 'shows the gitlab tab with an empty message' do work_package_page.visit! - work_package_page.switch_to_tab(tab: "gitlab") + work_package_page.switch_to_tab(tab: 'gitlab') tabs.expect_no_counter(gitlab_tab_element) - expect(page).to have_content("There are no issues linked yet.") + expect(page).to have_content('There are no issues linked yet.') expect(page).to have_content("Link an existing issue by using the code OP##{work_package.id} " \ "(or PP##{work_package.id} for private links) in the issue title/description " \ "or create a new issue") - expect(page).to have_content("There are no merge requests") + expect(page).to have_content('There are no merge requests') expect(page).to have_content("Link an existing MR by using the code OP##{work_package.id}") end end - context "when the user does not have the permissions to see the gitlab tab" do + context 'when the user does not have the permissions to see the gitlab tab' do let(:role) do create(:project_role, permissions: %i(view_work_packages add_work_package_notes)) end - it "does not show the gitlab tab" do + it 'does not show the gitlab tab' do work_package_page.visit! gitlab_tab.expect_tab_not_present end end - context "when the gitlab integration is not enabled for the project" do - let(:project) { create(:project, disable_modules: "gitlab") } + context 'when the gitlab integration is not enabled for the project' do + let(:project) { create(:project, disable_modules: 'gitlab') } - it "does not show the gitlab tab" do + it 'does not show the gitlab tab' do work_package_page.visit! gitlab_tab.expect_tab_not_present @@ -141,15 +141,15 @@ def expect_clipboard_content(text) end end - describe "work package full view" do + describe 'work package full view' do let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "a gitlab tab" + it_behaves_like 'a gitlab tab' end - describe "work package split view" do + describe 'work package split view' do let(:work_package_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "a gitlab tab" + it_behaves_like 'a gitlab tab' end end diff --git a/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_issue_representer_spec.rb b/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_issue_representer_spec.rb index 07a0bfdf9471..2abdb7603681 100644 --- a/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_issue_representer_spec.rb +++ b/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_issue_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::GitlabIssues::GitlabIssueRepresenter do @@ -36,15 +36,15 @@ let(:gitlab_issue) do build_stubbed(:gitlab_issue, - state: "opened", + state: 'opened', labels:, gitlab_user:) end let(:labels) do [ { - "name" => "grey", - "color" => "#666" + 'name' => 'grey', + 'color' => '#666' } ] end @@ -53,67 +53,67 @@ let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GitlabIssue".to_json).at_path("_type") } + it { is_expected.to include_json('GitlabIssue'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GitlabIssue" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GitlabIssue' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { gitlab_issue.id } end - it_behaves_like "property", :number do + it_behaves_like 'property', :number do let(:value) { gitlab_issue.number } end - it_behaves_like "property", :htmlUrl do + it_behaves_like 'property', :htmlUrl do let(:value) { gitlab_issue.gitlab_html_url } end - it_behaves_like "property", :state do + it_behaves_like 'property', :state do let(:value) { gitlab_issue.state } end - it_behaves_like "property", :repository do + it_behaves_like 'property', :repository do let(:value) { gitlab_issue.repository } end - it_behaves_like "property", :title do + it_behaves_like 'property', :title do let(:value) { gitlab_issue.title } end - it_behaves_like "formattable property", :body do + it_behaves_like 'formattable property', :body do let(:value) { gitlab_issue.body } end - it_behaves_like "property", :labels do + it_behaves_like 'property', :labels do let(:value) { gitlab_issue.labels } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { gitlab_issue.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { gitlab_issue.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - it_behaves_like "has a titled link" do - let(:link) { "gitlabUser" } + it_behaves_like 'has a titled link' do + let(:link) { 'gitlabUser' } let(:href) { api_v3_paths.gitlab_user(gitlab_user.id) } let(:title) { gitlab_user.gitlab_name } end end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -126,29 +126,29 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GitlabIssues", "GitlabIssueRepresenter") + .to include('API', 'V3', 'GitlabIssues', 'GitlabIssueRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the gitlab_issue is updated" do + it 'changes when the gitlab_issue is updated' do gitlab_issue.updated_at = 20.seconds.from_now expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the gitlab_user is updated" do + it 'changes when the gitlab_user is updated' do gitlab_issue.gitlab_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_user_representer_spec.rb b/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_user_representer_spec.rb index 904fcdc86642..488f4d2ed586 100644 --- a/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_user_representer_spec.rb +++ b/modules/gitlab_integration/spec/lib/api/v3/gitlab_issues/gitlab_user_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::GitlabIssues::GitlabUserRepresenter do @@ -39,32 +39,32 @@ let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GitlabUser".to_json).at_path("_type") } + it { is_expected.to include_json('GitlabUser'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GitlabUser" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GitlabUser' } end - it_behaves_like "property", :login do + it_behaves_like 'property', :login do let(:value) { gitlab_user.gitlab_name } end - it_behaves_like "property", :email do + it_behaves_like 'property', :email do let(:value) { gitlab_user.gitlab_email } end - it_behaves_like "property", :avatarUrl do + it_behaves_like 'property', :avatarUrl do let(:value) { gitlab_user.gitlab_avatar_url } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } - it { is_expected.to have_json_path("_links/self/href") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } + it { is_expected.to have_json_path('_links/self/href') } end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -77,22 +77,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GitlabIssues", "GitlabUserRepresenter") + .to include('API', 'V3', 'GitlabIssues', 'GitlabUserRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the gitlab_user is updated" do + it 'changes when the gitlab_user is updated' do gitlab_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer_spec.rb b/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer_spec.rb index 2f2546e0c830..02c7261412ea 100644 --- a/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer_spec.rb +++ b/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_merge_request_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::GitlabMergeRequests::GitlabMergeRequestRepresenter do @@ -36,7 +36,7 @@ let(:gitlab_merge_request) do build_stubbed(:gitlab_merge_request, - state: "opened", + state: 'opened', labels:, gitlab_user:, merged_by:).tap do |pr| @@ -48,8 +48,8 @@ let(:labels) do [ { - "name" => "grey", - "color" => "#666" + 'name' => 'grey', + 'color' => '#666' } ] end @@ -61,98 +61,98 @@ let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GitlabMergeRequest".to_json).at_path("_type") } + it { is_expected.to include_json('GitlabMergeRequest'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GitlabMergeRequest" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GitlabMergeRequest' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { gitlab_merge_request.id } end - it_behaves_like "property", :number do + it_behaves_like 'property', :number do let(:value) { gitlab_merge_request.number } end - it_behaves_like "property", :htmlUrl do + it_behaves_like 'property', :htmlUrl do let(:value) { gitlab_merge_request.gitlab_html_url } end - it_behaves_like "property", :state do + it_behaves_like 'property', :state do let(:value) { gitlab_merge_request.state } end - it_behaves_like "property", :repository do + it_behaves_like 'property', :repository do let(:value) { gitlab_merge_request.repository } end - it_behaves_like "property", :title do + it_behaves_like 'property', :title do let(:value) { gitlab_merge_request.title } end - it_behaves_like "formattable property", :body do + it_behaves_like 'formattable property', :body do let(:value) { gitlab_merge_request.body } end - it_behaves_like "property", :draft do + it_behaves_like 'property', :draft do let(:value) { gitlab_merge_request.draft } end - it_behaves_like "property", :merged do + it_behaves_like 'property', :merged do let(:value) { gitlab_merge_request.merged } end - it_behaves_like "property", :labels do + it_behaves_like 'property', :labels do let(:value) { gitlab_merge_request.labels } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { gitlab_merge_request.gitlab_updated_at } - let(:json_path) { "gitlabUpdatedAt" } + let(:json_path) { 'gitlabUpdatedAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { gitlab_merge_request.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { gitlab_merge_request.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - it_behaves_like "has a titled link" do - let(:link) { "gitlabUser" } + it_behaves_like 'has a titled link' do + let(:link) { 'gitlabUser' } let(:href) { api_v3_paths.gitlab_user(gitlab_user.id) } let(:title) { gitlab_user.gitlab_name } end - it_behaves_like "has a titled link" do - let(:link) { "mergedBy" } + it_behaves_like 'has a titled link' do + let(:link) { 'mergedBy' } let(:href) { api_v3_paths.gitlab_user(merged_by.id) } let(:title) { merged_by.gitlab_name } end - it_behaves_like "has a link collection" do - let(:link) { "pipelines" } + it_behaves_like 'has a link collection' do + let(:link) { 'pipelines' } let(:hrefs) do [ { - "href" => api_v3_paths.gitlab_pipeline(pipeline.id), - "title" => pipeline.name + 'href' => api_v3_paths.gitlab_pipeline(pipeline.id), + 'title' => pipeline.name } ] end end end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -165,36 +165,36 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GitlabMergeRequests", "GitlabMergeRequestRepresenter") + .to include('API', 'V3', 'GitlabMergeRequests', 'GitlabMergeRequestRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the gitlab_merge_request is updated" do + it 'changes when the gitlab_merge_request is updated' do gitlab_merge_request.updated_at = 20.seconds.from_now expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the gitlab_user is updated" do + it 'changes when the gitlab_user is updated' do gitlab_merge_request.gitlab_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the merged_by user is updated" do + it 'changes when the merged_by user is updated' do gitlab_merge_request.merged_by.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer_spec.rb b/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer_spec.rb index 7fd0aa7ff7b4..683566c2677c 100644 --- a/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer_spec.rb +++ b/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_pipeline_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::GitlabMergeRequests::GitlabPipelineRepresenter do @@ -38,62 +38,62 @@ let(:representer) { described_class.create(pipeline, current_user: user) } let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GitlabPipeline".to_json).at_path("_type") } + it { is_expected.to include_json('GitlabPipeline'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GitlabPipeline" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GitlabPipeline' } end - it_behaves_like "property", :htmlUrl do + it_behaves_like 'property', :htmlUrl do let(:value) { pipeline.gitlab_html_url } end - it_behaves_like "property", :userAvatarUrl do + it_behaves_like 'property', :userAvatarUrl do let(:value) { pipeline.gitlab_user_avatar_url } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { pipeline.name } end - it_behaves_like "property", :status do + it_behaves_like 'property', :status do let(:value) { pipeline.status } end - it_behaves_like "property", :detailsUrl do + it_behaves_like 'property', :detailsUrl do let(:value) { pipeline.details_url } end - it_behaves_like "property", :ciDetails do + it_behaves_like 'property', :ciDetails do let(:value) { pipeline.ci_details } end - it_behaves_like "property", :username do + it_behaves_like 'property', :username do let(:value) { pipeline.username } end - it_behaves_like "property", :commitId do + it_behaves_like 'property', :commitId do let(:value) { pipeline.commit_id } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { pipeline.started_at } - let(:json_path) { "startedAt" } + let(:json_path) { 'startedAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { pipeline.completed_at } - let(:json_path) { "completedAt" } + let(:json_path) { 'completedAt' } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } - it { is_expected.to have_json_path("_links/self/href") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } + it { is_expected.to have_json_path('_links/self/href') } end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -106,22 +106,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GitlabMergeRequests", "GitlabPipelineRepresenter") + .to include('API', 'V3', 'GitlabMergeRequests', 'GitlabPipelineRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the check run is updated" do + it 'changes when the check run is updated' do pipeline.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_user_representer_spec.rb b/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_user_representer_spec.rb index a3babd06c351..e50adcdfc0c2 100644 --- a/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_user_representer_spec.rb +++ b/modules/gitlab_integration/spec/lib/api/v3/gitlab_merge_requests/gitlab_user_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::GitlabMergeRequests::GitlabUserRepresenter do @@ -39,32 +39,32 @@ let(:user) { build_stubbed(:admin) } - it { is_expected.to include_json("GitlabUser".to_json).at_path("_type") } + it { is_expected.to include_json('GitlabUser'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "GitlabUser" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'GitlabUser' } end - it_behaves_like "property", :login do + it_behaves_like 'property', :login do let(:value) { gitlab_user.gitlab_name } end - it_behaves_like "property", :email do + it_behaves_like 'property', :email do let(:value) { gitlab_user.gitlab_email } end - it_behaves_like "property", :avatarUrl do + it_behaves_like 'property', :avatarUrl do let(:value) { gitlab_user.gitlab_avatar_url } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } - it { is_expected.to have_json_path("_links/self/href") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } + it { is_expected.to have_json_path('_links/self/href') } end - describe "caching" do + describe 'caching' do before do allow(OpenProject::Cache).to receive(:fetch).and_call_original end @@ -77,22 +77,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "GitlabMergeRequests", "GitlabUserRepresenter") + .to include('API', 'V3', 'GitlabMergeRequests', 'GitlabUserRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the gitlab_user is updated" do + it 'changes when the gitlab_user is updated' do gitlab_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/issue_hook_spec.rb b/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/issue_hook_spec.rb index 812ae950622d..cea60477e6fa 100644 --- a/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/issue_hook_spec.rb +++ b/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/issue_hook_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe OpenProject::GitlabIntegration::NotificationHandler::IssueHook do @@ -40,45 +40,45 @@ let(:gitlab_issue) { GitlabIssue.find_by_gitlab_identifiers(id: 5) } let(:mr_description) { "Mentioning OP##{work_package.id}" } - let(:gitlab_action) { "open" } - let(:issue_state) { "opened" } + let(:gitlab_action) { 'open' } + let(:issue_state) { 'opened' } let(:issue_draft) { false } let(:labels) { [] } let(:payload) do { - "open_project_user_id" => gitlab_system_user.id, - "object_kind" => "issue", - "event_type" => "issue", - "user" => { - "id" => 1, - "name" => "Administrator", - "username" => "root", - "avatar_url" => "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", - "email" => "[REDACTED]" + 'open_project_user_id' => gitlab_system_user.id, + 'object_kind' => "issue", + 'event_type' => "issue", + 'user' => { + 'id' => 1, + 'name' => "Administrator", + 'username' => "root", + 'avatar_url' => "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", + 'email' => "[REDACTED]" }, - "object_attributes" => { - "action" => gitlab_action, - "assignee_id" => nil, - "author_id" => 1, - "created_at" => "2024-03-04 16:09:08 UTC", - "title" => "An Issue title", - "description" => mr_description, - "draft" => issue_draft, - "work_in_progress" => issue_draft, - "state" => issue_state, - "id" => 5, - "iid" => 5, - "head_pipeline_id" => nil, - "url" => "http://79dfcd98b723/root/hot_do/-/issues/4", - "updated_at" => Time.current.iso8601 + 'object_attributes' => { + 'action' => gitlab_action, + 'assignee_id' => nil, + 'author_id' => 1, + 'created_at' => '2024-03-04 16:09:08 UTC', + 'title' => 'An Issue title', + 'description' => mr_description, + 'draft' => issue_draft, + 'work_in_progress' => issue_draft, + 'state' => issue_state, + 'id' => 5, + 'iid' => 5, + 'head_pipeline_id' => nil, + 'url' => 'http://79dfcd98b723/root/hot_do/-/issues/4', + 'updated_at' => Time.current.iso8601 }, - "labels" => labels, - "repository" => { - "name" => "Hot Do", - "url" => "git@79dfcd98b723:root/hot_do.git", - "description" => nil, - "homepage" => "http://79dfcd98b723/root/hot_do/-/issues/4" + 'labels' => labels, + 'repository' => { + 'name' => "Hot Do", + 'url' => "git@79dfcd98b723:root/hot_do.git", + 'description' => nil, + 'homepage' => 'http://79dfcd98b723/root/hot_do/-/issues/4' } } end @@ -89,15 +89,15 @@ allow(upsert_service).to receive(:call).and_call_original end - shared_examples_for "not adding a comment" do - it "does not add comments to work packages" do + shared_examples_for 'not adding a comment' do + it 'does not add comments to work packages' do process expect(handler_instance).not_to have_received(:comment_on_referenced_work_packages) end end - shared_examples_for "adding a comment" do - it "adds a comment to the work packages" do + shared_examples_for 'adding a comment' do + it 'adds a comment to the work packages' do process expect(handler_instance).to have_received(:comment_on_referenced_work_packages).with( [work_package], @@ -107,37 +107,37 @@ end end - shared_examples_for "calls the issue upsert service" do - it "calls the issue upsert service" do + shared_examples_for 'calls the issue upsert service' do + it 'calls the issue upsert service' do process expect(upsert_service).to have_received(:call) .with(a_kind_of(OpenProject::GitlabIntegration::NotificationHandler::Helper::Payload), work_packages: [work_package]) end - context "when no work_package was mentioned" do - let(:mr_description) { "some text that does not mention any work package" } + context 'when no work_package was mentioned' do + let(:mr_description) { 'some text that does not mention any work package' } - it "does not call the issue upsert service" do + it 'does not call the issue upsert service' do process expect(upsert_service).not_to have_received(:call) end end end - context "with an opened action" do + context 'with an opened action' do let(:comment) do "**Issue Opened:** Issue 5 [An Issue title](http://79dfcd98b723/root/hot_do/-/issues/4) for " \ "[Hot Do](http://79dfcd98b723/root/hot_do/-/issues/4) has been opened by " \ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the issue upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the issue upsert service' end - context "with a closed action" do - let(:gitlab_action) { "close" } - let(:issue_state) { "closed" } + context 'with a closed action' do + let(:gitlab_action) { 'close' } + let(:issue_state) { 'closed' } let(:comment) do "**Issue Closed:** Issue 5 [An Issue title](http://79dfcd98b723/root/hot_do/-/issues/4) for " \ @@ -145,16 +145,16 @@ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the issue upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the issue upsert service' - context "when the work package is already known to the GitlabIssue" do + context 'when the work package is already known to the GitlabIssue' do let!(:gitlab_issue) { create(:gitlab_issue, gitlab_id: 5, work_packages: [work_package]) } - it_behaves_like "adding a comment" + it_behaves_like 'adding a comment' - it "calls the issue upsert service" do - expect { process }.to change { gitlab_issue.reload.state }.from("opened").to("closed") + it 'calls the issue upsert service' do + expect { process }.to change { gitlab_issue.reload.state }.from('opened').to('closed') expect(upsert_service).to have_received(:call).with( a_kind_of(OpenProject::GitlabIntegration::NotificationHandler::Helper::Payload), work_packages: [work_package] ) @@ -162,10 +162,10 @@ end end - context "with a labeled action" do + context 'with a labeled action' do let!(:gitlab_issue) { create(:gitlab_issue, gitlab_id: 5, work_packages: [work_package]) } - let(:gitlab_action) { "update" } - let(:issue_state) { "opened" } + let(:gitlab_action) { 'update' } + let(:issue_state) { 'opened' } let(:labels) do [ @@ -201,9 +201,9 @@ # No comment is added when the labels are updated as there is no UI yet for labels supported by the plugin let(:comment) { nil } - it_behaves_like "adding a comment" + it_behaves_like 'adding a comment' - it "calls the issue upsert service with all work_packages" do + it 'calls the issue upsert service with all work_packages' do gitlab_issue = process.reload expect(gitlab_issue.labels).to eq([{ "title" => "feature", "color" => "#009966" }, { "title" => "needs review", "color" => "#9400d3" }]) @@ -213,9 +213,9 @@ end end - context "with a reopened action" do - let(:gitlab_action) { "reopen" } - let(:issue_state) { "opened" } + context 'with a reopened action' do + let(:gitlab_action) { 'reopen' } + let(:issue_state) { 'opened' } let(:comment) do "**Issue Reopened:** Issue 5 [An Issue title](http://79dfcd98b723/root/hot_do/-/issues/4) for " \ @@ -223,7 +223,7 @@ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the issue upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the issue upsert service' end end diff --git a/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/merge_request_hook_spec.rb b/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/merge_request_hook_spec.rb index 93ee37967e3b..8ae0e8ca2a2b 100644 --- a/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/merge_request_hook_spec.rb +++ b/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/merge_request_hook_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe OpenProject::GitlabIntegration::NotificationHandler::MergeRequestHook do @@ -40,45 +40,45 @@ let(:gitlab_merge_request) { GitlabMergeRequest.find_by_gitlab_identifiers(id: 4) } let(:mr_description) { "Mentioning OP##{work_package.id}" } - let(:gitlab_action) { "open" } - let(:mr_state) { "opened" } + let(:gitlab_action) { 'open' } + let(:mr_state) { 'opened' } let(:mr_draft) { false } let(:labels) { [] } let(:payload) do { - "open_project_user_id" => gitlab_system_user.id, - "object_kind" => "merge_request", - "event_type" => "merge_request", - "user" => { - "id" => 1, - "name" => "Administrator", - "username" => "root", - "avatar_url" => "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", - "email" => "[REDACTED]" + 'open_project_user_id' => gitlab_system_user.id, + 'object_kind' => "merge_request", + 'event_type' => "merge_request", + 'user' => { + 'id' => 1, + 'name' => "Administrator", + 'username' => "root", + 'avatar_url' => "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", + 'email' => "[REDACTED]" }, - "object_attributes" => { - "action" => gitlab_action, - "assignee_id" => nil, - "author_id" => 1, - "created_at" => "2024-03-04 16:09:08 UTC", - "title" => "A MR title", - "description" => mr_description, - "draft" => mr_draft, - "work_in_progress" => mr_draft, - "state" => mr_state, - "head_pipeline_id" => nil, - "id" => 4, - "iid" => 4, - "url" => "http://79dfcd98b723/root/hot_do/-/merge_requests/4", - "updated_at" => Time.current.iso8601 + 'object_attributes' => { + 'action' => gitlab_action, + 'assignee_id' => nil, + 'author_id' => 1, + 'created_at' => '2024-03-04 16:09:08 UTC', + 'title' => 'A MR title', + 'description' => mr_description, + 'draft' => mr_draft, + 'work_in_progress' => mr_draft, + 'state' => mr_state, + 'head_pipeline_id' => nil, + 'id' => 4, + 'iid' => 4, + 'url' => 'http://79dfcd98b723/root/hot_do/-/merge_requests/4', + 'updated_at' => Time.current.iso8601 }, - "labels" => labels, - "repository" => { - "name" => "Hot Do", - "url" => "git@79dfcd98b723:root/hot_do.git", - "description" => nil, - "homepage" => "http://79dfcd98b723/root/hot_do/-/merge_requests/4" + 'labels' => labels, + 'repository' => { + 'name' => "Hot Do", + 'url' => "git@79dfcd98b723:root/hot_do.git", + 'description' => nil, + 'homepage' => 'http://79dfcd98b723/root/hot_do/-/merge_requests/4' } } end @@ -89,15 +89,15 @@ allow(upsert_service).to receive(:call).and_call_original end - shared_examples_for "not adding a comment" do - it "does not add comments to work packages" do + shared_examples_for 'not adding a comment' do + it 'does not add comments to work packages' do process expect(handler_instance).not_to have_received(:comment_on_referenced_work_packages) end end - shared_examples_for "adding a comment" do - it "adds a comment to the work packages" do + shared_examples_for 'adding a comment' do + it 'adds a comment to the work packages' do process expect(handler_instance).to have_received(:comment_on_referenced_work_packages).with( [work_package], @@ -107,37 +107,37 @@ end end - shared_examples_for "calls the merge request upsert service" do - it "calls the merge request upsert service" do + shared_examples_for 'calls the merge request upsert service' do + it 'calls the merge request upsert service' do process expect(upsert_service).to have_received(:call) .with(a_kind_of(OpenProject::GitlabIntegration::NotificationHandler::Helper::Payload), work_packages: [work_package]) end - context "when no work_package was mentioned" do - let(:mr_description) { "some text that does not mention any work package" } + context 'when no work_package was mentioned' do + let(:mr_description) { 'some text that does not mention any work package' } - it "does not call the merge request upsert service" do + it 'does not call the merge request upsert service' do process expect(upsert_service).not_to have_received(:call) end end end - context "with an opened action" do + context 'with an opened action' do let(:comment) do "**MR Opened:** Merge request 4 [A MR title](http://79dfcd98b723/root/hot_do/-/merge_requests/4) for " \ "[Hot Do](git@79dfcd98b723:root/hot_do.git) has been opened by " \ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the merge request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the merge request upsert service' end - context "with a closed action" do - let(:gitlab_action) { "close" } - let(:mr_state) { "closed" } + context 'with a closed action' do + let(:gitlab_action) { 'close' } + let(:mr_state) { 'closed' } let(:comment) do "**MR Closed:** Merge request 4 [A MR title](http://79dfcd98b723/root/hot_do/-/merge_requests/4) for " \ @@ -145,13 +145,13 @@ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the merge request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the merge request upsert service' end - context "when the MR was merged" do - let(:gitlab_action) { "merge" } - let(:mr_state) { "merged" } + context 'when the MR was merged' do + let(:gitlab_action) { 'merge' } + let(:mr_state) { 'merged' } let(:comment) do "**MR Merged:** Merge request 4 [A MR title](http://79dfcd98b723/root/hot_do/-/merge_requests/4) for " \ @@ -159,16 +159,16 @@ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the merge request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the merge request upsert service' - context "when the work package is already known to the GitlabMergeRequest" do + context 'when the work package is already known to the GitlabMergeRequest' do let!(:gitlab_merge_request) { create(:gitlab_merge_request, gitlab_id: 4, work_packages: [work_package]) } - it_behaves_like "adding a comment" + it_behaves_like 'adding a comment' - it "calls the merge request upsert service" do - expect { process }.to change { gitlab_merge_request.reload.state }.from("opened").to("merged") + it 'calls the merge request upsert service' do + expect { process }.to change { gitlab_merge_request.reload.state }.from('opened').to('merged') expect(upsert_service).to have_received(:call).with( a_kind_of(OpenProject::GitlabIntegration::NotificationHandler::Helper::Payload), work_packages: [work_package] ) @@ -176,18 +176,18 @@ end end - context "when the MR is converted to draft" do - let(:gitlab_action) { "update" } - let(:mr_state) { "opened" } + context 'when the MR is converted to draft' do + let(:gitlab_action) { 'update' } + let(:mr_state) { 'opened' } let(:mr_draft) { true } - it_behaves_like "not adding a comment" - it_behaves_like "calls the merge request upsert service" + it_behaves_like 'not adding a comment' + it_behaves_like 'calls the merge request upsert service' end - context "with a labeled action" do - let(:gitlab_action) { "update" } - let(:mr_state) { "opened" } + context 'with a labeled action' do + let(:gitlab_action) { 'update' } + let(:mr_state) { 'opened' } let(:labels) do [ @@ -220,9 +220,9 @@ ] end - it_behaves_like "not adding a comment" + it_behaves_like 'not adding a comment' - it "calls the merge request upsert service with all work_packages" do + it 'calls the merge request upsert service with all work_packages' do gitlab_merge_request = process.reload expect(gitlab_merge_request.labels).to eq([{ "title" => "feature", "color" => "#009966" }, { "title" => "needs review", "color" => "#9400d3" }]) @@ -232,9 +232,9 @@ end end - context "when the MR is ready for review" do - let(:gitlab_action) { "update" } - let(:mr_state) { "opened" } + context 'when the MR is ready for review' do + let(:gitlab_action) { 'update' } + let(:mr_state) { 'opened' } let(:mr_draft) { false } let(:comment) do @@ -245,18 +245,18 @@ before { create(:gitlab_merge_request, gitlab_id: 4, work_packages: [work_package]) } - it_behaves_like "not adding a comment" + it_behaves_like 'not adding a comment' - it "calls the merge request upsert service" do + it 'calls the merge request upsert service' do process expect(upsert_service).to have_received(:call) .with(a_kind_of(OpenProject::GitlabIntegration::NotificationHandler::Helper::Payload), work_packages: [work_package]) end end - context "with a reopened action" do - let(:gitlab_action) { "reopen" } - let(:mr_state) { "opened" } + context 'with a reopened action' do + let(:gitlab_action) { 'reopen' } + let(:mr_state) { 'opened' } let(:comment) do "**MR Reopened:** Merge request 4 [A MR title](http://79dfcd98b723/root/hot_do/-/merge_requests/4) for " \ @@ -264,7 +264,7 @@ "[Administrator](https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon).\n" end - it_behaves_like "adding a comment" - it_behaves_like "calls the merge request upsert service" + it_behaves_like 'adding a comment' + it_behaves_like 'calls the merge request upsert service' end end diff --git a/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/pipeline_hook_spec.rb b/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/pipeline_hook_spec.rb index 10632b42eef9..2dc806a3c43d 100644 --- a/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/pipeline_hook_spec.rb +++ b/modules/gitlab_integration/spec/lib/open_project/gitlab_integration/notification_handler/pipeline_hook_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe OpenProject::GitlabIntegration::NotificationHandler::PipelineHook do @@ -40,17 +40,17 @@ let(:payload) do { - "open_project_user_id" => gitlab_system_user.id, - "object_kind" => "pipeline", - "event_type" => "pipeline", - "user" => { - "id" => 1, - "name" => "Administrator", - "username" => "root", - "avatar_url" => "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", - "email" => "[REDACTED]" + 'open_project_user_id' => gitlab_system_user.id, + 'object_kind' => "pipeline", + 'event_type' => "pipeline", + 'user' => { + 'id' => 1, + 'name' => "Administrator", + 'username' => "root", + 'avatar_url' => "https://www.gravatar.com/avatar/258d8dc916db8cea2cafb6c3cd0cb0246efe061421dbd83ec3a350428cabda4f?s=80&d=identicon", + 'email' => "[REDACTED]" }, - "object_attributes" => { + 'object_attributes' => { "id" => 5, "iid" => 5, "name" => nil, @@ -134,8 +134,8 @@ allow(upsert_service).to receive(:call).and_call_original end - context "with a new pipeline" do - it "calls the pipeline upsert service" do + context 'with a new pipeline' do + it 'calls the pipeline upsert service' do expect { process }.to change(GitlabPipeline, :count).by(1) expect(upsert_service).to have_received(:call) .with(a_kind_of(OpenProject::GitlabIntegration::NotificationHandler::Helper::Payload), diff --git a/modules/gitlab_integration/spec/models/gitlab_issue_spec.rb b/modules/gitlab_integration/spec/models/gitlab_issue_spec.rb index 5d29c218140e..5ca66a5e98fc 100644 --- a/modules/gitlab_integration/spec/models/gitlab_issue_spec.rb +++ b/modules/gitlab_integration/spec/models/gitlab_issue_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe GitlabIssue do - describe "Associations" do + describe 'Associations' do it { is_expected.to have_and_belong_to_many(:work_packages) } it { is_expected.to belong_to(:gitlab_user).optional } end - describe "Validations" do + describe 'Validations' do it { is_expected.to validate_presence_of :gitlab_html_url } it { is_expected.to validate_presence_of :number } it { is_expected.to validate_presence_of :repository } @@ -43,48 +43,48 @@ it { is_expected.to validate_presence_of :title } it { is_expected.to validate_presence_of :gitlab_updated_at } - context "when it is a partial issue" do + context 'when it is a partial issue' do let(:issue) { build(:gitlab_issue, :partial) } it { expect(issue).not_to validate_presence_of :body } end - context "when it is not a partial issue" do + context 'when it is not a partial issue' do let(:issue) { build(:gitlab_issue) } it { expect(issue).to be_valid } end - describe "labels" do + describe 'labels' do it { is_expected.to allow_value(nil).for(:labels) } it { is_expected.to allow_value([]).for(:labels) } - it { is_expected.to allow_value([{ "color" => "#666", "title" => "grey" }]).for(:labels) } + it { is_expected.to allow_value([{ 'color' => '#666', 'title' => 'grey' }]).for(:labels) } - it "requires both color and title" do - expect(subject).not_to allow_value([{ "title" => "grey" }]).for(:labels) + it 'requires both color and title' do + expect(subject).not_to allow_value([{ 'title' => 'grey' }]).for(:labels) end it { is_expected.not_to allow_value([{}]).for(:labels) } - it "returns an error message when invalid" do - issue = build(:gitlab_issue, labels: [{ "title" => "grey" }]) + it 'returns an error message when invalid' do + issue = build(:gitlab_issue, labels: [{ 'title' => 'grey' }]) issue.valid? - expect(issue.errors[:labels]).to include("must be an array of hashes with keys: color, title") + expect(issue.errors[:labels]).to include('must be an array of hashes with keys: color, title') end end end - describe "Enums" do + describe 'Enums' do let(:gitlab_issue) { build(:gitlab_issue) } it do expect(gitlab_issue).to define_enum_for(:state) - .with_values(opened: "opened", closed: "closed") + .with_values(opened: 'opened', closed: 'closed') .backed_by_column_of_type(:string) end end - describe ".without_work_package" do + describe '.without_work_package' do subject(:gitlab_issues_without_workpackages) { described_class.without_work_package } let(:gitlab_issue_no_work_packages) { create(:gitlab_issue, work_packages: []) } @@ -98,78 +98,78 @@ it { expect(gitlab_issues_without_workpackages).to contain_exactly(gitlab_issue_no_work_packages) } end - describe ".find_by_gitlab_identifiers" do + describe '.find_by_gitlab_identifiers' do shared_let(:issue) { create(:gitlab_issue) } - it "raises an ArgumentError when no id or url is provided" do - expect { described_class.find_by_gitlab_identifiers }.to raise_error(ArgumentError, "needs an id or an url") + it 'raises an ArgumentError when no id or url is provided' do + expect { described_class.find_by_gitlab_identifiers }.to raise_error(ArgumentError, 'needs an id or an url') end - context "when the gitlab_id attribute matches" do - it "finds by gitlab_id" do + context 'when the gitlab_id attribute matches' do + it 'finds by gitlab_id' do expect(described_class.find_by_gitlab_identifiers(id: issue.gitlab_id)).to eql(issue) end end - context "when the gitlab_html_url attribute matches" do - it "finds by gitlab_html_url" do + context 'when the gitlab_html_url attribute matches' do + it 'finds by gitlab_html_url' do expect(described_class.find_by_gitlab_identifiers(url: issue.gitlab_html_url)).to eql(issue) end end - context "when the provided gitlab_id does not match" do - it "is nil" do + context 'when the provided gitlab_id does not match' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: issue.gitlab_id + 1)).to be_nil end end - context "when the provided gitlab_html_url does not match" do - it "is nil" do + context 'when the provided gitlab_html_url does not match' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(url: "#{issue.gitlab_html_url}zzzz")) .to be_nil end end - context "when neither match" do - it "is nil" do + context 'when neither match' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: issue.gitlab_id + 1, url: "#{issue.gitlab_html_url}zzzz")) .to be_nil end end - context "when the provided gitlab_html_url does not match but the gitlab_id does" do - it "is nil" do + context 'when the provided gitlab_html_url does not match but the gitlab_id does' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: issue.gitlab_id, url: "#{issue.gitlab_html_url}zzzz")) .to eql issue end end - context "when the provided gitlab_html_url does match but the gitlab_id does not" do - it "is nil" do + context 'when the provided gitlab_html_url does match but the gitlab_id does not' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: issue.gitlab_id + 1, url: issue.gitlab_html_url)) .to eql issue end end - context "when neither match but initialize is true" do + context 'when neither match but initialize is true' do subject(:finder) do described_class.find_by_gitlab_identifiers(id: issue.gitlab_id + 1, url: "#{issue.gitlab_html_url}zzzz", initialize: true) end - it "returns an issue" do + it 'returns an issue' do expect(finder).to be_a(described_class) end - it "returns a new record" do + it 'returns a new record' do expect(finder).to be_new_record end - it "has the provided attributes initialized" do + it 'has the provided attributes initialized' do expect(finder.attributes.compact) .to eql("gitlab_id" => issue.gitlab_id + 1, "gitlab_html_url" => "#{issue.gitlab_html_url}zzzz") diff --git a/modules/gitlab_integration/spec/models/gitlab_merge_request_spec.rb b/modules/gitlab_integration/spec/models/gitlab_merge_request_spec.rb index 30050f244417..76b4533956ad 100644 --- a/modules/gitlab_integration/spec/models/gitlab_merge_request_spec.rb +++ b/modules/gitlab_integration/spec/models/gitlab_merge_request_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe GitlabMergeRequest do - describe "Associations" do + describe 'Associations' do it { is_expected.to have_and_belong_to_many(:work_packages) } it { is_expected.to have_many(:gitlab_pipelines).dependent(:destroy) } it { is_expected.to belong_to(:gitlab_user).optional } - it { is_expected.to belong_to(:merged_by).class_name("GitlabUser").optional } + it { is_expected.to belong_to(:merged_by).class_name('GitlabUser').optional } end - describe "Validations" do + describe 'Validations' do it { is_expected.to validate_presence_of :gitlab_html_url } it { is_expected.to validate_presence_of :number } it { is_expected.to validate_presence_of :repository } @@ -45,48 +45,48 @@ it { is_expected.to validate_presence_of :title } it { is_expected.to validate_presence_of :gitlab_updated_at } - context "when it is a partial merge request" do + context 'when it is a partial merge request' do let(:merge_request) { build(:gitlab_merge_request, :partial) } it { expect(merge_request).not_to validate_presence_of :body } end - context "when it is not a partial merge_request" do + context 'when it is not a partial merge_request' do let(:merge_request) { build(:gitlab_merge_request) } it { expect(merge_request).to be_valid } end - describe "labels" do + describe 'labels' do it { is_expected.to allow_value(nil).for(:labels) } it { is_expected.to allow_value([]).for(:labels) } - it { is_expected.to allow_value([{ "color" => "#666", "title" => "grey" }]).for(:labels) } + it { is_expected.to allow_value([{ 'color' => '#666', 'title' => 'grey' }]).for(:labels) } - it "requires both color and title" do - expect(subject).not_to allow_value([{ "title" => "grey" }]).for(:labels) + it 'requires both color and title' do + expect(subject).not_to allow_value([{ 'title' => 'grey' }]).for(:labels) end it { is_expected.not_to allow_value([{}]).for(:labels) } - it "returns an error message when invalid" do - merge_request = build(:gitlab_merge_request, labels: [{ "title" => "grey" }]) + it 'returns an error message when invalid' do + merge_request = build(:gitlab_merge_request, labels: [{ 'title' => 'grey' }]) merge_request.valid? - expect(merge_request.errors[:labels]).to include("must be an array of hashes with keys: color, title") + expect(merge_request.errors[:labels]).to include('must be an array of hashes with keys: color, title') end end end - describe "Enums" do + describe 'Enums' do let(:gitlab_merge_request) { build(:gitlab_merge_request) } it do expect(gitlab_merge_request).to define_enum_for(:state) - .with_values(opened: "opened", merged: "merged", closed: "closed") + .with_values(opened: 'opened', merged: 'merged', closed: 'closed') .backed_by_column_of_type(:string) end end - describe ".without_work_package" do + describe '.without_work_package' do subject { described_class.without_work_package } let(:merge_request) { create(:gitlab_merge_request, work_packages:) } @@ -96,85 +96,85 @@ it { is_expected.to contain_exactly(merge_request) } - context "when the pr is linked to a work_package" do + context 'when the pr is linked to a work_package' do let(:work_packages) { create_list(:work_package, 1) } it { is_expected.to be_empty } end end - describe ".find_by_gitlab_identifiers" do + describe '.find_by_gitlab_identifiers' do shared_let(:merge_request) { create(:gitlab_merge_request) } - it "raises an ArgumentError when no id or url is provided" do - expect { described_class.find_by_gitlab_identifiers }.to raise_error(ArgumentError, "needs an id or an url") + it 'raises an ArgumentError when no id or url is provided' do + expect { described_class.find_by_gitlab_identifiers }.to raise_error(ArgumentError, 'needs an id or an url') end - context "when the gitlab_id attribute matches" do - it "finds by gitlab_id" do + context 'when the gitlab_id attribute matches' do + it 'finds by gitlab_id' do expect(described_class.find_by_gitlab_identifiers(id: merge_request.gitlab_id)).to eql(merge_request) end end - context "when the gitlab_html_url attribute matches" do - it "finds by gitlab_html_url" do + context 'when the gitlab_html_url attribute matches' do + it 'finds by gitlab_html_url' do expect(described_class.find_by_gitlab_identifiers(url: merge_request.gitlab_html_url)).to eql(merge_request) end end - context "when the provided gitlab_id does not match" do - it "is nil" do + context 'when the provided gitlab_id does not match' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: merge_request.gitlab_id + 1)).to be_nil end end - context "when the provided gitlab_html_url does not match" do - it "is nil" do + context 'when the provided gitlab_html_url does not match' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(url: "#{merge_request.gitlab_html_url}zzzz")) .to be_nil end end - context "when neither match" do - it "is nil" do + context 'when neither match' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: merge_request.gitlab_id + 1, url: "#{merge_request.gitlab_html_url}zzzz")) .to be_nil end end - context "when the provided gitlab_html_url does not match but the gitlab_id does" do - it "is nil" do + context 'when the provided gitlab_html_url does not match but the gitlab_id does' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: merge_request.gitlab_id, url: "#{merge_request.gitlab_html_url}zzzz")) .to eql merge_request end end - context "when the provided gitlab_html_url does match but the gitlab_id does not" do - it "is nil" do + context 'when the provided gitlab_html_url does match but the gitlab_id does not' do + it 'is nil' do expect(described_class.find_by_gitlab_identifiers(id: merge_request.gitlab_id + 1, url: merge_request.gitlab_html_url)) .to eql merge_request end end - context "when neither match but initialize is true" do + context 'when neither match but initialize is true' do subject(:finder) do described_class.find_by_gitlab_identifiers(id: merge_request.gitlab_id + 1, url: "#{merge_request.gitlab_html_url}zzzz", initialize: true) end - it "returns an merge_request" do + it 'returns an merge_request' do expect(finder).to be_a(described_class) end - it "returns a new record" do + it 'returns a new record' do expect(finder).to be_new_record end - it "has the provided attributes initialized" do + it 'has the provided attributes initialized' do expect(finder.attributes.compact) .to eql("gitlab_id" => merge_request.gitlab_id + 1, "gitlab_html_url" => "#{merge_request.gitlab_html_url}zzzz") @@ -182,14 +182,14 @@ end end - describe "#latest_pipelines" do - context "when multiple pipelines for the same merge request exist" do + describe '#latest_pipelines' do + context 'when multiple pipelines for the same merge request exist' do shared_association_default(:gitlab_merge_request) { create(:gitlab_merge_request) } shared_let(:latest_pipelines) { create_list(:gitlab_pipeline, 2, :recent, project_id: 123) } shared_let(:outdated_pipelines) { create_list(:gitlab_pipeline, 2, :outdated, project_id: 123) } - it "returns the latest pipeline ordered from most recent" do + it 'returns the latest pipeline ordered from most recent' do expect(gitlab_merge_request.reload.latest_pipelines).to match_array(latest_pipelines + outdated_pipelines) end end diff --git a/modules/gitlab_integration/spec/models/gitlab_pipeline_spec.rb b/modules/gitlab_integration/spec/models/gitlab_pipeline_spec.rb index c58b6ae7fe70..4c4f9d333c78 100644 --- a/modules/gitlab_integration/spec/models/gitlab_pipeline_spec.rb +++ b/modules/gitlab_integration/spec/models/gitlab_pipeline_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe GitlabPipeline do - describe "Associations" do + describe 'Associations' do it { is_expected.to belong_to(:gitlab_merge_request).touch(true) } end - describe "Validations" do + describe 'Validations' do it { is_expected.to validate_presence_of :gitlab_user_avatar_url } it { is_expected.to validate_presence_of :gitlab_html_url } it { is_expected.to validate_presence_of :gitlab_id } @@ -45,22 +45,22 @@ it { is_expected.to validate_presence_of :username } end - describe "Enums" do + describe 'Enums' do let(:gitlab_pipeline) { build(:gitlab_pipeline) } it do expect(gitlab_pipeline).to define_enum_for(:status) - .with_values(created: "created", - running: "running", - success: "success", - waiting: "waiting", - preparing: "preparing", - failed: "failed", - pending: "pending", - canceled: "canceled", - skipped: "skipped", - manual: "manual", - scheduled: "scheduled") + .with_values(created: 'created', + running: 'running', + success: 'success', + waiting: 'waiting', + preparing: 'preparing', + failed: 'failed', + pending: 'pending', + canceled: 'canceled', + skipped: 'skipped', + manual: 'manual', + scheduled: 'scheduled') .backed_by_column_of_type(:string) end end diff --git a/modules/gitlab_integration/spec/models/gitlab_user_spec.rb b/modules/gitlab_integration/spec/models/gitlab_user_spec.rb index c184b0da932b..0c47d4d64961 100644 --- a/modules/gitlab_integration/spec/models/gitlab_user_spec.rb +++ b/modules/gitlab_integration/spec/models/gitlab_user_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe GitlabUser do - describe "Associations" do + describe 'Associations' do it { is_expected.to have_many(:gitlab_merge_requests) } end - describe "Validations" do + describe 'Validations' do it { is_expected.to validate_presence_of :gitlab_id } it { is_expected.to validate_presence_of :gitlab_name } it { is_expected.to validate_presence_of :gitlab_username } diff --git a/modules/gitlab_integration/spec/spec_helper.rb b/modules/gitlab_integration/spec/spec_helper.rb index e9b86f472dd9..5974eaa856cf 100644 --- a/modules/gitlab_integration/spec/spec_helper.rb +++ b/modules/gitlab_integration/spec/spec_helper.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' diff --git a/modules/gitlab_integration/spec/support/pages/work_package_gitlab_tab.rb b/modules/gitlab_integration/spec/support/pages/work_package_gitlab_tab.rb index cf8bf666b8a3..4792431eeef3 100644 --- a/modules/gitlab_integration/spec/support/pages/work_package_gitlab_tab.rb +++ b/modules/gitlab_integration/spec/support/pages/work_package_gitlab_tab.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rbconfig" -require "support/pages/page" +require 'rbconfig' +require 'support/pages/page' module Pages class GitlabTab < Page @@ -43,26 +43,26 @@ def path end def git_actions_menu_button - find(".gitlab-git-copy:not([disabled])", text: "Git") + find('.gitlab-git-copy:not([disabled])', text: 'Git') end def git_actions_copy_branch_name_button - find(".git-actions-menu .copy-button:not([disabled])", match: :first) + find('.git-actions-menu .copy-button:not([disabled])', match: :first) end def paste_clipboard_content meta_key = osx? ? :command : :control - page.send_keys(meta_key, "v") + page.send_keys(meta_key, 'v') end def expect_tab_not_present - expect(page).to have_no_css(".op-tab-row--link", text: "GITLAB") + expect(page).to have_no_css('.op-tab-row--link', text: 'GITLAB') end private def osx? - RbConfig::CONFIG["host_os"].include?("darwin") + RbConfig::CONFIG['host_os'].include?('darwin') end end end diff --git a/modules/grids/Gemfile b/modules/grids/Gemfile index b4e2a20bb606..fa75df156323 100644 --- a/modules/grids/Gemfile +++ b/modules/grids/Gemfile @@ -1,3 +1,3 @@ -source "https://rubygems.org" +source 'https://rubygems.org' gemspec diff --git a/modules/grids/app/contracts/grids/base_contract.rb b/modules/grids/app/contracts/grids/base_contract.rb index 62d88b5389ea..428daaf4a342 100644 --- a/modules/grids/app/contracts/grids/base_contract.rb +++ b/modules/grids/app/contracts/grids/base_contract.rb @@ -129,7 +129,7 @@ def validate_widgets_start_before_end end def run_registration_validations - validations = config.validations(model, self.class.name.demodulize.gsub("Contract", "").underscore.to_sym) + validations = config.validations(model, self.class.name.demodulize.gsub('Contract', '').underscore.to_sym) validations.each do |validation| instance_eval(&validation) diff --git a/modules/grids/app/contracts/grids/create_contract.rb b/modules/grids/app/contracts/grids/create_contract.rb index 0ced6dbb535e..86da86d4d3a6 100644 --- a/modules/grids/app/contracts/grids/create_contract.rb +++ b/modules/grids/app/contracts/grids/create_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "grids/base_contract" +require 'grids/base_contract' module Grids class CreateContract < BaseContract diff --git a/modules/grids/app/contracts/grids/delete_contract.rb b/modules/grids/app/contracts/grids/delete_contract.rb index 1ea7623a9b1d..285f86f969e2 100644 --- a/modules/grids/app/contracts/grids/delete_contract.rb +++ b/modules/grids/app/contracts/grids/delete_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "grids/base_contract" +require 'grids/base_contract' module Grids class DeleteContract < ::DeleteContract diff --git a/modules/grids/app/contracts/grids/update_contract.rb b/modules/grids/app/contracts/grids/update_contract.rb index 8a178e508637..74593827e59a 100644 --- a/modules/grids/app/contracts/grids/update_contract.rb +++ b/modules/grids/app/contracts/grids/update_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "grids/base_contract" +require 'grids/base_contract' module Grids class UpdateContract < BaseContract diff --git a/modules/grids/app/controllers/api/v3/grids/grids_api.rb b/modules/grids/app/controllers/api/v3/grids/grids_api.rb index 60e1011ccb24..75f9512a153d 100644 --- a/modules/grids/app/controllers/api/v3/grids/grids_api.rb +++ b/modules/grids/app/controllers/api/v3/grids/grids_api.rb @@ -57,12 +57,12 @@ class GridsAPI < ::API::OpenProjectAPI mount ::API::V3::Grids::CreateFormAPI mount ::API::V3::Grids::Schemas::GridSchemaAPI - route_param :id, type: Integer, desc: "Grid ID" do + route_param :id, type: Integer, desc: 'Grid ID' do after_validation do @grid = ::Grids::Query .new(user: current_user) .results - .find(params["id"]) + .find(params['id']) end get do diff --git a/modules/grids/app/controllers/grids/base_in_project_controller.rb b/modules/grids/app/controllers/grids/base_in_project_controller.rb index eac86aa79ab5..1458a8b8b550 100644 --- a/modules/grids/app/controllers/grids/base_in_project_controller.rb +++ b/modules/grids/app/controllers/grids/base_in_project_controller.rb @@ -4,7 +4,7 @@ class BaseInProjectController < ::ApplicationController before_action :authorize def show - render layout: "angular/angular" + render layout: 'angular/angular' end end end diff --git a/modules/grids/app/models/grids/grid.rb b/modules/grids/app/models/grids/grid.rb index c2c3f518d865..7e395db5feec 100644 --- a/modules/grids/app/models/grids/grid.rb +++ b/modules/grids/app/models/grids/grid.rb @@ -33,7 +33,7 @@ class Grid < ApplicationRecord serialize :options, type: Hash has_many :widgets, - class_name: "Widget", + class_name: 'Widget', dependent: :destroy, autosave: true diff --git a/modules/grids/app/queries/grids/filters/page_filter.rb b/modules/grids/app/queries/grids/filters/page_filter.rb index 78922f27de17..d53b03f739c3 100644 --- a/modules/grids/app/queries/grids/filters/page_filter.rb +++ b/modules/grids/app/queries/grids/filters/page_filter.rb @@ -30,7 +30,7 @@ module Grids module Filters class PageFilter < Filters::GridFilter def allowed_values - raise NotImplementedError, "There would be too many candidates" + raise NotImplementedError, 'There would be too many candidates' end def allowed_values_subset @@ -62,7 +62,7 @@ def where project_id_condition(actual_value[:project_id])] "(#{conditions.compact.join(' AND ')})" - end.join(" OR ") + end.join(' OR ') end private @@ -72,7 +72,7 @@ def class_condition(klass) operator_strategy.sql_for_field([klass.name], self.class.model.table_name, - "type") + 'type') end def project_id_condition(project_id) @@ -84,7 +84,7 @@ def project_id_condition(project_id) operator_strategy.sql_for_field([project_id], self.class.model.table_name, - "project_id") + 'project_id') end def available_operators diff --git a/modules/grids/app/queries/grids/filters/scope_filter.rb b/modules/grids/app/queries/grids/filters/scope_filter.rb index b5b26639b210..384cf0888f0a 100644 --- a/modules/grids/app/queries/grids/filters/scope_filter.rb +++ b/modules/grids/app/queries/grids/filters/scope_filter.rb @@ -30,7 +30,7 @@ module Grids module Filters class ScopeFilter < Filters::GridFilter def allowed_values - raise NotImplementedError, "There would be too many candidates" + raise NotImplementedError, 'There would be too many candidates' end def allowed_values_subset @@ -55,7 +55,7 @@ def where project_id_condition(config[:project_id])] "(#{conditions.compact.join(' AND ')})" - end.join(" OR ") + end.join(' OR ') end private @@ -70,7 +70,7 @@ def class_condition(klass) operator_strategy.sql_for_field([klass.name], self.class.model.table_name, - "type") + 'type') end def project_id_condition(project_id) @@ -82,7 +82,7 @@ def project_id_condition(project_id) operator_strategy.sql_for_field([project_id], self.class.model.table_name, - "project_id") + 'project_id') end def type_strategy diff --git a/modules/grids/app/representers/api/v3/grids/grid_representer.rb b/modules/grids/app/representers/api/v3/grids/grid_representer.rb index 2073ce9089bb..176d07b0f5fd 100644 --- a/modules/grids/app/representers/api/v3/grids/grid_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/grid_representer.rb @@ -45,11 +45,11 @@ class GridRepresenter < ::API::Decorators::Single { href: path, - type: "text/html" + type: 'text/html' } }, setter: ->(fragment:, **) { - represented.scope = fragment["href"] + represented.scope = fragment['href'] } self_link title_getter: ->(*) {} @@ -112,7 +112,7 @@ class GridRepresenter < ::API::Decorators::Single render_nil: false def _type - "Grid" + 'Grid' end private @@ -133,7 +133,7 @@ def scope_path # Remove all query params # Those are added when the path does not actually require # project or user - path&.gsub(/(\?.+)|(\.\d+)\z/, "") + path&.gsub(/(\?.+)|(\.\d+)\z/, '') end def scope_path_attributes diff --git a/modules/grids/app/representers/api/v3/grids/schemas/grid_schema_representer.rb b/modules/grids/app/representers/api/v3/grids/schemas/grid_schema_representer.rb index 702940dd8a91..a5e73b5513da 100644 --- a/modules/grids/app/representers/api/v3/grids/schemas/grid_schema_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/schemas/grid_schema_representer.rb @@ -39,28 +39,28 @@ def initialize(represented, self_link: nil, current_user: nil, form_embedded: fa end schema :id, - type: "Integer" + type: 'Integer' schema :created_at, - type: "DateTime" + type: 'DateTime' schema :updated_at, - type: "DateTime" + type: 'DateTime' schema :row_count, - type: "Integer" + type: 'Integer' schema :column_count, - type: "Integer" + type: 'Integer' schema :name, - type: "String" + type: 'String' schema :options, - type: "JSON" + type: 'JSON' schema_with_allowed_collection :scope, - type: "Href", + type: 'Href', required: true, has_default: false, value_representer: false, @@ -71,7 +71,7 @@ def initialize(represented, self_link: nil, current_user: nil, form_embedded: fa } schema_with_allowed_collection :widgets, - type: "[]GridWidget", + type: '[]GridWidget', required: true, has_default: false, values_callback: -> do diff --git a/modules/grids/app/representers/api/v3/grids/widgets/chart_options_representer.rb b/modules/grids/app/representers/api/v3/grids/widgets/chart_options_representer.rb index 62f3f81bb0d2..b0e47734be84 100644 --- a/modules/grids/app/representers/api/v3/grids/widgets/chart_options_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/widgets/chart_options_representer.rb @@ -33,7 +33,7 @@ module Widgets class ChartOptionsRepresenter < QueryOptionsRepresenter property :chartType, getter: ->(represented:, **) { - represented["chartType"] + represented['chartType'] } end end diff --git a/modules/grids/app/representers/api/v3/grids/widgets/default_options_representer.rb b/modules/grids/app/representers/api/v3/grids/widgets/default_options_representer.rb index 80bff573c508..533e0832d2ea 100644 --- a/modules/grids/app/representers/api/v3/grids/widgets/default_options_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/widgets/default_options_representer.rb @@ -33,7 +33,7 @@ module Widgets class DefaultOptionsRepresenter < ::API::Decorators::Single property :name, getter: ->(represented:, **) { - represented["name"] + represented['name'] } end end diff --git a/modules/grids/app/representers/api/v3/grids/widgets/query_options_representer.rb b/modules/grids/app/representers/api/v3/grids/widgets/query_options_representer.rb index 105cd13b63af..b54b8d8569af 100644 --- a/modules/grids/app/representers/api/v3/grids/widgets/query_options_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/widgets/query_options_representer.rb @@ -33,14 +33,14 @@ module Widgets class QueryOptionsRepresenter < DefaultOptionsRepresenter property :queryId, getter: ->(represented:, **) { - represented["queryId"] + represented['queryId'] } # This is required for initialization where the values # are stored like this so the front end can then initialize it. property :queryProps, getter: ->(represented:, **) { - represented["queryProps"] + represented['queryProps'] } end end diff --git a/modules/grids/app/representers/api/v3/grids/widgets/time_entry_calendar_options_representer.rb b/modules/grids/app/representers/api/v3/grids/widgets/time_entry_calendar_options_representer.rb index 3378d3684653..58b232c79f40 100644 --- a/modules/grids/app/representers/api/v3/grids/widgets/time_entry_calendar_options_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/widgets/time_entry_calendar_options_representer.rb @@ -33,7 +33,7 @@ module Widgets class TimeEntryCalendarOptionsRepresenter < DefaultOptionsRepresenter property :days, getter: ->(represented:, **) { - represented["days"] || {} + represented['days'] || {} } end end diff --git a/modules/grids/app/representers/api/v3/grids/widgets/widget_representer.rb b/modules/grids/app/representers/api/v3/grids/widgets/widget_representer.rb index 5a89c2d0bffa..bb7b159fc138 100644 --- a/modules/grids/app/representers/api/v3/grids/widgets/widget_representer.rb +++ b/modules/grids/app/representers/api/v3/grids/widgets/widget_representer.rb @@ -49,7 +49,7 @@ class WidgetRepresenter < ::API::Decorators::Single } def _type - "GridWidget" + 'GridWidget' end end end diff --git a/modules/grids/app/services/grids/set_attributes_service.rb b/modules/grids/app/services/grids/set_attributes_service.rb index c2317ad4cb05..4dcc4f726185 100644 --- a/modules/grids/app/services/grids/set_attributes_service.rb +++ b/modules/grids/app/services/grids/set_attributes_service.rb @@ -63,11 +63,11 @@ def update_widgets(widgets) to_destroy.each(&:mark_for_destruction) to_create.each do |widget| - model.widgets.build widget.attributes.except("id") + model.widgets.build widget.attributes.except('id') end update_map.each do |existing, provided| - existing.attributes = provided.attributes.except("id", "grid_id") + existing.attributes = provided.attributes.except('id', 'grid_id') end end diff --git a/modules/grids/grids.gemspec b/modules/grids/grids.gemspec index f7558f57b4a9..835911e21062 100644 --- a/modules/grids/grids.gemspec +++ b/modules/grids/grids.gemspec @@ -1,9 +1,9 @@ Gem::Specification.new do |s| s.name = "grids" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = ["OpenProject"] s.summary = "OpenProject Grids." s.files = Dir["{app,config,db,lib}/**/*"] - s.metadata["rubygems_mfa_required"] = "true" + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/grids/lib/grids.rb b/modules/grids/lib/grids.rb index b4eaac18ede9..6022892573d3 100644 --- a/modules/grids/lib/grids.rb +++ b/modules/grids/lib/grids.rb @@ -1,5 +1,5 @@ require "grids/engine" -require "grids/configuration" +require 'grids/configuration' module Grids end diff --git a/modules/grids/lib/grids/configuration/in_project_base_registration.rb b/modules/grids/lib/grids/configuration/in_project_base_registration.rb index ad268e575937..440b16e45820 100644 --- a/modules/grids/lib/grids/configuration/in_project_base_registration.rb +++ b/modules/grids/lib/grids/configuration/in_project_base_registration.rb @@ -1,18 +1,18 @@ module Grids::Configuration class InProjectBaseRegistration < ::Grids::Configuration::Registration - widgets "work_packages_table", - "work_packages_graph", - "project_description", - "project_status", - "project_details", - "subprojects", - "work_packages_calendar", - "work_packages_overview", - "time_entries_list", - "members", - "news", - "documents", - "custom_text" + widgets 'work_packages_table', + 'work_packages_graph', + 'project_description', + 'project_status', + 'project_details', + 'subprojects', + 'work_packages_calendar', + 'work_packages_overview', + 'time_entries_list', + 'members', + 'news', + 'documents', + 'custom_text' remove_query_lambda = -> { ::Query.find_by(id: options[:queryId])&.destroy @@ -32,43 +32,43 @@ class InProjectBaseRegistration < ::Grids::Configuration::Registration user.allowed_in_any_work_package?(:view_work_packages, in_project: project) } - widget_strategy "work_packages_table" do + widget_strategy 'work_packages_table' do after_destroy remove_query_lambda allowed save_or_manage_queries_lambda - options_representer "::API::V3::Grids::Widgets::QueryOptionsRepresenter" + options_representer '::API::V3::Grids::Widgets::QueryOptionsRepresenter' end - widget_strategy "work_packages_graph" do + widget_strategy 'work_packages_graph' do after_destroy remove_query_lambda allowed queries_permission_and_ee_lambda - options_representer "::API::V3::Grids::Widgets::ChartOptionsRepresenter" + options_representer '::API::V3::Grids::Widgets::ChartOptionsRepresenter' end - widget_strategy "custom_text" do - options_representer "::API::V3::Grids::Widgets::CustomTextOptionsRepresenter" + widget_strategy 'custom_text' do + options_representer '::API::V3::Grids::Widgets::CustomTextOptionsRepresenter' end - widget_strategy "work_packages_overview" do + widget_strategy 'work_packages_overview' do allowed view_work_packages_lambda end - widget_strategy "work_packages_calendar" do + widget_strategy 'work_packages_calendar' do allowed view_work_packages_lambda end - widget_strategy "members" do + widget_strategy 'members' do allowed ->(user, project) { user.allowed_in_project?(:view_members, project) } end - widget_strategy "news" do + widget_strategy 'news' do allowed ->(user, project) { user.allowed_in_project?(:view_news, project) } end - widget_strategy "documents" do + widget_strategy 'documents' do allowed ->(user, project) { user.allowed_in_project?(:view_documents, project) } end @@ -92,10 +92,10 @@ def all_scopes def from_scope(scope) # recognize_routes does not work with engine paths path = [OpenProject::Configuration.rails_relative_url_root, - "projects", - "([^/]+)", + 'projects', + '([^/]+)', in_project_scope_path, - "?"].flatten.compact.join("/") + '?'].flatten.compact.join('/') match = Regexp.new(path).match(scope) return if match.nil? diff --git a/modules/grids/lib/grids/configuration/registration.rb b/modules/grids/lib/grids/configuration/registration.rb index 3c075c17e431..3136deb10c6b 100644 --- a/modules/grids/lib/grids/configuration/registration.rb +++ b/modules/grids/lib/grids/configuration/registration.rb @@ -127,13 +127,13 @@ def validations(mode = nil, proc = nil) def register! unless grid_class - raise "Need to define the grid class first. Use grid_class to do so." + raise 'Need to define the grid class first. Use grid_class to do so.' end unless widgets - raise "Need to define at least one widget first. Use widgets to do so." + raise 'Need to define at least one widget first. Use widgets to do so.' end unless to_scope - raise "Need to define a scope. Use to_scope to do so" + raise 'Need to define a scope. Use to_scope to do so' end Grids::Configuration.register_grid(grid_class, self) diff --git a/modules/grids/lib/grids/configuration/widget_strategy.rb b/modules/grids/lib/grids/configuration/widget_strategy.rb index d160cef833b6..9738665f9cc3 100644 --- a/modules/grids/lib/grids/configuration/widget_strategy.rb +++ b/modules/grids/lib/grids/configuration/widget_strategy.rb @@ -54,7 +54,7 @@ def options_representer(klass = nil) @options_representer = klass end - @options_representer || "::API::V3::Grids::Widgets::DefaultOptionsRepresenter" + @options_representer || '::API::V3::Grids::Widgets::DefaultOptionsRepresenter' end end end diff --git a/modules/grids/spec/contracts/grids/create_contract_spec.rb b/modules/grids/spec/contracts/grids/create_contract_spec.rb index d2c970205fca..c5a04e7623b8 100644 --- a/modules/grids/spec/contracts/grids/create_contract_spec.rb +++ b/modules/grids/spec/contracts/grids/create_contract_spec.rb @@ -26,46 +26,46 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe Grids::CreateContract do - include_context "grid contract" - include_context "model contract" + include_context 'grid contract' + include_context 'model contract' - it_behaves_like "shared grid contract attributes" + it_behaves_like 'shared grid contract attributes' - describe "type" do + describe 'type' do let(:grid) { build_stubbed(:grid, default_values) } - it_behaves_like "is writable" do + it_behaves_like 'is writable' do let(:attribute) { :type } - let(:value) { "Grids::Grid" } + let(:value) { 'Grids::Grid' } end end - describe "user_id" do + describe 'user_id' do let(:grid) { build_stubbed(:grid, default_values) } - it_behaves_like "is not writable" do + it_behaves_like 'is not writable' do let(:attribute) { :user_id } let(:value) { 5 } end end - describe "project_id" do + describe 'project_id' do let(:grid) { build_stubbed(:grid, default_values) } - it_behaves_like "is not writable" do + it_behaves_like 'is not writable' do let(:attribute) { :project_id } let(:value) { 5 } end end - describe "#assignable_values" do - context "for scope" do - it "calls the grid configuration for the available values" do - scopes = double("scopes") + describe '#assignable_values' do + context 'for scope' do + it 'calls the grid configuration for the available values' do + scopes = double('scopes') allow(Grids::Configuration) .to receive(:all_scopes) @@ -76,8 +76,8 @@ end end - context "for widgets" do - it "calls the grid configuration for the available values but allows only those eligible" do + context 'for widgets' do + it 'calls the grid configuration for the available values but allows only those eligible' do widgets = %i[widget1 widget2] allow(Grids::Configuration) @@ -99,8 +99,8 @@ end end - context "for something else" do - it "returns nil" do + context 'for something else' do + it 'returns nil' do expect(instance.assignable_values(:something, user)) .to be_nil end diff --git a/modules/grids/spec/contracts/grids/delete_contract_spec.rb b/modules/grids/spec/contracts/grids/delete_contract_spec.rb index f855a9068f10..56b3648fbf13 100644 --- a/modules/grids/spec/contracts/grids/delete_contract_spec.rb +++ b/modules/grids/spec/contracts/grids/delete_contract_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Grids::DeleteContract do let(:user) { build_stubbed(:user) } @@ -44,29 +44,29 @@ allow(grid).to receive(:user_deletable?).and_return(user_deletable) end - context "when writable" do + context 'when writable' do let(:writable) { true } let(:user_deletable) { true } - it "deletes the grid even if no valid widgets" do + it 'deletes the grid even if no valid widgets' do expect(instance.validate).to be_truthy end end - context "when not writable" do + context 'when not writable' do let(:writable) { false } let(:user_deletable) { true } - it "deletes the grid even if not valid" do + it 'deletes the grid even if not valid' do expect(instance.validate).to be_falsey end end - context "when not deletable" do + context 'when not deletable' do let(:writable) { true } let(:user_deletable) { false } - it "deletes the grid even if not valid" do + it 'deletes the grid even if not valid' do expect(instance.validate).to be_falsey end end diff --git a/modules/grids/spec/contracts/grids/shared_examples.rb b/modules/grids/spec/contracts/grids/shared_examples.rb index 89a431a0e561..9c05ad4841f6 100644 --- a/modules/grids/spec/contracts/grids/shared_examples.rb +++ b/modules/grids/spec/contracts/grids/shared_examples.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "grid contract" do +RSpec.shared_context 'grid contract' do let(:user) { build_stubbed(:user) } let(:instance) { described_class.new(grid, user) } let(:widgets) { [] } @@ -41,11 +41,11 @@ build_stubbed(:grid, default_values) end - shared_examples_for "validates positive integer" do - context "when the value is negative" do + shared_examples_for 'validates positive integer' do + context 'when the value is negative' do let(:value) { -1 } - it "is invalid" do + it 'is invalid' do instance.validate expect(instance.errors.details[attribute]) @@ -53,10 +53,10 @@ end end - context "when the value is nil" do + context 'when the value is nil' do let(:value) { nil } - it "is invalid" do + it 'is invalid' do instance.validate expect(instance.errors.details[attribute]) @@ -66,24 +66,24 @@ end end -RSpec.shared_examples_for "shared grid contract attributes" do - include_context "model contract" +RSpec.shared_examples_for 'shared grid contract attributes' do + include_context 'model contract' let(:model) { grid } - describe "row_count" do - it_behaves_like "is writable" do + describe 'row_count' do + it_behaves_like 'is writable' do let(:attribute) { :row_count } let(:value) { 5 } - it_behaves_like "validates positive integer" + it_behaves_like 'validates positive integer' end - context "row_count less than 1" do + context 'row_count less than 1' do before do grid.row_count = 0 end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:row_count]) .to contain_exactly({ error: :greater_than, count: 0 }) @@ -91,20 +91,20 @@ end end - describe "column_count" do - it_behaves_like "is writable" do + describe 'column_count' do + it_behaves_like 'is writable' do let(:attribute) { :column_count } let(:value) { 5 } - it_behaves_like "validates positive integer" + it_behaves_like 'validates positive integer' end - context "row_count less than 1" do + context 'row_count less than 1' do before do grid.column_count = 0 end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:column_count]) .to contain_exactly({ error: :greater_than, count: 0 }) @@ -112,8 +112,8 @@ end end - describe "valid grid subclasses" do - context "for the Grid superclass itself" do + describe 'valid grid subclasses' do + context 'for the Grid superclass itself' do let(:grid) do build_stubbed(:grid, default_values) end @@ -122,14 +122,14 @@ instance.validate end - it "is invalid for the grid superclass itself" do + it 'is invalid for the grid superclass itself' do expect(instance.errors.details[:scope]) .to contain_exactly({ error: :inclusion }) end end end - describe "widgets" do + describe 'widgets' do before do allow(Grids::Configuration) .to receive(:writable?) @@ -142,21 +142,21 @@ allow(Grids::Configuration) .to receive(:allowed_widget?) - .with(Grids::Grid, "widget1", user, nil) + .with(Grids::Grid, 'widget1', user, nil) .and_return(true) allow(Grids::Configuration) .to receive(:allowed_widget?) - .with(Grids::Grid, "widget2", user, nil) + .with(Grids::Grid, 'widget2', user, nil) .and_return(false) end - context "if there are new widgets that are not allowed" do + context 'if there are new widgets that are not allowed' do let(:widgets) do - [Grids::Widget.new(identifier: "widget2", start_row: 1, end_row: 3, start_column: 1, end_column: 3)] + [Grids::Widget.new(identifier: 'widget2', start_row: 1, end_row: 3, start_column: 1, end_column: 3)] end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) @@ -164,20 +164,20 @@ end end - context "if there are new widgets that are allowed" do + context 'if there are new widgets that are allowed' do let(:widgets) do - [Grids::Widget.new(identifier: "widget1", start_row: 1, end_row: 3, start_column: 1, end_column: 3)] + [Grids::Widget.new(identifier: 'widget1', start_row: 1, end_row: 3, start_column: 1, end_column: 3)] end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "if there are new widgets that are not allowed but marked for destruction" do + context 'if there are new widgets that are not allowed but marked for destruction' do let(:widgets) do - widget = Grids::Widget.new(identifier: "widget2", start_row: 1, end_row: 3, start_column: 1, end_column: 3) + widget = Grids::Widget.new(identifier: 'widget2', start_row: 1, end_row: 3, start_column: 1, end_column: 3) allow(widget) .to receive(:marked_for_destruction?) @@ -186,18 +186,18 @@ [widget] end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "if there are existing widgets that are not allowed" do + context 'if there are existing widgets that are not allowed' do let(:widgets) do - [build_stubbed(:grid_widget, identifier: "widget2", start_row: 1, end_row: 3, start_column: 1, end_column: 3)] + [build_stubbed(:grid_widget, identifier: 'widget2', start_row: 1, end_row: 3, start_column: 1, end_column: 3)] end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end diff --git a/modules/grids/spec/contracts/grids/update_contract_spec.rb b/modules/grids/spec/contracts/grids/update_contract_spec.rb index f37f26c68d01..6bb5114b3d95 100644 --- a/modules/grids/spec/contracts/grids/update_contract_spec.rb +++ b/modules/grids/spec/contracts/grids/update_contract_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe Grids::UpdateContract do - include_context "model contract" - include_context "grid contract" + include_context 'model contract' + include_context 'grid contract' - it_behaves_like "shared grid contract attributes" + it_behaves_like 'shared grid contract attributes' - describe "type" do + describe 'type' do before do - grid.type = "Grid" + grid.type = 'Grid' end - it "is not writable" do + it 'is not writable' do expect(instance.validate) .to be_falsey end - it "explains the not writable error" do + it 'explains the not writable error' do instance.validate # scope because that is what type is called on the outside for grids expect(instance.errors.details[:scope]) @@ -53,16 +53,16 @@ end end - describe "user_id" do - it_behaves_like "is not writable" do + describe 'user_id' do + it_behaves_like 'is not writable' do let(:model) { grid } let(:attribute) { :user_id } let(:value) { 5 } end end - describe "project_id" do - it_behaves_like "is not writable" do + describe 'project_id' do + it_behaves_like 'is not writable' do let(:model) { grid } let(:attribute) { :project_id } let(:value) { 5 } diff --git a/modules/grids/spec/factories/grid_factory.rb b/modules/grids/spec/factories/grid_factory.rb index de0f77668bc4..477191983ab9 100644 --- a/modules/grids/spec/factories/grid_factory.rb +++ b/modules/grids/spec/factories/grid_factory.rb @@ -1,5 +1,5 @@ FactoryBot.define do - factory :grid, class: "Grids::Grid" do + factory :grid, class: 'Grids::Grid' do row_count { 5 } column_count { 5 } end diff --git a/modules/grids/spec/factories/grid_widget_factory.rb b/modules/grids/spec/factories/grid_widget_factory.rb index dae2774f785c..0e5dcedea21d 100644 --- a/modules/grids/spec/factories/grid_widget_factory.rb +++ b/modules/grids/spec/factories/grid_widget_factory.rb @@ -1,4 +1,4 @@ FactoryBot.define do - factory :grid_widget, class: "Grids::Widget" do + factory :grid_widget, class: 'Grids::Widget' do end end diff --git a/modules/grids/spec/lib/api/v3/grids/grid_payload_representer_parsing_spec.rb b/modules/grids/spec/lib/api/v3/grids/grid_payload_representer_parsing_spec.rb index b949add58815..0b21f150a834 100644 --- a/modules/grids/spec/lib/api/v3/grids/grid_payload_representer_parsing_spec.rb +++ b/modules/grids/spec/lib/api/v3/grids/grid_payload_representer_parsing_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Grids::GridPayloadRepresenter, "parsing" do +RSpec.describe API::V3::Grids::GridPayloadRepresenter, 'parsing' do include API::V3::Utilities::PathHelper let(:object) do @@ -46,7 +46,7 @@ "widgets" => [ { _type: "Widget", - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', startRow: 4, endRow: 5, startColumn: 1, @@ -54,7 +54,7 @@ }, { _type: "Widget", - identifier: "work_packages_created", + identifier: 'work_packages_created', startRow: 1, endRow: 2, startColumn: 1, @@ -62,7 +62,7 @@ }, { _type: "Widget", - identifier: "work_packages_watched", + identifier: 'work_packages_watched', startRow: 2, endRow: 4, startColumn: 4, @@ -71,45 +71,45 @@ ], "_links" => { "scope" => { - "href" => "some_path" + "href" => 'some_path' } } } end - describe "_links" do - context "scope" do - it "updates page" do + describe '_links' do + context 'scope' do + it 'updates page' do grid = representer.from_hash(hash) expect(grid.scope) - .to eql("some_path") + .to eql('some_path') end end end - describe "properties" do - context "rowCount" do - it "updates row_count" do + describe 'properties' do + context 'rowCount' do + it 'updates row_count' do grid = representer.from_hash(hash) expect(grid.row_count) .to be(10) end end - context "columnCount" do - it "updates column_count" do + context 'columnCount' do + it 'updates column_count' do grid = representer.from_hash(hash) expect(grid.column_count) .to be(20) end end - context "widgets" do - it "updates widgets" do + context 'widgets' do + it 'updates widgets' do grid = representer.from_hash(hash) expect(grid.widgets[0].identifier) - .to eql("work_packages_assigned") + .to eql('work_packages_assigned') expect(grid.widgets[0].start_row) .to be(4) expect(grid.widgets[0].end_row) @@ -120,7 +120,7 @@ .to be(2) expect(grid.widgets[1].identifier) - .to eql("work_packages_created") + .to eql('work_packages_created') expect(grid.widgets[1].start_row) .to be(1) expect(grid.widgets[1].end_row) @@ -131,7 +131,7 @@ .to be(2) expect(grid.widgets[2].identifier) - .to eql("work_packages_watched") + .to eql('work_packages_watched') expect(grid.widgets[2].start_row) .to be(2) expect(grid.widgets[2].end_row) diff --git a/modules/grids/spec/lib/api/v3/grids/grid_representer_rendering_spec.rb b/modules/grids/spec/lib/api/v3/grids/grid_representer_rendering_spec.rb index b388247b772c..8eb18241764a 100644 --- a/modules/grids/spec/lib/api/v3/grids/grid_representer_rendering_spec.rb +++ b/modules/grids/spec/lib/api/v3/grids/grid_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Grids::GridRepresenter, "rendering" do +RSpec.describe API::V3::Grids::GridRepresenter, 'rendering' do include OpenProject::StaticRouting::UrlHelpers include API::V3::Utilities::PathHelper @@ -40,7 +40,7 @@ widgets: [ build_stubbed( :grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 4, end_row: 5, start_column: 1, @@ -48,7 +48,7 @@ ), build_stubbed( :grid_widget, - identifier: "work_packages_created", + identifier: 'work_packages_created', start_row: 1, end_row: 2, start_column: 1, @@ -56,7 +56,7 @@ ), build_stubbed( :grid_widget, - identifier: "work_packages_watched", + identifier: 'work_packages_watched', start_row: 2, end_row: 4, start_column: 4, @@ -71,7 +71,7 @@ let(:representer) { described_class.new(grid, current_user:, embed_links:) } let(:writable) { true } - let(:scope_path) { "bogus_scope" } + let(:scope_path) { 'bogus_scope' } let(:attachment_addable) { true } before do @@ -93,54 +93,54 @@ .and_return(attachment_addable) end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - context "properties" do - it "denotes its type" do + context 'properties' do + it 'denotes its type' do expect(subject) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') end - it "has an id" do + it 'has an id' do expect(subject) .to be_json_eql(grid.id) - .at_path("id") + .at_path('id') end - it "has a rowCount" do + it 'has a rowCount' do expect(subject) .to be_json_eql(4) - .at_path("rowCount") + .at_path('rowCount') end - it "has a columnCount" do + it 'has a columnCount' do expect(subject) .to be_json_eql(5) - .at_path("columnCount") + .at_path('columnCount') end - describe "createdAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'createdAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { grid.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end - describe "updatedAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'updatedAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { grid.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - it "has a list of widgets" do + it 'has a list of widgets' do widgets = [ { _type: "GridWidget", id: grid.widgets[0].id, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', options: {}, startRow: 4, endRow: 5, @@ -150,7 +150,7 @@ { _type: "GridWidget", id: grid.widgets[1].id, - identifier: "work_packages_created", + identifier: 'work_packages_created', options: {}, startRow: 1, endRow: 2, @@ -160,7 +160,7 @@ { _type: "GridWidget", id: grid.widgets[2].id, - identifier: "work_packages_watched", + identifier: 'work_packages_watched', options: {}, startRow: 2, endRow: 4, @@ -171,41 +171,41 @@ expect(subject) .to be_json_eql(widgets.to_json) - .at_path("widgets") + .at_path('widgets') end end - context "_links" do - context "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context '_links' do + context 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { "/api/v3/grids/#{grid.id}" } end end - context "update link" do - it_behaves_like "has an untitled link" do - let(:link) { "update" } + context 'update link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { "/api/v3/grids/#{grid.id}/form" } let(:method) { :post } end end - context "updateImmediately link" do - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + context 'updateImmediately link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { "/api/v3/grids/#{grid.id}" } let(:method) { :patch } end end - context "scope link" do - it_behaves_like "has an untitled link" do - let(:link) { "scope" } + context 'scope link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'scope' } let(:href) { scope_path } let(:type) { "text/html" } - it "has a content type of html" do + it 'has a content type of html' do expect(subject) .to be_json_eql(type.to_json) .at_path("_links/#{link}/type") @@ -213,32 +213,32 @@ end end - it_behaves_like "has an untitled link" do - let(:link) { "attachments" } + it_behaves_like 'has an untitled link' do + let(:link) { 'attachments' } let(:href) { api_v3_paths.attachments_by_grid(grid.id) } end - context "addAttachments link" do - it_behaves_like "has an untitled link" do - let(:link) { "addAttachment" } + context 'addAttachments link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'addAttachment' } let(:href) { api_v3_paths.attachments_by_grid(grid.id) } end - context "user is not allowed to edit work packages" do + context 'user is not allowed to edit work packages' do let(:attachment_addable) { false } - it_behaves_like "has no link" do - let(:link) { "addAttachment" } + it_behaves_like 'has no link' do + let(:link) { 'addAttachment' } end end end end - context "embedded" do - it "embeds the attachments as collection" do + context 'embedded' do + it 'embeds the attachments as collection' do expect(subject) - .to be_json_eql("Collection".to_json) - .at_path("_embedded/attachments/_type") + .to be_json_eql('Collection'.to_json) + .at_path('_embedded/attachments/_type') end end end diff --git a/modules/grids/spec/lib/api/v3/grids/schemas/grid_schema_representer_spec.rb b/modules/grids/spec/lib/api/v3/grids/schemas/grid_schema_representer_spec.rb index 0e56bd51a6a3..718a0d9d462f 100644 --- a/modules/grids/spec/lib/api/v3/grids/schemas/grid_schema_representer_spec.rb +++ b/modules/grids/spec/lib/api/v3/grids/schemas/grid_schema_representer_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Grids::Schemas::GridSchemaRepresenter do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } - let(:self_link) { "/a/self/link" } + let(:self_link) { '/a/self/link' } let(:embedded) { true } let(:new_record) { true } let(:allowed_scopes) { %w(/some/path /some/other/path) } @@ -41,14 +41,14 @@ %w(first_widget second_widget) end let(:contract) do - contract = double("contract") + contract = double('contract') allow(contract) .to receive(:writable?) do |attribute| writable = %w(row_count column_count widgets) if new_record - writable << "scope" + writable << 'scope' end writable.include?(attribute.to_s) @@ -65,7 +65,7 @@ allow(contract) .to receive(:model) - .and_return(double("model")) + .and_return(double('model')) contract end @@ -76,89 +76,89 @@ current_user:) end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do - expect(subject).to be_json_eql("Schema".to_json).at_path("_type") + describe '_type' do + it 'is indicated as Schema' do + expect(subject).to be_json_eql('Schema'.to_json).at_path('_type') end end - describe "id" do - let(:path) { "id" } + describe 'id' do + let(:path) { 'id' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } - let(:name) { I18n.t("attributes.id") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } + let(:name) { I18n.t('attributes.id') } let(:required) { true } let(:writable) { false } end end - describe "rowCount" do - let(:path) { "rowCount" } + describe 'rowCount' do + let(:path) { 'rowCount' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } let(:name) { Grids::Grid.human_attribute_name(:row_count) } let(:required) { true } let(:writable) { true } end end - describe "columnCount" do - let(:path) { "columnCount" } + describe 'columnCount' do + let(:path) { 'columnCount' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } let(:name) { Grids::Grid.human_attribute_name(:column_count) } let(:required) { true } let(:writable) { true } end end - describe "createdAt" do - let(:path) { "createdAt" } + describe 'createdAt' do + let(:path) { 'createdAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Grids::Grid.human_attribute_name("created_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Grids::Grid.human_attribute_name('created_at') } let(:required) { true } let(:writable) { false } end end - describe "updatedAt" do - let(:path) { "updatedAt" } + describe 'updatedAt' do + let(:path) { 'updatedAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Grids::Grid.human_attribute_name("updated_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Grids::Grid.human_attribute_name('updated_at') } let(:required) { true } let(:writable) { false } end end - describe "widgets" do - let(:path) { "widgets" } + describe 'widgets' do + let(:path) { 'widgets' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]GridWidget" } - let(:name) { Grids::Grid.human_attribute_name("widgets") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]GridWidget' } + let(:name) { Grids::Grid.human_attribute_name('widgets') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "when embedding" do + context 'when embedding' do let(:embedded) { true } - it "contains no link to the allowed values" do + it 'contains no link to the allowed values' do expect(subject).not_to have_json_path("#{path}/_links/allowedValues") end - it "embeds the allowed values" do + it 'embeds the allowed values' do allowed_widgets.each_with_index do |identifier, index| href_path = "#{path}/_embedded/allowedValues/#{index}/identifier" expect(subject).to be_json_eql(identifier.to_json).at_path(href_path) @@ -166,98 +166,98 @@ end end - context "when not embedding" do + context 'when not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end - describe "scope" do - let(:path) { "scope" } + describe 'scope' do + let(:path) { 'scope' } - context "when having a new record" do - it_behaves_like "has basic schema properties" do - let(:type) { "Href" } - let(:name) { Grids::Grid.human_attribute_name("scope") } + context 'when having a new record' do + it_behaves_like 'has basic schema properties' do + let(:type) { 'Href' } + let(:name) { Grids::Grid.human_attribute_name('scope') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "when embedding" do + context 'when embedding' do let(:embedded) { true } - it_behaves_like "links to allowed values directly" do + it_behaves_like 'links to allowed values directly' do let(:hrefs) { allowed_scopes } end - it "does not embed" do + it 'does not embed' do expect(generated) - .not_to have_json_path("scope/embedded") + .not_to have_json_path('scope/embedded') end end - context "when not embedding" do + context 'when not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - it "does not embed" do + it 'does not embed' do expect(generated) - .not_to have_json_path("scope/embedded") + .not_to have_json_path('scope/embedded') end end end - context "when not having a new record" do + context 'when not having a new record' do let(:new_record) { false } let(:allowed_scopes) { nil } - it_behaves_like "has basic schema properties" do - let(:type) { "Href" } - let(:name) { Grids::Grid.human_attribute_name("scope") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Href' } + let(:name) { Grids::Grid.human_attribute_name('scope') } let(:required) { true } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - context "when embedding" do + context 'when embedding' do let(:embedded) { true } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - it "does not embed" do + it 'does not embed' do expect(generated) - .not_to have_json_path("scope/embedded") + .not_to have_json_path('scope/embedded') end end - context "when not embedding" do + context 'when not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - it "does not embed" do + it 'does not embed' do expect(generated) - .not_to have_json_path("scope/embedded") + .not_to have_json_path('scope/embedded') end end end end - context "_links" do - describe "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context '_links' do + describe 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end - context "embedded in a form" do + context 'embedded in a form' do let(:self_link) { nil } - it_behaves_like "has no link" do - let(:link) { "self" } + it_behaves_like 'has no link' do + let(:link) { 'self' } end end end diff --git a/modules/grids/spec/lib/api/v3/utilities/file_helper_spec.rb b/modules/grids/spec/lib/api/v3/utilities/file_helper_spec.rb index 1439b34b661a..d37e8f98dc6b 100644 --- a/modules/grids/spec/lib/api/v3/utilities/file_helper_spec.rb +++ b/modules/grids/spec/lib/api/v3/utilities/file_helper_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::PathHelper do let(:helper) { Class.new.tap { |c| c.extend(API::V3::Utilities::PathHelper) }.api_v3_paths } - context "attachments paths" do - describe "#attachments_by_grid" do + context 'attachments paths' do + describe '#attachments_by_grid' do subject { helper.attachments_by_grid 1 } - it "provides the path" do - expect(subject).to match("/grids/1/attachments") + it 'provides the path' do + expect(subject).to match('/grids/1/attachments') end end end diff --git a/modules/grids/spec/models/grids/grid_spec.rb b/modules/grids/spec/models/grids/grid_spec.rb index 6298a25f763e..a1edc503f0ae 100644 --- a/modules/grids/spec/models/grids/grid_spec.rb +++ b/modules/grids/spec/models/grids/grid_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_model" +require 'spec_helper' +require_relative 'shared_model' RSpec.describe Grids::Grid do let(:instance) { Grids::Grid.new column_count: 5, row_count: 5 } - it_behaves_like "grid attributes" + it_behaves_like 'grid attributes' end diff --git a/modules/grids/spec/models/grids/shared_model.rb b/modules/grids/spec/models/grids/shared_model.rb index c1910eaaa2a9..d21bd87805fd 100644 --- a/modules/grids/spec/models/grids/shared_model.rb +++ b/modules/grids/spec/models/grids/shared_model.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "grid attributes" do - describe "attributes" do - it "#row_count" do +RSpec.shared_examples_for 'grid attributes' do + describe 'attributes' do + it '#row_count' do instance.row_count = 5 expect(instance.row_count) .to be 5 end - it "#column_count" do + it '#column_count' do instance.column_count = 5 expect(instance.column_count) .to be 5 end - it "#name" do - instance.name = "custom 123" + it '#name' do + instance.name = 'custom 123' expect(instance.name) - .to eql "custom 123" + .to eql 'custom 123' # can be empty instance.name = nil expect(instance).to be_valid end - it "#options" do + it '#options' do value = { - some: "value", + some: 'value', and: { also: 1 } @@ -63,7 +63,7 @@ .to eql value end - it "#widgets" do + it '#widgets' do widgets = [ Grids::Widget.new(start_row: 2), Grids::Widget.new(start_row: 5) @@ -75,7 +75,7 @@ end end - it_behaves_like "acts_as_attachable included" do + it_behaves_like 'acts_as_attachable included' do let(:model_instance) { instance } let(:project) { create(:project) } end diff --git a/modules/grids/spec/models/grids/widget_spec.rb b/modules/grids/spec/models/grids/widget_spec.rb index d92562c3f319..20a43ea07dfb 100644 --- a/modules/grids/spec/models/grids/widget_spec.rb +++ b/modules/grids/spec/models/grids/widget_spec.rb @@ -26,45 +26,45 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Grids::Widget do let(:instance) { Grids::Widget.new } - describe "attributes" do - it "#start_row" do + describe 'attributes' do + it '#start_row' do instance.start_row = 5 expect(instance.start_row) .to be 5 end - it "#end_row" do + it '#end_row' do instance.end_row = 5 expect(instance.end_row) .to be 5 end - it "#start_column" do + it '#start_column' do instance.start_column = 5 expect(instance.start_column) .to be 5 end - it "#end_column" do + it '#end_column' do instance.end_column = 5 expect(instance.end_column) .to be 5 end - it "#identifier" do - instance.identifier = "some_identifier" + it '#identifier' do + instance.identifier = 'some_identifier' expect(instance.identifier) - .to eql "some_identifier" + .to eql 'some_identifier' end - it "#options" do + it '#options' do value = { - some: "value", + some: 'value', and: { also: 1 } @@ -75,7 +75,7 @@ .to eql value end - it "#grid" do + it '#grid' do grid = Grids::Grid.new instance.grid = grid expect(instance.grid) diff --git a/modules/grids/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb b/modules/grids/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb index e708d1f597ed..5524c6a470d2 100644 --- a/modules/grids/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb +++ b/modules/grids/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "POST /api/v3/grids/form", content_type: :json do include Rack::Test::Methods @@ -46,23 +46,23 @@ login_as(current_user) end - describe "#post" do + describe '#post' do before do - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be 200 end - it "is of type form" do + it 'is of type form' do expect(subject.body) .to be_json_eql("Form".to_json) - .at_path("_type") + .at_path('_type') end - it "contains default data in the payload" do + it 'contains default data in the payload' do expected = { rowCount: 4, columnCount: 5, @@ -75,18 +75,18 @@ expect(subject.body) .to be_json_eql(expected.to_json) - .at_path("_embedded/payload") + .at_path('_embedded/payload') end - it "has a validation error on scope" do + it 'has a validation error on scope' do expect(subject.body) .to be_json_eql("Scope is not set to one of the allowed values.".to_json) - .at_path("_embedded/validationErrors/scope/message") + .at_path('_embedded/validationErrors/scope/message') end - it "does not have a commit link" do + it 'does not have a commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end end diff --git a/modules/grids/spec/requests/api/v3/grids/grids_resource_spec.rb b/modules/grids/spec/requests/api/v3/grids/grids_resource_spec.rb index b58606aabca9..434c6c287a4e 100644 --- a/modules/grids/spec/requests/api/v3/grids/grids_resource_spec.rb +++ b/modules/grids/spec/requests/api/v3/grids/grids_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Grids resource", content_type: :json do +RSpec.describe 'API v3 Grids resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -43,26 +43,26 @@ subject(:response) { last_response } - describe "#get INDEX" do + describe '#get INDEX' do let(:path) { api_v3_paths.grids } before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end end - describe "#post" do + describe '#post' do let(:path) { api_v3_paths.grids } before do - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - context "without a page link" do + context 'without a page link' do let(:params) do { rowCount: 5, @@ -77,23 +77,23 @@ }.with_indifferent_access end - it "responds with 422" do + it 'responds with 422' do expect(subject.status).to eq(422) end - it "does not create a grid" do + it 'does not create a grid' do expect(Grids::Grid.count) .to be(0) end - it "returns the errors" do + it 'returns the errors' do expect(subject.body) - .to be_json_eql("Error".to_json) - .at_path("_type") + .to be_json_eql('Error'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql("Scope is not set to one of the allowed values.".to_json) - .at_path("message") + .at_path('message') end end end diff --git a/modules/grids/spec/requests/api/v3/grids/grids_schema_resource_spec.rb b/modules/grids/spec/requests/api/v3/grids/grids_schema_resource_spec.rb index 68afe1542497..3429e72990d9 100644 --- a/modules/grids/spec/requests/api/v3/grids/grids_schema_resource_spec.rb +++ b/modules/grids/spec/requests/api/v3/grids/grids_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Grids schema resource", content_type: :json do +RSpec.describe 'API v3 Grids schema resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -45,24 +45,24 @@ subject(:response) { last_response } - describe "#GET /grids/schema" do + describe '#GET /grids/schema' do before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns a schema" do + it 'returns a schema' do expect(subject.body) - .to be_json_eql("Schema".to_json) - .at_path "_type" + .to be_json_eql('Schema'.to_json) + .at_path '_type' end - it "does not embed" do + it 'does not embed' do expect(subject.body) - .not_to have_json_path("page/_links/allowedValues") + .not_to have_json_path('page/_links/allowedValues') end end end diff --git a/modules/grids/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb b/modules/grids/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb index f63d0b0d0cd9..bebfc2126e6f 100644 --- a/modules/grids/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb +++ b/modules/grids/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "PATCH /api/v3/grids/:id/form", content_type: :json do include Rack::Test::Methods @@ -45,15 +45,15 @@ login_as(current_user) end - describe "#post" do + describe '#post' do before do - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - context "for a non existing grid" do + context 'for a non existing grid' do let(:path) { api_v3_paths.grid_form(5) } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be 404 end diff --git a/modules/grids/spec/services/grids/create_service_spec.rb b/modules/grids/spec/services/grids/create_service_spec.rb index 13929ad99e90..8e87e4ee9b45 100644 --- a/modules/grids/spec/services/grids/create_service_spec.rb +++ b/modules/grids/spec/services/grids/create_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Grids::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:model_class) { Grids::Grid } end end diff --git a/modules/grids/spec/services/grids/set_attributes_service_spec.rb b/modules/grids/spec/services/grids/set_attributes_service_spec.rb index c1d324c867d4..e95d438355b8 100644 --- a/modules/grids/spec/services/grids/set_attributes_service_spec.rb +++ b/modules/grids/spec/services/grids/set_attributes_service_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Grids::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } let(:contract_class) do - contract = double("contract_class") + contract = double('contract_class') allow(contract) .to receive(:new) @@ -41,11 +41,11 @@ contract end let(:contract_instance) do - double("contract_instance", validate: contract_valid, errors: contract_errors) + double('contract_instance', validate: contract_valid, errors: contract_errors) end let(:contract_valid) { true } let(:contract_errors) do - double("contract_errors") + double('contract_errors') end let(:grid_valid) { true } let(:instance) do @@ -59,7 +59,7 @@ build_stubbed(grid_class.name.demodulize.underscore.to_sym, widgets: []) end - describe "call" do + describe 'call' do let(:call_attributes) do { column_count: 6 @@ -74,29 +74,29 @@ subject { instance.call(call_attributes) } - it "is successful" do + it 'is successful' do expect(subject.success?).to be_truthy end - it "sets the attributes" do + it 'sets the attributes' do subject expect(grid.attributes.slice(*grid.changed).symbolize_keys) .to eql call_attributes end - it "does not persist the grid" do + it 'does not persist the grid' do expect(grid) .not_to receive(:save) subject end - context "with additional widgets" do + context 'with additional widgets' do let(:widgets) do [ build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -114,34 +114,34 @@ subject end - it "adds the new widgets" do + it 'adds the new widgets' do expect(grid.widgets.length) .to be 1 end - it "does not persist the new widget" do + it 'does not persist the new widget' do expect(grid.widgets[0]) .to be_new_record end - it "applies the provided values" do - expect(grid.widgets[0].attributes.except("id")) - .to eql widgets[0].attributes.except("id").merge("grid_id" => grid.id) + it 'applies the provided values' do + expect(grid.widgets[0].attributes.except('id')) + .to eql widgets[0].attributes.except('id').merge('grid_id' => grid.id) end - context "with the widget not being allowed" do + context 'with the widget not being allowed' do before do allow(Grids::Configuration) .to receive(:allowed_widget?) - .with(grid, "work_packages_assigned", user, nil) + .with(grid, 'work_packages_assigned', user, nil) .and_return(false) end - context "with the grid being a new record" do + context 'with the grid being a new record' do let(:existing_widgets) do [ build(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -156,14 +156,14 @@ ) end - it "leaves the prohibited widget" do + it 'leaves the prohibited widget' do expect(grid.widgets.length) .to be 1 end end - context "with the grid not being a new record" do - it "leaves the prohibited widget" do + context 'with the grid not being a new record' do + it 'leaves the prohibited widget' do expect(grid.widgets.length) .to be 1 end @@ -171,11 +171,11 @@ end end - context "with empty widget params" do + context 'with empty widget params' do let(:existing_widgets) do [ build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -199,29 +199,29 @@ subject end - it "does not remove the widget right away" do + it 'does not remove the widget right away' do expect(grid.widgets.length) .to be 1 end - it "marks the widget for destruction" do + it 'marks the widget for destruction' do expect(grid.widgets[0]) .to be_marked_for_destruction end - context "with the widget not being allowed" do + context 'with the widget not being allowed' do before do allow(Grids::Configuration) .to receive(:allowed_widget?) - .with(grid, "work_packages_assigned", user, nil) + .with(grid, 'work_packages_assigned', user, nil) .and_return(false) end - context "with the grid being a new record" do + context 'with the grid being a new record' do let(:existing_widgets) do [ build(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -236,14 +236,14 @@ ) end - it "removes the prohibited widget" do + it 'removes the prohibited widget' do expect(grid.widgets) .to be_empty end end - context "with the grid not being a new record" do - it "leaves the prohibited widget" do + context 'with the grid not being a new record' do + it 'leaves the prohibited widget' do expect(grid.widgets.length) .to be 1 end @@ -251,11 +251,11 @@ end end - context "without widget params" do + context 'without widget params' do let(:existing_widgets) do [ build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -275,29 +275,29 @@ subject end - it "does not remove the widget" do + it 'does not remove the widget' do expect(grid.widgets.length) .to be 1 end - it "does not mark the widget for destruction" do + it 'does not mark the widget for destruction' do expect(grid.widgets[0]) .not_to be_marked_for_destruction end - context "with the widget not being allowed" do + context 'with the widget not being allowed' do before do allow(Grids::Configuration) .to receive(:allowed_widget?) - .with(grid, "work_packages_assigned", user, nil) + .with(grid, 'work_packages_assigned', user, nil) .and_return(false) end - context "with the grid being a new record" do + context 'with the grid being a new record' do let(:existing_widgets) do [ build(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -312,14 +312,14 @@ ) end - it "removes the prohibited widget" do + it 'removes the prohibited widget' do expect(grid.widgets) .to be_empty end end - context "with the grid not being a new record" do - it "leaves the prohibited widget" do + context 'with the grid not being a new record' do + it 'leaves the prohibited widget' do expect(grid.widgets.length) .to be 1 end @@ -327,12 +327,12 @@ end end - context "with updates to an existing widget" do + context 'with updates to an existing widget' do let(:widgets) do [ build_stubbed(:grid_widget, id: existing_widgets[0].id, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, @@ -342,7 +342,7 @@ let(:existing_widgets) do [ build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 2, end_row: 5, start_column: 1, @@ -362,40 +362,40 @@ subject end - it "updates the widget" do + it 'updates the widget' do expect(grid.widgets[0].start_row) .to eql widgets[0].start_row end - it "does not persist the changes" do + it 'does not persist the changes' do expect(grid.widgets[0]) .to be_changed end end - context "with additions and updates to existing widgets" do + context 'with additions and updates to existing widgets' do let(:widgets) do [ build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 3, end_row: 5, start_column: 1, end_column: 3), build_stubbed(:grid_widget, - identifier: "work_packages_watched", + identifier: 'work_packages_watched', start_row: 1, end_row: 2, start_column: 1, end_column: 2), build_stubbed(:grid_widget, - identifier: "work_packages_calendar", + identifier: 'work_packages_calendar', start_row: 2, end_row: 4, start_column: 1, end_column: 2), build_stubbed(:grid_widget, - identifier: "work_packages_calendar", + identifier: 'work_packages_calendar', start_row: 1, end_row: 2, start_column: 4, @@ -405,19 +405,19 @@ let(:existing_widgets) do [ build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 2, end_row: 5, start_column: 1, end_column: 3), build_stubbed(:grid_widget, - identifier: "work_packages_assigned", + identifier: 'work_packages_assigned', start_row: 1, end_row: 2, start_column: 3, end_column: 4), build_stubbed(:grid_widget, - identifier: "work_packages_calendar", + identifier: 'work_packages_calendar', start_row: 1, end_row: 2, start_column: 1, @@ -437,27 +437,27 @@ subject end - it "updates the widgets but does not persist them" do - expect(grid.widgets.detect { |w| w.identifier == "work_packages_assigned" && w.changed? } - .attributes.slice("start_row", "end_row", "start_colum", "end_column")) - .to eql("start_row" => 3, "end_row" => 5, "end_column" => 3) + it 'updates the widgets but does not persist them' do + expect(grid.widgets.detect { |w| w.identifier == 'work_packages_assigned' && w.changed? } + .attributes.slice('start_row', 'end_row', 'start_colum', 'end_column')) + .to eql('start_row' => 3, 'end_row' => 5, 'end_column' => 3) - expect(grid.widgets.detect { |w| w.identifier == "work_packages_calendar" && w.changed? } - .attributes.slice("start_row", "end_row", "start_colum", "end_column")) - .to eql("start_row" => 2, "end_row" => 4, "end_column" => 2) + expect(grid.widgets.detect { |w| w.identifier == 'work_packages_calendar' && w.changed? } + .attributes.slice('start_row', 'end_row', 'start_colum', 'end_column')) + .to eql('start_row' => 2, 'end_row' => 4, 'end_column' => 2) end - it "does not persist the new widgets" do - expect(grid.widgets.any? { |w| w.identifier == "work_packages_watched" && w.new_record? }) + it 'does not persist the new widgets' do + expect(grid.widgets.any? { |w| w.identifier == 'work_packages_watched' && w.new_record? }) .to be_truthy - expect(grid.widgets.any? { |w| w.identifier == "work_packages_calendar" && w.new_record? }) + expect(grid.widgets.any? { |w| w.identifier == 'work_packages_calendar' && w.new_record? }) .to be_truthy end - it "does mark a widget for destruction" do + it 'does mark a widget for destruction' do expect(grid.widgets.detect(&:marked_for_destruction?).identifier) - .to eql "work_packages_assigned" + .to eql 'work_packages_assigned' end end end diff --git a/modules/grids/spec/services/grids/update_service_spec.rb b/modules/grids/spec/services/grids/update_service_spec.rb index 4f25a7749cb8..3ece44b07c19 100644 --- a/modules/grids/spec/services/grids/update_service_spec.rb +++ b/modules/grids/spec/services/grids/update_service_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Grids::UpdateService, type: :model do let(:user) { build_stubbed(:user) } let(:contract_class) do - double("contract_class", "<=": true) + double('contract_class', '<=': true) end let(:grid_valid) { true } let(:instance) do @@ -45,7 +45,7 @@ true end let(:set_attributes_errors) do - double("set_attributes_errors") + double('set_attributes_errors') end let(:set_attributes_result) do ServiceResult.new result: grid, @@ -62,7 +62,7 @@ grid end let!(:set_attributes_service) do - service = double("set_attributes_service_instance") + service = double('set_attributes_service_instance') allow(Grids::SetAttributesService) .to receive(:new) @@ -79,20 +79,20 @@ service end - describe "call" do - shared_examples_for "service call" do + describe 'call' do + shared_examples_for 'service call' do subject { instance.call(call_attributes) } - it "is successful" do + it 'is successful' do expect(subject.success?).to be_truthy end - it "returns the result of the SetAttributesService" do + it 'returns the result of the SetAttributesService' do expect(subject) .to eql set_attributes_result end - it "persists the grid" do + it 'persists the grid' do expect(grid) .to receive(:save) .and_return(grid_valid) @@ -100,19 +100,19 @@ subject end - context "when the SetAttributeService is unsuccessful" do + context 'when the SetAttributeService is unsuccessful' do let(:set_attributes_success) { false } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject.success?).to be_falsey end - it "returns the result of the SetAttributesService" do + it 'returns the result of the SetAttributesService' do expect(subject) .to eql set_attributes_result end - it "does not persist the changes" do + it 'does not persist the changes' do expect(grid) .not_to receive(:save) @@ -126,10 +126,10 @@ end end - context "when the grid is invalid" do + context 'when the grid is invalid' do let(:grid_valid) { false } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject.success?).to be_falsey end @@ -141,13 +141,13 @@ end end - context "with parameters" do + context 'with parameters' do let(:call_attributes) { { row_count: 5 } } - it_behaves_like "service call" + it_behaves_like 'service call' end - context "with parameters only for widgets" do + context 'with parameters only for widgets' do let(:call_attributes) { { widgets: [build_stubbed(:grid_widget)] } } before do @@ -168,7 +168,7 @@ end end - it_behaves_like "service call" + it_behaves_like 'service call' end end end diff --git a/modules/grids/spec/support/pages/grid.rb b/modules/grids/spec/support/pages/grid.rb index 96446872a0ca..b0772d006012 100644 --- a/modules/grids/spec/support/pages/grid.rb +++ b/modules/grids/spec/support/pages/grid.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class Grid < ::Pages::Page def add_widget(row_number, column_number, location, name) within_add_widget_modal(row_number, column_number, location) do expect(page) - .to have_content(I18n.t("js.grid.add_widget")) + .to have_content(I18n.t('js.grid.add_widget')) SeleniumHubWaiter.wait unless using_cuprite? @@ -43,7 +43,7 @@ def add_widget(row_number, column_number, location, name) def expect_no_help_mode expect(page) - .to have_no_css(".toolbar-item .icon-add") + .to have_no_css('.toolbar-item .icon-add') end def expect_unable_to_add_widget(row_number, column_number, location, name = nil) @@ -57,10 +57,10 @@ def expect_unable_to_add_widget(row_number, column_number, location, name = nil) def expect_add_widget_enterprise_edition_notice(row_number, column_number, location) within_add_widget_modal(row_number, column_number, location) do expect(page) - .to have_content(I18n.t("js.grid.add_widget")) + .to have_content(I18n.t('js.grid.add_widget')) expect(page) - .to have_css(".op-toast.-ee-upsale", text: I18n.t("js.upsale.ee_only")) + .to have_css('.op-toast.-ee-upsale', text: I18n.t('js.upsale.ee_only')) end end @@ -84,14 +84,14 @@ def within_add_widget_modal(row_number, column_number, location, &) area.hover add_widget_button = if using_cuprite? - area.find(".grid--widget-add") + area.find('.grid--widget-add') else - area.find(".grid--widget-add", visible: :all) + area.find('.grid--widget-add', visible: :all) end add_widget_button.click - within(".spot-modal", &) + within('.spot-modal', &) end def expect_widget_adding_prohibited_generally(row_number = 1, column_number = 1) @@ -99,13 +99,13 @@ def expect_widget_adding_prohibited_generally(row_number = 1, column_number = 1) area.hover expect(area) - .to have_no_css(".grid--widget-add") + .to have_no_css('.grid--widget-add') end def expect_specific_widget_unaddable(row_number, column_number, location, name) within_add_widget_modal(row_number, column_number, location) do expect(page) - .to have_content(I18n.t("js.grid.add_widget")) + .to have_content(I18n.t('js.grid.add_widget')) expect(page) .to have_no_css('[data-test-selector="op-grid--addable-widget"]', text: Regexp.new("^#{name}$")) diff --git a/modules/job_status/app/models/job_status/status.rb b/modules/job_status/app/models/job_status/status.rb index 1372b5b2aa5a..6f4b3bc6a8e8 100644 --- a/modules/job_status/app/models/job_status/status.rb +++ b/modules/job_status/app/models/job_status/status.rb @@ -1,45 +1,17 @@ -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - module JobStatus class Status < ApplicationRecord - self.table_name = "job_statuses" + self.table_name = 'delayed_job_statuses' belongs_to :user belongs_to :reference, polymorphic: true enum status: { - in_queue: "in_queue", - error: "error", - in_process: "in_process", - success: "success", - failure: "failure", - cancelled: "cancelled" + in_queue: 'in_queue', + error: 'error', + in_process: 'in_process', + success: 'success', + failure: 'failure', + cancelled: 'cancelled' } def self.of_reference(reference) diff --git a/modules/job_status/app/workers/job_status/application_job_with_status.rb b/modules/job_status/app/workers/job_status/application_job_with_status.rb index e0c6e128fce0..e754700cde23 100644 --- a/modules/job_status/app/workers/job_status/application_job_with_status.rb +++ b/modules/job_status/app/workers/job_status/application_job_with_status.rb @@ -27,7 +27,8 @@ #++ module JobStatus module ApplicationJobWithStatus - # Backgroun jobs can have a status JobStatus::Status + # Delayed jobs can have a status: + # Delayed::Job::Status # which is related to the job via a reference which is an AR model instance. def status_reference nil @@ -60,6 +61,8 @@ def job_status ## # Update the status code for a given job def upsert_status(status:, **args) + # Can't use upsert, as we only want to insert the user_id once + # and not update it repeatedly resource = ::JobStatus::Status.find_or_initialize_by(job_id:) if resource.new_record? @@ -74,16 +77,7 @@ def upsert_status(status:, **args) resource.attributes = build_status_attributes(args.merge(status:)) end - # There is a possible race condition because of unique job_statuses.job_id - # Can't use upsert easily, because before updating we need to know user_id - # to set proper locale. Probably, it is possible to get it from - # a job's payload, then it would be possible to correctly prepare attributes before using upsert. - # Therefore, it is up to possible optimization in future. Now the race condition is handled with - # handling ActiveRecord::RecordNotUnique and trying again. resource.save! - rescue ActiveRecord::RecordNotUnique - OpenProject.logger.info("Retrying ApplicationJobWithStatus#upsert_status.") - retry end protected diff --git a/modules/job_status/app/workers/job_status/cron/clear_old_job_status_job.rb b/modules/job_status/app/workers/job_status/cron/clear_old_job_status_job.rb index 5069d9b39ea6..2b5e87b3d183 100644 --- a/modules/job_status/app/workers/job_status/cron/clear_old_job_status_job.rb +++ b/modules/job_status/app/workers/job_status/cron/clear_old_job_status_job.rb @@ -28,12 +28,15 @@ module JobStatus module Cron - class ClearOldJobStatusJob < ApplicationJob + class ClearOldJobStatusJob < ::Cron::CronJob + # runs at 4:15 nightly + self.cron_expression = '15 4 * * *' + RETENTION_PERIOD = 2.days.freeze def perform ::JobStatus::Status - .where(::JobStatus::Status.arel_table[:updated_at].lteq(Time.zone.now - RETENTION_PERIOD)) + .where(::JobStatus::Status.arel_table[:updated_at].lteq(Time.now - RETENTION_PERIOD)) .destroy_all end end diff --git a/modules/job_status/config/routes.rb b/modules/job_status/config/routes.rb index a28cc2a14210..c2d6d1a97c0e 100644 --- a/modules/job_status/config/routes.rb +++ b/modules/job_status/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - get "/job_statuses/:job_uuid", - to: "angular#empty_layout", - as: "job_status" + get '/job_statuses/:job_uuid', + to: 'angular#empty_layout', + as: 'job_status' end diff --git a/modules/job_status/db/migrate/20200422105623_add_job_status.rb b/modules/job_status/db/migrate/20200422105623_add_job_status.rb index 3dd8b817e0b9..8e662859891f 100644 --- a/modules/job_status/db/migrate/20200422105623_add_job_status.rb +++ b/modules/job_status/db/migrate/20200422105623_add_job_status.rb @@ -40,7 +40,7 @@ def up t.timestamps end - add_column :delayed_job_statuses, :status, :delayed_job_status, default: "in_queue" + add_column :delayed_job_statuses, :status, :delayed_job_status, default: 'in_queue' end def down diff --git a/modules/job_status/db/migrate/20200610124259_extend_job_status.rb b/modules/job_status/db/migrate/20200610124259_extend_job_status.rb index bf26ecff80b1..240c0c65b71d 100644 --- a/modules/job_status/db/migrate/20200610124259_extend_job_status.rb +++ b/modules/job_status/db/migrate/20200610124259_extend_job_status.rb @@ -50,8 +50,8 @@ def change reversible do |dir| dir.up do - change_column_default :delayed_job_statuses, :created_at, -> { "CURRENT_TIMESTAMP" } - change_column_default :delayed_job_statuses, :updated_at, -> { "CURRENT_TIMESTAMP" } + change_column_default :delayed_job_statuses, :created_at, -> { 'CURRENT_TIMESTAMP' } + change_column_default :delayed_job_statuses, :updated_at, -> { 'CURRENT_TIMESTAMP' } end end diff --git a/modules/job_status/lib/api/v3/job_status/job_status_api.rb b/modules/job_status/lib/api/v3/job_status/job_status_api.rb index f8d04b7f73b9..27a5fc7537c3 100644 --- a/modules/job_status/lib/api/v3/job_status/job_status_api.rb +++ b/modules/job_status/lib/api/v3/job_status/job_status_api.rb @@ -31,7 +31,7 @@ module V3 module JobStatus class JobStatusAPI < ::API::OpenProjectAPI resources :job_statuses do - route_param :job_id, type: String, desc: "Job UUID" do + route_param :job_id, type: String, desc: 'Job UUID' do after_validation do @job = ::JobStatus::Status .find_by(job_id: params[:job_id], user_id: current_user.id) diff --git a/modules/job_status/lib/api/v3/job_status/job_status_representer.rb b/modules/job_status/lib/api/v3/job_status/job_status_representer.rb index 179043b822cf..ec0c02fd3fc2 100644 --- a/modules/job_status/lib/api/v3/job_status/job_status_representer.rb +++ b/modules/job_status/lib/api/v3/job_status/job_status_representer.rb @@ -44,7 +44,7 @@ class JobStatusRepresenter < ::API::Decorators::Single render_nil: true def _type - "JobStatus" + 'JobStatus' end end end diff --git a/modules/job_status/lib/open_project/job_status.rb b/modules/job_status/lib/open_project/job_status.rb index 9eb10d776e6b..bc608cdec3d6 100644 --- a/modules/job_status/lib/open_project/job_status.rb +++ b/modules/job_status/lib/open_project/job_status.rb @@ -28,6 +28,6 @@ module OpenProject module JobStatus - require "open_project/job_status/engine" + require 'open_project/job_status/engine' end end diff --git a/modules/job_status/lib/open_project/job_status/engine.rb b/modules/job_status/lib/open_project/job_status/engine.rb index 85bd828a6456..66b9fe7afb85 100644 --- a/modules/job_status/lib/open_project/job_status/engine.rb +++ b/modules/job_status/lib/open_project/job_status/engine.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/plugins" +require 'open_project/plugins' module OpenProject::JobStatus class Engine < ::Rails::Engine @@ -34,11 +34,11 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-job_status", - author_url: "https://www.openproject.org", + register 'openproject-job_status', + author_url: 'https://www.openproject.org', bundled: true - add_api_endpoint "API::V3::Root" do + add_api_endpoint 'API::V3::Root' do mount ::API::V3::JobStatus::JobStatusAPI end @@ -46,16 +46,10 @@ class Engine < ::Rails::Engine "#{root}/job_statuses/#{uuid}" end - add_cron_jobs do - { - "JobStatus::Cron::ClearOldJobStatusJob": { - cron: "15 4 * * *", # runs at 4:15 nightly - class: ::JobStatus::Cron::ClearOldJobStatusJob.name - } - } - end - config.to_prepare do + # Register the cron job to clear statuses periodically + ::Cron::CronJob.register! ::JobStatus::Cron::ClearOldJobStatusJob + # Extends the ActiveJob adapter in use (DelayedJob) by a Status which lives # indenpendently from the job itself (which is deleted once successful or after max attempts). # That way, the result of a background job is available even after the original job is gone. diff --git a/modules/job_status/lib/open_project/job_status/event_listener.rb b/modules/job_status/lib/open_project/job_status/event_listener.rb index 9dfc4a81dc95..cd24529d8471 100644 --- a/modules/job_status/lib/open_project/job_status/event_listener.rb +++ b/modules/job_status/lib/open_project/job_status/event_listener.rb @@ -41,7 +41,7 @@ def register! end # Start of process - ActiveSupport::Notifications.subscribe("perform_start.active_job") do |_name, _started, _call, _id, payload| + ActiveSupport::Notifications.subscribe('perform_start.active_job') do |_name, _started, _call, _id, payload| job = payload[:job] next unless job @@ -50,7 +50,7 @@ def register! end # Complete, or failure - ActiveSupport::Notifications.subscribe("perform.active_job") do |_name, _started, _call, _id, payload| + ActiveSupport::Notifications.subscribe('perform.active_job') do |_name, _started, _call, _id, payload| job = payload[:job] exception_object = payload[:exception_object] @@ -63,7 +63,7 @@ def register! end # Retry stopped -> failure - ActiveSupport::Notifications.subscribe("retry_stopped.active_job") do |_name, _started, _call, _id, payload| + ActiveSupport::Notifications.subscribe('retry_stopped.active_job') do |_name, _started, _call, _id, payload| job = payload[:job] error = payload[:error] @@ -72,7 +72,7 @@ def register! end # Retry enqueued - ActiveSupport::Notifications.subscribe("enqueue_retry.active_job") do |_name, _started, _call, _id, payload| + ActiveSupport::Notifications.subscribe('enqueue_retry.active_job') do |_name, _started, _call, _id, payload| job = payload[:job] error = payload[:error] @@ -81,7 +81,7 @@ def register! end # Discarded job - ActiveSupport::Notifications.subscribe("discard.active_job") do |_name, _started, _call, _id, payload| + ActiveSupport::Notifications.subscribe('discard.active_job') do |_name, _started, _call, _id, payload| job = payload[:job] error = payload[:error] @@ -116,7 +116,7 @@ def on_start(job) # On requeuing a job after error def on_requeue(job, error) job.upsert_status status: :in_queue, - message: I18n.t("background_jobs.status.error_requeue", message: error) + message: I18n.t('background_jobs.status.error_requeue', message: error) end ## @@ -124,7 +124,7 @@ def on_requeue(job, error) def on_cancelled(job, error) upsert_status job, status: :cancelled, - message: I18n.t("background_jobs.status.cancelled_due_to", message: error) + message: I18n.t('background_jobs.status.cancelled_due_to', message: error) end ## diff --git a/modules/job_status/lib/openproject-job_status.rb b/modules/job_status/lib/openproject-job_status.rb index 6229f53c8d67..c0cb29dfe248 100644 --- a/modules/job_status/lib/openproject-job_status.rb +++ b/modules/job_status/lib/openproject-job_status.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/job_status" +require 'open_project/job_status' diff --git a/modules/job_status/openproject-job_status.gemspec b/modules/job_status/openproject-job_status.gemspec index e78cb9943845..7db686f70dc8 100644 --- a/modules/job_status/openproject-job_status.gemspec +++ b/modules/job_status/openproject-job_status.gemspec @@ -1,10 +1,10 @@ Gem::Specification.new do |s| - s.name = "openproject-job_status" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject Job status" - s.description = "Listing and status of background jobs" - s.license = "GPLv3" - s.metadata["rubygems_mfa_required"] = "true" + s.name = 'openproject-job_status' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject Job status' + s.description = 'Listing and status of background jobs' + s.license = 'GPLv3' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/job_status/spec/factories/delayed_job_status_factory.rb b/modules/job_status/spec/factories/delayed_job_status_factory.rb index 3945178832e9..73ad122492a4 100644 --- a/modules/job_status/spec/factories/delayed_job_status_factory.rb +++ b/modules/job_status/spec/factories/delayed_job_status_factory.rb @@ -27,7 +27,7 @@ #++ FactoryBot.define do - factory :delayed_job_status, class: "::JobStatus::Status" do + factory :delayed_job_status, class: '::JobStatus::Status' do job_id { SecureRandom.uuid } user { User.current } end diff --git a/modules/job_status/spec/features/job_status_spec.rb b/modules/job_status/spec/features/job_status_spec.rb index 990e417f6c0f..4e6002ae374b 100644 --- a/modules/job_status/spec/features/job_status_spec.rb +++ b/modules/job_status/spec/features/job_status_spec.rb @@ -26,51 +26,51 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Job status", :js do +RSpec.describe 'Job status', :js do shared_let(:admin) { create(:admin) } before do login_as admin end - it "renders a descriptive error in case of 404" do - visit "/job_statuses/something-that-does-not-exist" + it 'renders a descriptive error in case of 404' do + visit '/job_statuses/something-that-does-not-exist' - expect(page).to have_css(".icon-big.icon-help", wait: 10) - expect(page).to have_content I18n.t("js.job_status.generic_messages.not_found") + expect(page).to have_css('.icon-big.icon-help', wait: 10) + expect(page).to have_content I18n.t('js.job_status.generic_messages.not_found') end - describe "with a status that has an additional errors payload" do + describe 'with a status that has an additional errors payload' do let!(:status) { create(:delayed_job_status, user: admin) } before do - status.update! payload: { errors: ["Some error", "Another error"] } + status.update! payload: { errors: ['Some error', 'Another error'] } end - it "shows a list of these errors" do + it 'shows a list of these errors' do visit "/job_statuses/#{status.job_id}" - expect(page).to have_css(".job-status--modal-additional-errors", text: "Some errors have occurred", wait: 10) - expect(page).to have_css("ul li", text: "Some error") - expect(page).to have_css("ul li", text: "Another error") + expect(page).to have_css('.job-status--modal-additional-errors', text: 'Some errors have occurred', wait: 10) + expect(page).to have_css('ul li', text: 'Some error') + expect(page).to have_css('ul li', text: 'Another error') end end - describe "with a status with error and redirect" do + describe 'with a status with error and redirect' do let!(:status) { create(:delayed_job_status, user: admin) } before do - status.update! payload: { redirect: home_url, errors: ["Some error"] } + status.update! payload: { redirect: home_url, errors: ['Some error'] } end - it "does not automatically redirect" do + it 'does not automatically redirect' do visit "/job_statuses/#{status.job_id}" - expect(page).to have_css(".job-status--modal-additional-errors", text: "Some errors have occurred", wait: 10) - expect(page).to have_css("ul li", text: "Some error") - expect(page).to have_css("a[href='#{home_url}']", text: "Please click here to continue") + expect(page).to have_css('.job-status--modal-additional-errors', text: 'Some errors have occurred', wait: 10) + expect(page).to have_css('ul li', text: 'Some error') + expect(page).to have_css("a[href='#{home_url}']", text: 'Please click here to continue') end end end diff --git a/modules/job_status/spec/services/documents/create_service_spec.rb b/modules/job_status/spec/services/documents/create_service_spec.rb index 7db35ce1dce2..f2c553849239 100644 --- a/modules/job_status/spec/services/documents/create_service_spec.rb +++ b/modules/job_status/spec/services/documents/create_service_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Documents::CreateService, type: :model do - it_behaves_like "BaseServices create service" + it_behaves_like 'BaseServices create service' end diff --git a/modules/job_status/spec/services/documents/update_service_spec.rb b/modules/job_status/spec/services/documents/update_service_spec.rb index 85326054ae28..cbce9123182d 100644 --- a/modules/job_status/spec/services/documents/update_service_spec.rb +++ b/modules/job_status/spec/services/documents/update_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Documents::UpdateService, type: :model do - it_behaves_like "BaseServices update service" + it_behaves_like 'BaseServices update service' end diff --git a/modules/ldap_groups/app/components/ldap_groups/memberships/table_component.rb b/modules/ldap_groups/app/components/ldap_groups/memberships/table_component.rb index efd7aa5e0a92..f7cc0ef4580b 100644 --- a/modules/ldap_groups/app/components/ldap_groups/memberships/table_component.rb +++ b/modules/ldap_groups/app/components/ldap_groups/memberships/table_component.rb @@ -42,13 +42,13 @@ def sortable? end def empty_row_message - I18n.t "ldap_groups.synchronized_groups.no_members" + I18n.t 'ldap_groups.synchronized_groups.no_members' end def headers [ - ["user", { caption: ::LdapGroups::Membership.human_attribute_name("user") }], - ["added", { caption: ::LdapGroups::Membership.human_attribute_name("created_at") }] + ['user', { caption: ::LdapGroups::Membership.human_attribute_name('user') }], + ['added', { caption: ::LdapGroups::Membership.human_attribute_name('created_at') }] ] end end diff --git a/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/row_component.rb b/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/row_component.rb index 3d9a2bee67c5..896574aa9b73 100644 --- a/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/row_component.rb +++ b/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/row_component.rb @@ -65,7 +65,7 @@ def edit_link link_to I18n.t(:button_edit), { controller: table.target_controller, ldap_filter_id: model.id, action: :edit }, - class: "icon icon-edit", + class: 'icon icon-edit', title: t(:button_edit) end @@ -74,7 +74,7 @@ def delete_link link_to I18n.t(:button_delete), { controller: table.target_controller, ldap_filter_id: model.id, action: :destroy_info }, - class: "icon icon-delete", + class: 'icon icon-delete', title: t(:button_delete) end end diff --git a/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/table_component.rb b/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/table_component.rb index 150c8944882e..b1aed9b41ba0 100644 --- a/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/table_component.rb +++ b/modules/ldap_groups/app/components/ldap_groups/synchronized_filters/table_component.rb @@ -38,7 +38,7 @@ def initial_sort end def target_controller - "ldap_groups/synchronized_filters" + 'ldap_groups/synchronized_filters' end def sortable? @@ -47,18 +47,18 @@ def sortable? def inline_create_link link_to({ controller: target_controller, action: :new }, - class: "budget-add-row wp-inline-create--add-link", - title: I18n.t("ldap_groups.synchronized_filters.add_new")) do - helpers.op_icon("icon icon-add") + class: 'budget-add-row wp-inline-create--add-link', + title: I18n.t('ldap_groups.synchronized_filters.add_new')) do + helpers.op_icon('icon icon-add') end end def headers [ - ["name", { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name("name") }], - ["auth_source", { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name("auth_source") }], - ["groups", { caption: I18n.t("ldap_groups.synchronized_groups.plural") }], - ["sync_users", { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name("sync_users") }] + ['name', { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name('name') }], + ['auth_source', { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name('auth_source') }], + ['groups', { caption: I18n.t('ldap_groups.synchronized_groups.plural') }], + ['sync_users', { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name('sync_users') }] ] end end diff --git a/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/row_component.rb b/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/row_component.rb index e8c9a2a29fec..6f752c6da103 100644 --- a/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/row_component.rb +++ b/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/row_component.rb @@ -64,7 +64,7 @@ def delete_link link_to I18n.t(:button_delete), { controller: table.target_controller, ldap_group_id: model.id, action: :destroy_info }, - class: "icon icon-delete", + class: 'icon icon-delete', title: t(:button_delete) end end diff --git a/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/table_component.rb b/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/table_component.rb index d89594cbb804..24878b914a7d 100644 --- a/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/table_component.rb +++ b/modules/ldap_groups/app/components/ldap_groups/synchronized_groups/table_component.rb @@ -38,7 +38,7 @@ def initial_sort end def target_controller - "ldap_groups/synchronized_groups" + 'ldap_groups/synchronized_groups' end def sortable? @@ -51,23 +51,23 @@ def sortable_column?(_column) def inline_create_link link_to({ controller: target_controller, action: :new }, - class: "budget-add-row wp-inline-create--add-link", - title: I18n.t("ldap_groups.synchronized_groups.add_new")) do - helpers.op_icon("icon icon-add") + class: 'budget-add-row wp-inline-create--add-link', + title: I18n.t('ldap_groups.synchronized_groups.add_new')) do + helpers.op_icon('icon icon-add') end end def empty_row_message - I18n.t "ldap_groups.synchronized_groups.no_results" + I18n.t 'ldap_groups.synchronized_groups.no_results' end def headers [ - ["dn", { caption: ::LdapGroups::SynchronizedGroup.human_attribute_name("dn") }], - ["ldap_auth_source", { caption: ::LdapGroups::SynchronizedGroup.human_attribute_name("ldap_auth_source") }], - ["group", { caption: I18n.t(:label_group) }], - ["users", { caption: I18n.t(:label_user_plural) }], - ["sync_users", { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name("sync_users") }] + ['dn', { caption: ::LdapGroups::SynchronizedGroup.human_attribute_name('dn') }], + ['ldap_auth_source', { caption: ::LdapGroups::SynchronizedGroup.human_attribute_name('ldap_auth_source') }], + ['group', { caption: I18n.t(:label_group) }], + ['users', { caption: I18n.t(:label_user_plural) }], + ['sync_users', { caption: ::LdapGroups::SynchronizedFilter.human_attribute_name('sync_users') }] ] end end diff --git a/modules/ldap_groups/app/controllers/ldap_groups/synchronized_filters_controller.rb b/modules/ldap_groups/app/controllers/ldap_groups/synchronized_filters_controller.rb index 3cb6f03a9bd6..fc1008019a91 100644 --- a/modules/ldap_groups/app/controllers/ldap_groups/synchronized_filters_controller.rb +++ b/modules/ldap_groups/app/controllers/ldap_groups/synchronized_filters_controller.rb @@ -4,7 +4,7 @@ class SynchronizedFiltersController < ::ApplicationController before_action :check_ee before_action :find_filter, except: %i[new create] - layout "admin" + layout 'admin' menu_item :plugin_ldap_groups def new @@ -59,7 +59,7 @@ def synchronize call.on_success do count = call.result symbol = count > 0 ? :notice : :info - flash[symbol] = I18n.t("ldap_groups.synchronized_filters.label_n_groups_found", count:) + flash[symbol] = I18n.t('ldap_groups.synchronized_filters.label_n_groups_found', count:) end call.on_failure do @@ -79,7 +79,7 @@ def find_filter def check_ee unless EnterpriseToken.allows_to?(:ldap_groups) - render template: "ldap_groups/synchronized_groups/upsale" + render template: 'ldap_groups/synchronized_groups/upsale' false end end @@ -91,7 +91,7 @@ def permitted_params end def default_breadcrumb - ActionController::Base.helpers.link_to(t("ldap_groups.synchronized_groups.plural"), ldap_groups_synchronized_groups_path) + ActionController::Base.helpers.link_to(t('ldap_groups.synchronized_groups.plural'), ldap_groups_synchronized_groups_path) end def show_local_breadcrumb diff --git a/modules/ldap_groups/app/controllers/ldap_groups/synchronized_groups_controller.rb b/modules/ldap_groups/app/controllers/ldap_groups/synchronized_groups_controller.rb index dd7a9ec36609..eb577d4040c5 100644 --- a/modules/ldap_groups/app/controllers/ldap_groups/synchronized_groups_controller.rb +++ b/modules/ldap_groups/app/controllers/ldap_groups/synchronized_groups_controller.rb @@ -4,7 +4,7 @@ class SynchronizedGroupsController < ::ApplicationController before_action :check_ee before_action :find_group, only: %i(show destroy_info destroy) - layout "admin" + layout 'admin' menu_item :plugin_ldap_groups include PaginationHelper @@ -58,7 +58,7 @@ def find_group def check_ee unless EnterpriseToken.allows_to?(:ldap_groups) - render template: "ldap_groups/synchronized_groups/upsale" + render template: 'ldap_groups/synchronized_groups/upsale' false end end @@ -70,10 +70,10 @@ def permitted_params end def default_breadcrumb - if action_name == "index" - t("ldap_groups.synchronized_groups.plural") + if action_name == 'index' + t('ldap_groups.synchronized_groups.plural') else - ActionController::Base.helpers.link_to(t("ldap_groups.synchronized_groups.plural"), ldap_groups_synchronized_groups_path) + ActionController::Base.helpers.link_to(t('ldap_groups.synchronized_groups.plural'), ldap_groups_synchronized_groups_path) end end diff --git a/modules/ldap_groups/app/models/ldap_groups.rb b/modules/ldap_groups/app/models/ldap_groups.rb index 3d3053d2cff9..5a024ac7392e 100644 --- a/modules/ldap_groups/app/models/ldap_groups.rb +++ b/modules/ldap_groups/app/models/ldap_groups.rb @@ -1,5 +1,5 @@ module LdapGroups def self.table_name_prefix - "ldap_groups_" + 'ldap_groups_' end end diff --git a/modules/ldap_groups/app/models/ldap_groups/membership.rb b/modules/ldap_groups/app/models/ldap_groups/membership.rb index e0a70119a1d6..4396f78c866b 100644 --- a/modules/ldap_groups/app/models/ldap_groups/membership.rb +++ b/modules/ldap_groups/app/models/ldap_groups/membership.rb @@ -2,7 +2,7 @@ module LdapGroups class Membership < ApplicationRecord belongs_to :user belongs_to :group, - class_name: "::LdapGroups::SynchronizedGroup", + class_name: '::LdapGroups::SynchronizedGroup', counter_cache: :users_count validates_uniqueness_of :user_id, scope: :group_id diff --git a/modules/ldap_groups/app/models/ldap_groups/synchronized_filter.rb b/modules/ldap_groups/app/models/ldap_groups/synchronized_filter.rb index 10a4e563ff93..43baa15f7cec 100644 --- a/modules/ldap_groups/app/models/ldap_groups/synchronized_filter.rb +++ b/modules/ldap_groups/app/models/ldap_groups/synchronized_filter.rb @@ -1,13 +1,13 @@ -require "net/ldap" -require "net/ldap/dn" +require 'net/ldap' +require 'net/ldap/dn' module LdapGroups class SynchronizedFilter < ApplicationRecord belongs_to :ldap_auth_source has_many :groups, - class_name: "::LdapGroups::SynchronizedGroup", - foreign_key: "filter_id", + class_name: '::LdapGroups::SynchronizedGroup', + foreign_key: 'filter_id', dependent: :destroy validates_presence_of :name @@ -28,7 +28,7 @@ def seeded_from_env? return false if ldap_auth_source.nil? ldap_auth_source&.seeded_from_env? && - Setting.seed_ldap.dig(ldap_auth_source.name, "groupfilter", name) + Setting.seed_ldap.dig(ldap_auth_source.name, 'groupfilter', name) end private diff --git a/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb b/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb index b5778ef039b8..dbcd0be5a89c 100644 --- a/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb +++ b/modules/ldap_groups/app/models/ldap_groups/synchronized_group.rb @@ -1,5 +1,5 @@ -require "net/ldap" -require "net/ldap/dn" +require 'net/ldap' +require 'net/ldap/dn' module LdapGroups class SynchronizedGroup < ApplicationRecord @@ -8,12 +8,12 @@ class SynchronizedGroup < ApplicationRecord belongs_to :ldap_auth_source belongs_to :filter, - class_name: "::LdapGroups::SynchronizedFilter" + class_name: '::LdapGroups::SynchronizedFilter' has_many :users, - class_name: "::LdapGroups::Membership", + class_name: '::LdapGroups::Membership', dependent: :delete_all, - foreign_key: "group_id" + foreign_key: 'group_id' validates_presence_of :dn validates_presence_of :group diff --git a/modules/ldap_groups/app/services/ldap_groups/synchronize_filter_service.rb b/modules/ldap_groups/app/services/ldap_groups/synchronize_filter_service.rb index 26525d6b99f5..2010d084764f 100644 --- a/modules/ldap_groups/app/services/ldap_groups/synchronize_filter_service.rb +++ b/modules/ldap_groups/app/services/ldap_groups/synchronize_filter_service.rb @@ -61,7 +61,7 @@ def search(filter, ldap_con, &) ldap_con.search( base: filter.used_base_dn, filter: filter.parsed_filter_string, - attributes: ["dn", filter.group_name_attribute], + attributes: ['dn', filter.group_name_attribute], & ) end diff --git a/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/destroy_info.html.erb b/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/destroy_info.html.erb index 70f764b8694f..2690d747eedd 100644 --- a/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/destroy_info.html.erb +++ b/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/destroy_info.html.erb @@ -54,7 +54,7 @@
    - <%= styled_button_tag title: t(:button_delete), class: '-primary', disabled: true do + <%= styled_button_tag title: t(:button_delete), class: '-highlight', disabled: true do concat content_tag :i, '', class: 'button--icon icon-delete' concat content_tag :span, t(:button_delete), class: 'button--text' end %> @@ -65,3 +65,4 @@
    <% end %> + diff --git a/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/edit.html.erb b/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/edit.html.erb index 44ea00bf8298..566e8af702c5 100644 --- a/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/edit.html.erb +++ b/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/edit.html.erb @@ -10,7 +10,8 @@ <%= render partial: 'form', locals: { f: f } %>

    - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { action: :show }, class: 'button -with-icon icon-cancel' %>

    <% end %> + diff --git a/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/new.html.erb b/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/new.html.erb index 2953cf40fc92..4111fbb90e1a 100644 --- a/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/new.html.erb +++ b/modules/ldap_groups/app/views/ldap_groups/synchronized_filters/new.html.erb @@ -10,7 +10,8 @@ <%= render partial: 'form', locals: { f: f } %>

    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), ldap_groups_synchronized_groups_path, class: 'button -with-icon icon-cancel' %>

    <% end %> + diff --git a/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/destroy_info.html.erb b/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/destroy_info.html.erb index 8c9da393ae5a..bf65a30c5705 100644 --- a/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/destroy_info.html.erb +++ b/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/destroy_info.html.erb @@ -21,7 +21,7 @@

    - <%= styled_button_tag title: t(:button_delete), class: '-primary', disabled: true do + <%= styled_button_tag title: t(:button_delete), class: '-highlight', disabled: true do concat content_tag :i, '', class: 'button--icon icon-delete' concat content_tag :span, t(:button_delete), class: 'button--text' end %> @@ -32,3 +32,4 @@
    <% end %> + diff --git a/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/new.html.erb b/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/new.html.erb index 42cf3962f805..74ca579a3b94 100644 --- a/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/new.html.erb +++ b/modules/ldap_groups/app/views/ldap_groups/synchronized_groups/new.html.erb @@ -56,7 +56,8 @@

    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), url_for(action: :index), class: 'button -with-icon icon-cancel' %>

    <% end %> + diff --git a/modules/ldap_groups/app/workers/ldap_groups/synchronization_job.rb b/modules/ldap_groups/app/workers/ldap_groups/synchronization_job.rb index afde20b08a36..e2fdf2525925 100644 --- a/modules/ldap_groups/app/workers/ldap_groups/synchronization_job.rb +++ b/modules/ldap_groups/app/workers/ldap_groups/synchronization_job.rb @@ -27,7 +27,10 @@ #++ module LdapGroups - class SynchronizationJob < ApplicationJob + class SynchronizationJob < ::Cron::CronJob + # Run every 30 minutes + self.cron_expression = '*/30 * * * *' + def perform return unless EnterpriseToken.allows_to?(:ldap_groups) return if skipped? diff --git a/modules/ldap_groups/config/locales/crowdin/zh-CN.yml b/modules/ldap_groups/config/locales/crowdin/zh-CN.yml index 4d0259eed6ce..d551c0a9e91e 100644 --- a/modules/ldap_groups/config/locales/crowdin/zh-CN.yml +++ b/modules/ldap_groups/config/locales/crowdin/zh-CN.yml @@ -1,7 +1,7 @@ zh-CN: plugin_openproject_ldap_groups: name: "OpenProject LDAP 组" - description: "LDAP 组成员同步。" + description: "LDAP组成员同步。" activerecord: attributes: ldap_groups/synchronized_group: diff --git a/modules/ldap_groups/config/locales/crowdin/zh-TW.yml b/modules/ldap_groups/config/locales/crowdin/zh-TW.yml index 6f0cb1bf00fc..c32bdadf911f 100644 --- a/modules/ldap_groups/config/locales/crowdin/zh-TW.yml +++ b/modules/ldap_groups/config/locales/crowdin/zh-TW.yml @@ -9,7 +9,7 @@ zh-TW: ldap_auth_source: 'LDAP 連線' sync_users: '同步使用者' ldap_groups/synchronized_filter: - filter_string: '簡約登入目錄制約(LDAP)篩選' + filter_string: 'LDAP篩選條件' ldap_auth_source: 'LDAP 連線' group_name_attribute: "群組名字屬性" sync_users: '同步使用者' diff --git a/modules/ldap_groups/config/routes.rb b/modules/ldap_groups/config/routes.rb index f66e6f61535a..e4aec6a09d64 100644 --- a/modules/ldap_groups/config/routes.rb +++ b/modules/ldap_groups/config/routes.rb @@ -1,14 +1,14 @@ Rails.application.routes.draw do - namespace "ldap_groups" do + namespace 'ldap_groups' do resources :synchronized_filters, param: :ldap_filter_id, except: %i(index) do member do # Extract groups from filter - get "synchronize" + get 'synchronize' # Destroy warning - get "destroy_info" + get 'destroy_info' end end @@ -17,7 +17,7 @@ only: %i(new index create show destroy) do member do # Destroy warning - get "destroy_info" + get 'destroy_info' end end end diff --git a/modules/ldap_groups/db/migrate/20200427082928_ldap_groups_timestamps.rb b/modules/ldap_groups/db/migrate/20200427082928_ldap_groups_timestamps.rb index fe961cfdc9ea..3067955900fb 100644 --- a/modules/ldap_groups/db/migrate/20200427082928_ldap_groups_timestamps.rb +++ b/modules/ldap_groups/db/migrate/20200427082928_ldap_groups_timestamps.rb @@ -28,14 +28,14 @@ class LdapGroupsTimestamps < ActiveRecord::Migration[6.0] def up - change_column_default :ldap_groups_synchronized_groups, :created_at, -> { "CURRENT_TIMESTAMP" } - change_column_default :ldap_groups_synchronized_groups, :updated_at, -> { "CURRENT_TIMESTAMP" } + change_column_default :ldap_groups_synchronized_groups, :created_at, -> { 'CURRENT_TIMESTAMP' } + change_column_default :ldap_groups_synchronized_groups, :updated_at, -> { 'CURRENT_TIMESTAMP' } - change_column_default :ldap_groups_synchronized_filters, :created_at, -> { "CURRENT_TIMESTAMP" } - change_column_default :ldap_groups_synchronized_filters, :updated_at, -> { "CURRENT_TIMESTAMP" } + change_column_default :ldap_groups_synchronized_filters, :created_at, -> { 'CURRENT_TIMESTAMP' } + change_column_default :ldap_groups_synchronized_filters, :updated_at, -> { 'CURRENT_TIMESTAMP' } - change_column_default :ldap_groups_memberships, :created_at, -> { "CURRENT_TIMESTAMP" } - change_column_default :ldap_groups_memberships, :updated_at, -> { "CURRENT_TIMESTAMP" } + change_column_default :ldap_groups_memberships, :created_at, -> { 'CURRENT_TIMESTAMP' } + change_column_default :ldap_groups_memberships, :updated_at, -> { 'CURRENT_TIMESTAMP' } end def down diff --git a/modules/ldap_groups/db/migrate/20210219092709_move_base_dn_into_filters.rb b/modules/ldap_groups/db/migrate/20210219092709_move_base_dn_into_filters.rb index ed3c54a80873..630b89f12484 100644 --- a/modules/ldap_groups/db/migrate/20210219092709_move_base_dn_into_filters.rb +++ b/modules/ldap_groups/db/migrate/20210219092709_move_base_dn_into_filters.rb @@ -28,7 +28,7 @@ class MoveBaseDnIntoFilters < ActiveRecord::Migration[6.1] class MigratingAuthSource < ApplicationRecord - self.table_name = "auth_sources" + self.table_name = 'auth_sources' end def change diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb b/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb index 50e9b44d4fdb..e462c7464ea8 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/engine.rb @@ -4,29 +4,22 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-ldap_groups", - author_url: "https://github.com/opf/openproject-ldap_groups", + register 'openproject-ldap_groups', + author_url: 'https://github.com/opf/openproject-ldap_groups', bundled: true, settings: { default: {} } do menu :admin_menu, :plugin_ldap_groups, - { controller: "/ldap_groups/synchronized_groups", action: :index }, + { controller: '/ldap_groups/synchronized_groups', action: :index }, parent: :authentication, last: true, - caption: ->(*) { I18n.t("ldap_groups.label_menu_item") }, - enterprise_feature: "ldap_groups" + caption: ->(*) { I18n.t('ldap_groups.label_menu_item') }, + enterprise_feature: 'ldap_groups' end - add_cron_jobs do - { - "Ldap::SynchronizationJob": { - cron: "30 23 * * *", # Run once per night at 11:30pm - class: Ldap::SynchronizationJob.name - } - } - end + add_cron_jobs { LdapGroups::SynchronizationJob } patches %i[LdapAuthSource Group User] end diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/patches/group_patch.rb b/modules/ldap_groups/lib/open_project/ldap_groups/patches/group_patch.rb index 9b2b475b241c..a28cdeef1846 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/patches/group_patch.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/patches/group_patch.rb @@ -4,7 +4,7 @@ module GroupPatch def self.included(base) # :nodoc: base.class_eval do has_many :ldap_groups_synchronized_groups, - class_name: "::LdapGroups::SynchronizedGroup", + class_name: '::LdapGroups::SynchronizedGroup', dependent: :destroy end end diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/patches/ldap_auth_source_patch.rb b/modules/ldap_groups/lib/open_project/ldap_groups/patches/ldap_auth_source_patch.rb index c738d0569558..b5137b1e17a0 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/patches/ldap_auth_source_patch.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/patches/ldap_auth_source_patch.rb @@ -4,11 +4,11 @@ module LdapAuthSourcePatch def self.included(base) # :nodoc: base.class_eval do has_many :ldap_groups_synchronized_groups, - class_name: "::LdapGroups::SynchronizedGroup", + class_name: '::LdapGroups::SynchronizedGroup', dependent: :destroy has_many :ldap_groups_synchronized_filters, - class_name: "::LdapGroups::SynchronizedFilter", + class_name: '::LdapGroups::SynchronizedFilter', dependent: :destroy end end diff --git a/modules/ldap_groups/lib/open_project/ldap_groups/patches/user_patch.rb b/modules/ldap_groups/lib/open_project/ldap_groups/patches/user_patch.rb index f458ddf8714e..2860baa3e5f0 100644 --- a/modules/ldap_groups/lib/open_project/ldap_groups/patches/user_patch.rb +++ b/modules/ldap_groups/lib/open_project/ldap_groups/patches/user_patch.rb @@ -4,7 +4,7 @@ module UserPatch def self.included(base) # :nodoc: base.class_eval do has_many :ldap_groups_memberships, - class_name: "::LdapGroups::Membership", + class_name: '::LdapGroups::Membership', dependent: :destroy end end diff --git a/modules/ldap_groups/lib/openproject-ldap_groups.rb b/modules/ldap_groups/lib/openproject-ldap_groups.rb index c87a86e554d1..5b2bdd18f8b5 100644 --- a/modules/ldap_groups/lib/openproject-ldap_groups.rb +++ b/modules/ldap_groups/lib/openproject-ldap_groups.rb @@ -1 +1 @@ -require "open_project/ldap_groups" +require 'open_project/ldap_groups' diff --git a/modules/ldap_groups/lib/tasks/ldap_groups.rake b/modules/ldap_groups/lib/tasks/ldap_groups.rake index ff24331508a8..f67f3627ff07 100644 --- a/modules/ldap_groups/lib/tasks/ldap_groups.rake +++ b/modules/ldap_groups/lib/tasks/ldap_groups.rake @@ -27,13 +27,13 @@ #++ namespace :ldap_groups do - desc "Synchronize groups and their users from the LDAP auth source." \ - "Will only synchronize for those users already present in the application." + desc 'Synchronize groups and their users from the LDAP auth source.' \ + 'Will only synchronize for those users already present in the application.' task synchronize: :environment do LdapGroups::SynchronizationService.synchronize! end - desc "Print all members of groups tied to a synchronized group that are not derived from LDAP" + desc 'Print all members of groups tied to a synchronized group that are not derived from LDAP' task print_unsynced_members: :environment do LdapGroups::SynchronizedGroup .includes(:group) @@ -52,37 +52,37 @@ namespace :ldap_groups do end namespace :development do - desc "Create a development LDAP server from the fixtures LDIF" + desc 'Create a development LDAP server from the fixtures LDIF' task ldap_server: :environment do - require "ladle" - ldif = ENV.fetch("LDIF_FILE") { Rails.root.join("spec/fixtures/ldap/users.ldif") } - ldap_server = Ladle::Server.new(quiet: false, port: "12389", domain: "dc=example,dc=com", ldif:).start + require 'ladle' + ldif = ENV.fetch('LDIF_FILE') { Rails.root.join('spec/fixtures/ldap/users.ldif') } + ldap_server = Ladle::Server.new(quiet: false, port: '12389', domain: 'dc=example,dc=com', ldif:).start puts "Creating a connection called ladle" - source = LdapAuthSource.find_or_initialize_by(name: "ladle local development") + source = LdapAuthSource.find_or_initialize_by(name: 'ladle local development') source.attributes = { - host: "localhost", - port: "12389", - tls_mode: "plain_ldap", - account: "uid=admin,ou=system", - account_password: "secret", - base_dn: "dc=example,dc=com", + host: 'localhost', + port: '12389', + tls_mode: 'plain_ldap', + account: 'uid=admin,ou=system', + account_password: 'secret', + base_dn: 'dc=example,dc=com', onthefly_register: true, - attr_login: "uid", - attr_firstname: "givenName", - attr_lastname: "sn", - attr_mail: "mail", - attr_admin: "isAdmin" + attr_login: 'uid', + attr_firstname: 'givenName', + attr_lastname: 'sn', + attr_mail: 'mail', + attr_admin: 'isAdmin' } source.save! - filter = LdapGroups::SynchronizedFilter.find_or_initialize_by(ldap_auth_source: source, name: "All groups") - filter.group_name_attribute = "dn" + filter = LdapGroups::SynchronizedFilter.find_or_initialize_by(ldap_auth_source: source, name: 'All groups') + filter.group_name_attribute = 'dn' filter.sync_users = true - filter.filter_string = "(cn=*)" - filter.base_dn = "ou=groups,dc=example,dc=com" + filter.filter_string = '(cn=*)' + filter.base_dn = 'ou=groups,dc=example,dc=com' filter.save! @@ -139,7 +139,7 @@ namespace :ldap_groups do INFO puts "Send CTRL+D to stop the server" - require "irb" + require 'irb' binding.irb ldap_server.stop diff --git a/modules/ldap_groups/openproject-ldap_groups.gemspec b/modules/ldap_groups/openproject-ldap_groups.gemspec index 9749a9cca516..30b69af57d73 100644 --- a/modules/ldap_groups/openproject-ldap_groups.gemspec +++ b/modules/ldap_groups/openproject-ldap_groups.gemspec @@ -1,14 +1,14 @@ Gem::Specification.new do |s| s.name = "openproject-ldap_groups" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH, Oliver Günther" s.email = "info@openproject.com" s.homepage = "https://github.com/opf/openproject-ldap_groups" - s.summary = "OpenProject LDAP groups" - s.description = "Synchronization of LDAP group memberships" - s.license = "GPL-3" + s.summary = 'OpenProject LDAP groups' + s.description = 'Synchronization of LDAP group memberships' + s.license = 'GPL-3' s.files = Dir["{app,config,db,lib}/**/*"] + %w(README.md) - s.add_development_dependency "ladle" - s.metadata["rubygems_mfa_required"] = "true" + s.add_development_dependency 'ladle' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/ldap_groups/spec/controllers/synchronized_groups_controller_spec.rb b/modules/ldap_groups/spec/controllers/synchronized_groups_controller_spec.rb index e6699c875cb3..51d0eb64750b 100644 --- a/modules/ldap_groups/spec/controllers/synchronized_groups_controller_spec.rb +++ b/modules/ldap_groups/spec/controllers/synchronized_groups_controller_spec.rb @@ -1,4 +1,4 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' RSpec.describe LdapGroups::SynchronizedGroupsController, with_ee: %i[ldap_groups] do let(:user) { create(:user) } @@ -8,92 +8,92 @@ allow(User).to receive(:current).and_return(logged_in_user) end - describe "#index" do + describe '#index' do before do get :index end - context "when not admin" do + context 'when not admin' do let(:logged_in_user) { user } - it "does not give access" do + it 'does not give access' do expect(response.status).to eq 403 end end - context "when admin" do + context 'when admin' do let(:logged_in_user) { admin } - it "renders the page" do + it 'renders the page' do expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end end end - describe "#show" do - context "when not admin" do + describe '#show' do + context 'when not admin' do let(:logged_in_user) { user } - let(:id) { "whatever" } + let(:id) { 'whatever' } - it "does not give access" do + it 'does not give access' do get :show, params: { ldap_group_id: id } expect(response.status).to eq 403 end end - context "when admin" do + context 'when admin' do let(:logged_in_user) { admin } - context "when no entry exists" do - let(:id) { "foo" } + context 'when no entry exists' do + let(:id) { 'foo' } - it "renders 404" do + it 'renders 404' do get :show, params: { ldap_group_id: id } expect(response.status).to eq(404) end end - context "when entry exists" do + context 'when entry exists' do let!(:group) { build_stubbed(:ldap_synchronized_group) } - let(:id) { "foo" } + let(:id) { 'foo' } - it "renders the page" do + it 'renders the page' do expect(LdapGroups::SynchronizedGroup) .to receive(:find) - .with("foo") + .with('foo') .and_return(group) get :show, params: { ldap_group_id: id } expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' end end end end - describe "#new" do - context "when not admin" do + describe '#new' do + context 'when not admin' do let(:logged_in_user) { user } - it "does not give access" do + it 'does not give access' do get :new expect(response.status).to eq 403 end end - context "when admin" do + context 'when admin' do let(:logged_in_user) { admin } - it "renders the page" do + it 'renders the page' do get :new expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end end end - describe "#create" do + describe '#create' do let(:save_result) { false } before do @@ -101,40 +101,40 @@ post :create, params: { synchronized_group: params } end - context "when not admin" do + context 'when not admin' do let(:logged_in_user) { user } let(:params) { {} } - it "does not give access" do + it 'does not give access' do expect(response.status).to eq 403 end end - context "when admin" do + context 'when admin' do let(:logged_in_user) { admin } - context "with invalid params" do + context 'with invalid params' do let(:params) { {} } - it "renders 400" do + it 'renders 400' do expect(response.status).to eq(400) end end - context "with valid params" do - let(:params) { { ldap_auth_source_id: 1, group_id: 1, dn: "cn=foo,ou=groups,dc=example,dc=com" } } + context 'with valid params' do + let(:params) { { ldap_auth_source_id: 1, group_id: 1, dn: 'cn=foo,ou=groups,dc=example,dc=com' } } - context "and saving succeeds" do + context 'and saving succeeds' do let(:save_result) { true } - it "renders 200" do + it 'renders 200' do expect(flash[:notice]).to be_present expect(response).to redirect_to action: :index end end - context "and saving fails" do - it "renders new page" do + context 'and saving fails' do + it 'renders new page' do expect(response.status).to eq(200) expect(response).to render_template :new end @@ -143,78 +143,78 @@ end end - describe "#destroy_info" do - context "when not admin" do + describe '#destroy_info' do + context 'when not admin' do let(:logged_in_user) { user } - let(:id) { "whatever" } + let(:id) { 'whatever' } - it "does not give access" do + it 'does not give access' do get :destroy_info, params: { ldap_group_id: id } expect(response.status).to eq 403 end end - context "when admin" do + context 'when admin' do let(:logged_in_user) { admin } - context "when no entry exists" do - let(:id) { "foo" } + context 'when no entry exists' do + let(:id) { 'foo' } - it "renders 404" do + it 'renders 404' do get :destroy_info, params: { ldap_group_id: id } expect(response.status).to eq(404) end end - context "when entry exists" do + context 'when entry exists' do let!(:group) { build_stubbed(:ldap_synchronized_group) } - let(:id) { "foo" } + let(:id) { 'foo' } - it "renders the page" do + it 'renders the page' do expect(LdapGroups::SynchronizedGroup) .to receive(:find) - .with("foo") + .with('foo') .and_return(group) get :destroy_info, params: { ldap_group_id: id } expect(response).to be_successful - expect(response).to render_template "destroy_info" + expect(response).to render_template 'destroy_info' end end end end - describe "#destroy" do - context "when not admin" do + describe '#destroy' do + context 'when not admin' do let(:logged_in_user) { user } - let(:id) { "whatever" } + let(:id) { 'whatever' } - it "does not give access" do + it 'does not give access' do delete :destroy, params: { ldap_group_id: id } expect(response.status).to eq 403 end end - context "when admin" do + context 'when admin' do let(:logged_in_user) { admin } - context "when no entry exists" do - let(:id) { "foo" } + context 'when no entry exists' do + let(:id) { 'foo' } - it "renders 404" do + it 'renders 404' do delete :destroy, params: { ldap_group_id: id } expect(response.status).to eq(404) end end - context "when entry exists" do + context 'when entry exists' do let!(:group) { build_stubbed(:ldap_synchronized_group) } - let(:id) { "foo" } + let(:id) { 'foo' } before do expect(LdapGroups::SynchronizedGroup) .to receive(:find) - .with("foo") + .with('foo') .and_return(group) expect(group) @@ -222,20 +222,20 @@ .and_return(destroy_result) end - context "when deletion succeeds" do + context 'when deletion succeeds' do let(:destroy_result) { true } - it "redirects to index" do + it 'redirects to index' do delete :destroy, params: { ldap_group_id: id } expect(flash[:notice]).to be_present expect(response).to redirect_to action: :index end end - context "when deletion fails" do + context 'when deletion fails' do let(:destroy_result) { false } - it "redirects to index" do + it 'redirects to index' do delete :destroy, params: { ldap_group_id: id } expect(flash[:error]).to be_present expect(response).to redirect_to action: :index diff --git a/modules/ldap_groups/spec/factories/synchronized_filter_factory.rb b/modules/ldap_groups/spec/factories/synchronized_filter_factory.rb index c9840888269a..9c17156c117b 100644 --- a/modules/ldap_groups/spec/factories/synchronized_filter_factory.rb +++ b/modules/ldap_groups/spec/factories/synchronized_filter_factory.rb @@ -1,9 +1,9 @@ FactoryBot.define do - factory :ldap_synchronized_filter, class: "::LdapGroups::SynchronizedFilter" do - name { "foo and bar" } - filter_string { "(|(cn=foo)(cn=bar))" } - group_name_attribute { "cn" } - base_dn { "dc=example,dc=com" } + factory :ldap_synchronized_filter, class: '::LdapGroups::SynchronizedFilter' do + name { 'foo and bar' } + filter_string { '(|(cn=foo)(cn=bar))' } + group_name_attribute { 'cn' } + base_dn { 'dc=example,dc=com' } ldap_auth_source sync_users { true } end diff --git a/modules/ldap_groups/spec/factories/synchronized_group_factory.rb b/modules/ldap_groups/spec/factories/synchronized_group_factory.rb index 7476f3d92b90..9cf539f327f8 100644 --- a/modules/ldap_groups/spec/factories/synchronized_group_factory.rb +++ b/modules/ldap_groups/spec/factories/synchronized_group_factory.rb @@ -1,6 +1,6 @@ FactoryBot.define do - factory :ldap_synchronized_group, class: "::LdapGroups::SynchronizedGroup" do - dn { "cn=foo,ou=groups,dc=example,dc=com" } + factory :ldap_synchronized_group, class: '::LdapGroups::SynchronizedGroup' do + dn { 'cn=foo,ou=groups,dc=example,dc=com' } group factory: :group ldap_auth_source sync_users { true } diff --git a/modules/ldap_groups/spec/features/administration_spec.rb b/modules/ldap_groups/spec/features/administration_spec.rb index 2caeecc8b2eb..37b94cfafc2d 100644 --- a/modules/ldap_groups/spec/features/administration_spec.rb +++ b/modules/ldap_groups/spec/features/administration_spec.rb @@ -1,6 +1,6 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "LDAP group sync administration spec", :js do +RSpec.describe 'LDAP group sync administration spec', :js do let(:admin) { create(:admin) } before do @@ -8,65 +8,65 @@ visit ldap_groups_synchronized_groups_path end - context "without EE" do - it "shows upsale" do - expect(page).to have_css(".upsale-notification") + context 'without EE' do + it 'shows upsale' do + expect(page).to have_css('.upsale-notification') end end - context "with EE", with_ee: %i[ldap_groups] do - let!(:group) { create(:group, lastname: "foo") } - let!(:auth_source) { create(:ldap_auth_source, name: "ldap") } + context 'with EE', with_ee: %i[ldap_groups] do + let!(:group) { create(:group, lastname: 'foo') } + let!(:auth_source) { create(:ldap_auth_source, name: 'ldap') } - it "allows synced group administration flow" do - expect(page).to have_no_css(".upsale-notification") + it 'allows synced group administration flow' do + expect(page).to have_no_css('.upsale-notification') # Create group - find(".button", text: I18n.t("ldap_groups.synchronized_groups.singular")).click + find('.button', text: I18n.t('ldap_groups.synchronized_groups.singular')).click SeleniumHubWaiter.wait - select "ldap", from: "synchronized_group_ldap_auth_source_id" - select "foo", from: "synchronized_group_group_id" - fill_in "synchronized_group_dn", with: "cn=foo,ou=groups,dc=example,dc=com" - check "synchronized_group_sync_users" + select 'ldap', from: 'synchronized_group_ldap_auth_source_id' + select 'foo', from: 'synchronized_group_group_id' + fill_in 'synchronized_group_dn', with: 'cn=foo,ou=groups,dc=example,dc=com' + check 'synchronized_group_sync_users' - click_on "Create" - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_create)) - expect(page).to have_css("td.dn", text: "cn=foo,ou=groups,dc=example,dc=com") - expect(page).to have_css("td.ldap_auth_source", text: "ldap") - expect(page).to have_css("td.group", text: "foo") - expect(page).to have_css("td.users", text: "0") + click_on 'Create' + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_successful_create)) + expect(page).to have_css('td.dn', text: 'cn=foo,ou=groups,dc=example,dc=com') + expect(page).to have_css('td.ldap_auth_source', text: 'ldap') + expect(page).to have_css('td.group', text: 'foo') + expect(page).to have_css('td.users', text: '0') # Show entry SeleniumHubWaiter.wait - find("td.dn a").click - expect(page).to have_css ".generic-table--empty-row" + find('td.dn a').click + expect(page).to have_css '.generic-table--empty-row' # Check created group sync = LdapGroups::SynchronizedGroup.last expect(sync.group_id).to eq(group.id) expect(sync.ldap_auth_source_id).to eq(auth_source.id) - expect(sync.dn).to eq "cn=foo,ou=groups,dc=example,dc=com" + expect(sync.dn).to eq 'cn=foo,ou=groups,dc=example,dc=com' # Assume we have a membership sync.users.create user_id: admin.id visit ldap_groups_synchronized_group_path(sync) - expect(page).to have_css "td.user", text: admin.name + expect(page).to have_css 'td.user', text: admin.name memberships = sync.users.pluck(:id) visit ldap_groups_synchronized_groups_path expect_angular_frontend_initialized - find(".buttons a", text: "Delete").click + find('.buttons a', text: 'Delete').click SeleniumHubWaiter.wait - find(".danger-zone--verification input").set "cn=foo,ou=groups,dc=example,dc=com" + find('.danger-zone--verification input').set 'cn=foo,ou=groups,dc=example,dc=com' SeleniumHubWaiter.wait - click_on "Delete" + click_on 'Delete' - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_delete)) - expect(page).to have_css ".generic-table--empty-row" + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_successful_delete)) + expect(page).to have_css '.generic-table--empty-row' expect(LdapGroups::Membership.where(id: memberships)).to be_empty end diff --git a/modules/ldap_groups/spec/features/filter_administration_spec.rb b/modules/ldap_groups/spec/features/filter_administration_spec.rb index 1ff1401c9d93..c8a73e803e2b 100644 --- a/modules/ldap_groups/spec/features/filter_administration_spec.rb +++ b/modules/ldap_groups/spec/features/filter_administration_spec.rb @@ -1,14 +1,14 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "LDAP group filter administration spec", :js do +RSpec.describe 'LDAP group filter administration spec', :js do let(:admin) { create(:admin) } before do login_as admin end - context "with EE", with_ee: %i[ldap_groups] do - context "when providing seed variables", + context 'with EE', with_ee: %i[ldap_groups] do + context 'when providing seed variables', :settings_reset, with_env: { OPENPROJECT_SEED_LDAP_FOO_HOST: "localhost", @@ -30,18 +30,18 @@ OPENPROJECT_SEED_LDAP_FOO_GROUPFILTER_BAR_SYNC__USERS: "true", OPENPROJECT_SEED_LDAP_FOO_GROUPFILTER_BAR_GROUP__ATTRIBUTE: "dn" } do - it "blocks editing of the filter" do + it 'blocks editing of the filter' do reset(:seed_ldap) allow(LdapGroups::SynchronizationJob).to receive(:perform_now) EnvData::LdapSeeder.new({}).seed_data! visit ldap_groups_synchronized_groups_path - expect(page).to have_text "bar" - page.find("td.name a", text: "bar").click + expect(page).to have_text 'bar' + page.find('td.name a', text: 'bar').click expect(page).to have_text I18n.t(:label_seeded_from_env_warning) - expect(page).to have_no_link "Edit" - expect(page).to have_no_link "Delete" + expect(page).to have_no_link 'Edit' + expect(page).to have_no_link 'Delete' end end end diff --git a/modules/ldap_groups/spec/models/membership_spec.rb b/modules/ldap_groups/spec/models/membership_spec.rb index d57b2fc64c30..5a75336299d7 100644 --- a/modules/ldap_groups/spec/models/membership_spec.rb +++ b/modules/ldap_groups/spec/models/membership_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe LdapGroups::Membership do - describe "destroy" do + describe 'destroy' do let(:synchronized_group) { create(:ldap_synchronized_group, group:) } let(:group) { create(:group) } let(:user) { create(:user) } @@ -12,7 +12,7 @@ end end - it "is removed when the user is destroyed" do + it 'is removed when the user is destroyed' do expect(user.ldap_groups_memberships.count).to eq 1 membership = user.ldap_groups_memberships.first expect(membership.group).to eq(synchronized_group) diff --git a/modules/ldap_groups/spec/models/synchronized_filter_spec.rb b/modules/ldap_groups/spec/models/synchronized_filter_spec.rb index 80753aaabfb1..0ddbd2b0abd8 100644 --- a/modules/ldap_groups/spec/models/synchronized_filter_spec.rb +++ b/modules/ldap_groups/spec/models/synchronized_filter_spec.rb @@ -1,26 +1,26 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe LdapGroups::SynchronizedFilter do - describe "#used_base_dn" do - let(:ldap_auth_source) { build(:ldap_auth_source, base_dn: "dc=example,dc=com") } + describe '#used_base_dn' do + let(:ldap_auth_source) { build(:ldap_auth_source, base_dn: 'dc=example,dc=com') } let(:filter) { build(:ldap_synchronized_filter, ldap_auth_source:) } - it "validates the end of the base dn matches the ldap_auth_source" do + it 'validates the end of the base dn matches the ldap_auth_source' do filter.base_dn = nil expect(filter.base_dn).to be_nil expect(filter.used_base_dn).to eq(ldap_auth_source.base_dn) end end - describe "#base_dn" do - let(:ldap_auth_source) { build(:ldap_auth_source, base_dn: "dc=example,dc=com") } + describe '#base_dn' do + let(:ldap_auth_source) { build(:ldap_auth_source, base_dn: 'dc=example,dc=com') } let(:filter) { build(:ldap_synchronized_filter, ldap_auth_source:) } - it "validates the end of the base dn matches the ldap_auth_source" do + it 'validates the end of the base dn matches the ldap_auth_source' do filter.base_dn = nil expect(filter).to be_valid - filter.base_dn = "dc=something,dc=else" + filter.base_dn = 'dc=something,dc=else' expect(filter).not_to be_valid expect(filter.errors.details[:base_dn]).to contain_exactly(error: :must_contain_base_dn) end diff --git a/modules/ldap_groups/spec/models/synchronized_group_spec.rb b/modules/ldap_groups/spec/models/synchronized_group_spec.rb index f8a8f8c7aad5..4605b8909f44 100644 --- a/modules/ldap_groups/spec/models/synchronized_group_spec.rb +++ b/modules/ldap_groups/spec/models/synchronized_group_spec.rb @@ -1,19 +1,19 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe LdapGroups::SynchronizedGroup do - describe "validations" do + describe 'validations' do subject { build(:ldap_synchronized_group) } - context "correct attributes" do - it "saves the record" do + context 'correct attributes' do + it 'saves the record' do expect(subject.save).to be true end end - context "missing attributes" do + context 'missing attributes' do subject { described_class.new } - it "validates missing attributes" do + it 'validates missing attributes' do expect(subject.save).to be false expect(subject.errors[:dn]).to include "can't be blank." expect(subject.errors[:ldap_auth_source]).to include "can't be blank." @@ -22,16 +22,16 @@ end end - describe "manipulating members" do + describe 'manipulating members' do let(:users) { [user1, user2] } let(:user1) { create(:user) } let(:user2) { create(:user) } - describe ".add_members!" do + describe '.add_members!' do let(:synchronized_group) { create(:ldap_synchronized_group, group:) } let(:group) { create(:group) } - shared_examples "it adds users to the synchronized group and the internal one" do + shared_examples 'it adds users to the synchronized group and the internal one' do let(:members) { raise "define me!" } before do @@ -43,29 +43,29 @@ end end - it "adds the user(s) to the internal group" do + it 'adds the user(s) to the internal group' do expect(group.reload.users).to match_array users end - it "adds the user(s) to the synchronized group" do + it 'adds the user(s) to the synchronized group' do expect(synchronized_group.reload.users.map(&:user)).to match_array users end end - context "called with user records" do - it_behaves_like "it adds users to the synchronized group and the internal one" do + context 'called with user records' do + it_behaves_like 'it adds users to the synchronized group and the internal one' do let(:members) { users } end end - context "called just with user IDs" do - it_behaves_like "it adds users to the synchronized group and the internal one" do + context 'called just with user IDs' do + it_behaves_like 'it adds users to the synchronized group and the internal one' do let(:members) { users.pluck(:id) } end end end - describe ".remove_members!" do + describe '.remove_members!' do let(:synchronized_group) do create(:ldap_synchronized_group, group:).tap do |sg| group.users.each do |user| @@ -75,43 +75,43 @@ end let(:group) { create(:group, members: users) } - shared_examples "it removes the users from the synchronized group and the internal one" do + shared_examples 'it removes the users from the synchronized group and the internal one' do let(:members) { raise "define me!" } before do synchronized_group.remove_members! members end - it "removes the user(s) from the internal group" do + it 'removes the user(s) from the internal group' do expect(group.reload.users).to be_empty end - it "removes the users(s) from the synchronized group" do + it 'removes the users(s) from the synchronized group' do expect(synchronized_group.users).to be_empty end - it "does not, however, delete the actual users!" do + it 'does not, however, delete the actual users!' do expect(User.find(users.map(&:id))).to match_array users end end - context "called with user records" do - it_behaves_like "it removes the users from the synchronized group and the internal one" do + context 'called with user records' do + it_behaves_like 'it removes the users from the synchronized group and the internal one' do let(:members) { group.users } end end - context "called just with user IDs" do - it_behaves_like "it removes the users from the synchronized group and the internal one" do + context 'called just with user IDs' do + it_behaves_like 'it removes the users from the synchronized group and the internal one' do let(:members) { group.users.pluck(:id) } end end - context "when the service call fails for any reason" do + context 'when the service call fails for any reason' do let(:service) { instance_double(Groups::UpdateService) } - let(:failure_result) { ServiceResult.failure(message: "oh noes") } + let(:failure_result) { ServiceResult.failure(message: 'oh noes') } - it "does not commit the changes" do + it 'does not commit the changes' do allow(Groups::UpdateService).to receive(:new).and_return(service) allow(service).to receive(:call).and_return(failure_result) diff --git a/modules/ldap_groups/spec/services/synchronization_spec.rb b/modules/ldap_groups/spec/services/synchronization_spec.rb index fcbca7507ba3..2b4bfb5da2de 100644 --- a/modules/ldap_groups/spec/services/synchronization_spec.rb +++ b/modules/ldap_groups/spec/services/synchronization_spec.rb @@ -1,11 +1,11 @@ -require File.dirname(__FILE__) + "/../spec_helper" -require "ladle" +require File.dirname(__FILE__) + '/../spec_helper' +require 'ladle' RSpec.describe LdapGroups::SynchronizeGroupsService, with_ee: %i[ldap_groups] do - include_context "with temporary LDAP" + include_context 'with temporary LDAP' let(:plugin_settings) do - { group_base: "ou=groups,dc=example,dc=com", group_key: "cn" } + { group_base: 'ou=groups,dc=example,dc=com', group_key: 'cn' } end # Ldap has: @@ -14,38 +14,38 @@ let(:ldap_auth_source) do create(:ldap_auth_source, port: ParallelHelper.port_for_ldap.to_s, - account: "uid=admin,ou=system", - account_password: "secret", - base_dn: "ou=people,dc=example,dc=com", + account: 'uid=admin,ou=system', + account_password: 'secret', + base_dn: 'ou=people,dc=example,dc=com', onthefly_register:, filter_string: ldap_filter, - attr_login: "uid", - attr_firstname: "givenName", - attr_lastname: "sn", - attr_mail: "mail") + attr_login: 'uid', + attr_firstname: 'givenName', + attr_lastname: 'sn', + attr_mail: 'mail') end let(:onthefly_register) { false } let(:sync_users) { false } let(:ldap_filter) { nil } - let(:user_aa729) { create(:user, login: "aa729", ldap_auth_source:) } - let(:user_bb459) { create(:user, login: "bb459", ldap_auth_source:) } - let(:user_cc414) { create(:user, login: "cc414", ldap_auth_source:) } + let(:user_aa729) { create(:user, login: 'aa729', ldap_auth_source:) } + let(:user_bb459) { create(:user, login: 'bb459', ldap_auth_source:) } + let(:user_cc414) { create(:user, login: 'cc414', ldap_auth_source:) } - let(:group_foo) { create(:group, lastname: "foo_internal") } - let(:group_bar) { create(:group, lastname: "bar") } + let(:group_foo) { create(:group, lastname: 'foo_internal') } + let(:group_bar) { create(:group, lastname: 'bar') } let(:synced_foo) do create(:ldap_synchronized_group, - dn: "cn=foo,ou=groups,dc=example,dc=com", + dn: 'cn=foo,ou=groups,dc=example,dc=com', group: group_foo, sync_users:, ldap_auth_source:) end let(:synced_bar) do create(:ldap_synchronized_group, - dn: "cn=bar,ou=groups,dc=example,dc=com", + dn: 'cn=bar,ou=groups,dc=example,dc=com', group: group_bar, sync_users:, ldap_auth_source:) @@ -58,8 +58,8 @@ end end - shared_examples "does not change membership count" do - it "does not change membership count" do + shared_examples 'does not change membership count' do + it 'does not change membership count' do subject expect(group_foo.users).to be_empty @@ -70,33 +70,33 @@ end end - describe "adding memberships" do - context "when no synced group exists" do + describe 'adding memberships' do + context 'when no synced group exists' do before do user_aa729 user_bb459 user_cc414 end - it_behaves_like "does not change membership count" + it_behaves_like 'does not change membership count' end - context "when one synced group exists" do + context 'when one synced group exists' do before do group_foo synced_foo end - context "when no users exist" do - it_behaves_like "does not change membership count" + context 'when no users exist' do + it_behaves_like 'does not change membership count' end - context "when one mapped user exists" do + context 'when one mapped user exists' do before do user_aa729 end - it "synchronized the membership of aa729 to foo" do + it 'synchronized the membership of aa729 to foo' do subject expect(synced_foo.users.count).to eq(1) expect(group_foo.users).to eq([user_aa729]) @@ -104,7 +104,7 @@ end end - context "when all groups exist" do + context 'when all groups exist' do before do group_foo synced_foo @@ -112,14 +112,14 @@ synced_bar end - context "and all users exist" do + context 'and all users exist' do before do user_aa729 user_bb459 user_cc414 end - describe "synchronizes all memberships" do + describe 'synchronizes all memberships' do before do subject @@ -130,7 +130,7 @@ expect(group_bar.users).to eq([user_aa729, user_bb459, user_cc414]) end - it "removes all memberships after removing synced group" do + it 'removes all memberships after removing synced group' do synced_foo_id = synced_foo.id expect(LdapGroups::Membership.where(group_id: synced_foo_id).count).to eq(1) synced_foo.destroy @@ -140,7 +140,7 @@ expect(LdapGroups::Membership.where(group_id: synced_foo_id)).to be_empty end - it "removes all memberships and groups after removing auth source" do + it 'removes all memberships and groups after removing auth source' do expect { ldap_auth_source.destroy! } .to change { LdapGroups::Membership.count }.from(4).to(0) @@ -148,7 +148,7 @@ expect { synced_bar.reload }.to raise_error ActiveRecord::RecordNotFound end - it "removes all memberships and groups after removing actual group" do + it 'removes all memberships and groups after removing actual group' do synced_foo_id = synced_foo.id expect(LdapGroups::Membership.where(group_id: synced_foo_id).count).to eq(1) group_foo.destroy @@ -162,12 +162,12 @@ end end - context "and only one user of bar exists" do + context 'and only one user of bar exists' do before do user_cc414 end - it "synchronized that membership" do + it 'synchronized that membership' do subject expect(synced_foo.users.count).to eq(0) expect(synced_bar.users.count).to eq(1) @@ -176,15 +176,15 @@ expect(group_bar.users).to eq([user_cc414]) end - context "with LDAP on-the-fly disabled" do + context 'with LDAP on-the-fly disabled' do let(:onthefly_register) { false } - let(:user_aa729) { User.find_by login: "aa729" } - let(:user_bb459) { User.find_by login: "bb459" } + let(:user_aa729) { User.find_by login: 'aa729' } + let(:user_bb459) { User.find_by login: 'bb459' } - context "and users sync in the groups enabled" do + context 'and users sync in the groups enabled' do let(:sync_users) { true } - it "creates the remaining users" do + it 'creates the remaining users' do subject expect(synced_foo.users.count).to eq(1) expect(synced_bar.users.count).to eq(3) @@ -194,10 +194,10 @@ end end - context "and users sync not enabled" do + context 'and users sync not enabled' do let(:sync_users) { false } - it "does not create the users" do + it 'does not create the users' do subject expect(synced_foo.users.count).to eq(0) expect(synced_bar.users.count).to eq(1) @@ -208,15 +208,15 @@ end end - context "with LDAP on-the-fly enabled" do + context 'with LDAP on-the-fly enabled' do let(:onthefly_register) { true } - let(:user_aa729) { User.find_by login: "aa729" } - let(:user_bb459) { User.find_by login: "bb459" } + let(:user_aa729) { User.find_by login: 'aa729' } + let(:user_bb459) { User.find_by login: 'bb459' } - context "and users sync in the groups enabled" do + context 'and users sync in the groups enabled' do let(:sync_users) { true } - it "creates the remaining users" do + it 'creates the remaining users' do subject expect(synced_foo.users.count).to eq(1) expect(synced_bar.users.count).to eq(3) @@ -226,10 +226,10 @@ end end - context "and users sync not enabled" do + context 'and users sync not enabled' do let(:sync_users) { false } - it "does not create the users" do + it 'does not create the users' do subject expect(synced_foo.users.count).to eq(0) expect(synced_bar.users.count).to eq(1) @@ -240,16 +240,16 @@ end end - context "with an LDAP filter for users starting with b and on-the-fly enabled" do + context 'with an LDAP filter for users starting with b and on-the-fly enabled' do let(:onthefly_register) { true } - let(:ldap_filter) { "(uid=b*)" } - let(:user_aa729) { User.find_by login: "aa729" } - let(:user_bb459) { User.find_by login: "bb459" } + let(:ldap_filter) { '(uid=b*)' } + let(:user_aa729) { User.find_by login: 'aa729' } + let(:user_bb459) { User.find_by login: 'bb459' } - context "and users sync in the groups enabled" do + context 'and users sync in the groups enabled' do let(:sync_users) { true } - it "creates the remaining users" do + it 'creates the remaining users' do subject expect(synced_foo.users.count).to eq(0) expect(synced_bar.users.count).to eq(1) @@ -260,10 +260,10 @@ end end - context "and users sync not enabled" do + context 'and users sync not enabled' do let(:sync_users) { false } - it "does not create the users" do + it 'does not create the users' do subject expect(synced_foo.users.count).to eq(0) expect(synced_bar.users.count).to eq(0) @@ -276,15 +276,15 @@ end end - context "foo group exists" do - let(:group_foo) { create(:group, lastname: "foo_internal", members: user_aa729) } + context 'foo group exists' do + let(:group_foo) { create(:group, lastname: 'foo_internal', members: user_aa729) } before do group_foo synced_foo end - it "takes over users that are in LDAP" do + it 'takes over users that are in LDAP' do membership = LdapGroups::Membership.find_by user: user_aa729, group: group_foo expect(membership).not_to be_present @@ -300,11 +300,11 @@ end end - describe "removing memberships" do - context "with a user in a group thats not in ldap" do - let(:group_foo) { create(:group, lastname: "foo_internal", members: [user_cc414, user_aa729]) } - let(:manager) { create(:project_role, name: "Manager") } - let(:project) { create(:project, name: "Project 1", identifier: "project1", members: { group_foo => [manager] }) } + describe 'removing memberships' do + context 'with a user in a group thats not in ldap' do + let(:group_foo) { create(:group, lastname: 'foo_internal', members: [user_cc414, user_aa729]) } + let(:manager) { create(:project_role, name: 'Manager') } + let(:project) { create(:project, name: 'Project 1', identifier: 'project1', members: { group_foo => [manager] }) } before do project @@ -312,7 +312,7 @@ synced_foo.users.create(user: user_cc414) end - it "removes the membership" do + it 'removes the membership' do expect(project.members.count).to eq 2 expect(project.users).to contain_exactly user_aa729, user_cc414 @@ -331,14 +331,14 @@ end end - context "with invalid connection" do + context 'with invalid connection' do let(:ldap_auth_source) { create(:ldap_auth_source) } before do synced_foo end - it "does not raise, but print to stderr" do + it 'does not raise, but print to stderr' do allow(Rails.logger).to receive(:error) subject @@ -348,24 +348,24 @@ end end - context "with invalid base" do + context 'with invalid base' do let(:synced_foo) do - create(:ldap_synchronized_group, dn: "cn=foo,ou=invalid,dc=example,dc=com", group: group_foo, + create(:ldap_synchronized_group, dn: 'cn=foo,ou=invalid,dc=example,dc=com', group: group_foo, ldap_auth_source:) end let(:synced_bar) do - create(:ldap_synchronized_group, dn: "cn=bar,ou=invalid,dc=example,dc=com", group: group_bar, + create(:ldap_synchronized_group, dn: 'cn=bar,ou=invalid,dc=example,dc=com', group: group_bar, ldap_auth_source:) end - context "when one synced group exists" do + context 'when one synced group exists' do before do group_foo synced_foo user_aa729 end - it "does not find the group and syncs no user" do + it 'does not find the group and syncs no user' do subject expect(synced_foo.users).to be_empty expect(group_foo.users).to eq([]) @@ -373,14 +373,14 @@ end end - context "when one user does not match case" do + context 'when one user does not match case' do before do group_foo synced_foo - user_aa729.update_attribute(:login, "Aa729") + user_aa729.update_attribute(:login, 'Aa729') end - it "synchronized the membership of aa729 to foo" do + it 'synchronized the membership of aa729 to foo' do subject expect(synced_foo.users.count).to eq(1) expect(group_foo.users).to eq([user_aa729]) diff --git a/modules/ldap_groups/spec/services/synchronize_filter_spec.rb b/modules/ldap_groups/spec/services/synchronize_filter_spec.rb index c6c0c9ae2ad3..77cc5457eed7 100644 --- a/modules/ldap_groups/spec/services/synchronize_filter_spec.rb +++ b/modules/ldap_groups/spec/services/synchronize_filter_spec.rb @@ -1,10 +1,10 @@ -require File.dirname(__FILE__) + "/../spec_helper" -require "ladle" +require File.dirname(__FILE__) + '/../spec_helper' +require 'ladle' RSpec.describe LdapGroups::SynchronizeFilterService, with_ee: %i[ldap_groups] do before(:all) do - ldif = Rails.root.join("spec/fixtures/ldap/users.ldif") - @ldap_server = Ladle::Server.new(quiet: false, port: ParallelHelper.port_for_ldap.to_s, domain: "dc=example,dc=com", + ldif = Rails.root.join('spec/fixtures/ldap/users.ldif') + @ldap_server = Ladle::Server.new(quiet: false, port: ParallelHelper.port_for_ldap.to_s, domain: 'dc=example,dc=com', ldif:).start end @@ -18,19 +18,19 @@ let(:ldap_auth_source) do create(:ldap_auth_source, port: ParallelHelper.port_for_ldap.to_s, - account: "uid=admin,ou=system", - account_password: "secret", - base_dn: "dc=example,dc=com", - attr_login: "uid") + account: 'uid=admin,ou=system', + account_password: 'secret', + base_dn: 'dc=example,dc=com', + attr_login: 'uid') end - let(:group_foo) { create(:group, lastname: "foo") } - let(:group_bar) { create(:group, lastname: "bar") } + let(:group_foo) { create(:group, lastname: 'foo') } + let(:group_bar) { create(:group, lastname: 'bar') } let(:synced_foo) do create( :ldap_synchronized_group, - dn: "cn=foo,ou=groups,dc=example,dc=com", + dn: 'cn=foo,ou=groups,dc=example,dc=com', group: group_foo, ldap_auth_source: ) @@ -38,7 +38,7 @@ let(:synced_bar) do create( :ldap_synchronized_group, - dn: "cn=bar,ou=groups,dc=example,dc=com", + dn: 'cn=bar,ou=groups,dc=example,dc=com', group: group_bar, ldap_auth_source: ) @@ -48,42 +48,42 @@ subject { described_class.new(filter_foo_bar).call } - shared_examples "has foo and bar synced groups" do - it "creates the two groups" do + shared_examples 'has foo and bar synced groups' do + it 'creates the two groups' do expect { subject }.not_to raise_error filter_foo_bar.reload # Expect two synchronized groups added expect(filter_foo_bar.groups.count).to eq 2 - expect(filter_foo_bar.groups.map(&:dn)).to contain_exactly("cn=foo,ou=groups,dc=example,dc=com", - "cn=bar,ou=groups,dc=example,dc=com") + expect(filter_foo_bar.groups.map(&:dn)).to contain_exactly('cn=foo,ou=groups,dc=example,dc=com', + 'cn=bar,ou=groups,dc=example,dc=com') # Expect two actual groups added - op_foo_group = Group.find_by(lastname: "foo") - op_bar_group = Group.find_by(lastname: "bar") + op_foo_group = Group.find_by(lastname: 'foo') + op_bar_group = Group.find_by(lastname: 'bar') expect(op_foo_group).to be_present expect(op_bar_group).to be_present - sync_foo_group = LdapGroups::SynchronizedGroup.find_by(dn: "cn=foo,ou=groups,dc=example,dc=com") - sync_bar_group = LdapGroups::SynchronizedGroup.find_by(dn: "cn=bar,ou=groups,dc=example,dc=com") + sync_foo_group = LdapGroups::SynchronizedGroup.find_by(dn: 'cn=foo,ou=groups,dc=example,dc=com') + sync_bar_group = LdapGroups::SynchronizedGroup.find_by(dn: 'cn=bar,ou=groups,dc=example,dc=com') expect(sync_foo_group.group).to eq op_foo_group expect(sync_bar_group.group).to eq op_bar_group end end - describe "when filter is new and nothing exists" do - it_behaves_like "has foo and bar synced groups" + describe 'when filter is new and nothing exists' do + it_behaves_like 'has foo and bar synced groups' end - describe "when one group already exists" do + describe 'when one group already exists' do before do synced_foo end - it_behaves_like "has foo and bar synced groups" + it_behaves_like 'has foo and bar synced groups' - it "the group is taken over by the filter" do + it 'the group is taken over by the filter' do expect { subject }.not_to raise_error synced_foo.reload @@ -91,10 +91,10 @@ end end - describe "when one group already exists with different settings" do + describe 'when one group already exists with different settings' do let(:synced_foo) do create(:ldap_synchronized_group, - dn: "cn=foo,ou=groups,dc=example,dc=com", + dn: 'cn=foo,ou=groups,dc=example,dc=com', group: group_foo, sync_users: false, ldap_auth_source:) @@ -109,7 +109,7 @@ synced_foo end - it "the group receives the value of the filter" do + it 'the group receives the value of the filter' do expect(synced_foo.sync_users).to be false expect { subject }.not_to raise_error @@ -118,47 +118,47 @@ end end - describe "when it has a group that no longer exists in ldap" do - let!(:group_doesnotexist) { create(:group, lastname: "doesnotexist") } + describe 'when it has a group that no longer exists in ldap' do + let!(:group_doesnotexist) { create(:group, lastname: 'doesnotexist') } let!(:synced_doesnotexist) do create(:ldap_synchronized_group, - dn: "cn=doesnotexist,ou=groups,dc=example,dc=com", + dn: 'cn=doesnotexist,ou=groups,dc=example,dc=com', group: group_doesnotexist, filter: filter_foo_bar, ldap_auth_source:) end - it "removes that group" do + it 'removes that group' do expect { subject }.not_to raise_error expect { synced_doesnotexist.reload }.to raise_error(ActiveRecord::RecordNotFound) end end - describe "when filter has sync_users selected" do + describe 'when filter has sync_users selected' do let(:filter_foo_bar) { create(:ldap_synchronized_filter, ldap_auth_source:, sync_users: true) } - it "creates the groups with sync_users flag set" do + it 'creates the groups with sync_users flag set' do expect { subject }.not_to raise_error filter_foo_bar.reload # Expect two synchronized groups added expect(filter_foo_bar.groups.count).to eq 2 - sync_foo_group = LdapGroups::SynchronizedGroup.find_by(dn: "cn=foo,ou=groups,dc=example,dc=com") - sync_bar_group = LdapGroups::SynchronizedGroup.find_by(dn: "cn=bar,ou=groups,dc=example,dc=com") + sync_foo_group = LdapGroups::SynchronizedGroup.find_by(dn: 'cn=foo,ou=groups,dc=example,dc=com') + sync_bar_group = LdapGroups::SynchronizedGroup.find_by(dn: 'cn=bar,ou=groups,dc=example,dc=com') expect(sync_foo_group.sync_users).to be_truthy expect(sync_bar_group.sync_users).to be_truthy end end - describe "when filter has its own base dn" do + describe 'when filter has its own base dn' do let(:filter_foo_bar) do create(:ldap_synchronized_filter, ldap_auth_source:, - base_dn: "ou=users,dc=example,dc=com") + base_dn: 'ou=users,dc=example,dc=com') end - it "uses that base for searching and doesnt find any groups" do + it 'uses that base for searching and doesnt find any groups' do expect { subject }.not_to raise_error filter_foo_bar.reload diff --git a/modules/meeting/app/components/banner_message_component.rb b/modules/meeting/app/components/banner_message_component.rb index e72512e4882b..70f33ff8c5cb 100644 --- a/modules/meeting/app/components/banner_message_component.rb +++ b/modules/meeting/app/components/banner_message_component.rb @@ -31,7 +31,7 @@ def initialize(message: nil, full: true, full_when_narrow: false, dismiss_scheme: :hide, - dismiss_label: I18n.t("button_close"), + dismiss_label: I18n.t('button_close'), icon: false, scheme: :default, test_selector: "primer-banner-message-component") diff --git a/modules/meeting/app/components/meeting_agenda_items/form_component.rb b/modules/meeting/app/components/meeting_agenda_items/form_component.rb index 39d90ce694a6..599b74882395 100644 --- a/modules/meeting/app/components/meeting_agenda_items/form_component.rb +++ b/modules/meeting/app/components/meeting_agenda_items/form_component.rb @@ -56,9 +56,9 @@ def render? def wrapper_data_attributes { - controller: "meeting-agenda-item-form", - "application-target": "dynamic", - "meeting-agenda-item-form-cancel-url-value": @cancel_path + controller: 'meeting-agenda-item-form', + 'application-target': 'dynamic', + 'meeting-agenda-item-form-cancel-url-value': @cancel_path } end diff --git a/modules/meeting/app/components/meeting_agenda_items/item_component.rb b/modules/meeting/app/components/meeting_agenda_items/item_component.rb index e52d1cb514b4..0e961c52ad42 100644 --- a/modules/meeting/app/components/meeting_agenda_items/item_component.rb +++ b/modules/meeting/app/components/meeting_agenda_items/item_component.rb @@ -86,7 +86,7 @@ def wrapper_arguments scheme: :default, data: { id: @meeting_agenda_item.id, - "drop-url": drop_meeting_agenda_item_path(@meeting_agenda_item.meeting, @meeting_agenda_item) + 'drop-url': drop_meeting_agenda_item_path(@meeting_agenda_item.meeting, @meeting_agenda_item) } } end diff --git a/modules/meeting/app/components/meeting_agenda_items/item_component/show_component.rb b/modules/meeting/app/components/meeting_agenda_items/item_component/show_component.rb index cb3f6d9e45b6..88a711c49b01 100644 --- a/modules/meeting/app/components/meeting_agenda_items/item_component/show_component.rb +++ b/modules/meeting/app/components/meeting_agenda_items/item_component/show_component.rb @@ -81,7 +81,7 @@ def edit_action_item(menu) menu.with_item(label: t("label_edit"), href: edit_meeting_agenda_item_path(@meeting_agenda_item.meeting, @meeting_agenda_item), content_arguments: { - data: { "turbo-stream": true } + data: { 'turbo-stream': true } }) do |item| item.with_leading_visual_icon(icon: :pencil) end @@ -92,7 +92,7 @@ def add_note_action_item(menu) href: edit_meeting_agenda_item_path(@meeting_agenda_item.meeting, @meeting_agenda_item, display_notes_input: true), content_arguments: { - data: { "turbo-stream": true } + data: { 'turbo-stream': true } }) do |item| item.with_leading_visual_icon(icon: :note) end @@ -110,7 +110,7 @@ def delete_action_item(menu) scheme: :danger, href: meeting_agenda_item_path(@meeting_agenda_item.meeting, @meeting_agenda_item), form_arguments: { - method: :delete, data: { confirm: t("text_are_you_sure"), "turbo-stream": true } + method: :delete, data: { confirm: t("text_are_you_sure"), 'turbo-stream': true } }) do |item| item.with_leading_visual_icon(icon: :trash) end @@ -121,7 +121,7 @@ def move_action_item(menu, move_to, label_text, icon) href: move_meeting_agenda_item_path(@meeting_agenda_item.meeting, @meeting_agenda_item, move_to:), form_arguments: { - method: :put, data: { "turbo-stream": true } + method: :put, data: { 'turbo-stream': true } }) do |item| item.with_leading_visual_icon(icon:) end diff --git a/modules/meeting/app/components/meeting_agenda_items/list_component.rb b/modules/meeting/app/components/meeting_agenda_items/list_component.rb index 79bb962b064e..d44b477a41c0 100644 --- a/modules/meeting/app/components/meeting_agenda_items/list_component.rb +++ b/modules/meeting/app/components/meeting_agenda_items/list_component.rb @@ -44,9 +44,9 @@ def initialize(meeting:, form_hidden: true, form_type: :simple) def wrapper_data_attributes { - controller: "meeting-agenda-item-drag-and-drop", - "application-target": "dynamic", - "target-tag": "ul" + controller: 'meeting-agenda-item-drag-and-drop', + 'application-target': 'dynamic', + 'target-tag': 'ul' } end @@ -55,7 +55,7 @@ def insert_target_modified? end def insert_target_modifier_id - "meeting-agenda-items-new-item" + 'meeting-agenda-items-new-item' end end end diff --git a/modules/meeting/app/components/meetings/add_button_component.rb b/modules/meeting/app/components/meetings/add_button_component.rb index 7b5a3afbfe2a..84c8856fcc3a 100644 --- a/modules/meeting/app/components/meetings/add_button_component.rb +++ b/modules/meeting/app/components/meetings/add_button_component.rb @@ -44,7 +44,7 @@ def dynamic_path end def id - "add-meeting-button" + 'add-meeting-button' end def accessibility_label_text diff --git a/modules/meeting/app/components/meetings/row_component.rb b/modules/meeting/app/components/meetings/row_component.rb index 800a65cc5516..1db1a654ac7d 100644 --- a/modules/meeting/app/components/meetings/row_component.rb +++ b/modules/meeting/app/components/meetings/row_component.rb @@ -40,9 +40,9 @@ def title def type if model.is_a?(StructuredMeeting) - I18n.t("meeting.types.structured") + I18n.t('meeting.types.structured') else - I18n.t("meeting.types.classic") + I18n.t('meeting.types.classic') end end @@ -57,7 +57,7 @@ def duration def location helpers.auto_link(model.location, link: :all, - html: { target: "_blank" }) + html: { target: '_blank' }) end end end diff --git a/modules/meeting/app/components/meetings/sidebar/participants_component.rb b/modules/meeting/app/components/meetings/sidebar/participants_component.rb index 0d2c2b7dabe5..bc67bca91183 100644 --- a/modules/meeting/app/components/meetings/sidebar/participants_component.rb +++ b/modules/meeting/app/components/meetings/sidebar/participants_component.rb @@ -36,8 +36,8 @@ class Sidebar::ParticipantsComponent < ApplicationComponent def wrapper_data_attributes { - controller: "meetings-sidebar-participants", - "application-target": "dynamic" + controller: 'meetings-sidebar-participants', + 'application-target': 'dynamic' } end @@ -55,10 +55,10 @@ def count def render_participant(participant) flex_layout(align_items: :center) do |flex| - flex.with_column(classes: "ellipsis") do + flex.with_column(classes: 'ellipsis') do render(Users::AvatarComponent.new(user: participant.user, size: :medium, - classes: "op-principal_flex")) + classes: 'op-principal_flex')) end render_participant_state(participant, flex) end diff --git a/modules/meeting/app/components/meetings/table_component.rb b/modules/meeting/app/components/meetings/table_component.rb index f9b03a821799..1bad5a4b2ad7 100644 --- a/modules/meeting/app/components/meetings/table_component.rb +++ b/modules/meeting/app/components/meetings/table_component.rb @@ -39,7 +39,7 @@ def initial_sort end def sortable_columns_correlation - super.merge(project_name: "projects.name") + super.merge(project_name: 'projects.name') end def initialize_sorted_model diff --git a/modules/meeting/app/controllers/meeting_agendas_controller.rb b/modules/meeting/app/controllers/meeting_agendas_controller.rb index b67480d1f420..f8decd73a402 100644 --- a/modules/meeting/app/controllers/meeting_agendas_controller.rb +++ b/modules/meeting/app/controllers/meeting_agendas_controller.rb @@ -32,18 +32,18 @@ class MeetingAgendasController < MeetingContentsController def close @meeting.close_agenda_and_copy_to_minutes! - redirect_back_or_default controller: "/meetings", action: "show", id: @meeting + redirect_back_or_default controller: '/meetings', action: 'show', id: @meeting end def open @content.unlock! - redirect_back_or_default controller: "/meetings", action: "show", id: @meeting + redirect_back_or_default controller: '/meetings', action: 'show', id: @meeting end private def find_content @content = @meeting.agenda || @meeting.build_agenda - @content_type = "meeting_agenda" + @content_type = 'meeting_agenda' end end diff --git a/modules/meeting/app/controllers/meeting_contents_controller.rb b/modules/meeting/app/controllers/meeting_contents_controller.rb index f4a7b3fb8bc6..cf68b4d26982 100644 --- a/modules/meeting/app/controllers/meeting_contents_controller.rb +++ b/modules/meeting/app/controllers/meeting_contents_controller.rb @@ -45,17 +45,17 @@ class MeetingContentsController < ApplicationController def show if params[:id].present? && @content.last_journal.version == params[:id].to_i # Redirect links to the last version - redirect_to controller: "/meetings", + redirect_to controller: '/meetings', action: :show, id: @meeting, - tab: @content_type.sub(/^meeting_/, "") + tab: @content_type.sub(/^meeting_/, '') return end # go to an old version if a version id is given @journaled_version = true @content = @content.at_version params[:id] if params[:id].present? - render "meeting_contents/show" + render 'meeting_contents/show' end def update @@ -65,27 +65,27 @@ def update if call.success? flash[:notice] = I18n.t(:notice_successful_update) - redirect_back_or_default controller: "/meetings", action: "show", id: @meeting + redirect_back_or_default controller: '/meetings', action: 'show', id: @meeting else flash.now[:error] = call.message - params[:tab] ||= "minutes" if @meeting.agenda.present? && @meeting.agenda.locked? - render "meetings/show" + params[:tab] ||= 'minutes' if @meeting.agenda.present? && @meeting.agenda.locked? + render 'meetings/show' end end def history # don't load text - @content_versions = @content.journals.select("id, user_id, notes, created_at, version") - .order(Arel.sql("version DESC")) + @content_versions = @content.journals.select('id, user_id, notes, created_at, version') + .order(Arel.sql('version DESC')) .page(page_param) .per_page(per_page_param) - render "meeting_contents/history", layout: !request.xhr? + render 'meeting_contents/history', layout: !request.xhr? end def diff @diff = @content.diff(params[:version_to], params[:version_from]) - render "meeting_contents/diff" + render 'meeting_contents/diff' rescue ActiveRecord::RecordNotFound render_404 end diff --git a/modules/meeting/app/controllers/meeting_minutes_controller.rb b/modules/meeting/app/controllers/meeting_minutes_controller.rb index 270ac29912ed..da28ba43d743 100644 --- a/modules/meeting/app/controllers/meeting_minutes_controller.rb +++ b/modules/meeting/app/controllers/meeting_minutes_controller.rb @@ -33,6 +33,6 @@ class MeetingMinutesController < MeetingContentsController def find_content @content = @meeting.minutes || @meeting.build_minutes - @content_type = "meeting_minutes" + @content_type = 'meeting_minutes' end end diff --git a/modules/meeting/app/controllers/work_package_meetings_tab_controller.rb b/modules/meeting/app/controllers/work_package_meetings_tab_controller.rb index add8df560536..a12c06bc88b9 100644 --- a/modules/meeting/app/controllers/work_package_meetings_tab_controller.rb +++ b/modules/meeting/app/controllers/work_package_meetings_tab_controller.rb @@ -125,9 +125,9 @@ def get_agenda_items_of_work_package(direction) .includes(:meeting) .where(meeting_id: Meeting.visible(current_user)) .where(work_package_id: @work_package.id) - .order("meetings.start_time": :asc) + .order('meetings.start_time': :asc) - comparison = direction == :past ? "<" : ">=" + comparison = direction == :past ? '<' : '>=' agenda_items.where("meetings.start_time + (interval '1 hour' * meetings.duration) #{comparison} ?", Time.zone.now) end end diff --git a/modules/meeting/app/forms/meeting_agenda_item/duration.rb b/modules/meeting/app/forms/meeting_agenda_item/duration.rb index 5c4f91caa0b0..4be1c75d6d66 100644 --- a/modules/meeting/app/forms/meeting_agenda_item/duration.rb +++ b/modules/meeting/app/forms/meeting_agenda_item/duration.rb @@ -30,7 +30,7 @@ class MeetingAgendaItem::Duration < ApplicationForm form do |agenda_item_form| agenda_item_form.text_field( name: :duration_in_minutes, - placeholder: I18n.t("activerecord.attributes.meeting_agenda_items.duration_in_minutes"), + placeholder: I18n.t('activerecord.attributes.meeting_agenda_items.duration_in_minutes'), label: MeetingAgendaItem.human_attribute_name(:duration_in_minutes), leading_visual: { icon: :stopwatch }, visually_hide_label: true, diff --git a/modules/meeting/app/forms/meeting_agenda_item/meeting_form.rb b/modules/meeting/app/forms/meeting_agenda_item/meeting_form.rb index 0effb6db1bb9..3617285ef9e5 100644 --- a/modules/meeting/app/forms/meeting_agenda_item/meeting_form.rb +++ b/modules/meeting/app/forms/meeting_agenda_item/meeting_form.rb @@ -61,6 +61,6 @@ def initialize(disabled: false, wrapper_id: nil) end def append_to_container - @wrapper_id.nil? ? "body" : "##{@wrapper_id}" + @wrapper_id.nil? ? 'body' : "##{@wrapper_id}" end end diff --git a/modules/meeting/app/forms/meeting_agenda_item/title.rb b/modules/meeting/app/forms/meeting_agenda_item/title.rb index 20744648912f..9b8a8bff88d8 100644 --- a/modules/meeting/app/forms/meeting_agenda_item/title.rb +++ b/modules/meeting/app/forms/meeting_agenda_item/title.rb @@ -35,10 +35,10 @@ class MeetingAgendaItem::Title < ApplicationForm visually_hide_label: true, required: true, autofocus: true, - autocomplete: "off", + autocomplete: 'off', disabled: @disabled, data: { - action: "keydown.esc->meeting-agenda-item-form#cancel" + action: 'keydown.esc->meeting-agenda-item-form#cancel' } ) end diff --git a/modules/meeting/app/forms/meeting_agenda_item/work_package.rb b/modules/meeting/app/forms/meeting_agenda_item/work_package.rb index 7b2f169b7d68..52be6a872117 100644 --- a/modules/meeting/app/forms/meeting_agenda_item/work_package.rb +++ b/modules/meeting/app/forms/meeting_agenda_item/work_package.rb @@ -35,10 +35,10 @@ class MeetingAgendaItem::WorkPackage < ApplicationForm autocomplete_options: { id: "op-agenda-items-wp-autocomplete", data: { - "test-selector": "op-agenda-items-wp-autocomplete" + 'test-selector': 'op-agenda-items-wp-autocomplete' }, - resource: "work_packages", - searchKey: "subjectOrId", + resource: 'work_packages', + searchKey: 'subjectOrId', focusDirectly: true, disabled: @disabled } diff --git a/modules/meeting/app/helpers/meeting_contents_helper.rb b/modules/meeting/app/helpers/meeting_contents_helper.rb index d88780e2b3ac..e3ab854a4595 100644 --- a/modules/meeting/app/helpers/meeting_contents_helper.rb +++ b/modules/meeting/app/helpers/meeting_contents_helper.rb @@ -28,7 +28,7 @@ module MeetingContentsHelper def can_edit_meeting_content?(content, content_type) - authorize_for(content_type.pluralize, "update") && content.editable? + authorize_for(content_type.pluralize, 'update') && content.editable? end def saved_meeting_content_text_present?(content) @@ -45,7 +45,7 @@ def meeting_content_context_menu(content, content_type) menu << meeting_content_edit_link(content_type) if can_edit_meeting_content?(content, content_type) menu << meeting_content_history_link(content_type, content.meeting) - menu.join(" ") + menu.join(' ') end def meeting_agenda_toggle_status_link(content, content_type) @@ -58,75 +58,75 @@ def meeting_agenda_toggle_status_link(content, content_type) def close_meeting_agenda_link(content_type, meeting) case content_type - when "meeting_agenda" - content_tag :li, "", class: "toolbar-item" do - link_to_if_authorized({ controller: "/meeting_agendas", - action: "close", + when 'meeting_agenda' + content_tag :li, '', class: 'toolbar-item' do + link_to_if_authorized({ controller: '/meeting_agendas', + action: 'close', meeting_id: meeting }, method: :put, data: { confirm: I18n.t(:text_meeting_closing_are_you_sure) }, - class: "meetings--close-meeting-button button") do - text_with_icon(I18n.t(:label_meeting_close), "icon-locked") + class: 'meetings--close-meeting-button button') do + text_with_icon(I18n.t(:label_meeting_close), 'icon-locked') end end - when "meeting_minutes" - content_tag :li, "", class: "toolbar-item" do - link_to_if_authorized({ controller: "/meeting_agendas", - action: "close", + when 'meeting_minutes' + content_tag :li, '', class: 'toolbar-item' do + link_to_if_authorized({ controller: '/meeting_agendas', + action: 'close', meeting_id: meeting }, method: :put, - class: "button") do - text_with_icon(I18n.t(:label_meeting_agenda_close), "icon-locked") + class: 'button') do + text_with_icon(I18n.t(:label_meeting_agenda_close), 'icon-locked') end end end end def open_meeting_agenda_link(content_type, meeting) - return unless content_type == "meeting_agenda" + return unless content_type == 'meeting_agenda' - content_tag :li, "", class: "toolbar-item" do - link_to_if_authorized({ controller: "/meeting_agendas", - action: "open", + content_tag :li, '', class: 'toolbar-item' do + link_to_if_authorized({ controller: '/meeting_agendas', + action: 'open', meeting_id: meeting }, method: :put, - class: "button", + class: 'button', data: { confirm: I18n.t(:text_meeting_agenda_open_are_you_sure) }) do - text_with_icon(I18n.t(:label_meeting_open), "icon-unlocked") + text_with_icon(I18n.t(:label_meeting_open), 'icon-unlocked') end end end def meeting_content_edit_link(_content_type) - content_tag :li, "", class: "toolbar-item" do - link_to "", - class: "button button--edit-agenda", + content_tag :li, '', class: 'toolbar-item' do + link_to '', + class: 'button button--edit-agenda', data: { - action: "meeting-content#enableEditState", - "meeting-content-target": "editButton" + action: 'meeting-content#enableEditState', + 'meeting-content-target': 'editButton' }, accesskey: accesskey(:edit) do - text_with_icon(I18n.t(:label_edit), "icon-edit") + text_with_icon(I18n.t(:label_edit), 'icon-edit') end end end def meeting_content_history_link(content_type, meeting) - content_tag :li, "", class: "toolbar-item" do - link_to_if_authorized({ controller: "/" + content_type.pluralize, - action: "history", + content_tag :li, '', class: 'toolbar-item' do + link_to_if_authorized({ controller: '/' + content_type.pluralize, + action: 'history', meeting_id: meeting }, aria: { label: t(:label_history) }, title: t(:label_history), - class: "button") do - text_with_icon(I18n.t(:label_history), "icon-activity-history") + class: 'button') do + text_with_icon(I18n.t(:label_history), 'icon-activity-history') end end end def text_with_icon(text, icon) op_icon("button--icon #{icon}") + - " " + - content_tag("span", text, class: "button--text") + ' ' + + content_tag('span', text, class: 'button--text') end end diff --git a/modules/meeting/app/helpers/meetings_helper.rb b/modules/meeting/app/helpers/meetings_helper.rb index 0ba105163506..a7f7fc1f73fe 100644 --- a/modules/meeting/app/helpers/meetings_helper.rb +++ b/modules/meeting/app/helpers/meetings_helper.rb @@ -51,8 +51,8 @@ def menu_upcoming_meetings_item def menu_past_meetings_item path = project_or_global_meetings_path( - filters: [{ time: { operator: "=", values: ["past"] } }], - sort: "start_time:desc" + filters: [{ time: { operator: '=', values: ['past'] } }], + sort: 'start_time:desc' ) menu_link_element path, t(:label_past_meetings) @@ -61,10 +61,10 @@ def menu_past_meetings_item def menu_upcoming_invitations_item path = project_or_global_meetings_path( filters: [ - { time: { operator: "=", values: ["future"] } }, - { invited_user_id: { operator: "=", values: [User.current.id.to_s] } } + { time: { operator: '=', values: ['future'] } }, + { invited_user_id: { operator: '=', values: [User.current.id.to_s] } } ], - sort: "start_time" + sort: 'start_time' ) menu_link_element path, t(:label_upcoming_invitations) @@ -73,10 +73,10 @@ def menu_upcoming_invitations_item def menu_past_invitations_item path = project_or_global_meetings_path( filters: [ - { time: { operator: "=", values: ["past"] } }, - { invited_user_id: { operator: "=", values: [User.current.id.to_s] } } + { time: { operator: '=', values: ['past'] } }, + { invited_user_id: { operator: '=', values: [User.current.id.to_s] } } ], - sort: "start_time:desc" + sort: 'start_time:desc' ) menu_link_element path, t(:label_past_invitations) @@ -84,7 +84,7 @@ def menu_past_invitations_item def menu_attendee_item path = project_or_global_meetings_path( - filters: [{ attended_user_id: { operator: "=", values: [User.current.id.to_s] } }] + filters: [{ attended_user_id: { operator: '=', values: [User.current.id.to_s] } }] ) menu_link_element path, t(:label_attendee) @@ -92,7 +92,7 @@ def menu_attendee_item def menu_creator_item path = project_or_global_meetings_path( - filters: [{ author_id: { operator: "=", values: [User.current.id.to_s] } }] + filters: [{ author_id: { operator: '=', values: [User.current.id.to_s] } }] ) menu_link_element path, t(:label_author) @@ -111,7 +111,7 @@ def project_or_global_meetings_path(filters: nil, sort: nil) def menu_link_element(path, label) link_to path, class: menu_item_css_class(path), title: label do - content_tag(:span, class: "op-sidemenu--item-title") do + content_tag(:span, class: 'op-sidemenu--item-title') do label end end @@ -132,17 +132,17 @@ def format_participant_list(participants) .reject { |p| p.user.nil? } .map { |p| link_to_user p.user } - safe_join(user_links, "; ") + safe_join(user_links, '; ') else - t("placeholders.default") + t('placeholders.default') end end def render_meeting_journal(model, journal, options = {}) - return "" if journal.initial? + return '' if journal.initial? journal_content = render_journal_details(journal, :label_updated_time_by, model, options) - content_tag "div", journal_content, id: "change-#{journal.id}", class: "journal" + content_tag 'div', journal_content, id: "change-#{journal.id}", class: 'journal' end # This renders a journal entry with a header and details @@ -159,16 +159,16 @@ def render_journal_details(journal, header_label = :label_updated_time_by, _mode HTML if journal.details.any? - details = content_tag "ul", class: "details journal-attributes" do + details = content_tag 'ul', class: 'details journal-attributes' do journal.details.filter_map do |detail| if d = journal.render_detail(detail, cache: options[:cache]) - content_tag("li", d.html_safe) + content_tag('li', d.html_safe) end - end.join(" ").html_safe + end.join(' ').html_safe end end - content_tag("div", "#{header}#{details}".html_safe, id: "change-#{journal.id}", class: "journal") + content_tag('div', "#{header}#{details}".html_safe, id: "change-#{journal.id}", class: 'journal') end def global_meeting_create_context? diff --git a/modules/meeting/app/mailers/meeting_mailer.rb b/modules/meeting/app/mailers/meeting_mailer.rb index e001f0c405c6..7def8247802d 100644 --- a/modules/meeting/app/mailers/meeting_mailer.rb +++ b/modules/meeting/app/mailers/meeting_mailer.rb @@ -32,8 +32,8 @@ def invited(meeting, user, actor) @meeting = meeting @user = user - open_project_headers "Project" => @meeting.project.identifier, - "Meeting-Id" => @meeting.id + open_project_headers 'Project' => @meeting.project.identifier, + 'Meeting-Id' => @meeting.id with_attached_ics(meeting, user) do subject = "[#{@meeting.project.name}] #{@meeting.title}" @@ -47,12 +47,12 @@ def rescheduled(meeting, user, actor, changes:) @meeting = meeting @changes = changes - open_project_headers "Project" => @meeting.project.identifier, - "Meeting-Id" => @meeting.id + open_project_headers 'Project' => @meeting.project.identifier, + 'Meeting-Id' => @meeting.id with_attached_ics(meeting, user) do subject = "[#{@meeting.project.name}] " - subject << I18n.t("meeting.email.rescheduled.header", title: @meeting.title) + subject << I18n.t('meeting.email.rescheduled.header', title: @meeting.title) mail(to: user.mail, subject:) end end @@ -79,7 +79,7 @@ def with_attached_ics(meeting, user) .call call.on_success do - attachments["meeting.ics"] = call.result + attachments['meeting.ics'] = call.result yield end @@ -91,9 +91,9 @@ def with_attached_ics(meeting, user) end def set_headers(meeting) - open_project_headers "Project" => meeting.project.identifier, "Meeting-Id" => meeting.id - headers["Content-Type"] = 'text/calendar; charset=utf-8; method="PUBLISH"; name="meeting.ics"' - headers["Content-Transfer-Encoding"] = "8bit" + open_project_headers 'Project' => meeting.project.identifier, 'Meeting-Id' => meeting.id + headers['Content-Type'] = 'text/calendar; charset=utf-8; method="PUBLISH"; name="meeting.ics"' + headers['Content-Transfer-Encoding'] = '8bit' end def format_timezone_offset(timezone, time) diff --git a/modules/meeting/app/models/journal/meeting_agenda_item_journal.rb b/modules/meeting/app/models/journal/meeting_agenda_item_journal.rb index e24fdc591a67..f2cef2b0cb22 100644 --- a/modules/meeting/app/models/journal/meeting_agenda_item_journal.rb +++ b/modules/meeting/app/models/journal/meeting_agenda_item_journal.rb @@ -27,13 +27,13 @@ #++ class Journal::MeetingAgendaItemJournal < Journal::BaseJournal - self.table_name = "meeting_agenda_item_journals" + self.table_name = 'meeting_agenda_item_journals' enum item_type: MeetingAgendaItem::ITEM_TYPES belongs_to :meeting - belongs_to :author, class_name: "User" - belongs_to :agenda_item, class_name: "MeetingAgendaItem" + belongs_to :author, class_name: 'User' + belongs_to :agenda_item, class_name: 'MeetingAgendaItem' def editable? false diff --git a/modules/meeting/app/models/journal/meeting_content_journal.rb b/modules/meeting/app/models/journal/meeting_content_journal.rb index e761a7913bb0..98ad96ef48b6 100644 --- a/modules/meeting/app/models/journal/meeting_content_journal.rb +++ b/modules/meeting/app/models/journal/meeting_content_journal.rb @@ -27,10 +27,10 @@ #++ class Journal::MeetingContentJournal < Journal::BaseJournal - self.table_name = "meeting_content_journals" + self.table_name = 'meeting_content_journals' belongs_to :meeting - belongs_to :author, class_name: "User" + belongs_to :author, class_name: 'User' def editable? false diff --git a/modules/meeting/app/models/journal/meeting_journal.rb b/modules/meeting/app/models/journal/meeting_journal.rb index 491208c50b95..d5ef503b304a 100644 --- a/modules/meeting/app/models/journal/meeting_journal.rb +++ b/modules/meeting/app/models/journal/meeting_journal.rb @@ -27,7 +27,7 @@ #++ class Journal::MeetingJournal < Journal::BaseJournal - self.table_name = "meeting_journals" + self.table_name = 'meeting_journals' - belongs_to :author, class_name: "User" + belongs_to :author, class_name: 'User' end diff --git a/modules/meeting/app/models/meeting_agenda.rb b/modules/meeting/app/models/meeting_agenda.rb index 5508007cd13c..5e97bec0d058 100644 --- a/modules/meeting/app/models/meeting_agenda.rb +++ b/modules/meeting/app/models/meeting_agenda.rb @@ -28,14 +28,14 @@ class MeetingAgenda < MeetingContent def lock!(user = User.current) - self.journal_notes = I18n.t("events.meeting_agenda_closed") + self.journal_notes = I18n.t('events.meeting_agenda_closed') self.author = user self.locked = true save end def unlock!(user = User.current) - self.journal_notes = I18n.t("events.meeting_agenda_opened") + self.journal_notes = I18n.t('events.meeting_agenda_opened') self.author = user self.locked = false save diff --git a/modules/meeting/app/models/meeting_agenda_item.rb b/modules/meeting/app/models/meeting_agenda_item.rb index c643fd9dd6f2..1c0b4c519bdb 100644 --- a/modules/meeting/app/models/meeting_agenda_item.rb +++ b/modules/meeting/app/models/meeting_agenda_item.rb @@ -35,10 +35,10 @@ class MeetingAgendaItem < ApplicationRecord enum item_type: ITEM_TYPES - belongs_to :meeting, class_name: "StructuredMeeting" - belongs_to :work_package, class_name: "::WorkPackage" + belongs_to :meeting, class_name: 'StructuredMeeting' + belongs_to :work_package, class_name: '::WorkPackage' has_one :project, through: :meeting - belongs_to :author, class_name: "User", optional: false + belongs_to :author, class_name: 'User', optional: false acts_as_list scope: :meeting default_scope { order(:position) } @@ -91,6 +91,6 @@ def modifiable? end def copy_attributes - attributes.except("id", "meeting_id") + attributes.except('id', 'meeting_id') end end diff --git a/modules/meeting/app/models/meeting_content.rb b/modules/meeting/app/models/meeting_content.rb index e433df1ca4d2..441535ee7b51 100644 --- a/modules/meeting/app/models/meeting_content.rb +++ b/modules/meeting/app/models/meeting_content.rb @@ -33,7 +33,7 @@ class MeetingContent < ApplicationRecord belongs_to :meeting # Show the project on activity and search views has_one :project, through: :meeting - belongs_to :author, class_name: "User" + belongs_to :author, class_name: 'User' acts_as_attachable( after_remove: :attachments_changed, @@ -48,13 +48,7 @@ class MeetingContent < ApplicationRecord acts_as_journalized acts_as_event type: Proc.new { |o| o.class.to_s.underscore.dasherize.to_s }, title: Proc.new { |o| "#{o.class.model_name.human}: #{o.meeting.title}" }, - url: Proc.new { |o| { controller: "/meetings", action: "show", id: o.meeting } } - - scope :visible, ->(*args) { - includes(meeting: :project) - .references(:projects) - .merge(Project.allowed_to(args.first || User.current, :view_meetings)) - } + url: Proc.new { |o| { controller: '/meetings', action: 'show', id: o.meeting } } def editable? true diff --git a/modules/meeting/app/models/meeting_participant.rb b/modules/meeting/app/models/meeting_participant.rb index f13cf5701d20..d22436fb675e 100644 --- a/modules/meeting/app/models/meeting_participant.rb +++ b/modules/meeting/app/models/meeting_participant.rb @@ -34,11 +34,11 @@ class MeetingParticipant < ApplicationRecord scope :attended, -> { where(attended: true) } def name - user.present? ? user.name : I18n.t("user.deleted") + user.present? ? user.name : I18n.t('user.deleted') end def mail - user.present? ? user.mail : I18n.t("user.deleted") + user.present? ? user.mail : I18n.t('user.deleted') end def <=>(other) @@ -49,6 +49,6 @@ def <=>(other) def copy_attributes # create a clean attribute set allowing to attach participants to different meetings - attributes.reject { |k, _v| ["id", "meeting_id", "attended", "created_at", "updated_at"].include?(k) } + attributes.reject { |k, _v| ['id', 'meeting_id', 'attended', 'created_at', 'updated_at'].include?(k) } end end diff --git a/modules/meeting/app/models/queries/meetings/filters/time_filter.rb b/modules/meeting/app/models/queries/meetings/filters/time_filter.rb index 0f2691d911f1..6031a0a43dbb 100644 --- a/modules/meeting/app/models/queries/meetings/filters/time_filter.rb +++ b/modules/meeting/app/models/queries/meetings/filters/time_filter.rb @@ -27,8 +27,8 @@ #++ class Queries::Meetings::Filters::TimeFilter < Queries::Meetings::Filters::MeetingFilter - PAST_VALUE = "past".freeze - FUTURE_VALUE = "future".freeze + PAST_VALUE = 'past'.freeze + FUTURE_VALUE = 'future'.freeze validate :validate_only_single_value diff --git a/modules/meeting/app/models/structured_meeting.rb b/modules/meeting/app/models/structured_meeting.rb index c4d42d469791..1d7dc58c49d7 100644 --- a/modules/meeting/app/models/structured_meeting.rb +++ b/modules/meeting/app/models/structured_meeting.rb @@ -29,8 +29,8 @@ class StructuredMeeting < Meeting has_many :agenda_items, dependent: :destroy, - foreign_key: "meeting_id", - class_name: "MeetingAgendaItem", + foreign_key: 'meeting_id', + class_name: 'MeetingAgendaItem', inverse_of: :meeting accepts_nested_attributes_for :agenda_items diff --git a/modules/meeting/app/seeders/meetings/demo_data/meeting_agenda_items_seeder.rb b/modules/meeting/app/seeders/meetings/demo_data/meeting_agenda_items_seeder.rb index 36227d6c825b..83fff13ce60f 100644 --- a/modules/meeting/app/seeders/meetings/demo_data/meeting_agenda_items_seeder.rb +++ b/modules/meeting/app/seeders/meetings/demo_data/meeting_agenda_items_seeder.rb @@ -30,7 +30,7 @@ module Meetings module DemoData class MeetingAgendaItemsSeeder < ::BasicData::ModelSeeder self.model_class = MeetingAgendaItem - self.seed_data_model_key = "meeting_agenda_items" + self.seed_data_model_key = 'meeting_agenda_items' ## # @@ -40,12 +40,12 @@ def initialize(_project, seed_data) def model_attributes(meeting_data) { - title: meeting_data["title"], - notes: meeting_data["notes"], - duration_in_minutes: meeting_data["duration"], - author: seed_data.find_reference(meeting_data["author"]), - meeting: seed_data.find_reference(meeting_data["meeting"]), - work_package: seed_data.find_reference(meeting_data["work_package"]) + title: meeting_data['title'], + notes: meeting_data['notes'], + duration_in_minutes: meeting_data['duration'], + author: seed_data.find_reference(meeting_data['author']), + meeting: seed_data.find_reference(meeting_data['meeting']), + work_package: seed_data.find_reference(meeting_data['work_package']) } end end diff --git a/modules/meeting/app/seeders/meetings/demo_data/meeting_seeder.rb b/modules/meeting/app/seeders/meetings/demo_data/meeting_seeder.rb index bffdf8392e43..233c98d7890f 100644 --- a/modules/meeting/app/seeders/meetings/demo_data/meeting_seeder.rb +++ b/modules/meeting/app/seeders/meetings/demo_data/meeting_seeder.rb @@ -30,7 +30,7 @@ module Meetings module DemoData class MeetingSeeder < ::BasicData::ModelSeeder self.model_class = StructuredMeeting - self.seed_data_model_key = "meetings" + self.seed_data_model_key = 'meetings' attr_reader :project @@ -41,9 +41,9 @@ def initialize(project, seed_data) def model_attributes(meeting_data) { - title: meeting_data["title"], - author: seed_data.find_reference(meeting_data["author"]), - duration: minutes_to_hours(meeting_data["duration"]), + title: meeting_data['title'], + author: seed_data.find_reference(meeting_data['author']), + duration: minutes_to_hours(meeting_data['duration']), project: } end diff --git a/modules/meeting/app/services/meetings/copy_service.rb b/modules/meeting/app/services/meetings/copy_service.rb index 686421add8c4..e0c5a5f50577 100644 --- a/modules/meeting/app/services/meetings/copy_service.rb +++ b/modules/meeting/app/services/meetings/copy_service.rb @@ -74,9 +74,9 @@ def copied_attributes(meeting, override) meeting .attributes .slice(*writable_meeting_attributes(meeting)) - .merge("start_time" => meeting.start_time + 1.week) - .merge("author" => user) - .merge("participants_attributes" => meeting.allowed_participants.collect(&:copy_attributes)) + .merge('start_time' => meeting.start_time + 1.week) + .merge('author' => user) + .merge('participants_attributes' => meeting.allowed_participants.collect(&:copy_attributes)) .merge(overwritten_attributes) end @@ -86,7 +86,7 @@ def writable_meeting_attributes(meeting) def copy_meeting_attachment(copy) copy_attachments( - "Meeting", + 'Meeting', from: meeting, to: copy ) @@ -110,7 +110,7 @@ def copy_meeting_agenda(copy) meeting: copy, author: user, text: meeting.agenda&.text, - journal_notes: I18n.t("meeting.copied", id: meeting.id) + journal_notes: I18n.t('meeting.copied', id: meeting.id) ) end end diff --git a/modules/meeting/app/services/meetings/create_service.rb b/modules/meeting/app/services/meetings/create_service.rb index cc5e874eed9a..78c634947837 100644 --- a/modules/meeting/app/services/meetings/create_service.rb +++ b/modules/meeting/app/services/meetings/create_service.rb @@ -35,7 +35,7 @@ def instance(params) # Setting the #type as attributes will not work # as the STI instance is not changed without using e.g., +becomes!+ case params.delete(:type) - when "StructuredMeeting" + when 'StructuredMeeting' StructuredMeeting.new else Meeting.new diff --git a/modules/meeting/app/services/meetings/ical_service.rb b/modules/meeting/app/services/meetings/ical_service.rb index 9ef87dc81b77..5eec3f22a35b 100644 --- a/modules/meeting/app/services/meetings/ical_service.rb +++ b/modules/meeting/app/services/meetings/ical_service.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "icalendar" -require "icalendar/tzinfo" +require 'icalendar' +require 'icalendar/tzinfo' module Meetings class ICalService @@ -104,7 +104,7 @@ def ical_subject end def ical_datetime(time, timezone_id) - Icalendar::Values::DateTime.new time.in_time_zone(timezone_id), "tzid" => timezone_id + Icalendar::Values::DateTime.new time.in_time_zone(timezone_id), 'tzid' => timezone_id end def ical_organizer diff --git a/modules/meeting/app/views/meeting_contents/_form.html.erb b/modules/meeting/app/views/meeting_contents/_form.html.erb index cbeb4cc1d584..1ea5a8337a0a 100644 --- a/modules/meeting/app/views/meeting_contents/_form.html.erb +++ b/modules/meeting/app/views/meeting_contents/_form.html.erb @@ -48,7 +48,7 @@ See COPYRIGHT and LICENSE files for more details.

    <%= f.text_field :journal_notes, label: :comments %>

    <%= styled_button_tag t(:button_save), - class: '-primary -with-icon icon-checkmark button--save-agenda', + class: '-highlight -with-icon icon-checkmark button--save-agenda', data: { disable_with: I18n.t(:label_loading) } %> <%= link_to t(:button_cancel), "#", diff --git a/modules/meeting/app/views/meeting_contents/history.html.erb b/modules/meeting/app/views/meeting_contents/history.html.erb index fc3d44e919bd..87ec5a962576 100644 --- a/modules/meeting/app/views/meeting_contents/history.html.erb +++ b/modules/meeting/app/views/meeting_contents/history.html.erb @@ -137,6 +137,6 @@ See COPYRIGHT and LICENSE files for more details. -<%= styled_button_tag t(:label_view_diff), class: '-small -primary' if show_diff %> +<%= styled_button_tag t(:label_view_diff), class: '-small -highlight' if show_diff %> <%= pagination_links_full @content_versions %> <% end %> diff --git a/modules/meeting/app/views/meetings/_menu_query_select.html.erb b/modules/meeting/app/views/meetings/_menu_query_select.html.erb index 812a78d211fc..24d2d6afb613 100644 --- a/modules/meeting/app/views/meetings/_menu_query_select.html.erb +++ b/modules/meeting/app/views/meetings/_menu_query_select.html.erb @@ -68,7 +68,7 @@ See COPYRIGHT and LICENSE files for more details. <% if (@project && User.current.allowed_in_project?(:create_meetings, @project)) || (@project.nil? && User.current.allowed_in_any_project?(:create_meetings)) %> <%= button_to polymorphic_path([:new, @project, :meeting]), { method: :get, - class: 'button -primary -expand', + class: 'button -alt-highlight -expand', aria: { label: t(:label_meeting_new) }, title: t(:label_meeting_new) } do %> <%= spot_icon('add') %> diff --git a/modules/meeting/app/views/meetings/edit.html.erb b/modules/meeting/app/views/meetings/edit.html.erb index 365a37834db1..3f3eaaabac1a 100644 --- a/modules/meeting/app/views/meetings/edit.html.erb +++ b/modules/meeting/app/views/meetings/edit.html.erb @@ -32,7 +32,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: "#{t(:label_meeting)} ##{@meeting.id}" %> <%= labelled_tabular_form_for @meeting, :url => {:controller => '/meetings', :action => 'update'}, :html => {:id => 'meeting-form', :method => :put} do |f| -%> <%= render :partial => 'form', :locals => {:f => f} %> -<%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> +<%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { :action => 'show', :id => @meeting }, class: 'button -with-icon icon-cancel' %> <% end if @project %> diff --git a/modules/meeting/app/views/meetings/new.html.erb b/modules/meeting/app/views/meetings/new.html.erb index 1661907a753d..2c498f663402 100644 --- a/modules/meeting/app/views/meetings/new.html.erb +++ b/modules/meeting/app/views/meetings/new.html.erb @@ -43,7 +43,7 @@ See COPYRIGHT and LICENSE files for more details. 'refresh-on-form-changes-target': 'form', 'refresh-on-form-changes-turbo-stream-url-value': new_meeting_url }} do |f| -%> <%= render :partial => 'form', :locals => { f:, copy_from: } %> - <%= styled_button_tag t(:button_create), class: '-primary' %> + <%= styled_button_tag t(:button_create), class: '-highlight' %> <%= link_to t(:button_cancel), { :action => 'index', :project_id => @project }, class: 'button' %> <% end %> diff --git a/modules/meeting/config/locales/crowdin/cs.yml b/modules/meeting/config/locales/crowdin/cs.yml index 49f081d214e2..c01aaea97f27 100644 --- a/modules/meeting/config/locales/crowdin/cs.yml +++ b/modules/meeting/config/locales/crowdin/cs.yml @@ -115,7 +115,7 @@ cs: types: classic: 'Klasické' classic_text: 'Uspořádat schůzku do formátů textového programu a protokolu.' - structured: 'Dynamická' + structured: 'Dynamický' structured_text: 'Uspořádat schůzku jako seznam bodů pořadu jednání, případně je propojit s pracovním balíčkem.' structured_text_copy: 'Kopírování schůzky v současné době nezkopíruje související body pořadu jednání, jen podrobnosti' copied: "Zkopírováno ze schůzky #%{id}" @@ -123,7 +123,7 @@ cs: notice_timezone_missing: Není nastaveno žádné časové pásmo a předpokládá se %{zone} . Chcete-li vybrat časové pásmo, klikněte prosím zde. permission_create_meetings: "Vytvořit schůzku\n" permission_edit_meetings: "Upravit schůzku" - permission_delete_meetings: "Smazat schůzku" + permission_delete_meetings: "Odstranit schůzky" permission_view_meetings: "Zobrazit schůzky" permission_create_meeting_agendas: "Vytvořit agendy schůzek" permission_create_meeting_agendas_explanation: "Umožňuje upravovat obsah programu klasické schůzky." diff --git a/modules/meeting/config/locales/crowdin/zh-TW.yml b/modules/meeting/config/locales/crowdin/zh-TW.yml index ac36b806e1b3..88128f8742a4 100644 --- a/modules/meeting/config/locales/crowdin/zh-TW.yml +++ b/modules/meeting/config/locales/crowdin/zh-TW.yml @@ -126,7 +126,7 @@ zh-TW: permission_create_meeting_agendas_explanation: "允許編輯傳統會議的議程。" permission_manage_agendas: "管理議程" permission_manage_agendas_explanation: "允許編輯動態會議的議程項目。" - permission_close_meeting_agendas: "定案會議大綱" + permission_close_meeting_agendas: "結束會議大綱" permission_send_meeting_agendas_notification: "傳送會議大綱審閱通知" permission_create_meeting_minutes: "管理會議記錄" permission_send_meeting_minutes_notification: "傳送會議記錄審閱通知" diff --git a/modules/meeting/db/migrate/20180323135408_to_v710_aggregated_meeting_migrations.rb b/modules/meeting/db/migrate/20180323135408_to_v710_aggregated_meeting_migrations.rb index b5057153214a..9aa249ad92cf 100644 --- a/modules/meeting/db/migrate/20180323135408_to_v710_aggregated_meeting_migrations.rb +++ b/modules/meeting/db/migrate/20180323135408_to_v710_aggregated_meeting_migrations.rb @@ -42,37 +42,37 @@ class ToV710AggregatedMeetingMigrations < ActiveRecord::Migration[5.1] def up Migration::MigrationSquasher.squash(migrations) do - create_table "meeting_contents", id: :integer do |t| - t.string "type" - t.integer "meeting_id" - t.integer "author_id" - t.text "text" - t.integer "lock_version" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "locked", default: false + create_table 'meeting_contents', id: :integer do |t| + t.string 'type' + t.integer 'meeting_id' + t.integer 'author_id' + t.text 'text' + t.integer 'lock_version' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.boolean 'locked', default: false end - create_table "meeting_participants", id: :integer do |t| - t.integer "user_id" - t.integer "meeting_id" - t.string "email" - t.string "name" - t.boolean "invited" - t.boolean "attended" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + create_table 'meeting_participants', id: :integer do |t| + t.integer 'user_id' + t.integer 'meeting_id' + t.string 'email' + t.string 'name' + t.boolean 'invited' + t.boolean 'attended' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false end - create_table "meetings", id: :integer do |t| - t.string "title" - t.integer "author_id" - t.integer "project_id" - t.string "location" - t.datetime "start_time" - t.float "duration" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + create_table 'meetings', id: :integer do |t| + t.string 'title' + t.integer 'author_id' + t.integer 'project_id' + t.string 'location' + t.datetime 'start_time' + t.float 'duration' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false t.index %i[project_id updated_at] end @@ -98,9 +98,9 @@ def up end def down - drop_table "meeting_contents" - drop_table "meeting_participants" - drop_table "meetings" + drop_table 'meeting_contents' + drop_table 'meeting_participants' + drop_table 'meetings' drop_table :meeting_journals drop_table :meeting_content_journals end @@ -109,7 +109,7 @@ def down def migrations MIGRATION_FILES.split.map do |m| - m.gsub(/_.*\z/, "") + m.gsub(/_.*\z/, '') end end end diff --git a/modules/meeting/db/migrate/20230911102918_add_type_to_meeting.rb b/modules/meeting/db/migrate/20230911102918_add_type_to_meeting.rb index 9dec164b3b34..b09b4a1d7764 100644 --- a/modules/meeting/db/migrate/20230911102918_add_type_to_meeting.rb +++ b/modules/meeting/db/migrate/20230911102918_add_type_to_meeting.rb @@ -1,5 +1,5 @@ class AddTypeToMeeting < ActiveRecord::Migration[7.0] def change - add_column :meetings, :type, :string, default: "Meeting", null: false + add_column :meetings, :type, :string, default: 'Meeting', null: false end end diff --git a/modules/meeting/lib/api/v3/meeting_contents/meeting_content_representer.rb b/modules/meeting/lib/api/v3/meeting_contents/meeting_content_representer.rb index 8ca90f379ab2..ce4592cbe2e1 100644 --- a/modules/meeting/lib/api/v3/meeting_contents/meeting_content_representer.rb +++ b/modules/meeting/lib/api/v3/meeting_contents/meeting_content_representer.rb @@ -49,7 +49,7 @@ class MeetingContentRepresenter < ::API::Decorators::Single end def _type - "MeetingContent" + 'MeetingContent' end end end diff --git a/modules/meeting/lib/api/v3/meetings/meeting_representer.rb b/modules/meeting/lib/api/v3/meetings/meeting_representer.rb index 8a536d8eaa5b..af49d7dc4f68 100644 --- a/modules/meeting/lib/api/v3/meetings/meeting_representer.rb +++ b/modules/meeting/lib/api/v3/meetings/meeting_representer.rb @@ -75,7 +75,7 @@ class MeetingRepresenter < ::API::Decorators::Single date_time_property :updated_at def _type - "Meeting" + 'Meeting' end end end diff --git a/modules/meeting/lib/api/v3/meetings/meetings_api.rb b/modules/meeting/lib/api/v3/meetings/meetings_api.rb index 6a8e4a791a5a..7f9cd0005188 100644 --- a/modules/meeting/lib/api/v3/meetings/meetings_api.rb +++ b/modules/meeting/lib/api/v3/meetings/meetings_api.rb @@ -37,7 +37,7 @@ def meeting end end - route_param :id, type: Integer, desc: "Activity ID" do + route_param :id, type: Integer, desc: 'Activity ID' do after_validation do @meeting = Meeting.visible.find(declared_params[:id]) end diff --git a/modules/meeting/lib/open_project/meeting.rb b/modules/meeting/lib/open_project/meeting.rb index 300a95884998..87b48d92c60f 100644 --- a/modules/meeting/lib/open_project/meeting.rb +++ b/modules/meeting/lib/open_project/meeting.rb @@ -28,6 +28,6 @@ module OpenProject module Meeting - require "open_project/meeting/engine" + require 'open_project/meeting/engine' end end diff --git a/modules/meeting/lib/open_project/meeting/patches/setting_seeder_patch.rb b/modules/meeting/lib/open_project/meeting/patches/setting_seeder_patch.rb index 4e49dc806c9b..5c4c641eee2a 100644 --- a/modules/meeting/lib/open_project/meeting/patches/setting_seeder_patch.rb +++ b/modules/meeting/lib/open_project/meeting/patches/setting_seeder_patch.rb @@ -35,8 +35,8 @@ module InstanceMethods def data original_data = super - unless original_data["default_projects_modules"].include? "meetings" - original_data["default_projects_modules"] << "meetings" + unless original_data['default_projects_modules'].include? 'meetings' + original_data['default_projects_modules'] << 'meetings' end original_data diff --git a/modules/meeting/lib/openproject-meeting.rb b/modules/meeting/lib/openproject-meeting.rb index 27257af1d0bd..bedae3a08cd4 100644 --- a/modules/meeting/lib/openproject-meeting.rb +++ b/modules/meeting/lib/openproject-meeting.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/meeting" +require 'open_project/meeting' diff --git a/modules/meeting/openproject-meeting.gemspec b/modules/meeting/openproject-meeting.gemspec index e66b89f0c686..1c53c3b40ac4 100644 --- a/modules/meeting/openproject-meeting.gemspec +++ b/modules/meeting/openproject-meeting.gemspec @@ -1,19 +1,19 @@ # Describe your gem and declare its dependencies: Gem::Specification.new do |s| - s.name = "openproject-meeting" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject Meeting" + s.name = 'openproject-meeting' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject Meeting' s.description = "This module adds functions to support project meetings to OpenProject. Meetings can be scheduled selecting invitees from the same project to take part in the meeting. An agenda can be created and sent to the invitees. After the meeting, attendees can be selected and minutes can be created based on the agenda. Finally, the minutes can be sent to all attendees and invitees." - s.license = "GPLv3" + s.license = 'GPLv3' - s.files = Dir["{app,config,db,lib,doc}/**/*", "README.md"] + s.files = Dir['{app,config,db,lib,doc}/**/*', 'README.md'] - s.add_dependency "icalendar", "~> 2.10.0" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'icalendar', '~> 2.10.0' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/meeting/spec/contracts/meeting_agenda_items/create_contract_spec.rb b/modules/meeting/spec/contracts/meeting_agenda_items/create_contract_spec.rb index 95bad151e84a..c21a76337139 100644 --- a/modules/meeting/spec/contracts/meeting_agenda_items/create_contract_spec.rb +++ b/modules/meeting/spec/contracts/meeting_agenda_items/create_contract_spec.rb @@ -28,56 +28,56 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe MeetingAgendaItems::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' shared_let(:project) { create(:project) } let(:meeting) { create(:structured_meeting, project:) } let(:item) { build(:meeting_agenda_item, meeting:) } let(:contract) { described_class.new(item, user) } - context "with permission" do + context 'with permission' do let(:user) do create(:user, member_with_permissions: { project => %i[view_meetings manage_agendas] }) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when :meeting is not editable" do + context 'when :meeting is not editable' do before do meeting.update_column(:state, :closed) end - it_behaves_like "contract is invalid", base: I18n.t(:text_agenda_item_not_editable_anymore) + it_behaves_like 'contract is invalid', base: I18n.t(:text_agenda_item_not_editable_anymore) end - context "when :meeting is not present anymore" do + context 'when :meeting is not present anymore' do before do meeting.destroy end - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "when an item_type is provided" do + context 'when an item_type is provided' do before do - allow(item).to receive(:changed).and_return(["item_type"]) + allow(item).to receive(:changed).and_return(['item_type']) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - context "without permission" do + context 'without permission' do let(:user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :does_not_exist + it_behaves_like 'contract is invalid', base: :does_not_exist end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:user) { build_stubbed(:user) } end end diff --git a/modules/meeting/spec/contracts/meeting_agenda_items/delete_contract_spec.rb b/modules/meeting/spec/contracts/meeting_agenda_items/delete_contract_spec.rb index 2f236c169970..3af14d395c9a 100644 --- a/modules/meeting/spec/contracts/meeting_agenda_items/delete_contract_spec.rb +++ b/modules/meeting/spec/contracts/meeting_agenda_items/delete_contract_spec.rb @@ -28,40 +28,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe MeetingAgendaItems::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' shared_let(:project) { create(:project) } shared_let(:meeting) { create(:structured_meeting, project:) } shared_let(:item) { create(:meeting_agenda_item, meeting:) } let(:contract) { described_class.new(item, user) } - context "with permission" do + context 'with permission' do let(:user) do create(:user, member_with_permissions: { project => [:manage_agendas] }) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when :meeting is not editable" do + context 'when :meeting is not editable' do before do meeting.update_column(:state, :closed) end - it_behaves_like "contract is invalid", base: I18n.t(:text_agenda_item_not_editable_anymore) + it_behaves_like 'contract is invalid', base: I18n.t(:text_agenda_item_not_editable_anymore) end end - context "without permission" do + context 'without permission' do let(:user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:user) { build_stubbed(:user) } end end diff --git a/modules/meeting/spec/contracts/meeting_agenda_items/update_contract_spec.rb b/modules/meeting/spec/contracts/meeting_agenda_items/update_contract_spec.rb index 10fbdfb51ad7..dd84d5460d56 100644 --- a/modules/meeting/spec/contracts/meeting_agenda_items/update_contract_spec.rb +++ b/modules/meeting/spec/contracts/meeting_agenda_items/update_contract_spec.rb @@ -28,48 +28,48 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe MeetingAgendaItems::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' shared_let(:project) { create(:project) } shared_let(:meeting) { create(:structured_meeting, project:) } shared_let(:item) { create(:meeting_agenda_item, meeting:) } let(:contract) { described_class.new(item, user) } - context "with permission" do + context 'with permission' do let(:user) do create(:user, member_with_permissions: { project => [:manage_agendas] }) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when :meeting is not editable" do + context 'when :meeting is not editable' do before do meeting.update_column(:state, :closed) end - it_behaves_like "contract is invalid", base: I18n.t(:text_agenda_item_not_editable_anymore) + it_behaves_like 'contract is invalid', base: I18n.t(:text_agenda_item_not_editable_anymore) end - context "when an item_type is provided" do + context 'when an item_type is provided' do before do - allow(item).to receive(:changed).and_return(["item_type"]) + allow(item).to receive(:changed).and_return(['item_type']) end - it_behaves_like "contract is invalid", item_type: :error_readonly + it_behaves_like 'contract is invalid', item_type: :error_readonly end end - context "without permission" do + context 'without permission' do let(:user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:user) { build_stubbed(:user) } end end diff --git a/modules/meeting/spec/contracts/meeting_contents/update_contract_spec.rb b/modules/meeting/spec/contracts/meeting_contents/update_contract_spec.rb index c15f80179765..28eebc8172f9 100644 --- a/modules/meeting/spec/contracts/meeting_contents/update_contract_spec.rb +++ b/modules/meeting/spec/contracts/meeting_contents/update_contract_spec.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe MeetingContents::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:agenda) { build_stubbed(:meeting_agenda) } let(:current_user) { build_stubbed(:user) } let(:contract) { described_class.new(agenda, current_user) } - context "when not editable" do + context 'when not editable' do before do allow(agenda).to receive(:editable?).and_return false end - it_behaves_like "contract is invalid", base: :error_readonly + it_behaves_like 'contract is invalid', base: :error_readonly end - context "when editable" do + context 'when editable' do before do allow(agenda).to receive(:editable?).and_return true end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/meeting/spec/contracts/meetings/create_contract_spec.rb b/modules/meeting/spec/contracts/meetings/create_contract_spec.rb index 4191e25dbc37..824be59068a2 100644 --- a/modules/meeting/spec/contracts/meetings/create_contract_spec.rb +++ b/modules/meeting/spec/contracts/meetings/create_contract_spec.rb @@ -28,31 +28,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Meetings::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' shared_let(:project) { create(:project) } let(:meeting) { build(:structured_meeting, project:) } let(:contract) { described_class.new(meeting, user) } - context "with permission" do + context 'with permission' do let(:user) do create(:user, member_with_permissions: { project => %i[view_meetings create_meetings] }) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "without permission" do + context 'without permission' do let(:user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:user) { build_stubbed(:user) } end end diff --git a/modules/meeting/spec/contracts/meetings/update_contract_spec.rb b/modules/meeting/spec/contracts/meetings/update_contract_spec.rb index c752017e9f32..1904a52d6fef 100644 --- a/modules/meeting/spec/contracts/meetings/update_contract_spec.rb +++ b/modules/meeting/spec/contracts/meetings/update_contract_spec.rb @@ -28,39 +28,39 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Meetings::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' shared_let(:project) { create(:project) } shared_let(:meeting) { create(:structured_meeting, project:) } let(:contract) { described_class.new(meeting, user) } - context "with permission" do + context 'with permission' do let(:user) do create(:user, member_with_permissions: { project => [:edit_meetings] }) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when lock_version is changed" do + context 'when lock_version is changed' do before do allow(meeting).to receive(:lock_version_changed?).and_return(true) end - it_behaves_like "contract is invalid", base: :error_conflict + it_behaves_like 'contract is invalid', base: :error_conflict end end - context "without permission" do + context 'without permission' do let(:user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:user) { build_stubbed(:user) } end end diff --git a/modules/meeting/spec/controllers/meetings_controller_spec.rb b/modules/meeting/spec/controllers/meetings_controller_spec.rb index 7976f548f2fb..4771ef8cb503 100644 --- a/modules/meeting/spec/controllers/meetings_controller_spec.rb +++ b/modules/meeting/spec/controllers/meetings_controller_spec.rb @@ -43,8 +43,8 @@ allow(controller).to receive(:check_if_login_required) end - describe "GET" do - describe "index" do + describe 'GET' do + describe 'index' do let(:meetings) do [ create(:meeting, project:), @@ -53,19 +53,19 @@ ] end - describe "html" do - context "when requesting meetings globally" do + describe 'html' do + context 'when requesting meetings globally' do before do - get "index" + get 'index' end it { expect(response).to be_successful } it { expect(assigns(:meetings)).to match_array meetings } end - context "when requesting meetings scoped to a project ID" do + context 'when requesting meetings scoped to a project ID' do before do - get "index", params: { project_id: project.id } + get 'index', params: { project_id: project.id } end it { expect(response).to be_successful } @@ -74,12 +74,12 @@ end end - describe "show" do + describe 'show' do let(:meeting) { create(:meeting, project:, agenda: nil) } - describe "html" do + describe 'html' do before do - get "show", params: { id: meeting.id } + get 'show', params: { id: meeting.id } end it { expect(response).to be_successful } @@ -87,7 +87,7 @@ end end - describe "new" do + describe 'new' do let(:meeting) { Meeting.new(project:) } before do @@ -95,11 +95,11 @@ allow(Meeting).to receive(:new).and_return(meeting) end - shared_examples_for "new action" do |response_type:| + shared_examples_for 'new action' do |response_type:| describe response_type do - context "when requesting the page without a project id" do + context 'when requesting the page without a project id' do before do - get "new" + get 'new' end it { expect(response).to be_successful } @@ -107,9 +107,9 @@ it { expect(assigns(:project)).to be_nil } end - context "when requesting the page with a project id" do + context 'when requesting the page with a project id' do before do - get "new", params: { project_id: project.id } + get 'new', params: { project_id: project.id } end it { expect(response).to be_successful } @@ -119,16 +119,16 @@ end end - it_behaves_like "new action", response_type: "html" - it_behaves_like "new action", response_type: "turbo_stream" + it_behaves_like 'new action', response_type: 'html' + it_behaves_like 'new action', response_type: 'turbo_stream' end - describe "edit" do + describe 'edit' do let(:meeting) { create(:meeting, project:) } - describe "html" do + describe 'html' do before do - get "edit", params: { id: meeting.id } + get 'edit', params: { id: meeting.id } end it { expect(response).to be_successful } @@ -137,8 +137,8 @@ end end - describe "POST" do - describe "create" do + describe 'POST' do + describe 'create' do render_views let(:base_params) do @@ -150,10 +150,10 @@ let(:base_meeting_params) do { - title: "Foobar", - duration: "1.0", - start_date: "2015-06-01", - start_time_hour: "10:00" + title: 'Foobar', + duration: '1.0', + start_date: '2015-06-01', + start_time_hour: '10:00' } end @@ -167,80 +167,80 @@ params: end - context "with a project_id" do - context "and an invalid start_date with start_time_hour" do + context 'with a project_id' do + context 'and an invalid start_date with start_time_hour' do let(:meeting_params) do - base_meeting_params.merge(start_date: "-") + base_meeting_params.merge(start_date: '-') end - it "renders an error" do + it 'renders an error' do expect(response).to have_http_status :ok expect(response).to render_template :new expect(response.body) - .to have_css "#errorExplanation li", + .to have_css '#errorExplanation li', text: "Date #{I18n.t('activerecord.errors.messages.not_an_iso_date')}" end end - context "and an invalid start_time_hour with start_date" do + context 'and an invalid start_time_hour with start_date' do let(:meeting_params) do - base_meeting_params.merge(start_time_hour: "-") + base_meeting_params.merge(start_time_hour: '-') end - it "renders an error" do + it 'renders an error' do expect(response).to have_http_status :ok expect(response).to render_template :new expect(response.body) - .to have_css "#errorExplanation li", + .to have_css '#errorExplanation li', text: "Starting time #{I18n.t('activerecord.errors.messages.invalid_time_format')}" end end end - context "with a nil project_id" do + context 'with a nil project_id' do let(:project) { nil } - it "renders an error" do + it 'renders an error' do expect(response).to have_http_status :ok expect(response).to render_template :new expect(response.body) - .to have_css "#errorExplanation li", + .to have_css '#errorExplanation li', text: "Project #{I18n.t('activerecord.errors.messages.blank')}" end end - context "without a project_id" do + context 'without a project_id' do let(:params) { base_params.except(:project_id) } let(:project) { nil } - it "renders an error" do + it 'renders an error' do expect(response).to have_http_status :ok expect(response).to render_template :new expect(response.body) - .to have_css "#errorExplanation li", + .to have_css '#errorExplanation li', text: "Project #{I18n.t('activerecord.errors.messages.blank')}" end end end end - describe "notify" do + describe 'notify' do let!(:meeting) { create(:meeting) } let!(:participant) { create(:meeting_participant, meeting:, attended: true) } - it "produces a background job for notification" do + it 'produces a background job for notification' do post :notify, params: { id: meeting.id } perform_enqueued_jobs expect(ActionMailer::Base.deliveries.count).to eq(1) end - context "with an error during deliver" do + context 'with an error during deliver' do before do allow(MeetingMailer).to receive(:invited).and_raise(Net::SMTPError) end - it "produces a flash message containing the mail addresses raising the error" do + it 'produces a flash message containing the mail addresses raising the error' do expect { post :notify, params: { id: meeting.id } }.not_to raise_error meeting.participants.each do |participant| expect(flash[:error]).to include(participant.name) diff --git a/modules/meeting/spec/factories/meeting_agenda_item_factory.rb b/modules/meeting/spec/factories/meeting_agenda_item_factory.rb index 4cebfcd5eac0..5a4bfe7939f1 100644 --- a/modules/meeting/spec/factories/meeting_agenda_item_factory.rb +++ b/modules/meeting/spec/factories/meeting_agenda_item_factory.rb @@ -34,7 +34,7 @@ duration_in_minutes { 10 } item_type { :simple } m.sequence(:title) { |n| "Agenda item #{n}" } - notes { "Agenda Item Notes" } + notes { 'Agenda Item Notes' } factory(:wp_meeting_agenda_item) do item_type { :work_package } diff --git a/modules/meeting/spec/factories/meeting_content_journal_factory.rb b/modules/meeting/spec/factories/meeting_content_journal_factory.rb index 245798e6014d..b5cd62f9b8dd 100644 --- a/modules/meeting/spec/factories/meeting_content_journal_factory.rb +++ b/modules/meeting/spec/factories/meeting_content_journal_factory.rb @@ -27,6 +27,6 @@ #++ FactoryBot.define do - factory :journal_meeting_content_journal, class: "Journal::MeetingContentJournal" do + factory :journal_meeting_content_journal, class: 'Journal::MeetingContentJournal' do end end diff --git a/modules/meeting/spec/factories/meeting_factory.rb b/modules/meeting/spec/factories/meeting_factory.rb index e7c31bbdb528..e23442368d48 100644 --- a/modules/meeting/spec/factories/meeting_factory.rb +++ b/modules/meeting/spec/factories/meeting_factory.rb @@ -27,19 +27,19 @@ #++ FactoryBot.define do - factory :meeting, class: "Meeting" do |m| + factory :meeting, class: 'Meeting' do |m| author factory: :user project start_time { Date.tomorrow + 10.hours } duration { 1.0 } - location { "https://some-url.com" } + location { 'https://some-url.com' } m.sequence(:title) { |n| "Meeting #{n}" } after(:create) do |meeting, evaluator| meeting.project = evaluator.project if evaluator.project end - factory :structured_meeting, class: "StructuredMeeting" do |m| + factory :structured_meeting, class: 'StructuredMeeting' do |m| m.sequence(:title) { |n| "Structured meeting #{n}" } end end diff --git a/modules/meeting/spec/factories/meeting_journal_factory.rb b/modules/meeting/spec/factories/meeting_journal_factory.rb index b26df1ead8de..baa02ebfa3f9 100644 --- a/modules/meeting/spec/factories/meeting_journal_factory.rb +++ b/modules/meeting/spec/factories/meeting_journal_factory.rb @@ -31,8 +31,8 @@ created_at { Time.now } sequence(:version) - factory :meeting_content_journal, class: "Journal" do - journable_type { "MeetingContent" } + factory :meeting_content_journal, class: 'Journal' do + journable_type { 'MeetingContent' } end end end diff --git a/modules/meeting/spec/features/meetings_activity_spec.rb b/modules/meeting/spec/features/meetings_activity_spec.rb index 414092441924..7c623f909057 100644 --- a/modules/meeting/spec/features/meetings_activity_spec.rb +++ b/modules/meeting/spec/features/meetings_activity_spec.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meetings", :js do +RSpec.describe 'Meetings', :js do let(:project) { create(:project, enabled_module_names: %w[meetings activity]) } let(:user) { create(:admin) } - let!(:meeting) { create(:meeting, project:, title: "Awesome meeting!") } - let!(:agenda) { create(:meeting_agenda, meeting:, text: "foo") } - let!(:minutes) { create(:meeting_minutes, meeting:, text: "minutes") } + let!(:meeting) { create(:meeting, project:, title: 'Awesome meeting!') } + let!(:agenda) { create(:meeting_agenda, meeting:, text: 'foo') } + let!(:minutes) { create(:meeting_minutes, meeting:, text: 'minutes') } before do login_as(user) end - describe "project activity" do - it "can show the meeting in the project activity" do + describe 'project activity' do + it 'can show the meeting in the project activity' do visit project_activity_index_path(project) - check "Meetings" - click_on "Apply" + check 'Meetings' + click_on 'Apply' - expect(page).to have_css(".op-activity-list--item-title", text: "Minutes: Awesome meeting!") - expect(page).to have_css(".op-activity-list--item-title", text: "Agenda: Awesome meeting!") - expect(page).to have_css(".op-activity-list--item-title", text: "Meeting: Awesome meeting!") + expect(page).to have_css('.op-activity-list--item-title', text: 'Minutes: Awesome meeting!') + expect(page).to have_css('.op-activity-list--item-title', text: 'Agenda: Awesome meeting!') + expect(page).to have_css('.op-activity-list--item-title', text: 'Meeting: Awesome meeting!') end end end diff --git a/modules/meeting/spec/features/meetings_attachments_spec.rb b/modules/meeting/spec/features/meetings_attachments_spec.rb index e628b662d8e9..e1ed93526f35 100644 --- a/modules/meeting/spec/features/meetings_attachments_spec.rb +++ b/modules/meeting/spec/features/meetings_attachments_spec.rb @@ -41,7 +41,7 @@ it 'can upload an image via drag & drop' do find('.ck-content') - editor.expect_button 'Upload image from computer' + editor.expect_button 'Insert image' editor.drag_attachment image_fixture.path, 'Some image caption' diff --git a/modules/meeting/spec/features/meetings_close_spec.rb b/modules/meeting/spec/features/meetings_close_spec.rb index 7dd952537c03..b0fb0a47d1df 100644 --- a/modules/meeting/spec/features/meetings_close_spec.rb +++ b/modules/meeting/spec/features/meetings_close_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meetings close" do +RSpec.describe 'Meetings close' do let(:project) { create(:project, enabled_module_names: %w[meetings]) } let(:user) do create(:user, @@ -39,55 +39,55 @@ member_with_permissions: { project => permissions }) end - let!(:meeting) { create(:meeting, project:, title: "Own awesome meeting!", author: user) } + let!(:meeting) { create(:meeting, project:, title: 'Own awesome meeting!', author: user) } let!(:meeting_agenda) { create(:meeting_agenda, meeting:, text: "asdf") } before do login_as(user) end - context "with permission to close meetings", :js do + context 'with permission to close meetings', :js do let(:permissions) { %i[view_meetings close_meeting_agendas] } - it "can delete own and other`s meetings" do + it 'can delete own and other`s meetings' do visit meetings_path(project) click_link meeting.title # Go to minutes, expect uneditable - find(".op-tab-row--link", text: "MINUTES").click + find('.op-tab-row--link', text: 'MINUTES').click - expect(page).to have_css(".button", text: "Close the agenda to begin the Minutes") + expect(page).to have_css('.button', text: 'Close the agenda to begin the Minutes') # Close the meeting - find(".op-tab-row--link", text: "AGENDA").click + find('.op-tab-row--link', text: 'AGENDA').click accept_confirm do - find(".button", text: "Close").click + find('.button', text: 'Close').click end # Expect to be on minutes - expect(page).to have_css(".op-tab-row--link_selected", text: "MINUTES") + expect(page).to have_css('.op-tab-row--link_selected', text: 'MINUTES') # Copies the text - expect(page).to have_css("#tab-content-minutes", text: "asdf") + expect(page).to have_css('#tab-content-minutes', text: 'asdf') # Go back to agenda, expect we can open it again - find(".op-tab-row--link", text: "AGENDA").click + find('.op-tab-row--link', text: 'AGENDA').click accept_confirm do - find(".button", text: "Open").click + find('.button', text: 'Open').click end - expect(page).to have_css(".button", text: "Close") + expect(page).to have_css('.button', text: 'Close') end end - context "without permission to close meetings" do + context 'without permission to close meetings' do let(:permissions) { %i[view_meetings] } - it "cannot delete own and other`s meetings" do + it 'cannot delete own and other`s meetings' do visit meetings_path(project) expect(page) - .to have_no_link "Close" + .to have_no_link 'Close' end end end diff --git a/modules/meeting/spec/features/meetings_copy_spec.rb b/modules/meeting/spec/features/meetings_copy_spec.rb index 2c6e503c7e5a..0aac54cf3949 100644 --- a/modules/meeting/spec/features/meetings_copy_spec.rb +++ b/modules/meeting/spec/features/meetings_copy_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meetings copy", :js, :with_cuprite do +RSpec.describe 'Meetings copy', :js, :with_cuprite do shared_let(:project) { create(:project, enabled_module_names: %w[meetings]) } shared_let(:permissions) { %i[view_meetings create_meetings] } shared_let(:user) do create(:user, member_with_permissions: { project => permissions }).tap do |u| - u.pref[:time_zone] = "UTC" + u.pref[:time_zone] = 'UTC' u.save! end @@ -51,8 +51,8 @@ create(:meeting, author: user, project:, - title: "Awesome meeting!", - location: "Meeting room", + title: 'Awesome meeting!', + location: 'Meeting room', duration:, start_time:).tap do |m| create(:meeting_agenda, meeting: m, text: agenda_text) @@ -73,26 +73,26 @@ login_as user end - it "copying a meeting" do + it 'copying a meeting' do visit project_meetings_path(project) click_link meeting.title - find_test_selector("meetings-more-dropdown-menu").click - page.within(".menu-drop-down-container") do - click_link "Copy" + find_test_selector('meetings-more-dropdown-menu').click + page.within('.menu-drop-down-container') do + click_link 'Copy' end expect(page) - .to have_field "Title", with: meeting.title + .to have_field 'Title', with: meeting.title expect(page) - .to have_field "Location", with: meeting.location + .to have_field 'Location', with: meeting.location expect(page) - .to have_field "Duration", with: meeting.duration + .to have_field 'Duration', with: meeting.duration expect(page) - .to have_field "Start date", with: (start_time + 1.week).strftime("%Y-%m-%d") + .to have_field 'Start date', with: (start_time + 1.week).strftime("%Y-%m-%d") expect(page) - .to have_field "Time", with: start_time.strftime("%H:%M") + .to have_field 'Time', with: start_time.strftime("%H:%M") click_button "Create" diff --git a/modules/meeting/spec/features/meetings_delete_spec.rb b/modules/meeting/spec/features/meetings_delete_spec.rb index 76fa351234d3..bfc9ec1d0679 100644 --- a/modules/meeting/spec/features/meetings_delete_spec.rb +++ b/modules/meeting/spec/features/meetings_delete_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meetings deletion" do +RSpec.describe 'Meetings deletion' do let(:project) { create(:project, enabled_module_names: %w[meetings]) } let(:user) do create(:user, @@ -39,8 +39,8 @@ member_with_permissions: { project => permissions }) end - let!(:meeting) { create(:meeting, project:, title: "Own awesome meeting!", author: user) } - let!(:other_meeting) { create(:meeting, project:, title: "Other awesome meeting!", author: other_user) } + let!(:meeting) { create(:meeting, project:, title: 'Own awesome meeting!', author: user) } + let!(:other_meeting) { create(:meeting, project:, title: 'Other awesome meeting!', author: other_user) } let(:index_path) { project_meetings_path(project) } @@ -48,7 +48,7 @@ login_as(user) end - context "with permission to delete meetings", :js do + context 'with permission to delete meetings', :js do let(:permissions) { %i[view_meetings delete_meetings] } it "can delete own and other's meetings" do @@ -56,7 +56,7 @@ click_link meeting.title accept_confirm do - find_test_selector("meetings-more-dropdown-menu").click + find_test_selector('meetings-more-dropdown-menu').click click_link "Delete" end @@ -65,19 +65,19 @@ click_link other_meeting.title accept_confirm do - find_test_selector("meetings-more-dropdown-menu").click + find_test_selector('meetings-more-dropdown-menu').click click_link "Delete" end expect(page) - .to have_content(I18n.t(".no_results_title_text", cascade: true)) + .to have_content(I18n.t('.no_results_title_text', cascade: true)) expect(page) .to have_current_path index_path end end - context "without permission to delete meetings" do + context 'without permission to delete meetings' do let(:permissions) { %i[view_meetings] } it "cannot delete own and other's meetings" do @@ -85,13 +85,13 @@ click_link meeting.title expect(page) - .to have_no_link "Delete" + .to have_no_link 'Delete' visit index_path click_link other_meeting.title expect(page) - .to have_no_link "Delete" + .to have_no_link 'Delete' end end end diff --git a/modules/meeting/spec/features/meetings_global_menu_item_spec.rb b/modules/meeting/spec/features/meetings_global_menu_item_spec.rb index d849d29f2e82..047878b24825 100644 --- a/modules/meeting/spec/features/meetings_global_menu_item_spec.rb +++ b/modules/meeting/spec/features/meetings_global_menu_item_spec.rb @@ -29,10 +29,10 @@ # ++ # -require "spec_helper" -require_relative "../support/pages/meetings/index" +require 'spec_helper' +require_relative '../support/pages/meetings/index' -RSpec.describe "Meetings global menu item", +RSpec.describe 'Meetings global menu item', :with_cuprite do shared_let(:user_without_permissions) { create(:user) } shared_let(:admin) { create(:admin) } @@ -44,33 +44,33 @@ login_as current_user end - context "as a user with permissions" do + context 'as a user with permissions' do let(:current_user) { admin } before do meetings_page.navigate_by_global_menu end - it "navigates to the global meetings index page" do - expect(page).to have_current_path("/meetings") + it 'navigates to the global meetings index page' do + expect(page).to have_current_path('/meetings') end specify '"Upcoming meetings" is the default filter set' do - within "#main-menu" do - expect(page).to have_css(".selected", text: I18n.t(:label_upcoming_meetings)) + within '#main-menu' do + expect(page).to have_css('.selected', text: I18n.t(:label_upcoming_meetings)) end end end - context "as a user without permissions" do + context 'as a user without permissions' do let(:current_user) { user_without_permissions } before do visit root_path end - it "does not render" do - within "#main-menu" do + it 'does not render' do + within '#main-menu' do expect(page).to have_no_link(meetings_label) end end diff --git a/modules/meeting/spec/features/meetings_index_spec.rb b/modules/meeting/spec/features/meetings_index_spec.rb index 941ac61d057e..5f99d71a894b 100644 --- a/modules/meeting/spec/features/meetings_index_spec.rb +++ b/modules/meeting/spec/features/meetings_index_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/meetings/index" +require_relative '../support/pages/meetings/index' -RSpec.describe "Meetings", "Index", :with_cuprite do +RSpec.describe 'Meetings', 'Index', :with_cuprite do # The order the Projects are created in is important. By naming `project` alphanumerically # after `other_project`, we can ensure that subsequent specs that assert sorting is # correct for the right reasons (sorting by Project name and not id) - shared_let(:project) { create(:project, name: "Project 2", enabled_module_names: %w[meetings]) } - shared_let(:other_project) { create(:project, name: "Project 1", enabled_module_names: %w[meetings]) } + shared_let(:project) { create(:project, name: 'Project 2', enabled_module_names: %w[meetings]) } + shared_let(:other_project) { create(:project, name: 'Project 1', enabled_module_names: %w[meetings]) } let(:role) { create(:project_role, permissions:) } let(:permissions) { %i(view_meetings) } let(:user) do @@ -52,42 +52,42 @@ let(:meeting) do create(:meeting, project:, - title: "Awesome meeting today!", + title: 'Awesome meeting today!', start_time: Time.current) end let(:tomorrows_meeting) do create(:meeting, project:, - title: "Awesome meeting tomorrow!", + title: 'Awesome meeting tomorrow!', start_time: 1.day.from_now, duration: 2.0, - location: "no-protocol.com") + location: 'no-protocol.com') end let(:meeting_with_no_location) do create(:meeting, project:, - title: "Boring meeting without a location!", + title: 'Boring meeting without a location!', start_time: 1.day.from_now, - location: "") + location: '') end let(:meeting_with_malicious_location) do create(:meeting, project:, - title: "Sneaky meeting!", + title: 'Sneaky meeting!', start_time: 1.day.from_now, location: "") end let(:yesterdays_meeting) do - create(:meeting, project:, title: "Awesome meeting yesterday!", start_time: 1.day.ago) + create(:meeting, project:, title: 'Awesome meeting yesterday!', start_time: 1.day.ago) end shared_let(:other_project_meeting) do create(:meeting, project: other_project, - title: "Awesome other project meeting!", + title: 'Awesome other project meeting!', start_time: 2.days.from_now, duration: 2.0, - location: "not-a-url") + location: 'not-a-url') end def setup_meeting_involvement @@ -101,10 +101,10 @@ def setup_meeting_involvement login_as user end - shared_examples "sidebar filtering" do |context:| - context "when filtering with the sidebar" do + shared_examples 'sidebar filtering' do |context:| + context 'when filtering with the sidebar' do shared_let(:ongoing_meeting) do - create(:meeting, project:, title: "Awesome ongoing meeting!", start_time: 30.minutes.ago) + create(:meeting, project:, title: 'Awesome ongoing meeting!', start_time: 30.minutes.ago) end before do @@ -114,10 +114,10 @@ def setup_meeting_involvement context 'with the "Upcoming meetings" filter' do before do - meetings_page.set_sidebar_filter "Upcoming meetings" + meetings_page.set_sidebar_filter 'Upcoming meetings' end - it "shows all upcoming and ongoing meetings", :aggregate_failures do + it 'shows all upcoming and ongoing meetings', :aggregate_failures do expected_upcoming_meetings = if context == :global [ongoing_meeting, meeting, tomorrows_meeting, other_project_meeting] else @@ -131,10 +131,10 @@ def setup_meeting_involvement context 'with the "Past meetings" filter' do before do - meetings_page.set_sidebar_filter "Past meetings" + meetings_page.set_sidebar_filter 'Past meetings' end - it "show all past and ongoing meetings" do + it 'show all past and ongoing meetings' do meetings_page.expect_meetings_listed_in_order(ongoing_meeting, yesterdays_meeting) meetings_page.expect_meetings_not_listed(meeting, @@ -144,7 +144,7 @@ def setup_meeting_involvement context 'with the "Upcoming invitations" filter' do before do - meetings_page.set_sidebar_filter "Upcoming invitations" + meetings_page.set_sidebar_filter 'Upcoming invitations' end it "shows all upcoming meetings I've been marked as invited to" do @@ -157,7 +157,7 @@ def setup_meeting_involvement context 'with the "Past invitations" filter' do before do - meetings_page.set_sidebar_filter "Past invitations" + meetings_page.set_sidebar_filter 'Past invitations' end it "shows all past meetings I've been marked as invited to" do @@ -170,7 +170,7 @@ def setup_meeting_involvement context 'with the "Attendee" filter' do before do - meetings_page.set_sidebar_filter "Attendee" + meetings_page.set_sidebar_filter 'Attendee' end it "shows all meetings I've been marked as attending to" do @@ -183,7 +183,7 @@ def setup_meeting_involvement context 'with the "Creator" filter' do before do - meetings_page.set_sidebar_filter "Creator" + meetings_page.set_sidebar_filter 'Creator' end it "shows all meetings I'm the author of" do @@ -196,10 +196,10 @@ def setup_meeting_involvement end end - context "when visiting from a global context" do + context 'when visiting from a global context' do let(:meetings_page) { Pages::Meetings::Index.new(project: nil) } - it "lists all upcoming meetings for all projects the user has access to" do + it 'lists all upcoming meetings for all projects the user has access to' do meeting yesterdays_meeting @@ -223,17 +223,17 @@ def setup_meeting_involvement meetings_page.expect_no_meeting_location(meeting_with_no_location) end - context "and the user is allowed to create meetings" do + context 'and the user is allowed to create meetings' do let(:permissions) { %i(view_meetings create_meetings) } - it "shows the create new buttons" do + it 'shows the create new buttons' do meetings_page.navigate_by_modules_menu meetings_page.expect_create_new_buttons end end - context "and the user is not allowed to create meetings" do + context 'and the user is not allowed to create meetings' do let(:permissions) { %i[view_meetings] } it "doesn't show a create new button" do @@ -243,7 +243,7 @@ def setup_meeting_involvement end end - describe "sorting" do + describe 'sorting' do before do meeting visit meetings_path @@ -255,78 +255,78 @@ def setup_meeting_involvement meetings_page.expect_meetings_listed_in_order(meeting, other_project_meeting) end - it "allows sorting by every column" do - aggregate_failures "Sorting by Title" do - meetings_page.click_to_sort_by("Title") + it 'allows sorting by every column' do + aggregate_failures 'Sorting by Title' do + meetings_page.click_to_sort_by('Title') meetings_page.expect_meetings_listed_in_order(meeting, other_project_meeting) - meetings_page.click_to_sort_by("Title") + meetings_page.click_to_sort_by('Title') meetings_page.expect_meetings_listed_in_order(other_project_meeting, meeting) end - aggregate_failures "Sorting by Project" do - meetings_page.click_to_sort_by("Project") + aggregate_failures 'Sorting by Project' do + meetings_page.click_to_sort_by('Project') meetings_page.expect_meetings_listed_in_order(other_project_meeting, meeting) - meetings_page.click_to_sort_by("Project") + meetings_page.click_to_sort_by('Project') meetings_page.expect_meetings_listed_in_order(meeting, other_project_meeting) end - aggregate_failures "Sorting by Time" do - meetings_page.click_to_sort_by("Time") + aggregate_failures 'Sorting by Time' do + meetings_page.click_to_sort_by('Time') meetings_page.expect_meetings_listed_in_order(meeting, other_project_meeting) - meetings_page.click_to_sort_by("Time") + meetings_page.click_to_sort_by('Time') meetings_page.expect_meetings_listed_in_order(other_project_meeting, meeting) end - aggregate_failures "Sorting by Duration" do - meetings_page.click_to_sort_by("Duration") + aggregate_failures 'Sorting by Duration' do + meetings_page.click_to_sort_by('Duration') meetings_page.expect_meetings_listed_in_order(meeting, other_project_meeting) - meetings_page.click_to_sort_by("Duration") + meetings_page.click_to_sort_by('Duration') meetings_page.expect_meetings_listed_in_order(other_project_meeting, meeting) end - aggregate_failures "Sorting by Location" do - meetings_page.click_to_sort_by("Location") + aggregate_failures 'Sorting by Location' do + meetings_page.click_to_sort_by('Location') meetings_page.expect_meetings_listed_in_order(meeting, other_project_meeting) - meetings_page.click_to_sort_by("Location") + meetings_page.click_to_sort_by('Location') meetings_page.expect_meetings_listed_in_order(other_project_meeting, meeting) end end end - include_examples "sidebar filtering", context: :global + include_examples 'sidebar filtering', context: :global end - context "when visiting from a project specific context" do + context 'when visiting from a project specific context' do let(:meetings_page) { Pages::Meetings::Index.new(project:) } - context "via the menu" do - specify "with no meetings" do + context 'via the menu' do + specify 'with no meetings' do meetings_page.navigate_by_project_menu meetings_page.expect_no_meetings_listed end end - context "when the user is allowed to create meetings" do + context 'when the user is allowed to create meetings' do let(:permissions) { %i(view_meetings create_meetings) } - it "shows the create new buttons" do + it 'shows the create new buttons' do meetings_page.visit! meetings_page.expect_create_new_buttons end end - context "when the user is not allowed to create meetings" do + context 'when the user is not allowed to create meetings' do let(:permissions) { %i[view_meetings] } it "doesn't show the create new buttons" do @@ -335,16 +335,16 @@ def setup_meeting_involvement end end - include_examples "sidebar filtering", context: :project + include_examples 'sidebar filtering', context: :project - specify "with 1 meeting listed" do + specify 'with 1 meeting listed' do meeting meetings_page.visit! meetings_page.expect_meetings_listed(meeting) end - it "with pagination", with_settings: { per_page_options: "1" } do + it 'with pagination', with_settings: { per_page_options: '1' } do meeting tomorrows_meeting yesterdays_meeting @@ -377,7 +377,7 @@ def setup_meeting_involvement meetings_page.expect_no_meeting_location(meeting_with_no_location) end - describe "sorting" do + describe 'sorting' do before do meeting tomorrows_meeting @@ -390,57 +390,57 @@ def setup_meeting_involvement meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) end - it "allows sorting by every column" do - aggregate_failures "Sorting by Title" do - meetings_page.click_to_sort_by("Title") + it 'allows sorting by every column' do + aggregate_failures 'Sorting by Title' do + meetings_page.click_to_sort_by('Title') meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) - meetings_page.click_to_sort_by("Title") + meetings_page.click_to_sort_by('Title') meetings_page.expect_meetings_listed_in_order(tomorrows_meeting, meeting) end - aggregate_failures "Sorting by Time" do - meetings_page.click_to_sort_by("Time") + aggregate_failures 'Sorting by Time' do + meetings_page.click_to_sort_by('Time') meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) - meetings_page.click_to_sort_by("Time") + meetings_page.click_to_sort_by('Time') meetings_page.expect_meetings_listed_in_order(tomorrows_meeting, meeting) end - aggregate_failures "Sorting by Time" do - meetings_page.click_to_sort_by("Time") + aggregate_failures 'Sorting by Time' do + meetings_page.click_to_sort_by('Time') meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) - meetings_page.click_to_sort_by("Time") + meetings_page.click_to_sort_by('Time') meetings_page.expect_meetings_listed_in_order(tomorrows_meeting, meeting) end - aggregate_failures "Sorting by Duration" do - meetings_page.click_to_sort_by("Duration") + aggregate_failures 'Sorting by Duration' do + meetings_page.click_to_sort_by('Duration') meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) - meetings_page.click_to_sort_by("Duration") + meetings_page.click_to_sort_by('Duration') meetings_page.expect_meetings_listed_in_order(tomorrows_meeting, meeting) end - aggregate_failures "Sorting by Duration" do - meetings_page.click_to_sort_by("Duration") + aggregate_failures 'Sorting by Duration' do + meetings_page.click_to_sort_by('Duration') meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) - meetings_page.click_to_sort_by("Duration") + meetings_page.click_to_sort_by('Duration') meetings_page.expect_meetings_listed_in_order(tomorrows_meeting, meeting) end - aggregate_failures "Sorting by Location" do - meetings_page.click_to_sort_by("Location") + aggregate_failures 'Sorting by Location' do + meetings_page.click_to_sort_by('Location') meetings_page.expect_meetings_listed_in_order(meeting, tomorrows_meeting) - meetings_page.click_to_sort_by("Location") + meetings_page.click_to_sort_by('Location') meetings_page.expect_meetings_listed_in_order(tomorrows_meeting, meeting) end diff --git a/modules/meeting/spec/features/meetings_locking_spec.rb b/modules/meeting/spec/features/meetings_locking_spec.rb index d40186178d0e..cf4dbac72dcd 100644 --- a/modules/meeting/spec/features/meetings_locking_spec.rb +++ b/modules/meeting/spec/features/meetings_locking_spec.rb @@ -26,40 +26,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meetings locking", :js do +RSpec.describe 'Meetings locking', :js do let(:project) { create(:project, enabled_module_names: %w[meetings]) } let(:user) { create(:admin) } let!(:meeting) { create(:meeting) } let!(:agenda) { create(:meeting_agenda, meeting:) } let(:agenda_field) do TextEditorField.new(page, - "", - selector: test_selector("op-meeting--meeting_agenda")) + '', + selector: test_selector('op-meeting--meeting_agenda')) end before do login_as(user) end - it "shows an error when trying to update a meeting update while editing" do + it 'shows an error when trying to update a meeting update while editing' do visit meeting_path(meeting) # Edit agenda - within "#tab-content-agenda" do - find(".button--edit-agenda").click + within '#tab-content-agenda' do + find('.button--edit-agenda').click - agenda_field.set_value("Some new text") + agenda_field.set_value('Some new text') - agenda.text = "blabla" + agenda.text = 'blabla' agenda.save! - click_on "Save" + click_on 'Save' end - expect(page).to have_text "Information has been updated by at least one other user in the meantime." + expect(page).to have_text 'Information has been updated by at least one other user in the meantime.' - agenda_field.expect_value("Some new text") + agenda_field.expect_value('Some new text') end end diff --git a/modules/meeting/spec/features/meetings_new_spec.rb b/modules/meeting/spec/features/meetings_new_spec.rb index 5f710ba71edb..cf042da7c1da 100644 --- a/modules/meeting/spec/features/meetings_new_spec.rb +++ b/modules/meeting/spec/features/meetings_new_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/meetings/index" +require_relative '../support/pages/meetings/index' -RSpec.describe "Meetings new", :js, with_cuprite: false do +RSpec.describe 'Meetings new', :js, with_cuprite: false do shared_let(:project) { create(:project, enabled_module_names: %w[meetings]) } shared_let(:admin) { create(:admin) } - let(:time_zone) { "utc" } + let(:time_zone) { 'utc' } let(:user) do create(:user, - lastname: "First", + lastname: 'First', member_with_permissions: { project => permissions }).tap do |u| u.pref[:time_zone] = time_zone @@ -45,7 +45,7 @@ end let(:other_user) do create(:user, - lastname: "Second", + lastname: 'Second', member_with_permissions: { project => permissions }) end let(:permissions) { %i[view_meetings create_meetings] } @@ -55,7 +55,7 @@ login_as current_user end - context "when creating a meeting from the global page" do + context 'when creating a meeting from the global page' do before do other_user project @@ -64,21 +64,21 @@ let(:index_page) { Pages::Meetings::Index.new(project: nil) } let(:new_page) { Pages::Meetings::New.new(nil) } - context "with permission to create meetings" do - it "does not render menus", :with_cuprite do + context 'with permission to create meetings' do + it 'does not render menus', :with_cuprite do new_page.visit! new_page.expect_no_main_menu end - describe "clicking on the create new meeting button", :with_cuprite do - it "navigates to the global create form" do + describe 'clicking on the create new meeting button', :with_cuprite do + it 'navigates to the global create form' do index_page.visit! index_page.click_create_new expect(page).to have_current_path(new_page.path) end end - ["CET", "UTC", "", "Pacific Time (US & Canada)"].each do |zone| + ['CET', 'UTC', '', 'Pacific Time (US & Canada)'].each do |zone| let(:time_zone) { zone } it "allows creating a project and handles errors in time zone #{zone}" do @@ -86,18 +86,18 @@ expect_angular_frontend_initialized # Wait for project dropdown to be ready - new_page.set_title "Some title" - new_page.set_type "Classic" + new_page.set_title 'Some title' + new_page.set_type 'Classic' new_page.set_project project - new_page.set_start_date "2013-03-28" - new_page.set_start_time "13:30" - new_page.set_duration "1.5" + new_page.set_start_date '2013-03-28' + new_page.set_start_time '13:30' + new_page.set_duration '1.5' new_page.invite(other_user) show_page = new_page.click_create - show_page.expect_toast(message: "Successful creation") + show_page.expect_toast(message: 'Successful creation') show_page.expect_invited(user, other_user) @@ -105,7 +105,7 @@ end end - context "without a title set" do + context 'without a title set' do before do new_page.visit! @@ -114,13 +114,13 @@ new_page.set_project project - new_page.set_start_date "2013-03-28" - new_page.set_start_time "13:30" - new_page.set_duration "1.5" + new_page.set_start_date '2013-03-28' + new_page.set_start_time '13:30' + new_page.set_duration '1.5' new_page.invite(other_user) end - it "renders a validation error" do + it 'renders a validation error' do expect do new_page.click_create end.not_to change(Query, :count) @@ -130,17 +130,17 @@ end end - context "without a project set" do + context 'without a project set' do before do new_page.visit! - new_page.set_title "Some title" - new_page.set_type "Classic" - new_page.set_start_date "2013-03-28" - new_page.set_start_time "13:30" - new_page.set_duration "1.5" + new_page.set_title 'Some title' + new_page.set_type 'Classic' + new_page.set_start_date '2013-03-28' + new_page.set_start_time '13:30' + new_page.set_duration '1.5' end - it "renders a validation error" do + it 'renders a validation error' do new_page.click_create new_page.expect_toast(message: "#{Project.model_name.human} #{I18n.t('activerecord.errors.messages.blank')}", @@ -151,26 +151,26 @@ end end - context "without permission to create meetings", :with_cuprite do + context 'without permission to create meetings', :with_cuprite do let(:permissions) { %i[view_meetings] } - it "shows no edit link" do + it 'shows no edit link' do index_page.visit! index_page.expect_no_create_new_button end end - context "as an admin", :with_cuprite do + context 'as an admin', :with_cuprite do let(:current_user) { admin } - it "allows creating meeting in a project without members" do + it 'allows creating meeting in a project without members' do new_page.visit! expect_angular_frontend_initialized # Wait for project dropdown to be ready - new_page.set_title "Some title" - new_page.set_type "Classic" + new_page.set_title 'Some title' + new_page.set_type 'Classic' new_page.set_project project @@ -178,20 +178,20 @@ show_page = new_page.click_create - show_page.expect_toast(message: "Successful creation") + show_page.expect_toast(message: 'Successful creation') # Not sure if that is then intended behaviour but that is what is currently programmed show_page.expect_invited(admin) end - context "without a project set" do + context 'without a project set' do before do new_page.visit! - new_page.set_title "Some title" - new_page.set_type "Classic" + new_page.set_title 'Some title' + new_page.set_type 'Classic' end - it "renders a validation error" do + it 'renders a validation error' do new_page.click_create new_page.expect_toast(message: "#{Project.model_name.human} #{I18n.t('activerecord.errors.messages.blank')}", @@ -200,7 +200,7 @@ end end - context "without a title set" do + context 'without a title set' do before do new_page.visit! @@ -210,7 +210,7 @@ new_page.set_project project end - it "renders a validation error" do + it 'renders a validation error' do expect do new_page.click_create end.not_to change(Query, :count) @@ -222,39 +222,39 @@ end end - context "when creating a meeting from the project-specific page" do + context 'when creating a meeting from the project-specific page' do let(:index_page) { Pages::Meetings::Index.new(project:) } let(:new_page) { Pages::Meetings::New.new(project) } - context "with permission to create meetings" do + context 'with permission to create meetings' do before do other_user end - describe "clicking on the create new meeting button", :with_cuprite do - it "navigates to the project-specific create form" do + describe 'clicking on the create new meeting button', :with_cuprite do + it 'navigates to the project-specific create form' do index_page.visit! index_page.click_create_new expect(page).to have_current_path(new_page.path) end end - ["CET", "UTC", "", "Pacific Time (US & Canada)"].each do |zone| + ['CET', 'UTC', '', 'Pacific Time (US & Canada)'].each do |zone| let(:time_zone) { zone } it "allows creating a project and handles errors in time zone #{zone}" do new_page.visit! - new_page.set_title "Some title" - new_page.set_type "Classic" - new_page.set_start_date "2013-03-28" - new_page.set_start_time "13:30" - new_page.set_duration "1.5" + new_page.set_title 'Some title' + new_page.set_type 'Classic' + new_page.set_start_date '2013-03-28' + new_page.set_start_time '13:30' + new_page.set_duration '1.5' new_page.invite(other_user) show_page = new_page.click_create - show_page.expect_toast(message: "Successful creation") + show_page.expect_toast(message: 'Successful creation') show_page.expect_invited(user, other_user) @@ -262,16 +262,16 @@ end end - context "without a title set" do + context 'without a title set' do before do new_page.visit! - new_page.set_start_date "2013-03-28" - new_page.set_start_time "13:30" - new_page.set_duration "1.5" + new_page.set_start_date '2013-03-28' + new_page.set_start_time '13:30' + new_page.set_duration '1.5' new_page.invite(other_user) end - it "renders a validation error" do + it 'renders a validation error' do expect do new_page.click_create end.not_to change(Query, :count) @@ -282,44 +282,44 @@ end end - context "without permission to create meetings", :with_cuprite do + context 'without permission to create meetings', :with_cuprite do let(:permissions) { %i[view_meetings] } - it "shows no edit link" do + it 'shows no edit link' do index_page.visit! index_page.expect_no_create_new_button end end - context "as an admin", :with_cuprite do + context 'as an admin', :with_cuprite do let(:current_user) { admin } let(:field) do TextEditorField.new(page, - "", - selector: test_selector("op-meeting--meeting_agenda")) + '', + selector: test_selector('op-meeting--meeting_agenda')) end - it "allows creating meeting in a project without members" do + it 'allows creating meeting in a project without members' do new_page.visit! - new_page.set_type "Classic" - new_page.set_title "Some title" + new_page.set_type 'Classic' + new_page.set_title 'Some title' show_page = new_page.click_create - show_page.expect_toast(message: "Successful creation") + show_page.expect_toast(message: 'Successful creation') # Not sure if that is then intended behaviour but that is what is currently programmed show_page.expect_invited(admin) end - context "without a title set" do + context 'without a title set' do before do new_page.visit! end - it "renders a validation error" do + it 'renders a validation error' do expect do new_page.click_create end.not_to change(Query, :count) @@ -329,27 +329,27 @@ end end - it "can save the meeting agenda via cmd+Enter" do + it 'can save the meeting agenda via cmd+Enter' do new_page.visit! - new_page.set_title "Some title" - new_page.set_type "Classic" + new_page.set_title 'Some title' + new_page.set_type 'Classic' show_page = new_page.click_create - show_page.expect_toast(message: "Successful creation") + show_page.expect_toast(message: 'Successful creation') meeting = Meeting.last - field.set_value("My new meeting text") + field.set_value('My new meeting text') field.submit_by_enter - show_page.expect_and_dismiss_toaster message: "Successful update" + show_page.expect_and_dismiss_toaster message: 'Successful update' meeting.reload - expect(meeting.agenda.text).to eq "My new meeting text" + expect(meeting.agenda.text).to eq 'My new meeting text' end end end diff --git a/modules/meeting/spec/features/meetings_participants_spec.rb b/modules/meeting/spec/features/meetings_participants_spec.rb index 3159e2df5cf5..fd05156c1087 100644 --- a/modules/meeting/spec/features/meetings_participants_spec.rb +++ b/modules/meeting/spec/features/meetings_participants_spec.rb @@ -26,35 +26,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/meetings/edit" +require_relative '../support/pages/meetings/edit' -RSpec.describe "Meetings participants" do +RSpec.describe 'Meetings participants' do let(:project) { create(:project, enabled_module_names: %w[meetings]) } let!(:user) do create(:user, - firstname: "Current", + firstname: 'Current', member_with_permissions: { project => %i[view_meetings edit_meetings] }) end let!(:viewer_user) do create(:user, - firstname: "Viewer", + firstname: 'Viewer', member_with_permissions: { project => %i[view_meetings] }) end let!(:non_viewer_user) do create(:user, - firstname: "Nonviewer", + firstname: 'Nonviewer', member_with_permissions: { project => %i[] }) end let(:edit_page) { Pages::Meetings::Edit.new(meeting) } - let!(:meeting) { create(:meeting, project:, title: "Awesome meeting!") } + let!(:meeting) { create(:meeting, project:, title: 'Awesome meeting!') } before do login_as(user) end - it "allows setting members to participants which are allowed to view the meeting" do + it 'allows setting members to participants which are allowed to view the meeting' do edit_page.visit! edit_page.expect_available_participant(user) @@ -64,7 +64,7 @@ edit_page.invite(viewer_user) show_page = edit_page.click_save - show_page.expect_toast(message: "Successful update") + show_page.expect_toast(message: 'Successful update') show_page.expect_invited(viewer_user) @@ -72,12 +72,12 @@ edit_page.uninvite(viewer_user) show_page = edit_page.click_save - show_page.expect_toast(message: "Successful update") + show_page.expect_toast(message: 'Successful update') show_page.expect_uninvited(viewer_user) end - context "with an invalid user reference" do + context 'with an invalid user reference' do let(:show_page) { Pages::Meetings::Show.new(meeting) } let(:meeting_participant) { create(:meeting_participant, user: viewer_user, meeting:) } @@ -85,7 +85,7 @@ meeting_participant.update_column(:user_id, 12341234) end - it "still allows to view the meeting" do + it 'still allows to view the meeting' do show_page.visit! show_page.expect_invited meeting.author diff --git a/modules/meeting/spec/features/meetings_search_spec.rb b/modules/meeting/spec/features/meetings_search_spec.rb index c9ab648b204c..dfd6e4165c1b 100644 --- a/modules/meeting/spec/features/meetings_search_spec.rb +++ b/modules/meeting/spec/features/meetings_search_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meeting search", :js do +RSpec.describe 'Meeting search', :js do include Components::Autocompleter::NgSelectAutocompleteHelpers let(:project) { create(:project) } let(:role) { create(:project_role, permissions: %i(view_meetings view_work_packages)) } @@ -43,35 +43,35 @@ visit project_path(project) end - context "global search" do - it "works with a title" do - select_autocomplete(page.find(".top-menu-search--input"), + context 'global search' do + it 'works with a title' do + select_autocomplete(page.find('.top-menu-search--input'), query: "Meeting", select_text: "In this project ↵", wait_dropdown_open: false) page.find('[data-qa-tab-id="meetings"]').click - expect(page.find_by_id("search-results")).to have_text(meeting.title) + expect(page.find_by_id('search-results')).to have_text(meeting.title) end - it "works with an agenda item title" do - select_autocomplete(page.find(".top-menu-search--input"), + it 'works with an agenda item title' do + select_autocomplete(page.find('.top-menu-search--input'), query: agenda_item.title, select_text: "In this project ↵", wait_dropdown_open: false) page.find('[data-qa-tab-id="meetings"]').click - expect(page.find_by_id("search-results")).to have_text(meeting.title) + expect(page.find_by_id('search-results')).to have_text(meeting.title) end - it "works with an agenda item notes" do - select_autocomplete(page.find(".top-menu-search--input"), + it 'works with an agenda item notes' do + select_autocomplete(page.find('.top-menu-search--input'), query: agenda_item.notes, select_text: "In this project ↵", wait_dropdown_open: false) page.find('[data-qa-tab-id="meetings"]').click - expect(page.find_by_id("search-results")).to have_text(meeting.title) + expect(page.find_by_id('search-results')).to have_text(meeting.title) end end end diff --git a/modules/meeting/spec/features/meetings_show_spec.rb b/modules/meeting/spec/features/meetings_show_spec.rb index 498d830b1ad1..7715a4c020fa 100644 --- a/modules/meeting/spec/features/meetings_show_spec.rb +++ b/modules/meeting/spec/features/meetings_show_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/pages/meetings/show" +require 'spec_helper' +require_relative '../support/pages/meetings/show' -RSpec.describe "Meetings", :js do +RSpec.describe 'Meetings', :js do let(:project) { create(:project, enabled_module_names: %w[meetings]) } let(:role) { create(:project_role, permissions:) } let(:user) do @@ -37,39 +37,39 @@ member_with_roles: { project => role }) end - let!(:meeting) { create(:meeting, project:, title: "Awesome meeting!") } + let!(:meeting) { create(:meeting, project:, title: 'Awesome meeting!') } let(:show_page) { Pages::Meetings::Show.new(meeting) } current_user { user } - describe "navigate to meeting page" do + describe 'navigate to meeting page' do let(:permissions) { %i[view_meetings] } - it "can visit the meeting" do + it 'can visit the meeting' do visit meetings_path(project) - find("td.title a", text: "Awesome meeting!", wait: 10).click - expect(page).to have_css("h2", text: "Meeting: Awesome meeting!") + find('td.title a', text: 'Awesome meeting!', wait: 10).click + expect(page).to have_css('h2', text: 'Meeting: Awesome meeting!') - expect(page).to have_test_selector("op-meeting--meeting_agenda", - text: "There is currently nothing to display") + expect(page).to have_test_selector('op-meeting--meeting_agenda', + text: 'There is currently nothing to display') end - context "with a location" do - context "as a valid url" do - it "renders a link to the meeting location" do + context 'with a location' do + context 'as a valid url' do + it 'renders a link to the meeting location' do show_page.visit! show_page.expect_link_to_location(meeting.location) end end - context "as an invalid url" do + context 'as an invalid url' do before do - meeting.update!(location: "badurl") + meeting.update!(location: 'badurl') end - it "renders the meeting location as plaintext" do + it 'renders the meeting location as plaintext' do show_page.visit! show_page.expect_plaintext_location(meeting.location) @@ -77,100 +77,100 @@ end end - context "with an open agenda" do - let!(:agenda) { create(:meeting_agenda, meeting:, text: "foo") } - let(:agenda_update) { create(:meeting_agenda, meeting:, text: "bla") } + context 'with an open agenda' do + let!(:agenda) { create(:meeting_agenda, meeting:, text: 'foo') } + let(:agenda_update) { create(:meeting_agenda, meeting:, text: 'bla') } - it "shows the agenda" do + it 'shows the agenda' do visit meeting_path(meeting) - expect(page).to have_test_selector("op-meeting--meeting_agenda", - text: "foo") + expect(page).to have_test_selector('op-meeting--meeting_agenda', + text: 'foo') # May not edit - expect(page).to have_no_css(".button--edit-agenda") - expect(page).not_to have_test_selector("op-meeting--meeting_agenda", - text: "Edit") + expect(page).to have_no_css('.button--edit-agenda') + expect(page).not_to have_test_selector('op-meeting--meeting_agenda', + text: 'Edit') end - it "can view history" do + it 'can view history' do agenda_update visit meeting_path(meeting) - click_on "History" + click_on 'History' - find_by_id("version-1").click - expect(page).to have_test_selector("op-meeting--meeting_agenda", text: "foo") + find_by_id('version-1').click + expect(page).to have_test_selector('op-meeting--meeting_agenda', text: 'foo') end - context "and edit permissions" do + context 'and edit permissions' do let(:permissions) { %i[view_meetings create_meeting_agendas] } let(:field) do TextEditorField.new(page, - "", - selector: test_selector("op-meeting--meeting_agenda")) + '', + selector: test_selector('op-meeting--meeting_agenda')) end - it "can edit the agenda" do + it 'can edit the agenda' do visit meeting_path(meeting) - find(".toolbar-item", text: "Edit").click + find('.toolbar-item', text: 'Edit').click - field.expect_value("foo") + field.expect_value('foo') - field.set_value("My new meeting text") + field.set_value('My new meeting text') field.submit_by_enter - show_page.expect_and_dismiss_toaster message: "Successful update" + show_page.expect_and_dismiss_toaster message: 'Successful update' meeting.reload - expect(meeting.agenda.text).to eq "My new meeting text" + expect(meeting.agenda.text).to eq 'My new meeting text' end end - context "and edit minutes permissions" do + context 'and edit minutes permissions' do let(:permissions) { %i[view_meetings create_meeting_minutes] } - it "can not edit the minutes" do + it 'can not edit the minutes' do visit meeting_path(meeting) - click_link "Minutes" - expect(page).not_to have_test_selector("op-meeting--meeting_minutes", text: "Edit") - expect(page).to have_test_selector("op-meeting--meeting_minutes", - text: "There is currently nothing to display") + click_link 'Minutes' + expect(page).not_to have_test_selector('op-meeting--meeting_minutes', text: 'Edit') + expect(page).to have_test_selector('op-meeting--meeting_minutes', + text: 'There is currently nothing to display') end end end - context "with a locked agenda" do - let!(:agenda) { create(:meeting_agenda, meeting:, text: "foo", locked: true) } + context 'with a locked agenda' do + let!(:agenda) { create(:meeting_agenda, meeting:, text: 'foo', locked: true) } - it "shows the minutes when visiting" do + it 'shows the minutes when visiting' do visit meeting_path(meeting) - expect(page).to have_no_css("h2", text: "Agenda") - expect(page).to have_no_css("#meeting_minutes_text") - expect(page).to have_css("h2", text: "Minutes") + expect(page).to have_no_css('h2', text: 'Agenda') + expect(page).to have_no_css('#meeting_minutes_text') + expect(page).to have_css('h2', text: 'Minutes') end - context "and edit permissions" do + context 'and edit permissions' do let(:permissions) { %i[view_meetings create_meeting_minutes] } let(:field) do TextEditorField.new(page, - "", - selector: test_selector("op-meeting--meeting_minutes")) + '', + selector: test_selector('op-meeting--meeting_minutes')) end - it "can edit the minutes" do + it 'can edit the minutes' do visit meeting_path(meeting) - field.set_value("This is what we talked about") + field.set_value('This is what we talked about') - click_button "Save" + click_button 'Save' expect(page) - .to have_css(".op-uc-container", - text: "This is what we talked about") + .to have_css('.op-uc-container', + text: 'This is what we talked about') end end end diff --git a/modules/meeting/spec/features/structured_meetings/attachment_upload_spec.rb b/modules/meeting/spec/features/structured_meetings/attachment_upload_spec.rb index 6861e51649d9..a1cad1c3e48b 100644 --- a/modules/meeting/spec/features/structured_meetings/attachment_upload_spec.rb +++ b/modules/meeting/spec/features/structured_meetings/attachment_upload_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" -require_relative "../../support/pages/structured_meeting/show" +require 'spec_helper' +require 'features/page_objects/notification' +require_relative '../../support/pages/structured_meeting/show' -RSpec.describe "Upload attachment to meetings", :js do +RSpec.describe 'Upload attachment to meetings', :js do let(:user) do create(:user, member_with_permissions: { project => %i[view_meetings edit_meetings manage_agendas] }) end let(:project) { create(:project) } let(:attachments) { Components::Attachments.new } - let(:image_fixture) { UploadedFile.load_from("spec/fixtures/files/image.png") } - let(:editor) { Components::WysiwygEditor.new "#content", "opce-ckeditor-augmented-textarea" } + let(:image_fixture) { UploadedFile.load_from('spec/fixtures/files/image.png') } + let(:editor) { Components::WysiwygEditor.new '#content', 'opce-ckeditor-augmented-textarea' } let(:wiki_page_content) { project.wiki.pages.first.text } let(:meeting) { create(:structured_meeting, project: project)} @@ -48,22 +48,22 @@ login_as(user) end - it "can upload an image to new and existing meeting agenda item via drag & drop in editor" do + it 'can upload an image to new and existing meeting agenda item via drag & drop in editor' do show_page.visit! show_page.add_agenda_item(save: false) do - click_link_or_button "Notes" + click_link_or_button 'Notes' end # adding an image - editor.drag_attachment image_fixture.path, "Image uploaded the first time" + editor.drag_attachment image_fixture.path, 'Image uploaded the first time' - editor.attachments_list.expect_attached("image.png") + editor.attachments_list.expect_attached('image.png') editor.wait_until_upload_progress_toaster_cleared - click_link_or_button "Save" - expect(page).to have_css("#meeting-agenda-items-list-component img", count: 1) - expect(page).to have_content("Image uploaded the first time") - editor.attachments_list.expect_attached("image.png") + click_link_or_button 'Save' + expect(page).to have_css('#meeting-agenda-items-list-component img', count: 1) + expect(page).to have_content('Image uploaded the first time') + editor.attachments_list.expect_attached('image.png') end end diff --git a/modules/meeting/spec/features/structured_meetings/mobile_structure_meeting_spec.rb b/modules/meeting/spec/features/structured_meetings/mobile_structure_meeting_spec.rb index 780c4d883fd8..f951b91ba4c8 100644 --- a/modules/meeting/spec/features/structured_meetings/mobile_structure_meeting_spec.rb +++ b/modules/meeting/spec/features/structured_meetings/mobile_structure_meeting_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/structured_meeting//mobile/show" +require_relative '../../support/pages/structured_meeting//mobile/show' -RSpec.describe "Structured meetings CRUD", +RSpec.describe 'Structured meetings CRUD', :js, :with_cuprite do include Components::Autocompleter::NgSelectAutocompleteHelpers @@ -38,22 +38,22 @@ shared_let(:project) { create(:project, enabled_module_names: %w[meetings work_package_tracking]) } shared_let(:user) do create(:user, - lastname: "First", + lastname: 'First', member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas close_meeting_agendas view_work_packages] }).tap do |u| - u.pref[:time_zone] = "utc" + u.pref[:time_zone] = 'utc' u.save! end end shared_let(:other_user) do create(:user, - lastname: "Second", + lastname: 'Second', member_with_permissions: { project => %i[view_meetings view_work_packages] }) end shared_let(:no_member_user) do create(:user, - lastname: "Third") + lastname: 'Third') end shared_let(:meeting) do @@ -63,14 +63,14 @@ let(:current_user) { user } let(:show_page) { Pages::StructuredMeeting::Mobile::Show.new(StructuredMeeting.order(id: :asc).last) } - include_context "with mobile screen size" + include_context 'with mobile screen size' before do login_as current_user show_page.visit! end - it "can edit participants of a structured meeting" do + it 'can edit participants of a structured meeting' do expect(page).to have_current_path(show_page.path) show_page.expect_participants(count: 1) @@ -79,10 +79,10 @@ show_page.expect_participant(user, invited: true, attended: false) show_page.expect_participant(other_user, invited: false, attended: false) show_page.expect_available_participants(count: 2) - expect(page).to have_button("Save") + expect(page).to have_button('Save') check(id: "checkbox_invited_#{other_user.id}") - click_button("Save") + click_button('Save') end show_page.expect_participants(count: 2) @@ -95,7 +95,7 @@ show_page.expect_participant(user, invited: true, attended: false, editable: false) show_page.expect_participant(other_user, invited: true, attended: false, editable: false) show_page.expect_available_participants(count: 2) - expect(page).to have_no_button("Save") + expect(page).to have_no_button('Save') end show_page.close_dialog @@ -110,7 +110,7 @@ show_page.expect_participant(user, invited: true, attended: false, editable: false) show_page.expect_participant(other_user, invited: true, attended: false, editable: false) show_page.expect_available_participants(count: 2) - expect(page).to have_no_button("Save") + expect(page).to have_no_button('Save') end end end diff --git a/modules/meeting/spec/features/structured_meetings/structured_meeting_crud_spec.rb b/modules/meeting/spec/features/structured_meetings/structured_meeting_crud_spec.rb index a7c9f9d8f86f..fb33994db521 100644 --- a/modules/meeting/spec/features/structured_meetings/structured_meeting_crud_spec.rb +++ b/modules/meeting/spec/features/structured_meetings/structured_meeting_crud_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/meetings/new" -require_relative "../../support/pages/structured_meeting/show" +require_relative '../../support/pages/meetings/new' +require_relative '../../support/pages/structured_meeting/show' -RSpec.describe "Structured meetings CRUD", +RSpec.describe 'Structured meetings CRUD', :js, :with_cuprite do include Components::Autocompleter::NgSelectAutocompleteHelpers @@ -39,25 +39,25 @@ shared_let(:project) { create(:project, enabled_module_names: %w[meetings work_package_tracking]) } shared_let(:user) do create(:user, - lastname: "First", + lastname: 'First', member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas view_work_packages] }).tap do |u| - u.pref[:time_zone] = "utc" + u.pref[:time_zone] = 'utc' u.save! end end shared_let(:other_user) do create(:user, - lastname: "Second", + lastname: 'Second', member_with_permissions: { project => %i[view_meetings view_work_packages] }) end shared_let(:no_member_user) do create(:user, - lastname: "Third") + lastname: 'Third') end shared_let(:work_package) do - create(:work_package, project:, subject: "Important task") + create(:work_package, project:, subject: 'Important task') end let(:current_user) { user } @@ -69,80 +69,80 @@ login_as current_user new_page.visit! expect(page).to have_current_path(new_page.path) - new_page.set_title "Some title" - new_page.set_type "Dynamic" + new_page.set_title 'Some title' + new_page.set_type 'Dynamic' - new_page.set_start_date "2013-03-28" - new_page.set_start_time "13:30" - new_page.set_duration "1.5" + new_page.set_start_date '2013-03-28' + new_page.set_start_time '13:30' + new_page.set_duration '1.5' new_page.invite(other_user) new_page.click_create end - it "can create a structured meeting and add agenda items" do - show_page.expect_toast(message: "Successful creation") + it 'can create a structured meeting and add agenda items' do + show_page.expect_toast(message: 'Successful creation') # Can add and edit a single item show_page.add_agenda_item do - fill_in "Title", with: "My agenda item" - fill_in "Duration (min)", with: "25" + fill_in 'Title', with: 'My agenda item' + fill_in 'Duration (min)', with: '25' end - show_page.expect_agenda_item title: "My agenda item" + show_page.expect_agenda_item title: 'My agenda item' show_page.cancel_add_form - item = MeetingAgendaItem.find_by(title: "My agenda item") + item = MeetingAgendaItem.find_by(title: 'My agenda item') show_page.edit_agenda_item(item) do - fill_in "Title", with: "Updated title" - click_button "Save" + fill_in 'Title', with: 'Updated title' + click_button 'Save' end - show_page.expect_no_agenda_item title: "My agenda item" + show_page.expect_no_agenda_item title: 'My agenda item' # Can add multiple items show_page.add_agenda_item do - fill_in "Title", with: "First" + fill_in 'Title', with: 'First' end - show_page.expect_agenda_item title: "Updated title" - show_page.expect_agenda_item title: "First" + show_page.expect_agenda_item title: 'Updated title' + show_page.expect_agenda_item title: 'First' show_page.in_agenda_form do - fill_in "Title", with: "Second" - click_button "Save" + fill_in 'Title', with: 'Second' + click_button 'Save' end - show_page.expect_agenda_item title: "Updated title" - show_page.expect_agenda_item title: "First" - show_page.expect_agenda_item title: "Second" + show_page.expect_agenda_item title: 'Updated title' + show_page.expect_agenda_item title: 'First' + show_page.expect_agenda_item title: 'Second' # Can reorder - show_page.assert_agenda_order! "Updated title", "First", "Second" + show_page.assert_agenda_order! 'Updated title', 'First', 'Second' - second = MeetingAgendaItem.find_by!(title: "Second") + second = MeetingAgendaItem.find_by!(title: 'Second') show_page.select_action(second, I18n.t(:label_sort_higher)) - show_page.assert_agenda_order! "Updated title", "Second", "First" + show_page.assert_agenda_order! 'Updated title', 'Second', 'First' - first = MeetingAgendaItem.find_by!(title: "First") + first = MeetingAgendaItem.find_by!(title: 'First') show_page.select_action(first, I18n.t(:label_sort_highest)) - show_page.assert_agenda_order! "First", "Updated title", "Second" + show_page.assert_agenda_order! 'First', 'Updated title', 'Second' # Can edit and cancel with escape show_page.edit_agenda_item(first) do - find_field("Title").send_keys :escape + find_field('Title').send_keys :escape end show_page.expect_item_edit_form(first, visible: false) # Can remove show_page.remove_agenda_item first - show_page.assert_agenda_order! "Updated title", "Second" + show_page.assert_agenda_order! 'Updated title', 'Second' show_page.cancel_add_form # Can link work packages show_page.add_agenda_item(type: WorkPackage) do - select_autocomplete(find_test_selector("op-agenda-items-wp-autocomplete"), - query: "task", - results_selector: "body") + select_autocomplete(find_test_selector('op-agenda-items-wp-autocomplete'), + query: 'task', + results_selector: 'body') end show_page.expect_agenda_link work_package @@ -152,7 +152,7 @@ # Can edit and validate a work package item show_page.edit_agenda_item(wp_item) do show_page.clear_item_edit_work_package_title - click_button "Save" + click_button 'Save' end show_page.expect_item_edit_field_error(wp_item, "Work package can't be blank.") @@ -160,54 +160,54 @@ # Keeping the editing state of an agenda item while modifying other items show_page.edit_agenda_item(second) do - fill_in "Title", with: "Second edited" + fill_in 'Title', with: 'Second edited' end show_page.select_action(item, I18n.t(:label_sort_lowest)) show_page.cancel_add_form show_page.add_agenda_item do - fill_in "Title", with: "My agenda item" - fill_in "Duration in minutes", with: "25" + fill_in 'Title', with: 'My agenda item' + fill_in 'Duration in minutes', with: '25' end - show_page.expect_agenda_item title: "My agenda item" - my_item = MeetingAgendaItem.find_by!(title: "My agenda item") + show_page.expect_agenda_item title: 'My agenda item' + my_item = MeetingAgendaItem.find_by!(title: 'My agenda item') show_page.edit_agenda_item(my_item) do - fill_in "Title", with: "My agenda item edited" - click_button "Save" + fill_in 'Title', with: 'My agenda item edited' + click_button 'Save' end show_page.remove_agenda_item my_item show_page.expect_item_edit_form(second) - show_page.expect_item_edit_title(second, "Second edited") + show_page.expect_item_edit_title(second, 'Second edited') show_page.cancel_edit_form(second) # user can see actions - expect(page).to have_css("#meeting-agenda-items-new-button-component") - expect(page).to have_test_selector("op-meeting-agenda-actions", count: 3) + expect(page).to have_css('#meeting-agenda-items-new-button-component') + expect(page).to have_test_selector('op-meeting-agenda-actions', count: 3) # other_use can view, but not edit login_as other_user show_page.visit! - expect(page).to have_no_css("#meeting-agenda-items-new-button-component") - expect(page).not_to have_test_selector("op-meeting-agenda-actions") + expect(page).to have_no_css('#meeting-agenda-items-new-button-component') + expect(page).not_to have_test_selector('op-meeting-agenda-actions') end - it "can delete a meeting and get back to the index page" do - click_button("op-meetings-header-action-trigger") + it 'can delete a meeting and get back to the index page' do + click_button('op-meetings-header-action-trigger') - accept_confirm(I18n.t("text_are_you_sure")) do - click_button "Delete meeting" + accept_confirm(I18n.t('text_are_you_sure')) do + click_button 'Delete meeting' end expect(page).to have_current_path project_meetings_path(project) end - context "when exporting as ICS" do + context 'when exporting as ICS' do before do @download_list = DownloadList.new end @@ -218,8 +218,8 @@ subject { @download_list.refresh_from(page).latest_download.to_s } - it "can export the meeting as ICS" do - click_button("op-meetings-header-action-trigger") + it 'can export the meeting as ICS' do + click_button('op-meetings-header-action-trigger') click_link I18n.t(:label_icalendar_download) @@ -227,73 +227,73 @@ end end - it "shows an error toast trying to update an outdated item" do - show_page.expect_toast(message: "Successful creation") + it 'shows an error toast trying to update an outdated item' do + show_page.expect_toast(message: 'Successful creation') # Can add and edit a single item show_page.add_agenda_item do - fill_in "Title", with: "My agenda item" - fill_in "Duration (min)", with: "25" + fill_in 'Title', with: 'My agenda item' + fill_in 'Duration (min)', with: '25' end - show_page.expect_agenda_item title: "My agenda item" + show_page.expect_agenda_item title: 'My agenda item' show_page.cancel_add_form - item = MeetingAgendaItem.find_by!(title: "My agenda item") + item = MeetingAgendaItem.find_by!(title: 'My agenda item') show_page.edit_agenda_item(item) do # Side effect: update the item - item.update!(title: "Updated title") + item.update!(title: 'Updated title') - fill_in "Title", with: "My agenda item edited" - click_button "Save" + fill_in 'Title', with: 'My agenda item edited' + click_button 'Save' end - expect(page).to have_css(".flash", text: I18n.t("activerecord.errors.messages.error_conflict")) + expect(page).to have_css('.flash', text: I18n.t('activerecord.errors.messages.error_conflict')) end - it "can copy the meeting" do - show_page.expect_toast(message: "Successful creation") + it 'can copy the meeting' do + show_page.expect_toast(message: 'Successful creation') # Can add and edit a single item show_page.add_agenda_item do - fill_in "Title", with: "My agenda item" - fill_in "Duration (min)", with: "25" + fill_in 'Title', with: 'My agenda item' + fill_in 'Duration (min)', with: '25' end - show_page.expect_agenda_item title: "My agenda item" + show_page.expect_agenda_item title: 'My agenda item' show_page.cancel_add_form - click_button("op-meetings-header-action-trigger") - click_link "Copy" + click_button('op-meetings-header-action-trigger') + click_link 'Copy' expect(page).to have_current_path "/meetings/#{meeting.id}/copy" - click_button "Create" + click_button 'Create' - show_page.expect_agenda_item title: "My agenda item" + show_page.expect_agenda_item title: 'My agenda item' new_meeting = StructuredMeeting.reorder(id: :asc).last expect(page).to have_current_path "/meetings/#{new_meeting.id}" end - context "with a work package reference to another" do + context 'with a work package reference to another' do let!(:meeting) { create(:structured_meeting, project:, author: current_user) } let!(:other_project) { create(:project) } - let!(:other_wp) { create(:work_package, project: other_project, author: current_user, subject: "Private task") } + let!(:other_wp) { create(:work_package, project: other_project, author: current_user, subject: 'Private task') } let!(:role) { create(:project_role, permissions: %w[view_work_packages]) } let!(:membership) { create(:member, principal: user, project: other_project, roles: [role]) } let!(:agenda_item) { create(:wp_meeting_agenda_item, meeting:, author: current_user, work_package: other_wp) } let(:show_page) { Pages::StructuredMeeting::Show.new(meeting) } - it "shows correctly for author, but returns an unresolved reference for the second user" do + it 'shows correctly for author, but returns an unresolved reference for the second user' do show_page.visit! show_page.expect_agenda_link agenda_item - expect(page).to have_text "Private task" + expect(page).to have_text 'Private task' login_as other_user show_page.visit! show_page.expect_undisclosed_agenda_link agenda_item - expect(page).to have_no_text "Private task" + expect(page).to have_no_text 'Private task' end end end diff --git a/modules/meeting/spec/features/structured_meetings/work_package_meetings_tab_spec.rb b/modules/meeting/spec/features/structured_meetings/work_package_meetings_tab_spec.rb index 0f1fb07fb763..f817188f8ccf 100644 --- a/modules/meeting/spec/features/structured_meetings/work_package_meetings_tab_spec.rb +++ b/modules/meeting/spec/features/structured_meetings/work_package_meetings_tab_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../../support/pages/work_package_meetings_tab" +require 'spec_helper' +require_relative '../../support/pages/work_package_meetings_tab' -RSpec.describe "Open the Meetings tab", :js do +RSpec.describe 'Open the Meetings tab', :js do shared_let(:project) { create(:project) } - shared_let(:work_package) { create(:work_package, project:, subject: "A test work_package") } + shared_let(:work_package) { create(:work_package, project:, subject: 'A test work_package') } let(:user) do create(:user, @@ -47,33 +47,33 @@ let(:meetings_tab) { Pages::MeetingsTab.new(work_package.id) } let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } - let(:meetings_tab_element) { find(".op-tab-row--link_selected", text: "MEETINGS") } + let(:meetings_tab_element) { find('.op-tab-row--link_selected', text: 'MEETINGS') } shared_context "a meetings tab" do before do login_as(user) end - it "shows the meetings tab when the user is allowed to see it" do + it 'shows the meetings tab when the user is allowed to see it' do work_package_page.visit! - work_package_page.switch_to_tab(tab: "meetings") + work_package_page.switch_to_tab(tab: 'meetings') meetings_tab.expect_tab_content_rendered end - context "when the user does not have the permissions to see the meetings tab" do + context 'when the user does not have the permissions to see the meetings tab' do let(:role) do create(:project_role, permissions: %i(view_work_packages)) end - it "does not show the meetings tab" do + it 'does not show the meetings tab' do work_package_page.visit! meetings_tab.expect_tab_not_present end - context "when the user has permission in another project" do + context 'when the user has permission in another project' do let(:other_project) { create(:project, enabled_module_names: %w[meetings]) } let(:user) do @@ -84,7 +84,7 @@ }) end - it "does show the tab" do + it 'does show the tab' do work_package_page.visit! meetings_tab.expect_tab_present @@ -92,7 +92,7 @@ end end - context "when the user has the permission to see the tab, but the work package is linked in two projects" do + context 'when the user has the permission to see the tab, but the work package is linked in two projects' do let(:other_project) { create(:project, enabled_module_names: %w[meetings]) } let!(:visible_meeting) { create(:structured_meeting, project:) } let!(:invisible_meeting) { create(:structured_meeting, project: other_project) } @@ -110,7 +110,7 @@ permissions: %i(view_work_packages view_meetings)) end - it "shows the one visible meeting" do + it 'shows the one visible meeting' do work_package_page.visit! switch_to_meetings_tab @@ -128,19 +128,19 @@ end end - context "when the meetings module is not enabled for the project" do + context 'when the meetings module is not enabled for the project' do before do - project.enabled_module_names = ["work_package_tracking"] + project.enabled_module_names = ['work_package_tracking'] project.save! end - it "does not show the meetings tab" do + it 'does not show the meetings tab' do work_package_page.visit! meetings_tab.expect_tab_not_present end - context "when the user has permission to view in another project" do + context 'when the user has permission to view in another project' do let(:other_project) { create(:project, enabled_module_names: %w[meetings]) } let(:user) do @@ -151,7 +151,7 @@ }) end - it "does show the tab, but does not show the button" do + it 'does show the tab, but does not show the button' do work_package_page.visit! meetings_tab.expect_tab_present @@ -160,7 +160,7 @@ end end - context "when the user has permission to manage in another project" do + context 'when the user has permission to manage in another project' do let(:other_project) { create(:project, enabled_module_names: %w[meetings]) } let(:user) do @@ -171,7 +171,7 @@ }) end - it "does show the tab and shows the add button" do + it 'does show the tab and shows the add button' do work_package_page.visit! meetings_tab.expect_tab_present @@ -181,30 +181,30 @@ end end - context "when the work_package is not referenced in an upcoming meeting" do - it "shows an empty message within the upcoming meetings section" do + context 'when the work_package is not referenced in an upcoming meeting' do + it 'shows an empty message within the upcoming meetings section' do work_package_page.visit! switch_to_meetings_tab meetings_tab.expect_upcoming_counter_to_be(0) - expect(page).to have_content("This work package is not scheduled in an upcoming meeting agenda yet.") + expect(page).to have_content('This work package is not scheduled in an upcoming meeting agenda yet.') end end - context "when the work_package is not referenced in a past meeting" do - it "shows an empty message within the past meetings section" do + context 'when the work_package is not referenced in a past meeting' do + it 'shows an empty message within the past meetings section' do work_package_page.visit! switch_to_meetings_tab meetings_tab.expect_past_counter_to_be(0) meetings_tab.switch_to_past_meetings_section - expect(page).to have_content("This work package was not mentioned in a past meeting.") + expect(page).to have_content('This work package was not mentioned in a past meeting.') end end - context "when the work_package is already referenced in upcoming meetings" do + context 'when the work_package is already referenced in upcoming meetings' do let!(:first_meeting) { create(:structured_meeting, project:) } let!(:second_meeting) { create(:structured_meeting, project:) } @@ -220,7 +220,7 @@ notes: "A very important note in the second meeting!") end - it "shows the meeting agenda items in the upcoming meetings section grouped by meeting" do + it 'shows the meeting agenda items in the upcoming meetings section grouped by meeting' do work_package_page.visit! switch_to_meetings_tab @@ -240,7 +240,7 @@ end end - context "when the work_package was already referenced in past meetings" do + context 'when the work_package was already referenced in past meetings' do let!(:first_past_meeting) { create(:structured_meeting, project:, start_time: Date.yesterday - 10.hours) } let!(:second_past_meeting) { create(:structured_meeting, project:, start_time: Date.yesterday - 10.hours) } @@ -256,7 +256,7 @@ notes: "A very important note in the second meeting!") end - it "shows the meeting agenda items in the past meetings section grouped by meeting" do + it 'shows the meeting agenda items in the past meetings section grouped by meeting' do work_package_page.visit! switch_to_meetings_tab @@ -278,15 +278,15 @@ end end - context "when user is allowed to edit meetings" do - it "shows the add to meeting button" do + context 'when user is allowed to edit meetings' do + it 'shows the add to meeting button' do work_package_page.visit! switch_to_meetings_tab meetings_tab.expect_add_to_meeting_button_present end - it "opens the add to meeting dialog when clicking the add to meeting button" do + it 'opens the add to meeting dialog when clicking the add to meeting button' do work_package_page.visit! switch_to_meetings_tab @@ -295,16 +295,16 @@ meetings_tab.expect_add_to_meeting_dialog_shown end - context "when open, upcoming meetings are visible for the user" do + context 'when open, upcoming meetings are visible for the user' do shared_let(:past_meeting) { create(:structured_meeting, project:, start_time: Date.yesterday - 10.hours) } shared_let(:first_upcoming_meeting) { create(:structured_meeting, project:) } shared_let(:second_upcoming_meeting) { create(:structured_meeting, project:) } shared_let(:closed_upcoming_meeting) { create(:structured_meeting, project:, state: :closed) } shared_let(:ongoing_meeting) do - create(:structured_meeting, title: "Ongoing", project:, start_time: 1.hour.ago, duration: 4.0) + create(:structured_meeting, title: 'Ongoing', project:, start_time: 1.hour.ago, duration: 4.0) end - it "enables the user to add the work package to multiple open, upcoming meetings" do + it 'enables the user to add the work package to multiple open, upcoming meetings' do work_package_page.visit! switch_to_meetings_tab @@ -314,30 +314,30 @@ meetings_tab.fill_and_submit_meeting_dialog( first_upcoming_meeting, - "A very important note added from the meetings tab to the first meeting!" + 'A very important note added from the meetings tab to the first meeting!' ) meetings_tab.expect_upcoming_counter_to_be(1) page.within_test_selector("op-meeting-container-#{first_upcoming_meeting.id}") do - expect(page).to have_content("A very important note added from the meetings tab to the first meeting!") + expect(page).to have_content('A very important note added from the meetings tab to the first meeting!') end meetings_tab.open_add_to_meeting_dialog meetings_tab.fill_and_submit_meeting_dialog( second_upcoming_meeting, - "A very important note added from the meetings tab to the second meeting!" + 'A very important note added from the meetings tab to the second meeting!' ) meetings_tab.expect_upcoming_counter_to_be(2) page.within_test_selector("op-meeting-container-#{second_upcoming_meeting.id}") do - expect(page).to have_content("A very important note added from the meetings tab to the second meeting!") + expect(page).to have_content('A very important note added from the meetings tab to the second meeting!') end end - it "allows the user to select ongoing meetings" do + it 'allows the user to select ongoing meetings' do work_package_page.visit! switch_to_meetings_tab @@ -345,50 +345,50 @@ meetings_tab.fill_and_submit_meeting_dialog( ongoing_meeting, - "Some notes to be added" + 'Some notes to be added' ) meetings_tab.expect_upcoming_counter_to_be(1) page.within_test_selector("op-meeting-container-#{ongoing_meeting.id}") do - expect(page).to have_content("Some notes to be added") + expect(page).to have_content('Some notes to be added') end end - it "does not enable the user to select a past meeting" do + it 'does not enable the user to select a past meeting' do work_package_page.visit! switch_to_meetings_tab meetings_tab.open_add_to_meeting_dialog - fill_in("meeting_agenda_item_meeting_id", with: past_meeting.title) - expect(page).to have_no_css(".ng-option-marked", text: past_meeting.title) + fill_in('meeting_agenda_item_meeting_id', with: past_meeting.title) + expect(page).to have_no_css('.ng-option-marked', text: past_meeting.title) end - it "does not enable the user to select a closed, upcoming meeting" do + it 'does not enable the user to select a closed, upcoming meeting' do work_package_page.visit! switch_to_meetings_tab meetings_tab.open_add_to_meeting_dialog - fill_in("meeting_agenda_item_meeting_id", with: closed_upcoming_meeting.title) - expect(page).to have_no_css(".ng-option-marked", text: closed_upcoming_meeting.title) + fill_in('meeting_agenda_item_meeting_id', with: closed_upcoming_meeting.title) + expect(page).to have_no_css('.ng-option-marked', text: closed_upcoming_meeting.title) end - it "requires a meeting to be selected" do + it 'requires a meeting to be selected' do work_package_page.visit! switch_to_meetings_tab meetings_tab.open_add_to_meeting_dialog - click_button("Save") + click_button('Save') - expect(page).to have_content("Meeting can't be blank") + expect(page).to have_content('Meeting can\'t be blank') end end end - context "when user is not allowed to edit meetings" do + context 'when user is not allowed to edit meetings' do let(:restricted_role) do create(:project_role, permissions: %i(view_work_packages @@ -399,7 +399,7 @@ member_with_roles: { project => restricted_role }) end - it "does not show the add to meeting button" do + it 'does not show the add to meeting button' do work_package_page.visit! switch_to_meetings_tab @@ -408,20 +408,20 @@ end end - describe "work package full view" do + describe 'work package full view' do let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "a meetings tab" + it_behaves_like 'a meetings tab' end - describe "work package split view" do + describe 'work package split view' do let(:work_package_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "a meetings tab" + it_behaves_like 'a meetings tab' end def switch_to_meetings_tab - work_package_page.switch_to_tab(tab: "meetings") + work_package_page.switch_to_tab(tab: 'meetings') meetings_tab.expect_tab_content_rendered # wait for the tab to be rendered end end diff --git a/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb b/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb index 1a3a7ed3858f..bf376f6b1932 100644 --- a/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb +++ b/modules/meeting/spec/lib/api/v3/meetings/meeting_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Meetings::MeetingRepresenter do include API::V3::Utilities::PathHelper @@ -42,59 +42,59 @@ let(:meeting) do create(:meeting, author: user, - location: "https://foo.example.com", + location: 'https://foo.example.com', project:) end let(:representer) { described_class.new(meeting, current_user: user) } - describe "generation" do + describe 'generation' do subject(:generated) { representer.to_json } - describe "self link" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'self link' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.meeting(meeting.id) } let(:title) { meeting.title } end end - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:link) { :attachments } let(:href) { api_v3_paths.attachments_by_meeting meeting.id } end - it_behaves_like "has a titled link" do - let(:link) { "author" } + it_behaves_like 'has a titled link' do + let(:link) { 'author' } let(:href) { api_v3_paths.user(user.id) } let(:title) { user.name } end - it_behaves_like "has a titled link" do - let(:link) { "project" } + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project(project.id) } let(:title) { project.name } end - it_behaves_like "has an untitled action link" do + it_behaves_like 'has an untitled action link' do let(:link) { :addAttachment } let(:href) { api_v3_paths.attachments_by_meeting meeting.id } let(:method) { :post } let(:permission) { :edit_meetings } end - it "describes the object", :aggregate_failures do - expect(subject).to be_json_eql("Meeting".to_json).at_path("_type") - expect(subject).to be_json_eql(meeting.id.to_json).at_path("id") - expect(subject).to be_json_eql(meeting.title.to_json).at_path("title") - expect(subject).to be_json_eql(meeting.lock_version.to_json).at_path("lockVersion") - expect(subject).to be_json_eql(meeting.start_time.utc.iso8601(3).to_json).at_path("startTime") - expect(subject).to be_json_eql(meeting.end_time.utc.iso8601(3).to_json).at_path("endTime") - expect(subject).to be_json_eql(meeting.duration.to_json).at_path("duration") - expect(subject).to be_json_eql(meeting.location.to_json).at_path("location") + it 'describes the object', :aggregate_failures do + expect(subject).to be_json_eql('Meeting'.to_json).at_path('_type') + expect(subject).to be_json_eql(meeting.id.to_json).at_path('id') + expect(subject).to be_json_eql(meeting.title.to_json).at_path('title') + expect(subject).to be_json_eql(meeting.lock_version.to_json).at_path('lockVersion') + expect(subject).to be_json_eql(meeting.start_time.utc.iso8601(3).to_json).at_path('startTime') + expect(subject).to be_json_eql(meeting.end_time.utc.iso8601(3).to_json).at_path('endTime') + expect(subject).to be_json_eql(meeting.duration.to_json).at_path('duration') + expect(subject).to be_json_eql(meeting.location.to_json).at_path('location') - expect(subject).to be_json_eql(meeting.created_at.utc.iso8601(3).to_json).at_path("createdAt") - expect(subject).to be_json_eql(meeting.updated_at.utc.iso8601(3).to_json).at_path("updatedAt") + expect(subject).to be_json_eql(meeting.created_at.utc.iso8601(3).to_json).at_path('createdAt') + expect(subject).to be_json_eql(meeting.updated_at.utc.iso8601(3).to_json).at_path('updatedAt') end end end diff --git a/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb b/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb index 920b94ef28ae..7f555949b947 100644 --- a/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb +++ b/modules/meeting/spec/lib/api/v3/utilities/path_helper_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::PathHelper do let(:helper) { Class.new.tap { |c| c.extend(described_class) }.api_v3_paths } - describe "#meeting" do + describe '#meeting' do subject { helper.meeting 42 } - it { is_expected.to eql("/api/v3/meetings/42") } + it { is_expected.to eql('/api/v3/meetings/42') } end - describe "#attachments_by_meeting" do + describe '#attachments_by_meeting' do subject { helper.attachments_by_meeting 42 } - it { is_expected.to eql("/api/v3/meetings/42/attachments") } + it { is_expected.to eql('/api/v3/meetings/42/attachments') } end end diff --git a/modules/meeting/spec/lib/open_project/markdown_formatting_spec.rb b/modules/meeting/spec/lib/open_project/markdown_formatting_spec.rb index b885c0d6383c..65240c46440a 100644 --- a/modules/meeting/spec/lib/open_project/markdown_formatting_spec.rb +++ b/modules/meeting/spec/lib/open_project/markdown_formatting_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::TextFormatting, - "Meeting links" do + 'Meeting links' do include ActionView::Helpers::UrlHelper # soft-dependency include ActionView::Context include OpenProject::StaticRouting::UrlHelpers @@ -43,7 +43,7 @@ def controller end shared_let(:meeting) do - create(:meeting, project:, title: "Monthly coordination") + create(:meeting, project:, title: 'Monthly coordination') end subject do @@ -64,7 +64,7 @@ def controller TEXT end - context "when visible" do + context 'when visible' do let(:role) { create(:project_role, permissions: %i[view_meetings view_project]) } let(:user) { create(:user, member_with_roles: { project => role }) } @@ -80,19 +80,19 @@ def controller let(:meeting_link) do link_to( - "Monthly coordination", - { controller: "/meetings", action: "show", id: meeting.id, only_path: true }, - class: "meeting op-uc-link", - target: "_top" + 'Monthly coordination', + { controller: '/meetings', action: 'show', id: meeting.id, only_path: true }, + class: 'meeting op-uc-link', + target: '_top' ) end - it "renders the links" do + it 'renders the links' do expect(subject).to be_html_eql(expected) end end - context "when not visible" do + context 'when not visible' do let(:user) { create(:user) } let(:expected) do @@ -105,7 +105,7 @@ def controller HTML end - it "renders the raw text" do + it 'renders the raw text' do expect(subject).to be_html_eql(expected) end end diff --git a/modules/meeting/spec/mailers/meeting_mailer_spec.rb b/modules/meeting/spec/mailers/meeting_mailer_spec.rb index c7119eb91565..e50c7ee9607a 100644 --- a/modules/meeting/spec/mailers/meeting_mailer_spec.rb +++ b/modules/meeting/spec/mailers/meeting_mailer_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../spec_helper" +require_relative '../spec_helper' RSpec.describe MeetingMailer do shared_let(:role) { create(:project_role, permissions: [:view_meetings]) } - shared_let(:project) { create(:project, name: "My project") } + shared_let(:project) { create(:project, name: 'My project') } shared_let(:author) do create(:user, member_with_roles: { project => role }, - preferences: { time_zone: "Europe/Berlin" }) + preferences: { time_zone: 'Europe/Berlin' }) end shared_let(:watcher1) { create(:user, member_with_roles: { project => role }) } shared_let(:watcher2) { create(:user, member_with_roles: { project => role }) } @@ -56,7 +56,7 @@ meeting.save! end - describe "invited" do + describe 'invited' do let(:mail) { described_class.invited(meeting, watcher1, author) } # this is needed to call module functions from Redmine::I18n let(:i18n) do @@ -66,67 +66,67 @@ end end - it "renders the headers" do + it 'renders the headers' do expect(mail.subject).to include(meeting.project.name) expect(mail.subject).to include(meeting.title) expect(mail.to).to contain_exactly(watcher1.mail) expect(mail.from).to eq([Setting.mail_from]) end - it "renders the text body" do + it 'renders the text body' do User.execute_as(watcher1) do check_meeting_mail_content mail.text_part.body end end - it "renders the html body" do + it 'renders the html body' do User.execute_as(watcher1) do check_meeting_mail_content mail.html_part.body end end - context "with a recipient with another time zone" do - let!(:preference) { create(:user_preference, user: watcher1, time_zone: "Asia/Tokyo") } + context 'with a recipient with another time zone' do + let!(:preference) { create(:user_preference, user: watcher1, time_zone: 'Asia/Tokyo') } - it "renders the mail with the correcet locale" do - expect(mail.text_part.body).to include("Tokyo") - expect(mail.text_part.body).to include("GMT+09:00") - expect(mail.html_part.body).to include("Tokyo") - expect(mail.html_part.body).to include("GMT+09:00") + it 'renders the mail with the correcet locale' do + expect(mail.text_part.body).to include('Tokyo') + expect(mail.text_part.body).to include('GMT+09:00') + expect(mail.html_part.body).to include('Tokyo') + expect(mail.html_part.body).to include('GMT+09:00') expect(mail.to).to contain_exactly(watcher1.mail) end end - context "when the meeting time results in another date" do + context 'when the meeting time results in another date' do let(:meeting) do create(:meeting, author:, project:, - start_time: "2021-11-09T23:00:00 +0100".to_datetime.utc) + start_time: '2021-11-09T23:00:00 +0100'.to_datetime.utc) end - describe "it renders november 9th for Berlin zone" do + describe 'it renders november 9th for Berlin zone' do let(:mail) { described_class.invited(meeting, author, author) } - it "renders the mail with the correct locale" do - expect(mail.html_part.body).to include("11/09/2021 11:00 PM") - expect(mail.html_part.body).to include("12:00 AM (GMT+01:00) Europe/Berlin") - expect(mail.text_part.body).to include("11/09/2021 11:00 PM-12:00 AM (GMT+01:00) Europe/Berlin") + it 'renders the mail with the correct locale' do + expect(mail.html_part.body).to include('11/09/2021 11:00 PM') + expect(mail.html_part.body).to include('12:00 AM (GMT+01:00) Europe/Berlin') + expect(mail.text_part.body).to include('11/09/2021 11:00 PM-12:00 AM (GMT+01:00) Europe/Berlin') expect(mail.to).to contain_exactly(author.mail) end end - describe "it renders november 10th for Tokyo zone" do - let!(:preference) { create(:user_preference, user: watcher1, time_zone: "Asia/Tokyo") } + describe 'it renders november 10th for Tokyo zone' do + let!(:preference) { create(:user_preference, user: watcher1, time_zone: 'Asia/Tokyo') } let(:mail) { described_class.invited(meeting, watcher1, author) } - it "renders the mail with the correct locale" do - expect(mail.html_part.body).to include("11/10/2021 07:00 AM") - expect(mail.html_part.body).to include("08:00 AM (GMT+09:00) Asia/Tokyo") + it 'renders the mail with the correct locale' do + expect(mail.html_part.body).to include('11/10/2021 07:00 AM') + expect(mail.html_part.body).to include('08:00 AM (GMT+09:00) Asia/Tokyo') - expect(mail.text_part.body).to include("11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo") + expect(mail.text_part.body).to include('11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo') expect(mail.to).to contain_exactly(watcher1.mail) end @@ -134,114 +134,114 @@ end end - describe "icalendar" do + describe 'icalendar' do let(:meeting) do create(:meeting, author:, project:, - title: "Important meeting", - location: "https://example.com/meet/important-meeting", + title: 'Important meeting', + location: 'https://example.com/meet/important-meeting', start_time: "2021-01-19T10:00:00Z".to_time(:utc), duration: 1.0) end let(:mail) { described_class.icalendar_notification(meeting, author, author) } - it "renders the headers" do + it 'renders the headers' do expect(mail.subject).to include(meeting.project.name) expect(mail.subject).to include(meeting.title) expect(mail.to).to contain_exactly(author.mail) expect(mail.from).to eq([Setting.mail_from]) end - describe "text body" do + describe 'text body' do subject(:body) { mail.text_part.body } - it "renders the text body" do + it 'renders the text body' do expect(body).to include(meeting.project.name) expect(body).to include(meeting.title) expect(body).to include(meeting.location) - expect(body).to include("01/19/2021 11:00 AM-12:00 PM (GMT+01:00) Europe/Berlin") + expect(body).to include('01/19/2021 11:00 AM-12:00 PM (GMT+01:00) Europe/Berlin') expect(body).to include(meeting.participants[0].name) expect(body).to include(meeting.participants[1].name) end end - describe "renders the html body" do + describe 'renders the html body' do subject(:body) { mail.html_part.body } - it "renders the text body" do + it 'renders the text body' do expect(body).to include(meeting.project.name) expect(body).to include(meeting.title) expect(body).to include(meeting.location) - expect(body).to include("01/19/2021 11:00 AM") - expect(body).to include("12:00 PM (GMT+01:00) Europe/Berlin") + expect(body).to include('01/19/2021 11:00 AM') + expect(body).to include('12:00 PM (GMT+01:00) Europe/Berlin') expect(body).to include(meeting.participants[0].name) expect(body).to include(meeting.participants[1].name) end end - describe "renders the calendar entry" do + describe 'renders the calendar entry' do let(:ical) { mail.parts.detect { |x| !x.multipart? } } let(:parsed) { Icalendar::Event.parse(ical.body.raw_source) } let(:entry) { parsed.first } - it "renders the calendar entry" do + it 'renders the calendar entry' do expect(parsed).to be_a Array expect(parsed.length).to eq 1 expect(entry.dtstart.utc).to eq meeting.start_time expect(entry.dtend.utc).to eq meeting.start_time + 1.hour - expect(entry.summary).to eq "[My project] Important meeting" + expect(entry.summary).to eq '[My project] Important meeting' expect(entry.description).to eq "[My project] Meeting: Important meeting" expect(entry.location).to eq(meeting.location.presence) end - it "has the correct time matching the timezone" do + it 'has the correct time matching the timezone' do expect(entry.dtstart).to eq "2021-01-19T10:00:00Z".to_time(:utc).in_time_zone("Europe/Berlin") expect(entry.dtend).to eq ("2021-01-19T10:00:00Z".to_time(:utc) + 1.hour).in_time_zone("Europe/Berlin") end end - context "with a recipient with another time zone" do - let!(:preference) { create(:user_preference, user: watcher1, time_zone: "Asia/Tokyo") } + context 'with a recipient with another time zone' do + let!(:preference) { create(:user_preference, user: watcher1, time_zone: 'Asia/Tokyo') } let(:mail) { described_class.icalendar_notification(meeting, watcher1, author) } - it "renders the mail with the correct locale" do - expect(mail.text_part.body).to include("01/19/2021 07:00 PM-08:00 PM (GMT+09:00) Asia/Tokyo") - expect(mail.html_part.body).to include("01/19/2021 07:00 PM") - expect(mail.html_part.body).to include("08:00 PM (GMT+09:00) Asia/Tokyo") + it 'renders the mail with the correct locale' do + expect(mail.text_part.body).to include('01/19/2021 07:00 PM-08:00 PM (GMT+09:00) Asia/Tokyo') + expect(mail.html_part.body).to include('01/19/2021 07:00 PM') + expect(mail.html_part.body).to include('08:00 PM (GMT+09:00) Asia/Tokyo') expect(mail.to).to contain_exactly(watcher1.mail) end end - context "when the meeting time results in another date" do + context 'when the meeting time results in another date' do let(:meeting) do create(:meeting, author:, project:, - start_time: "2021-11-09T23:00:00 +0100".to_datetime.utc) + start_time: '2021-11-09T23:00:00 +0100'.to_datetime.utc) end - describe "it renders november 9th for Berlin zone" do + describe 'it renders november 9th for Berlin zone' do let(:mail) { described_class.icalendar_notification(meeting, author, author) } - it "renders the mail with the correct locale" do - expect(mail.text_part.body).to include("11/09/2021 11:00 PM-12:00 AM (GMT+01:00) Europe/Berlin") - expect(mail.html_part.body).to include("11/09/2021 11:00 PM") - expect(mail.html_part.body).to include("12:00 AM (GMT+01:00) Europe/Berlin") + it 'renders the mail with the correct locale' do + expect(mail.text_part.body).to include('11/09/2021 11:00 PM-12:00 AM (GMT+01:00) Europe/Berlin') + expect(mail.html_part.body).to include('11/09/2021 11:00 PM') + expect(mail.html_part.body).to include('12:00 AM (GMT+01:00) Europe/Berlin') expect(mail.to).to contain_exactly(author.mail) end end - describe "it renders november 10th for Tokyo zone" do + describe 'it renders november 10th for Tokyo zone' do let(:mail) { described_class.icalendar_notification(meeting, watcher1, author) } - let!(:preference) { create(:user_preference, user: watcher1, time_zone: "Asia/Tokyo") } + let!(:preference) { create(:user_preference, user: watcher1, time_zone: 'Asia/Tokyo') } - it "renders the mail with the correct locale" do - expect(mail.text_part.body).to include("11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo") - expect(mail.html_part.body).to include("11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo") + it 'renders the mail with the correct locale' do + expect(mail.text_part.body).to include('11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo') + expect(mail.html_part.body).to include('11/10/2021 07:00 AM-08:00 AM (GMT+09:00) Asia/Tokyo') expect(mail.to).to contain_exactly(watcher1.mail) end diff --git a/modules/meeting/spec/models/meeting_acts_as_journalized_spec.rb b/modules/meeting/spec/models/meeting_acts_as_journalized_spec.rb index 493c2b158ae7..3b3dc5f34c00 100644 --- a/modules/meeting/spec/models/meeting_acts_as_journalized_spec.rb +++ b/modules/meeting/spec/models/meeting_acts_as_journalized_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Meeting do shared_let (:user) { create(:user) } @@ -38,59 +38,59 @@ end end - describe "#journal" do - context "for meeting creation" do + describe '#journal' do + context 'for meeting creation' do it { expect(Journal.for_meeting.count).to eq(1) } - it "has a journal entry" do + it 'has a journal entry' do expect(Journal.for_meeting.first.journable).to eq(meeting) end - it "notes the changes to title" do + it 'notes the changes to title' do expect(meeting.last_journal.details[:title]) .to contain_exactly(nil, meeting.title) end - it "notes the changes to project" do + it 'notes the changes to project' do expect(meeting.last_journal.details[:project_id]) .to contain_exactly(nil, meeting.project_id) end - it "notes the location" do + it 'notes the location' do expect(meeting.last_journal.details[:location]) .to contain_exactly(nil, meeting.location) end - it "notes the start time" do + it 'notes the start time' do expect(meeting.last_journal.details[:start_time]) .to contain_exactly(nil, meeting.start_time) end - it "notes the duration" do + it 'notes the duration' do expect(meeting.last_journal.details[:duration]) .to contain_exactly(nil, meeting.duration) end - it "has the timestamp of the meeting update time for created_at" do + it 'has the timestamp of the meeting update time for created_at' do expect(meeting.last_journal.created_at) .to eql(meeting.reload.updated_at) end - it "has the updated_at of the meeting as the lower bound for validity_period and no upper bound" do + it 'has the updated_at of the meeting as the lower bound for validity_period and no upper bound' do expect(meeting.last_journal.validity_period) .to eql(meeting.reload.updated_at...) end end - context "when nothing is changed" do + context 'when nothing is changed' do it { expect { meeting.save! }.not_to change(Journal, :count) } - it "does not update the updated_at time of the work package" do + it 'does not update the updated_at time of the work package' do expect { meeting.save! }.not_to change(meeting, :updated_at) end end - describe "agenda_items" do + describe 'agenda_items' do let(:work_package) { nil } let(:agenda_item_attributes) { {} } let(:agenda_item) { meeting.agenda_items.first } @@ -101,32 +101,32 @@ meeting.save end - context "for a new agenda item within aggregation time" do + context 'for a new agenda item within aggregation time' do it { expect(meeting.journals.count).to eq(1) } it { expect(agenda_item_journals.count).to eq(1) } it { expect(agenda_item_journals.last).to have_attributes agenda_item.attributes.slice( - "author_id", "title", "notes", "position", "duration_in_minutes", - "start_time", "end_time", "work_package_id", "item_type" + 'author_id', 'title', 'notes', 'position', 'duration_in_minutes', + 'start_time', 'end_time', 'work_package_id', 'item_type' ) } end - context "for a new agenda item outside aggregation time", with_settings: { journal_aggregation_time_minutes: 0 } do + context 'for a new agenda item outside aggregation time', with_settings: { journal_aggregation_time_minutes: 0 } do it { expect(meeting.journals.count).to eq(2) } it { expect(meeting.journals.first.agenda_item_journals).to be_empty } it { expect(agenda_item_journals.count).to eq(1) } it { expect(agenda_item_journals.last).to have_attributes agenda_item.attributes.slice( - "author_id", "title", "notes", "position", "duration_in_minutes", - "start_time", "end_time", "work_package_id", "item_type" + 'author_id', 'title', 'notes', 'position', 'duration_in_minutes', + 'start_time', 'end_time', 'work_package_id', 'item_type' ) } end - context "when agenda item saved w/o change" do + context 'when agenda item saved w/o change' do it { expect do agenda_item.save @@ -136,21 +136,21 @@ end Journal::MeetingAgendaItemJournal.columns_hash.slice( - "notes", "position", "duration_in_minutes", "work_package_id", "item_type" + 'notes', 'position', 'duration_in_minutes', 'work_package_id', 'item_type' ).each do |column_name, column_info| column_value = - if column_name == "item_type" then "work_package" + if column_name == 'item_type' then 'work_package' elsif column_info.type == :integer then 11 - else "A string" + else 'A string' end - if column_name == "item_type" + if column_name == 'item_type' # When testing the work_package item_type, a work_package is required. let(:work_package) { create(:work_package) } end - context "when updating an agenda_item within the aggregation time" do - shared_examples "it updates the existing journals" do + context 'when updating an agenda_item within the aggregation time' do + shared_examples 'it updates the existing journals' do subject(:update_agenda_item) do agenda_item.update(column_name => updated_value) meeting.save_journals @@ -158,7 +158,7 @@ it { expect { update_agenda_item }.not_to change(Journal, :count) } - it "updates the agenda item journal" do + it 'updates the agenda item journal' do expect { update_agenda_item } .to change { agenda_item_journals.last.send(column_name) } .to(updated_value) @@ -166,7 +166,7 @@ end describe "setting a value for the #{column_name} column" do - it_behaves_like "it updates the existing journals" do + it_behaves_like 'it updates the existing journals' do let(:updated_value) { column_value } end end @@ -174,15 +174,15 @@ describe "unsetting a value for the #{column_name} column" do let(:agenda_item_attributes) { { column_name => column_value } } - it_behaves_like "it updates the existing journals" do + it_behaves_like 'it updates the existing journals' do let(:updated_value) { nil } end end end - context "when updating an agenda_item outside the aggregation time", + context 'when updating an agenda_item outside the aggregation time', with_settings: { journal_aggregation_time_minutes: 0 } do - shared_examples "creates a new journal and keeps old journal intact" do + shared_examples 'creates a new journal and keeps old journal intact' do subject(:update_agenda_item) do agenda_item.update(column_name => updated_value) meeting.save_journals @@ -192,13 +192,13 @@ it { expect { update_agenda_item }.to change(Journal::MeetingJournal, :count).by(1) } it { expect { update_agenda_item }.to change(Journal::MeetingAgendaItemJournal, :count).by(1) } - it "does not update the previous agenda item journal" do + it 'does not update the previous agenda item journal' do previous_journal_agenda_items = agenda_item_journals expect { update_agenda_item } .not_to change { previous_journal_agenda_items.reload } end - it "updates the new agenda item journal" do + it 'updates the new agenda item journal' do expect { update_agenda_item } .to change { Journal::MeetingAgendaItemJournal.last.send(column_name) } .to(updated_value) @@ -206,7 +206,7 @@ end describe "setting a value for the #{column_name} column" do - it_behaves_like "creates a new journal and keeps old journal intact" do + it_behaves_like 'creates a new journal and keeps old journal intact' do let(:updated_value) { column_value } end end @@ -214,14 +214,14 @@ describe "unsetting a value for the #{column_name} column" do let(:agenda_item_attributes) { { column_name => column_value } } - it_behaves_like "creates a new journal and keeps old journal intact" do + it_behaves_like 'creates a new journal and keeps old journal intact' do let(:updated_value) { nil } end end end end - context "for a removed agenda_item within aggregation time" do + context 'for a removed agenda_item within aggregation time' do subject(:remove_agenda_item) do agenda_item.destroy meeting.save_journals @@ -237,7 +237,7 @@ } end - context "for a removed agenda_item outside aggregation time", with_settings: { journal_aggregation_time_minutes: 0 } do + context 'for a removed agenda_item outside aggregation time', with_settings: { journal_aggregation_time_minutes: 0 } do let(:agenda_item_journals) { meeting.journals.second.agenda_item_journals } subject(:remove_agenda_item) do @@ -265,12 +265,12 @@ it { remove_agenda_item expect(agenda_item_journals.last).to have_attributes agenda_item.attributes.slice( - "author_id", "title", "notes", "position", "duration_in_minutes", - "start_time", "end_time", "work_package_id" + 'author_id', 'title', 'notes', 'position', 'duration_in_minutes', + 'start_time', 'end_time', 'work_package_id' ) } - it "removes the agenda_item_journals from the new journal" do + it 'removes the agenda_item_journals from the new journal' do remove_agenda_item expect(meeting.journals.last.agenda_item_journals).to be_empty end @@ -278,7 +278,7 @@ end end - describe "#destroy" do + describe '#destroy' do before do meeting.agenda_items << create(:meeting_agenda_item) meeting.save @@ -289,21 +289,21 @@ subject { meeting.destroy } - it "removes the journal" do + it 'removes the journal' do expect { subject } .to change { Journal.exists?(journal.id) } .from(true) .to(false) end - it "removes the journal data" do + it 'removes the journal data' do expect { subject } .to change { Journal::MeetingJournal.exists?(id: journal.data_id) } .from(true) .to(false) end - it "removes the meeting agenda items journals" do + it 'removes the meeting agenda items journals' do expect { subject } .to change { Journal::MeetingAgendaItemJournal.where(id: agenda_item_journals.map(&:id)).count diff --git a/modules/meeting/spec/models/meeting_agenda_item_spec.rb b/modules/meeting/spec/models/meeting_agenda_item_spec.rb index 220e244f14c8..694b64d6c4ae 100644 --- a/modules/meeting/spec/models/meeting_agenda_item_spec.rb +++ b/modules/meeting/spec/models/meeting_agenda_item_spec.rb @@ -36,94 +36,94 @@ subject { meeting_agenda_item } - describe "#author" do - let(:attributes) { { title: "foo", author: } } + describe '#author' do + let(:attributes) { { title: 'foo', author: } } - context "when author is missing" do + context 'when author is missing' do let(:author) { nil } - it "validates" do + it 'validates' do expect(subject).not_to be_valid expect(subject.errors[:author]).to include "must exist" end end - context "when author is present" do + context 'when author is present' do let(:author) { build_stubbed(:user) } - it "validates" do + it 'validates' do expect(subject).to be_valid end end end - describe "#duration" do - let(:attributes) { { title: "foo", author: build_stubbed(:user), duration_in_minutes: } } + describe '#duration' do + let(:attributes) { { title: 'foo', author: build_stubbed(:user), duration_in_minutes: } } - context "with a valid duration" do + context 'with a valid duration' do let(:duration_in_minutes) { 60 } - it "is valid" do + it 'is valid' do expect(subject).to be_valid end end - context "with a negative duration" do + context 'with a negative duration' do let(:duration_in_minutes) { -1 } - it "is invalid" do + it 'is invalid' do expect(subject).not_to be_valid expect(subject.errors[:duration_in_minutes]).to include "must be greater than or equal to 0." end end - context "with a duration that is too large" do + context 'with a duration that is too large' do let(:duration_in_minutes) { 10000000000 } - it "is valid" do + it 'is valid' do expect(subject).not_to be_valid expect(subject.errors[:duration_in_minutes]).to include "must be less than or equal to 1440." end end - context "with max duration" do + context 'with max duration' do let(:duration_in_minutes) { 1440 } - it "is valid" do + it 'is valid' do expect(subject).to be_valid end end - context "with overmax duration" do + context 'with overmax duration' do let(:duration_in_minutes) { 1441 } - it "is valid" do + it 'is valid' do expect(subject).not_to be_valid expect(subject.errors[:duration_in_minutes]).to include "must be less than or equal to 1440." end end end - describe "#title" do + describe '#title' do let(:attributes) { { title:, item_type:, author: build_stubbed(:user), work_package_id: 1 } } - context "when item_type is simple" do + context 'when item_type is simple' do let(:item_type) { :simple } - context "and title is missing" do + context 'and title is missing' do let(:title) { nil } it { is_expected.not_to be_valid } end - context "and title is present" do - let(:title) { "title" } + context 'and title is present' do + let(:title) { 'title' } it { is_expected.to be_valid } end end - context "when item_type is work_package and title is missing" do + context 'when item_type is work_package and title is missing' do let(:item_type) { :work_package } let(:title) { nil } @@ -131,36 +131,36 @@ end end - describe "#work_package_id" do - let(:attributes) { { work_package_id:, item_type:, author: build_stubbed(:user), title: "title" } } + describe '#work_package_id' do + let(:attributes) { { work_package_id:, item_type:, author: build_stubbed(:user), title: 'title' } } - context "on create" do - context "when item_type is simple" do + context 'on create' do + context 'when item_type is simple' do let(:item_type) { :simple } - context "and work_package_id is missing" do + context 'and work_package_id is missing' do let(:work_package_id) { nil } it { is_expected.to be_valid } end - context "and work_package_id is present" do + context 'and work_package_id is present' do let(:work_package_id) { 1 } it { is_expected.to be_valid } end end - context "when item_type is work_package" do + context 'when item_type is work_package' do let(:item_type) { :work_package } - context "and work_package_id is missing" do + context 'and work_package_id is missing' do let(:work_package_id) { nil } it { is_expected.not_to be_valid } end - context "and work_package_id is present" do + context 'and work_package_id is present' do let(:work_package_id) { 1 } it { is_expected.to be_valid } @@ -168,7 +168,7 @@ end end - context "on update" do + context 'on update' do let(:meeting_agenda_item) { create(:meeting_agenda_item) } subject do @@ -176,32 +176,32 @@ meeting_agenda_item end - context "when item_type is simple" do + context 'when item_type is simple' do let(:item_type) { :simple } - context "and work_package_id is missing" do + context 'and work_package_id is missing' do let(:work_package_id) { nil } it { is_expected.to be_valid } end - context "and work_package_id is present" do + context 'and work_package_id is present' do let(:work_package_id) { 1 } it { is_expected.to be_valid } end end - context "when item_type is work_package" do + context 'when item_type is work_package' do let(:item_type) { :work_package } - context "and work_package_id is missing" do + context 'and work_package_id is missing' do let(:work_package_id) { nil } it { is_expected.to be_valid } end - context "and work_package_id is present" do + context 'and work_package_id is present' do let(:work_package_id) { 1 } it { is_expected.to be_valid } @@ -210,7 +210,7 @@ end end - describe "#deleted_work_package?" do + describe '#deleted_work_package?' do subject { meeting_agenda_item.deleted_work_package? } let(:attributes) { { work_package_id:, item_type: } } @@ -219,11 +219,11 @@ let(:item_type) { :simple } let(:work_package_id) { nil } - context "and the agenda_item is not persisted" do + context 'and the agenda_item is not persisted' do it { is_expected.to be false } end - context "and the agenda_item is persisted" do + context 'and the agenda_item is persisted' do let(:meeting_agenda_item) { build_stubbed(:meeting_agenda_item, meeting:, **attributes) } it { is_expected.to be false } @@ -233,27 +233,27 @@ context 'when item_type is "work_package"' do let(:item_type) { :work_package } - context "and the agenda_item is not persisted" do - context "and work_package_id is missing" do + context 'and the agenda_item is not persisted' do + context 'and work_package_id is missing' do let(:work_package_id) { nil } it { is_expected.to be false } end - context "and work_package_id is present" do + context 'and work_package_id is present' do let(:work_package_id) { 1 } it { is_expected.to be false } end end - context "and the agenda_item is persisted" do + context 'and the agenda_item is persisted' do let(:meeting_agenda_item) { build_stubbed(:meeting_agenda_item, meeting:, **attributes) } - context "and work_package_id was originally missing" do + context 'and work_package_id was originally missing' do let(:work_package_id) { nil } - context "and now is present" do + context 'and now is present' do before do meeting_agenda_item.work_package_id = 1 end @@ -261,19 +261,19 @@ it { is_expected.to be true } end - context "and now is also missing" do + context 'and now is also missing' do it { is_expected.to be true } end end - context "and work_package_id was originally present" do + context 'and work_package_id was originally present' do let(:work_package_id) { 1 } - context "and now is also present" do + context 'and now is also present' do it { is_expected.to be false } end - context "and now is missing" do + context 'and now is missing' do before do meeting_agenda_item.work_package_id = nil end @@ -285,18 +285,18 @@ end end - describe "#modifiable?" do + describe '#modifiable?' do subject { meeting_agenda_item.modifiable? } let(:attributes) { { work_package_id: nil, item_type: :work_package } } - context "when meeting is closed" do + context 'when meeting is closed' do let(:meeting_attributes) { { state: :closed } } it { is_expected.to be false } end - context "when the work package is not deleted" do + context 'when the work package is not deleted' do before do allow(meeting_agenda_item).to receive(:deleted_work_package?).and_return(false) end @@ -304,16 +304,16 @@ it { is_expected.to be true } end - context "when work package is deleted" do + context 'when work package is deleted' do before do allow(meeting_agenda_item).to receive(:deleted_work_package?).and_return(true) end - context "and the current value is not modified" do + context 'and the current value is not modified' do it { is_expected.to be true } end - context "and the current value is modified" do + context 'and the current value is modified' do before do meeting_agenda_item.work_package_id = 1 end diff --git a/modules/meeting/spec/models/meeting_agenda_spec.rb b/modules/meeting/spec/models/meeting_agenda_spec.rb index 2bf070ca61e6..72ccbb53844e 100644 --- a/modules/meeting/spec/models/meeting_agenda_spec.rb +++ b/modules/meeting/spec/models/meeting_agenda_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' -RSpec.describe "MeetingAgenda" do +RSpec.describe 'MeetingAgenda' do before do @a = build(:meeting_agenda, text: "Some content...\n\nMore content!\n\nExtraordinary content!!") end # TODO: Test the right user and messages are set in the history - describe "#lock!" do - it "locks the agenda" do + describe '#lock!' do + it 'locks the agenda' do @a.save @a.reload @a.lock! @@ -44,8 +44,8 @@ end end - describe "#unlock!" do - it "unlocks the agenda" do + describe '#unlock!' do + it 'unlocks the agenda' do @a.locked = true @a.save @a.reload @@ -56,13 +56,13 @@ end # a meeting agenda is editable when it is not locked - describe "#editable?" do - it "is editable when not locked" do + describe '#editable?' do + it 'is editable when not locked' do @a.locked = false expect(@a.editable?).to be_truthy end - it "is not editable when locked" do + it 'is not editable when locked' do @a.locked = true expect(@a.editable?).to be_falsey end diff --git a/modules/meeting/spec/models/meeting_minutes_spec.rb b/modules/meeting/spec/models/meeting_minutes_spec.rb index e56f8990163e..22310c31951b 100644 --- a/modules/meeting/spec/models/meeting_minutes_spec.rb +++ b/modules/meeting/spec/models/meeting_minutes_spec.rb @@ -26,37 +26,37 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' -RSpec.describe "MeetingMinutes" do +RSpec.describe 'MeetingMinutes' do before do @min = build(:meeting_minutes) end # meeting minutes are editable when the meeting agenda is locked - describe "#editable?" do + describe '#editable?' do before do @mee = build(:meeting) @min.meeting = @mee end - describe "with no agenda present" do - it "is not editable" do + describe 'with no agenda present' do + it 'is not editable' do expect(@min.editable?).to be_falsey end end - describe "with an agenda present" do + describe 'with an agenda present' do before do @a = build(:meeting_agenda) @mee.agenda = @a end - it "is not editable when the agenda is open" do + it 'is not editable when the agenda is open' do expect(@min.editable?).to be_falsey end - it "is editable when the agenda is closed" do + it 'is editable when the agenda is closed' do @a.lock! expect(@min.editable?).to be_truthy end diff --git a/modules/meeting/spec/models/meeting_spec.rb b/modules/meeting/spec/models/meeting_spec.rb index 7774235d9e54..443dda9dfae4 100644 --- a/modules/meeting/spec/models/meeting_spec.rb +++ b/modules/meeting/spec/models/meeting_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe Meeting do shared_let (:user1) { create(:user) } @@ -34,7 +34,7 @@ let(:project) { create(:project, members: project_members) } let(:meeting) { create(:meeting, project:, author: user1) } let(:agenda) do - meeting.create_agenda text: "Meeting Agenda text" + meeting.create_agenda text: 'Meeting Agenda text' meeting.reload_agenda # avoiding stale object errors end let(:project_members) { {} } @@ -45,60 +45,60 @@ it { is_expected.to belong_to :author } it { is_expected.to validate_presence_of :title } - describe "new instance" do - let(:meeting) { build(:meeting, project:, title: "dingens") } + describe 'new instance' do + let(:meeting) { build(:meeting, project:, title: 'dingens') } - describe "to_s" do - it { expect(meeting.to_s).to eq("dingens") } + describe 'to_s' do + it { expect(meeting.to_s).to eq('dingens') } end - describe "start_date" do + describe 'start_date' do it { expect(meeting.start_date).to eq(Date.tomorrow.iso8601) } end - describe "start_month" do + describe 'start_month' do it { expect(meeting.start_month).to eq(Date.tomorrow.month) } end - describe "start_year" do + describe 'start_year' do it { expect(meeting.start_year).to eq(Date.tomorrow.year) } end - describe "end_time" do + describe 'end_time' do it { expect(meeting.end_time).to eq(Date.tomorrow + 11.hours) } end - describe "date validations" do - it "marks invalid start dates" do - meeting.start_date = "-" - expect(meeting.start_date).to eq("-") + describe 'date validations' do + it 'marks invalid start dates' do + meeting.start_date = '-' + expect(meeting.start_date).to eq('-') expect(meeting.start_time).to be_nil expect(meeting).not_to be_valid expect(meeting.errors.count).to eq(1) end - it "marks invalid start hours" do - meeting.start_time_hour = "-" - expect(meeting.start_time_hour).to eq("-") + it 'marks invalid start hours' do + meeting.start_time_hour = '-' + expect(meeting.start_time_hour).to eq('-') expect(meeting.start_time).to be_nil expect(meeting).not_to be_valid expect(meeting.errors.count).to eq(1) end - it "is not invalid when setting date_time explicitly" do + it 'is not invalid when setting date_time explicitly' do meeting.start_time = DateTime.now expect(meeting).to be_valid end - it "raises an error trying to set invalid time" do - expect { meeting.start_time = "-" }.to raise_error(Date::Error) + it 'raises an error trying to set invalid time' do + expect { meeting.start_time = '-' }.to raise_error(Date::Error) end - it "accepts changes after invalid dates" do - meeting.start_date = "-" + it 'accepts changes after invalid dates' do + meeting.start_date = '-' expect(meeting.start_time).to be_nil expect(meeting).not_to be_valid - expect(meeting.errors[:start_date]).to contain_exactly "is not a valid date. Required format: YYYY-MM-DD." + expect(meeting.errors[:start_date]).to contain_exactly 'is not a valid date. Required format: YYYY-MM-DD.' meeting.start_date = Time.zone.today.iso8601 expect(meeting).to be_valid @@ -109,38 +109,38 @@ end end - describe "all_changeable_participants" do - describe "WITH a user having the view_meetings permission" do + describe 'all_changeable_participants' do + describe 'WITH a user having the view_meetings permission' do let(:project_members) { { user1 => role } } - it "contains the user" do + it 'contains the user' do expect(meeting.all_changeable_participants).to eq([user1]) end end - describe "WITH a user not having the view_meetings permission" do + describe 'WITH a user not having the view_meetings permission' do let(:role2) { create(:project_role, permissions: []) } let(:project_members) { { user1 => role, user2 => role2 } } - it "does not contain the user" do + it 'does not contain the user' do expect(meeting.all_changeable_participants).not_to include(user2) end end - describe "WITH a user being locked but invited" do + describe 'WITH a user being locked but invited' do let(:locked_user) { create(:locked_user) } before do meeting.participants_attributes = [{ user_id: locked_user.id, invited: 1 }] end - it "contains the user" do + it 'contains the user' do expect(meeting.all_changeable_participants).to include(locked_user) end end end - describe "participants and author as watchers" do + describe 'participants and author as watchers' do let(:project_members) { { user1 => role, user2 => role } } before do @@ -151,7 +151,7 @@ it { expect(meeting.watchers.collect(&:user)).to contain_exactly(user1, user2) } end - describe "#close_agenda_and_copy_to_minutes" do + describe '#close_agenda_and_copy_to_minutes' do before do agenda # creating it @@ -162,48 +162,48 @@ expect(meeting.minutes.text).to eq(meeting.agenda.text) end - it "closes the agenda" do + it 'closes the agenda' do expect(meeting.agenda).to be_locked end end - describe "Timezones" do - shared_examples "uses that zone" do |zone| + describe 'Timezones' do + shared_examples 'uses that zone' do |zone| it do - meeting.start_date = "2016-07-01" + meeting.start_date = '2016-07-01' expect(meeting.start_time.zone).to eq(zone) end end - context "default zone" do - it_behaves_like "uses that zone", "UTC" + context 'default zone' do + it_behaves_like 'uses that zone', 'UTC' end - context "other timezone set" do + context 'other timezone set' do let!(:old_time_zone) { Time.zone } before do - Time.zone = "EST" + Time.zone = 'EST' end after do Time.zone = old_time_zone.name end - it_behaves_like "uses that zone", "EST" + it_behaves_like 'uses that zone', 'EST' end end - describe "acts_as_watchable" do - it "is watchable" do + describe 'acts_as_watchable' do + it 'is watchable' do expect(described_class).to include(Redmine::Acts::Watchable::InstanceMethods) end - it "uses the :view_meetings permission" do + it 'uses the :view_meetings permission' do expect(described_class.acts_as_watchable_permission).to eq(:view_meetings) end - it "uses the :view_meetings permission in STI classes" do + it 'uses the :view_meetings permission in STI classes' do expect(StructuredMeeting.acts_as_watchable_permission).to eq(:view_meetings) end end diff --git a/modules/meeting/spec/models/permitted_params_spec.rb b/modules/meeting/spec/models/permitted_params_spec.rb index 043ecbc1ce22..9c67383dee3c 100644 --- a/modules/meeting/spec/models/permitted_params_spec.rb +++ b/modules/meeting/spec/models/permitted_params_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.dirname(__FILE__) + "/../spec_helper" +require File.dirname(__FILE__) + '/../spec_helper' RSpec.describe PermittedParams do let(:user) { build_stubbed(:user) } - describe "#search" do - it "permits its whitelisted params" do + describe '#search' do + it 'permits its whitelisted params' do acceptable_params = { messages: 1 } permitted = ActionController::Parameters.new(acceptable_params).permit! diff --git a/modules/meeting/spec/models/project/activity_spec.rb b/modules/meeting/spec/models/project/activity_spec.rb index ab0824e782d5..c19c756ef44b 100644 --- a/modules/meeting/spec/models/project/activity_spec.rb +++ b/modules/meeting/spec/models/project/activity_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::Activity, "meeting" do +RSpec.describe Projects::Activity, 'meeting' do shared_let(:project) do create(:project, :updated_a_long_time_ago) end @@ -54,8 +54,8 @@ def latest_activity Project.with_latest_activity.find(project.id).latest_activity_at end - describe ".with_latest_activity" do - it "set project.latest_activity_at to the latest updated meeting time" do + describe '.with_latest_activity' do + it 'set project.latest_activity_at to the latest updated meeting time' do meeting.update(updated_at: initial_time - 10.seconds) meeting2.update(updated_at: initial_time - 20.seconds) @@ -63,7 +63,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(meeting.updated_at) end - it "takes the time stamp of the latest activity across models" do + it 'takes the time stamp of the latest activity across models' do work_package.update(updated_at: initial_time - 10.seconds) meeting.update(updated_at: initial_time - 20.seconds) diff --git a/modules/meeting/spec/models/queries/meeting_query_spec.rb b/modules/meeting/spec/models/queries/meeting_query_spec.rb index 4947e56d7f58..76279af44fef 100644 --- a/modules/meeting/spec/models/queries/meeting_query_spec.rb +++ b/modules/meeting/spec/models/queries/meeting_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Meetings::MeetingQuery do subject { described_class.new(user:) } @@ -46,78 +46,78 @@ let(:invisible_project) { create(:project) } let!(:invisible_meeting) { create(:meeting, project: invisible_project, start_time: 1.day.ago) } - context "without a filter" do - it "returns all visible meetings" do + context 'without a filter' do + it 'returns all visible meetings' do expect(subject.results).to contain_exactly(visible_meeting_past, visible_meeting_ongoing, visible_meeting_future) end end - context "when filtering by project" do + context 'when filtering by project' do let(:other_visible_project) { create(:project, members: { user => create(:project_role, permissions: %i[view_meetings]) }) } let!(:other_visible_meeting) { create(:meeting, project: other_visible_project, author: user, start_time: 1.day.ago) } before do - subject.where("project_id", "=", [other_visible_project.id]) + subject.where('project_id', '=', [other_visible_project.id]) end - it "returns only visible meetings for that project" do + it 'returns only visible meetings for that project' do expect(subject.results).to contain_exactly(other_visible_meeting) end end - context "when filtering by time" do - context "for future meetings" do + context 'when filtering by time' do + context 'for future meetings' do before do - subject.where("time", "=", ["future"]) + subject.where('time', '=', ['future']) end - it "returns meetings starting in the future and meetings currently ongoing" do + it 'returns meetings starting in the future and meetings currently ongoing' do expect(subject.results).to contain_exactly(visible_meeting_future, visible_meeting_ongoing) end end - context "for past meetings" do + context 'for past meetings' do before do - subject.where("time", "=", ["past"]) + subject.where('time', '=', ['past']) end - it "returns meetings starting in the past and meetings currently ongoing" do + it 'returns meetings starting in the past and meetings currently ongoing' do expect(subject.results).to contain_exactly(visible_meeting_past, visible_meeting_ongoing) end end end - context "when filtering by attending users" do + context 'when filtering by attending users' do before do create(:meeting_participant, user: other_user, meeting: visible_meeting_ongoing, attended: true) create(:meeting_participant, user: other_user, meeting: visible_meeting_future, attended: false) - subject.where("attended_user_id", "=", [other_user.id]) + subject.where('attended_user_id', '=', [other_user.id]) end - it "returns meetings where the given user is attending" do + it 'returns meetings where the given user is attending' do expect(subject.results).to contain_exactly(visible_meeting_ongoing) end end - context "when filtering by invited users" do + context 'when filtering by invited users' do before do create(:meeting_participant, user: other_user, meeting: visible_meeting_ongoing, invited: true) create(:meeting_participant, user: other_user, meeting: visible_meeting_future, invited: false) - subject.where("invited_user_id", "=", [other_user.id]) + subject.where('invited_user_id', '=', [other_user.id]) end - it "returns meetings where the given user is invited" do + it 'returns meetings where the given user is invited' do expect(subject.results).to contain_exactly(visible_meeting_ongoing) end end - context "when filtering by author" do + context 'when filtering by author' do before do visible_meeting_future.update(author: other_user) - subject.where("author_id", "=", [other_user.id]) + subject.where('author_id', '=', [other_user.id]) end - it "returns meetings where the given user is invited" do + it 'returns meetings where the given user is invited' do expect(subject.results).to contain_exactly(visible_meeting_future) end end diff --git a/modules/meeting/spec/requests/api/v3/attachments/meeting_agenda_spec.rb b/modules/meeting/spec/requests/api/v3/attachments/meeting_agenda_spec.rb index d902c51eba78..46a60c9220ef 100644 --- a/modules/meeting/spec/requests/api/v3/attachments/meeting_agenda_spec.rb +++ b/modules/meeting/spec/requests/api/v3/attachments/meeting_agenda_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "requests/api/v3/attachments/attachment_resource_shared_examples" +require 'spec_helper' +require 'requests/api/v3/attachments/attachment_resource_shared_examples' RSpec.describe "meeting agenda attachments" do it_behaves_like "an APIv3 attachment resource" do diff --git a/modules/meeting/spec/requests/api/v3/attachments/meeting_minutes_spec.rb b/modules/meeting/spec/requests/api/v3/attachments/meeting_minutes_spec.rb index 7bdc16fa6bb8..7ddc1dac3ad7 100644 --- a/modules/meeting/spec/requests/api/v3/attachments/meeting_minutes_spec.rb +++ b/modules/meeting/spec/requests/api/v3/attachments/meeting_minutes_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "requests/api/v3/attachments/attachment_resource_shared_examples" +require 'spec_helper' +require 'requests/api/v3/attachments/attachment_resource_shared_examples' RSpec.describe "meeting minutes attachments" do it_behaves_like "an APIv3 attachment resource" do diff --git a/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb b/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb index b1dc4377b414..bb76e3f8eb18 100644 --- a/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb +++ b/modules/meeting/spec/requests/api/v3/attachments/meetings_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "requests/api/v3/attachments/attachment_resource_shared_examples" +require 'spec_helper' +require 'requests/api/v3/attachments/attachment_resource_shared_examples' RSpec.describe "meetings attachments" do it_behaves_like "an APIv3 attachment resource" do diff --git a/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb b/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb index ce5637d5989f..c7918ebd3611 100644 --- a/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb +++ b/modules/meeting/spec/requests/api/v3/meetings/meetings_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Meeting resource" do +RSpec.describe 'API v3 Meeting resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -42,45 +42,45 @@ member_with_permissions: { project => permissions }) end - describe "meetings/:id" do + describe 'meetings/:id' do let(:get_path) { api_v3_paths.meeting meeting.id } - context "with logged in user" do + context 'with logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - context "when valid id" do - it "returns HTTP 200" do + context 'when valid id' do + it 'returns HTTP 200' do expect(last_response.status).to eq 200 end end - context "when valid id, but not visible" do + context 'when valid id, but not visible' do let(:permissions) { [:view_work_packages] } - it "returns HTTP 404" do + it 'returns HTTP 404' do expect(last_response.status).to eq 404 end end - context "when invalid id" do - let(:get_path) { api_v3_paths.budget "bogus" } + context 'when invalid id' do + let(:get_path) { api_v3_paths.budget 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } end end end - context "with not logged in user" do + context 'with not logged in user' do before do get get_path end - it_behaves_like "not found response based on login_required" + it_behaves_like 'not found response based on login_required' end end end diff --git a/modules/meeting/spec/requests/meetings_spec.rb b/modules/meeting/spec/requests/meetings_spec.rb index 075e7bc5ebf6..09e70761db3a 100644 --- a/modules/meeting/spec/requests/meetings_spec.rb +++ b/modules/meeting/spec/requests/meetings_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Meeting requests", +RSpec.describe 'Meeting requests', :skip_csrf, type: :rails_request do shared_let(:project) { create(:project, enabled_module_names: %i[meetings]) } @@ -38,15 +38,15 @@ login_as user end - describe "copy" do + describe 'copy' do let(:meeting) { create(:structured_meeting, project:) } let(:base_params) do { copied_from_meeting_id: meeting.id, project_id: project.id, meeting: { - title: "Copied meeting", - type: "StructuredMeeting" + title: 'Copied meeting', + type: 'StructuredMeeting' } } end @@ -56,26 +56,26 @@ post meetings_path(project), params: base_params.merge(params) - Meeting.find_by(title: "Copied meeting") + Meeting.find_by(title: 'Copied meeting') end - context "when copying agenda items" do - let!(:agenda_item) { create(:meeting_agenda_item, meeting:, notes: "**foo**") } - let(:params) { { copy_agenda: "1" } } + context 'when copying agenda items' do + let!(:agenda_item) { create(:meeting_agenda_item, meeting:, notes: '**foo**') } + let(:params) { { copy_agenda: '1' } } - it "copies the agenda items" do + it 'copies the agenda items' do subject expect(response).to be_redirect expect(subject).to be_present expect(subject.agenda_items.count).to eq(1) - expect(subject.agenda_items.first.notes).to eq("**foo**") + expect(subject.agenda_items.first.notes).to eq('**foo**') end end - context "when copying without additional params" do - it "copies the meeting, but not the agenda" do + context 'when copying without additional params' do + it 'copies the meeting, but not the agenda' do subject expect(response).to be_redirect @@ -85,11 +85,11 @@ end end - context "when meeting is not visible" do + context 'when meeting is not visible' do let(:other_project) { create(:project) } let(:meeting) { create(:meeting, project: other_project) } - it "renders a 404" do + it 'renders a 404' do subject expect(response).to have_http_status(:not_found) end diff --git a/modules/meeting/spec/routing/previews_routing_spec.rb b/modules/meeting/spec/routing/previews_routing_spec.rb index 0f4763d36dd2..4a379d9c88d9 100644 --- a/modules/meeting/spec/routing/previews_routing_spec.rb +++ b/modules/meeting/spec/routing/previews_routing_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "preview" do - it "connects POST /meetings/:meeting_id/agenda/preview to meeting_agendas#preview" do - expect(post("/meetings/1/agenda/preview")).to route_to(controller: "meeting_agendas", - meeting_id: "1", - action: "preview") +RSpec.describe 'preview' do + it 'connects POST /meetings/:meeting_id/agenda/preview to meeting_agendas#preview' do + expect(post('/meetings/1/agenda/preview')).to route_to(controller: 'meeting_agendas', + meeting_id: '1', + action: 'preview') end - it "connects POST /meetings/:meeting_id/agenda/preview to meeting_minutes#preview" do - expect(post("/meetings/1/minutes/preview")).to route_to(controller: "meeting_minutes", - meeting_id: "1", - action: "preview") + it 'connects POST /meetings/:meeting_id/agenda/preview to meeting_minutes#preview' do + expect(post('/meetings/1/minutes/preview')).to route_to(controller: 'meeting_minutes', + meeting_id: '1', + action: 'preview') end end diff --git a/modules/meeting/spec/seeders/demo_data/project_seeder_spec.rb b/modules/meeting/spec/seeders/demo_data/project_seeder_spec.rb index 839e59efb4ac..40b1212971ac 100644 --- a/modules/meeting/spec/seeders/demo_data/project_seeder_spec.rb +++ b/modules/meeting/spec/seeders/demo_data/project_seeder_spec.rb @@ -28,20 +28,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DemoData::ProjectSeeder do - include_context "with basic seed data" + include_context 'with basic seed data' - subject(:project_seeder) { described_class.new(seed_data.lookup("projects.my-project")) } + subject(:project_seeder) { described_class.new(seed_data.lookup('projects.my-project')) } let(:work_package) { create(:work_package) } let(:user) { create(:user) } let(:seed_data) do data = basic_seed_data.merge( Source::SeedData.new( - "projects" => { - "my-project" => project_data + 'projects' => { + 'my-project' => project_data } ) ) @@ -81,27 +81,27 @@ project_seeder.seed! end - it "creates an associated meeting" do - meeting = Meeting.find_by(title: "Weekly") + it 'creates an associated meeting' do + meeting = Meeting.find_by(title: 'Weekly') expect(meeting.author).to eq user expect(meeting.duration).to eq 0.5 expect(meeting.agenda_items.count).to eq 2 - first = meeting.agenda_items.find_by(title: "First topic") + first = meeting.agenda_items.find_by(title: 'First topic') expect(first.duration_in_minutes).to eq 10 expect(first.author).to eq user - expect(first.notes).to eq "Some **markdown**" + expect(first.notes).to eq 'Some **markdown**' - second = meeting.agenda_items.find_by(title: "Reference") + second = meeting.agenda_items.find_by(title: 'Reference') expect(second.duration_in_minutes).to eq 5 expect(second.author).to eq user - expect(second.notes).to eq "Some **markdown**" + expect(second.notes).to eq 'Some **markdown**' expect(second.work_package).to eq work_package end - it "uses default duration of 1h if not specified" do - meeting = Meeting.find_by(title: "Implicit 1h duration") + it 'uses default duration of 1h if not specified' do + meeting = Meeting.find_by(title: 'Implicit 1h duration') expect(meeting.duration).to eq 1 end end diff --git a/modules/meeting/spec/services/meeting_contents/update_service_spec.rb b/modules/meeting/spec/services/meeting_contents/update_service_spec.rb index 0d7c63e45e13..d7f898747e94 100644 --- a/modules/meeting/spec/services/meeting_contents/update_service_spec.rb +++ b/modules/meeting/spec/services/meeting_contents/update_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe MeetingContents::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:factory) { :meeting_agenda } end end diff --git a/modules/meeting/spec/services/meetings/copy_service_integration_spec.rb b/modules/meeting/spec/services/meetings/copy_service_integration_spec.rb index 7f855ea018bb..979ae2b76ed4 100644 --- a/modules/meeting/spec/services/meetings/copy_service_integration_spec.rb +++ b/modules/meeting/spec/services/meetings/copy_service_integration_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Meetings::CopyService, "integration", type: :model do +RSpec.describe Meetings::CopyService, 'integration', type: :model do shared_let(:project) { create(:project, enabled_module_names: %i[meetings]) } shared_let(:user) do create(:user, member_with_permissions: { project => %i(view_meetings create_meetings) }) end - shared_let(:meeting) { create(:structured_meeting, project:, start_time: Time.parse("2013-03-27T15:35:00Z")) } + shared_let(:meeting) { create(:structured_meeting, project:, start_time: Time.parse('2013-03-27T15:35:00Z')) } let(:instance) { described_class.new(model: meeting, user:) } let(:attributes) { {} } @@ -42,18 +42,18 @@ let(:service_result) { instance.call(attributes:, **params) } let(:copy) { service_result.result } - it "copies the meeting as is" do + it 'copies the meeting as is' do expect(service_result).to be_success expect(copy.author).to eq(user) expect(copy.start_time).to eq(meeting.start_time + 1.week) end - describe "with participants" do + describe 'with participants' do let(:invited_user) { create(:user, member_with_permissions: { project => %i(view_meetings) }) } let(:attending_user) { create(:user, member_with_permissions: { project => %i(view_meetings) }) } let(:invalid_user) { create(:user) } - it "copies applicable participants, resetting attended status" do + it 'copies applicable participants, resetting attended status' do meeting.participants.create!(user: invited_user, invited: true, attended: false) meeting.participants.create!(user: attending_user, invited: true, attended: true) meeting.participants.create!(user: invalid_user, invited: true, attended: true) @@ -73,10 +73,10 @@ end end - describe "when not saving" do + describe 'when not saving' do let(:params) { { save: false } } - it "builds the meeting" do + it 'builds the meeting' do expect(service_result).to be_success expect(copy.author).to eq(user) expect(copy.start_time).to eq(meeting.start_time + 1.week) @@ -84,14 +84,14 @@ end end - context "with agenda items" do + context 'with agenda items' do shared_let(:agenda_item) do create(:meeting_agenda_item, meeting:, notes: "hello there") end - it "copies the agenda item" do + it 'copies the agenda item' do expect(copy.agenda_items.length) .to eq 1 @@ -99,16 +99,16 @@ .to eq agenda_item.notes end - context "when asking not to copy agenda" do + context 'when asking not to copy agenda' do let(:params) { { copy_agenda: false } } - it "does not copy agenda items" do + it 'does not copy agenda items' do expect(copy.agenda_items).to be_empty end end end - context "with attachments" do + context 'with attachments' do shared_let(:attachment) do create(:attachment, container: meeting) @@ -119,7 +119,7 @@ notes: "![](/api/v3/attachments/#{attachment.id}/content") end - it "copies the attachment" do + it 'copies the attachment' do expect(copy.attachments.length) .to eq 1 @@ -130,10 +130,10 @@ expect(copy.agenda_items.first.notes).to include "attachments/#{copy.attachments.first.id}/content" end - context "when asking not to copy attachments" do + context 'when asking not to copy attachments' do let(:params) { { copy_attachments: false } } - it "does not copy attachments" do + it 'does not copy attachments' do expect(copy.attachments).to be_empty expect(copy.agenda_items.first.notes).to include "attachments/#{attachment.id}/content" end diff --git a/modules/meeting/spec/services/meetings/create_service_spec.rb b/modules/meeting/spec/services/meetings/create_service_spec.rb index ed6ff57d5623..6e4101a89e24 100644 --- a/modules/meeting/spec/services/meetings/create_service_spec.rb +++ b/modules/meeting/spec/services/meetings/create_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Meetings::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:factory) { :meeting } end end diff --git a/modules/meeting/spec/services/meetings/ical_service_spec.rb b/modules/meeting/spec/services/meetings/ical_service_spec.rb index 56aad869dc5f..38bb479b0d9d 100644 --- a/modules/meeting/spec/services/meetings/ical_service_spec.rb +++ b/modules/meeting/spec/services/meetings/ical_service_spec.rb @@ -26,23 +26,23 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Meetings::ICalService, type: :model do - shared_let(:user) { create(:user, firstname: "Bob", lastname: "Barker", mail: "bob@example.com") } - shared_let(:user2) { create(:user, firstname: "Foo", lastname: "Fooer", mail: "foo@example.com") } - shared_let(:project) { create(:project, name: "My Project") } + shared_let(:user) { create(:user, firstname: 'Bob', lastname: 'Barker', mail: 'bob@example.com') } + shared_let(:user2) { create(:user, firstname: 'Foo', lastname: 'Fooer', mail: 'foo@example.com') } + shared_let(:project) { create(:project, name: 'My Project') } shared_let(:meeting) do create(:meeting, author: user, project:, - title: "Important meeting", + title: 'Important meeting', participants: [ MeetingParticipant.new(user:), MeetingParticipant.new(user: user2) ], - location: "https://example.com/meet/important-meeting", + location: 'https://example.com/meet/important-meeting', start_time: Time.zone.parse("2021-01-19T10:00:00Z"), duration: 1.0) end @@ -52,31 +52,31 @@ subject(:entry) { Icalendar::Event.parse(result).first } - describe "#call" do - it "returns a success" do + describe '#call' do + it 'returns a success' do expect(service.call).to be_success end - context "when exception is raised" do + context 'when exception is raised' do subject { service.call } before do allow(service).to receive(:generate_ical).and_raise StandardError.new("Oh noes") end - it "returns a failure" do + it 'returns a failure' do expect(subject).to be_failure expect(subject.message).to eq("Oh noes") end end - it "renders the ICS file", :aggregate_failures do + it 'renders the ICS file', :aggregate_failures do expect(result).to be_a String - expect(entry.attendee.map(&:to_s)).to contain_exactly("mailto:foo@example.com", "mailto:bob@example.com") + expect(entry.attendee.map(&:to_s)).to contain_exactly('mailto:foo@example.com', 'mailto:bob@example.com') expect(entry.dtstart.utc).to eq meeting.start_time expect(entry.dtend.utc).to eq meeting.start_time + 1.hour - expect(entry.summary).to eq "[My Project] Important meeting" + expect(entry.summary).to eq '[My Project] Important meeting' expect(entry.description).to eq "[My Project] Meeting: Important meeting" expect(entry.location).to eq(meeting.location.presence) expect(entry.dtstart).to eq Time.zone.parse("2021-01-19T10:00:00Z").in_time_zone("Europe/Berlin") diff --git a/modules/meeting/spec/services/meetings/update_service_spec.rb b/modules/meeting/spec/services/meetings/update_service_spec.rb index 0c8abaeab289..f0390ca6572c 100644 --- a/modules/meeting/spec/services/meetings/update_service_spec.rb +++ b/modules/meeting/spec/services/meetings/update_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Meetings::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:factory) { :meeting } end end diff --git a/modules/meeting/spec/services/principals/replace_references_service_call_integration_spec.rb b/modules/meeting/spec/services/principals/replace_references_service_call_integration_spec.rb index c647bee6981b..4b16548a5c77 100644 --- a/modules/meeting/spec/services/principals/replace_references_service_call_integration_spec.rb +++ b/modules/meeting/spec/services/principals/replace_references_service_call_integration_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe Principals::ReplaceReferencesService, "#call", type: :model do +RSpec.describe Principals::ReplaceReferencesService, '#call', type: :model do shared_let(:principal) { create(:user) } shared_let(:to_principal) { create(:user) } @@ -41,17 +41,17 @@ described_class.new end - shared_examples "replaces the creator" do + shared_examples 'replaces the creator' do before do model end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "replaces principal with to_principal" do + it 'replaces principal with to_principal' do service_call model.reload @@ -59,8 +59,8 @@ end end - context "with MeetingAgendaItem" do - it_behaves_like "replaces the creator" do + context 'with MeetingAgendaItem' do + it_behaves_like 'replaces the creator' do let(:model) { create(:meeting_agenda_item, author: principal) } end end diff --git a/modules/meeting/spec/spec_helper.rb b/modules/meeting/spec/spec_helper.rb index 9bf43696be67..b2e984d0fa2a 100644 --- a/modules/meeting/spec/spec_helper.rb +++ b/modules/meeting/spec/spec_helper.rb @@ -27,4 +27,4 @@ #++ # -- load spec_helper from OpenProject core -require "spec_helper" +require 'spec_helper' diff --git a/modules/meeting/spec/support/pages/meetings/edit.rb b/modules/meeting/spec/support/pages/meetings/edit.rb index bdf14e7ac658..92552b59b30e 100644 --- a/modules/meeting/spec/support/pages/meetings/edit.rb +++ b/modules/meeting/spec/support/pages/meetings/edit.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "base" -require_relative "show" +require_relative 'base' +require_relative 'show' module Pages::Meetings class Edit < Base @@ -56,7 +56,7 @@ def uninvite(user) end def click_save - click_button("Save") + click_button('Save') Pages::Meetings::Show.new(meeting) end diff --git a/modules/meeting/spec/support/pages/meetings/index.rb b/modules/meeting/spec/support/pages/meetings/index.rb index 2efdae790a33..2df01c40d598 100644 --- a/modules/meeting/spec/support/pages/meetings/index.rb +++ b/modules/meeting/spec/support/pages/meetings/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "new" +require_relative 'new' module Pages::Meetings class Index < Pages::Page @@ -39,72 +39,72 @@ def initialize(project:) end def click_create_new - within ".toolbar-items" do - click_link "Meeting" + within '.toolbar-items' do + click_link 'Meeting' end New.new(project) end def expect_no_main_menu - expect(page).to have_no_css "#main-menu" + expect(page).to have_no_css '#main-menu' end def expect_no_create_new_button - within ".toolbar-items" do - expect(page).to have_no_css "#add-meeting-button" + within '.toolbar-items' do + expect(page).to have_no_css '#add-meeting-button' end end def expect_no_create_new_buttons - within ".toolbar-items" do - expect(page).to have_no_css "#add-meeting-button" + within '.toolbar-items' do + expect(page).to have_no_css '#add-meeting-button' end - within "#main-menu" do - expect(page).to have_no_button "Meeting" + within '#main-menu' do + expect(page).to have_no_button 'Meeting' end end def expect_create_new_button - within ".toolbar-items" do - expect(page).to have_css "#add-meeting-button" + within '.toolbar-items' do + expect(page).to have_css '#add-meeting-button' end end def expect_create_new_buttons - within ".toolbar-items" do - expect(page).to have_css "#add-meeting-button" + within '.toolbar-items' do + expect(page).to have_css '#add-meeting-button' end - within "#main-menu" do - expect(page).to have_button "Meeting" + within '#main-menu' do + expect(page).to have_button 'Meeting' end end def set_sidebar_filter(filter_name) - within "#main-menu" do + within '#main-menu' do click_link text: filter_name end end def expect_no_meetings_listed - within "#content-wrapper" do + within '#content-wrapper' do expect(page) .to have_content I18n.t(:no_results_title_text) end end def expect_meetings_listed_in_order(*meetings) - within ".generic-table tbody" do - listed_meeting_titles = all("tr td.title").map(&:text) + within '.generic-table tbody' do + listed_meeting_titles = all('tr td.title').map(&:text) expect(listed_meeting_titles).to eq(meetings.map(&:title)) end end def expect_meetings_listed(*meetings) - within ".generic-table tbody" do + within '.generic-table tbody' do meetings.each do |meeting| expect(page).to have_css("td.title", text: meeting.title) @@ -113,7 +113,7 @@ def expect_meetings_listed(*meetings) end def expect_meetings_not_listed(*meetings) - within "#content-wrapper" do + within '#content-wrapper' do meetings.each do |meeting| expect(page).to have_no_css("td.title", text: meeting.title) @@ -122,7 +122,7 @@ def expect_meetings_not_listed(*meetings) end def expect_link_to_meeting_location(meeting) - within "#content-wrapper" do + within '#content-wrapper' do within row_for(meeting) do expect(page).to have_link meeting.location end @@ -130,45 +130,45 @@ def expect_link_to_meeting_location(meeting) end def expect_plaintext_meeting_location(meeting) - within "#content-wrapper" do + within '#content-wrapper' do within row_for(meeting) do - expect(page).to have_css("td.location", text: meeting.location) + expect(page).to have_css('td.location', text: meeting.location) expect(page).to have_no_link meeting.location end end end def expect_no_meeting_location(meeting) - within "#content-wrapper" do + within '#content-wrapper' do within row_for(meeting) do - expect(page).to have_css("td.location", text: "") + expect(page).to have_css('td.location', text: '') end end end def expect_to_be_on_page(number) expect(page) - .to have_css(".op-pagination--item_current", + .to have_css('.op-pagination--item_current', text: number) end def to_page(number) - within ".op-pagination--pages" do + within '.op-pagination--pages' do click_link number.to_s end end def navigate_by_project_menu visit project_path(project) - within "#main-menu" do - click_link "Meetings", match: :first + within '#main-menu' do + click_link 'Meetings', match: :first end end def navigate_by_global_menu visit root_path - within "#main-menu" do - click_link "Meetings", match: :first + within '#main-menu' do + click_link 'Meetings', match: :first end end @@ -183,7 +183,7 @@ def path private def row_for(meeting) - find("td.title", text: meeting.title).ancestor("tr") + find('td.title', text: meeting.title).ancestor('tr') end end end diff --git a/modules/meeting/spec/support/pages/meetings/new.rb b/modules/meeting/spec/support/pages/meetings/new.rb index 9dd8beec89de..712f9667f3f7 100644 --- a/modules/meeting/spec/support/pages/meetings/new.rb +++ b/modules/meeting/spec/support/pages/meetings/new.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "base" -require_relative "show" +require_relative 'base' +require_relative 'show' module Pages::Meetings class New < Base include Components::Autocompleter::NgSelectAutocompleteHelpers def expect_no_main_menu - expect(page).to have_no_css "#main-menu" + expect(page).to have_no_css '#main-menu' end def click_create - click_button "Create" + click_button 'Create' meeting = Meeting.last @@ -54,7 +54,7 @@ def set_type(type) end def set_title(text) - fill_in "Title", with: text + fill_in 'Title', with: text end def expect_project_dropdown @@ -64,22 +64,22 @@ def expect_project_dropdown def set_project(project) select_autocomplete find("[data-test-selector='project_id']"), query: project.name, - results_selector: "body" + results_selector: 'body' end def set_start_date(date) - find_by_id("meeting_start_date").click + find_by_id('meeting_start_date').click datepicker = Components::BasicDatepicker.new datepicker.set_date(date) end def set_start_time(time) - input = page.find_by_id("meeting-form-start-time") + input = page.find_by_id('meeting-form-start-time') page.execute_script("arguments[0].value = arguments[1]", input.native, time) end def set_duration(duration) - fill_in "Duration", with: duration + fill_in 'Duration', with: duration end def invite(user) diff --git a/modules/meeting/spec/support/pages/meetings/show.rb b/modules/meeting/spec/support/pages/meetings/show.rb index 75c908dfc201..3a3218475595 100644 --- a/modules/meeting/spec/support/pages/meetings/show.rb +++ b/modules/meeting/spec/support/pages/meetings/show.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "base" +require_relative 'base' module Pages::Meetings class Show < Base @@ -83,12 +83,12 @@ def expect_plaintext_location(location) end def meeting_details_container - find(".meeting.details") + find('.meeting.details') end def click_edit - within ".meeting--main-toolbar .toolbar-items" do - click_link "Edit" + within '.meeting--main-toolbar .toolbar-items' do + click_link 'Edit' end end diff --git a/modules/meeting/spec/support/pages/structured_meeting/mobile/show.rb b/modules/meeting/spec/support/pages/structured_meeting/mobile/show.rb index b5a292d1547b..0956e4512226 100644 --- a/modules/meeting/spec/support/pages/structured_meeting/mobile/show.rb +++ b/modules/meeting/spec/support/pages/structured_meeting/mobile/show.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../show" +require_relative '../show' module Pages::StructuredMeeting::Mobile class Show < ::Pages::StructuredMeeting::Show @@ -41,7 +41,7 @@ def open_participant_form within(meeting_details_container) do click_button "Show all" end - expect(page).to have_css("#meetings-sidebar-participants-form-component") + expect(page).to have_css('#meetings-sidebar-participants-form-component') end end end diff --git a/modules/meeting/spec/support/pages/structured_meeting/show.rb b/modules/meeting/spec/support/pages/structured_meeting/show.rb index 6eae44a7c5fe..cfd23e03b0bf 100644 --- a/modules/meeting/spec/support/pages/structured_meeting/show.rb +++ b/modules/meeting/spec/support/pages/structured_meeting/show.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../meetings/show" +require_relative '../meetings/show' module Pages::StructuredMeeting class Show < ::Pages::Meetings::Show @@ -44,12 +44,12 @@ def add_agenda_item(type: MeetingAgendaItem, save: true, &) in_agenda_form do yield - click_button("Save") if save + click_button('Save') if save end end def cancel_add_form - page.within("#meeting-agenda-items-new-component") do + page.within('#meeting-agenda-items-new-component') do click_link I18n.t(:button_cancel) expect(page).to have_no_link I18n.t(:button_cancel) end @@ -63,18 +63,18 @@ def cancel_edit_form(item) end def in_agenda_form(&) - page.within("#meeting-agenda-items-form-component", &) + page.within('#meeting-agenda-items-form-component', &) end def assert_agenda_order!(*titles) retry_block do - found = page.all(:test_id, "op-meeting-agenda-title").map(&:text) + found = page.all(:test_id, 'op-meeting-agenda-title').map(&:text) raise "Expected order of agenda items #{titles.inspect}, but found #{found.inspect}" if titles != found end end def remove_agenda_item(item) - accept_confirm(I18n.t("text_are_you_sure")) do + accept_confirm(I18n.t('text_are_you_sure')) do select_action item, I18n.t(:button_delete) end @@ -82,7 +82,7 @@ def remove_agenda_item(item) end def expect_agenda_item(title:) - expect(page).to have_test_selector("op-meeting-agenda-title", text: title) + expect(page).to have_test_selector('op-meeting-agenda-title', text: title) end def expect_agenda_link(item) @@ -94,7 +94,7 @@ def expect_agenda_link(item) end def expect_agenda_author(name) - expect(page).to have_test_selector("op-principal", text: name) + expect(page).to have_test_selector('op-principal', text: name) end def expect_undisclosed_agenda_link(item) @@ -103,24 +103,24 @@ def expect_undisclosed_agenda_link(item) end def expect_no_agenda_item(title:) - expect(page).not_to have_test_selector("op-meeting-agenda-title", text: title) + expect(page).not_to have_test_selector('op-meeting-agenda-title', text: title) end def select_action(item, action) retry_block do page.within("#meeting-agenda-items-item-component-#{item.id}") do - page.find_test_selector("op-meeting-agenda-actions").click + page.find_test_selector('op-meeting-agenda-actions').click end - page.find(".Overlay") + page.find('.Overlay') end - page.within(".Overlay") do + page.within('.Overlay') do click_on action end end def edit_agenda_item(item, &) - select_action item, "Edit" + select_action item, 'Edit' expect_item_edit_form(item) page.within("#meeting-agenda-items-form-component-#{item.id}", &) end @@ -135,7 +135,7 @@ def expect_item_edit_form(item, visible: true) def expect_item_edit_title(item, value) page.within("#meeting-agenda-items-form-component-#{item.id}") do - find_field("Title", with: value) + find_field('Title', with: value) end end @@ -151,7 +151,7 @@ def clear_item_edit_work_package_title end def in_participant_form(&) - page.within("#meetings-sidebar-participants-form-component form", &) + page.within('#meetings-sidebar-participants-form-component form', &) end def expect_participant(participant, invited: false, attended: false, editable: true) @@ -165,25 +165,25 @@ def invite_participant(participant) end def expect_available_participants(count:) - expect(page).to have_link(class: "op-principal--name", count:) + expect(page).to have_link(class: 'op-principal--name', count:) end def close_meeting - click_button("Close meeting") - expect(page).to have_button("Reopen meeting") + click_button('Close meeting') + expect(page).to have_button('Reopen meeting') end def reopen_meeting - click_button("Reopen meeting") - expect(page).to have_button("Close meeting") + click_button('Reopen meeting') + expect(page).to have_button('Close meeting') end def close_dialog - click_button(class: "Overlay-closeButton") + click_button(class: 'Overlay-closeButton') end def meeting_details_container - find_by_id("meetings-sidebar-details-component") + find_by_id('meetings-sidebar-details-component') end end end diff --git a/modules/meeting/spec/support/pages/work_package_meetings_tab.rb b/modules/meeting/spec/support/pages/work_package_meetings_tab.rb index 6278ddf802af..4010698bc9ee 100644 --- a/modules/meeting/spec/support/pages/work_package_meetings_tab.rb +++ b/modules/meeting/spec/support/pages/work_package_meetings_tab.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rbconfig" -require "support/pages/page" +require 'rbconfig' +require 'support/pages/page' module Pages class MeetingsTab < Page @@ -43,78 +43,78 @@ def path end def expect_tab_present - expect(page).to have_css(".op-tab-row--link", text: "MEETINGS") + expect(page).to have_css('.op-tab-row--link', text: 'MEETINGS') end def expect_tab_count(count) - expect(page).to have_css(".op-tab-row--link", text: "MEETINGS (#{count})", wait: 10) + expect(page).to have_css('.op-tab-row--link', text: "MEETINGS (#{count})", wait: 10) end def expect_tab_not_present - expect(page).to have_no_css(".op-tab-row--link", text: "MEETINGS") + expect(page).to have_no_css('.op-tab-row--link', text: 'MEETINGS') end def expect_tab_content_rendered - expect(page).to have_test_selector("op-work-package-meetings-tab-container") + expect(page).to have_test_selector('op-work-package-meetings-tab-container') end def expect_upcoming_counter_to_be(amount) - page.within_test_selector("op-upcoming-meetings-counter") do + page.within_test_selector('op-upcoming-meetings-counter') do expect(page).to have_content(amount) end end def expect_past_counter_to_be(amount) - page.within_test_selector("op-past-meetings-counter") do + page.within_test_selector('op-past-meetings-counter') do expect(page).to have_content(amount) end end def expect_add_to_meeting_button_present - expect(page).to have_test_selector("op-add-work-package-to-meeting-dialog-trigger") + expect(page).to have_test_selector('op-add-work-package-to-meeting-dialog-trigger') end def expect_add_to_meeting_button_not_present - expect(page).not_to have_test_selector("op-add-work-package-to-meeting-dialog-trigger") + expect(page).not_to have_test_selector('op-add-work-package-to-meeting-dialog-trigger') end def expect_add_to_meeting_dialog_shown - expect(page).to have_test_selector("op-add-work-package-to-meeting-dialog-body") + expect(page).to have_test_selector('op-add-work-package-to-meeting-dialog-body') end def switch_to_upcoming_meetings_section within container_element do - find(".tabnav-tab", text: "Upcoming").click + find('.tabnav-tab', text: 'Upcoming').click end end def switch_to_past_meetings_section within container_element do - find(".tabnav-tab", text: "Past").click + find('.tabnav-tab', text: 'Past').click end end def open_add_to_meeting_dialog - page.find_test_selector("op-add-work-package-to-meeting-dialog-trigger").click + page.find_test_selector('op-add-work-package-to-meeting-dialog-trigger').click end def fill_and_submit_meeting_dialog(meeting, notes) - fill_in("meeting_agenda_item_meeting_id", with: meeting.title) - expect(page).to have_css(".ng-option-marked", text: meeting.title) # wait for selection - page.find(".ng-option-marked").click - page.find(".ck-editor__editable").set(notes) + fill_in('meeting_agenda_item_meeting_id', with: meeting.title) + expect(page).to have_css('.ng-option-marked', text: meeting.title) # wait for selection + page.find('.ng-option-marked').click + page.find('.ck-editor__editable').set(notes) - click_button("Save") + click_button('Save') end private def container_element - page.find_test_selector("op-work-package-meetings-tab-container") + page.find_test_selector('op-work-package-meetings-tab-container') end def osx? - RbConfig::CONFIG["host_os"].include?("darwin") + RbConfig::CONFIG['host_os'].include?('darwin') end end end diff --git a/modules/my_page/Gemfile b/modules/my_page/Gemfile index b4e2a20bb606..fa75df156323 100644 --- a/modules/my_page/Gemfile +++ b/modules/my_page/Gemfile @@ -1,3 +1,3 @@ -source "https://rubygems.org" +source 'https://rubygems.org' gemspec diff --git a/modules/my_page/config/routes.rb b/modules/my_page/config/routes.rb index a29d8d40c028..a25a741b4328 100644 --- a/modules/my_page/config/routes.rb +++ b/modules/my_page/config/routes.rb @@ -27,5 +27,5 @@ #++ Rails.application.routes.draw do - get "/my/page", to: "angular#empty_layout" + get '/my/page', to: 'angular#empty_layout' end diff --git a/modules/my_page/lib/my_page/engine.rb b/modules/my_page/lib/my_page/engine.rb index fc120248e3fb..9da20e2359e7 100644 --- a/modules/my_page/lib/my_page/engine.rb +++ b/modules/my_page/lib/my_page/engine.rb @@ -6,10 +6,10 @@ class Engine < ::Rails::Engine MyPage::GridRegistration.register! end - initializer "my_page.conversion" do + initializer 'my_page.conversion' do require Rails.root.join("config/constants/ar_to_api_conversions") - Constants::ARToAPIConversions.add("grids/my_page": "grid") + Constants::ARToAPIConversions.add('grids/my_page': 'grid') end end end diff --git a/modules/my_page/lib/my_page/grid_registration.rb b/modules/my_page/lib/my_page/grid_registration.rb index 6e0085812dcd..1f4808b98082 100644 --- a/modules/my_page/lib/my_page/grid_registration.rb +++ b/modules/my_page/lib/my_page/grid_registration.rb @@ -1,43 +1,43 @@ module MyPage class GridRegistration < ::Grids::Configuration::Registration - grid_class "Grids::MyPage" + grid_class 'Grids::MyPage' to_scope :my_page_path - widgets "custom_text", - "documents", - "work_packages_assigned", - "work_packages_accountable", - "work_packages_watched", - "work_packages_created", - "work_packages_calendar", - "work_packages_table", - "time_entries_current_user", - "news" + widgets 'custom_text', + 'documents', + 'work_packages_assigned', + 'work_packages_accountable', + 'work_packages_watched', + 'work_packages_created', + 'work_packages_calendar', + 'work_packages_table', + 'time_entries_current_user', + 'news' wp_table_strategy_proc = Proc.new do after_destroy -> { ::Query.find_by(id: options[:queryId])&.destroy } allowed ->(user, _project) { user.allowed_in_any_project?(:save_queries) } - options_representer "::API::V3::Grids::Widgets::QueryOptionsRepresenter" + options_representer '::API::V3::Grids::Widgets::QueryOptionsRepresenter' end - widget_strategy "work_packages_table", &wp_table_strategy_proc - widget_strategy "work_packages_assigned", &wp_table_strategy_proc - widget_strategy "work_packages_accountable", &wp_table_strategy_proc - widget_strategy "work_packages_watched", &wp_table_strategy_proc - widget_strategy "work_packages_created", &wp_table_strategy_proc + widget_strategy 'work_packages_table', &wp_table_strategy_proc + widget_strategy 'work_packages_assigned', &wp_table_strategy_proc + widget_strategy 'work_packages_accountable', &wp_table_strategy_proc + widget_strategy 'work_packages_watched', &wp_table_strategy_proc + widget_strategy 'work_packages_created', &wp_table_strategy_proc - widget_strategy "time_entries_current_user" do - options_representer "::API::V3::Grids::Widgets::TimeEntryCalendarOptionsRepresenter" + widget_strategy 'time_entries_current_user' do + options_representer '::API::V3::Grids::Widgets::TimeEntryCalendarOptionsRepresenter' end - widget_strategy "custom_text" do + widget_strategy 'custom_text' do # Requiring a permission here as one is required to assign attachments. # Should be replaced by a global permission to have a my page allowed ->(user, _project) { user.allowed_in_any_project?(:view_project) } - options_representer "::API::V3::Grids::Widgets::CustomTextOptionsRepresenter" + options_representer '::API::V3::Grids::Widgets::CustomTextOptionsRepresenter' end defaults -> { @@ -46,30 +46,30 @@ class GridRegistration < ::Grids::Configuration::Registration column_count: 2, widgets: [ { - identifier: "work_packages_table", + identifier: 'work_packages_table', start_row: 1, end_row: 2, start_column: 1, end_column: 2, options: { - name: I18n.t("js.grid.widgets.work_packages_assigned.title"), + name: I18n.t('js.grid.widgets.work_packages_assigned.title'), queryProps: { - "columns[]": %w(id project type subject), + 'columns[]': %w(id project type subject), filters: JSON.dump([{ status: { operator: "o", values: [] } }, { assigned_to: { operator: "=", values: ["me"] } }]) } } }, { - identifier: "work_packages_table", + identifier: 'work_packages_table', start_row: 1, end_row: 2, start_column: 2, end_column: 3, options: { - name: I18n.t("js.grid.widgets.work_packages_created.title"), + name: I18n.t('js.grid.widgets.work_packages_created.title'), queryProps: { - "columns[]": %w(id project type subject), + 'columns[]': %w(id project type subject), filters: JSON.dump([{ status: { operator: "o", values: [] } }, { author: { operator: "=", values: ["me"] } }]) } diff --git a/modules/my_page/my_page.gemspec b/modules/my_page/my_page.gemspec index cfe498374cb1..d9bc2a813ab2 100644 --- a/modules/my_page/my_page.gemspec +++ b/modules/my_page/my_page.gemspec @@ -1,11 +1,11 @@ Gem::Specification.new do |s| s.name = "my_page" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = ["OpenProject"] s.summary = "OpenProject MyPage." s.files = Dir["{app,config,db,lib}/**/*"] - s.add_dependency "grids" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'grids' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/my_page/spec/contracts/grids/create_contract_spec.rb b/modules/my_page/spec/contracts/grids/create_contract_spec.rb index 09b554ae265b..0e49aadc67ab 100644 --- a/modules/my_page/spec/contracts/grids/create_contract_spec.rb +++ b/modules/my_page/spec/contracts/grids/create_contract_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe Grids::CreateContract do - include_context "grid contract" - include_context "model contract" + include_context 'grid contract' + include_context 'model contract' - it_behaves_like "shared grid contract attributes" + it_behaves_like 'shared grid contract attributes' - describe "user_id" do - context "for a Grids::MyPage" do + describe 'user_id' do + context 'for a Grids::MyPage' do let(:grid) { build_stubbed(:my_page, default_values) } - it_behaves_like "is writable" do + it_behaves_like 'is writable' do let(:attribute) { :user_id } let(:value) { 5 } end end end - describe "project_id" do - context "for a Grids::MyPage" do + describe 'project_id' do + context 'for a Grids::MyPage' do let(:grid) { build_stubbed(:my_page, default_values) } - it_behaves_like "is not writable" do + it_behaves_like 'is not writable' do let(:attribute) { :project_id } let(:value) { 5 } end diff --git a/modules/my_page/spec/contracts/grids/shared_examples.rb b/modules/my_page/spec/contracts/grids/shared_examples.rb index 82596925ce85..00634fc97938 100644 --- a/modules/my_page/spec/contracts/grids/shared_examples.rb +++ b/modules/my_page/spec/contracts/grids/shared_examples.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "grid contract" do +RSpec.shared_context 'grid contract' do let(:user) { build_stubbed(:user) } let(:instance) { described_class.new(grid, user) } let(:default_values) do @@ -41,12 +41,12 @@ end end -RSpec.shared_examples_for "shared grid contract attributes" do - include_context "model contract" +RSpec.shared_examples_for 'shared grid contract attributes' do + include_context 'model contract' let(:model) { grid } - describe "widgets" do - it_behaves_like "is writable" do + describe 'widgets' do + it_behaves_like 'is writable' do let(:attribute) { :widgets } let(:value) do [ @@ -54,233 +54,233 @@ end_row: 4, start_column: 2, end_column: 5, - identifier: "news") + identifier: 'news') ] end end - context "invalid identifier" do + context 'invalid identifier' do before do grid.widgets.build(start_row: 1, end_row: 4, start_column: 2, end_column: 5, - identifier: "bogus_identifier") + identifier: 'bogus_identifier') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :inclusion }) end end - context "collisions between widgets" do + context 'collisions between widgets' do before do grid.widgets.build(start_row: 1, end_row: 3, start_column: 1, end_column: 3, - identifier: "news") + identifier: 'news') grid.widgets.build(start_row: 2, end_row: 4, start_column: 2, end_column: 4, - identifier: "documents") + identifier: 'documents') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :overlaps }, { error: :overlaps }) end end - context "widgets having the same start column as another's end column" do + context 'widgets having the same start column as another\'s end column' do before do grid.widgets.build(start_row: 1, end_row: 3, start_column: 1, end_column: 3, - identifier: "news") + identifier: 'news') grid.widgets.build(start_row: 1, end_row: 3, start_column: 3, end_column: 4, - identifier: "documents") + identifier: 'documents') end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "widgets having the same start row as another's end row" do + context 'widgets having the same start row as another\'s end row' do before do grid.widgets.build(start_row: 1, end_row: 3, start_column: 1, end_column: 3, - identifier: "news") + identifier: 'news') grid.widgets.build(start_row: 3, end_row: 4, start_column: 1, end_column: 3, - identifier: "documents") + identifier: 'documents') end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "widgets being outside (max) of the grid" do + context 'widgets being outside (max) of the grid' do before do grid.widgets.build(start_row: 1, end_row: grid.row_count + 2, start_column: 1, end_column: 3, - identifier: "news") + identifier: 'news') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :outside }) end end - context "widgets being outside (min) of the grid" do + context 'widgets being outside (min) of the grid' do before do grid.widgets.build(start_row: 1, end_row: 2, start_column: -1, end_column: 3, - identifier: "news") + identifier: 'news') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :outside }) end end - context "widgets spanning the whole grid" do + context 'widgets spanning the whole grid' do before do grid.widgets.build(start_row: 1, end_row: grid.row_count + 1, start_column: 1, end_column: grid.column_count + 1, - identifier: "news") + identifier: 'news') end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "widgets having start after end column" do + context 'widgets having start after end column' do before do grid.widgets.build(start_row: 1, end_row: 2, start_column: 4, end_column: 3, - identifier: "news") + identifier: 'news') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) end end - context "widgets having start after end row" do + context 'widgets having start after end row' do before do grid.widgets.build(start_row: 4, end_row: 2, start_column: 1, end_column: 3, - identifier: "news") + identifier: 'news') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) end end - context "widgets having start equals end column" do + context 'widgets having start equals end column' do before do grid.widgets.build(start_row: 1, end_row: 2, start_column: 4, end_column: 3, - identifier: "news") + identifier: 'news') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) end end - context "widgets having start equals end row" do + context 'widgets having start equals end row' do before do grid.widgets.build(start_row: 2, end_row: 2, start_column: 1, end_column: 3, - identifier: "news") + identifier: 'news') end - it "is invalid" do + it 'is invalid' do expect(instance.validate) .to be_falsey end - it "notes the error" do + it 'notes the error' do instance.validate expect(instance.errors.details[:widgets]) .to contain_exactly({ error: :end_before_start }) @@ -288,19 +288,19 @@ end end - describe "valid grid subclasses" do - context "for a registered subclass" do + describe 'valid grid subclasses' do + context 'for a registered subclass' do let(:grid) do build_stubbed(:my_page, default_values) end - it "is valid" do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "for the Grid superclass itself" do + context 'for the Grid superclass itself' do let(:grid) do build_stubbed(:grid, default_values) end @@ -309,7 +309,7 @@ instance.validate end - it "is invalid for the grid superclass itself" do + it 'is invalid for the grid superclass itself' do expect(instance.errors.details[:scope]) .to contain_exactly({ error: :inclusion }) end diff --git a/modules/my_page/spec/contracts/grids/update_contract_spec.rb b/modules/my_page/spec/contracts/grids/update_contract_spec.rb index 909e8ad7501a..028653ec5398 100644 --- a/modules/my_page/spec/contracts/grids/update_contract_spec.rb +++ b/modules/my_page/spec/contracts/grids/update_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe Grids::UpdateContract do - include_context "model contract" - include_context "grid contract" + include_context 'model contract' + include_context 'grid contract' - it_behaves_like "shared grid contract attributes" + it_behaves_like 'shared grid contract attributes' end diff --git a/modules/my_page/spec/factories/grid_factory.rb b/modules/my_page/spec/factories/grid_factory.rb index be2158a85460..14fb7b9ac8de 100644 --- a/modules/my_page/spec/factories/grid_factory.rb +++ b/modules/my_page/spec/factories/grid_factory.rb @@ -1,19 +1,19 @@ FactoryBot.define do - factory :my_page, class: "Grids::MyPage" do + factory :my_page, class: 'Grids::MyPage' do user row_count { 7 } column_count { 4 } widgets do [ Grids::Widget.new( - identifier: "news", + identifier: 'news', start_row: 1, end_row: 7, start_column: 1, end_column: 3 ), Grids::Widget.new( - identifier: "documents", + identifier: 'documents', start_row: 1, end_row: 7, start_column: 3, diff --git a/modules/my_page/spec/features/my/accountable_spec.rb b/modules/my_page/spec/features/my/accountable_spec.rb index e595cbc5c325..a73ec008d80d 100644 --- a/modules/my_page/spec/features/my/accountable_spec.rb +++ b/modules/my_page/spec/features/my/accountable_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "Accountable widget on my page", :js do +RSpec.describe 'Accountable widget on my page', :js do let!(:type) { create(:type) } let!(:priority) { create(:default_priority) } let!(:project) { create(:project, types: [type]) } @@ -77,12 +77,12 @@ my_page.visit! end - it "can add the widget and see the work packages the user is accountable for" do + it 'can add the widget and see the work packages the user is accountable for' do # Added to ensure the page has finished loading. # The page starts with a "wp created widget". - created_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + created_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') expect(created_area.area) - .to have_css(".subject", text: accountable_work_package.subject) + .to have_css('.subject', text: accountable_work_package.subject) # Add widget below existing widgets my_page.add_widget(2, 2, :row, "Work packages I am accountable for") @@ -92,30 +92,30 @@ # browser can get confused. Therefore we wait. sleep(1) - my_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + my_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') - accountable_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(3)") + accountable_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(3)') accountable_area.expect_to_span(2, 2, 3, 3) - assigned_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + assigned_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') assigned_area.remove - my_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + my_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') - created_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + created_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') created_area.expect_to_span(1, 1, 2, 2) # as the assigned widget was removed, the numbers have changed - accountable_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + accountable_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') accountable_area.expect_to_span(2, 1, 3, 2) expect(accountable_area.area) - .to have_css(".subject", text: accountable_work_package.subject) + .to have_css('.subject', text: accountable_work_package.subject) expect(accountable_area.area) - .to have_no_css(".subject", text: accountable_by_other_work_package.subject) + .to have_no_css('.subject', text: accountable_by_other_work_package.subject) expect(accountable_area.area) - .to have_no_css(".subject", text: accountable_but_invisible_work_package.subject) + .to have_no_css('.subject', text: accountable_but_invisible_work_package.subject) end end diff --git a/modules/my_page/spec/features/my/assigned_to_me_spec.rb b/modules/my_page/spec/features/my/assigned_to_me_spec.rb index fff827fe278d..9c3cbcea941a 100644 --- a/modules/my_page/spec/features/my/assigned_to_me_spec.rb +++ b/modules/my_page/spec/features/my/assigned_to_me_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "Assigned to me embedded query on my page", :js do +RSpec.describe 'Assigned to me embedded query on my page', :js do let!(:type) { create(:type) } let!(:priority) { create(:default_priority) } let!(:project) { create(:project, types: [type]) } @@ -38,7 +38,7 @@ let!(:assigned_work_package) do create(:work_package, project:, - subject: "Assigned to me", + subject: 'Assigned to me', type:, author: user, assigned_to: user) @@ -46,7 +46,7 @@ let!(:assigned_work_package_2) do create(:work_package, project:, - subject: "My task 2", + subject: 'My task 2', type:, author: user, assigned_to: user) @@ -54,7 +54,7 @@ let!(:assigned_to_other_work_package) do create(:work_package, project:, - subject: "Not assigned to me", + subject: 'Not assigned to me', type:, author: user, assigned_to: other_user) @@ -75,17 +75,17 @@ let(:my_page) do Pages::My::Page.new end - let(:assigned_area) { Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") } - let(:created_area) { Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") } + let(:assigned_area) { Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') } + let(:created_area) { Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') } let(:embedded_table) { Pages::EmbeddedWorkPackagesTable.new(assigned_area.area) } let(:hierarchies) { Components::WorkPackages::Hierarchies.new } current_user { user } - context "with parent work package" do + context 'with parent work package' do let!(:assigned_work_package_child) do create(:work_package, - subject: "Child", + subject: 'Child', parent: assigned_work_package, project:, type:, @@ -93,7 +93,7 @@ assigned_to: user) end - it "can toggle hierarchy mode in embedded tables (Regression test #29578)" do + it 'can toggle hierarchy mode in embedded tables (Regression test #29578)' do my_page.visit! # exists as default @@ -127,28 +127,28 @@ end end - it "can create a new ticket with correct me values (Regression test #28488)" do + it 'can create a new ticket with correct me values (Regression test #28488)' do my_page.visit! # exists as default assigned_area.expect_to_exist expect(assigned_area.area) - .to have_css(".subject", text: assigned_work_package.subject) + .to have_css('.subject', text: assigned_work_package.subject) expect(assigned_area.area) - .to have_no_css(".subject", text: assigned_to_other_work_package.subject) + .to have_no_css('.subject', text: assigned_to_other_work_package.subject) embedded_table.click_inline_create subject_field = embedded_table.edit_field(nil, :subject) subject_field.expect_active! - subject_field.set_value "Assigned to me" + subject_field.set_value 'Assigned to me' subject_field.save! embedded_table.expect_toast( - message: "Project can't be blank.", + message: 'Project can\'t be blank.', type: :error ) @@ -159,17 +159,17 @@ project_field.set_value project.name embedded_table.expect_toast( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) wp = WorkPackage.last - expect(wp.subject).to eq("Assigned to me") + expect(wp.subject).to eq('Assigned to me') expect(wp.assigned_to_id).to eq(user.id) embedded_table.expect_work_package_listed wp end - it "can paginate in embedded tables (Regression test #29845)", with_settings: { per_page_options: "1" } do + it 'can paginate in embedded tables (Regression test #29845)', with_settings: { per_page_options: '1' } do my_page.visit! # exists as default @@ -177,21 +177,21 @@ within assigned_area.area do expect(page) - .to have_css(".subject", text: assigned_work_package.subject) + .to have_css('.subject', text: assigned_work_package.subject) expect(page) - .to have_no_css(".subject", text: assigned_work_package_2.subject) + .to have_no_css('.subject', text: assigned_work_package_2.subject) - page.find(".op-pagination--item button", text: "2").click + page.find('.op-pagination--item button', text: '2').click expect(page) - .to have_no_css(".subject", text: assigned_work_package.subject) + .to have_no_css('.subject', text: assigned_work_package.subject) expect(page) - .to have_css(".subject", text: assigned_work_package_2.subject) + .to have_css('.subject', text: assigned_work_package_2.subject) end assigned_area.resize_to(1, 2) - my_page.expect_toast(message: I18n.t("js.notice_successful_update")) + my_page.expect_toast(message: I18n.t('js.notice_successful_update')) assigned_area.expect_to_span(1, 1, 2, 3) # has been moved down by resizing diff --git a/modules/my_page/spec/features/my/custom_text_spec.rb b/modules/my_page/spec/features/my/custom_text_spec.rb index 438277a8944a..78d99a34bd58 100644 --- a/modules/my_page/spec/features/my/custom_text_spec.rb +++ b/modules/my_page/spec/features/my/custom_text_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "Custom text widget on my page", :js do +RSpec.describe 'Custom text widget on my page', :js do let(:permissions) do [] end @@ -49,9 +49,9 @@ let(:my_page) do Pages::My::Page.new end - let(:image_fixture) { UploadedFile.load_from("spec/fixtures/files/image.png") } - let(:editor) { Components::WysiwygEditor.new "body" } - let(:field) { TextEditorField.new(page, "description", selector: ".inline-edit--active-field") } + let(:image_fixture) { UploadedFile.load_from('spec/fixtures/files/image.png') } + let(:editor) { Components::WysiwygEditor.new 'body' } + let(:field) { TextEditorField.new(page, 'description', selector: '.inline-edit--active-field') } before do login_as user @@ -59,56 +59,56 @@ my_page.visit! end - it "can add the widget set custom text and upload attachments" do + it 'can add the widget set custom text and upload attachments' do my_page.add_widget(1, 1, :within, "Custom text") sleep(0.1) # As the user lacks the manage_public_queries and save_queries permission, no other widget is present - custom_text_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + custom_text_widget = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') custom_text_widget.expect_to_span(1, 1, 2, 2) within custom_text_widget.area do - find(".inplace-editing--container").click + find('.inplace-editing--container').click - expect(page).to have_css(".op-uc-container_editing", wait: 10) + expect(page).to have_css('.op-uc-container_editing', wait: 10) - field.set_value("My own little text") + field.set_value('My own little text') field.save! expect(page) - .to have_css(".inline-edit--display-field", text: "My own little text") + .to have_css('.inline-edit--display-field', text: 'My own little text') - find(".inplace-editing--container").click + find('.inplace-editing--container').click - field.set_value("My new text") + field.set_value('My new text') field.cancel_by_click expect(page) - .to have_css(".inline-edit--display-field", text: "My own little text") + .to have_css('.inline-edit--display-field', text: 'My own little text') # adding an image - find(".inplace-editing--container").click + find('.inplace-editing--container').click sleep(0.1) end # The drag_attachment is written in a way that it requires to be executed with page on body # so we cannot have it wrapped in the within block. - editor.drag_attachment image_fixture.path, "Image uploaded" + editor.drag_attachment image_fixture.path, 'Image uploaded' within custom_text_widget.area do - expect(page).to have_test_selector("op-attachment-list-item", text: "image.png") - expect(page).to have_no_css("notifications-upload-progress") + expect(page).to have_test_selector('op-attachment-list-item', text: 'image.png') + expect(page).to have_no_css('notifications-upload-progress') field.save! expect(page) - .to have_css("#content img", count: 1) + .to have_css('#content img', count: 1) expect(page) - .not_to have_test_selector("op-attachment-list-item", text: "image.png") + .not_to have_test_selector('op-attachment-list-item', text: 'image.png') end # ensure no one but the page's user can see the uploaded attachment diff --git a/modules/my_page/spec/features/my/documents_spec.rb b/modules/my_page/spec/features/my/documents_spec.rb index 562e85d40001..f451ccb68edf 100644 --- a/modules/my_page/spec/features/my/documents_spec.rb +++ b/modules/my_page/spec/features/my/documents_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "My page documents widget", :js do +RSpec.describe 'My page documents widget', :js do let!(:project) { create(:project) } let!(:other_project) { create(:project) } let!(:visible_document) do create(:document, project:, - description: "blubs") + description: 'blubs') end let!(:invisible_document) do create(:document, @@ -59,11 +59,11 @@ my_page.visit! end - it "can add the widget and see the visible documents" do + it 'can add the widget and see the visible documents' do # within top-right area, add an additional widget - my_page.add_widget(1, 1, :within, "Documents") + my_page.add_widget(1, 1, :within, 'Documents') - document_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + document_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') document_area.expect_to_span(1, 1, 2, 2) expect(page) @@ -71,7 +71,7 @@ expect(page) .to have_content visible_document.description expect(page) - .to have_content visible_document.created_at.strftime("%m/%d/%Y") + .to have_content visible_document.created_at.strftime('%m/%d/%Y') expect(page) .to have_no_content invisible_document.title diff --git a/modules/my_page/spec/features/my/my_page_spec.rb b/modules/my_page/spec/features/my/my_page_spec.rb index 3058d5d57c9e..7bd0992590d1 100644 --- a/modules/my_page/spec/features/my/my_page_spec.rb +++ b/modules/my_page/spec/features/my/my_page_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "My page", :js do +RSpec.describe 'My page', :js do let!(:type) { create(:type) } let!(:project) { create(:project, types: [type]) } let!(:open_status) { create(:default_status) } @@ -97,9 +97,9 @@ def find_area(name) end end - it "renders the default view, allows altering and saving" do + it 'renders the default view, allows altering and saving' do # Waits for the default view to be created - my_page.expect_toast(message: "Successful update") + my_page.expect_toast(message: 'Successful update') assigned_area.expect_to_exist created_area.expect_to_exist @@ -113,7 +113,7 @@ def find_area(name) .to have_content(assigned_work_package.subject) # add widget above to right area - my_page.add_widget(1, 1, :row, "Calendar") + my_page.add_widget(1, 1, :row, 'Calendar') sleep(0.5) reload_grid! @@ -131,7 +131,7 @@ def find_area(name) calendar_area.expect_to_span(1, 1, 2, 2) # add widget right next to the calendar widget - my_page.add_widget(1, 2, :within, "News") + my_page.add_widget(1, 2, :within, 'News') sleep(0.5) reload_grid! @@ -148,7 +148,7 @@ def find_area(name) assigned_area.expect_to_span(3, 1, 4, 2) created_area.expect_to_span(2, 2, 3, 3) - my_page.add_widget(1, 3, :column, "Work packages watched by me") + my_page.add_widget(1, 3, :column, 'Work packages watched by me') sleep(0.5) reload_grid! @@ -161,7 +161,7 @@ def find_area(name) # that widgets that have been there are moved down created_area.drag_to(1, 3) - my_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + my_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') reload_grid! @@ -176,7 +176,7 @@ def find_area(name) # as no more widgets start in the second column, that column is removed news_area.drag_to(1, 3) - my_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + my_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') reload_grid! diff --git a/modules/my_page/spec/features/my/my_spent_time_widget_with_a_negative_time_zone_spec.rb b/modules/my_page/spec/features/my/my_spent_time_widget_with_a_negative_time_zone_spec.rb index 7c4fa6476b7d..e83329dafc04 100644 --- a/modules/my_page/spec/features/my/my_spent_time_widget_with_a_negative_time_zone_spec.rb +++ b/modules/my_page/spec/features/my/my_spent_time_widget_with_a_negative_time_zone_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "My spent time widget with a negative time zone", :js, +RSpec.describe 'My spent time widget with a negative time zone', :js, driver: :chrome_headless_new, with_settings: { start_of_week: 1 } do let(:beginning_of_week) { monday } @@ -39,11 +39,11 @@ let(:tuesday) { beginning_of_week + 1.day } let(:thursday) { beginning_of_week + 3.days } let(:sunday) { beginning_of_week + 6.days } - let(:time_zone) { "America/Phoenix" } + let(:time_zone) { 'America/Phoenix' } let!(:type) { create(:type) } let!(:project) { create(:project, types: [type]) } - let!(:activity) { create(:time_entry_activity, name: "Development") } + let!(:activity) { create(:time_entry_activity, name: 'Development') } let!(:work_package) do create(:work_package, project:, @@ -71,7 +71,7 @@ # Configure the time zone of the browser # @param [String] time_zone The time zone to set, for instance 'Europe/Paris' def set_browser_time_zone(time_zone) - page.driver.browser.execute_cdp("Emulation.setTimezoneOverride", timezoneId: time_zone) + page.driver.browser.execute_cdp('Emulation.setTimezoneOverride', timezoneId: time_zone) end before do @@ -80,25 +80,25 @@ def set_browser_time_zone(time_zone) my_page.visit! end - it "correctly displays non-working days and prefills day when logging time [fix #49779]" do - my_page.add_widget(1, 1, :within, "My spent time") + it 'correctly displays non-working days and prefills day when logging time [fix #49779]' do + my_page.add_widget(1, 1, :within, 'My spent time') my_page.expect_and_dismiss_toaster message: I18n.t(:notice_successful_update) aggregate_failures("non-working days are displayed properly") do - expect(page).to have_button("Today", disabled: true) - expect(page).to have_no_css(".fc-day-mon.fc-non-working-day", wait: 0) - expect(page).to have_css(".fc-day-tue.fc-non-working-day", wait: 0) - expect(page).to have_no_css(".fc-day-wed.fc-non-working-day", wait: 0) - expect(page).to have_no_css(".fc-day-thu.fc-non-working-day", wait: 0) - expect(page).to have_no_css(".fc-day-fri.fc-non-working-day", wait: 0) - expect(page).to have_css(".fc-day-sat.fc-non-working-day", wait: 0) - expect(page).to have_css(".fc-day-sun.fc-non-working-day", wait: 0) + expect(page).to have_button('Today', disabled: true) + expect(page).to have_no_css('.fc-day-mon.fc-non-working-day', wait: 0) + expect(page).to have_css('.fc-day-tue.fc-non-working-day', wait: 0) + expect(page).to have_no_css('.fc-day-wed.fc-non-working-day', wait: 0) + expect(page).to have_no_css('.fc-day-thu.fc-non-working-day', wait: 0) + expect(page).to have_no_css('.fc-day-fri.fc-non-working-day', wait: 0) + expect(page).to have_css('.fc-day-sat.fc-non-working-day', wait: 0) + expect(page).to have_css('.fc-day-sun.fc-non-working-day', wait: 0) end aggregate_failures("when clicking a day, time entry day is set to the day clicked (Thursday)") do find(".fc-day-thu .te-calendar--add-entry", visible: false).click - time_logging_modal.has_field_with_value "spentOn", thursday.iso8601 + time_logging_modal.has_field_with_value 'spentOn', thursday.iso8601 end end end diff --git a/modules/my_page/spec/features/my/news_spec.rb b/modules/my_page/spec/features/my/news_spec.rb index 853b5ded75bb..a55e7c16f3f5 100644 --- a/modules/my_page/spec/features/my/news_spec.rb +++ b/modules/my_page/spec/features/my/news_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "My page news widget spec", :js do +RSpec.describe 'My page news widget spec', :js do let!(:project) { create(:project) } let!(:other_project) { create(:project) } let!(:visible_news) do create(:news, project:, - description: "blubs") + description: 'blubs') end let!(:invisible_news) do create(:news, @@ -59,12 +59,12 @@ my_page.visit! end - it "can add the widget and see the visible news" do + it 'can add the widget and see the visible news' do # No other widgets exist as the user lacks the permissions for the default widgets # add widget in top right corner - my_page.add_widget(1, 1, :within, "News") + my_page.add_widget(1, 1, :within, 'News') - news_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + news_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') news_area.expect_to_span(1, 1, 2, 2) expect(page) @@ -74,7 +74,7 @@ expect(page) .to have_content visible_news.project.name expect(page) - .to have_content visible_news.created_at.strftime("%m/%d/%Y") + .to have_content visible_news.created_at.strftime('%m/%d/%Y') expect(page) .to have_no_content invisible_news.title diff --git a/modules/my_page/spec/features/my/time_entries_current_user_spec.rb b/modules/my_page/spec/features/my/time_entries_current_user_spec.rb index e7f1e5727bd9..8827bb288977 100644 --- a/modules/my_page/spec/features/my/time_entries_current_user_spec.rb +++ b/modules/my_page/spec/features/my/time_entries_current_user_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "My page time entries current user widget spec", :js do +RSpec.describe 'My page time entries current user widget spec', :js do let!(:type) { create(:type) } let!(:project) { create(:project, types: [type]) } let!(:activity) { create(:time_entry_activity) } @@ -40,14 +40,14 @@ project:, type:, author: user, - subject: "First work package") + subject: 'First work package') end let!(:other_work_package) do create(:work_package, project:, type:, author: user, - subject: "Another task") + subject: 'Another task') end let!(:visible_time_entry) do create(:time_entry, @@ -57,7 +57,7 @@ user:, spent_on: Date.current.beginning_of_week(:sunday) + 1.day, hours: 3, - comments: "My comment") + comments: 'My comment') end let!(:visible_time_entry_on_project) do create(:time_entry, @@ -67,7 +67,7 @@ user:, spent_on: Date.current.beginning_of_week(:sunday) + 1.day, hours: 1, - comments: "My comment") + comments: 'My comment') end let!(:other_visible_time_entry) do create(:time_entry, @@ -77,7 +77,7 @@ user:, spent_on: Date.current.beginning_of_week(:sunday) + 4.days, hours: 2, - comments: "My other comment") + comments: 'My other comment') end let!(:last_week_visible_time_entry) do create(:time_entry, @@ -87,7 +87,7 @@ user:, spent_on: Date.current - (Date.current.wday + 3).days, hours: 8, - comments: "My last week comment") + comments: 'My last week comment') end let!(:invisible_time_entry) do create(:time_entry, @@ -120,53 +120,53 @@ my_page.visit! end - it "adds the widget which then displays time entries and allows manipulating them" do + it 'adds the widget which then displays time entries and allows manipulating them' do # within top-right area, add an additional widget - my_page.add_widget(1, 1, :within, "My spent time") + my_page.add_widget(1, 1, :within, 'My spent time') - entries_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") + entries_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') my_page.expect_and_dismiss_toaster message: I18n.t(:notice_successful_update) entries_area.expect_to_span(1, 1, 2, 2) - expect(page).to have_no_css(".fc-day-mon.fc-non-working-day") - expect(page).to have_no_css(".fc-day-tue.fc-non-working-day") - expect(page).to have_no_css(".fc-day-wed.fc-non-working-day") - expect(page).to have_no_css(".fc-day-thu.fc-non-working-day") - expect(page).to have_no_css(".fc-day-fri.fc-non-working-day") - expect(page).to have_css(".fc-day-sat.fc-non-working-day") - expect(page).to have_css(".fc-day-sun.fc-non-working-day") + expect(page).to have_no_css('.fc-day-mon.fc-non-working-day') + expect(page).to have_no_css('.fc-day-tue.fc-non-working-day') + expect(page).to have_no_css('.fc-day-wed.fc-non-working-day') + expect(page).to have_no_css('.fc-day-thu.fc-non-working-day') + expect(page).to have_no_css('.fc-day-fri.fc-non-working-day') + expect(page).to have_css('.fc-day-sat.fc-non-working-day') + expect(page).to have_css('.fc-day-sun.fc-non-working-day') expect(page) .to have_content "Total: 6 h" expect(page) - .to have_content visible_time_entry.spent_on.strftime("%-m/%-d") + .to have_content visible_time_entry.spent_on.strftime('%-m/%-d') expect(page) - .to have_css(".fc-event .fc-event-title", text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") + .to have_css('.fc-event .fc-event-title', text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") expect(page) - .to have_content(other_visible_time_entry.spent_on.strftime("%-m/%-d")) + .to have_content(other_visible_time_entry.spent_on.strftime('%-m/%-d')) expect(page) - .to have_css(".fc-event .fc-event-title", text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") + .to have_css('.fc-event .fc-event-title', text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") # go to last week within entries_area.area do - find(".fc-toolbar .fc-prev-button").click + find('.fc-toolbar .fc-prev-button').click end expect(page) .to have_content "Total: 8 h" expect(page) - .to have_content(last_week_visible_time_entry.spent_on.strftime("%-m/%-d")) + .to have_content(last_week_visible_time_entry.spent_on.strftime('%-m/%-d')) expect(page) - .to have_css(".fc-event .fc-event-title", text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") + .to have_css('.fc-event .fc-event-title', text: "#{project.name} - ##{work_package.id}: #{work_package.subject}") # go to today again within entries_area.area do - find(".fc-toolbar .fc-today-button").click + find('.fc-toolbar .fc-today-button').click end expect(page) @@ -177,7 +177,7 @@ end expect(page) - .to have_css(".ui-tooltip", text: "Project: #{project.name}") + .to have_css('.ui-tooltip', text: "Project: #{project.name}") # Adding a time entry @@ -190,32 +190,32 @@ time_logging_modal.work_package_is_missing true - time_logging_modal.has_field_with_value "spentOn", (Date.current.beginning_of_week(:sunday) + 3.days).strftime + time_logging_modal.has_field_with_value 'spentOn', (Date.current.beginning_of_week(:sunday) + 3.days).strftime - time_logging_modal.shows_field "user", false + time_logging_modal.shows_field 'user', false expect(page) - .to have_no_css(".ng-spinner-loader") + .to have_no_css('.ng-spinner-loader') # Expect filtering works time_logging_modal.work_package_field.autocomplete work_package.subject, select: false - expect(page).to have_test_selector("op-autocompleter-item-subject", text: work_package.subject) - expect(page).not_to have_test_selector("op-autocompleter-item-subject", text: other_work_package.subject) + expect(page).to have_test_selector('op-autocompleter-item-subject', text: work_package.subject) + expect(page).not_to have_test_selector('op-autocompleter-item-subject', text: other_work_package.subject) time_logging_modal.update_work_package_field other_work_package.subject time_logging_modal.work_package_is_missing false - time_logging_modal.update_field "comment", "Comment for new entry" + time_logging_modal.update_field 'comment', 'Comment for new entry' - time_logging_modal.update_field "activity", activity.name + time_logging_modal.update_field 'activity', activity.name - time_logging_modal.update_field "hours", 4 + time_logging_modal.update_field 'hours', 4 sleep(0.1) - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' time_logging_modal.is_visible false my_page.expect_and_dismiss_toaster message: I18n.t(:notice_successful_create) @@ -240,19 +240,19 @@ time_logging_modal.is_visible true - time_logging_modal.update_field "activity", other_activity.name + time_logging_modal.update_field 'activity', other_activity.name # As the other_work_package now has time logged, it is now considered to be a # recent work package. time_logging_modal.update_work_package_field other_work_package.subject, true - time_logging_modal.update_field "hours", 6 + time_logging_modal.update_field 'hours', 6 - time_logging_modal.update_field "comment", "Some comment" + time_logging_modal.update_field 'comment', 'Some comment' - cf_field.set_value("Cf text value") + cf_field.set_value('Cf text value') - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' time_logging_modal.is_visible false sleep(0.1) @@ -263,32 +263,32 @@ end expect(page) - .to have_css(".ui-tooltip", text: "Work package: ##{other_work_package.id}: #{other_work_package.subject}") + .to have_css('.ui-tooltip', text: "Work package: ##{other_work_package.id}: #{other_work_package.subject}") expect(page) - .to have_css(".ui-tooltip", text: "Hours: 6 h") + .to have_css('.ui-tooltip', text: "Hours: 6 h") expect(page) - .to have_css(".ui-tooltip", text: "Activity: #{other_activity.name}") + .to have_css('.ui-tooltip', text: "Activity: #{other_activity.name}") expect(page) - .to have_css(".ui-tooltip", text: "Comment: Some comment") + .to have_css('.ui-tooltip', text: "Comment: Some comment") expect(page) .to have_content "Total: 13 h" ## Hiding weekdays - entries_area.click_menu_item I18n.t("js.grid.configure") + entries_area.click_menu_item I18n.t('js.grid.configure') - uncheck "Monday" # the day visible_time_entry is logged for + uncheck 'Monday' # the day visible_time_entry is logged for - click_button "Apply" + click_button 'Apply' within entries_area.area do expect(page) - .to have_no_css(".fc-day-header", text: "Mon") + .to have_no_css('.fc-day-header', text: 'Mon') expect(page) - .to have_no_css(".fc-duration", text: "6 h") + .to have_no_css('.fc-duration', text: "6 h") end ## Removing the time entry @@ -300,7 +300,7 @@ end time_logging_modal.is_visible true - time_logging_modal.perform_action "Delete" + time_logging_modal.perform_action 'Delete' page.driver.browser.switch_to.alert.accept time_logging_modal.is_visible false @@ -325,7 +325,7 @@ .to have_css(".te-calendar--time-entry", count: 1) expect(page) - .to have_no_css(".fc-col-header-cell", text: "Mon") + .to have_no_css('.fc-col-header-cell', text: 'Mon') end # Removing the widget diff --git a/modules/my_page/spec/features/my/work_package_table_spec.rb b/modules/my_page/spec/features/my/work_package_table_spec.rb index ed49057a3a2f..05b3b564014c 100644 --- a/modules/my_page/spec/features/my/work_package_table_spec.rb +++ b/modules/my_page/spec/features/my/work_package_table_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../../support/pages/my/page" +require_relative '../../support/pages/my/page' -RSpec.describe "Arbitrary WorkPackage query table widget on my page", :js do +RSpec.describe 'Arbitrary WorkPackage query table widget on my page', :js do let!(:type) { create(:type) } let!(:other_type) { create(:type) } let!(:priority) { create(:default_priority) } @@ -72,13 +72,13 @@ my_page.visit! end - context "with the permission to save queries" do - it "can add the widget and see the work packages of the filtered for types" do + context 'with the permission to save queries' do + it 'can add the widget and see the work packages of the filtered for types' do # This one always exists by default. # Using it here as a safeguard to govern speed. - created_by_me_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") + created_by_me_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') expect(created_by_me_area.area) - .to have_css(".subject", text: type_work_package.subject) + .to have_css('.subject', text: type_work_package.subject) my_page.add_widget(1, 2, :column, "Work packages table") @@ -87,50 +87,50 @@ # browser can get confused. Therefore we wait. sleep(2) - my_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + my_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') - filter_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(3)") + filter_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(3)') filter_area.expect_to_span(1, 2, 2, 3) # At the beginning, the default query is displayed expect(filter_area.area) - .to have_css(".subject", text: type_work_package.subject) + .to have_css('.subject', text: type_work_package.subject) expect(filter_area.area) - .to have_css(".subject", text: other_type_work_package.subject) + .to have_css('.subject', text: other_type_work_package.subject) # User has the ability to modify the query filter_area.configure_wp_table - modal.switch_to("Filters") + modal.switch_to('Filters') filters.expect_filter_count(2) - filters.add_filter_by("Type", "is (OR)", type.name) + filters.add_filter_by('Type', 'is (OR)', type.name) modal.save filter_area.configure_wp_table - modal.switch_to("Columns") + modal.switch_to('Columns') columns.assume_opened - columns.remove "Subject" + columns.remove 'Subject' expect(filter_area.area) - .to have_css(".id", text: type_work_package.id) + .to have_css('.id', text: type_work_package.id) # as the Subject column is disabled expect(filter_area.area) - .to have_no_css(".subject", text: type_work_package.subject) + .to have_no_css('.subject', text: type_work_package.subject) # As other_type is filtered out expect(filter_area.area) - .to have_no_css(".id", text: other_type_work_package.id) + .to have_no_css('.id', text: other_type_work_package.id) scroll_to_element(filter_area.area) within filter_area.area do - input = find(".editable-toolbar-title--input") - input.set("My WP Filter") + input = find('.editable-toolbar-title--input') + input.set('My WP Filter') input.native.send_keys(:return) end - my_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + my_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') sleep(1) @@ -140,28 +140,28 @@ visit root_path my_page.visit! - filter_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(3)") + filter_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(3)') expect(filter_area.area) - .to have_css(".id", text: type_work_package.id) + .to have_css('.id', text: type_work_package.id) # as the Subject column is disabled expect(filter_area.area) - .to have_no_css(".subject", text: type_work_package.subject) + .to have_no_css('.subject', text: type_work_package.subject) # As other_type is filtered out expect(filter_area.area) - .to have_no_css(".id", text: other_type_work_package.id) + .to have_no_css('.id', text: other_type_work_package.id) within filter_area.area do - expect(page).to have_field("editable-toolbar-title", with: "My WP Filter", wait: 10) + expect(page).to have_field('editable-toolbar-title', with: 'My WP Filter', wait: 10) end end end - context "without the permission to save queries" do + context 'without the permission to save queries' do let(:permissions) { %i[view_work_packages add_work_packages] } - it "cannot add the widget" do + it 'cannot add the widget' do my_page.expect_unable_to_add_widget(1, 1, :within, "Work packages table") end end diff --git a/modules/my_page/spec/models/grids/my_page_spec.rb b/modules/my_page/spec/models/grids/my_page_spec.rb index 07d81f91096d..c6e763ec9380 100644 --- a/modules/my_page/spec/models/grids/my_page_spec.rb +++ b/modules/my_page/spec/models/grids/my_page_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "shared_model" +require_relative 'shared_model' RSpec.describe Grids::MyPage do let(:instance) { described_class.new(row_count: 5, column_count: 5) } let(:user) { build_stubbed(:user) } - it_behaves_like "grid attributes" + it_behaves_like 'grid attributes' - context "attributes" do - it "#user" do + context 'attributes' do + it '#user' do instance.user = user expect(instance.user) .to eql user end end - context "altering widgets" do - context "when removing a work_packages_table widget" do + context 'altering widgets' do + context 'when removing a work_packages_table widget' do let(:user) { create(:user) } let(:query) do create(:query, @@ -53,7 +53,7 @@ end before do - widget = Grids::Widget.new(identifier: "work_packages_table", + widget = Grids::Widget.new(identifier: 'work_packages_table', start_row: 1, end_row: 2, start_column: 1, @@ -64,7 +64,7 @@ instance.save! end - it "removes the widget's query" do + it 'removes the widget\'s query' do instance.widgets = [] expect(Query.find_by(id: query.id)) diff --git a/modules/my_page/spec/models/grids/shared_model.rb b/modules/my_page/spec/models/grids/shared_model.rb index ff54c7b20eb1..57adc5aeba52 100644 --- a/modules/my_page/spec/models/grids/shared_model.rb +++ b/modules/my_page/spec/models/grids/shared_model.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "grid attributes" do - describe "attributes" do - it "#row_count" do +RSpec.shared_examples_for 'grid attributes' do + describe 'attributes' do + it '#row_count' do instance.row_count = 5 expect(instance.row_count) .to be 5 end - it "#column_count" do + it '#column_count' do instance.column_count = 5 expect(instance.column_count) .to be 5 end - it "#name" do - instance.name = "custom 123" + it '#name' do + instance.name = 'custom 123' expect(instance.name) - .to eql "custom 123" + .to eql 'custom 123' # can be empty instance.name = nil expect(instance).to be_valid end - it "#options" do + it '#options' do value = { - some: "value", + some: 'value', and: { also: 1 } @@ -63,7 +63,7 @@ .to eql value end - it "#widgets" do + it '#widgets' do widgets = [ Grids::Widget.new(start_row: 2), Grids::Widget.new(start_row: 5) diff --git a/modules/my_page/spec/queries/grids/filters/scope_filter_spec.rb b/modules/my_page/spec/queries/grids/filters/scope_filter_spec.rb index 52e45760069d..4a96fd9c9611 100644 --- a/modules/my_page/spec/queries/grids/filters/scope_filter_spec.rb +++ b/modules/my_page/spec/queries/grids/filters/scope_filter_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Grids::Filters::ScopeFilter, type: :model do - include_context "filter tests" - let(:values) { ["/my/page"] } + include_context 'filter tests' + let(:values) { ['/my/page'] } let(:user) { build_stubbed(:user) } let(:model) { Grids::Grid } @@ -38,19 +38,19 @@ login_as(user) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :scope } let(:type) { :list } let(:model) { Grids::Grid.where(user_id: user.id) } - let(:values) { ["/my/page"] } + let(:values) { ['/my/page'] } end - describe "#scope" do + describe '#scope' do context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - context "for /my/page do" do - it "is the same as handwriting the query" do + context 'for /my/page do' do + it 'is the same as handwriting the query' do expected = model.where("(grids.type IN ('Grids::MyPage'))") expect(instance.scope.to_sql).to eql expected.to_sql diff --git a/modules/my_page/spec/queries/grids/query_integration_spec.rb b/modules/my_page/spec/queries/grids/query_integration_spec.rb index 2ba8a1e4f3c4..1197ed5c1bd3 100644 --- a/modules/my_page/spec/queries/grids/query_integration_spec.rb +++ b/modules/my_page/spec/queries/grids/query_integration_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Grids::Query, type: :model do let(:user) { create(:user) } @@ -43,32 +43,32 @@ login_as(user) end - context "without a filter" do - describe "#results" do - it "is the same as getting all the grids visible to the user" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the grids visible to the user' do expect(instance.results).to contain_exactly(my_page_grid) end end end - context "with a scope filter" do + context 'with a scope filter' do before do - instance.where("scope", "=", ["/my/page"]) + instance.where('scope', '=', ['/my/page']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expect(instance.results).to contain_exactly(my_page_grid) end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("scope", "!", ["/some/other/page"]) + it 'is invalid if the filter is invalid' do + instance.where('scope', '!', ['/some/other/page']) expect(instance).to be_invalid end end diff --git a/modules/my_page/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb b/modules/my_page/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb index 5428eadaf247..9175e3717dfd 100644 --- a/modules/my_page/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb +++ b/modules/my_page/spec/requests/api/v3/grids/grids_create_form_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "POST /api/v3/grids/form", content_type: :json do include Rack::Test::Methods @@ -50,22 +50,22 @@ login_as(current_user) end - describe "#post" do + describe '#post' do before do - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "contains a Schema embedding the available values" do + it 'contains a Schema embedding the available values' do expect(subject.body) .to be_json_eql("Schema".to_json) - .at_path("_embedded/schema/_type") + .at_path('_embedded/schema/_type') expect(subject.body) .to be_json_eql(my_page_path.to_json) - .at_path("_embedded/schema/scope/_links/allowedValues/0/href") + .at_path('_embedded/schema/scope/_links/allowedValues/0/href') end - context "with /my/page for the scope value" do + context 'with /my/page for the scope value' do let(:params) do { _links: { @@ -76,7 +76,7 @@ } end - it "contains default data in the payload" do + it 'contains default data in the payload' do expected = { rowCount: 1, columnCount: 2, @@ -84,11 +84,11 @@ widgets: [ { _type: "GridWidget", - identifier: "work_packages_table", + identifier: 'work_packages_table', options: { name: "Work packages assigned to me", queryProps: { - "columns[]": %w(id project type subject), + 'columns[]': %w(id project type subject), filters: "[{\"status\":{\"operator\":\"o\",\"values\":[]}},{\"assigned_to\":{\"operator\":\"=\",\"values\":[\"me\"]}}]" } }, @@ -99,11 +99,11 @@ }, { _type: "GridWidget", - identifier: "work_packages_table", + identifier: 'work_packages_table', options: { name: "Work packages created by me", queryProps: { - "columns[]": %w(id project type subject), + 'columns[]': %w(id project type subject), filters: "[{\"status\":{\"operator\":\"o\",\"values\":[]}},{\"author\":{\"operator\":\"=\",\"values\":[\"me\"]}}]" } }, @@ -124,23 +124,23 @@ expect(subject.body) .to be_json_eql(expected.to_json) - .at_path("_embedded/payload") + .at_path('_embedded/payload') end - it "has no validationErrors" do + it 'has no validationErrors' do expect(subject.body) .to be_json_eql({}.to_json) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.grids.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "with an unsupported widget identifier" do + context 'with an unsupported widget identifier' do let(:params) do { _links: { @@ -161,17 +161,17 @@ } end - it "has a validationError on widget" do + it 'has a validationError on widget' do expect(subject.body) .to be_json_eql("Widgets is not set to one of the allowed values.".to_json) - .at_path("_embedded/validationErrors/widgets/message") + .at_path('_embedded/validationErrors/widgets/message') end end - context "with name set" do + context 'with name set' do let(:params) do { - name: "My custom grid 1", + name: 'My custom grid 1', _links: { scope: { href: my_page_path @@ -180,18 +180,18 @@ } end - it "feeds it back" do + it 'feeds it back' do expect(subject.body) .to be_json_eql("My custom grid 1".to_json) - .at_path("_embedded/payload/name") + .at_path('_embedded/payload/name') end end - context "with options set" do + context 'with options set' do let(:params) do { options: { - foo: "bar" + foo: 'bar' }, _links: { scope: { @@ -201,10 +201,10 @@ } end - it "feeds them back" do + it 'feeds them back' do expect(subject.body) .to be_json_eql("bar".to_json) - .at_path("_embedded/payload/options/foo") + .at_path('_embedded/payload/options/foo') end end end diff --git a/modules/my_page/spec/requests/api/v3/grids/grids_resource_spec.rb b/modules/my_page/spec/requests/api/v3/grids/grids_resource_spec.rb index 110bb9d1d629..7ab52ed79da9 100644 --- a/modules/my_page/spec/requests/api/v3/grids/grids_resource_spec.rb +++ b/modules/my_page/spec/requests/api/v3/grids/grids_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Grids resource", content_type: :json do +RSpec.describe 'API v3 Grids resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -49,7 +49,7 @@ subject(:response) { last_response } - describe "#get INDEX" do + describe '#get INDEX' do let(:path) { api_v3_paths.grids } let(:stored_grids) do @@ -63,21 +63,21 @@ get path end - it "sends a collection of grids but only those visible to the current user" do + it 'sends a collection of grids but only those visible to the current user' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_embedded/elements/0/_type") + .to be_json_eql('Grid'.to_json) + .at_path('_embedded/elements/0/_type') expect(subject.body) .to be_json_eql(1.to_json) - .at_path("total") + .at_path('total') end - context "with a filter on the scope attribute" do + context 'with a filter on the scope attribute' do shared_let(:other_grid) do grid = Grids::Grid.new(row_count: 20, column_count: 20) @@ -97,36 +97,36 @@ end let(:path) do - filter = [{ "scope" => + filter = [{ 'scope' => { - "operator" => "=", - "values" => [my_page_path] + 'operator' => '=', + 'values' => [my_page_path] } }] "#{api_v3_paths.grids}?#{{ filters: filter.to_json }.to_query}" end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "sends only the my page of the current user" do + it 'sends only the my page of the current user' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_embedded/elements/0/_type") + .to be_json_eql('Grid'.to_json) + .at_path('_embedded/elements/0/_type') expect(subject.body) .to be_json_eql(1.to_json) - .at_path("total") + .at_path('total') end end end - describe "#get" do + describe '#get' do let(:path) { api_v3_paths.grid(my_page_grid.id) } let(:stored_grids) do @@ -139,35 +139,35 @@ get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "sends a grid block" do + it 'sends a grid block' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') end - it "identifies the url the grid is stored for" do + it 'identifies the url the grid is stored for' do expect(subject.body) .to be_json_eql(my_page_path.to_json) - .at_path("_links/scope/href") + .at_path('_links/scope/href') end - context "with the page not existing" do + context 'with the page not existing' do let(:stored_grids) do # no pages exist so the page requests for is not existing as well end let(:path) { api_v3_paths.grid(5) } - it "responds with 404 NOT FOUND" do + it 'responds with 404 NOT FOUND' do expect(subject.status).to be 404 end end - context "with the grid belonging to someone else" do + context 'with the grid belonging to someone else' do let(:stored_grids) do my_page_grid other_my_page_grid @@ -175,19 +175,19 @@ let(:path) { api_v3_paths.grid(other_my_page_grid.id) } - it "responds with 404 NOT FOUND" do + it 'responds with 404 NOT FOUND' do expect(subject.status).to be 404 end end end - describe "#patch" do + describe '#patch' do let(:path) { api_v3_paths.grid(my_page_grid.id) } let(:params) do { rowCount: 10, - name: "foo", + name: 'foo', columnCount: 15, widgets: [{ identifier: "documents", @@ -206,34 +206,34 @@ before do stored_grids - patch path, params.to_json, "CONTENT_TYPE" => "application/json" + patch path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns the altered grid block" do + it 'returns the altered grid block' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("foo".to_json) - .at_path("name") + .to be_json_eql('foo'.to_json) + .at_path('name') expect(subject.body) - .to be_json_eql(params["rowCount"].to_json) - .at_path("rowCount") + .to be_json_eql(params['rowCount'].to_json) + .at_path('rowCount') expect(subject.body) - .to be_json_eql(params["widgets"][0]["identifier"].to_json) - .at_path("widgets/0/identifier") + .to be_json_eql(params['widgets'][0]['identifier'].to_json) + .at_path('widgets/0/identifier') end - it "perists the changes" do + it 'perists the changes' do expect(my_page_grid.reload.row_count) - .to eql params["rowCount"] + .to eql params['rowCount'] end - context "with invalid params" do + context 'with invalid params' do let(:params) do { rowCount: -5, @@ -248,42 +248,42 @@ }.with_indifferent_access end - it "responds with 422 and mentions the error" do + it 'responds with 422 and mentions the error' do expect(subject.status).to eq 422 - expect(JSON.parse(subject.body)["_embedded"]["errors"].map { |e| e["message"] }) + expect(JSON.parse(subject.body)['_embedded']['errors'].map { |e| e['message'] }) .to contain_exactly("Widgets is outside of the grid.", "Number of rows must be greater than 0.") end - it "does not persist the changes to widgets" do + it 'does not persist the changes to widgets' do expect(my_page_grid.reload.widgets.count) .to eql MyPage::GridRegistration.defaults[:widgets].size end end - context "with a scope param" do + context 'with a scope param' do let(:params) do { _links: { scope: { - href: "" + href: '' } } }.with_indifferent_access end - it_behaves_like "read-only violation", "scope", Grids::Grid + it_behaves_like 'read-only violation', 'scope', Grids::Grid end - context "with the page not existing" do + context 'with the page not existing' do let(:path) { api_v3_paths.grid(5) } - it "responds with 404 NOT FOUND" do + it 'responds with 404 NOT FOUND' do expect(subject.status).to be 404 end end - context "with the grid belonging to someone else" do + context 'with the grid belonging to someone else' do let(:stored_grids) do my_page_grid other_my_page_grid @@ -291,13 +291,13 @@ let(:path) { api_v3_paths.grid(other_my_page_grid.id) } - it "responds with 404 NOT FOUND" do + it 'responds with 404 NOT FOUND' do expect(subject.status).to be 404 end end end - describe "#post" do + describe '#post' do let(:path) { api_v3_paths.grids } let(:params) do @@ -320,31 +320,31 @@ end before do - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end - it "responds with 201 CREATED" do + it 'responds with 201 CREATED' do expect(subject.status).to eq(201) end - it "returns the created grid block" do + it 'returns the created grid block' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql(params["rowCount"].to_json) - .at_path("rowCount") + .to be_json_eql(params['rowCount'].to_json) + .at_path('rowCount') expect(subject.body) - .to be_json_eql(params["widgets"][0]["identifier"].to_json) - .at_path("widgets/0/identifier") + .to be_json_eql(params['widgets'][0]['identifier'].to_json) + .at_path('widgets/0/identifier') end - it "persists the grid" do + it 'persists the grid' do expect(Grids::Grid.count) .to be(1) end - context "with invalid params" do + context 'with invalid params' do let(:params) do { rowCount: -5, @@ -364,21 +364,21 @@ }.with_indifferent_access end - it "responds with 422" do + it 'responds with 422' do expect(subject.status).to eq(422) end - it "does not create a grid" do + it 'does not create a grid' do expect(Grids::Grid.count) .to be(0) end - it "returns the errors" do + it 'returns the errors' do expect(subject.body) - .to be_json_eql("Error".to_json) - .at_path("_type") + .to be_json_eql('Error'.to_json) + .at_path('_type') - expect(JSON.parse(subject.body)["_embedded"]["errors"].map { |e| e["message"] }) + expect(JSON.parse(subject.body)['_embedded']['errors'].map { |e| e['message'] }) .to contain_exactly("Widgets is outside of the grid.", "Number of rows must be greater than 0.", "Number of columns must be greater than 0.") end diff --git a/modules/my_page/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb b/modules/my_page/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb index 94541a5fc656..62a9bfb99129 100644 --- a/modules/my_page/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb +++ b/modules/my_page/spec/requests/api/v3/grids/grids_update_form_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "PATCH /api/v3/grids/:id/form", content_type: :json do include Rack::Test::Methods @@ -49,9 +49,9 @@ login_as(current_user) end - describe "#post" do + describe '#post' do before do - post path, params.to_json, "CONTENT_TYPE" => "application/json" + post path, params.to_json, 'CONTENT_TYPE' => 'application/json' end let(:expected_payload) do @@ -62,7 +62,7 @@ widgets: [ { _type: "GridWidget", - identifier: "news", + identifier: 'news', options: {}, startRow: 1, endRow: 7, @@ -71,7 +71,7 @@ }, { _type: "GridWidget", - identifier: "documents", + identifier: 'documents', options: {}, startRow: 1, endRow: 7, @@ -89,58 +89,58 @@ } end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be 200 end - it "is of type form" do + it 'is of type form' do expect(subject.body) .to be_json_eql("Form".to_json) - .at_path("_type") + .at_path('_type') end - it "contains a Schema disallowing setting scope" do + it 'contains a Schema disallowing setting scope' do expect(subject.body) .to be_json_eql("Schema".to_json) - .at_path("_embedded/schema/_type") + .at_path('_embedded/schema/_type') expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/schema/scope/writable") + .at_path('_embedded/schema/scope/writable') end - it "contains the current data in the payload" do + it 'contains the current data in the payload' do expect(subject.body) .to be_json_eql(expected_payload.to_json) - .at_path("_embedded/payload") + .at_path('_embedded/payload') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.grid(grid.id).to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end - context "with some value for the scope value" do + context 'with some value for the scope value' do let(:params) do { _links: { scope: { - href: "/some/path" + href: '/some/path' } } } end - it "has a validation error on scope as the value is not writable" do + it 'has a validation error on scope as the value is not writable' do expect(subject.body) .to be_json_eql("Scope was attempted to be written but is not writable.".to_json) - .at_path("_embedded/validationErrors/scope/message") + .at_path('_embedded/validationErrors/scope/message') end end - context "with an unsupported widget identifier" do + context 'with an unsupported widget identifier' do let(:params) do { widgets: [ @@ -156,20 +156,20 @@ } end - it "has a validationError on widget" do + it 'has a validationError on widget' do expect(subject.body) .to be_json_eql("Widgets is not set to one of the allowed values.".to_json) - .at_path("_embedded/validationErrors/widgets/message") + .at_path('_embedded/validationErrors/widgets/message') end end - context "for another user's grid" do + context 'for another user\'s grid' do let(:other_user) { create(:user) } let(:other_grid) { create(:my_page, user: other_user) } let(:path) { api_v3_paths.grid_form(other_grid.id) } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be 404 end diff --git a/modules/my_page/spec/support/pages/my/page.rb b/modules/my_page/spec/support/pages/my/page.rb index 92a06968f905..40953ee0257c 100644 --- a/modules/my_page/spec/support/pages/my/page.rb +++ b/modules/my_page/spec/support/pages/my/page.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' -require_relative "../../../../../grids/spec/support/pages/grid" +require_relative '../../../../../grids/spec/support/pages/grid' module Pages module My diff --git a/modules/openid_connect/app/components/openid_connect/providers/row_component.rb b/modules/openid_connect/app/components/openid_connect/providers/row_component.rb index 220b156153cd..350b8473d53f 100644 --- a/modules/openid_connect/app/components/openid_connect/providers/row_component.rb +++ b/modules/openid_connect/app/components/openid_connect/providers/row_component.rb @@ -14,9 +14,9 @@ def name def row_css_class [ - "openid-connect--provider-row", + 'openid-connect--provider-row', "openid-connect--provider-row-#{model.id}" - ].join(" ") + ].join(' ') end ### @@ -27,7 +27,7 @@ def button_links def edit_link link_to( - helpers.op_icon("icon icon-edit button--link"), + helpers.op_icon('icon icon-edit button--link'), url_for(action: :edit, id: provider.id), title: t(:button_edit) ) @@ -35,7 +35,7 @@ def edit_link def delete_link link_to( - helpers.op_icon("icon icon-delete button--link"), + helpers.op_icon('icon icon-delete button--link'), url_for(action: :destroy, id: provider.id), method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, diff --git a/modules/openid_connect/app/components/openid_connect/providers/table_component.rb b/modules/openid_connect/app/components/openid_connect/providers/table_component.rb index 8b4225548255..781baa1a11dc 100644 --- a/modules/openid_connect/app/components/openid_connect/providers/table_component.rb +++ b/modules/openid_connect/app/components/openid_connect/providers/table_component.rb @@ -12,12 +12,12 @@ def sortable? end def empty_row_message - I18n.t "openid_connect.providers.no_results_table" + I18n.t 'openid_connect.providers.no_results_table' end def headers [ - ["name", { caption: I18n.t("attributes.name") }] + ['name', { caption: I18n.t('attributes.name') }] ] end end diff --git a/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb b/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb index f3f817ffc720..38c504544b9f 100644 --- a/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb +++ b/modules/openid_connect/app/controllers/openid_connect/providers_controller.rb @@ -1,6 +1,6 @@ module OpenIDConnect class ProvidersController < ::ApplicationController - layout "admin" + layout 'admin' menu_item :plugin_openid_connect before_action :require_admin @@ -56,7 +56,7 @@ def destroy def check_ee unless EnterpriseToken.allows_to?(:openid_providers) - render template: "/openid_connect/providers/upsale" + render template: '/openid_connect/providers/upsale' false end end @@ -91,8 +91,8 @@ def openid_connect_providers_available_for_configure helper_method :openid_connect_providers_available_for_configure def default_breadcrumb - if action_name != "index" - ActionController::Base.helpers.link_to(t("openid_connect.providers.plural"), openid_connect_providers_path) + if action_name != 'index' + ActionController::Base.helpers.link_to(t('openid_connect.providers.plural'), openid_connect_providers_path) end end diff --git a/modules/openid_connect/app/models/openid_connect/user_session_link.rb b/modules/openid_connect/app/models/openid_connect/user_session_link.rb index baa3caab442a..26bfb6a53969 100644 --- a/modules/openid_connect/app/models/openid_connect/user_session_link.rb +++ b/modules/openid_connect/app/models/openid_connect/user_session_link.rb @@ -1,7 +1,7 @@ module OpenIDConnect class UserSessionLink < ::ApplicationRecord - self.table_name = "oidc_user_session_links" + self.table_name = 'oidc_user_session_links' - belongs_to :session, class_name: "Sessions::UserSession", dependent: :delete + belongs_to :session, class_name: 'Sessions::UserSession', dependent: :delete end end diff --git a/modules/openid_connect/app/session/session_controller.rb b/modules/openid_connect/app/session/session_controller.rb index c86ec40f5065..aa327273930b 100644 --- a/modules/openid_connect/app/session/session_controller.rb +++ b/modules/openid_connect/app/session/session_controller.rb @@ -2,7 +2,7 @@ class SessionController < ActionController::Base def logout_warning url = signin_url back_url: params[:back_url] - render "logout_warning", locals: { message: link_i18n(:logout_warning, url) } + render 'logout_warning', locals: { message: link_i18n(:logout_warning, url) } end private diff --git a/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb b/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb index 2f244dabd588..95a6f1b60342 100644 --- a/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb +++ b/modules/openid_connect/app/views/openid_connect/providers/edit.html.erb @@ -11,7 +11,7 @@ html: { class: 'form', autocomplete: 'off' } do |f| %> <%= render partial: "form", locals: { f: f } %>

    - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { action: :index }, class: 'button -with-icon icon-cancel' %>

    <% end %> diff --git a/modules/openid_connect/app/views/openid_connect/providers/index.html.erb b/modules/openid_connect/app/views/openid_connect/providers/index.html.erb index 415c998f96ff..f84ddf5283bf 100644 --- a/modules/openid_connect/app/views/openid_connect/providers/index.html.erb +++ b/modules/openid_connect/app/views/openid_connect/providers/index.html.erb @@ -4,7 +4,7 @@ <%= toolbar title: t('openid_connect.providers.plural') do %>
  • <%= link_to new_openid_connect_provider_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t('openid_connect.providers.label_add_new')}, title: t('openid_connect.providers.label_add_new')} do %> <%= op_icon('button--icon icon-add') %> diff --git a/modules/openid_connect/app/views/openid_connect/providers/new.html.erb b/modules/openid_connect/app/views/openid_connect/providers/new.html.erb index c7cbf0dce176..2ffecfae30b8 100644 --- a/modules/openid_connect/app/views/openid_connect/providers/new.html.erb +++ b/modules/openid_connect/app/views/openid_connect/providers/new.html.erb @@ -12,7 +12,7 @@ html: { class: 'form', autocomplete: 'off' } do |f| %> <%= render partial: "form", locals: { f: f } %>

    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { action: :index }, class: 'button -with-icon icon-cancel' %>

    <% end %> diff --git a/modules/openid_connect/config/routes.rb b/modules/openid_connect/config/routes.rb index d10644fbc8fe..f27795fcca78 100644 --- a/modules/openid_connect/config/routes.rb +++ b/modules/openid_connect/config/routes.rb @@ -1,5 +1,5 @@ Rails.application.routes.draw do - get "/session/logout_warning", to: "session#logout_warning" + get '/session/logout_warning', to: 'session#logout_warning' scope :admin do namespace :openid_connect do diff --git a/modules/openid_connect/db/migrate/20221122072857_add_oidc_session_link.rb b/modules/openid_connect/db/migrate/20221122072857_add_oidc_session_link.rb index b90addd98a0e..f0fb006652b3 100644 --- a/modules/openid_connect/db/migrate/20221122072857_add_oidc_session_link.rb +++ b/modules/openid_connect/db/migrate/20221122072857_add_oidc_session_link.rb @@ -34,7 +34,7 @@ def change ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.create_unlogged_tables = true create_table :oidc_user_session_links do |t| t.string :oidc_session, null: false, index: true - t.references :session, index: true, foreign_key: { to_table: "sessions", on_delete: :cascade } + t.references :session, index: true, foreign_key: { to_table: 'sessions', on_delete: :cascade } t.timestamps end diff --git a/modules/openid_connect/lib/open_project/openid_connect.rb b/modules/openid_connect/lib/open_project/openid_connect.rb index c9331a39ee5d..f10bee5d4172 100644 --- a/modules/openid_connect/lib/open_project/openid_connect.rb +++ b/modules/openid_connect/lib/open_project/openid_connect.rb @@ -1,10 +1,10 @@ -require "omniauth/openid_connect" -require "omniauth/openid_connect/providers" -require "open_project/openid_connect/engine" +require 'omniauth/openid_connect' +require 'omniauth/openid_connect/providers' +require 'open_project/openid_connect/engine' module OpenProject module OpenIDConnect - CONFIG_KEY = "openid_connect".freeze + CONFIG_KEY = 'openid_connect'.freeze def providers # update base redirect URI in case settings changed diff --git a/modules/openid_connect/lib/open_project/openid_connect/hooks/hook.rb b/modules/openid_connect/lib/open_project/openid_connect/hooks/hook.rb index 2d3b92c952d9..c3411f64c7df 100644 --- a/modules/openid_connect/lib/open_project/openid_connect/hooks/hook.rb +++ b/modules/openid_connect/lib/open_project/openid_connect/hooks/hook.rb @@ -34,7 +34,7 @@ class Hook < OpenProject::Hook::Listener # we want to map that to the internal session def user_logged_in(context) session = context[:session] - oidc_sid = session["omniauth.oidc_sid"] + oidc_sid = session['omniauth.oidc_sid'] return if oidc_sid.nil? ::OpenProject::OpenIDConnect::SessionMapper.handle_login(oidc_sid, session) diff --git a/modules/openid_connect/lib/openproject-openid_connect.rb b/modules/openid_connect/lib/openproject-openid_connect.rb index 74691683e7e7..66b53f45ae8f 100644 --- a/modules/openid_connect/lib/openproject-openid_connect.rb +++ b/modules/openid_connect/lib/openproject-openid_connect.rb @@ -1 +1 @@ -require "open_project/openid_connect" +require 'open_project/openid_connect' diff --git a/modules/openid_connect/openproject-openid_connect.gemspec b/modules/openid_connect/openproject-openid_connect.gemspec index 929e867192c6..2763f0ef235d 100644 --- a/modules/openid_connect/openproject-openid_connect.gemspec +++ b/modules/openid_connect/openproject-openid_connect.gemspec @@ -1,16 +1,16 @@ Gem::Specification.new do |s| - s.name = "openproject-openid_connect" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject OpenID Connect" - s.description = "Adds OmniAuth OpenID Connect strategy providers to Openproject." - s.license = "GPLv3" + s.name = 'openproject-openid_connect' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject OpenID Connect' + s.description = 'Adds OmniAuth OpenID Connect strategy providers to Openproject.' + s.license = 'GPLv3' - s.files = Dir["{app,config,db,lib}/**/*"] + %w(CHANGELOG.md README.md) + s.files = Dir['{app,config,db,lib}/**/*'] + %w(CHANGELOG.md README.md) - s.add_dependency "lobby_boy", "~> 0.1.3" - s.add_dependency "omniauth-openid_connect-providers", "~> 0.1" - s.add_dependency "openproject-auth_plugins" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'lobby_boy', '~> 0.1.3' + s.add_dependency 'omniauth-openid_connect-providers', '~> 0.1' + s.add_dependency 'openproject-auth_plugins' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/openid_connect/spec/controllers/providers_controller_spec.rb b/modules/openid_connect/spec/controllers/providers_controller_spec.rb index 16fb9165fef0..807343eb2f8e 100644 --- a/modules/openid_connect/spec/controllers/providers_controller_spec.rb +++ b/modules/openid_connect/spec/controllers/providers_controller_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenIDConnect::ProvidersController do let(:user) { build_stubbed(:admin) } let(:valid_params) do { - name: "azure", + name: 'azure', identifier: "IDENTIFIER", secret: "SECRET" } @@ -43,54 +43,54 @@ login_as user end - context "without an EE token", with_ee: false do - it "renders upsale" do + context 'without an EE token', with_ee: false do + it 'renders upsale' do get :index expect(response).to have_http_status(:ok) - expect(response).to render_template "openid_connect/providers/upsale" + expect(response).to render_template 'openid_connect/providers/upsale' end end - context "with an EE token", with_ee: %i[openid_providers] do + context 'with an EE token', with_ee: %i[openid_providers] do before do login_as user end - context "when not admin" do + context 'when not admin' do let(:user) { build_stubbed(:user) } - it "renders 403" do + it 'renders 403' do get :index expect(response).to have_http_status(:forbidden) end end - context "when not logged in" do + context 'when not logged in' do let(:user) { User.anonymous } - it "renders 403" do + it 'renders 403' do get :index expect(response.status).to redirect_to(signin_url(back_url: openid_connect_providers_url)) end end - describe "#index" do - it "renders the index page" do + describe '#index' do + it 'renders the index page' do get :index expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end end - describe "#new" do - it "renders the new page" do + describe '#new' do + it 'renders the new page' do get :new expect(response).to be_successful expect(assigns[:provider]).to be_new_record - expect(response).to render_template "new" + expect(response).to render_template 'new' end - it "redirects to the index page if no provider available", with_settings: { + it 'redirects to the index page if no provider available', with_settings: { plugin_openproject_openid_connect: { "providers" => OpenIDConnect::Provider::ALLOWED_TYPES.inject({}) do |accu, name| accu.merge(name => { "identifier" => "IDENTIFIER", "secret" => "SECRET" }) @@ -102,64 +102,64 @@ end end - describe "#create" do - context "with valid params" do + describe '#create' do + context 'with valid params' do let(:params) { { openid_connect_provider: valid_params } } before do post :create, params: end - it "is successful" do + it 'is successful' do expect(flash[:notice]).to eq(I18n.t(:notice_successful_create)) expect(Setting.plugin_openproject_openid_connect["providers"]).to have_key("azure") expect(response).to be_redirect end - context "with limit_self_registration checked" do + context 'with limit_self_registration checked' do let(:params) do { openid_connect_provider: valid_params.merge(limit_self_registration: 1) } end - it "sets the setting" do + it 'sets the setting' do expect(OpenProject::Plugins::AuthPlugin) .to be_limit_self_registration provider: valid_params[:name] end end - context "with limit_self_registration unchecked" do + context 'with limit_self_registration unchecked' do let(:params) do { openid_connect_provider: valid_params.merge(limit_self_registration: 0) } end - it "does not set the setting" do + it 'does not set the setting' do expect(OpenProject::Plugins::AuthPlugin) .not_to be_limit_self_registration provider: valid_params[:name] end end end - it "renders an error if invalid params" do + it 'renders an error if invalid params' do post :create, params: { openid_connect_provider: valid_params.merge(identifier: "") } - expect(response).to render_template "new" + expect(response).to render_template 'new' end end - describe "#edit" do - context "when found", with_settings: { + describe '#edit' do + context 'when found', with_settings: { plugin_openproject_openid_connect: { "providers" => { "azure" => { "identifier" => "IDENTIFIER", "secret" => "SECRET" } } } } do - it "renders the edit page" do - get :edit, params: { id: "azure" } + it 'renders the edit page' do + get :edit, params: { id: 'azure' } expect(response).to be_successful expect(assigns[:provider]).to be_present - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end context( - "with limit_self_registration set", + 'with limit_self_registration set', with_settings: { plugin_openproject_openid_connect: { "providers" => { @@ -173,43 +173,43 @@ } ) do before do - get :edit, params: { id: "azure" } + get :edit, params: { id: 'azure' } end - it "shows limit_self_registration as checked" do + it 'shows limit_self_registration as checked' do expect(assigns[:provider]).to be_limit_self_registration end end - context "with limit_self_registration not set" do + context 'with limit_self_registration not set' do before do - get :edit, params: { id: "azure" } + get :edit, params: { id: 'azure' } end - it "shows limit_self_registration as checked" do + it 'shows limit_self_registration as checked' do expect(assigns[:provider]).to be_limit_self_registration end end end - context "when not found" do - it "renders 404" do - get :edit, params: { id: "doesnoexist" } + context 'when not found' do + it 'renders 404' do + get :edit, params: { id: 'doesnoexist' } expect(response).not_to be_successful expect(response).to have_http_status(:not_found) end end end - describe "#update" do - context "when found" do + describe '#update' do + context 'when found' do before do Setting.plugin_openproject_openid_connect = { "providers" => { "azure" => { "identifier" => "IDENTIFIER", "secret" => "SECRET" } } } end - it "successfully updates the provider configuration" do + it 'successfully updates the provider configuration' do put :update, params: { id: "azure", openid_connect_provider: valid_params.merge(secret: "NEWSECRET") } expect(response).to be_redirect expect(flash[:notice]).to be_present @@ -217,12 +217,12 @@ expect(provider.secret).to eq("NEWSECRET") end - context "with limit_self_registration checked" do + context 'with limit_self_registration checked' do let(:params) do - { id: "azure", openid_connect_provider: valid_params.merge(limit_self_registration: 1) } + { id: 'azure', openid_connect_provider: valid_params.merge(limit_self_registration: 1) } end - it "sets the setting" do + it 'sets the setting' do put(:update, params:) expect(OpenProject::Plugins::AuthPlugin) @@ -232,12 +232,12 @@ end end - context "with limit_self_registration unchecked" do + context 'with limit_self_registration unchecked' do let(:params) do { id: :azure, openid_connect_provider: valid_params.merge(limit_self_registration: 0) } end - it "does not set the setting" do + it 'does not set the setting' do put(:update, params:) expect(OpenProject::Plugins::AuthPlugin) @@ -250,15 +250,15 @@ end end - describe "#destroy" do - context "when found" do + describe '#destroy' do + context 'when found' do before do Setting.plugin_openproject_openid_connect = { "providers" => { "azure" => { "identifier" => "IDENTIFIER", "secret" => "SECRET" } } } end - it "removes the provider" do + it 'removes the provider' do delete :destroy, params: { id: "azure" } expect(response).to be_redirect expect(flash[:notice]).to be_present diff --git a/modules/openid_connect/spec/factories/user_session_link_factory.rb b/modules/openid_connect/spec/factories/user_session_link_factory.rb index 4f6d5c681711..e85d6659ae7e 100644 --- a/modules/openid_connect/spec/factories/user_session_link_factory.rb +++ b/modules/openid_connect/spec/factories/user_session_link_factory.rb @@ -1,6 +1,6 @@ FactoryBot.define do - factory :user_session_link, class: "OpenIDConnect::UserSessionLink" do + factory :user_session_link, class: 'OpenIDConnect::UserSessionLink' do session { nil } - oidc_session { "foobar" } + oidc_session { 'foobar' } end end diff --git a/modules/openid_connect/spec/lib/session_mapper_spec.rb b/modules/openid_connect/spec/lib/session_mapper_spec.rb index ff0ff73afe6c..011000df1c90 100644 --- a/modules/openid_connect/spec/lib/session_mapper_spec.rb +++ b/modules/openid_connect/spec/lib/session_mapper_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::OpenIDConnect::SessionMapper do let(:mock_session) do @@ -39,34 +39,34 @@ def initialize(id) end end - describe "handle_login" do - let(:session) { mock_session.new("foo") } + describe 'handle_login' do + let(:session) { mock_session.new('foo') } let!(:plain_session) { create(:user_session, session_id: session.id.private_id) } let!(:user_session) { Sessions::UserSession.find_by(session_id: plain_session.session_id) } - subject { described_class.handle_login "oidc_sid_foo", session } + subject { described_class.handle_login 'oidc_sid_foo', session } - it "creates a user link object" do + it 'creates a user link object' do expect { subject }.to change(OpenIDConnect::UserSessionLink, :count).by(1) link = OpenIDConnect::UserSessionLink.find_by(session_id: user_session.id) expect(link).to be_present expect(link.session).to eq user_session - expect(link.oidc_session).to eq "oidc_sid_foo" + expect(link.oidc_session).to eq 'oidc_sid_foo' end end - describe "handle_logout" do - let(:token) { instance_double(OmniAuth::OpenIDConnect::LogoutToken, sid: "oidc_foobar") } + describe 'handle_logout' do + let(:token) { instance_double(OmniAuth::OpenIDConnect::LogoutToken, sid: 'oidc_foobar') } subject { described_class.handle_logout token } - context "when an unrelated session exists" do - let!(:plain_session) { create(:user_session, session_id: "internal_foobar") } - let!(:user_session) { Sessions::UserSession.find_by(session_id: "internal_foobar") } - let!(:link) { create(:user_session_link, oidc_session: "other_oidc_sid", session: user_session) } + context 'when an unrelated session exists' do + let!(:plain_session) { create(:user_session, session_id: 'internal_foobar') } + let!(:user_session) { Sessions::UserSession.find_by(session_id: 'internal_foobar') } + let!(:link) { create(:user_session_link, oidc_session: 'other_oidc_sid', session: user_session) } - it "does not delete it" do + it 'does not delete it' do expect { subject }.not_to change(OpenIDConnect::UserSessionLink, :count) expect { link.reload }.not_to raise_error @@ -74,12 +74,12 @@ def initialize(id) end end - context "when a linked session exists" do - let!(:plain_session) { create(:user_session, session_id: "internal_foobar") } - let!(:user_session) { Sessions::UserSession.find_by(session_id: "internal_foobar") } - let!(:link) { create(:user_session_link, oidc_session: "oidc_foobar", session: user_session) } + context 'when a linked session exists' do + let!(:plain_session) { create(:user_session, session_id: 'internal_foobar') } + let!(:user_session) { Sessions::UserSession.find_by(session_id: 'internal_foobar') } + let!(:link) { create(:user_session_link, oidc_session: 'oidc_foobar', session: user_session) } - it "deletes the linked session" do + it 'deletes the linked session' do expect { subject }.to change(OpenIDConnect::UserSessionLink, :count).by(-1) expect { link.reload }.to raise_error(ActiveRecord::RecordNotFound) diff --git a/modules/openid_connect/spec/models/openid_connect/provider_spec.rb b/modules/openid_connect/spec/models/openid_connect/provider_spec.rb index 13e74ddea3f5..8ce328858bfc 100644 --- a/modules/openid_connect/spec/models/openid_connect/provider_spec.rb +++ b/modules/openid_connect/spec/models/openid_connect/provider_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenIDConnect::Provider do let(:params) do @@ -40,19 +40,19 @@ def auth_plugin OpenProject::Plugins::AuthPlugin end - describe "limit_self_registration" do + describe 'limit_self_registration' do before do # required so that the auth plugin sees any providers (ee feature) allow(EnterpriseToken).to receive(:show_banners?).and_return false end - context "with no limited providers" do + context 'with no limited providers' do it "shows the provider as limited" do provider.save expect(auth_plugin).to be_limit_self_registration provider: provider.name end - context "when set to true" do + context 'when set to true' do let(:params) do { limit_self_registration: true } end @@ -64,7 +64,7 @@ def auth_plugin end end - context "when set to false" do + context 'when set to false' do let(:params) do { limit_self_registration: false } end @@ -78,7 +78,7 @@ def auth_plugin end context( - "with a limited provider", + 'with a limited provider', with_settings: { plugin_openproject_openid_connect: { "providers" => { diff --git a/modules/openid_connect/spec/models/user_session_link_spec.rb b/modules/openid_connect/spec/models/user_session_link_spec.rb index 3a892242bd07..ccbee29d7609 100644 --- a/modules/openid_connect/spec/models/user_session_link_spec.rb +++ b/modules/openid_connect/spec/models/user_session_link_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenIDConnect::UserSessionLink do - describe "session" do + describe 'session' do let(:plain_session) { create(:user_session) } let(:user_session) { Sessions::UserSession.find_by(session_id: plain_session.session_id) } let(:link) { create(:user_session_link, session: user_session) } - it "gets deleted when session is deleted" do + it 'gets deleted when session is deleted' do expect(link).to be_present expect(link.session).to eq user_session diff --git a/modules/openid_connect/spec/requests/openid_connect_spec.rb b/modules/openid_connect/spec/requests/openid_connect_spec.rb index c09af595b26b..9b5f4687973f 100644 --- a/modules/openid_connect/spec/requests/openid_connect_spec.rb +++ b/modules/openid_connect/spec/requests/openid_connect_spec.rb @@ -26,24 +26,24 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "openid_connect_spec_helpers" +require 'spec_helper' +require_relative 'openid_connect_spec_helpers' RSpec.configure do |c| c.include OpenIDConnectSpecHelpers end -RSpec.describe "OpenID Connect", :skip_2fa_stage, # Prevent redirects to 2FA stage +RSpec.describe 'OpenID Connect', :skip_2fa_stage, # Prevent redirects to 2FA stage type: :rails_request, with_ee: %i[openid_providers] do - let(:host) { OmniAuth::OpenIDConnect::Heroku.new("foo", {}).host } + let(:host) { OmniAuth::OpenIDConnect::Heroku.new('foo', {}).host } let(:user_info) do { - sub: "87117114115116", - name: "Hans Wurst", - email: "h.wurst@finn.de", - given_name: "Hans", - family_name: "Wurst" + sub: '87117114115116', + name: 'Hans Wurst', + email: 'h.wurst@finn.de', + given_name: 'Hans', + family_name: 'Wurst' } end @@ -51,7 +51,7 @@ # The redirect will include an authorisation code. # Since we don't actually get a valid code in the test we will stub the resulting AccessToken. allow_any_instance_of(OpenIDConnect::Client).to receive(:access_token!) do - OpenIDConnect::AccessToken.new client: self, access_token: "foo bar baz" + OpenIDConnect::AccessToken.new client: self, access_token: 'foo bar baz' end # Using the granted AccessToken the client then performs another request to the OpenID Connect @@ -65,19 +65,19 @@ # be true. end - describe "sign-up and login" do + describe 'sign-up and login' do before do allow(Setting).to receive(:plugin_openproject_openid_connect).and_return( - "providers" => { - "heroku" => { - "identifier" => "does not", - "secret" => "matter" + 'providers' => { + 'heroku' => { + 'identifier' => 'does not', + 'secret' => 'matter' } } ) end - it "works" do + it 'works' do ## # it should redirect to the provider's openid connect authentication endpoint click_on_signin @@ -85,11 +85,11 @@ expect(response).to have_http_status :found expect(response.location).to match /https:\/\/#{host}.*$/ - params = Rack::Utils.parse_nested_query(response.location.gsub(/^.*\?/, "")) + params = Rack::Utils.parse_nested_query(response.location.gsub(/^.*\?/, '')) - expect(params).to include "client_id" - expect(params["redirect_uri"]).to match /^.*\/auth\/heroku\/callback$/ - expect(params["scope"]).to include "openid" + expect(params).to include 'client_id' + expect(params['redirect_uri']).to match /^.*\/auth\/heroku\/callback$/ + expect(params['scope']).to include 'openid' ## # it should redirect back from the provider to the login page @@ -102,7 +102,7 @@ # remove this guard once we are on v4.1 if OpenProject::OmniAuth::Authorization.method(:after_login!).arity.abs > 2 # check that cookie is stored in the access token - expect(response.cookies["_open_project_session_access_token"]).to eq "foo bar baz" + expect(response.cookies['_open_project_session_access_token']).to eq 'foo bar baz' end user = User.find_by(mail: user_info[:email]) @@ -129,68 +129,68 @@ expect(response.location).to match /\/my\/page/ end - context "with a custom claim and mapping" do + context 'with a custom claim and mapping' do let(:user_info) do { - sub: "87117114115116", - name: "Hans Wurst", - email: "h.wurst@finn.de", - given_name: "Hans", - family_name: "Wurst", - foobar: "a.truly.random.value" + sub: '87117114115116', + name: 'Hans Wurst', + email: 'h.wurst@finn.de', + given_name: 'Hans', + family_name: 'Wurst', + foobar: 'a.truly.random.value' } end before do allow(Setting).to receive(:plugin_openproject_openid_connect).and_return( - "providers" => { - "heroku" => { - "attribute_map" => { login: :foobar }, - "identifier" => "does not", - "secret" => "matter" + 'providers' => { + 'heroku' => { + 'attribute_map' => { login: :foobar }, + 'identifier' => 'does not', + 'secret' => 'matter' } } ) end - it "maps to the login" do + it 'maps to the login' do click_on_signin redirect_from_provider - user = User.find_by(login: "a.truly.random.value") + user = User.find_by(login: 'a.truly.random.value') expect(user).to be_present end end end - context "provider configuration through the settings" do + context 'provider configuration through the settings' do before do allow(Setting).to receive(:plugin_openproject_openid_connect).and_return( - "providers" => { - "google" => { - "identifier" => "does not", - "secret" => "matter" + 'providers' => { + 'google' => { + 'identifier' => 'does not', + 'secret' => 'matter' }, - "azure" => { - "identifier" => "IDENTIFIER", - "secret" => "SECRET" + 'azure' => { + 'identifier' => 'IDENTIFIER', + 'secret' => 'SECRET' } } ) end - it "shows no option unless EE", with_ee: false do - get "/login" + it 'shows no option unless EE', with_ee: false do + get '/login' expect(response.body).not_to match /Google/i expect(response.body).not_to match /Azure/i end - it "makes providers that have been configured through settings available without requiring a restart" do - get "/login" + it 'makes providers that have been configured through settings available without requiring a restart' do + get '/login' expect(response.body).to match /Google/i expect(response.body).to match /Azure/i - expect { click_on_signin("google") }.not_to raise_error + expect { click_on_signin('google') }.not_to raise_error expect(response).to have_http_status :found end end diff --git a/modules/openid_connect/spec/requests/openid_connect_spec_helpers.rb b/modules/openid_connect/spec/requests/openid_connect_spec_helpers.rb index 042b30cd42f7..b90aba9383f0 100644 --- a/modules/openid_connect/spec/requests/openid_connect_spec_helpers.rb +++ b/modules/openid_connect/spec/requests/openid_connect_spec_helpers.rb @@ -1,15 +1,15 @@ module OpenIDConnectSpecHelpers - def redirect_from_provider(name = "heroku") + def redirect_from_provider(name = 'heroku') # Emulate the provider's redirect with a nonsense code. get "/auth/#{name}/callback", params: { - code: "foobar", + code: 'foobar', redirect_uri: "http://localhost:3000/auth/#{name}/callback", - state: session["omniauth.state"] + state: session['omniauth.state'] } end - def click_on_signin(pro_name = "heroku") + def click_on_signin(pro_name = 'heroku') # Emulate click on sign-in for that particular provider get "/auth/#{pro_name}" end diff --git a/modules/openid_connect/spec/routing/openid_connect/providers_controller_spec.rb b/modules/openid_connect/spec/routing/openid_connect/providers_controller_spec.rb index 3058687a042c..3ec5958538e8 100644 --- a/modules/openid_connect/spec/routing/openid_connect/providers_controller_spec.rb +++ b/modules/openid_connect/spec/routing/openid_connect/providers_controller_spec.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "OpenIDConnect Providers" do - it "routes to index" do - expect(get("/admin/openid_connect/providers")).to route_to("openid_connect/providers#index") +RSpec.describe 'OpenIDConnect Providers' do + it 'routes to index' do + expect(get('/admin/openid_connect/providers')).to route_to('openid_connect/providers#index') end - it "routes to new" do - expect(get("/admin/openid_connect/providers/new")).to route_to("openid_connect/providers#new") + it 'routes to new' do + expect(get('/admin/openid_connect/providers/new')).to route_to('openid_connect/providers#new') end - it "routes to edit" do - expect(get("/admin/openid_connect/providers/azure/edit")).to( + it 'routes to edit' do + expect(get('/admin/openid_connect/providers/azure/edit')).to( route_to( - controller: "openid_connect/providers", - action: "edit", - id: "azure" + controller: 'openid_connect/providers', + action: 'edit', + id: 'azure' ) ) end - it "routes to destroy" do - expect(delete("/admin/openid_connect/providers/azure")).to( + it 'routes to destroy' do + expect(delete('/admin/openid_connect/providers/azure')).to( route_to( - controller: "openid_connect/providers", - action: "destroy", - id: "azure" + controller: 'openid_connect/providers', + action: 'destroy', + id: 'azure' ) ) end diff --git a/modules/openid_connect/spec/spec_helper.rb b/modules/openid_connect/spec/spec_helper.rb index 671fd6c8666d..f8ec36959dea 100644 --- a/modules/openid_connect/spec/spec_helper.rb +++ b/modules/openid_connect/spec/spec_helper.rb @@ -1 +1 @@ -require "spec_helper" +require 'spec_helper' diff --git a/modules/overviews/db/migrate/20190826083604_my_project_page_to_grid.rb b/modules/overviews/db/migrate/20190826083604_my_project_page_to_grid.rb index 34decad8baa4..ecc54a71ccfd 100644 --- a/modules/overviews/db/migrate/20190826083604_my_project_page_to_grid.rb +++ b/modules/overviews/db/migrate/20190826083604_my_project_page_to_grid.rb @@ -29,7 +29,7 @@ class MyProjectPageToGrid < ActiveRecord::Migration[5.2] # rubocop:disable Rails/ApplicationRecord class MyPageEntry < ActiveRecord::Base - self.table_name = "my_projects_overviews" + self.table_name = 'my_projects_overviews' serialize :top serialize :left @@ -77,7 +77,7 @@ def remove_my_page_table def add_permission Role .includes(:role_permissions) - .where(role_permissions: { permission: "edit_project" }) + .where(role_permissions: { permission: 'edit_project' }) .each do |role| role.add_permission!(:manage_overview) end @@ -101,19 +101,19 @@ def create_grid(entry) def move_attachments(entry, grid) Attachment .where(container_type: "MyProjectsOverview", container_id: entry.id) - .update_all(container_type: "Grids::Grid", container_id: grid.id) + .update_all(container_type: 'Grids::Grid', container_id: grid.id) end def build_widget(grid, widget_config, position) method = case widget_config when Array :build_custom_text_widget - when "project_details" + when 'project_details' :build_project_details_widget - when "work_packages_assigned_to_me", - "work_packages_reported_by_me", - "work_packages_responsible_for", - "work_packages_watched" + when 'work_packages_assigned_to_me', + 'work_packages_reported_by_me', + 'work_packages_responsible_for', + 'work_packages_watched' :build_wp_table_widget else :build_default_widget @@ -123,7 +123,7 @@ def build_widget(grid, widget_config, position) end def build_custom_text_widget(grid, widget_config, position) - build_widget_with_options(grid, "custom_text", position) do |options| + build_widget_with_options(grid, 'custom_text', position) do |options| name = widget_config[1].presence || grid.project.name options[:name] = name @@ -132,8 +132,8 @@ def build_custom_text_widget(grid, widget_config, position) end def build_project_details_widget(grid, _identifier, position) - build_default_widget(grid, "subprojects", position) - build_default_widget(grid, "project_details", position) + build_default_widget(grid, 'subprojects', position) + build_default_widget(grid, 'project_details', position) end def build_wp_table_widget(grid, identifier, position) @@ -165,13 +165,13 @@ def build_widget_with_options(grid, identifier, position) def new_name(name) { - news_latest: "news", - work_package_tracking: "work_packages_overview", - spent_time: "time_entries_list", - work_packages_assigned_to_me: "work_packages_table", - work_packages_reported_by_me: "work_packages_table", - work_packages_responsible_for: "work_packages_table", - work_packages_watched: "work_packages_table" + news_latest: 'news', + work_package_tracking: 'work_packages_overview', + spent_time: 'time_entries_list', + work_packages_assigned_to_me: 'work_packages_table', + work_packages_reported_by_me: 'work_packages_table', + work_packages_responsible_for: 'work_packages_table', + work_packages_watched: 'work_packages_table' }.with_indifferent_access[name] || name end @@ -213,11 +213,11 @@ def next_right_position(grid) end def applicable? - ActiveRecord::Base.connection.table_exists?("my_projects_overviews") + ActiveRecord::Base.connection.table_exists?('my_projects_overviews') end def attachments(id) - Attachment.where(container_type: "MyProjectsOverview", container_id: id) + Attachment.where(container_type: 'MyProjectsOverview', container_id: id) end def new_default_query(attributes = nil) @@ -229,13 +229,13 @@ def new_default_query(attributes = nil) end def query(grid, identifier) - query = new_default_query name: "_", + query = new_default_query name: '_', is_public: true, hidden: true, project: grid.project, user: query_user(grid) - query.add_filter(filter_name(identifier), "=", [::Queries::Filters::MeValue::KEY]) + query.add_filter(filter_name(identifier), '=', [::Queries::Filters::MeValue::KEY]) query.column_names = %w(id type subject) User.execute_as(query.user) do @@ -254,27 +254,27 @@ def migratable_entries def filter_name(identifier) case identifier - when "work_packages_assigned_to_me" - "assigned_to_id" - when "work_packages_reported_by_me" - "author_id" - when "work_packages_responsible_for" - "responsible_id" - when "work_packages_watched" - "watcher_id" + when 'work_packages_assigned_to_me' + 'assigned_to_id' + when 'work_packages_reported_by_me' + 'author_id' + when 'work_packages_responsible_for' + 'responsible_id' + when 'work_packages_watched' + 'watcher_id' end end def wp_table_widget_name(identifier) new_identifier = case identifier - when "work_packages_assigned_to_me" - "work_packages_assigned" - when "work_packages_reported_by_me" - "work_packages_created" - when "work_packages_responsible_for" - "work_packages_accountable" - when "work_packages_watched" - "work_packages_watched" + when 'work_packages_assigned_to_me' + 'work_packages_assigned' + when 'work_packages_reported_by_me' + 'work_packages_created' + when 'work_packages_responsible_for' + 'work_packages_accountable' + when 'work_packages_watched' + 'work_packages_watched' end I18n.t("js.grid.widgets.#{new_identifier}.title") diff --git a/modules/overviews/lib/overviews/grid_registration.rb b/modules/overviews/lib/overviews/grid_registration.rb index 04de8323cf25..50b3095a0f99 100644 --- a/modules/overviews/lib/overviews/grid_registration.rb +++ b/modules/overviews/lib/overviews/grid_registration.rb @@ -1,6 +1,6 @@ module Overviews class GridRegistration < ::Grids::Configuration::InProjectBaseRegistration - grid_class "Grids::Overview" + grid_class 'Grids::Overview' to_scope :project_overview_path view_permission :view_project @@ -13,53 +13,53 @@ class GridRegistration < ::Grids::Configuration::InProjectBaseRegistration column_count: 2, widgets: [ { - identifier: "project_description", + identifier: 'project_description', start_row: 1, end_row: 2, start_column: 1, end_column: 2, options: { - name: I18n.t("js.grid.widgets.project_description.title") + name: I18n.t('js.grid.widgets.project_description.title') } }, { - identifier: "project_status", + identifier: 'project_status', start_row: 1, end_row: 2, start_column: 2, end_column: 3, options: { - name: I18n.t("js.grid.widgets.project_status.title") + name: I18n.t('js.grid.widgets.project_status.title') } }, { - identifier: "project_details", + identifier: 'project_details', start_row: 2, end_row: 3, start_column: 1, end_column: 2, options: { - name: I18n.t("js.grid.widgets.project_details.title") + name: I18n.t('js.grid.widgets.project_details.title') } }, { - identifier: "work_packages_overview", + identifier: 'work_packages_overview', start_row: 3, end_row: 4, start_column: 1, end_column: 3, options: { - name: I18n.t("js.grid.widgets.work_packages_overview.title") + name: I18n.t('js.grid.widgets.work_packages_overview.title') } }, { - identifier: "members", + identifier: 'members', start_row: 2, end_row: 3, start_column: 2, end_column: 3, options: { - name: I18n.t("js.grid.widgets.members.title") + name: I18n.t('js.grid.widgets.members.title') } } ] diff --git a/modules/overviews/overviews.gemspec b/modules/overviews/overviews.gemspec index 0edf17a9ab7e..3cea45a216c0 100644 --- a/modules/overviews/overviews.gemspec +++ b/modules/overviews/overviews.gemspec @@ -1,11 +1,11 @@ Gem::Specification.new do |s| s.name = "overviews" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = ["OpenProject"] s.summary = "OpenProject Project Overviews" s.files = Dir["{app,config,db,lib}/**/*"] - s.add_dependency "grids" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'grids' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/overviews/spec/contracts/grids/create_contract_spec.rb b/modules/overviews/spec/contracts/grids/create_contract_spec.rb index c6401a8a4e55..13935632be8c 100644 --- a/modules/overviews/spec/contracts/grids/create_contract_spec.rb +++ b/modules/overviews/spec/contracts/grids/create_contract_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Grids::CreateContract, "for Grids::Overview" do +RSpec.describe Grids::CreateContract, 'for Grids::Overview' do let(:project) do build_stubbed(:project).tap do |p| allow(Project) @@ -51,23 +51,23 @@ end end - include_context "model contract" + include_context 'model contract' - describe "user_id" do - it_behaves_like "is not writable" do + describe 'user_id' do + it_behaves_like 'is not writable' do let(:attribute) { :user_id } let(:value) { 5 } end end - describe "project_id" do - it_behaves_like "is writable" do + describe 'project_id' do + it_behaves_like 'is writable' do let(:attribute) { :project_id } let(:value) { 5 } end end - context "if an overview grid already exists for the project" do + context 'if an overview grid already exists for the project' do before do allow(Grids::Overview) .to receive(:exists?) @@ -75,7 +75,7 @@ .and_return(true) end - it "reports an error on scope" do + it 'reports an error on scope' do instance.validate expect(instance.errors.symbols_for(:scope)) @@ -83,7 +83,7 @@ end end - context "if the user lacks :manage_overview permission" do + context 'if the user lacks :manage_overview permission' do # View project is a public permission so every member will have it but as we stub... let(:permissions) { [:view_project] } @@ -93,20 +93,20 @@ grid.widgets = grid.widgets.reject { |w| %w(members work_packages_overview).include?(w.identifier) } end - context "if the grid does not have any changes compared to the default" do - it "is valid" do + context 'if the grid does not have any changes compared to the default' do + it 'is valid' do expect(instance.validate) .to be_truthy end end - context "if the grid has changes compared to the default" do - context "(row_count)" do + context 'if the grid has changes compared to the default' do + context '(row_count)' do before do grid.row_count += 1 end - it "reports an error on row_count" do + it 'reports an error on row_count' do instance.validate expect(instance.errors.symbols_for(:row_count)) @@ -114,12 +114,12 @@ end end - context "(column_count)" do + context '(column_count)' do before do grid.column_count += 1 end - it "reports an error on row_count" do + it 'reports an error on row_count' do instance.validate expect(instance.errors.symbols_for(:column_count)) @@ -127,20 +127,20 @@ end end - context "(widget added)" do + context '(widget added)' do before do grid.row_count = 4 - grid.widgets.build(identifier: "project_details", + grid.widgets.build(identifier: 'project_details', start_row: 3, end_row: 4, start_column: 1, end_column: 3, options: { - name: I18n.t("js.grid.widgets.work_packages_overview.title") + name: I18n.t('js.grid.widgets.work_packages_overview.title') }) end - it "reports an error on widgets" do + it 'reports an error on widgets' do instance.validate expect(instance.errors.symbols_for(:widgets)) @@ -148,13 +148,13 @@ end end - context "(widget altered)" do + context '(widget altered)' do before do grid.row_count = 4 grid.widgets.last.end_row += 1 end - it "reports an error on widgets" do + it 'reports an error on widgets' do instance.validate expect(instance.errors.symbols_for(:widgets)) @@ -162,12 +162,12 @@ end end - context "(widget options altered)" do + context '(widget options altered)' do before do - grid.widgets[0].options = { name: "My own name" } + grid.widgets[0].options = { name: 'My own name' } end - it "reports an error on widgets" do + it 'reports an error on widgets' do instance.validate expect(instance.errors.symbols_for(:widgets)) diff --git a/modules/overviews/spec/contracts/roles/base_contract_spec.rb b/modules/overviews/spec/contracts/roles/base_contract_spec.rb index 66b21e14a3a2..7fda73f04de7 100644 --- a/modules/overviews/spec/contracts/roles/base_contract_spec.rb +++ b/modules/overviews/spec/contracts/roles/base_contract_spec.rb @@ -24,7 +24,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe Roles::BaseContract do let(:work_package_role) { build_stubbed(:work_package_role) } @@ -34,38 +34,38 @@ let(:current_user) { build_stubbed(:admin) } let(:contract) { described_class.new(role, current_user) } - describe "assignable_permissions" do - context "for a work package role" do + describe 'assignable_permissions' do + context 'for a work package role' do let(:role) { work_package_role } - it "does not include manage_overview" do + it 'does not include manage_overview' do expect(contract.assignable_permissions.map(&:name)) .not_to include :manage_overview end end - context "for a member role" do + context 'for a member role' do let(:role) { member_role } - it "includes manage_overview" do + it 'includes manage_overview' do expect(contract.assignable_permissions.map(&:name)) .to include :manage_overview end end - context "for a global role" do + context 'for a global role' do let(:role) { global_role } - it "does not include manage_overview" do + it 'does not include manage_overview' do expect(contract.assignable_permissions.map(&:name)) .not_to include :manage_overview end end - context "for a builtin role" do + context 'for a builtin role' do let(:role) { anonymous_role } - it "does not include manage_overview" do + it 'does not include manage_overview' do expect(contract.assignable_permissions.map(&:name)) .not_to include :manage_overview end diff --git a/modules/overviews/spec/controllers/overviews/overviews_controller_spec.rb b/modules/overviews/spec/controllers/overviews/overviews_controller_spec.rb index ea0b4b1fd11b..3c2b2807a9fc 100644 --- a/modules/overviews/spec/controllers/overviews/overviews_controller_spec.rb +++ b/modules/overviews/spec/controllers/overviews/overviews_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Overviews::OverviewsController do let(:permissions) do @@ -54,24 +54,24 @@ login_as current_user end - describe "#show" do - context "with jump parameter" do - it "redirects to active tab" do - get :show, params: { project_id: project.id, jump: "news" } + describe '#show' do + context 'with jump parameter' do + it 'redirects to active tab' do + get :show, params: { project_id: project.id, jump: 'news' } expect(response) .to redirect_to main_app_routes.project_news_index_path(project) end - it "ignores inactive/unpermitted module" do - get :show, params: { project_id: project.id, jump: "work_packages" } + it 'ignores inactive/unpermitted module' do + get :show, params: { project_id: project.id, jump: 'work_packages' } expect(response) .to be_successful end - it "ignores bogus module" do - get :show, params: { project_id: project.id, jump: "foobar" } + it 'ignores bogus module' do + get :show, params: { project_id: project.id, jump: 'foobar' } expect(response) .to be_successful diff --git a/modules/overviews/spec/factories/grid_factory.rb b/modules/overviews/spec/factories/grid_factory.rb index c7e13364ff11..d48b998616b5 100644 --- a/modules/overviews/spec/factories/grid_factory.rb +++ b/modules/overviews/spec/factories/grid_factory.rb @@ -1,5 +1,5 @@ FactoryBot.define do - factory :overview, class: "Grids::Overview" do + factory :overview, class: 'Grids::Overview' do project row_count { 7 } column_count { 4 } diff --git a/modules/overviews/spec/features/low_permissions_page_creation_spec.rb b/modules/overviews/spec/features/low_permissions_page_creation_spec.rb index 3480c1d6987c..283c24cc60e9 100644 --- a/modules/overviews/spec/features/low_permissions_page_creation_spec.rb +++ b/modules/overviews/spec/features/low_permissions_page_creation_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/overview" +require_relative '../support/pages/overview' -RSpec.describe "Overview page on the fly creation if user lacks :mange_overview permission", :js do +RSpec.describe 'Overview page on the fly creation if user lacks :mange_overview permission', :js do let!(:type) { create(:type) } let!(:project) { create(:project, types: [type]) } let!(:open_status) { create(:default_status) } @@ -53,10 +53,10 @@ overview_page.visit! end - it "renders the default view, allows altering and saving" do - description_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") - details_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") - overview_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(3)") + it 'renders the default view, allows altering and saving' do + description_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') + details_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') + overview_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(3)') description_area.expect_to_exist details_area.expect_to_exist diff --git a/modules/overviews/spec/features/managing_overview_page_spec.rb b/modules/overviews/spec/features/managing_overview_page_spec.rb index ef6c0e839fd1..22fe1ae5da6c 100644 --- a/modules/overviews/spec/features/managing_overview_page_spec.rb +++ b/modules/overviews/spec/features/managing_overview_page_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require_relative "../support/pages/overview" +require_relative '../support/pages/overview' -RSpec.describe "Overview page managing", :js do +RSpec.describe 'Overview page managing', :js do let!(:type) { create(:type) } - let!(:project) { create(:project, types: [type], description: "My **custom** description") } + let!(:project) { create(:project, types: [type], description: 'My **custom** description') } let!(:open_status) { create(:default_status) } let!(:created_work_package) do create(:work_package, @@ -70,12 +70,12 @@ overview_page.visit! end - it "renders the default view, allows altering and saving" do - description_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)") - status_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(2)") - details_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(3)") - overview_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(4)") - members_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(5)") + it 'renders the default view, allows altering and saving' do + description_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(1)') + status_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(2)') + details_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(3)') + overview_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(4)') + members_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(5)') description_area.expect_to_exist status_area.expect_to_exist @@ -91,32 +91,32 @@ # The widgets load their respective contents within description_area.area do expect(page) - .to have_content("My custom description") + .to have_content('My custom description') end # within top-left area, add an additional widget - overview_page.add_widget(1, 1, :row, "Work packages table") + overview_page.add_widget(1, 1, :row, 'Work packages table') # Actually there are two success messages displayed currently. One for the grid getting updated and one # for the query assigned to the new widget being created. A user will not notice it but the automated # browser can get confused. Therefore we wait. sleep(1) - overview_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + overview_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') - table_area = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(6)") + table_area = Components::Grids::GridArea.new('.grid--area.-widgeted:nth-of-type(6)') table_area.expect_to_span(1, 1, 2, 2) # A useless resizing shows no message and does not alter the size table_area.resize_to(1, 1) - overview_page.expect_no_toaster message: I18n.t("js.notice_successful_update") + overview_page.expect_no_toaster message: I18n.t('js.notice_successful_update') table_area.expect_to_span(1, 1, 2, 2) table_area.resize_to(1, 2) - overview_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + overview_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') # Resizing leads to the table area now spanning a larger area table_area.expect_to_span(1, 1, 2, 3) diff --git a/modules/overviews/spec/features/navigation_spec.rb b/modules/overviews/spec/features/navigation_spec.rb index ca23d402c4ac..3390a8719b69 100644 --- a/modules/overviews/spec/features/navigation_spec.rb +++ b/modules/overviews/spec/features/navigation_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Navigate to overview", :js do +RSpec.describe 'Navigate to overview', :js do let(:project) { create(:project) } let(:permissions) { [] } let(:user) do @@ -40,16 +40,16 @@ login_as user end - it "can visit the overview page" do + it 'can visit the overview page' do visit project_path(project) - within "#menu-sidebar" do + within '#menu-sidebar' do click_link "Overview" end - within "#content" do + within '#content' do expect(page) - .to have_content("Overview") + .to have_content('Overview') end end end diff --git a/modules/overviews/spec/lib/overview/grid_registration_spec.rb b/modules/overviews/spec/lib/overview/grid_registration_spec.rb index cc0e4c112917..fbd7cf90297c 100644 --- a/modules/overviews/spec/lib/overview/grid_registration_spec.rb +++ b/modules/overviews/spec/lib/overview/grid_registration_spec.rb @@ -1,11 +1,11 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Overviews::GridRegistration do let(:user) { build_stubbed(:user) } let(:project) { build_stubbed(:project) } let(:grid) { build_stubbed(:overview, project:) } - describe "writable?" do + describe 'writable?' do let(:permissions) { %i[manage_overview view_project] } before do @@ -14,27 +14,27 @@ end end - context "if the user has the :manage_overview permission" do - it "is truthy" do + context 'if the user has the :manage_overview permission' do + it 'is truthy' do expect(described_class) .to be_writable(grid, user) end end - context "if the user lacks the :manage_overview permission and it is a persisted page" do + context 'if the user lacks the :manage_overview permission and it is a persisted page' do let(:permissions) { %i[view_project] } - it "is falsey" do + it 'is falsey' do expect(described_class) .not_to be_writable(grid, user) end end - context "if the user lacks the :manage_overview permission and it is a new record" do + context 'if the user lacks the :manage_overview permission and it is a new record' do let(:permissions) { %i[view_project] } let(:grid) { Grids::Overview.new **attributes_for(:overview).merge(project:) } - it "is truthy" do + it 'is truthy' do expect(described_class) .to be_writable(grid, user) end diff --git a/modules/overviews/spec/requests/api/v3/grids/grids_resource_spec.rb b/modules/overviews/spec/requests/api/v3/grids/grids_resource_spec.rb index 4e5dd99c3826..97fcb670edd7 100644 --- a/modules/overviews/spec/requests/api/v3/grids/grids_resource_spec.rb +++ b/modules/overviews/spec/requests/api/v3/grids/grids_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Grids resource", content_type: :json do +RSpec.describe 'API v3 Grids resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -46,7 +46,7 @@ end let(:widgets) do [create(:grid_widget, - identifier: "custom_text", + identifier: 'custom_text', start_column: 1, end_column: 3, start_row: 1, @@ -59,7 +59,7 @@ subject(:response) { last_response } - describe "#get api/v3/grids/:id" do + describe '#get api/v3/grids/:id' do let(:path) { api_v3_paths.grid(grid.id) } before do @@ -68,65 +68,65 @@ get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "sends a grid block" do + it 'sends a grid block' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') end - it "identifies the url the grid is stored for" do + it 'identifies the url the grid is stored for' do expect(subject.body) .to be_json_eql(project_overview_path(project).to_json) - .at_path("_links/scope/href") + .at_path('_links/scope/href') end - it "has a widget that renders custom text" do + it 'has a widget that renders custom text' do expect(subject.body) - .to be_json_eql("custom_text".to_json) - .at_path("widgets/0/identifier") + .to be_json_eql('custom_text'.to_json) + .at_path('widgets/0/identifier') expect(subject.body) .to be_json_eql(custom_text.to_json) - .at_path("widgets/0/options/text/raw") + .at_path('widgets/0/options/text/raw') end - context "with the grid not existing" do + context 'with the grid not existing' do let(:path) { api_v3_paths.grid(grid.id + 1) } - it "responds with 404 NOT FOUND" do + it 'responds with 404 NOT FOUND' do expect(subject.status).to be 404 end end end - shared_examples_for "creates a grid resource" do - it "responds with 201 CREATED" do + shared_examples_for 'creates a grid resource' do + it 'responds with 201 CREATED' do expect(subject.status).to eq(201) end - it "returns the created grid block" do + it 'returns the created grid block' do expect(subject.body) - .to be_json_eql("Grid".to_json) - .at_path("_type") + .to be_json_eql('Grid'.to_json) + .at_path('_type') if params["rowCount"] expect(subject.body) - .to be_json_eql(params["rowCount"].to_json) - .at_path("rowCount") + .to be_json_eql(params['rowCount'].to_json) + .at_path('rowCount') end end - it "persists the grid" do + it 'persists the grid' do expect(Grids::Grid.count) .to be(1) end end - describe "#post api/v3/grids" do + describe '#post api/v3/grids' do let(:path) { api_v3_paths.grids } let(:permissions) { %i[manage_overview] } @@ -147,9 +147,9 @@ post path, params.to_json end - it_behaves_like "creates a grid resource" + it_behaves_like 'creates a grid resource' - context "if lacking the manage_overview permission and not changing the default values" do + context 'if lacking the manage_overview permission and not changing the default values' do # Creating a grid should be possible for every member in the project to avoid having an empty page for the project # which is why this test case is the same as the one above. # But this is only true if only the scope is provided and no other attribute. @@ -164,36 +164,36 @@ }.with_indifferent_access end - it_behaves_like "creates a grid resource" + it_behaves_like 'creates a grid resource' end - context "if lacking the manage_overview permission and changing the default values" do + context 'if lacking the manage_overview permission and changing the default values' do # Creating a grid should be possible for every member in the project to avoid having an empty page for the project # which is why this test case is the same as the one above. # But this is only true if only the scope is provided and no other attribute. # In this test, the rowCount and columnCount is changed let(:permissions) { %i[] } - it "responds with 422" do + it 'responds with 422' do expect(subject.status).to eq(422) end - it "persists no grid" do + it 'persists no grid' do expect(Grids::Grid.count) .to be(0) end end - context "if not being a member in the project" do + context 'if not being a member in the project' do current_user do create(:user) end - it "responds with 422" do + it 'responds with 422' do expect(subject.status).to eq(422) end - it "persists no grid" do + it 'persists no grid' do expect(Grids::Grid.count) .to be(0) end diff --git a/modules/overviews/spec/services/copy_service_integration_spec.rb b/modules/overviews/spec/services/copy_service_integration_spec.rb index 8681551f1b50..7d24d5deec57 100644 --- a/modules/overviews/spec/services/copy_service_integration_spec.rb +++ b/modules/overviews/spec/services/copy_service_integration_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::CopyService, "integration", type: :model do +RSpec.describe Projects::CopyService, 'integration', type: :model do shared_let(:source) { create(:project, enabled_module_names: %w[wiki work_package_tracking]) } - shared_let(:source_category) { create(:category, project: source, name: "Stock management") } - shared_let(:source_version) { create(:version, project: source, name: "Version A") } + shared_let(:source_category) { create(:category, project: source, name: 'Stock management') } + shared_let(:source_version) { create(:version, project: source, name: 'Version A') } let(:current_user) do create(:user, @@ -43,18 +43,18 @@ end let(:only_args) { nil } let(:target_project_params) do - { name: "Some name", identifier: "some-identifier" } + { name: 'Some name', identifier: 'some-identifier' } end let(:params) do { target_project_params:, only: only_args } end - describe "call" do + describe 'call' do subject { instance.call(params) } let(:project_copy) { subject.result } - describe "overview" do + describe 'overview' do let(:widget_data) do [ [[1, 1, 1, 2], "project_description", {}], @@ -81,7 +81,7 @@ let(:overview) { Grids::Overview.find_by(project: project_copy) } - context "when requested" do + context 'when requested' do let(:only_args) { %i[work_packages overview] } before do @@ -90,12 +90,12 @@ expect(subject).to be_success end - it "is copied" do + it 'is copied' do expect(overview.widgets.size).to eq original_overview.widgets.size end end - context "when not requested" do + context 'when not requested' do let(:only_args) { %i[work_packages] } before do @@ -104,12 +104,12 @@ expect(subject).to be_success end - it "is ignored" do + it 'is ignored' do expect(overview).to be_nil end end - describe "copy" do + describe 'copy' do let(:only_args) { %i[versions categories overview] } before do @@ -118,7 +118,7 @@ expect(subject).to be_success end - it "contains the same widgets" do + it 'contains the same widgets' do expect(overview.widgets.size).to eq original_overview.widgets.size fields = %i(identifier options start_row end_row start_column end_column) @@ -128,12 +128,12 @@ end end - context "with references" do - describe "to queries" do + context 'with references' do + describe 'to queries' do let!(:query) do create(:public_query, project: source).tap do |query| - query.add_filter "version_id", "=", [source_version.id.to_s] - query.add_filter "category_id", "=", [source_category.id.to_s] + query.add_filter 'version_id', '=', [source_version.id.to_s] + query.add_filter 'category_id', '=', [source_category.id.to_s] query.save! end end @@ -144,7 +144,7 @@ ] end - it "copies the widgets and updates references to copied queries" do + it 'copies the widgets and updates references to copied queries' do expect(overview.widgets.size).to eq original_overview.widgets.size overview.widgets.zip(original_overview.widgets).each do |widget, original_widget| @@ -159,7 +159,7 @@ end end - it "updates references within the copied query" do + it 'updates references within the copied query' do query_copy = Query.where(name: query.name, project: project_copy).first expect(query_copy).to be_present diff --git a/modules/overviews/spec/support/pages/overview.rb b/modules/overviews/spec/support/pages/overview.rb index 2794648b64f6..f79af96f932d 100644 --- a/modules/overviews/spec/support/pages/overview.rb +++ b/modules/overviews/spec/support/pages/overview.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' -require_relative "../../../../grids/spec/support/pages/grid" +require_relative '../../../../grids/spec/support/pages/grid' module Pages class Overview < ::Pages::Grid diff --git a/modules/recaptcha/Gemfile b/modules/recaptcha/Gemfile index 3be9c3cd812e..851fabc21ddb 100644 --- a/modules/recaptcha/Gemfile +++ b/modules/recaptcha/Gemfile @@ -1,2 +1,2 @@ -source "https://rubygems.org" +source 'https://rubygems.org' gemspec diff --git a/modules/recaptcha/app/controllers/recaptcha/admin_controller.rb b/modules/recaptcha/app/controllers/recaptcha/admin_controller.rb index 9749af2063b9..c23678e18947 100644 --- a/modules/recaptcha/app/controllers/recaptcha/admin_controller.rb +++ b/modules/recaptcha/app/controllers/recaptcha/admin_controller.rb @@ -4,7 +4,7 @@ class AdminController < ApplicationController before_action :require_admin before_action :validate_settings, only: :update - layout "admin" + layout 'admin' menu_item :plugin_recaptcha @@ -23,7 +23,7 @@ def validate_settings allowed_options = recaptcha_available_options.map(&:last) unless allowed_options.include? new_params[:recaptcha_type] - flash[:error] = I18n.t(:error_code, code: "400") + flash[:error] = I18n.t(:error_code, code: '400') redirect_to action: :show return end @@ -36,7 +36,7 @@ def permitted_params end def default_breadcrumb - t("recaptcha.label_recaptcha") + t('recaptcha.label_recaptcha') end def show_local_breadcrumb diff --git a/modules/recaptcha/app/controllers/recaptcha/request_controller.rb b/modules/recaptcha/app/controllers/recaptcha/request_controller.rb index 2d48aa38032e..162b29141d20 100644 --- a/modules/recaptcha/app/controllers/recaptcha/request_controller.rb +++ b/modules/recaptcha/app/controllers/recaptcha/request_controller.rb @@ -1,9 +1,9 @@ -require "recaptcha" +require 'recaptcha' module ::Recaptcha class RequestController < ApplicationController # Include global layout helper - layout "no_menu" + layout 'no_menu' # User is not yet logged in, so skip login required check skip_before_action :check_if_login_required @@ -38,7 +38,7 @@ def verify save_recaptcha_verification_success! complete_stage_redirect else - fail_recaptcha I18n.t("recaptcha.error_captcha") + fail_recaptcha I18n.t('recaptcha.error_captcha') end end @@ -63,7 +63,7 @@ def save_recaptcha_verification_success! end def recaptcha_version - case recaptcha_settings["recaptcha_type"] + case recaptcha_settings['recaptcha_type'] when ::OpenProject::Recaptcha::TYPE_DISABLED 0 when ::OpenProject::Recaptcha::TYPE_V2, ::OpenProject::Recaptcha::TYPE_HCAPTCHA @@ -76,9 +76,9 @@ def recaptcha_version ## # def valid_recaptcha? - call_args = { secret_key: recaptcha_settings["secret_key"] } + call_args = { secret_key: recaptcha_settings['secret_key'] } if recaptcha_version == 3 - call_args[:action] = "login" + call_args[:action] = 'login' end verify_recaptcha call_args @@ -105,7 +105,7 @@ def recaptcha_settings end def skip_if_disabled - if recaptcha_settings["recaptcha_type"] == ::OpenProject::Recaptcha::TYPE_DISABLED + if recaptcha_settings['recaptcha_type'] == ::OpenProject::Recaptcha::TYPE_DISABLED complete_stage_redirect end end diff --git a/modules/recaptcha/app/helpers/recaptcha_helper.rb b/modules/recaptcha/app/helpers/recaptcha_helper.rb index 662db0a65079..b5929cf60f66 100644 --- a/modules/recaptcha/app/helpers/recaptcha_helper.rb +++ b/modules/recaptcha/app/helpers/recaptcha_helper.rb @@ -1,10 +1,10 @@ module RecaptchaHelper def recaptcha_available_options [ - [I18n.t("recaptcha.settings.type_disabled"), ::OpenProject::Recaptcha::TYPE_DISABLED], - [I18n.t("recaptcha.settings.type_v2"), ::OpenProject::Recaptcha::TYPE_V2], - [I18n.t("recaptcha.settings.type_v3"), ::OpenProject::Recaptcha::TYPE_V3], - [I18n.t("recaptcha.settings.type_hcaptcha"), ::OpenProject::Recaptcha::TYPE_HCAPTCHA] + [I18n.t('recaptcha.settings.type_disabled'), ::OpenProject::Recaptcha::TYPE_DISABLED], + [I18n.t('recaptcha.settings.type_v2'), ::OpenProject::Recaptcha::TYPE_V2], + [I18n.t('recaptcha.settings.type_v3'), ::OpenProject::Recaptcha::TYPE_V3], + [I18n.t('recaptcha.settings.type_hcaptcha'), ::OpenProject::Recaptcha::TYPE_HCAPTCHA] ] end diff --git a/modules/recaptcha/app/models/recaptcha/entry.rb b/modules/recaptcha/app/models/recaptcha/entry.rb index 59637d25a681..3af1e68c1efa 100644 --- a/modules/recaptcha/app/models/recaptcha/entry.rb +++ b/modules/recaptcha/app/models/recaptcha/entry.rb @@ -1,6 +1,6 @@ module Recaptcha class Entry < ::ApplicationRecord - self.table_name_prefix = "recaptcha_" + self.table_name_prefix = 'recaptcha_' belongs_to :user end end diff --git a/modules/recaptcha/app/views/recaptcha/admin/show.html.erb b/modules/recaptcha/app/views/recaptcha/admin/show.html.erb index c67374539fb0..302d86662950 100644 --- a/modules/recaptcha/app/views/recaptcha/admin/show.html.erb +++ b/modules/recaptcha/app/views/recaptcha/admin/show.html.erb @@ -52,6 +52,6 @@ - <%= styled_submit_tag t(:button_apply), class: '-primary' %> + <%= styled_submit_tag t(:button_apply), class: '-highlight' %> <% end %> diff --git a/modules/recaptcha/config/routes.rb b/modules/recaptcha/config/routes.rb index 02937c072c1b..ba999384cf3c 100644 --- a/modules/recaptcha/config/routes.rb +++ b/modules/recaptcha/config/routes.rb @@ -1,9 +1,9 @@ Rails.application.routes.draw do - namespace "recaptcha" do - get :settings, to: "admin#show" - post :settings, to: "admin#update" + namespace 'recaptcha' do + get :settings, to: 'admin#show' + post :settings, to: 'admin#update' - get :request, to: "request#perform", as: "request" - post :verify, to: "request#verify", as: "verify" + get :request, to: 'request#perform', as: 'request' + post :verify, to: 'request#verify', as: 'verify' end end diff --git a/modules/recaptcha/lib/open_project/recaptcha.rb b/modules/recaptcha/lib/open_project/recaptcha.rb index d7933a433069..815c7d1cbe1e 100644 --- a/modules/recaptcha/lib/open_project/recaptcha.rb +++ b/modules/recaptcha/lib/open_project/recaptcha.rb @@ -1,9 +1,9 @@ module OpenProject module Recaptcha - TYPE_DISABLED ||= "disabled" - TYPE_V2 ||= "v2" - TYPE_V3 ||= "v3" - TYPE_HCAPTCHA ||= "hcaptcha" + TYPE_DISABLED ||= 'disabled' + TYPE_V2 ||= 'v2' + TYPE_V3 ||= 'v3' + TYPE_HCAPTCHA ||= 'hcaptcha' require "open_project/recaptcha/engine" require "open_project/recaptcha/configuration" diff --git a/modules/recaptcha/lib/open_project/recaptcha/configuration.rb b/modules/recaptcha/lib/open_project/recaptcha/configuration.rb index 205c9ee39362..8c2956fa5d41 100644 --- a/modules/recaptcha/lib/open_project/recaptcha/configuration.rb +++ b/modules/recaptcha/lib/open_project/recaptcha/configuration.rb @@ -1,7 +1,7 @@ module OpenProject module Recaptcha module Configuration - CONFIG_KEY = "recaptcha_via_hcaptcha".freeze + CONFIG_KEY = 'recaptcha_via_hcaptcha'.freeze extend self @@ -14,11 +14,11 @@ def use_hcaptcha? end def type - ::Setting.plugin_openproject_recaptcha["recaptcha_type"] + ::Setting.plugin_openproject_recaptcha['recaptcha_type'] end def hcaptcha_response_limit - (::Setting.plugin_openproject_recaptcha["response_limit"] || "5000").to_i + (::Setting.plugin_openproject_recaptcha['response_limit'] || '5000').to_i end def hcaptcha_verify_url diff --git a/modules/recaptcha/lib/open_project/recaptcha/engine.rb b/modules/recaptcha/lib/open_project/recaptcha/engine.rb index a81b8d846615..312cc01b444d 100644 --- a/modules/recaptcha/lib/open_project/recaptcha/engine.rb +++ b/modules/recaptcha/lib/open_project/recaptcha/engine.rb @@ -1,5 +1,5 @@ -require "open_project/plugins" -require "recaptcha" +require 'open_project/plugins' +require 'recaptcha' module OpenProject::Recaptcha class Engine < ::Rails::Engine @@ -7,8 +7,8 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-recaptcha", - author_url: "https://www.openproject.org", + register 'openproject-recaptcha', + author_url: 'https://www.openproject.org', settings: { default: { recaptcha_type: ::OpenProject::Recaptcha::TYPE_DISABLED, @@ -18,9 +18,9 @@ class Engine < ::Rails::Engine bundled: true do menu :admin_menu, :plugin_recaptcha, - { controller: "/recaptcha/admin", action: :show }, + { controller: '/recaptcha/admin', action: :show }, parent: :authentication, - caption: ->(*) { I18n.t("recaptcha.label_recaptcha") } + caption: ->(*) { I18n.t('recaptcha.label_recaptcha') } end initializer "openproject.configuration" do diff --git a/modules/recaptcha/lib/openproject-recaptcha.rb b/modules/recaptcha/lib/openproject-recaptcha.rb index 91424a510a5c..f626d3d0e5df 100644 --- a/modules/recaptcha/lib/openproject-recaptcha.rb +++ b/modules/recaptcha/lib/openproject-recaptcha.rb @@ -1 +1 @@ -require "open_project/recaptcha" +require 'open_project/recaptcha' diff --git a/modules/recaptcha/openproject-recaptcha.gemspec b/modules/recaptcha/openproject-recaptcha.gemspec index 8d07ff66c8af..b994e33c9f56 100644 --- a/modules/recaptcha/openproject-recaptcha.gemspec +++ b/modules/recaptcha/openproject-recaptcha.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "openproject-recaptcha" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" s.summary = "OpenProject ReCaptcha" @@ -8,6 +8,6 @@ Gem::Specification.new do |s| s.files = Dir["{app,config,db,lib}/**/*", "CHANGELOG.md", "README.rdoc"] - s.add_dependency "recaptcha", "~> 5.7" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'recaptcha', '~> 5.7' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/recaptcha/spec/controllers/admin_controller_spec.rb b/modules/recaptcha/spec/controllers/admin_controller_spec.rb index b621683c2e76..e253baf1d799 100644 --- a/modules/recaptcha/spec/controllers/admin_controller_spec.rb +++ b/modules/recaptcha/spec/controllers/admin_controller_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Recaptcha::AdminController do let(:user) { build_stubbed(:admin) } @@ -7,10 +7,10 @@ login_as user end - describe "as non admin" do + describe 'as non admin' do let(:user) { build_stubbed(:user) } - it "does not allow access" do + it 'does not allow access' do get :show expect(response.status).to eq 403 @@ -19,23 +19,23 @@ end end - describe "show" do - it "renders show" do + describe 'show' do + it 'renders show' do get :show expect(response).to be_successful - expect(response).to render_template "recaptcha/admin/show" + expect(response).to render_template 'recaptcha/admin/show' end end - describe "#update" do - it "fails if invalid param" do + describe '#update' do + it 'fails if invalid param' do post :update, params: { recaptcha_type: :unknown } expect(response).to be_redirect expect(flash[:error]).to be_present end - it "succeeds" do - expected = { recaptcha_type: "v2", website_key: "B", secret_key: "A" } + it 'succeeds' do + expected = { recaptcha_type: 'v2', website_key: 'B', secret_key: 'A' } expect(Setting) .to receive(:plugin_openproject_recaptcha=) diff --git a/modules/recaptcha/spec/controllers/request_controller_spec.rb b/modules/recaptcha/spec/controllers/request_controller_spec.rb index c586259152a7..ac8ac0233ce5 100644 --- a/modules/recaptcha/spec/controllers/request_controller_spec.rb +++ b/modules/recaptcha/spec/controllers/request_controller_spec.rb @@ -1,15 +1,15 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Recaptcha::RequestController do let(:user) { create(:user) } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_recaptcha: { - "recaptcha_type" => "v2", - "website_key" => "A", - "secret_key" => "B" + 'recaptcha_type' => 'v2', + 'website_key' => 'A', + 'secret_key' => 'B' } } end @@ -19,49 +19,49 @@ login_as user session[:authenticated_user_id] = user.id - session[:stage_secrets] = { recaptcha: "asdf" } + session[:stage_secrets] = { recaptcha: 'asdf' } end - describe "request" do - it "renders the template" do + describe 'request' do + it 'renders the template' do get :perform expect(response).to be_successful - expect(response).to render_template "recaptcha/request/perform" + expect(response).to render_template 'recaptcha/request/perform' end - it "skips if user is verified" do + it 'skips if user is verified' do allow(Recaptcha::Entry) .to receive(:exists?).with(user_id: user.id) .and_return true get :perform - expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: "asdf") + expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: 'asdf') end - context "if the user is an admin" do + context 'if the user is an admin' do let(:user) { create(:admin) } - it "skips the verification" do + it 'skips the verification' do allow(controller).to receive(:perform) get :perform - expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: "asdf") + expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: 'asdf') expect(controller).not_to have_received(:perform) end end end - describe "verify" do - it "succeeds assuming verification works" do + describe 'verify' do + it 'succeeds assuming verification works' do allow(controller).to receive(:valid_recaptcha?).and_return true allow(controller).to receive(:save_recaptcha_verification_success!) post :verify expect(flash[:error]).to be_nil - expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: "asdf") + expect(response).to redirect_to stage_success_path(stage: :recaptcha, secret: 'asdf') expect(controller).to have_received(:save_recaptcha_verification_success!) end - it "fails assuming verification fails" do + it 'fails assuming verification fails' do allow(controller).to receive(:valid_recaptcha?).and_return false post :verify expect(flash[:error]).to be_present diff --git a/modules/reporting/app/controllers/cost_reports_controller.rb b/modules/reporting/app/controllers/cost_reports_controller.rb index 8014ac1b6e56..e8e8c28b99e5 100644 --- a/modules/reporting/app/controllers/cost_reports_controller.rb +++ b/modules/reporting/app/controllers/cost_reports_controller.rb @@ -65,7 +65,7 @@ class CostReportsController < ApplicationController before_action :set_cost_types # has to be set AFTER the Report::Controller filters run - layout "angular/angular" + layout 'angular/angular' # Checks if custom fields have been updated, added or removed since we # last saw them, to rebuild the filters and group bys. @@ -120,7 +120,7 @@ def create @query.send(:"#{user_key}=", current_user.id) @query.save! - redirect_params = { action: "show", id: @query.id } + redirect_params = { action: 'show', id: @query.id } redirect_params[:project_id] = @project.identifier if @project if request.xhr? # Update via AJAX - return url for redirect @@ -137,7 +137,7 @@ def show if @query store_query(@query) table - render action: "index", locals: { menu_name: project_or_global_menu } unless performed? + render action: 'index', locals: { menu_name: project_or_global_menu } unless performed? else raise ActiveRecord::RecordNotFound end @@ -152,7 +152,7 @@ def destroy else raise ActiveRecord::RecordNotFound end - redirect_to action: "index", default: 1 + redirect_to action: 'index', default: 1 end ## @@ -169,7 +169,7 @@ def update if request.xhr? table else - redirect_to action: "show", id: @query.id + redirect_to action: 'show', id: @query.id end end @@ -184,7 +184,7 @@ def rename if request.xhr? render plain: @query.name else - redirect_to action: "show", id: @query.id + redirect_to action: 'show', id: @query.id end end @@ -202,7 +202,7 @@ def available_values filter = f_cls.new.tap do |f| f.values = JSON.parse(params[:values].tr("'", '"')) if params[:values].present? && params[:values] end - render_widget Widget::Filters::Option, filter, to: canvas = "" + render_widget Widget::Filters::Option, filter, to: canvas = '' render plain: canvas, layout: !request.xhr? end @@ -224,8 +224,8 @@ def no_progress? # Set a default query to cut down initial load time def default_filter_parameters { - operators: { spent_on: ">d" }, - values: { spent_on: [30.days.ago.strftime("%Y-%m-%d")] } + operators: { spent_on: '>d' }, + values: { spent_on: [30.days.ago.strftime('%Y-%m-%d')] } }.tap do |hash| if @project set_project_filter(hash, @project.id) @@ -281,12 +281,12 @@ def update_project_context!(filters) def set_project_filter(filters, project_id) filters[:project_context] = project_id - filters[:operators].merge! project_id: "=" + filters[:operators].merge! project_id: '=' filters[:values].merge! project_id: [project_id] end def set_me_filter(filters) - filters[:operators].merge! user_id: "=" + filters[:operators].merge! user_id: '=' filters[:values].merge! user_id: [CostQuery::Filter::UserId.me_value] end @@ -329,14 +329,14 @@ def set_unit def set_cost_type return unless @query - @query.filter :cost_type_id, operator: "=", value: @unit_id.to_s, display: false + @query.filter :cost_type_id, operator: '=', value: @unit_id.to_s, display: false @cost_type = CostType.find(@unit_id) if @unit_id > 0 end # set the @cost_types -> this is used to determine which tabs to display def set_active_cost_types unless session[:report] && (@cost_types = session[:report][:filters][:values][:cost_type_id].try(:collect, &:to_i)) - relevant_cost_types = CostType.select(:id).order(Arel.sql("id ASC")).select do |t| + relevant_cost_types = CostType.select(:id).order(Arel.sql('id ASC')).select do |t| t.cost_entries.count > 0 end.collect(&:id) @cost_types = [-1, 0, *relevant_cost_types] @@ -411,7 +411,7 @@ def get_filter_class(name) # Determine the available values for the specified filter and return them as # json, if that was requested. This will be executed INSTEAD of the actual action def possibly_only_narrow_values - if params[:narrow_values] == "1" + if params[:narrow_values] == '1' sources = params[:sources] dependent = params[:dependent] @@ -422,9 +422,9 @@ def possibly_only_narrow_values values: params[:values][dependency]) end query.column(dependent) - values = [[::I18n.t(:label_inactive), "<>"]] + query.result.map { |r| r.fields[query.group_bys.first.field] } + values = [[::I18n.t(:label_inactive), '<>']] + query.result.map { |r| r.fields[query.group_bys.first.field] } # replace null-values with corresponding placeholder - values = values.map { |value| value.nil? ? [::I18n.t(:label_none), "<>"] : value } + values = values.map { |value| value.nil? ? [::I18n.t(:label_none), '<>'] : value } # try to find corresponding labels to the given values values = values.map do |value| filter = get_filter_class(dependent) @@ -463,8 +463,8 @@ def http_filter_parameters # Extract active group bys from the http params def http_group_parameters if params[:groups] - rows = params[:groups]["rows"] - columns = params[:groups]["columns"] + rows = params[:groups]['rows'] + columns = params[:groups]['columns'] end { rows: rows || [], columns: columns || [] } end @@ -507,8 +507,8 @@ def build_query(filters, groups = {}) query = report_engine.new project: @project query.tap do |q| filters[:operators].each do |filter, operator| - unless filters[:values][filter] == ["<>"] - values = Array(filters[:values][filter]).map { |v| v == "<>" ? nil : v } + unless filters[:values][filter] == ['<>'] + values = Array(filters[:values][filter]).map { |v| v == '<>' ? nil : v } q.filter(filter.to_sym, operator:, values:) @@ -539,7 +539,7 @@ def store_query(_query) ## # Override in subclass if user key def user_key - "user_id" + 'user_id' end ## @@ -557,7 +557,7 @@ def make_query_public? # Raises RecordNotFound if an invalid :id was passed. # # @param query An optional query added to the disjunction qualifiying reports to be returned. - def find_optional_report(query = "1=0") + def find_optional_report(query = '1=0') if params[:id] @query = report_engine .where(["#{is_public_sql} OR (#{user_key} = ?) OR (#{query})", current_user.id]) diff --git a/modules/reporting/app/helpers/reporting_helper.rb b/modules/reporting/app/helpers/reporting_helper.rb index f457ee3d3ba7..28f717337ddd 100644 --- a/modules/reporting/app/helpers/reporting_helper.rb +++ b/modules/reporting/app/helpers/reporting_helper.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "digest/md5" +require 'digest/md5' module ReportingHelper # ======================= SHARED CODE START @@ -50,7 +50,7 @@ def mapped(value, klass, default) def label_for(field) name = field.to_s - if name.starts_with?("label") + if name.starts_with?('label') return I18n.t(field) end @@ -68,8 +68,8 @@ def label_for(field) end end - def debug_fields(result, prefix = ", ") - prefix << result.fields.inspect << ", " << result.important_fields.inspect << ", " << result.key.inspect if params[:debug] + def debug_fields(result, prefix = ', ') + prefix << result.fields.inspect << ', ' << result.important_fields.inspect << ', ' << result.key.inspect if params[:debug] end def month_name(index) @@ -101,7 +101,7 @@ def budget_link(budget_id) end def field_representation_map(key, value) - return I18n.t(:"placeholders.default") if value.blank? + return I18n.t(:'placeholders.default') if value.blank? case key.to_sym when :activity_id then mapped value, Enumeration, "#{I18n.t(:caption_material_costs)}" @@ -119,7 +119,7 @@ def field_representation_map(key, value) when :week then "#{I18n.t(:label_week)} #%s" % value.to_i.modulo(100) when :priority_id then h(IssuePriority.find(value.to_i).name) when :version_id then h(Version.find(value.to_i).name) - when :singleton_value then "" + when :singleton_value then '' when :status_id then h(Status.find(value.to_i).name) when /custom_field\d+/ then custom_value(key, value) else h(value.to_s) @@ -127,7 +127,7 @@ def field_representation_map(key, value) end def custom_value(cf_identifier, value) - cf_id = cf_identifier.gsub("custom_field", "").to_i + cf_id = cf_identifier.gsub('custom_field', '').to_i # Reuses rails cache to locate the custom field # and then properly cast the value @@ -137,7 +137,7 @@ def custom_value(cf_identifier, value) end def field_sort_map(key, value) - return "" if value.blank? + return '' if value.blank? case key.to_sym when :work_package_id, :tweek, :tmonth, :week then value.to_i @@ -149,7 +149,7 @@ def field_sort_map(key, value) def show_result(row, unit_id = self.unit_id) case unit_id when -1 then l_hours(row.units) - when 0 then row.real_costs ? number_to_currency(row.real_costs) : "-" + when 0 then row.real_costs ? number_to_currency(row.real_costs) : '-' else current_cost_type = @cost_type || CostType.find(unit_id) pluralize(row.units, current_cost_type.unit, current_cost_type.unit_plural) @@ -157,7 +157,7 @@ def show_result(row, unit_id = self.unit_id) end def set_filter_options(struct, key, value) - struct[:operators][key] = "=" + struct[:operators][key] = '=' struct[:values][key] = value.to_s end @@ -177,7 +177,7 @@ def cost_type_label(cost_type_id, cost_type_inst = nil, _plural = true) end def link_to_details(result) - return "" # unless result.respond_to? :fields # uncomment to display + return '' # unless result.respond_to? :fields # uncomment to display session_filter = { operators: session[:report][:filters][:operators].dup, values: session[:report][:filters][:values].dup } filters = result.fields.inject session_filter do |struct, (key, value)| key = key.to_sym @@ -194,24 +194,24 @@ def link_to_details(result) struct end options = { fields: filters[:operators].keys, set_filter: 1, action: :drill_down } - link_to "[+]", filters.merge(options), class: "drill_down", title: I18n.t(:description_drill_down) + link_to '[+]', filters.merge(options), class: 'drill_down', title: I18n.t(:description_drill_down) end ## # Create the appropriate action for an entry with the type of log to use def action_for(result, options = {}) - options.merge controller: controller_for(result.fields["type"]), id: result.fields["id"].to_i + options.merge controller: controller_for(result.fields['type']), id: result.fields['id'].to_i end def controller_for(type) - type == "TimeEntry" ? "timelog" : "costlog" + type == 'TimeEntry' ? 'timelog' : 'costlog' end ## # Create the appropriate action for an entry with the type of log to use def entry_for(result) - type = result.fields["type"] == "TimeEntry" ? TimeEntry : CostEntry - type.find(result.fields["id"].to_i) + type = result.fields['type'] == 'TimeEntry' ? TimeEntry : CostEntry + type.find(result.fields['id'].to_i) end ## @@ -224,7 +224,7 @@ def show_row(row) def delimit(items, options = {}) options[:step] ||= 1 - options[:delim] ||= "•" + options[:delim] ||= '•' delimited = [] items.each_with_index do |item, ix| delimited << if ix != 0 && (ix % options[:step]).zero? diff --git a/modules/reporting/app/models/cost_query.rb b/modules/reporting/app/models/cost_query.rb index 75596387f50b..726fb0a9569b 100644 --- a/modules/reporting/app/models/cost_query.rb +++ b/modules/reporting/app/models/cost_query.rb @@ -60,24 +60,24 @@ def self.deserialize(hash, object = new) def self.public(project) if project - CostQuery.where(["is_public = ? AND (project_id IS NULL OR project_id = ?)", true, project]) - .order(Arel.sql("name ASC")) + CostQuery.where(['is_public = ? AND (project_id IS NULL OR project_id = ?)', true, project]) + .order(Arel.sql('name ASC')) else - CostQuery.where(["is_public = ? AND project_id IS NULL", true]) - .order(Arel.sql("name ASC")) + CostQuery.where(['is_public = ? AND project_id IS NULL', true]) + .order(Arel.sql('name ASC')) end end def self.private(project, user) if project - CostQuery.where(["user_id = ? AND is_public = ? AND (project_id IS NULL OR project_id = ?)", + CostQuery.where(['user_id = ? AND is_public = ? AND (project_id IS NULL OR project_id = ?)', user, false, project]) - .order(Arel.sql("name ASC")) + .order(Arel.sql('name ASC')) else - CostQuery.where(["user_id = ? AND is_public = ? AND project_id IS NULL", user, false]) - .order(Arel.sql("name ASC")) + CostQuery.where(['user_id = ? AND is_public = ? AND project_id IS NULL', user, false]) + .order(Arel.sql('name ASC')) end end @@ -93,7 +93,7 @@ def serialize def deserialize if @chain - raise ArgumentError, "Cannot deserialize a report which already has a chain" + raise ArgumentError, 'Cannot deserialize a report which already has a chain' else hash = serialized || serialize self.class.deserialize(hash, self) @@ -214,9 +214,9 @@ def size def cache_key deserialize unless @chain - parts = [self.class.table_name.sub("_reports", "")] - parts.concat([filters.sort, group_bys].map { |l| l.map(&:cache_key).join(" ") }) - parts.join "/" + parts = [self.class.table_name.sub('_reports', '')] + parts.concat([filters.sort, group_bys].map { |l| l.map(&:cache_key).join(' ') }) + parts.join '/' end def self.engine diff --git a/modules/reporting/app/models/cost_query/custom_field_mixin.rb b/modules/reporting/app/models/cost_query/custom_field_mixin.rb index 4bf23500170f..8c9f35c2891b 100644 --- a/modules/reporting/app/models/cost_query/custom_field_mixin.rb +++ b/modules/reporting/app/models/cost_query/custom_field_mixin.rb @@ -32,13 +32,13 @@ module CostQuery::CustomFieldMixin attr_reader :custom_field SQL_TYPES = { - "string" => "varchar", - "list" => "varchar", - "text" => "text", - "bool" => "boolean", - "date" => "date", - "int" => "decimal(60,3)", - "float" => "decimal(60,3)" + 'string' => 'varchar', + 'list' => 'varchar', + 'text' => 'text', + 'bool' => 'boolean', + 'date' => 'date', + 'int' => 'decimal(60,3)', + 'float' => 'decimal(60,3)' }.freeze def self.extended(base) diff --git a/modules/reporting/app/models/cost_query/filter/activity_id.rb b/modules/reporting/app/models/cost_query/filter/activity_id.rb index 16a5722ddfe3..266795163489 100644 --- a/modules/reporting/app/models/cost_query/filter/activity_id.rb +++ b/modules/reporting/app/models/cost_query/filter/activity_id.rb @@ -32,6 +32,6 @@ def self.label end def self.available_values(*) - TimeEntryActivity.order(Arel.sql("name")).pluck(:name, :id) + TimeEntryActivity.order(Arel.sql('name')).pluck(:name, :id) end end diff --git a/modules/reporting/app/models/cost_query/filter/budget_id.rb b/modules/reporting/app/models/cost_query/filter/budget_id.rb index 8449b1aea8c3..03f3cf8e09ab 100644 --- a/modules/reporting/app/models/cost_query/filter/budget_id.rb +++ b/modules/reporting/app/models/cost_query/filter/budget_id.rb @@ -38,7 +38,7 @@ def self.available_values(*) Budget .visible(User.current) .includes(:project) - .pluck(:"projects.name", :subject, :id) + .pluck(:'projects.name', :subject, :id) .map { |a| ["#{a[0]} - #{a[1]} ", a[2]] } .sort_by { |a| a.first.downcase } end diff --git a/modules/reporting/app/models/cost_query/filter/cost_type_id.rb b/modules/reporting/app/models/cost_query/filter/cost_type_id.rb index 6e3d094edf90..beea7cb01741 100644 --- a/modules/reporting/app/models/cost_query/filter/cost_type_id.rb +++ b/modules/reporting/app/models/cost_query/filter/cost_type_id.rb @@ -60,6 +60,6 @@ def field end def self.available_values(*) - [[::I18n.t(:caption_labor), -1]] + CostType.order(Arel.sql("name")).pluck(:name, :id) + [[::I18n.t(:caption_labor), -1]] + CostType.order(Arel.sql('name')).pluck(:name, :id) end end diff --git a/modules/reporting/app/models/cost_query/filter/created_on.rb b/modules/reporting/app/models/cost_query/filter/created_on.rb index 95627e9d12a2..935e69773399 100644 --- a/modules/reporting/app/models/cost_query/filter/created_on.rb +++ b/modules/reporting/app/models/cost_query/filter/created_on.rb @@ -27,7 +27,7 @@ #++ class CostQuery::Filter::CreatedOn < Report::Filter::Base - db_field "entries.created_at" + db_field 'entries.created_at' use :time_operators def self.label diff --git a/modules/reporting/app/models/cost_query/filter/custom_field_entries.rb b/modules/reporting/app/models/cost_query/filter/custom_field_entries.rb index ad796431406e..8d9ff1d187d9 100644 --- a/modules/reporting/app/models/cost_query/filter/custom_field_entries.rb +++ b/modules/reporting/app/models/cost_query/filter/custom_field_entries.rb @@ -33,12 +33,12 @@ class CostQuery::Filter::CustomFieldEntries < Report::Filter::Base applies_for :label_work_package_attributes # redmine internals just suck case custom_field.field_format - when "string", "text" then use :string_operators - when "list" then use :null_operators - when "date" then use :time_operators - when "int", "float" then use :integer_operators - when "bool" - @possible_values = [["true", "t"], ["false", "f"]] + when 'string', 'text' then use :string_operators + when 'list' then use :null_operators + when 'date' then use :time_operators + when 'int', 'float' then use :integer_operators + when 'bool' + @possible_values = [['true', 't'], ['false', 'f']] use :null_operators else fail "cannot handle #{custom_field.field_format.inspect}" @@ -53,7 +53,7 @@ def self.field # Mapping to the human readable value is done for all custom values (e.g. users, versions) # following the same pattern of code, so simply making the exception here to use the value # would complicated the code later on. - if custom_field.field_format == "list" + if custom_field.field_format == 'list' "#{db_field}.value" else super @@ -65,7 +65,7 @@ def self.available_values(*) end def self.get_possible_values - if custom_field.field_format == "list" + if custom_field.field_format == 'list' # Treat list CFs values as string options again, since # aggregation of groups are made by the values as well # and otherwise, it won't work as a filter. diff --git a/modules/reporting/app/models/cost_query/filter/logged_by_id.rb b/modules/reporting/app/models/cost_query/filter/logged_by_id.rb index 23f4d2a1be62..10d93d770ff9 100644 --- a/modules/reporting/app/models/cost_query/filter/logged_by_id.rb +++ b/modules/reporting/app/models/cost_query/filter/logged_by_id.rb @@ -32,7 +32,7 @@ def self.label end def self.me_value - "me".freeze + 'me'.freeze end def transformed_values diff --git a/modules/reporting/app/models/cost_query/filter/no_filter.rb b/modules/reporting/app/models/cost_query/filter/no_filter.rb index b2da44996af3..c2953c116e27 100644 --- a/modules/reporting/app/models/cost_query/filter/no_filter.rb +++ b/modules/reporting/app/models/cost_query/filter/no_filter.rb @@ -27,7 +27,7 @@ #++ class CostQuery::Filter::NoFilter < Report::Filter::NoFilter - table_name "entries" + table_name 'entries' dont_display! singleton diff --git a/modules/reporting/app/models/cost_query/filter/overridden_costs.rb b/modules/reporting/app/models/cost_query/filter/overridden_costs.rb index 052cf9194ce4..0eb28bf1287d 100644 --- a/modules/reporting/app/models/cost_query/filter/overridden_costs.rb +++ b/modules/reporting/app/models/cost_query/filter/overridden_costs.rb @@ -32,7 +32,7 @@ def self.label end def self.available_operators - ["y", "n"].map(&:to_operator) + ['y', 'n'].map(&:to_operator) end def self.available_values(*) diff --git a/modules/reporting/app/models/cost_query/filter/permission_filter.rb b/modules/reporting/app/models/cost_query/filter/permission_filter.rb index 8a59058a9d78..86adddfcdbe1 100644 --- a/modules/reporting/app/models/cost_query/filter/permission_filter.rb +++ b/modules/reporting/app/models/cost_query/filter/permission_filter.rb @@ -29,7 +29,7 @@ class CostQuery::Filter::PermissionFilter < Report::Filter::Base dont_display! not_selectable! - db_field "" + db_field '' singleton initialize_query_with { |query| query.filter to_s.demodulize.to_sym } @@ -46,10 +46,10 @@ def permission_for(type) def display_costs "(#{permission_statement :view_hourly_rates} " \ "AND #{permission_statement :view_cost_rates}) " \ - "OR " \ + 'OR ' \ "(#{permission_statement :view_own_hourly_rate} " \ "AND type = 'TimeEntry' AND user_id = #{User.current.id}) " \ - "OR " \ + 'OR ' \ "(#{permission_statement :view_cost_rates} " \ "AND type = 'CostEntry' AND user_id = #{User.current.id})" end @@ -57,9 +57,9 @@ def display_costs def sql_statement super.tap do |query| query.from.each_subselect do |sub| - sub.where permission_for(sub == query.from.first ? "time" : "cost") - sub.select.delete_if { |f| f.end_with? "display_costs" } - sub.select display_costs: switch(display_costs => "1", else: 0) + sub.where permission_for(sub == query.from.first ? 'time' : 'cost') + sub.select.delete_if { |f| f.end_with? 'display_costs' } + sub.select display_costs: switch(display_costs => '1', else: 0) end end end diff --git a/modules/reporting/app/models/cost_query/filter/priority_id.rb b/modules/reporting/app/models/cost_query/filter/priority_id.rb index 14ef1020177f..258c5800d060 100644 --- a/modules/reporting/app/models/cost_query/filter/priority_id.rb +++ b/modules/reporting/app/models/cost_query/filter/priority_id.rb @@ -35,6 +35,6 @@ def self.label end def self.available_values(*) - IssuePriority.order(Arel.sql("position DESC")).pluck(:name, :id) + IssuePriority.order(Arel.sql('position DESC')).pluck(:name, :id) end end diff --git a/modules/reporting/app/models/cost_query/filter/project_id.rb b/modules/reporting/app/models/cost_query/filter/project_id.rb index 786bd7ad958c..eeeaa1eb2d94 100644 --- a/modules/reporting/app/models/cost_query/filter/project_id.rb +++ b/modules/reporting/app/models/cost_query/filter/project_id.rb @@ -27,14 +27,14 @@ #++ class CostQuery::Filter::ProjectId < Report::Filter::Base - db_field "entries.project_id" + db_field 'entries.project_id' def self.label Project.model_name.human end def self.available_operators - ["=", "!", "=_child_projects", "!_child_projects"].map(&:to_operator) + ['=', '!', '=_child_projects', '!_child_projects'].map(&:to_operator) end ## diff --git a/modules/reporting/app/models/cost_query/filter/status_id.rb b/modules/reporting/app/models/cost_query/filter/status_id.rb index 14ba39203054..9dacbdaf7aa8 100644 --- a/modules/reporting/app/models/cost_query/filter/status_id.rb +++ b/modules/reporting/app/models/cost_query/filter/status_id.rb @@ -27,7 +27,7 @@ #++ class CostQuery::Filter::StatusId < Report::Filter::Base - available_operators "c", "o" + available_operators 'c', 'o' join_table WorkPackage, Status => [WorkPackage, :status] applies_for :label_work_package_attributes @@ -36,6 +36,6 @@ def self.label end def self.available_values(*) - Status.order(Arel.sql("name")).pluck(:name, :id) + Status.order(Arel.sql('name')).pluck(:name, :id) end end diff --git a/modules/reporting/app/models/cost_query/filter/tmonth.rb b/modules/reporting/app/models/cost_query/filter/tmonth.rb index e3e0c7ceb135..5d62d320fc8b 100644 --- a/modules/reporting/app/models/cost_query/filter/tmonth.rb +++ b/modules/reporting/app/models/cost_query/filter/tmonth.rb @@ -34,6 +34,6 @@ def self.label end def self.available_values(*) - 1.upto(12).map { |i| [::I18n.t("date.month_names")[i], i] } + 1.upto(12).map { |i| [::I18n.t('date.month_names')[i], i] } end end diff --git a/modules/reporting/app/models/cost_query/filter/type_id.rb b/modules/reporting/app/models/cost_query/filter/type_id.rb index dd7b78e2c3a8..92bcf3b538ff 100644 --- a/modules/reporting/app/models/cost_query/filter/type_id.rb +++ b/modules/reporting/app/models/cost_query/filter/type_id.rb @@ -35,6 +35,6 @@ def self.label end def self.available_values(*) - Type.order(Arel.sql("name")).pluck(:name, :id) + Type.order(Arel.sql('name')).pluck(:name, :id) end end diff --git a/modules/reporting/app/models/cost_query/filter/updated_on.rb b/modules/reporting/app/models/cost_query/filter/updated_on.rb index 623d8381e551..9f379d04bd23 100644 --- a/modules/reporting/app/models/cost_query/filter/updated_on.rb +++ b/modules/reporting/app/models/cost_query/filter/updated_on.rb @@ -27,7 +27,7 @@ #++ class CostQuery::Filter::UpdatedOn < Report::Filter::Base - db_field "entries.updated_at" + db_field 'entries.updated_at' use :time_operators def self.label diff --git a/modules/reporting/app/models/cost_query/filter/user_id.rb b/modules/reporting/app/models/cost_query/filter/user_id.rb index 9d3c70c31e28..215e593850c3 100644 --- a/modules/reporting/app/models/cost_query/filter/user_id.rb +++ b/modules/reporting/app/models/cost_query/filter/user_id.rb @@ -32,7 +32,7 @@ def self.label end def self.me_value - "me".freeze + 'me'.freeze end def transformed_values diff --git a/modules/reporting/app/models/cost_query/filter/work_package_id.rb b/modules/reporting/app/models/cost_query/filter/work_package_id.rb index d26f48ffcfb4..9174407e3e48 100644 --- a/modules/reporting/app/models/cost_query/filter/work_package_id.rb +++ b/modules/reporting/app/models/cost_query/filter/work_package_id.rb @@ -40,7 +40,7 @@ def self.available_values(*) end def self.available_operators - ["="].map(&:to_operator) + ['='].map(&:to_operator) end ## @@ -55,7 +55,7 @@ def self.label_for_value(value) def self.text_for_tuple(id, subject) str = "##{id} " - str << (subject.length > 30 ? subject.first(26) + "..." : subject) + str << (subject.length > 30 ? subject.first(26) + '...' : subject) end def self.text_for_work_package(i) diff --git a/modules/reporting/app/models/cost_query/operator.rb b/modules/reporting/app/models/cost_query/operator.rb index 47ef027bc1bb..85675cc42960 100644 --- a/modules/reporting/app/models/cost_query/operator.rb +++ b/modules/reporting/app/models/cost_query/operator.rb @@ -30,7 +30,7 @@ class CostQuery::Operator < Report::Operator # Operators from Redmine new "c", arity: 0, label: :label_closed do def modify(query, field, *_values) - raise "wrong field" if field.to_s.split(".").last != "status_id" + raise "wrong field" if field.to_s.split('.').last != "status_id" query.where "(#{Status.table_name}.is_closed = #{quoted_true})" query @@ -39,7 +39,7 @@ def modify(query, field, *_values) new "o", arity: 0, label: :label_open do def modify(query, field, *_values) - raise "wrong field" if field.to_s.split(".").last != "status_id" + raise "wrong field" if field.to_s.split('.').last != "status_id" query.where "(#{Status.table_name}.is_closed = #{quoted_false})" query @@ -62,7 +62,7 @@ def modify(query, field, *values) def modify(query, field, *values) p_ids = [] values.each do |value| - value.to_s.split(",").each do |id| + value.to_s.split(',').each do |id| p_ids += ([id] << Project.find(id).descendants.map(&:id)) end end diff --git a/modules/reporting/app/models/cost_query/sql_statement.rb b/modules/reporting/app/models/cost_query/sql_statement.rb index db4e05a32dbc..d7ebfd3d2a8a 100644 --- a/modules/reporting/app/models/cost_query/sql_statement.rb +++ b/modules/reporting/app/models/cost_query/sql_statement.rb @@ -44,7 +44,7 @@ def initialize(table, desc = "") # this is a hack to ensure that additional joins added by filters do not result # in additional columns being selected. def to_s - select(["entries.*"]) if select == ["*"] && group_by.empty? && entry_union + select(['entries.*']) if select == ['*'] && group_by.empty? && entry_union super end diff --git a/modules/reporting/app/models/entry.rb b/modules/reporting/app/models/entry.rb index 4af0eace0c45..17a4f515aad3 100644 --- a/modules/reporting/app/models/entry.rb +++ b/modules/reporting/app/models/entry.rb @@ -64,12 +64,12 @@ def calculate(type, *) private def all(*args) - ActiveSupport::Deprecation.warn("Passing arguments is deprecated") if args.any? + ActiveSupport::Deprecation.warn('Passing arguments is deprecated') if args.any? find_many :all # *args end def count(*args) - ActiveSupport::Deprecation.warn("Passing arguments is deprecated") if args.any? + ActiveSupport::Deprecation.warn('Passing arguments is deprecated') if args.any? find_many :count # *args end diff --git a/modules/reporting/app/workers/cost_query/export_job.rb b/modules/reporting/app/workers/cost_query/export_job.rb index 530e40f1134d..a9b597a955c7 100644 --- a/modules/reporting/app/workers/cost_query/export_job.rb +++ b/modules/reporting/app/workers/cost_query/export_job.rb @@ -1,10 +1,10 @@ -require "active_storage/filename" +require 'active_storage/filename' class CostQuery::ExportJob < Exports::ExportJob self.model = ::CostQuery def title - I18n.t("export.cost_reports.title") + I18n.t('export.cost_reports.title') end def project @@ -30,12 +30,12 @@ def export! def xls_report_result params = { query:, project:, cost_types: } content = ::OpenProject::Reporting::CostEntryXlsTable.generate(params).xls - time = Time.current.strftime("%Y-%m-%d-T-%H-%M-%S") + time = Time.current.strftime('%Y-%m-%d-T-%H-%M-%S') export_title = "cost-report-#{time}.xls" ::Exports::Result.new(format: :xls, title: export_title, - mime_type: "application/vnd.ms-excel", + mime_type: 'application/vnd.ms-excel', content:) end @@ -44,8 +44,8 @@ def build_query(filters, groups = {}) query = CostQuery.new(project:) query.tap do |q| filters[:operators].each do |filter, operator| - unless filters[:values][filter] == ["<>"] - values = Array(filters[:values][filter]).map { |v| v == "<>" ? nil : v } + unless filters[:values][filter] == ['<>'] + values = Array(filters[:values][filter]).map { |v| v == '<>' ? nil : v } q.filter(filter.to_sym, operator:, values:) diff --git a/modules/reporting/config/locales/crowdin/zh-TW.yml b/modules/reporting/config/locales/crowdin/zh-TW.yml index eab8024031e0..2c0a3fdc5f58 100644 --- a/modules/reporting/config/locales/crowdin/zh-TW.yml +++ b/modules/reporting/config/locales/crowdin/zh-TW.yml @@ -51,7 +51,7 @@ zh-TW: label_money: "現金價值" label_month_reporting: "月 (已用)" label_new_report: "新建成本報表" - label_open: "進行中" + label_open: "開啟" label_operator: "操作員" label_private_report_plural: "私密成本報告" label_progress_bar_explanation: "產生報告中..." diff --git a/modules/reporting/config/routes.rb b/modules/reporting/config/routes.rb index 1cc8ea7b225e..81d826ae64b6 100644 --- a/modules/reporting/config/routes.rb +++ b/modules/reporting/config/routes.rb @@ -27,7 +27,7 @@ #++ Rails.application.routes.draw do - scope "projects/:project_id" do + scope 'projects/:project_id' do resources :cost_reports, except: :create do collection do match :index, via: %i[get post] diff --git a/modules/reporting/db/migrate/20180323130704_to_v710_aggregated_reporting_migrations.rb b/modules/reporting/db/migrate/20180323130704_to_v710_aggregated_reporting_migrations.rb index aa464e64736d..7b4b581cea3e 100644 --- a/modules/reporting/db/migrate/20180323130704_to_v710_aggregated_reporting_migrations.rb +++ b/modules/reporting/db/migrate/20180323130704_to_v710_aggregated_reporting_migrations.rb @@ -57,7 +57,7 @@ def down def migrations MIGRATION_FILES.split.map do |m| - m.gsub(/_.*\z/, "") + m.gsub(/_.*\z/, '') end end end diff --git a/modules/reporting/lib/open_project/reporting/cost_entry_xls_table.rb b/modules/reporting/lib/open_project/reporting/cost_entry_xls_table.rb index 6cdd22eedb73..11851766e81f 100644 --- a/modules/reporting/lib/open_project/reporting/cost_entry_xls_table.rb +++ b/modules/reporting/lib/open_project/reporting/cost_entry_xls_table.rb @@ -19,7 +19,7 @@ def setup_query_for_tab(query, unit_id) @unit_id = unit_id if @unit_id != 0 - @query.filter :cost_type_id, operator: "=", value: @unit_id.to_s + @query.filter :cost_type_id, operator: '=', value: @unit_id.to_s @cost_type = CostType.find(unit_id) if unit_id.positive? end end @@ -53,7 +53,7 @@ def format_columns end def cost_row(result) - current_cost_type_id = result.fields["cost_type_id"].to_i + current_cost_type_id = result.fields['cost_type_id'].to_i cost_entry_attributes .map { |field| show_field field, result.fields[field.to_s] } @@ -67,7 +67,7 @@ def cost_row(result) end def build_footer - footer = [""] * cost_entry_attributes.size + footer = [''] * cost_entry_attributes.size footer += if show_result(query, 0) == show_result(query) multiple_unit_types_footer else @@ -77,11 +77,11 @@ def build_footer end def one_unit_type_footer - [show_result(query), "", show_result(query, 0)] + [show_result(query), '', show_result(query, 0)] end def multiple_unit_types_footer - ["", "", show_result(query)] + ['', '', show_result(query)] end def headers @@ -99,8 +99,8 @@ def sorted_results query .each_direct_result .map(&:itself) - .group_by { |r| DateTime.parse(r.fields["spent_on"]) } + .group_by { |r| DateTime.parse(r.fields['spent_on']) } .sort - .flat_map { |_, date_results| date_results.sort_by { |r| r.fields["id"] } } + .flat_map { |_, date_results| date_results.sort_by { |r| r.fields['id'] } } end end diff --git a/modules/reporting/lib/open_project/reporting/engine.rb b/modules/reporting/lib/open_project/reporting/engine.rb index 0a1e34e48bff..f9e59e754e64 100644 --- a/modules/reporting/lib/open_project/reporting/engine.rb +++ b/modules/reporting/lib/open_project/reporting/engine.rb @@ -34,8 +34,8 @@ class Engine < ::Rails::Engine config.eager_load_paths += Dir["#{config.root}/lib/"] - register "openproject-reporting", - author_url: "https://www.openproject.org", + register 'openproject-reporting', + author_url: 'https://www.openproject.org', bundled: true do view_actions = %i[index show drill_down available_values] edit_actions = %i[create update rename destroy] @@ -75,54 +75,54 @@ class Engine < ::Rails::Engine # menu extensions menu :top_menu, :cost_reports_global, - { controller: "/cost_reports", action: "index", project_id: nil }, + { controller: '/cost_reports', action: 'index', project_id: nil }, caption: :cost_reports_title, - icon: "cost-reports", + icon: 'cost-reports', if: should_render menu :global_menu, :cost_reports_global, - { controller: "/cost_reports", action: "index", project_id: nil }, + { controller: '/cost_reports', action: 'index', project_id: nil }, after: :news, caption: :cost_reports_title, - icon: "cost-reports", + icon: 'cost-reports', if: should_render menu :global_menu, :cost_reports_global_report_menu, - { controller: "/cost_reports", action: "index", project_id: nil }, + { controller: '/cost_reports', action: 'index', project_id: nil }, parent: :cost_reports_global, - partial: "cost_reports/report_menu", + partial: 'cost_reports/report_menu', if: should_render menu :project_menu, :costs, - { controller: "/cost_reports", action: "index" }, + { controller: '/cost_reports', action: 'index' }, after: :news, caption: :cost_reports_title, if: Proc.new { |project| project.module_enabled?(:costs) }, - icon: "cost-reports" + icon: 'cost-reports' menu :project_menu, :costs_menu, - { controller: "/cost_reports", action: "index" }, + { controller: '/cost_reports', action: 'index' }, if: Proc.new { |project| project.module_enabled?(:costs) }, - partial: "/cost_reports/report_menu", + partial: '/cost_reports/report_menu', parent: :costs end initializer "reporting.register_hooks" do # don't use require_dependency to not reload hooks in development mode - require "open_project/reporting/hooks" + require 'open_project/reporting/hooks' end - initializer "reporting.load_patches" do - require_relative "patches/big_decimal_patch" - require_relative "patches/to_date_patch" + initializer 'reporting.load_patches' do + require_relative 'patches/big_decimal_patch' + require_relative 'patches/to_date_patch' end - initializer "reporting.configuration" do - ::Settings::Definition.add "cost_reporting_cache_filter_classes", + initializer 'reporting.configuration' do + ::Settings::Definition.add 'cost_reporting_cache_filter_classes', default: true, format: :boolean end diff --git a/modules/reporting/lib/open_project/reporting/patches/setting_seeder_patch.rb b/modules/reporting/lib/open_project/reporting/patches/setting_seeder_patch.rb index 8a23156abf1d..45c7dbb1481b 100644 --- a/modules/reporting/lib/open_project/reporting/patches/setting_seeder_patch.rb +++ b/modules/reporting/lib/open_project/reporting/patches/setting_seeder_patch.rb @@ -35,8 +35,8 @@ module InstanceMethods def data original_data = super - unless original_data["default_projects_modules"].include? "reporting_module" - original_data["default_projects_modules"] << "reporting_module" + unless original_data['default_projects_modules'].include? 'reporting_module' + original_data['default_projects_modules'] << 'reporting_module' end original_data diff --git a/modules/reporting/lib/open_project/reporting/patches/to_date_patch.rb b/modules/reporting/lib/open_project/reporting/patches/to_date_patch.rb index 38817aa998ba..9f53f56f0188 100644 --- a/modules/reporting/lib/open_project/reporting/patches/to_date_patch.rb +++ b/modules/reporting/lib/open_project/reporting/patches/to_date_patch.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "date" +require 'date' module OpenProject::Reporting::Patches::ToDatePatch module StringAndNil diff --git a/modules/reporting/lib/openproject-reporting.rb b/modules/reporting/lib/openproject-reporting.rb index 3e3364089053..a8ef79633a7a 100644 --- a/modules/reporting/lib/openproject-reporting.rb +++ b/modules/reporting/lib/openproject-reporting.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/reporting" +require 'open_project/reporting' diff --git a/modules/reporting/lib/report/chainable.rb b/modules/reporting/lib/report/chainable.rb index 19078a56ea26..ebf31f7b80d5 100644 --- a/modules/reporting/lib/report/chainable.rb +++ b/modules/reporting/lib/report/chainable.rb @@ -37,7 +37,7 @@ class Chainable # this attr. should point to a symbol useable for translations inherited_attribute :applies_for, default: :label_cost_entry_attributes - def_delegators :"self.class", :table_joins, :table_name, :field, :display?, :underscore_name + def_delegators :'self.class', :table_joins, :table_name, :field, :display?, :underscore_name def self.accepts_property(*list) engine.accepted_properties.push(*list.map(&:to_s)) @@ -72,7 +72,7 @@ def self.available def self.register(label) available << klass - set_inherited_attribute "label", label + set_inherited_attribute 'label', label end def self.table_joins @@ -117,7 +117,7 @@ def self.cache_key inherited_attribute :properties, list: true def self.label - "Translation needed" + 'Translation needed' end class << self @@ -192,7 +192,7 @@ def compute_to_a end def to_s - URI.escape to_a.map(&:join).join(",") + URI.escape to_a.map(&:join).join(',') end def serialize diff --git a/modules/reporting/lib/report/filter/base.rb b/modules/reporting/lib/report/filter/base.rb index c029100c4ca8..2f59b0c83212 100644 --- a/modules/reporting/lib/report/filter/base.rb +++ b/modules/reporting/lib/report/filter/base.rb @@ -39,12 +39,12 @@ class Base < Report::Chainable accepts_property :values, :value, :operator mattr_accessor :skip_inherited_operators - self.skip_inherited_operators = [:time_operators, "y", "n"] + self.skip_inherited_operators = [:time_operators, 'y', 'n'] attr_accessor :values def cache_key - self.class.cache_key + operator.to_s + Array(values).join(",") + self.class.cache_key + operator.to_s + Array(values).join(',') end ## diff --git a/modules/reporting/lib/report/filter/multi_choice.rb b/modules/reporting/lib/report/filter/multi_choice.rb index f8dc5601b007..fe3f2a5415d9 100644 --- a/modules/reporting/lib/report/filter/multi_choice.rb +++ b/modules/reporting/lib/report/filter/multi_choice.rb @@ -29,7 +29,7 @@ class Report::Filter class MultiChoice < Base dont_inherit :available_operators - use "=" + use '=' def self.is_multiple_choice? true diff --git a/modules/reporting/lib/report/filter/no_filter.rb b/modules/reporting/lib/report/filter/no_filter.rb index 41b2c87219cb..81193f802320 100644 --- a/modules/reporting/lib/report/filter/no_filter.rb +++ b/modules/reporting/lib/report/filter/no_filter.rb @@ -27,7 +27,7 @@ #++ class Report::Filter::NoFilter < Report::Filter::Base - table_name "entries" + table_name 'entries' dont_display! singleton diff --git a/modules/reporting/lib/report/group_by/base.rb b/modules/reporting/lib/report/group_by/base.rb index cd029d4fa120..b71d41191371 100644 --- a/modules/reporting/lib/report/group_by/base.rb +++ b/modules/reporting/lib/report/group_by/base.rb @@ -54,7 +54,7 @@ def cache_key def all_group_fields(prefix = true) @all_group_fields ||= [] @all_group_fields[prefix ? 0 : 1] ||= begin - fields = group_fields.reject { |c| c.blank? or c == "base" } + fields = group_fields.reject { |c| c.blank? or c == 'base' } (parent ? parent.all_group_fields(prefix) : []) + (prefix ? with_table(fields) : fields) end.uniq end @@ -78,7 +78,7 @@ def select_fields def all_select_fields(prefix = true) @all_select_fields ||= [] @all_select_fields[prefix ? 0 : 1] ||= begin - fields = select_fields.reject { |c| c.blank? or c == "base" } + fields = select_fields.reject { |c| c.blank? or c == 'base' } (parent ? parent.all_select_fields(prefix) : []) + (prefix ? with_table(fields) : fields) end.uniq end diff --git a/modules/reporting/lib/report/group_by/singleton_value.rb b/modules/reporting/lib/report/group_by/singleton_value.rb index f41e597066ff..f2d0777f799c 100644 --- a/modules/reporting/lib/report/group_by/singleton_value.rb +++ b/modules/reporting/lib/report/group_by/singleton_value.rb @@ -30,12 +30,12 @@ class Report::GroupBy class SingletonValue < Base dont_display! - put_sql_table_names "singleton_value" => false - select_fields "1 as singleton_value" + put_sql_table_names 'singleton_value' => false + select_fields '1 as singleton_value' def define_group(sql) - sql.select "1 as singleton_value" - sql.group_by "singleton_value" + sql.select '1 as singleton_value' + sql.group_by 'singleton_value' end end end diff --git a/modules/reporting/lib/report/group_by/sql_aggregation.rb b/modules/reporting/lib/report/group_by/sql_aggregation.rb index bad9b6a4fb0d..c82d0ac134db 100644 --- a/modules/reporting/lib/report/group_by/sql_aggregation.rb +++ b/modules/reporting/lib/report/group_by/sql_aggregation.rb @@ -39,7 +39,7 @@ def compute_result def sql_statement super.tap do |sql| define_group sql - sql.count unless sql.selects.include? "count" + sql.count unless sql.selects.include? 'count' end end end diff --git a/modules/reporting/lib/report/operator.rb b/modules/reporting/lib/report/operator.rb index e148ef488375..35654636dbe5 100644 --- a/modules/reporting/lib/report/operator.rb +++ b/modules/reporting/lib/report/operator.rb @@ -57,14 +57,14 @@ def label end # Operators from Redmine - new ">t-", label: :label_less_than_ago do + new '>t-', label: :label_less_than_ago do include DateRange def modify(query, field, value) super(query, field, -value.to_i, 0) end end - new "w", arity: 0, label: :label_this_week do + new 'w', arity: 0, label: :label_this_week do def modify(query, field, offset = nil) offset ||= 0 first_day = begin @@ -75,50 +75,50 @@ def modify(query, field, offset = nil) from = Time.now.at_beginning_of_week + ((first_day % 7) - 1).days from -= offset.days - "<>d".to_operator.modify query, field, from, from + 7.days + '<>d'.to_operator.modify query, field, from, from + 7.days end end - new "t+", label: :label_in do + new 't+', label: :label_in do include DateRange def modify(query, field, *values) super(query, field, values.first.to_i, values.first.to_i) end end - new "<=", label: :label_less_or_equal + new '<=', label: :label_less_or_equal - new "!", label: :label_not_equals do + new '!', label: :label_not_equals do def modify(query, field, *values) where_clause = "(#{field} IS NULL" where_clause += " OR #{field} NOT IN #{collection(*values)}" unless values.all?(&:blank?) - where_clause += ")" + where_clause += ')' query.where where_clause query end end - new "t-", label: :label_ago do + new 't-', label: :label_ago do include DateRange def modify(query, field, *values) super(query, field, -values.first.to_i, -values.first.to_i) end end - new "!~", arity: 1, label: :label_not_contains do + new '!~', arity: 1, label: :label_not_contains do def modify(query, field, *values) - value = values.first || "" + value = values.first || '' query.where "LOWER(#{field}) NOT LIKE '%#{quote_string(value.to_s.downcase)}%'" query end end - new "=", label: :label_equals do + new '=', label: :label_equals do def modify(query, field, *values) if values.size == 1 && values.first.nil? query.where "#{field} IS NULL" elsif values.all?(&:blank?) - query.where "1=0" + query.where '1=0' else query.where "#{field} IN #{collection(*values)}" end @@ -126,80 +126,80 @@ def modify(query, field, *values) end end - new "~", arity: 1, label: :label_contains do + new '~', arity: 1, label: :label_contains do def modify(query, field, *values) - value = values.first || "" + value = values.first || '' query.where "LOWER(#{field}) LIKE '%#{quote_string(value.to_s.downcase)}%'" query end end - new "=", label: :label_greater_or_equal + new '>=', label: :label_greater_or_equal - new "!*", arity: 0, where_clause: "%s IS NULL", label: :label_none + new '!*', arity: 0, where_clause: '%s IS NULL', label: :label_none - new "t+", label: :label_in_more_than do + new '>t+', label: :label_in_more_than do include DateRange def modify(query, field, value) super(query, field, value.to_i, nil) end end - new "*", arity: 0, where_clause: "%s IS NOT NULL", label: :label_all + new '*', arity: 0, where_clause: '%s IS NOT NULL', label: :label_all # Our own operators - new "<", label: :label_less - new ">", label: :label_greater + new '<', label: :label_less + new '>', label: :label_greater - new "=n", label: :label_equals do + new '=n', label: :label_equals do def modify(query, field, value) query.where "#{field} = #{parse_number_string(value)}" query end end - new "0", label: :label_none, where_clause: "%s = 0" - new "y", label: :label_yes, arity: 0, where_clause: "%s IS NOT NULL" - new "n", label: :label_no, arity: 0, where_clause: "%s IS NULL" + new '0', label: :label_none, where_clause: '%s = 0' + new 'y', label: :label_yes, arity: 0, where_clause: '%s IS NOT NULL' + new 'n', label: :label_no, arity: 0, where_clause: '%s IS NULL' - new "d", label: :label_greater_or_equal, validate: :dates do + new '>d', label: :label_greater_or_equal, validate: :dates do def modify(query, field, value) return query if value.to_s.empty? - ">=".to_operator.modify query, field, quoted_date(value) + '>='.to_operator.modify query, field, quoted_date(value) end end - new "<>d", label: :label_between, validate: :dates do + new '<>d', label: :label_between, validate: :dates do def modify(query, field, from, to) return query if from.to_s.empty? || to.to_s.empty? @@ -208,39 +208,39 @@ def modify(query, field, from, to) end end - new "=d", label: :label_date_on, validate: :dates do + new '=d', label: :label_date_on, validate: :dates do def modify(query, field, value) return query if value.to_s.empty? - "=".to_operator.modify query, field, quoted_date(value) + '='.to_operator.modify query, field, quoted_date(value) end end - new ">=d", label: :label_days_ago, validate: :integers do + new '>=d', label: :label_days_ago, validate: :integers do force! :integers def modify(query, field, value) now = Time.now from = (now - value.to_i.days).beginning_of_day - "<>d".to_operator.modify query, field, from, now + '<>d'.to_operator.modify query, field, from, now end end - new "?=", label: :label_null_or_equal do + new '?=', label: :label_null_or_equal do def modify(query, field, *values) where_clause = "(#{field} IS NULL" where_clause += " OR #{field} IN #{collection(*values)}" unless values.compact.empty? - where_clause += ")" + where_clause += ')' query.where where_clause query end end - new "?!", label: :label_not_null_and_not_equal do + new '?!', label: :label_not_null_and_not_equal do def modify(query, field, *values) where_clause = "(#{field} IS NOT NULL" where_clause += " AND #{field} NOT IN #{collection(*values)}" unless values.compact.empty? - where_clause += ")" + where_clause += ')' query.where where_clause query end @@ -297,28 +297,28 @@ def self.defaults(&) end def self.default_operator - find "=" + find '=' end def self.integer_operators - ["<", ">", "<=", ">="].map(&:to_operator) + ['<', '>', '<=', '>='].map(&:to_operator) end def self.null_operators - ["*", "!*"].map(&:to_operator) + ['*', '!*'].map(&:to_operator) end def self.string_operators - ["!~", "~"].map(&:to_operator) + ['!~', '~'].map(&:to_operator) end def self.time_operators # ["t-", "t+", ">t-", "t+", "d", ">d", "=d"].map(&:to_operator) + ['t', 'w', '<>d', '>d', '=d'].map(&:to_operator) end def self.default_operators - ["=", "!"].map(&:to_operator) + ['=', '!'].map(&:to_operator) end attr_reader :name @@ -365,7 +365,7 @@ def aka(alt_name, alt_label) op = all[name].clone op.send(:rename_to, alt_name) - op.singleton_class.send(:define_method, "label") { alt_label } + op.singleton_class.send(:define_method, 'label') { alt_label } all[alt] = op end diff --git a/modules/reporting/lib/report/query_utils.rb b/modules/reporting/lib/report/query_utils.rb index d4bd166f3f94..83ecc312938d 100644 --- a/modules/reporting/lib/report/query_utils.rb +++ b/modules/reporting/lib/report/query_utils.rb @@ -30,7 +30,7 @@ module Report::QueryUtils Infinity = 1.0 / 0 include Engine - delegate :quoted_false, :quoted_true, to: "engine.reporting_connection" + delegate :quoted_false, :quoted_true, to: 'engine.reporting_connection' attr_writer :engine include Costs::NumberHelper @@ -57,7 +57,7 @@ def current_language # @param [#flatten] *values Ruby collection # @return [String] SQL collection def collection(*values) - return "" if values.empty? + return '' if values.empty? v = if values.is_a?(Array) values.flatten.each_with_object([]) do |str, l| @@ -74,7 +74,7 @@ def split_with_safe_return(str) # From ruby doc: # When the input str is empty an empty Array is returned as the string is # considered to have no fields to split. - str.to_s.empty? ? "" : str.to_s.split(",") + str.to_s.empty? ? '' : str.to_s.split(',') end ## @@ -129,7 +129,7 @@ def table_name_for(object) # @param [Object, optional] default_table Table name to use if no table name is given. # @return [String] Field name. def field_name_for(arg) - return "NULL" unless arg + return 'NULL' unless arg return field_name_for(arg.keys.first) if arg.is_a? Hash return "#{table_name_for(arg.first)}.#{arg.last}" if arg.is_a? Array and arg.size == 2 @@ -179,7 +179,7 @@ def convert_unless_nil(value) def map_field(key, value) case key.to_s - when "tweek", "tmonth", "tweek" then value.to_i + when 'tweek', 'tmonth', 'tweek' then value.to_i else convert_unless_nil(value, &:to_s) end end diff --git a/modules/reporting/lib/report/result.rb b/modules/reporting/lib/report/result.rb index bfc6d58069fc..7b3375f25a62 100644 --- a/modules/reporting/lib/report/result.rb +++ b/modules/reporting/lib/report/result.rb @@ -162,11 +162,11 @@ def has_children? end def count - self["count"].to_i + self['count'].to_i end def units - self["units"].to_d + self['units'].to_d end ## diff --git a/modules/reporting/lib/report/sql_statement.rb b/modules/reporting/lib/report/sql_statement.rb index 3a0313e21513..00417cbe07d4 100644 --- a/modules/reporting/lib/report/sql_statement.rb +++ b/modules/reporting/lib/report/sql_statement.rb @@ -61,7 +61,7 @@ def gsub(...) # Generates new SqlStatement. # # @param [String, #to_s] table Table name (or subselect) for from part. - def initialize(table, desc = "") + def initialize(table, desc = '') self.desc = desc from table end @@ -93,7 +93,7 @@ def sum(field, name = :sum, type = :sum) # # @param [#to_s] field Name of the field to aggregate on (defaults to *) # @param [#to_s] name Name of the result (defaults to sum) - def count(field = "*", name = :count) + def count(field = '*', name = :count) sum field, name, :count end @@ -143,7 +143,7 @@ def from(table = nil) # @param [Array, Hash, String] fields Parameters passed to sanitize_sql_for_conditions. # @see Report::QueryUtils#sanitize_sql_for_conditions def where(fields = nil) - @where ||= ["1=1"] + @where ||= ['1=1'] unless fields.nil? @where << sanitize_sql_for_conditions(fields) @sql = nil @@ -171,7 +171,7 @@ def joins # @see #joins def join(*list) @sql = nil - join_syntax = "LEFT OUTER JOIN %1$s ON %1$s.id = %2$s_id" + join_syntax = 'LEFT OUTER JOIN %1$s ON %1$s.id = %2$s_id' list.each do |e| case e when Class then joins << (join_syntax % [table_name_for(e), e.lookup_ancestors.last.model_name.to_s.underscore]) @@ -186,7 +186,7 @@ def join(*list) def default_select(value = nil) @default_select = value if value - @default_select ||= ["*"] + @default_select ||= ['*'] end ## @@ -222,7 +222,7 @@ def select(*fields) end # when doing a union in sql, both subselects must have the same order. # by sorting here we never ever have to worry about this again, sucker! - @select = @select.uniq.sort_by { |x| x.split(" as ").last } + @select = @select.uniq.sort_by { |x| x.split(' as ').last } end end @@ -246,7 +246,7 @@ def never_select(*fields) # Return the names which have been bound through select statements # @return [Array] All fields for select part def selects - @select.map { |s| s.split(" as ").last } + @select.map { |s| s.split(' as ').last } end ## diff --git a/modules/reporting/lib/report/validation.rb b/modules/reporting/lib/report/validation.rb index 3d555a4e27cf..72462dfcb5e8 100644 --- a/modules/reporting/lib/report/validation.rb +++ b/modules/reporting/lib/report/validation.rb @@ -40,7 +40,7 @@ def register_validation(val_method) begin val_module = Report::Validation.const_get const_name singleton_class.send(:include, val_module) - val_method = "validate_" + val_method.to_s.pluralize + val_method = 'validate_' + val_method.to_s.pluralize if method(val_method) validations << val_method else diff --git a/modules/reporting/lib/report/walker.rb b/modules/reporting/lib/report/walker.rb index 4ce0749d8c21..201e6002a422 100644 --- a/modules/reporting/lib/report/walker.rb +++ b/modules/reporting/lib/report/walker.rb @@ -87,7 +87,7 @@ def headers(result = nil, &) end def reverse_headers - fail "call header first" unless @header_stack + fail 'call header first' unless @header_stack first = true @header_stack.reverse_each do |list| @@ -99,7 +99,7 @@ def reverse_headers end def headers_empty? - fail "call header first" unless @header_stack + fail 'call header first' unless @header_stack @header_stack.empty? end diff --git a/modules/reporting/lib/widget/base.rb b/modules/reporting/lib/widget/base.rb index 3138db91fa2e..98e213b5c0cb 100644 --- a/modules/reporting/lib/widget/base.rb +++ b/modules/reporting/lib/widget/base.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "digest/sha1" +require 'digest/sha1' module ::Widget class Base < Widget::ReportingWidget @@ -56,9 +56,9 @@ def initialize(query) # Write a string to the canvas. The string is marked as html_safe. # This will write twice, if @cache_output is set. def write(str) - str ||= "" - @output ||= "".html_safe - @output = @output + "" if @output.frozen? # Rails 2 freezes tag strings + str ||= '' + @output ||= ''.html_safe + @output = @output + '' if @output.frozen? # Rails 2 freezes tag strings @output.concat str.html_safe @cache_output.concat(str.html_safe) if @cache_output str.html_safe @@ -116,7 +116,7 @@ def render_with_cache(_options = {}, &) # Set the canvas. If the canvas object isn't a string (e.g. cannot be cached easily), # a @cache_output String is created, that will mirror what is being written to the canvas. def set_canvas(canvas) - @cache_output = "".html_safe + @cache_output = ''.html_safe @output = canvas end end diff --git a/modules/reporting/lib/widget/controls/apply.rb b/modules/reporting/lib/widget/controls/apply.rb index 2ede1fcab776..aaa12db717d2 100644 --- a/modules/reporting/lib/widget/controls/apply.rb +++ b/modules/reporting/lib/widget/controls/apply.rb @@ -29,9 +29,9 @@ class Widget::Controls::Apply < Widget::Controls def render write link_to(I18n.t(:button_apply), - "#", - id: "query-icon-apply-button", - class: "button -primary", - "data-target": url_for(action: "index", set_filter: "1")) + '#', + id: 'query-icon-apply-button', + class: 'button -highlight', + 'data-target': url_for(action: 'index', set_filter: '1')) end end diff --git a/modules/reporting/lib/widget/controls/clear.rb b/modules/reporting/lib/widget/controls/clear.rb index dfb4261cf087..a08d6bcd59db 100644 --- a/modules/reporting/lib/widget/controls/clear.rb +++ b/modules/reporting/lib/widget/controls/clear.rb @@ -29,8 +29,8 @@ class Widget::Controls::Clear < Widget::Controls def render write link_to(I18n.t(:button_clear), - "#", - id: "query-link-clear", - class: "button icon-context icon-undo") + '#', + id: 'query-link-clear', + class: 'button icon-context icon-undo') end end diff --git a/modules/reporting/lib/widget/controls/delete.rb b/modules/reporting/lib/widget/controls/delete.rb index 4959c927a63d..a783f9e12e20 100644 --- a/modules/reporting/lib/widget/controls/delete.rb +++ b/modules/reporting/lib/widget/controls/delete.rb @@ -28,13 +28,13 @@ class Widget::Controls::Delete < Widget::Controls def render - return "" if @subject.new_record? or !@options[:can_delete] + return '' if @subject.new_record? or !@options[:can_delete] button = link_to(I18n.t(:button_delete), - "#", - id: "query-icon-delete", - class: "button icon-context icon-delete") - popup = content_tag :div, id: "delete_form", style: "display:none", class: "button_form" do + '#', + id: 'query-icon-delete', + class: 'button icon-context icon-delete') + popup = content_tag :div, id: 'delete_form', style: 'display:none', class: 'button_form' do question = content_tag :p, I18n.t(:label_really_delete_question) url_opts = { id: @subject.id } @@ -42,11 +42,11 @@ def render opt1 = link_to I18n.t(:button_delete), url_for(url_opts), method: :delete, - class: "button -primary icon-context icon-delete" + class: 'button -highlight icon-context icon-delete' opt2 = link_to I18n.t(:button_cancel), - "#", - id: "query-icon-delete-cancel", - class: "button icon-context icon-cancel" + '#', + id: 'query-icon-delete-cancel', + class: 'button icon-context icon-cancel' opt1 + opt2 question + opt1 + opt2 diff --git a/modules/reporting/lib/widget/controls/query_name.rb b/modules/reporting/lib/widget/controls/query_name.rb index e969f6fa4d2f..3edf0031e61b 100644 --- a/modules/reporting/lib/widget/controls/query_name.rb +++ b/modules/reporting/lib/widget/controls/query_name.rb @@ -30,19 +30,19 @@ class Widget::Controls::QueryName < Widget::Controls dont_cache! # The name might change, but the query stays the same... def render - options = { id: "query_saved_name", "data-translations" => translations } + options = { id: 'query_saved_name', 'data-translations' => translations } if @subject.new_record? name = I18n.t(:label_new_report) - icon = "" + icon = '' else name = @subject.name - options["data-is_public"] = @subject.public? - options["data-is_new"] = @subject.new_record? + options['data-is_public'] = @subject.public? + options['data-is_new'] = @subject.new_record? end write(content_tag(:span, h(name), options) + icon.to_s) end def translations - { isPublic: I18n.t(:public, scope: "attributes") }.to_json + { isPublic: I18n.t(:public, scope: 'attributes') }.to_json end end diff --git a/modules/reporting/lib/widget/controls/save.rb b/modules/reporting/lib/widget/controls/save.rb index 9a7464fe4439..01bf62c8cfaa 100644 --- a/modules/reporting/lib/widget/controls/save.rb +++ b/modules/reporting/lib/widget/controls/save.rb @@ -28,12 +28,12 @@ class Widget::Controls::Save < Widget::Controls def render - return "" if @subject.new_record? or !@options[:can_save] + return '' if @subject.new_record? or !@options[:can_save] write link_to(I18n.t(:button_save), - "#", - id: "query-breadcrumb-save", - class: "button icon-context icon-save", - "data-target": url_for(action: "update", id: @subject.id, set_filter: "1")) + '#', + id: 'query-breadcrumb-save', + class: 'button icon-context icon-save', + 'data-target': url_for(action: 'update', id: @subject.id, set_filter: '1')) end end diff --git a/modules/reporting/lib/widget/controls/save_as.rb b/modules/reporting/lib/widget/controls/save_as.rb index c23ac74658f7..a97db23bea44 100644 --- a/modules/reporting/lib/widget/controls/save_as.rb +++ b/modules/reporting/lib/widget/controls/save_as.rb @@ -30,12 +30,12 @@ class Widget::Controls::SaveAs < Widget::Controls def render if @subject.new_record? link_name = I18n.t(:button_save) - icon = "icon-save" + icon = 'icon-save' else link_name = I18n.t(:button_save_as) - icon = "icon-save" + icon = 'icon-save' end - button = link_to(link_name, "#", id: "query-icon-save-as", class: "button icon-context #{icon}") + button = link_to(link_name, '#', id: 'query-icon-save-as', class: "button icon-context #{icon}") write(button + render_popup) end @@ -45,15 +45,15 @@ def cache_key def render_popup_form name = content_tag :p, - class: "form--field -required -wide-label" do + class: 'form--field -required -wide-label' do label_tag(:query_name, - class: "form--label -transparent") do + class: 'form--label -transparent') do Query.human_attribute_name(:name).html_safe end + content_tag(:span, - class: "form--field-container") do + class: 'form--field-container') do content_tag(:span, - class: "form--text-field-container") do + class: 'form--text-field-container') do text_field_tag(:query_name, @subject.name, required: true) @@ -61,18 +61,18 @@ def render_popup_form end end if @options[:can_save_as_public] - box = content_tag :p, class: "form--field -wide-label" do + box = content_tag :p, class: 'form--field -wide-label' do label_tag(:query_is_public, Query.human_attribute_name(:public), - class: "form--label -transparent") + + class: 'form--label -transparent') + content_tag(:span, - class: "form--field-container") do + class: 'form--field-container') do content_tag(:span, - class: "form--check-box-container") do + class: 'form--check-box-container') do check_box_tag(:query_is_public, 1, false, - class: "form--check-box") + class: 'form--check-box') end end end @@ -83,24 +83,24 @@ def render_popup_form end def render_popup_buttons - save_url_params = { action: "create", set_filter: "1" } + save_url_params = { action: 'create', set_filter: '1' } save_url_params[:project_id] = @subject.project.id if @subject.project save = link_to(I18n.t(:button_save), - "#", - id: "query-icon-save-button", - class: "button -primary icon-context icon-save", - "data-target": url_for(**save_url_params)) + '#', + id: 'query-icon-save-button', + class: 'button -highlight icon-context icon-save', + 'data-target': url_for(**save_url_params)) cancel = link_to(I18n.t(:button_cancel), - "#", - id: "query-icon-save-as-cancel", - class: "button icon-context icon-cancel") + '#', + id: 'query-icon-save-as-cancel', + class: 'button icon-context icon-cancel') save + cancel end def render_popup - content_tag :div, id: "save_as_form", class: "button_form", style: "display:none" do + content_tag :div, id: 'save_as_form', class: 'button_form', style: 'display:none' do render_popup_form + render_popup_buttons end end diff --git a/modules/reporting/lib/widget/cost_types.rb b/modules/reporting/lib/widget/cost_types.rb index aa47078d88ef..5ed55afbdfad 100644 --- a/modules/reporting/lib/widget/cost_types.rb +++ b/modules/reporting/lib/widget/cost_types.rb @@ -45,11 +45,11 @@ def contents types = label_tag "unit_#{id}", h(label), class: "form--label" types += content_tag :span, class: "form--field-container" do content_tag :span, class: "form--radio-button-container" do - radio_button_tag("unit", id, id == @selected_type_id, class: "form--radio-button") + radio_button_tag('unit', id, id == @selected_type_id, class: "form--radio-button") end end end - end.join("").html_safe + end.join('').html_safe end end end diff --git a/modules/reporting/lib/widget/filters.rb b/modules/reporting/lib/widget/filters.rb index f1a9aaf41456..36a1c842d497 100644 --- a/modules/reporting/lib/widget/filters.rb +++ b/modules/reporting/lib/widget/filters.rb @@ -28,26 +28,26 @@ class Widget::Filters < Widget::Base def render - spacer = content_tag :li, "", class: "advanced-filters--spacer hide-when-print" + spacer = content_tag :li, '', class: 'advanced-filters--spacer hide-when-print' - add_filter = content_tag :li, id: "add_filter_block", class: "advanced-filters--add-filter hide-when-print" do - add_filter_label = label_tag "add_filter_select", I18n.t(:label_filter_add), - class: "advanced-filters--add-filter-label" - add_filter_label += label_tag "add_filter_select", I18n.t("js.filter.description.text_open_filter") + " " + - I18n.t("js.filter.description.text_close_filter"), - class: "hidden-for-sighted" + add_filter = content_tag :li, id: 'add_filter_block', class: 'advanced-filters--add-filter hide-when-print' do + add_filter_label = label_tag 'add_filter_select', I18n.t(:label_filter_add), + class: 'advanced-filters--add-filter-label' + add_filter_label += label_tag 'add_filter_select', I18n.t('js.filter.description.text_open_filter') + ' ' + + I18n.t('js.filter.description.text_close_filter'), + class: 'hidden-for-sighted' - add_filter_value = content_tag :div, class: "advanced-filters--add-filter-value" do - select_tag "add_filter_select", - options_for_select([["", ""]] + selectables), - class: "advanced-filters--select", + add_filter_value = content_tag :div, class: 'advanced-filters--add-filter-value' do + select_tag 'add_filter_select', + options_for_select([['', '']] + selectables), + class: 'advanced-filters--select', name: nil end (add_filter_label + add_filter_value).html_safe end - list = content_tag :ul, id: "filter_table", class: "advanced-filters--filters" do + list = content_tag :ul, id: 'filter_table', class: 'advanced-filters--filters' do render_filters + spacer + add_filter end @@ -66,12 +66,12 @@ def render_filters engine::Filter.all.select(&:selectable?).map do |filter| opts = { id: "filter_#{filter.underscore_name}", class: "#{filter.underscore_name} advanced-filters--filter", - "data-filter-name": filter.underscore_name } + 'data-filter-name': filter.underscore_name } active_instance = active_filters.detect { |f| f.instance_of?(filter) } if active_instance - opts[:"data-selected"] = true + opts[:'data-selected'] = true else - opts[:style] = "display:none" + opts[:style] = 'display:none' end content_tag :li, opts do render_filter filter, active_instance @@ -81,7 +81,7 @@ def render_filters def render_filter(f_cls, f_inst) f = f_inst || f_cls - html = "".html_safe + html = ''.html_safe render_widget Label, f, to: html render_widget Operators, f, to: html diff --git a/modules/reporting/lib/widget/filters/date.rb b/modules/reporting/lib/widget/filters/date.rb index 2e11b3285d39..95e671764ae9 100644 --- a/modules/reporting/lib/widget/filters/date.rb +++ b/modules/reporting/lib/widget/filters/date.rb @@ -35,13 +35,13 @@ def render name = "values[#{filter_class.underscore_name}][]" id_prefix = "#{filter_class.underscore_name}_" - write(content_tag(:span, class: "advanced-filters--filter-value -binary") do + write(content_tag(:span, class: 'advanced-filters--filter-value -binary') do label1 = label_tag "#{id_prefix}arg_1_val", - h(filter_class.label) + " " + I18n.t(:label_filter_value), - class: "hidden-for-sighted" + h(filter_class.label) + ' ' + I18n.t(:label_filter_value), + class: 'hidden-for-sighted' arg1 = content_tag :span, id: "#{id_prefix}arg_1" do - text1 = angular_component_tag "op-basic-single-date-picker", + text1 = angular_component_tag 'op-basic-single-date-picker', inputs: { value: filter.values.first.to_s, id: "#{id_prefix}arg_1_val", @@ -51,11 +51,11 @@ def render end label2 = label_tag "#{id_prefix}arg_2_val", - h(filter_class.label) + " " + I18n.t(:label_filter_value), - class: "hidden-for-sighted" + h(filter_class.label) + ' ' + I18n.t(:label_filter_value), + class: 'hidden-for-sighted' - arg2 = content_tag :span, id: "#{id_prefix}arg_2", class: "advanced-filters--filter-value2" do - text2 = angular_component_tag "op-basic-single-date-picker", + arg2 = content_tag :span, id: "#{id_prefix}arg_2", class: 'advanced-filters--filter-value2' do + text2 = angular_component_tag 'op-basic-single-date-picker', inputs: { value: filter.values.second.to_s, id: "#{id_prefix}arg_2_val", diff --git a/modules/reporting/lib/widget/filters/heavy.rb b/modules/reporting/lib/widget/filters/heavy.rb index e9701052cfc8..0cdf94aca22f 100644 --- a/modules/reporting/lib/widget/filters/heavy.rb +++ b/modules/reporting/lib/widget/filters/heavy.rb @@ -37,20 +37,20 @@ def render # this might be a bug - further research would be fine values = filter.values.first.is_a?(Array) ? filter.values.first : filter.values opts = Array(values).empty? ? [] : values.map { |i| filter_class.label_for_value(i.to_i) } - div = content_tag :div, id: "#{filter_class.underscore_name}_arg_1", class: "advanced-filters--filter-value hidden" do - select_options = { "data-remote-url": url_for(action: "available_values"), - "data-initially-selected": JSON::dump(Array(filter.values).flatten), + div = content_tag :div, id: "#{filter_class.underscore_name}_arg_1", class: 'advanced-filters--filter-value hidden' do + select_options = { 'data-remote-url': url_for(action: 'available_values'), + 'data-initially-selected': JSON::dump(Array(filter.values).flatten), name: "values[#{filter_class.underscore_name}][]", - "data-loading": "", + 'data-loading': '', id: "#{filter_class.underscore_name}_arg_1_val", - class: "advanced-filters--select filter-value", - "data-filter-name": filter_class.underscore_name } + class: 'advanced-filters--select filter-value', + 'data-filter-name': filter_class.underscore_name } box = content_tag :select, select_options do - render_widget Widget::Filters::Option, filter, to: "", content: opts + render_widget Widget::Filters::Option, filter, to: '', content: opts end box end - alternate_text = opts.map(&:first).join(", ").html_safe + alternate_text = opts.map(&:first).join(', ').html_safe write(div + content_tag(:label) do alternate_text end) diff --git a/modules/reporting/lib/widget/filters/label.rb b/modules/reporting/lib/widget/filters/label.rb index b34dd2c57e18..1a062e62a268 100644 --- a/modules/reporting/lib/widget/filters/label.rb +++ b/modules/reporting/lib/widget/filters/label.rb @@ -30,7 +30,7 @@ class Widget::Filters::Label < Widget::Filters::Base def render options = { id: filter_class.underscore_name, - class: "advanced-filters--filter-name", + class: 'advanced-filters--filter-name', title: h(filter_class.label) } write(content_tag(:label, options) do diff --git a/modules/reporting/lib/widget/filters/operators.rb b/modules/reporting/lib/widget/filters/operators.rb index 1c24fb6a21ed..91057075a24f 100644 --- a/modules/reporting/lib/widget/filters/operators.rb +++ b/modules/reporting/lib/widget/filters/operators.rb @@ -28,26 +28,26 @@ class Widget::Filters::Operators < Widget::Filters::Base def render - write(content_tag(:div, class: "advanced-filters--filter-operator") do + write(content_tag(:div, class: 'advanced-filters--filter-operator') do hide_select_box = filter_class.available_operators.count == 1 || filter_class.heavy? - options = { class: "advanced-filters--select filters-select filter_operator", + options = { class: 'advanced-filters--select filters-select filter_operator', id: "operators[#{filter_class.underscore_name}]", name: "operators[#{filter_class.underscore_name}]", - "data-filter-name": filter_class.underscore_name } - options.merge! style: "display: none" if hide_select_box + 'data-filter-name': filter_class.underscore_name } + options.merge! style: 'display: none' if hide_select_box select_box = content_tag :select, options do filter_class.available_operators.map do |o| - opts = { value: h(o.to_s), "data-arity": o.arity } - opts.reverse_merge! "data-forced": o.forced if o.forced? - opts[:selected] = "selected" if filter.operator.to_s == o.to_s + opts = { value: h(o.to_s), 'data-arity': o.arity } + opts.reverse_merge! 'data-forced': o.forced if o.forced? + opts[:selected] = 'selected' if filter.operator.to_s == o.to_s content_tag(:option, opts) { h(I18n.t(o.label)) } end.join.html_safe end label1 = content_tag :label, hidden_for_sighted_label, for: "operators[#{filter_class.underscore_name}]", - class: "hidden-for-sighted" + class: 'hidden-for-sighted' label = content_tag :label do if filter_class.available_operators.any? filter_class.available_operators.first.label @@ -58,6 +58,6 @@ def render end def hidden_for_sighted_label - h(filter_class.label) + " " + I18n.t(:label_operator) + " " + I18n.t("js.filter.description.text_open_filter") + h(filter_class.label) + ' ' + I18n.t(:label_operator) + ' ' + I18n.t('js.filter.description.text_open_filter') end end diff --git a/modules/reporting/lib/widget/filters/option.rb b/modules/reporting/lib/widget/filters/option.rb index 21c71ebd4d40..194dd4ecc74b 100644 --- a/modules/reporting/lib/widget/filters/option.rb +++ b/modules/reporting/lib/widget/filters/option.rb @@ -38,13 +38,13 @@ def render level = options[:level] # nesting_level is optional for values name = I18n.t(name) if name.is_a? Symbol name = I18n.t(:label_none) if name.empty? - name_prefix = (level && level > 0 ? ((" " * 2 * level) + "> ") : "") + name_prefix = (level && level > 0 ? ((' ' * 2 * level) + '> ') : '') if options[:optgroup] tag :optgroup, label: I18n.t(:label_sector) else opts = { value: id } if (Array(filter.values).map(&:to_s).include? id.to_s) || (first && Array(filter.values).empty?) - opts[:selected] = "selected" + opts[:selected] = 'selected' end first = false content_tag(:option, opts) { name_prefix + name } diff --git a/modules/reporting/lib/widget/filters/remove_button.rb b/modules/reporting/lib/widget/filters/remove_button.rb index e32be053a0e8..5a431c9a2f7f 100644 --- a/modules/reporting/lib/widget/filters/remove_button.rb +++ b/modules/reporting/lib/widget/filters/remove_button.rb @@ -29,12 +29,12 @@ class Widget::Filters::RemoveButton < Widget::Filters::Base def render hidden_field = tag :input, id: "rm_#{filter_class.underscore_name}", - name: "fields[]", type: "hidden", value: "" + name: 'fields[]', type: 'hidden', value: '' button = content_tag(:a, href: "#", class: "filter_rem") do - icon_wrapper("icon-close advanced-filters--remove-filter-icon", I18n.t(:description_remove_filter)) + icon_wrapper('icon-close advanced-filters--remove-filter-icon', I18n.t(:description_remove_filter)) end write(content_tag(:div, hidden_field + button, id: "rm_box_#{filter_class.underscore_name}", - class: "advanced-filters--remove-filter")) + class: 'advanced-filters--remove-filter')) end end diff --git a/modules/reporting/lib/widget/filters/text_box.rb b/modules/reporting/lib/widget/filters/text_box.rb index 73d20e7f9cb3..eed8cd5c564b 100644 --- a/modules/reporting/lib/widget/filters/text_box.rb +++ b/modules/reporting/lib/widget/filters/text_box.rb @@ -31,14 +31,14 @@ def render label = content_tag :label, "#{h(filter_class.label)} #{I18n.t(:label_filter_value)}", for: "#{filter_class.underscore_name}_arg_1_val", - class: "hidden-for-sighted" + class: 'hidden-for-sighted' - write(content_tag(:div, id: "#{filter_class.underscore_name}_arg_1", class: "advanced-filters--filter-value") do - label + text_field_tag("values[#{filter_class.underscore_name}]", "", - size: "6", - class: "advanced-filters--text-field", + write(content_tag(:div, id: "#{filter_class.underscore_name}_arg_1", class: 'advanced-filters--filter-value') do + label + text_field_tag("values[#{filter_class.underscore_name}]", '', + size: '6', + class: 'advanced-filters--text-field', id: "#{filter_class.underscore_name}_arg_1_val", - "data-filter-name": filter_class.underscore_name) + 'data-filter-name': filter_class.underscore_name) end) end end diff --git a/modules/reporting/lib/widget/group_bys.rb b/modules/reporting/lib/widget/group_bys.rb index ed3ddd51eaf6..d495ccc60fd0 100644 --- a/modules/reporting/lib/widget/group_bys.rb +++ b/modules/reporting/lib/widget/group_bys.rb @@ -32,7 +32,7 @@ def render_options(group_by_ary) next unless group_by.selectable? label_text = CGI::escapeHTML(h(group_by.label)).to_s - option_tags = { value: group_by.underscore_name, "data-label": label_text } + option_tags = { value: group_by.underscore_name, 'data-label': label_text } option_tags[:title] = label_text if group_by.label.length > 40 content_tag :option, option_tags do h(truncate_single_line(group_by.label, length: 40)) @@ -46,29 +46,29 @@ def render_group(type, initially_selected) end content_tag :fieldset do - legend = content_tag :legend, I18n.t("reporting.group_by.selected_#{type}"), class: "hidden-for-sighted" + legend = content_tag :legend, I18n.t("reporting.group_by.selected_#{type}"), class: 'hidden-for-sighted' container = content_tag :div, id: "group-by--#{type}", - class: "group-by--container grid-block", - "data-initially-selected": initially_selected.to_json.tr('"', "'") do - out = content_tag :span, class: "group-by--caption grid-content shrink" do + class: 'group-by--container grid-block', + 'data-initially-selected': initially_selected.to_json.tr('"', "'") do + out = content_tag :span, class: 'group-by--caption grid-content shrink' do content_tag :span do I18n.t(:"label_#{type}") end end - out += content_tag :span, "", id: "group-by--selected-#{type}", class: "group-by--selected-elements grid-block" + out += content_tag :span, '', id: "group-by--selected-#{type}", class: 'group-by--selected-elements grid-block' out += content_tag :span, - class: "group-by--control grid-content shrink" do + class: 'group-by--control grid-content shrink' do label = label_tag "group-by--add-#{type}", - I18n.t(:label_group_by_add) + " " + - I18n.t("js.filter.description.text_open_filter"), - class: "hidden-for-sighted" + I18n.t(:label_group_by_add) + ' ' + + I18n.t('js.filter.description.text_open_filter'), + class: 'hidden-for-sighted' - label += content_tag :select, id: "group-by--add-#{type}", class: "advanced-filters--select" do - content = content_tag :option, I18n.t(:label_group_by_add), value: "", disabled: true, selected: true + label += content_tag :select, id: "group-by--add-#{type}", class: 'advanced-filters--select' do + content = content_tag :option, I18n.t(:label_group_by_add), value: '', disabled: true, selected: true content += engine::GroupBy.all_grouped.sort_by do |label, _group_by_ary| I18n.t(label) @@ -91,9 +91,9 @@ def render_group(type, initially_selected) end def render - write(content_tag(:div, id: "group-by--area", class: "autoscroll") do - out = render_group "columns", @subject.group_bys(:column) - out += render_group "rows", @subject.group_bys(:row) + write(content_tag(:div, id: 'group-by--area', class: 'autoscroll') do + out = render_group 'columns', @subject.group_bys(:column) + out += render_group 'rows', @subject.group_bys(:row) out.html_safe end) end diff --git a/modules/reporting/lib/widget/settings.rb b/modules/reporting/lib/widget/settings.rb index 3adbdf7a3826..cc0dd44d65b7 100644 --- a/modules/reporting/lib/widget/settings.rb +++ b/modules/reporting/lib/widget/settings.rb @@ -31,14 +31,14 @@ class Widget::Settings < Widget::Base def render_filter_settings render_widget Widget::Settings::Fieldset, @subject, - type: "filters" do + type: 'filters' do render_widget Widget::Filters, @subject end end def render_group_by_settings render_widget Widget::Settings::Fieldset, @subject, - type: "group_by" do + type: 'group_by' do render_widget Widget::GroupBys, @subject end end @@ -52,8 +52,8 @@ def render_cost_types_settings end def render_controls_settings - content_tag :div, class: "form--buttons -with-button-form hide-when-print" do - widgets = "".html_safe + content_tag :div, class: 'form--buttons -with-button-form hide-when-print' do + widgets = ''.html_safe render_widget(Widget::Controls::Apply, @subject, to: widgets) render_widget(Widget::Controls::Save, @subject, to: widgets, can_save: allowed_in_report?(:save, @subject, current_user)) @@ -68,12 +68,12 @@ def render_controls_settings end def render - write(form_tag("#", id: "query_form", method: :post) do - content_tag :div, id: "query_form_content" do + write(form_tag('#', id: 'query_form', method: :post) do + content_tag :div, id: 'query_form_content' do # will render a setting menu for every setting. # To add new settings, write a new instance method render__setting # and add to the @@settings_to_render list. - content = "".html_safe + content = ''.html_safe settings_to_render.each do |setting_name| render_method_name = "render_#{setting_name}_settings" content << send(render_method_name) if respond_to? render_method_name diff --git a/modules/reporting/lib/widget/settings/fieldset.rb b/modules/reporting/lib/widget/settings/fieldset.rb index 86a98061b393..e865930db6f7 100644 --- a/modules/reporting/lib/widget/settings/fieldset.rb +++ b/modules/reporting/lib/widget/settings/fieldset.rb @@ -30,7 +30,7 @@ class Widget::Settings::Fieldset < Widget::Base dont_cache! def render_with_options(options, &) - @type = options.delete(:type) || "filter" + @type = options.delete(:type) || 'filter' @id = @type.to_s @label = :"label_#{@type}" super(options, &) @@ -40,14 +40,14 @@ def render hash = self.hash write(content_tag(:fieldset, id: @id, - class: "form--fieldset -collapsible") do + class: 'form--fieldset -collapsible') do html = content_tag(:legend, show_at_id: hash.to_s, icon: "#{@type}-legend-icon", tooltip: "#{@type}-legend-tip", - class: "form--fieldset-legend", + class: 'form--fieldset-legend', id: hash.to_s) do - content_tag(:a, href: "#") { I18n.t(@label) } + content_tag(:a, href: '#') { I18n.t(@label) } end html + yield end) diff --git a/modules/reporting/lib/widget/table.rb b/modules/reporting/lib/widget/table.rb index c66f2e7e80d6..b83c3b5ccc67 100644 --- a/modules/reporting/lib/widget/table.rb +++ b/modules/reporting/lib/widget/table.rb @@ -33,7 +33,7 @@ class Widget::Table < Widget::Base attr_accessor :debug, :fields, :mapping def initialize(query) - raise ArgumentError, "Tables only work on CostQuery!" unless query.is_a? CostQuery + raise ArgumentError, 'Tables only work on CostQuery!' unless query.is_a? CostQuery super end @@ -47,11 +47,11 @@ def resolve_table end def render - write("") + write('') if @subject.result.count <= 0 - write(content_tag(:div, "", class: "generic-table--no-results-container") do - content_tag(:i, "", class: "icon-info1") + - content_tag(:span, I18n.t(:no_results_title_text), class: "generic-table--no-results-title") + write(content_tag(:div, '', class: 'generic-table--no-results-container') do + content_tag(:i, '', class: 'icon-info1') + + content_tag(:span, I18n.t(:no_results_title_text), class: 'generic-table--no-results-title') end) else str = render_widget(resolve_table, @subject, @options.reverse_merge(to: @output)) diff --git a/modules/reporting/lib/widget/table/entry_table.rb b/modules/reporting/lib/widget/table/entry_table.rb index 76cc3958adda..a5bdb10e0db4 100644 --- a/modules/reporting/lib/widget/table/entry_table.rb +++ b/modules/reporting/lib/widget/table/entry_table.rb @@ -30,10 +30,10 @@ class ::Widget::Table::EntryTable < Widget::Table FIELDS = %i[spent_on user_id activity_id work_package_id comments logged_by_id project_id].freeze def render - content = content_tag :div, class: "generic-table--container -with-footer" do - content_tag :div, class: "generic-table--results-container" do - table = content_tag :table, class: "generic-table", - id: "sortable-table" do + content = content_tag :div, class: 'generic-table--container -with-footer' do + content_tag :div, class: 'generic-table--results-container' do + table = content_tag :table, class: 'generic-table', + id: 'sortable-table' do concat colgroup concat head concat foot @@ -48,10 +48,10 @@ def render def colgroup content_tag :colgroup do FIELDS.each do - concat content_tag(:col, "opHighlightCol" => true) {} + concat content_tag(:col, 'opHighlightCol' => true) {} end - concat content_tag(:col, "opHighlightCol" => true) {} - concat content_tag(:col, "opHighlightCol" => true) {} + concat content_tag(:col, 'opHighlightCol' => true) {} + concat content_tag(:col, 'opHighlightCol' => true) {} concat content_tag(:col) {} end end @@ -61,23 +61,23 @@ def head content_tag :tr do FIELDS.map do |field| concat content_tag(:th) { - content_tag(:div, class: "generic-table--sort-header-outer") do - content_tag(:div, class: "generic-table--sort-header") do + content_tag(:div, class: 'generic-table--sort-header-outer') do + content_tag(:div, class: 'generic-table--sort-header') do content_tag(:span, label_for(field)) end end } end concat content_tag(:th) { - content_tag(:div, class: "generic-table--sort-header-outer") do - content_tag(:div, class: "generic-table--sort-header") do + content_tag(:div, class: 'generic-table--sort-header-outer') do + content_tag(:div, class: 'generic-table--sort-header') do content_tag(:span, cost_type.try(:unit_plural) || I18n.t(:units)) end end } concat content_tag(:th) { - content_tag(:div, class: "generic-table--sort-header-outer") do - content_tag(:div, class: "generic-table--sort-header") do + content_tag(:div, class: 'generic-table--sort-header-outer') do + content_tag(:div, class: 'generic-table--sort-header') do content_tag(:span, CostEntry.human_attribute_name(:costs)) end end @@ -87,8 +87,8 @@ def head next if hit if entry_for(result).editable_by? User.current - concat content_tag(:th, class: "unsortable") { - content_tag(:div, "", class: "generic-table--empty-header") + concat content_tag(:th, class: 'unsortable') { + content_tag(:div, '', class: 'generic-table--empty-header') } hit = true end @@ -101,48 +101,48 @@ def foot content_tag :tfoot do content_tag :tr do if show_result(@subject, 0) == show_result(@subject) - concat content_tag(:td, "", colspan: FIELDS.size + 1) + concat content_tag(:td, '', colspan: FIELDS.size + 1) concat content_tag(:td) { concat content_tag(:div, show_result(@subject), - class: "result generic-table--footer-outer") + class: 'result generic-table--footer-outer') } else - concat content_tag(:td, "", colspan: FIELDS.size) + concat content_tag(:td, '', colspan: FIELDS.size) concat content_tag(:td) { concat content_tag(:div, show_result(@subject), - class: "inner generic-table--footer-outer") + class: 'inner generic-table--footer-outer') } concat content_tag(:td) { concat content_tag(:div, show_result(@subject, 0), - class: "result generic-table--footer-outer") + class: 'result generic-table--footer-outer') } end - concat content_tag(:th, "", class: "unsortable") + concat content_tag(:th, '', class: 'unsortable') end end end def body content_tag :tbody do - rows = "".html_safe + rows = ''.html_safe @subject.each_direct_result do |result| rows << (content_tag(:tr) do - "".html_safe + ''.html_safe FIELDS.each do |field| concat content_tag(:td, show_field(field, result.fields[field.to_s]).html_safe, - "raw-data": raw_field(field, result.fields[field.to_s]), - class: "left") + 'raw-data': raw_field(field, result.fields[field.to_s]), + class: 'left') end - concat content_tag :td, show_result(result, result.fields["cost_type_id"].to_i).html_safe, - class: "units right", - "raw-data": result.units + concat content_tag :td, show_result(result, result.fields['cost_type_id'].to_i).html_safe, + class: 'units right', + 'raw-data': result.units concat content_tag :td, show_result(result, 0).html_safe, - class: "currency right", - "raw-data": result.real_costs + class: 'currency right', + 'raw-data': result.real_costs concat content_tag :td, icons(result) end) end @@ -151,26 +151,26 @@ def body end def icons(result) - icons = "" - with_project(result.fields["project_id"]) do + icons = '' + with_project(result.fields['project_id']) do if entry_for(result).editable_by? User.current - if controller_for(result.fields["type"]) == "costlog" - icons = link_to(icon_wrapper("icon-context icon-edit", I18n.t(:button_edit)), - action_for(result, action: "edit"), - class: "no-decoration-on-hover", + if controller_for(result.fields['type']) == 'costlog' + icons = link_to(icon_wrapper('icon-context icon-edit', I18n.t(:button_edit)), + action_for(result, action: 'edit'), + class: 'no-decoration-on-hover', title: I18n.t(:button_edit)) - icons << link_to(icon_wrapper("icon-context icon-delete", I18n.t(:button_delete)), - action_for(result, action: "destroy") + icons << link_to(icon_wrapper('icon-context icon-delete', I18n.t(:button_delete)), + action_for(result, action: 'destroy') .reverse_merge(authenticity_token: form_authenticity_token), data: { confirm: I18n.t(:text_are_you_sure) }, method: :delete, - class: "no-decoration-on-hover", + class: 'no-decoration-on-hover', title: I18n.t(:button_delete)) else - icons = content_tag(:"time-entry--trigger-actions-entry", - "", - data: { entry: result["id"] }) + icons = content_tag(:'time-entry--trigger-actions-entry', + '', + data: { entry: result['id'] }) end end end diff --git a/modules/reporting/lib/widget/table/report_table.rb b/modules/reporting/lib/widget/table/report_table.rb index a47a9e23798b..e9d51479a188 100644 --- a/modules/reporting/lib/widget/table/report_table.rb +++ b/modules/reporting/lib/widget/table/report_table.rb @@ -63,7 +63,7 @@ def configure_walker @walker.for_empty_cell { " ".html_safe } @walker.for_cell do |result| - write(" ".html_safe) # XXX: This keeps the Apache from timing out on us. Keep-Alive byte! + write(' '.html_safe) # XXX: This keeps the Apache from timing out on us. Keep-Alive byte! "#{show_result result}#{debug_fields(result)}".html_safe end end @@ -75,11 +75,11 @@ def render render_thead render_tfoot render_tbody - write "" + write '' end def render_tbody - write "" + write '' first = true odd = true walker.body do |line| @@ -91,7 +91,7 @@ def render_tbody write "#{line}" odd = !odd end - write "" + write '' end def mark_penultimate_column!(line) @@ -103,48 +103,48 @@ def mark_penultimate_column!(line) def render_thead return if (walker.headers || true) and walker.headers_empty? - write "" + write '' walker.headers do |list, first, first_in_col, last_in_col| - write "" if first_in_col + write '' if first_in_col if first write(content_tag(:th, rowspan: @subject.depth_of(:column), colspan: @subject.depth_of(:row)) do - "" + '' end) end list.each do |column| opts = { colspan: column.final_number(:column) } - opts.merge!(class: "inner") if column.final?(:column) + opts.merge!(class: 'inner') if column.final?(:column) write(content_tag(:th, opts) do show_row column end) end if first write(content_tag(:th, rowspan: @subject.depth_of(:column), colspan: @subject.depth_of(:row)) do - "" + '' end) end - write "" if last_in_col + write '' if last_in_col end - write "" + write '' end def render_tfoot return if walker.headers_empty? - write "" + write '' walker.reverse_headers do |list, first, first_in_col, last_in_col| if first_in_col - write "" + write '' if first - write(content_tag(:th, rowspan: @subject.depth_of(:column), colspan: @subject.depth_of(:row), class: "top") do - " " + write(content_tag(:th, rowspan: @subject.depth_of(:column), colspan: @subject.depth_of(:row), class: 'top') do + ' ' end) end end list.each do |column| opts = { colspan: column.final_number(:column) } - opts.merge!(class: "inner") if first + opts.merge!(class: 'inner') if first write(content_tag(:th, opts) do show_result(column) # {debug_fields(column)} end) @@ -154,33 +154,33 @@ def render_tfoot write(content_tag(:th, rowspan: @subject.depth_of(:column), colspan: @subject.depth_of(:row), - class: "top result") do + class: 'top result') do show_result @subject end) end - write "" + write '' end end - write "" + write '' end def debug_content content_tag :pre do - debug_pre_content = "[ Query ]" + + debug_pre_content = '[ Query ]' + @subject.chain.each do |child| "#{h child.class.inspect}, #{h child.type}" end - debug_pre_content += "[ RESULT ]" + debug_pre_content += '[ RESULT ]' @subject.result.recursive_each_with_level do |level, result| - debug_pre_content += ">>> " * (level + 1) + debug_pre_content += '>>> ' * (level + 1) debug_pre_content += h(result.inspect) - debug_pre_content += " " * (level + 1) + debug_pre_content += ' ' * (level + 1) debug_pre_content += h(result.type.inspect) - debug_pre_content += " " * (level + 1) + debug_pre_content += ' ' * (level + 1) debug_pre_content += h(result.fields.inspect) end - debug_pre_content += "[ HEADER STACK ]" + debug_pre_content += '[ HEADER STACK ]' debug_pre_content += walker.header_stack.each do |l| ">>> #{l.inspect}" end diff --git a/modules/reporting/openproject-reporting.gemspec b/modules/reporting/openproject-reporting.gemspec index aaea75301059..1b066934b5f0 100644 --- a/modules/reporting/openproject-reporting.gemspec +++ b/modules/reporting/openproject-reporting.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "openproject-reporting" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" s.summary = "OpenProject Reporting" @@ -9,5 +9,5 @@ Gem::Specification.new do |s| s.files = Dir["{app,config,db,lib,doc}/**/*", "README.md"] s.add_dependency "costs" - s.metadata["rubygems_mfa_required"] = "true" + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/reporting/spec/controllers/cost_reports_controller_spec.rb b/modules/reporting/spec/controllers/cost_reports_controller_spec.rb index 94e81b5c3b2b..8e772b2942cb 100644 --- a/modules/reporting/spec/controllers/cost_reports_controller_spec.rb +++ b/modules/reporting/spec/controllers/cost_reports_controller_spec.rb @@ -43,64 +43,64 @@ is_member project, user, [:view_cost_entries] end - context "with invalid units" do - context "with :view_cost_entries permission" do + context 'with invalid units' do + context 'with :view_cost_entries permission' do before do get :show, params: { id: 1, unit: -1 } end - it "returns 404 Not found" do + it 'returns 404 Not found' do expect(response).to have_http_status(:not_found) end end end end - describe "DELETE destroy" do + describe 'DELETE destroy' do let(:user) { build(:admin) } let(:cost_query) { create(:public_cost_query, user:, project:) } - context "with valid params" do + context 'with valid params' do before do delete :destroy, params: { id: cost_query.id, project_id: project.identifier } end - it "destroyed" do + it 'destroyed' do expect(CostQuery.count).to be_zero end - it "redirected" do + it 'redirected' do expect(response).to have_http_status(:redirect) end end - context "with invalid params" do + context 'with invalid params' do before do create(:public_cost_query, user:, project:) delete :destroy, params: { id: -1, project_id: -1 } end - it "not destroyed" do + it 'not destroyed' do expect(CostQuery.count).not_to be_zero end - it "returns 404 Not found" do + it 'returns 404 Not found' do expect(response).to have_http_status(:not_found) end end - context "with non-admin user" do + context 'with non-admin user' do let(:user) { build(:user) } before do delete :destroy, params: { id: cost_query.id, project_id: project.identifier } end - it "not destroyed" do + it 'not destroyed' do expect(CostQuery.count).not_to be_zero end - it "returns 403 Forbidden" do + it 'returns 403 Forbidden' do expect(response).to have_http_status(:forbidden) end end diff --git a/modules/reporting/spec/controllers/custom_fields_controller_spec.rb b/modules/reporting/spec/controllers/custom_fields_controller_spec.rb index a7710dd26c43..e36f3b9166bc 100644 --- a/modules/reporting/spec/controllers/custom_fields_controller_spec.rb +++ b/modules/reporting/spec/controllers/custom_fields_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomFieldsController do let!(:custom_field) { create(:work_package_custom_field) } @@ -47,10 +47,10 @@ CostQuery::GroupBy::CustomFieldEntries.all end - describe "#destroy" do - shared_context "remove custom field" do + describe '#destroy' do + shared_context 'remove custom field' do before do - cost_query.filter(custom_field_permanent_name, { operator: "=", values: [] }) + cost_query.filter(custom_field_permanent_name, { operator: '=', values: [] }) cost_query.group_by(custom_field_permanent_name) cost_query.save! @@ -58,67 +58,67 @@ end end - shared_examples_for "custom field is removed from cost query" do - include_context "remove custom field" + shared_examples_for 'custom field is removed from cost query' do + include_context 'remove custom field' - shared_examples_for "custom field removed" do + shared_examples_for 'custom field removed' do it { expect(subject).not_to include(name) } end - shared_examples_for "custom field exists" do + shared_examples_for 'custom field exists' do it { expect(subject).to include(name) } end - describe "custom field is removed from cost query filter" do + describe 'custom field is removed from cost query filter' do subject { CostQuery.find(cost_query.id).filters.collect(&:class).collect(&:name) } - it_behaves_like "custom field removed" do + it_behaves_like 'custom field removed' do let(:name) { "CostQuery::Filter::#{custom_field_name}" } end end - describe "custom field is removed from cost query group bys" do + describe 'custom field is removed from cost query group bys' do subject { CostQuery.find(cost_query.id).group_bys.collect(&:class).collect(&:name) } - it_behaves_like "custom field removed" do + it_behaves_like 'custom field removed' do let(:name) { "CostQuery::GroupBy::#{custom_field_name}" } end end - describe "permanent custom field still exists in cost query filter" do + describe 'permanent custom field still exists in cost query filter' do subject { cost_query.reload.filters.collect(&:class).collect(&:name) } - it_behaves_like "custom field exists" do + it_behaves_like 'custom field exists' do let(:name) { "CostQuery::Filter::#{custom_field_permanent_name}" } end end - describe "permanent custom field still exists in cost query group by" do + describe 'permanent custom field still exists in cost query group by' do subject { cost_query.reload.group_bys.collect(&:class).collect(&:name) } - it_behaves_like "custom field exists" do + it_behaves_like 'custom field exists' do let(:name) { "CostQuery::GroupBy::#{custom_field_permanent_name}" } end end end - context "with custom field filter set" do + context 'with custom field filter set' do before do - cost_query.filter(custom_field_name, { operator: "=", values: [] }) + cost_query.filter(custom_field_name, { operator: '=', values: [] }) end - it_behaves_like "custom field is removed from cost query" + it_behaves_like 'custom field is removed from cost query' end - context "with custom field group by set" do + context 'with custom field group by set' do before do cost_query.group_by(custom_field_name) end - it_behaves_like "custom field is removed from cost query" + it_behaves_like 'custom field is removed from cost query' end - context "session" do + context 'session' do let(:engine_name) { CostQuery.name.underscore.to_sym } let(:key) { :"custom_field#{custom_field.id}" } let(:query) do @@ -132,8 +132,8 @@ before { session[engine_name] = query } - describe "does not contain custom field reference" do - include_context "remove custom field" + describe 'does not contain custom field reference' do + include_context 'remove custom field' it { expect(session[engine_name][:filters][:operators][key]).to be_nil } diff --git a/modules/reporting/spec/features/calculations_spec.rb b/modules/reporting/spec/features/calculations_spec.rb index dd4d1f94a6a1..096b2905a07f 100644 --- a/modules/reporting/spec/features/calculations_spec.rb +++ b/modules/reporting/spec/features/calculations_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost Report", "calculations", :js, :with_cuprite do +RSpec.describe 'Cost Report', 'calculations', :js, :with_cuprite do let(:project) { create(:project) } let(:user) { create(:admin) } let(:work_package) { create(:work_package, project:) } @@ -26,13 +26,13 @@ def create_time_entries_on(*timestamps_of_recordings) create_hourly_rates create_time_entries_on(6.months.ago, 18.months.ago, 30.months.ago) login_as user - visit "/cost_reports?set_filter=1" + visit '/cost_reports?set_filter=1' end - it "shows the correct calculations" do - expect(page).to have_text "10.00" # 1 EUR x 10 - expect(page).to have_text "50.00" # 5 EUR x 10 - expect(page).to have_text "100.00" # 10 EUR x 10 - expect(page).to have_text "160.00" # Total + it 'shows the correct calculations' do + expect(page).to have_text '10.00' # 1 EUR x 10 + expect(page).to have_text '50.00' # 5 EUR x 10 + expect(page).to have_text '100.00' # 10 EUR x 10 + expect(page).to have_text '160.00' # Total end end diff --git a/modules/reporting/spec/features/custom_fields_spec.rb b/modules/reporting/spec/features/custom_fields_spec.rb index f3578cf0fdb2..453140787226 100644 --- a/modules/reporting/spec/features/custom_fields_spec.rb +++ b/modules/reporting/spec/features/custom_fields_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Custom fields reporting", :js do +RSpec.describe 'Custom fields reporting', :js do let(:type) { create(:type) } let(:project) { create(:project, types: [type]) } @@ -63,17 +63,17 @@ def custom_value_for(cf, str) current_user { user } - context "with multi value cf" do + context 'with multi value cf' do let!(:custom_field) do create(:list_wp_custom_field, name: "List CF", multi_value: true, types: [type], projects: [project], - possible_values: ["First option", "Second option"]) + possible_values: ['First option', 'Second option']) end - let(:initial_custom_values) { { custom_field.id => custom_value_for(custom_field, "First option") } } + let(:initial_custom_values) { { custom_field.id => custom_value_for(custom_field, 'First option') } } let(:cf_id) { "custom_field#{custom_field.id}" } # Have a second work package in the test that will have no values @@ -85,70 +85,70 @@ def custom_value_for(cf, str) end before do - visit "/cost_reports" + visit '/cost_reports' sleep(0.1) end - it "filters by the multi CF" do - expect(page).to have_css("#add_filter_select option", text: "List CF") - select "List CF", from: "add_filter_select" + it 'filters by the multi CF' do + expect(page).to have_css('#add_filter_select option', text: 'List CF') + select 'List CF', from: 'add_filter_select' # Adds filter to page, filtering out the time entries on the work package expect(page).to have_css("label##{cf_id}") custom_field_selector = "##{cf_id}_arg_1_val" select = find(custom_field_selector) - expect(select).to have_css("option", text: "First option") - expect(select).to have_css("option", text: "Second option") - select.find("option", text: "Second option").select_option + expect(select).to have_css('option', text: 'First option') + expect(select).to have_css('option', text: 'Second option') + select.find('option', text: 'Second option').select_option - click_link "Apply" + click_link 'Apply' # Expect empty result table - within("#result-table") do - expect(page).to have_no_css(".top.result", text: "12.50 hours") + within('#result-table') do + expect(page).to have_no_css('.top.result', text: '12.50 hours') end - expect(page).to have_css(".generic-table--no-results-title") + expect(page).to have_css('.generic-table--no-results-title') # Update filter to value the work package has select = find(custom_field_selector) - select.find("option", text: "First option").select_option - find_by_id("query-icon-apply-button").click + select.find('option', text: 'First option').select_option + find_by_id('query-icon-apply-button').click # Expect row of work package - within("#result-table") do - expect(page).to have_css(".top.result", text: "12.50 hours") + within('#result-table') do + expect(page).to have_css('.top.result', text: '12.50 hours') end end - it "groups by the multi CF (Regression #26050)" do - expect(page).to have_css("#group-by--add-columns") - expect(page).to have_css("#group-by--add-rows") + it 'groups by the multi CF (Regression #26050)' do + expect(page).to have_css('#group-by--add-columns') + expect(page).to have_css('#group-by--add-rows') - select "List CF", from: "group-by--add-columns" - select "Work package", from: "group-by--add-rows" + select 'List CF', from: 'group-by--add-columns' + select 'Work package', from: 'group-by--add-rows' - click_link "Apply" + click_link 'Apply' # Expect row of work package - within("#result-table") do - expect(page).to have_css("a.work_package", text: "#{work_package.type} ##{work_package.id}") + within('#result-table') do + expect(page).to have_css('a.work_package', text: "#{work_package.type} ##{work_package.id}") # There used to be additional and unwanted text after the option name being rendered. - expect(page).to have_css("th.inner", text: /^First option$/) - expect(page).to have_no_css("th.inner", text: "Second option") + expect(page).to have_css('th.inner', text: /^First option$/) + expect(page).to have_no_css('th.inner', text: 'Second option') # Only first option should have content for the work package - expect(page).to have_css("table.report tbody tr", count: 1) - row_elements = page.all("table.report tr.odd th") + expect(page).to have_css('table.report tbody tr', count: 1) + row_elements = page.all('table.report tr.odd th') expect(row_elements[0].text).to eq(project.name) expect(row_elements[1].text).to eq(work_package.to_s) - row_elements = page.all("table.report tr.odd td") - expect(row_elements[0].text).to eq("12.50 hours") + row_elements = page.all('table.report tr.odd td') + expect(row_elements[0].text).to eq('12.50 hours') end end - context "with additional WP with invalid value" do + context 'with additional WP with invalid value' do let!(:custom_field_2) do create(:list_wp_custom_field, name: "Invalid List CF", @@ -161,7 +161,7 @@ def custom_value_for(cf, str) let!(:work_package2) do create(:work_package, project:, - custom_values: { custom_field_2.id => custom_value_for(custom_field_2, "A") }) + custom_values: { custom_field_2.id => custom_value_for(custom_field_2, 'A') }) end let!(:time_entry1) do @@ -173,73 +173,73 @@ def custom_value_for(cf, str) end before do - CustomValue.find_by(customized_id: work_package2.id).update_columns(value: "invalid") + CustomValue.find_by(customized_id: work_package2.id).update_columns(value: 'invalid') work_package2.reload - visit "/cost_reports" + visit '/cost_reports' sleep(0.1) end - it "groups by the raw values when an invalid value exists" do - expect(work_package2.send(custom_field_2.attribute_getter)).to eq(["invalid not found"]) + it 'groups by the raw values when an invalid value exists' do + expect(work_package2.send(custom_field_2.attribute_getter)).to eq(['invalid not found']) - expect(page).to have_css("#group-by--add-columns") - expect(page).to have_css("#group-by--add-rows") + expect(page).to have_css('#group-by--add-columns') + expect(page).to have_css('#group-by--add-rows') - select "Invalid List CF", from: "group-by--add-columns" - select "Work package", from: "group-by--add-rows" + select 'Invalid List CF', from: 'group-by--add-columns' + select 'Work package', from: 'group-by--add-rows' sleep(0.1) - click_link "Apply" + click_link 'Apply' # Expect row of work package - within("#result-table") do - expect(page).to have_css("a.work_package", text: "#{work_package.type} ##{work_package.id}") - expect(page).to have_css("th.inner", text: "1") - expect(page).to have_no_css("th.inner", text: "invalid!") + within('#result-table') do + expect(page).to have_css('a.work_package', text: "#{work_package.type} ##{work_package.id}") + expect(page).to have_css('th.inner', text: '1') + expect(page).to have_no_css('th.inner', text: 'invalid!') end end end end - context "with text CF" do + context 'with text CF' do let(:custom_field) do create(:text_wp_custom_field, - name: "Text CF", + name: 'Text CF', types: [type], projects: [project]) end - let(:initial_custom_values) { { custom_field.id => "foo" } } + let(:initial_custom_values) { { custom_field.id => 'foo' } } before do - visit "/cost_reports" + visit '/cost_reports' sleep(0.1) end - it "groups by a text CF" do - expect(page).to have_css("#group-by--add-columns") - expect(page).to have_css("#group-by--add-rows") + it 'groups by a text CF' do + expect(page).to have_css('#group-by--add-columns') + expect(page).to have_css('#group-by--add-rows') - select "Text CF", from: "group-by--add-columns" - select "Work package", from: "group-by--add-rows" + select 'Text CF', from: 'group-by--add-columns' + select 'Work package', from: 'group-by--add-rows' - click_link "Apply" + click_link 'Apply' # Expect row of work package - within("#result-table") do - expect(page).to have_css("a.work_package", text: "#{work_package.type} ##{work_package.id}") - expect(page).to have_css("th.inner", text: "foo") - expect(page).to have_no_css("th.inner", text: "None") + within('#result-table') do + expect(page).to have_css('a.work_package', text: "#{work_package.type} ##{work_package.id}") + expect(page).to have_css('th.inner', text: 'foo') + expect(page).to have_no_css('th.inner', text: 'None') # Only first option should have content for the work package - expect(page).to have_css("table.report tbody tr", count: 1) - row_elements = page.all("table.report tr.odd th") + expect(page).to have_css('table.report tbody tr', count: 1) + row_elements = page.all('table.report tr.odd th') expect(row_elements[0].text).to eq(project.name) expect(row_elements[1].text).to eq(work_package.to_s) - row_elements = page.all("table.report tr.odd td") - expect(row_elements[0].text).to eq("12.50 hours") + row_elements = page.all('table.report tr.odd td') + expect(row_elements[0].text).to eq('12.50 hours') end end end diff --git a/modules/reporting/spec/features/export_cost_report_spec.rb b/modules/reporting/spec/features/export_cost_report_spec.rb index 8f3fb358d649..aac374de3117 100644 --- a/modules/reporting/spec/features/export_cost_report_spec.rb +++ b/modules/reporting/spec/features/export_cost_report_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../spec_helper" -require_relative "support/pages/cost_report_page" +require_relative '../spec_helper' +require_relative 'support/pages/cost_report_page' RSpec.describe "Cost reports XLS export", :js do shared_let(:project) { create(:project) } shared_let(:user) { create(:admin) } - shared_let(:cost_type) { create(:cost_type, name: "Post-war", unit: "cap", unit_plural: "caps") } - shared_let(:work_package) { create(:work_package, project:, subject: "Some task") } + shared_let(:cost_type) { create(:cost_type, name: 'Post-war', unit: 'cap', unit_plural: 'caps') } + shared_let(:work_package) { create(:work_package, project:, subject: 'Some task') } shared_let(:cost_entry) { create(:cost_entry, user:, work_package:, project:, cost_type:) } let(:report_page) { Pages::CostReportPage.new project } let(:sheet) { @download_list.refresh_from(page).latest_downloaded_content } # rubocop:disable RSpec/InstanceVariable @@ -52,11 +52,11 @@ DownloadList.clear end - it "can download and open the XLS" do + it 'can download and open the XLS' do report_page.visit! - click_on "Export XLS" + click_on 'Export XLS' - expect(page).to have_content I18n.t("js.job_status.generic_messages.in_queue"), + expect(page).to have_content I18n.t('js.job_status.generic_messages.in_queue'), wait: 10 perform_enqueued_jobs @@ -68,9 +68,9 @@ expect(date).to eq(Time.zone.today.iso8601) expect(user_ref).to eq(user.name) - expect(wp_ref).to include "Some task" + expect(wp_ref).to include 'Some task' expect(project_ref).to eq project.name expect(costs).to eq 1.0 - expect(type).to eq "Post-war" + expect(type).to eq 'Post-war' end end diff --git a/modules/reporting/spec/features/filter_spec.rb b/modules/reporting/spec/features/filter_spec.rb index f3466494374d..708398e9176f 100644 --- a/modules/reporting/spec/features/filter_spec.rb +++ b/modules/reporting/spec/features/filter_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost report calculations", :js, :with_cuprite do +RSpec.describe 'Cost report calculations', :js, :with_cuprite do let(:project) { create(:project) } let(:user) { create(:admin) } @@ -10,8 +10,8 @@ end def clear_project_filter - within "#filter_project_id" do - find(".filter_rem").click + within '#filter_project_id' do + find('.filter_rem').click end end @@ -20,7 +20,7 @@ def reload_page wait_for_reload end - it "provides filtering" do + it 'provides filtering' do # Then filter "spent_on" should be visible # And filter "user_id" should be visible expect(page).to have_css("#filter_project_id") @@ -32,11 +32,11 @@ def reload_page # And I click on the filter's "Clear" button clear_project_filter # Then filter "project_id" should not be visible - expect(page).to have_no_css("#filter_project_id") + expect(page).to have_no_css('#filter_project_id') # Remove filters: # And I click on "Clear" - click_on "Clear" + click_on 'Clear' # Then filter "spent_on" should not be visible # And filter "user_id" should not be visible expect(page).to have_no_css("#filter_spent_on") @@ -49,6 +49,6 @@ def reload_page expect(page).to have_css("#filter_spent_on") expect(page).to have_css("#filter_user_id") - expect(page).to have_css("#user_id_arg_1_val", text: "me") + expect(page).to have_css("#user_id_arg_1_val", text: 'me') end end diff --git a/modules/reporting/spec/features/group_by_spec.rb b/modules/reporting/spec/features/group_by_spec.rb index 5d41ed4b7364..129ff4e7cbcf 100644 --- a/modules/reporting/spec/features/group_by_spec.rb +++ b/modules/reporting/spec/features/group_by_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" -require_relative "support/pages/cost_report_page" +require 'spec_helper' +require_relative 'support/pages/cost_report_page' -RSpec.describe "Cost report calculations", "grouping", :js, :with_cuprite do +RSpec.describe 'Cost report calculations', 'grouping', :js, :with_cuprite do let(:project) { create(:project) } let(:user) { create(:admin) } let(:work_package) { create(:work_package, project:) } @@ -23,93 +23,93 @@ visit cost_reports_path(project) end - it "provides grouping" do + it 'provides grouping' do # Then I should see "Week (Spent)" in columns # And I should see "Work package" in rows - report_page.expect_column_element("Week (Spent)") - report_page.expect_row_element("Work package") + report_page.expect_column_element('Week (Spent)') + report_page.expect_row_element('Work package') # When I click on "Clear" report_page.clear # Then I should not see "Week (Spent)" in columns # And I should not see "Work package" in rows - report_page.expect_column_element("Week (Spent)", present: false) - report_page.expect_row_element("Work package", present: false) + report_page.expect_column_element('Week (Spent)', present: false) + report_page.expect_row_element('Work package', present: false) # And I group rows by "User" - report_page.add_to_rows "User" + report_page.add_to_rows 'User' # And I group rows by "Cost type" - report_page.add_to_rows "Cost type" + report_page.add_to_rows 'Cost type' # When I click on "Clear" report_page.clear # Then I should not see "Week (Spent)" in columns # And I should not see "Work package" in rows - report_page.expect_column_element("Week (Spent)", present: false) - report_page.expect_row_element("Work package", present: false) + report_page.expect_column_element('Week (Spent)', present: false) + report_page.expect_row_element('Work package', present: false) # And I should not see "User" in rows # And I should not see "Cost type" in rows - report_page.expect_row_element("User", present: false) - report_page.expect_row_element("Cost type", present: false) + report_page.expect_row_element('User', present: false) + report_page.expect_row_element('Cost type', present: false) # When I click on "Clear" report_page.clear # And I group columns by "Work package" - report_page.add_to_columns "Work package" + report_page.add_to_columns 'Work package' # Then I should see "Work package" in columns - report_page.expect_column_element("Work package") + report_page.expect_column_element('Work package') # When I group rows by "Project" - report_page.add_to_columns "Project" + report_page.add_to_columns 'Project' # Then I should see "Project" in rows - report_page.expect_column_element("Project") + report_page.expect_column_element('Project') # When I click on "Clear" report_page.clear # And I group columns by "Work package" - report_page.add_to_columns "Work package" + report_page.add_to_columns 'Work package' # And I group rows by "Project" - report_page.add_to_rows "Project" + report_page.add_to_rows 'Project' # Then I should see "Work package" in columns - report_page.expect_column_element("Work package") + report_page.expect_column_element('Work package') # And I should see "Project" in rows - report_page.expect_row_element("Project") + report_page.expect_row_element('Project') # When I remove "Project" from rows - report_page.remove_row_element("Project") + report_page.remove_row_element('Project') # And I remove "Work package" from columns - report_page.remove_column_element("Work package") + report_page.remove_column_element('Work package') # Then I should not see "Work package" in columns - report_page.expect_column_element("Work package", present: false) + report_page.expect_column_element('Work package', present: false) # And I should not see "Project" in rows - report_page.expect_row_element("Project", present: false) + report_page.expect_row_element('Project', present: false) # When I click on "Clear" report_page.clear # And I group columns by "Project" - report_page.add_to_columns "Project" + report_page.add_to_columns 'Project' # And I group columns by "Work package" - report_page.add_to_columns "Work package" + report_page.add_to_columns 'Work package' # And I group rows by "User" - report_page.add_to_rows "User" + report_page.add_to_rows 'User' # And I group rows by "Cost type" - report_page.add_to_rows "Cost type" + report_page.add_to_rows 'Cost type' # And I send the query report_page.apply # Then I should see "Project" in columns - report_page.expect_column_element("Work package") + report_page.expect_column_element('Work package') # And I should see "Work package" in columns - report_page.expect_column_element("Project") + report_page.expect_column_element('Project') # And I should see "User" in rows - report_page.expect_row_element("User") + report_page.expect_row_element('User') # And I should see "Cost type" in rows - report_page.expect_row_element("Cost type") + report_page.expect_row_element('Cost type') end end diff --git a/modules/reporting/spec/features/main_menu_item_spec.rb b/modules/reporting/spec/features/main_menu_item_spec.rb index 96e98e89b8d3..1a90c2f992d0 100644 --- a/modules/reporting/spec/features/main_menu_item_spec.rb +++ b/modules/reporting/spec/features/main_menu_item_spec.rb @@ -29,9 +29,9 @@ # ++ # -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost and Reports Main Menu Item", :js, :with_cuprite do +RSpec.describe 'Cost and Reports Main Menu Item', :js, :with_cuprite do shared_let(:admin) { create(:admin) } shared_let(:project) { create(:project) } shared_let(:user_with_permissions) { create(:user, member_with_permissions: { project => %i[view_time_entries] }) } @@ -42,37 +42,37 @@ visit root_path end - shared_examples "visiting the global cost reports page" do - it "allows visiting the global cost reports page" do - within "#main-menu" do + shared_examples 'visiting the global cost reports page' do + it 'allows visiting the global cost reports page' do + within '#main-menu' do click_link I18n.t(:cost_reports_title) end - expect(page).to have_current_path(url_for(controller: "/cost_reports", - action: "index", + expect(page).to have_current_path(url_for(controller: '/cost_reports', + action: 'index', project_id: nil, only_path: true)) end end - describe "Main Menu" do - context "as an admin" do + describe 'Main Menu' do + context 'as an admin' do let(:current_user) { admin } - include_examples "visiting the global cost reports page" + include_examples 'visiting the global cost reports page' end - context "as a user with permissions" do + context 'as a user with permissions' do let(:current_user) { user_with_permissions } - include_examples "visiting the global cost reports page" + include_examples 'visiting the global cost reports page' end - context "as a user without adequate permissions" do + context 'as a user without adequate permissions' do let(:current_user) { user_without_permissions } - it "is not rendered" do - within "#main-menu" do + it 'is not rendered' do + within '#main-menu' do expect(page).to have_no_link(I18n.t(:cost_reports_title)) end end diff --git a/modules/reporting/spec/features/me_value_spec.rb b/modules/reporting/spec/features/me_value_spec.rb index 0fa670edfd1c..7c969b0c2253 100644 --- a/modules/reporting/spec/features/me_value_spec.rb +++ b/modules/reporting/spec/features/me_value_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost report showing my own times", :js do +RSpec.describe 'Cost report showing my own times', :js do let(:project) { create(:project) } let(:user) { create(:admin) } let(:user2) { create(:admin) } @@ -31,17 +31,17 @@ visit cost_reports_path(project) end - shared_examples "me filter value" do |filter_name, filter_selector| + shared_examples 'me filter value' do |filter_name, filter_selector| it 'keeps the special "me" value for the current user' do - select "me", from: filter_selector - click_on "Save" - fill_in "query_name", with: "Query ME value" - check "query_is_public" - find_by_id("query-icon-save-button").click + select 'me', from: filter_selector + click_on 'Save' + fill_in 'query_name', with: 'Query ME value' + check 'query_is_public' + find_by_id('query-icon-save-button').click # wait until the save is complete - expect(page).to have_css("h2", text: "Query ME value") + expect(page).to have_css('h2', text: 'Query ME value') - expect(page).to have_css(".report", text: "10.00") + expect(page).to have_css('.report', text: '10.00') report = nil retry_block do @@ -57,14 +57,14 @@ # Create and save cost report visit cost_report_path(report.id, project_id: project.identifier) - expect(page).to have_no_css(".report", text: "10.00") - expect(page).to have_css(".report", text: "15.00") + expect(page).to have_no_css('.report', text: '10.00') + expect(page).to have_css('.report', text: '15.00') - expect(page).to have_field(filter_selector, text: "me") + expect(page).to have_field(filter_selector, text: 'me') end end - describe "assignee filter" do + describe 'assignee filter' do let(:work_package) { create(:work_package, project:, assigned_to: user) } let(:work_package2) { create(:work_package, project:, assigned_to: user2) } @@ -85,14 +85,14 @@ before do # Remove default user filter, add assignee filter - find("#rm_box_user_id .filter_rem").click - select "Assignee", from: "add_filter_select" + find('#rm_box_user_id .filter_rem').click + select 'Assignee', from: 'add_filter_select' end - it_behaves_like "me filter value", "AssignedToId", "assigned_to_id_arg_1_val" + it_behaves_like 'me filter value', 'AssignedToId', 'assigned_to_id_arg_1_val' end - describe "user filter" do - it_behaves_like "me filter value", "UserId", "user_id_arg_1_val" + describe 'user filter' do + it_behaves_like 'me filter value', 'UserId', 'user_id_arg_1_val' end end diff --git a/modules/reporting/spec/features/menu_spec.rb b/modules/reporting/spec/features/menu_spec.rb index c24941b7f80b..7813f0117aba 100644 --- a/modules/reporting/spec/features/menu_spec.rb +++ b/modules/reporting/spec/features/menu_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "project menu" do +RSpec.describe 'project menu' do let(:current_user) { create(:admin) } - let!(:project) { create(:valid_project, identifier: "ponyo", name: "Ponyo") } + let!(:project) { create(:valid_project, identifier: 'ponyo', name: 'Ponyo') } before do allow(User).to receive(:current).and_return current_user @@ -59,59 +59,59 @@ # Refer to `engine.rb` to see where the menu entries are declared. # # * May apply to routes used with parameters in general. - describe "#18788 (cost reports not found (404)) regression test" do - describe "link to project cost reports" do - shared_examples "it leads to the project costs reports" do + describe '#18788 (cost reports not found (404)) regression test' do + describe 'link to project cost reports' do + shared_examples 'it leads to the project costs reports' do before do visit current_path end - it "leads to cost reports" do - find("#main-menu #{test_selector('op-menu--item-action')}", text: "Time and costs").click + it 'leads to cost reports' do + find("#main-menu #{test_selector('op-menu--item-action')}", text: 'Time and costs').click expect(page).to have_current_path("/projects/ponyo/cost_reports") end end context "when on the project's activity page" do - let(:current_path) { "/projects/ponyo/activity" } + let(:current_path) { '/projects/ponyo/activity' } - it_behaves_like "it leads to the project costs reports" + it_behaves_like 'it leads to the project costs reports' end context "when on the project's calendars" do - let(:current_path) { "/projects/ponyo/calendars" } + let(:current_path) { '/projects/ponyo/calendars' } - it_behaves_like "it leads to the project costs reports" + it_behaves_like 'it leads to the project costs reports' end end - describe "link to global cost reports" do - shared_examples "it leads to the cost reports" do + describe 'link to global cost reports' do + shared_examples 'it leads to the cost reports' do before do visit current_path end - it "leads to cost reports" do + it 'leads to cost reports' do # doing what no human can - click on invisible items. # This way, we avoid having to use selenium and by that increase stability. - find("#main-menu #{test_selector('op-menu--item-action')}", text: "Time and costs").click + find("#main-menu #{test_selector('op-menu--item-action')}", text: 'Time and costs').click # to make sure we're not seeing the project cost reports: - expect(page).to have_no_text("Ponyo") + expect(page).to have_no_text('Ponyo') end end context "when on the project's activity page" do - let(:current_path) { "/projects/ponyo/activity" } + let(:current_path) { '/projects/ponyo/activity' } - it_behaves_like "it leads to the cost reports" + it_behaves_like 'it leads to the cost reports' end context "when on the project's calendar" do - let(:current_path) { "/projects/ponyo/calendars" } + let(:current_path) { '/projects/ponyo/calendars' } - it_behaves_like "it leads to the cost reports" + it_behaves_like 'it leads to the cost reports' end end end diff --git a/modules/reporting/spec/features/my_time_spec.rb b/modules/reporting/spec/features/my_time_spec.rb index 093811d9c63f..f3d6e42c4d1c 100644 --- a/modules/reporting/spec/features/my_time_spec.rb +++ b/modules/reporting/spec/features/my_time_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost report showing my own times", :js do +RSpec.describe 'Cost report showing my own times', :js do let(:project) { create(:project) } let(:user) { create(:admin) } let(:user2) { create(:admin) } @@ -21,21 +21,21 @@ visit cost_reports_path(project) end - context "as user with logged time" do + context 'as user with logged time' do let(:current_user) { user } - it "shows my time" do - expect(page).to have_css(".report", text: "10.0") + it 'shows my time' do + expect(page).to have_css('.report', text: '10.0') end end - context "as user without logged time" do + context 'as user without logged time' do let(:current_user) { user2 } - it "shows my time" do - expect(page).to have_no_css(".report") - expect(page).to have_css(".generic-table--no-results-title") - expect(page).to have_no_text "10.0" # 1 EUR x 10 + it 'shows my time' do + expect(page).to have_no_css('.report') + expect(page).to have_css('.generic-table--no-results-title') + expect(page).to have_no_text '10.0' # 1 EUR x 10 end end end diff --git a/modules/reporting/spec/features/permissions_spec.rb b/modules/reporting/spec/features/permissions_spec.rb index 73e4b11803cf..1567a9889fb2 100644 --- a/modules/reporting/spec/features/permissions_spec.rb +++ b/modules/reporting/spec/features/permissions_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" -require_relative "support/pages/cost_report_page" +require 'spec_helper' +require_relative 'support/pages/cost_report_page' -RSpec.describe "Cost report calculations", :js do +RSpec.describe 'Cost report calculations', :js do let(:project) { create(:project) } let(:admin) { create(:admin) } @@ -33,7 +33,7 @@ hours: 5) end let!(:cost_type) do - type = create(:cost_type, name: "Translations") + type = create(:cost_type, name: 'Translations') create(:cost_rate, cost_type: type, rate: 7.00) type end @@ -48,33 +48,33 @@ before do login_as current_user - visit "/cost_reports?set_filter=1" + visit '/cost_reports?set_filter=1' end - context "as anonymous" do + context 'as anonymous' do let(:current_user) { User.anonymous } - it "is redirect to login" do - expect(page).to have_content "Username" - expect(page).to have_content "Password" + it 'is redirect to login' do + expect(page).to have_content 'Username' + expect(page).to have_content 'Password' end end - context "as admin" do + context 'as admin' do let(:current_user) { admin } - it "shows everything" do - expect(page).to have_content "5.00 hours" - expect(page).to have_content "10.00 hours" + it 'shows everything' do + expect(page).to have_content '5.00 hours' + expect(page).to have_content '10.00 hours' - report_page.switch_to_type "Translations" + report_page.switch_to_type 'Translations' - expect(page).to have_content "3.0 plural_unit" - expect(page).to have_content "21.00 EUR" + expect(page).to have_content '3.0 plural_unit' + expect(page).to have_content '21.00 EUR' end end - context "as user with all permissions" do + context 'as user with all permissions' do let(:current_user) { user } let!(:permissions) do %i(view_own_hourly_rate view_hourly_rates view_cost_rates @@ -82,65 +82,65 @@ view_time_entries) end - it "shows everything" do - expect(page).to have_content "5.00 hours" - expect(page).to have_content "10.00 hours" - report_page.switch_to_type "Translations" - expect(page).to have_css("td.units", text: "3.0 plural_unit", wait: 10) + it 'shows everything' do + expect(page).to have_content '5.00 hours' + expect(page).to have_content '10.00 hours' + report_page.switch_to_type 'Translations' + expect(page).to have_css('td.units', text: '3.0 plural_unit', wait: 10) end end - context "as user with no permissions" do + context 'as user with no permissions' do let(:current_user) { user } let!(:permissions) { %i() } - it "shows nothing" do - expect(page).to have_text "[Error 403]" + it 'shows nothing' do + expect(page).to have_text '[Error 403]' end end - context "as user with own permissions" do + context 'as user with own permissions' do let(:current_user) { user } let!(:permissions) do %i(view_own_hourly_rate view_own_time_entries view_own_cost_entries) end - it "shows his own costs" do - expect(page).to have_content "5.00 hours" - expect(page).to have_no_content "10.00 hours" - report_page.switch_to_type "Translations" - expect(page).to have_css("td.units", text: "3.0 plural_unit", wait: 10) + it 'shows his own costs' do + expect(page).to have_content '5.00 hours' + expect(page).to have_no_content '10.00 hours' + report_page.switch_to_type 'Translations' + expect(page).to have_css('td.units', text: '3.0 plural_unit', wait: 10) end end - context "as user with own time permissions" do + context 'as user with own time permissions' do let(:current_user) { user } let!(:permissions) do %i(view_own_time_entries) end - it "shows his own time only" do - expect(page).to have_content "5.00 hours" - expect(page).to have_no_content "10.00 hours" + it 'shows his own time only' do + expect(page).to have_content '5.00 hours' + expect(page).to have_no_content '10.00 hours' - report_page.switch_to_type "Translations" - expect(page).to have_css(".generic-table--no-results-title") - expect(page).to have_no_css("td.unit", text: "3.0 plural_unit") + report_page.switch_to_type 'Translations' + expect(page).to have_css('.generic-table--no-results-title') + expect(page).to have_no_css('td.unit', text: '3.0 plural_unit') end end - context "as user with own costs permissions" do + context 'as user with own costs permissions' do let(:current_user) { user } let!(:permissions) do %i(view_own_cost_entries) end - it "shows his own costs" do - expect(page).to have_css(".generic-table--no-results-title") - expect(page).to have_no_content "5.00 hours" - expect(page).to have_no_content "10.00 hours" - report_page.switch_to_type "Translations" - expect(page).to have_no_css("td.unit", text: "3.0 plural_unit") + it 'shows his own costs' do + expect(page).to have_css('.generic-table--no-results-title') + expect(page).to have_no_content '5.00 hours' + expect(page).to have_no_content '10.00 hours' + report_page.switch_to_type 'Translations' + expect(page).to have_no_css('td.unit', text: '3.0 plural_unit') end end end diff --git a/modules/reporting/spec/features/project_context_spec.rb b/modules/reporting/spec/features/project_context_spec.rb index 755793d0a0fe..a28f9ffc94e8 100644 --- a/modules/reporting/spec/features/project_context_spec.rb +++ b/modules/reporting/spec/features/project_context_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" -require_relative "support/pages/cost_report_page" +require 'spec_helper' +require_relative 'support/pages/cost_report_page' -RSpec.describe "Cost report project context", :js do +RSpec.describe 'Cost report project context', :js do let(:project1) { create(:project) } let(:project2) { create(:project) } let(:admin) { create(:admin) } @@ -16,9 +16,9 @@ it "switches the project context when visiting another project's cost report" do visit cost_reports_path(project1) - expect(page).to have_css(".ng-value-label", text: project1.name) + expect(page).to have_css('.ng-value-label', text: project1.name) visit cost_reports_path(project2) - expect(page).to have_css(".ng-value-label", text: project2.name) + expect(page).to have_css('.ng-value-label', text: project2.name) end end diff --git a/modules/reporting/spec/features/saving_spec.rb b/modules/reporting/spec/features/saving_spec.rb index 4210d2f808b3..7351eb6bcb78 100644 --- a/modules/reporting/spec/features/saving_spec.rb +++ b/modules/reporting/spec/features/saving_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" -require_relative "support/pages/cost_report_page" +require 'spec_helper' +require_relative 'support/pages/cost_report_page' -RSpec.describe "Cost report saving", :js do +RSpec.describe 'Cost report saving', :js do let(:project) { create(:project) } let(:user) { create(:admin) } @@ -12,49 +12,49 @@ visit cost_reports_path(project) end - it "can save reports privately" do + it 'can save reports privately' do report_page.clear - report_page.add_to_columns "Work package" - report_page.add_to_rows "Project" + report_page.add_to_columns 'Work package' + report_page.add_to_rows 'Project' - report_page.save as: "Testreport" + report_page.save as: 'Testreport' # Check if the category is displayed - expect(page).to have_css(".op-sidemenu--title", text: I18n.t(:label_private_report_plural).upcase) + expect(page).to have_css('.op-sidemenu--title', text: I18n.t(:label_private_report_plural).upcase) # Check if the new report is displayed - expect(page).to have_css(".op-sidemenu--item-title", text: "Testreport") + expect(page).to have_css('.op-sidemenu--item-title', text: 'Testreport') - report_page.expect_column_element "Work package" - report_page.expect_row_element "Project" + report_page.expect_column_element 'Work package' + report_page.expect_row_element 'Project' end - it "can save reports publicly" do + it 'can save reports publicly' do report_page.clear - report_page.add_to_columns "Work package" - report_page.add_to_rows "Project" + report_page.add_to_columns 'Work package' + report_page.add_to_rows 'Project' - report_page.save as: "Public report", public: true + report_page.save as: 'Public report', public: true # Check if the category is displayed - expect(page).to have_css(".op-sidemenu--title", text: I18n.t(:label_public_report_plural).upcase) + expect(page).to have_css('.op-sidemenu--title', text: I18n.t(:label_public_report_plural).upcase) # Check if the new report is displayed - expect(page).to have_css(".op-sidemenu--item-title", text: "Public report") + expect(page).to have_css('.op-sidemenu--item-title', text: 'Public report') - report_page.expect_column_element "Work package" - report_page.expect_row_element "Project" + report_page.expect_column_element 'Work package' + report_page.expect_row_element 'Project' end - context "as user without permissions" do + context 'as user without permissions' do let(:role) { create(:project_role, permissions: %i(view_time_entries)) } let!(:user) do create(:user, member_with_roles: { project => role }) end - it "cannot save reports" do - expect(page).to have_no_css(".buttons", text: "Save") + it 'cannot save reports' do + expect(page).to have_no_css('.buttons', text: 'Save') end end end diff --git a/modules/reporting/spec/features/subproject_spec.rb b/modules/reporting/spec/features/subproject_spec.rb index 68ae8ee3f0a0..8e32ca47c97a 100644 --- a/modules/reporting/spec/features/subproject_spec.rb +++ b/modules/reporting/spec/features/subproject_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost report in subproject", :js do +RSpec.describe 'Cost report in subproject', :js do let!(:project) { create(:project) } let!(:subproject) { create(:project, parent: project) } @@ -15,13 +15,13 @@ visit project_path(subproject) end - it "provides filtering" do - within "#main-menu" do - click_on "Time and costs" + it 'provides filtering' do + within '#main-menu' do + click_on 'Time and costs' end - within "#content" do - expect(page).to have_content "New cost report" + within '#content' do + expect(page).to have_content 'New cost report' end end end diff --git a/modules/reporting/spec/features/support/components/cost_reports_base_table.rb b/modules/reporting/spec/features/support/components/cost_reports_base_table.rb index 929e8873d5cf..8bda2bb010b9 100644 --- a/modules/reporting/spec/features/support/components/cost_reports_base_table.rb +++ b/modules/reporting/spec/features/support/components/cost_reports_base_table.rb @@ -39,7 +39,7 @@ def initialize end def rows_count(count) - expect(page).to have_css("#result-table tbody tr", count:) + expect(page).to have_css('#result-table tbody tr', count:) end def expect_action_icon(icon, row, present: true) @@ -59,13 +59,13 @@ def edit_time_entry(new_value, row) page.find("#{row_selector(row)} .icon-edit").click time_logging_modal.is_visible true - time_logging_modal.update_field "hours", new_value + time_logging_modal.update_field 'hours', new_value time_logging_modal.work_package_is_missing false - time_logging_modal.perform_action "Save" + time_logging_modal.perform_action 'Save' SeleniumHubWaiter.wait - expect_action_icon "edit", row + expect_action_icon 'edit', row expect_value new_value, row end @@ -73,12 +73,12 @@ def edit_cost_entry(new_value, row, cost_entry_id) SeleniumHubWaiter.wait page.find("#{row_selector(row)} .icon-edit").click - expect(page).to have_current_path("/cost_entries/" + cost_entry_id + "/edit") + expect(page).to have_current_path('/cost_entries/' + cost_entry_id + '/edit') SeleniumHubWaiter.wait - fill_in("cost_entry_units", with: new_value) - click_button "Save" - expect(page).to have_css(".op-toast.-success") + fill_in('cost_entry_units', with: new_value) + click_button 'Save' + expect(page).to have_css('.op-toast.-success') end def delete_entry(row) diff --git a/modules/reporting/spec/features/support/pages/cost_report_page.rb b/modules/reporting/spec/features/support/pages/cost_report_page.rb index c10eeac31c78..97dafbd84c6c 100644 --- a/modules/reporting/spec/features/support/pages/cost_report_page.rb +++ b/modules/reporting/spec/features/support/pages/cost_report_page.rb @@ -10,29 +10,29 @@ def clear # We often clear the page as the first action of the example, # which is why the frontend might not be fully initialized retry_block do - scroll_to_and_click(find_by_id("query-link-clear", text: "Clear")) + scroll_to_and_click(find_by_id('query-link-clear', text: 'Clear')) # Safeguard to force waiting for the form to be cleared expect(page) - .to have_no_css(".group-by--selected-element") + .to have_no_css('.group-by--selected-element') end end def save(as:, public: false) # Scroll to report bottom and click - scroll_to_and_click(find_by_id("query-icon-save-as", text: "Save")) + scroll_to_and_click(find_by_id('query-icon-save-as', text: 'Save')) # Ensure the form is visible - scroll_to_element find_by_id("save_as_form") + scroll_to_element find_by_id('save_as_form') - page.within("#save_as_form") do - fill_in "Name", with: as + page.within('#save_as_form') do + fill_in 'Name', with: as if public - check "Public" + check 'Public' end - click_on "Save" + click_on 'Save' end end @@ -52,38 +52,38 @@ def remove_column_element(text) end def apply - scroll_to_and_click(find_by_id("query-icon-apply-button")) + scroll_to_and_click(find_by_id('query-icon-apply-button')) end def add_to_rows(name) - select name, from: "group-by--add-rows" + select name, from: 'group-by--add-rows' end def add_to_columns(name) - select name, from: "group-by--add-columns" + select name, from: 'group-by--add-columns' end def expect_row_element(text, present: true) if present - expect(page).to have_css("#group-by--selected-rows .group-by--selected-element", text:) + expect(page).to have_css('#group-by--selected-rows .group-by--selected-element', text:) else - expect(page).to have_no_css("#group-by--selected-rows .group-by--selected-element", text:) + expect(page).to have_no_css('#group-by--selected-rows .group-by--selected-element', text:) end end def expect_column_element(text, present: true) if present - expect(page).to have_css("#group-by--selected-columns .group-by--selected-element", text:) + expect(page).to have_css('#group-by--selected-columns .group-by--selected-element', text:) else - expect(page).to have_no_css("#group-by--selected-columns .group-by--selected-element", text:) + expect(page).to have_no_css('#group-by--selected-columns .group-by--selected-element', text:) end end def show_loading_indicator(present: true) if present - expect(page).to have_css("#ajax-indicator") + expect(page).to have_css('#ajax-indicator') else - expect(page).to have_no_css("#ajax-indicator") + expect(page).to have_no_css('#ajax-indicator') end end diff --git a/modules/reporting/spec/features/top_menu_item_spec.rb b/modules/reporting/spec/features/top_menu_item_spec.rb index 137fcc62e31c..dfac4711d12f 100644 --- a/modules/reporting/spec/features/top_menu_item_spec.rb +++ b/modules/reporting/spec/features/top_menu_item_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Top menu items", :js do +RSpec.describe 'Top menu items', :js do let(:user) { create(:user) } let(:open_menu) { true } def has_menu_items?(*labels) - within ".op-app-header" do + within '.op-app-header' do labels.each do |l| expect(page).to have_link(l) end @@ -41,7 +41,7 @@ def has_menu_items?(*labels) end def expect_no_menu_item(*labels) - within ".op-app-header" do + within '.op-app-header' do labels.each do |l| expect(page).to have_no_link(l) end @@ -52,8 +52,8 @@ def click_link_in_open_menu(title) # if the menu is not completely expanded (e.g. if the frontend thread is too fast), # the click might be ignored - within ".op-app-menu--item_has-dropdown .op-app-menu--dropdown[aria-expanded=true]" do - expect(page).to have_no_css("[style~=overflow]") + within '.op-app-menu--item_has-dropdown .op-app-menu--dropdown[aria-expanded=true]' do + expect(page).to have_no_css('[style~=overflow]') page.click_link(title) end @@ -72,32 +72,32 @@ def click_link_in_open_menu(title) top_menu.click if open_menu end - describe "Modules" do + describe 'Modules' do let!(:top_menu) { find(:css, "[title=#{I18n.t('label_modules')}]") } - let(:reporting_item) { I18n.t("cost_reports_title") } + let(:reporting_item) { I18n.t('cost_reports_title') } - context "as an admin" do + context 'as an admin' do let(:user) { create(:admin) } - it "displays reporting item" do + it 'displays reporting item' do has_menu_items?(reporting_item) end - it "visits the reporting page" do + it 'visits the reporting page' do click_link_in_open_menu(reporting_item) - expect(page).to have_current_path(url_for(controller: "/cost_reports", action: "index", project_id: nil, only_path: true)) + expect(page).to have_current_path(url_for(controller: '/cost_reports', action: 'index', project_id: nil, only_path: true)) end end - context "as a regular user" do - it "has no menu item" do + context 'as a regular user' do + it 'has no menu item' do expect_no_menu_item reporting_item end end - context "as a user with permissions", :allow_all_permissions do - it "displays all options" do + context 'as a user with permissions', :allow_all_permissions do + it 'displays all options' do has_menu_items?(reporting_item) end end diff --git a/modules/reporting/spec/features/update_cost_report_spec.rb b/modules/reporting/spec/features/update_cost_report_spec.rb index 777ac25966a1..b2b33bab5af9 100644 --- a/modules/reporting/spec/features/update_cost_report_spec.rb +++ b/modules/reporting/spec/features/update_cost_report_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../spec_helper.rb") -require_relative "support/pages/cost_report_page" +require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb') +require_relative 'support/pages/cost_report_page' RSpec.describe "updating a cost report's cost type", :js do let(:project) { create(:project_with_types, members: { user => create(:project_role) }) } @@ -36,7 +36,7 @@ end let(:cost_type) do - create(:cost_type, name: "Post-war", unit: "cap", unit_plural: "caps") + create(:cost_type, name: 'Post-war', unit: 'cap', unit_plural: 'caps') end let!(:cost_entry) do @@ -49,16 +49,16 @@ login_as(user) end - it "works" do + it 'works' do report_page.visit! - report_page.save(as: "My Query", public: true) + report_page.save(as: 'My Query', public: true) report_page.wait_for_page_to_reload - cost_query = CostQuery.find_by!(name: "My Query") + cost_query = CostQuery.find_by!(name: 'My Query') expect(page).to have_current_path("/projects/#{project.identifier}/cost_reports/#{cost_query.id}") - expect(page).to have_field("Labor", checked: true) + expect(page).to have_field('Labor', checked: true) report_page.switch_to_type cost_type.name expect(page).to have_field(cost_type.name, checked: true, wait: 10) diff --git a/modules/reporting/spec/features/update_entries_spec.rb b/modules/reporting/spec/features/update_entries_spec.rb index 788fa4a3e7a4..d3c2ae2fe84c 100644 --- a/modules/reporting/spec/features/update_entries_spec.rb +++ b/modules/reporting/spec/features/update_entries_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "support/pages/cost_report_page" -require_relative "support/components/cost_reports_base_table" +require 'spec_helper' +require_relative 'support/pages/cost_report_page' +require_relative 'support/components/cost_reports_base_table' -RSpec.describe "Updating entries within the cost report", :js do +RSpec.describe 'Updating entries within the cost report', :js do let(:project) { create(:project) } let(:user) { create(:admin, member_with_permissions: { project => %i[work_package_assigned] }) } let(:work_package) { create(:work_package, project:) } @@ -44,7 +44,7 @@ end let(:cost_type) do - type = create(:cost_type, name: "My cool type") + type = create(:cost_type, name: 'My cool type') create(:cost_rate, cost_type: type, rate: 7.00) type end @@ -69,11 +69,11 @@ report_page.show_loading_indicator present: false end - it "can edit and delete time entries" do + it 'can edit and delete time entries' do table.rows_count 1 - table.expect_action_icon "edit", 1 - table.expect_action_icon "delete", 1 + table.expect_action_icon 'edit', 1 + table.expect_action_icon 'delete', 1 table.edit_time_entry 2, 1 @@ -81,16 +81,16 @@ table.rows_count 0 end - it "can edit and delete cost entries" do + it 'can edit and delete cost entries' do table.rows_count 1 - report_page.switch_to_type "My cool type" + report_page.switch_to_type 'My cool type' report_page.show_loading_indicator present: false table.rows_count 1 - table.expect_action_icon "edit", 1 - table.expect_action_icon "delete", 1 + table.expect_action_icon 'edit', 1 + table.expect_action_icon 'delete', 1 table.edit_cost_entry 2, 1, cost_entry_user.id.to_s visit cost_reports_path(project) @@ -100,11 +100,11 @@ table.rows_count 0 end - it "shows the action icons after a table refresh" do + it 'shows the action icons after a table refresh' do table.rows_count 1 - table.expect_action_icon "edit", 1 - table.expect_action_icon "delete", 1 + table.expect_action_icon 'edit', 1 + table.expect_action_icon 'delete', 1 # Force a reload of the table (although nothing has changed) report_page.apply @@ -113,22 +113,22 @@ table.rows_count 1 - table.expect_action_icon "edit", 1 - table.expect_action_icon "delete", 1 + table.expect_action_icon 'edit', 1 + table.expect_action_icon 'delete', 1 end - context "as user without permissions" do + context 'as user without permissions' do let(:role) { create(:project_role, permissions: %i(view_time_entries)) } let!(:user) do create(:user, member_with_roles: { project => role }) end - it "cannot edit or delete" do + it 'cannot edit or delete' do table.rows_count 1 - table.expect_action_icon "edit", 1, present: false - table.expect_action_icon "delete", 1, present: false + table.expect_action_icon 'edit', 1, present: false + table.expect_action_icon 'delete', 1, present: false end end end diff --git a/modules/reporting/spec/features/work_package_costlog_spec.rb b/modules/reporting/spec/features/work_package_costlog_spec.rb index 4c8a43983b27..8bb034a5b294 100644 --- a/modules/reporting/spec/features/work_package_costlog_spec.rb +++ b/modules/reporting/spec/features/work_package_costlog_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cost report showing my own times", :js do +RSpec.describe 'Cost report showing my own times', :js do let(:project) { create(:project) } let(:user) do create(:user, member_with_roles: { project => role }) @@ -11,7 +11,7 @@ let(:budget) do create(:budget, project:) end - let(:cost_type) { create(:cost_type, name: "Foobar", unit: "Foobar", unit_plural: "Foobars") } + let(:cost_type) { create(:cost_type, name: 'Foobar', unit: 'Foobar', unit_plural: 'Foobars') } let(:work_package) { create(:work_package, project:, budget:) } let(:wp_page) { Pages::FullWorkPackage.new work_package, project } @@ -21,9 +21,9 @@ project:, work_package:, spent_on: Date.today, - units: "10", + units: '10', user:, - comments: "foobar") + comments: 'foobar') end before do @@ -32,15 +32,15 @@ wp_page.visit! end - it "allows visiting the costs which redirects to cost reports" do + it 'allows visiting the costs which redirects to cost reports' do new_window = window_opened_by do - page.find(".costsByType a", text: "10 Foobar").click + page.find('.costsByType a', text: '10 Foobar').click end within_window new_window do - expect(page).to have_css("#query_saved_name", text: "New cost report") - expect(page).to have_field("values[work_package_id][]", with: work_package.id) - expect(page).to have_css("td.units", text: "10.0 Foobars") + expect(page).to have_css('#query_saved_name', text: 'New cost report') + expect(page).to have_field('values[work_package_id][]', with: work_package.id) + expect(page).to have_css('td.units', text: '10.0 Foobars') end end end diff --git a/modules/reporting/spec/helpers/reporting_helper_spec.rb b/modules/reporting/spec/helpers/reporting_helper_spec.rb index 6cd5de8acc28..840a206c588e 100644 --- a/modules/reporting/spec/helpers/reporting_helper_spec.rb +++ b/modules/reporting/spec/helpers/reporting_helper_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ReportingHelper do - describe "#field_representation_map" do - context "for a custom field" do - context "for which a custom option exists (e.g. a list field)" do + describe '#field_representation_map' do + context 'for a custom field' do + context 'for which a custom option exists (e.g. a list field)' do let(:custom_field) do create( :list_wp_custom_field, @@ -40,20 +40,20 @@ ) end - it "returns the option value" do + it 'returns the option value' do option = custom_field.possible_values.first expect(field_representation_map("custom_field#{custom_field.id}", option.id)) - .to eql "ham" + .to eql 'ham' end - it "returns not found for an outdated value value" do + it 'returns not found for an outdated value value' do expect(field_representation_map("custom_field#{custom_field.id}", "1234123")) - .to eql "1234123 not found" + .to eql '1234123 not found' end end - context "for which no custom option exists (e.g. a float field)" do + context 'for which no custom option exists (e.g. a float field)' do let(:custom_field) do create( :float_wp_custom_field, @@ -61,15 +61,15 @@ ) end - it "returns the option value" do + it 'returns the option value' do expect(field_representation_map("custom_field#{custom_field.id}", 3.0)) .to be 3.0 end end end - context "for which no custom option exists" do - it "returns the not found value" do + context 'for which no custom option exists' do + it 'returns the not found value' do expect(field_representation_map("custom_field12345", "345")) .to eql "345 not found" end diff --git a/modules/reporting/spec/lib/open_project/configuration_spec.rb b/modules/reporting/spec/lib/open_project/configuration_spec.rb index 34f7d4792ff4..bb506bb36d00 100644 --- a/modules/reporting/spec/lib/open_project/configuration_spec.rb +++ b/modules/reporting/spec/lib/open_project/configuration_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "OpenProject::Configuration" do - describe ".cost_reporting_cache_filter_classes" do - it "is a true by default via the method" do +RSpec.describe 'OpenProject::Configuration' do + describe '.cost_reporting_cache_filter_classes' do + it 'is a true by default via the method' do expect(OpenProject::Configuration.cost_reporting_cache_filter_classes).to be_truthy end - it "is true by default via the hash" do - expect(OpenProject::Configuration["cost_reporting_cache_filter_classes"]).to be_truthy + it 'is true by default via the hash' do + expect(OpenProject::Configuration['cost_reporting_cache_filter_classes']).to be_truthy end end end diff --git a/modules/reporting/spec/models/cost_query/cache_spec.rb b/modules/reporting/spec/models/cost_query/cache_spec.rb index bd04aed28795..2245b4712ad6 100644 --- a/modules/reporting/spec/models/cost_query/cache_spec.rb +++ b/modules/reporting/spec/models/cost_query/cache_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.join(File.dirname(__FILE__), "..", "..", "support", "configuration_helper") +require 'spec_helper' +require File.join(File.dirname(__FILE__), '..', '..', 'support', 'configuration_helper') RSpec.describe CostQuery::Cache do include OpenProject::Reporting::SpecHelper::ConfigurationHelper @@ -75,20 +75,20 @@ def no_custom_fields_exist reset_cache_keys end - describe ".check" do - context "with cache_classes configuration enabled" do + describe '.check' do + context 'with cache_classes configuration enabled' do before do mock_cache_classes_setting_with(true) end - it "resets the caches on filters and group by" do + it 'resets the caches on filters and group by' do custom_fields_exist expect_reset_on_caches described_class.check end - it "stores when the last update was made and does not reset again if nothing changed" do + it 'stores when the last update was made and does not reset again if nothing changed' do custom_fields_exist expect_reset_on_caches @@ -99,7 +99,7 @@ def no_custom_fields_exist described_class.check end - it "does reset the cache if last CustomField is removed" do + it 'does reset the cache if last CustomField is removed' do custom_fields_exist expect_reset_on_caches @@ -112,12 +112,12 @@ def no_custom_fields_exist end end - context "with_cache_classes configuration disabled" do + context 'with_cache_classes configuration disabled' do before do mock_cache_classes_setting_with(false) end - it "resets the cache again even if nothing changed" do + it 'resets the cache again even if nothing changed' do custom_fields_exist expect_reset_on_caches diff --git a/modules/reporting/spec/models/cost_query/chaining_spec.rb b/modules/reporting/spec/models/cost_query/chaining_spec.rb index ab7a450bbf4e..65cd5d4f238e 100644 --- a/modules/reporting/spec/models/cost_query/chaining_spec.rb +++ b/modules/reporting/spec/models/cost_query/chaining_spec.rb @@ -33,7 +33,7 @@ minimal_query - describe "#chain" do + describe '#chain' do around do |example| # FIXME: is there a better way to load all filter and groups? CostQuery::Filter.all && CostQuery::GroupBy.all @@ -165,7 +165,7 @@ def self.engine end describe Report::Chainable do - describe "#top" do + describe '#top' do let(:chain) { described_class.new } it "returns for an one element long chain that chain as top" do @@ -190,7 +190,7 @@ def self.engine end end - describe "#inherited_attribute" do + describe '#inherited_attribute' do before do @a = Class.new described_class @a.inherited_attribute :foo, default: 42 @@ -199,31 +199,31 @@ def self.engine @d = Class.new @b end - it "takes default argument" do + it 'takes default argument' do expect(@a.foo).to eq(42) expect(@b.foo).to eq(42) expect(@c.foo).to eq(42) expect(@d.foo).to eq(42) end - it "inherits values" do + it 'inherits values' do @a.foo 1337 expect(@d.foo).to eq(1337) end - it "does not change values of parents and akin" do + it 'does not change values of parents and akin' do @b.foo 1337 expect(@a.foo).not_to eq(1337) expect(@c.foo).not_to eq(1337) end - it "is able to map values" do + it 'is able to map values' do @a.inherited_attribute :bar, map: proc { |x| x * 2 } @a.bar 21 expect(@a.bar).to eq(42) end - describe "#list" do + describe '#list' do it "merges lists" do @a.inherited_attribute :bar, list: true @a.bar 1 @@ -262,7 +262,7 @@ def self.engine end end - describe "#display" do + describe '#display' do it "gives display? == false when a filter says dont_display!" do class TestFilter < Report::Filter::Base dont_display! @@ -287,7 +287,7 @@ class TestFilter < Report::Filter::Base end end - describe "#selectable" do + describe '#selectable' do it "gives selectable? == false when a filter says not_selectable!" do class TestFilter < Report::Filter::Base not_selectable! diff --git a/modules/reporting/spec/models/cost_query/filter_spec.rb b/modules/reporting/spec/models/cost_query/filter_spec.rb index c18b92e60065..745086b4793b 100644 --- a/modules/reporting/spec/models/cost_query/filter_spec.rb +++ b/modules/reporting/spec/models/cost_query/filter_spec.rb @@ -27,7 +27,7 @@ #++ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper") -require File.join(File.dirname(__FILE__), "..", "..", "support", "custom_field_filter") +require File.join(File.dirname(__FILE__), '..', '..', 'support', 'custom_field_filter') RSpec.describe CostQuery, :reporting_query_helper do minimal_query @@ -69,11 +69,11 @@ def create_work_package_with_time_entry(work_package_params = {}, entry_params = # Test Work Package attributes that are included in of the result set [ - [CostQuery::Filter::ProjectId, "project", "project_id", 2], - [CostQuery::Filter::UserId, "user", "user_id", 2], - [CostQuery::Filter::CostTypeId, "cost_type", "cost_type_id", 1], - [CostQuery::Filter::WorkPackageId, "work_package", "work_package_id", 2], - [CostQuery::Filter::ActivityId, "activity", "activity_id", 1] + [CostQuery::Filter::ProjectId, 'project', "project_id", 2], + [CostQuery::Filter::UserId, 'user', "user_id", 2], + [CostQuery::Filter::CostTypeId, 'cost_type', "cost_type_id", 1], + [CostQuery::Filter::WorkPackageId, 'work_package', "work_package_id", 2], + [CostQuery::Filter::ActivityId, 'activity', "activity_id", 1] ].each do |filter, object_name, field, expected_count| describe filter do let!(:non_matching_entry) { create(:cost_entry) } @@ -157,7 +157,7 @@ def create_work_package_with_time_entry(work_package_params = {}, entry_params = end it "onlies return entries from the given CostQuery::Filter::AuthorId" do - query.filter "author_id", value: author.id + query.filter 'author_id', value: author.id query.result.each do |result| work_package_id = result["work_package_id"] expect(WorkPackage.find(work_package_id).author.id).to eq(author.id) @@ -165,8 +165,8 @@ def create_work_package_with_time_entry(work_package_params = {}, entry_params = end it "allows chaining the same filter" do - query.filter "author_id", value: author.id - query.filter "author_id", value: author.id + query.filter 'author_id', value: author.id + query.filter 'author_id', value: author.id query.result.each do |result| work_package_id = result["work_package_id"] expect(WorkPackage.find(work_package_id).author.id).to eq(author.id) @@ -174,30 +174,30 @@ def create_work_package_with_time_entry(work_package_params = {}, entry_params = end it "returns no results for excluding filters" do - query.filter "author_id", value: author.id - query.filter "author_id", value: author.id + 1 + query.filter 'author_id', value: author.id + query.filter 'author_id', value: author.id + 1 expect(query.result.count).to eq(0) end it "computes the correct number of results" do - query.filter "author_id", value: author.id + query.filter 'author_id', value: author.id expect(query.result.count).to eq(2) end end it "filters spent_on" do - query.filter :spent_on, operator: "w" + query.filter :spent_on, operator: 'w' expect(query.result.count).to eq(Entry.all.count { |e| e.spent_on.cweek == TimeEntry.all.first.spent_on.cweek }) end it "filters created_at" do - query.filter :created_on, operator: "t" + query.filter :created_on, operator: 't' # we assume that some of our fixtures set created_at to Time.now expect(query.result.count).to eq(Entry.all.count { |e| e.created_at.to_date == Time.zone.today }) end it "filters updated_at" do - query.filter :updated_on, value: Time.zone.today.years_ago(20), operator: ">d" + query.filter :updated_on, value: Time.zone.today.years_ago(20), operator: '>d' # we assume that our were updated in the last 20 years expect(query.result.count).to eq(Entry.all.count { |e| e.updated_at.to_date > Time.zone.today.years_ago(20) }) end @@ -209,7 +209,7 @@ def create_work_package_with_time_entry(work_package_params = {}, entry_params = create_work_package_with_time_entry({}, { user: anonymous }) # create matching entry create_work_package_with_time_entry - query.filter :user_id, value: user.id, operator: "=" + query.filter :user_id, value: user.id, operator: '=' expect(query.result.count).to eq(1) end @@ -227,46 +227,46 @@ def create_matching_object_with_time_entries(factory, work_package_field, entry_ end it "filters overridden_costs" do - query.filter :overridden_costs, operator: "y" + query.filter :overridden_costs, operator: 'y' expect(query.result.count).to eq(Entry.all.count { |e| !e.overridden_costs.nil? }) end it "filters status" do matching_status = create(:status, is_closed: true) create_work_packages_and_time_entries(3, status: matching_status) - query.filter :status_id, operator: "c" + query.filter :status_id, operator: 'c' expect(query.result.count).to eq(3) end it "filters types" do matching_type = project.types.first create_work_packages_and_time_entries(3, type: matching_type) - query.filter :type_id, operator: "=", value: matching_type.id + query.filter :type_id, operator: '=', value: matching_type.id expect(query.result.count).to eq(3) end it "filters work_package authors" do matching_author = create_matching_object_with_time_entries(:user, :author, 3) - query.filter :author_id, operator: "=", value: matching_author.id + query.filter :author_id, operator: '=', value: matching_author.id expect(query.result.count).to eq(3) end it "filters priority" do matching_priority = create_matching_object_with_time_entries(:priority, :priority, 3) - query.filter :priority_id, operator: "=", value: matching_priority.id + query.filter :priority_id, operator: '=', value: matching_priority.id expect(query.result.count).to eq(3) end it "filters assigned to" do matching_user = create_matching_object_with_time_entries(:user, :assigned_to, 3) - query.filter :assigned_to_id, operator: "=", value: matching_user.id + query.filter :assigned_to_id, operator: '=', value: matching_user.id expect(query.result.count).to eq(3) end it "filters category" do category = create(:category, project:) create_work_packages_and_time_entries(3, category:) - query.filter :category_id, operator: "=", value: category.id + query.filter :category_id, operator: '=', value: category.id expect(query.result.count).to eq(3) end @@ -274,32 +274,32 @@ def create_matching_object_with_time_entries(factory, work_package_field, entry_ matching_version = create(:version, project:) create_work_packages_and_time_entries(3, version: matching_version) - query.filter :version_id, operator: "=", value: matching_version.id + query.filter :version_id, operator: '=', value: matching_version.id expect(query.result.count).to eq(3) end it "filters subject" do - matching_work_package = create_work_package_with_time_entry(subject: "matching subject") - query.filter :subject, operator: "=", value: "matching subject" + matching_work_package = create_work_package_with_time_entry(subject: 'matching subject') + query.filter :subject, operator: '=', value: 'matching subject' expect(query.result.count).to eq(1) end it "filters start" do start_date = Date.new(2013, 1, 1) matching_work_package = create_work_package_with_time_entry(start_date:) - query.filter :start_date, operator: "=d", value: start_date + query.filter :start_date, operator: '=d', value: start_date expect(query.result.count).to eq(1) end it "filters due date" do due_date = Date.new(2013, 1, 1) matching_work_package = create_work_package_with_time_entry(due_date:) - query.filter :due_date, operator: "=d", value: due_date + query.filter :due_date, operator: '=d', value: due_date expect(query.result.count).to eq(1) end it "raises an error if operator is not supported" do - expect { query.filter :spent_on, operator: "c" }.to raise_error(ArgumentError) + expect { query.filter :spent_on, operator: 'c' }.to raise_error(ArgumentError) end end @@ -353,15 +353,15 @@ def create_matching_object_with_time_entries(factory, work_package_field, entry_ describe CostQuery::Filter::CustomFieldEntries do let!(:custom_field) do cf = create(:work_package_custom_field, - name: "My custom field") + name: 'My custom field') clear_cache cf end let(:custom_field2) do - build(:work_package_custom_field, name: "Database", + build(:work_package_custom_field, name: 'Database', field_format: "list", - possible_values: ["value"]) + possible_values: ['value']) end after(:all) do @@ -458,14 +458,14 @@ def create_searchable_fields_and_values it "is usable as filter" do create_searchable_fields_and_values cf = WorkPackageCustomField.find_by(name: "Searchable Field") - query.filter cf.attribute_name, operator: "=", value: "125" + query.filter cf.attribute_name, operator: '=', value: "125" expect(query.result.count).to eq(2) end it "is usable as filter #2" do create_searchable_fields_and_values cf = WorkPackageCustomField.find_by(name: "Searchable Field") - query.filter cf.attribute_name, operator: "=", value: "finnlabs" + query.filter cf.attribute_name, operator: '=', value: "finnlabs" expect(query.result.count).to eq(0) end end diff --git a/modules/reporting/spec/models/cost_query/group_by_spec.rb b/modules/reporting/spec/models/cost_query/group_by_spec.rb index 174b3e675442..4fbb9c0d4519 100644 --- a/modules/reporting/spec/models/cost_query/group_by_spec.rb +++ b/modules/reporting/spec/models/cost_query/group_by_spec.rb @@ -27,7 +27,7 @@ #++ require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper") -require File.join(File.dirname(__FILE__), "..", "..", "support", "custom_field_filter") +require File.join(File.dirname(__FILE__), '..', '..', 'support', 'custom_field_filter') RSpec.describe CostQuery, :reporting_query_helper do let!(:type) { create(:type) } diff --git a/modules/reporting/spec/models/cost_query/integration_spec.rb b/modules/reporting/spec/models/cost_query/integration_spec.rb index 1671e337a4e1..3af98ccf1df9 100644 --- a/modules/reporting/spec/models/cost_query/integration_spec.rb +++ b/modules/reporting/spec/models/cost_query/integration_spec.rb @@ -48,7 +48,7 @@ describe "the reporting system" do it "computes group_by and a filter" do query.group_by :project_id - query.filter :status_id, operator: "o" + query.filter :status_id, operator: 'o' sql_result = query.result expect(sql_result.size).to eq(2) @@ -63,9 +63,9 @@ end it "applies two filter and a group_by correctly" do - query.filter :project_id, operator: "=", value: [project1.id] + query.filter :project_id, operator: '=', value: [project1.id] query.group_by :user_id - query.filter :overridden_costs, operator: "n" + query.filter :overridden_costs, operator: 'n' sql_result = query.result expect(sql_result.size).to eq(2) @@ -80,21 +80,21 @@ end it "applies two different filters on the same field" do - query.filter :project_id, operator: "=", value: [project1.id, project2.id] - query.filter :project_id, operator: "!", value: [project2.id] + query.filter :project_id, operator: '=', value: [project1.id, project2.id] + query.filter :project_id, operator: '!', value: [project2.id] sql_result = query.result expect(sql_result.count).to eq(2) end - it "processes only _one_ SQL query for any operations on a valid CostQuery" do + it 'processes only _one_ SQL query for any operations on a valid CostQuery' do number_of_sql_queries = 0 expect_any_instance_of(CostQuery::SqlStatement).to receive(:to_s) do |*_| - number_of_sql_queries += 1 unless caller.third.include? "sql_statement.rb" + number_of_sql_queries += 1 unless caller.third.include? 'sql_statement.rb' # Apparently, we have to return a valid SQL query - "SELECT 1=1" + 'SELECT 1=1' end # create a random query diff --git a/modules/reporting/spec/models/cost_query/operator_spec.rb b/modules/reporting/spec/models/cost_query/operator_spec.rb index 3cb849628411..0adef7845b06 100644 --- a/modules/reporting/spec/models/cost_query/operator_spec.rb +++ b/modules/reporting/spec/models/cost_query/operator_spec.rb @@ -53,241 +53,241 @@ def create_project(options = {}) end it "does =" do - expect(cost_query("projects", "id", "=", project1.id).size).to eq(1) + expect(cost_query('projects', 'id', '=', project1.id).size).to eq(1) end it "does = for multiple values" do - expect(cost_query("projects", "id", "=", project1.id, project2.id).size).to eq(2) + expect(cost_query('projects', 'id', '=', project1.id, project2.id).size).to eq(2) end it "does = for no values" do - sql = CostQuery::SqlStatement.new "projects" - "=".to_operator.modify sql, "id" + sql = CostQuery::SqlStatement.new 'projects' + "=".to_operator.modify sql, 'id' result = (ActiveRecord::Base.connection.select_all sql.to_s) expect(result).to be_empty end it "does = for nil" do - expect(cost_query("projects", "id", "=", nil).size).to eq(0) + expect(cost_query('projects', 'id', '=', nil).size).to eq(0) end it "does = for empty string" do - expect(cost_query("projects", "id", "=", "").size).to eq(0) + expect(cost_query('projects', 'id', '=', '').size).to eq(0) end it "does <=" do - expect(cost_query("projects", "id", "<=", project2.id - 1).size).to eq(1) + expect(cost_query('projects', 'id', '<=', project2.id - 1).size).to eq(1) end it "does >=" do - expect(cost_query("projects", "id", ">=", project1.id + 1).size).to eq(1) + expect(cost_query('projects', 'id', '>=', project1.id + 1).size).to eq(1) end it "does !" do - expect(cost_query("projects", "id", "!", project1.id).size).to eq(1) + expect(cost_query('projects', 'id', '!', project1.id).size).to eq(1) end it "does ! for empty string" do - expect(cost_query("projects", "id", "!", "").size).to eq(0) + expect(cost_query('projects', 'id', '!', '').size).to eq(0) end it "does ! for multiple values" do - expect(cost_query("projects", "id", "!", project1.id, project2.id).size).to eq(0) + expect(cost_query('projects', 'id', '!', project1.id, project2.id).size).to eq(0) end it "does !*" do - expect(cost_query("cost_entries", "project_id", "!*", []).size).to eq(0) + expect(cost_query('cost_entries', 'project_id', '!*', []).size).to eq(0) end it "does ~ (contains)" do - expect(cost_query("projects", "name", "~", "o").size).to eq(Project.all.count { |p| p.name.include?("o") }) - expect(cost_query("projects", "name", "~", "test").size).to eq(Project.all.count { |p| p.name.include?("test") }) - expect(cost_query("projects", "name", "~", "child").size).to eq(Project.all.count { |p| p.name.include?("child") }) + expect(cost_query('projects', 'name', '~', 'o').size).to eq(Project.all.count { |p| p.name.include?('o') }) + expect(cost_query('projects', 'name', '~', 'test').size).to eq(Project.all.count { |p| p.name.include?('test') }) + expect(cost_query('projects', 'name', '~', 'child').size).to eq(Project.all.count { |p| p.name.include?('child') }) end it "does !~ (not contains)" do - expect(cost_query("projects", "name", "!~", "o").size).to eq(Project.all.count { |p| p.name.exclude?("o") }) - expect(cost_query("projects", "name", "!~", "test").size).to eq(Project.all.count { |p| p.name.exclude?("test") }) - expect(cost_query("projects", "name", "!~", "child").size).to eq(Project.all.count { |p| p.name.exclude?("child") }) + expect(cost_query('projects', 'name', '!~', 'o').size).to eq(Project.all.count { |p| p.name.exclude?('o') }) + expect(cost_query('projects', 'name', '!~', 'test').size).to eq(Project.all.count { |p| p.name.exclude?('test') }) + expect(cost_query('projects', 'name', '!~', 'child').size).to eq(Project.all.count { |p| p.name.exclude?('child') }) end it "does c (closed work_package)" do - expect(cost_query("work_packages", "status_id", "c") { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0 + expect(cost_query('work_packages', 'status_id', 'c') { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0 end it "does o (open work_package)" do - expect(cost_query("work_packages", "status_id", "o") { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0 + expect(cost_query('work_packages', 'status_id', 'o') { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0 end it "does give the correct number of results when counting closed and open work_packages" do - a = cost_query("work_packages", "status_id", "o") { |s| s.join Status => [WorkPackage, :status] }.size - b = cost_query("work_packages", "status_id", "c") { |s| s.join Status => [WorkPackage, :status] }.size + a = cost_query('work_packages', 'status_id', 'o') { |s| s.join Status => [WorkPackage, :status] }.size + b = cost_query('work_packages', 'status_id', 'c') { |s| s.join Status => [WorkPackage, :status] }.size expect(WorkPackage.count).to eq(a + b) end it "does w (this week)" do # somehow this test doesn't work on sundays - n = cost_query("projects", "created_at", "w").size + n = cost_query('projects', 'created_at', 'w').size day_in_this_week = Time.zone.now.at_beginning_of_week + 1.day create(:project, created_at: day_in_this_week) - expect(cost_query("projects", "created_at", "w").size).to eq(n + 1) + expect(cost_query('projects', 'created_at', 'w').size).to eq(n + 1) create(:project, created_at: day_in_this_week + 7.days) create(:project, created_at: day_in_this_week - 7.days) - expect(cost_query("projects", "created_at", "w").size).to eq(n + 1) + expect(cost_query('projects', 'created_at', 'w').size).to eq(n + 1) end it "does t (today)" do - s = cost_query("projects", "created_at", "t").size + s = cost_query('projects', 'created_at', 't').size create(:project, created_at: Date.yesterday) - expect(cost_query("projects", "created_at", "t").size).to eq(s) + expect(cost_query('projects', 'created_at', 't').size).to eq(s) create(:project, created_at: Time.zone.now) - expect(cost_query("projects", "created_at", "t").size).to eq(s + 1) + expect(cost_query('projects', 'created_at', 't').size).to eq(s + 1) end it "does t+ (after the day which is n days in the future)" do - n = cost_query("projects", "created_at", ">t+", 1).size + n = cost_query('projects', 'created_at', '>t+', 1).size create(:project, created_at: Time.zone.now) - expect(cost_query("projects", "created_at", ">t+", 1).size).to eq(n) + expect(cost_query('projects', 'created_at', '>t+', 1).size).to eq(n) create(:project, created_at: Date.tomorrow + 1) - expect(cost_query("projects", "created_at", ">t+", 1).size).to eq(n + 1) + expect(cost_query('projects', 'created_at', '>t+', 1).size).to eq(n + 1) end it "does >t- (after the day which is n days ago)" do - n = cost_query("projects", "created_at", ">t-", 1).size + n = cost_query('projects', 'created_at', '>t-', 1).size create(:project, created_at: Date.today) - expect(cost_query("projects", "created_at", ">t-", 1).size).to eq(n + 1) + expect(cost_query('projects', 'created_at', '>t-', 1).size).to eq(n + 1) create(:project, created_at: Date.yesterday - 1) - expect(cost_query("projects", "created_at", ">t-", 1).size).to eq(n + 1) + expect(cost_query('projects', 'created_at', '>t-', 1).size).to eq(n + 1) end it "does t- (n days ago)" do - n = cost_query("projects", "created_at", "t-", 1).size + n = cost_query('projects', 'created_at', 't-', 1).size create(:project, created_at: Date.yesterday) - expect(cost_query("projects", "created_at", "t-", 1).size).to eq(n + 1) + expect(cost_query('projects', 'created_at', 't-', 1).size).to eq(n + 1) create(:project, created_at: Date.yesterday - 2) - expect(cost_query("projects", "created_at", "t-", 1).size).to eq(n + 1) + expect(cost_query('projects', 'created_at', 't-', 1).size).to eq(n + 1) end it "does d" do - expect(cost_query("projects", "created_at", "<>d", Time.zone.now, 5.minutes.from_now).size).to eq(0) + expect(cost_query('projects', 'created_at', '<>d', Time.zone.now, 5.minutes.from_now).size).to eq(0) end it "does >d" do # assuming that all projects were created in the past - expect(cost_query("projects", "created_at", ">d", Time.zone.now).size).to eq(0) + expect(cost_query('projects', 'created_at', '>d', Time.zone.now).size).to eq(0) end - describe "arity" do - arities = { "t" => 0, "w" => 0, "<>d" => 2, ">d" => 1 } + describe 'arity' do + arities = { 't' => 0, 'w' => 0, '<>d' => 2, '>d' => 1 } arities.each do |o, a| it("#{o} should take #{a} values") { expect(o.to_operator.arity).to eq(a) } end diff --git a/modules/reporting/spec/models/cost_query/validation_spec.rb b/modules/reporting/spec/models/cost_query/validation_spec.rb index ad4def9a8b56..930b57818601 100644 --- a/modules/reporting/spec/models/cost_query/validation_spec.rb +++ b/modules/reporting/spec/models/cost_query/validation_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') RSpec.describe "CostQuery::Validation" do class CostQuery::SomeBase diff --git a/modules/reporting/spec/requests/custom_field_cache_spec.rb b/modules/reporting/spec/requests/custom_field_cache_spec.rb index 56bca39f8b8e..a36a3cacfd49 100644 --- a/modules/reporting/spec/requests/custom_field_cache_spec.rb +++ b/modules/reporting/spec/requests/custom_field_cache_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.join(File.dirname(__FILE__), "..", "support", "custom_field_filter") -require File.join(File.dirname(__FILE__), "..", "support", "configuration_helper") +require 'spec_helper' +require File.join(File.dirname(__FILE__), '..', 'support', 'custom_field_filter') +require File.join(File.dirname(__FILE__), '..', 'support', 'configuration_helper') -RSpec.describe "Custom field filter and group by caching" do +RSpec.describe 'Custom field filter and group by caching' do include OpenProject::Reporting::SpecHelper::CustomFieldFilterHelper include OpenProject::Reporting::SpecHelper::ConfigurationHelper @@ -69,11 +69,11 @@ def expect_filter_all_to_not_exist(custom_field) def visit_cost_reports_index header "Content-Type", "text/html" - header "X-Requested-With", "XMLHttpRequest" + header 'X-Requested-With', 'XMLHttpRequest' get "/projects/#{project.id}/cost_reports" end - it "removes the filter/group_by if the custom field is removed" do + it 'removes the filter/group_by if the custom field is removed' do custom_field2.save! visit_cost_reports_index @@ -95,7 +95,7 @@ def visit_cost_reports_index expect_filter_all_to_not_exist(custom_field2) end - it "removes the filter/group_by if the last custom field is removed" do + it 'removes the filter/group_by if the last custom field is removed' do visit_cost_reports_index expect_group_by_all_to_include(custom_field) diff --git a/modules/reporting/spec/spec_helper.rb b/modules/reporting/spec/spec_helper.rb index 1956c5840108..5c944d50187e 100644 --- a/modules/reporting/spec/spec_helper.rb +++ b/modules/reporting/spec/spec_helper.rb @@ -29,4 +29,4 @@ RAILS_ENV = "test" unless defined? RAILS_ENV require "spec_helper" -Dir[File.dirname(__FILE__) + "/support/*.rb"].each { |file| require file } +Dir[File.dirname(__FILE__) + '/support/*.rb'].each { |file| require file } diff --git a/modules/reporting/spec/support/configuration_helper.rb b/modules/reporting/spec/support/configuration_helper.rb index 99c4f7f3f16d..6e644c51a2b3 100644 --- a/modules/reporting/spec/support/configuration_helper.rb +++ b/modules/reporting/spec/support/configuration_helper.rb @@ -31,7 +31,7 @@ module ConfigurationHelper def mock_cache_classes_setting_with(value) allow(OpenProject::Configuration).to receive(:[]).and_call_original allow(OpenProject::Configuration).to receive(:[]) - .with("cost_reporting_cache_filter_classes") + .with('cost_reporting_cache_filter_classes') .and_return(value) allow(OpenProject::Configuration).to receive(:cost_reporting_cache_filter_classes) .and_return(value) diff --git a/modules/reporting/spec/support/query_helper.rb b/modules/reporting/spec/support/query_helper.rb index 699e92564d11..7400fead0063 100644 --- a/modules/reporting/spec/support/query_helper.rb +++ b/modules/reporting/spec/support/query_helper.rb @@ -27,7 +27,7 @@ #++ # need to define all the operators -require "cost_query/operator" +require 'cost_query/operator' module OpenProject::Reporting module QueryHelper diff --git a/modules/storages/app/common/storages/peripherals/oauth_configurations/configuration_interface.rb b/modules/storages/app/common/storages/peripherals/oauth_configurations/configuration_interface.rb index a5442092376c..8100224d5ba5 100644 --- a/modules/storages/app/common/storages/peripherals/oauth_configurations/configuration_interface.rb +++ b/modules/storages/app/common/storages/peripherals/oauth_configurations/configuration_interface.rb @@ -38,8 +38,6 @@ def scope = raise ::Storages::Errors::SubclassResponsibility def basic_rack_oauth_client = raise ::Storages::Errors::SubclassResponsibility - def to_httpx_oauth_config = raise ::Storages::Errors::SubclassResponsibility - private def authorization_check_wrapper diff --git a/modules/storages/app/common/storages/peripherals/oauth_configurations/nextcloud_configuration.rb b/modules/storages/app/common/storages/peripherals/oauth_configurations/nextcloud_configuration.rb index 33570cad6b5d..af3dfdaea08f 100644 --- a/modules/storages/app/common/storages/peripherals/oauth_configurations/nextcloud_configuration.rb +++ b/modules/storages/app/common/storages/peripherals/oauth_configurations/nextcloud_configuration.rb @@ -32,26 +32,23 @@ module Storages module Peripherals module OAuthConfigurations class NextcloudConfiguration < ConfigurationInterface - Util = StorageInteraction::Nextcloud::Util - attr_reader :oauth_client - # rubocop:disable Lint/MissingSuper def initialize(storage) @uri = storage.uri @oauth_client = storage.oauth_client.freeze end - # rubocop:enable Lint/MissingSuper - def authorization_state_check(token) + util = ::Storages::Peripherals::StorageInteraction::Nextcloud::Util + authorization_check_wrapper do OpenProject.httpx.get( - Util.join_uri_path(@uri, "/ocs/v1.php/cloud/user"), + util.join_uri_path(@uri, '/ocs/v1.php/cloud/user'), headers: { - "Authorization" => "Bearer #{token}", - "OCS-APIRequest" => "true", - "Accept" => "application/json" + 'Authorization' => "Bearer #{token}", + 'OCS-APIRequest' => 'true', + 'Accept' => 'application/json' } ) end @@ -61,15 +58,6 @@ def extract_origin_user_id(rack_access_token) rack_access_token.raw_attributes[:user_id] end - def to_httpx_oauth_config - StorageInteraction::AuthenticationStrategies::OAuthConfiguration.new( - client_id: @oauth_client.client_id, - client_secret: @oauth_client.client_secret, - issuer: URI(Util.join_uri_path(@uri, "/index.php/apps/oauth2/api/v1")).normalize, - scope: [] - ) - end - def scope [] end @@ -82,8 +70,8 @@ def basic_rack_oauth_client scheme: @uri.scheme, host: @uri.host, port: @uri.port, - authorization_endpoint: Util.join_uri_path(@uri.path, "/index.php/apps/oauth2/authorize"), - token_endpoint: Util.join_uri_path(@uri.path, "/index.php/apps/oauth2/api/v1/token") + authorization_endpoint: File.join(@uri.path, "/index.php/apps/oauth2/authorize"), + token_endpoint: File.join(@uri.path, "/index.php/apps/oauth2/api/v1/token") ) end end diff --git a/modules/storages/app/common/storages/peripherals/oauth_configurations/one_drive_configuration.rb b/modules/storages/app/common/storages/peripherals/oauth_configurations/one_drive_configuration.rb index c66ea8c86a2e..c1380290898c 100644 --- a/modules/storages/app/common/storages/peripherals/oauth_configurations/one_drive_configuration.rb +++ b/modules/storages/app/common/storages/peripherals/oauth_configurations/one_drive_configuration.rb @@ -32,47 +32,39 @@ module Storages module Peripherals module OAuthConfigurations class OneDriveConfiguration < ConfigurationInterface - Util = StorageInteraction::OneDrive::Util + DEFAULT_SCOPES = %w[offline_access files.readwrite.all user.read sites.readwrite.all].freeze attr_reader :oauth_client - # rubocop:disable Lint/MissingSuper def initialize(storage) @storage = storage @uri = storage.uri @oauth_client = storage.oauth_client - @oauth_uri = URI("https://login.microsoftonline.com/#{@storage.tenant_id}/oauth2/v2.0").normalize + @oauth_uri = URI('https://login.microsoftonline.com/').normalize end - # rubocop:enable Lint/MissingSuper - def authorization_state_check(access_token) + util = ::Storages::Peripherals::StorageInteraction::OneDrive::Util + authorization_check_wrapper do OpenProject.httpx.get( - Util.join_uri_path(@uri, "/v1.0/me"), - headers: { "Authorization" => "Bearer #{access_token}", "Accept" => "application/json" } + util.join_uri_path(@uri, '/v1.0/me'), + headers: { 'Authorization' => "Bearer #{access_token}", 'Accept' => 'application/json' } ) end end def extract_origin_user_id(rack_access_token) - OpenProject.httpx.get( - Util.join_uri_path(@uri, "/v1.0/me"), - headers: { "Authorization" => "Bearer #{rack_access_token.access_token}", "Accept" => "application/json" } - ).raise_for_status.json["id"] - end + util = ::Storages::Peripherals::StorageInteraction::OneDrive::Util - def to_httpx_oauth_config - StorageInteraction::AuthenticationStrategies::OAuthConfiguration.new( - client_id: @oauth_client.client_id, - client_secret: @oauth_client.client_secret, - issuer: @oauth_uri, - scope: %w[https://graph.microsoft.com/.default] - ) + OpenProject.httpx.get( + util.join_uri_path(@uri, '/v1.0/me'), + headers: { 'Authorization' => "Bearer #{rack_access_token.access_token}", 'Accept' => 'application/json' } + ).raise_for_status.json['id'] end def scope - %w[https://graph.microsoft.com/.default] + DEFAULT_SCOPES end def basic_rack_oauth_client @@ -83,8 +75,8 @@ def basic_rack_oauth_client scheme: @oauth_uri.scheme, host: @oauth_uri.host, port: @oauth_uri.port, - authorization_endpoint: "#{@oauth_uri.path}/authorize", - token_endpoint: "#{@oauth_uri.path}/token" + authorization_endpoint: "/#{@storage.tenant_id}/oauth2/v2.0/authorize", + token_endpoint: "/#{@storage.tenant_id}/oauth2/v2.0/token" ) end end diff --git a/modules/storages/app/common/storages/peripherals/parse_create_params_service.rb b/modules/storages/app/common/storages/peripherals/parse_create_params_service.rb index 56696f951596..b3b021a94ad6 100644 --- a/modules/storages/app/common/storages/peripherals/parse_create_params_service.rb +++ b/modules/storages/app/common/storages/peripherals/parse_create_params_service.rb @@ -56,20 +56,20 @@ def assert_valid_elements def assert_elements_is_present return if elements.present? - raise API::Errors::PropertyMissingError.new("_embedded/elements") + raise API::Errors::PropertyMissingError.new('_embedded/elements') end def assert_elements_is_an_array return if elements.is_a?(Array) - raise API::Errors::PropertyFormatError.new("_embedded/elements", "Array", elements.class.name) + raise API::Errors::PropertyFormatError.new('_embedded/elements', 'Array', elements.class.name) end def assert_elements_does_not_exceed_maximum return if elements.size <= MAX_ELEMENTS - raise API::Errors::Validation.new("_embedded/elements", - I18n.t("api_v3.errors.too_many_elements_created_at_once", + raise API::Errors::Validation.new('_embedded/elements', + I18n.t('api_v3.errors.too_many_elements_created_at_once', max: MAX_ELEMENTS, actual: elements.size)) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb deleted file mode 100644 index 908ea6a6eec0..000000000000 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication.rb +++ /dev/null @@ -1,69 +0,0 @@ -# frozen_string_literal:true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -module Storages - module Peripherals - module StorageInteraction - class Authentication - using ::Storages::Peripherals::ServiceResultRefinements - - def self.[](strategy) - case strategy.key - when :basic_auth - AuthenticationStrategies::BasicAuth.new - when :oauth_user_token - AuthenticationStrategies::OAuthUserToken.new(strategy.user) - when :oauth_client_credentials - AuthenticationStrategies::OAuthClientCredentials.new - else - raise "Invalid authentication strategy '#{strategy}'" - end - end - - # Checks for the current authorization state of a user on a specific file storage. - # Returns one of three results: - # - :connected If a valid user token is available - # - :failed_authorization If a user token is available, which is invalid and not refreshable - # - :error If an unexpected error occurred - def self.authorization_state(storage:, user:) - auth_strategy = AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - - ::Storages::Peripherals::Registry - .resolve("#{storage.short_provider_type}.queries.auth_check") - .call(storage:, auth_strategy:) - .match( - on_success: ->(result) { result }, - on_failure: ->(error) { error.code == :unauthorized ? :failed_authorization : :error } - ) - end - end - end - end -end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/o_auth_client_credentials.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/o_auth_client_credentials.rb deleted file mode 100644 index ed482c92d757..000000000000 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/o_auth_client_credentials.rb +++ /dev/null @@ -1,84 +0,0 @@ -# frozen_string_literal:true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -module Storages - module Peripherals - module StorageInteraction - module AuthenticationStrategies - class OAuthClientCredentials - def self.strategy - Strategy.new(:oauth_client_credentials) - end - - def call(storage:, http_options: {}, &) - config = storage.oauth_configuration.to_httpx_oauth_config - - return build_failure(storage) unless config.valid? - - create_http_and_yield(issuer: config.issuer, - client_id: config.client_id, - client_secret: config.client_secret, - scope: config.scope, - http_options:, - &) - end - - private - - def create_http_and_yield(issuer:, client_id:, client_secret:, scope:, http_options:) - begin - http = OpenProject.httpx - .oauth_auth(issuer:, - client_id:, - client_secret:, - scope:, - token_endpoint_auth_method: "client_secret_post") - .with_access_token - .with(http_options) - rescue HTTPX::HTTPError => e - data = ::Storages::StorageErrorData.new(source: self.class, payload: e.response.json) - return Failures::Builder.call(code: :unauthorized, - log_message: "Error while fetching OAuth access token.", - data:) - end - - yield http - end - - def build_failure(storage) - log_message = "Cannot authenticate storage with client credential oauth flow. Storage not configured." - data = ::Storages::StorageErrorData.new(source: self.class, payload: storage) - Failures::Builder.call(code: :error, log_message:, data:) - end - end - end - end - end -end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/o_auth_user_token.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/o_auth_user_token.rb deleted file mode 100644 index 22bdc4994b75..000000000000 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/o_auth_user_token.rb +++ /dev/null @@ -1,125 +0,0 @@ -# frozen_string_literal:true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -module Storages - module Peripherals - module StorageInteraction - module AuthenticationStrategies - class OAuthUserToken - def self.strategy - Strategy.new(:oauth_user_token) - end - - def initialize(user) - @user = user - end - - # rubocop:disable Metrics/AbcSize - def call(storage:, http_options: {}, &) - config = storage.oauth_configuration - current_token = OAuthClientToken.find_by(user_id: @user, oauth_client_id: config.oauth_client.id) - if current_token.nil? - data = ::Storages::StorageErrorData.new(source: self.class) - return Failures::Builder.call(code: :unauthorized, - log_message: "Authorization failed. No user access token found.", - data:) - end - - opts = http_options.merge({ headers: { "Authorization" => "Bearer #{current_token.access_token}" } }) - response_with_current_token = yield OpenProject.httpx.with(opts) - - if response_with_current_token.success? || response_with_current_token.result != :unauthorized - response_with_current_token - else - httpx_oauth_config = config.to_httpx_oauth_config - return build_failure(storage) unless httpx_oauth_config.valid? - - refresh_and_retry(httpx_oauth_config, http_options, current_token, &) - end - end - - # rubocop:enable Metrics/AbcSize - - private - - # rubocop:disable Metrics/AbcSize - def refresh_and_retry(config, http_options, token, &) - begin - http_session = OpenProject.httpx - .oauth_auth(issuer: config.issuer, - client_id: config.client_id, - client_secret: config.client_secret, - scope: config.scope, - refresh_token: token.refresh_token, - token_endpoint_auth_method: "client_secret_post") - .with_access_token - .with(http_options) - rescue HTTPX::HTTPError => e - data = ::Storages::StorageErrorData.new(source: self.class, payload: e.response.json) - return Failures::Builder.call(code: :unauthorized, - log_message: "Error while refreshing OAuth token.", - data:) - end - - response = yield http_session - - if response.success? - success = update_refreshed_token(token, http_session) - unless success - data = ::Storages::StorageErrorData.new(source: self.class) - return Failures::Builder.call(code: :error, - log_message: "Error while persisting updated access token.", - data:) - end - end - - response - end - - # rubocop:enable Metrics/AbcSize - - def update_refreshed_token(token, http_session) - oauth = http_session.instance_variable_get(:@options).oauth_session - access_token = oauth.access_token - refresh_token = oauth.refresh_token - - token.update(access_token:, refresh_token:) - end - - def build_failure(storage) - log_message = "Cannot refresh user token for storage. Storage authentication credentials not configured." - data = ::Storages::StorageErrorData.new(source: self.class, payload: storage) - Failures::Builder.call(code: :error, log_message:, data:) - end - end - end - end - end -end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/add_user_to_group_command.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/add_user_to_group_command.rb index 6de0ec796fe2..d955de0b8ec6 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/add_user_to_group_command.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/add_user_to_group_command.rb @@ -46,13 +46,13 @@ def call(user:, group: @group) response = OpenProject .httpx .basic_auth(@username, @password) - .with(headers: { "OCS-APIRequest" => "true" }) + .with(headers: { 'OCS-APIRequest' => 'true' }) .post( Util.join_uri_path( @uri, - "ocs/v1.php/cloud/users", + 'ocs/v1.php/cloud/users', CGI.escapeURIComponent(user), - "groups" + 'groups' ), form: { "groupid" => CGI.escapeURIComponent(group) } ) @@ -61,7 +61,7 @@ def call(user:, group: @group) case response in { status: 200..299 } - statuscode = Nokogiri::XML(response.body.to_s).xpath("/ocs/meta/statuscode").text + statuscode = Nokogiri::XML(response.body.to_s).xpath('/ocs/meta/statuscode').text case statuscode when "100" @@ -78,15 +78,15 @@ def call(user:, group: @group) Util.error(:error, "Failed to add user to group", error_data) end in { status: 405 } - Util.error(:not_allowed, "Outbound request method not allowed", error_data) + Util.error(:not_allowed, 'Outbound request method not allowed', error_data) in { status: 401 } - Util.error(:not_found, "Outbound request destination not found", error_data) + Util.error(:not_found, 'Outbound request destination not found', error_data) in { status: 404 } - Util.error(:unauthorized, "Outbound request not authorized", error_data) + Util.error(:unauthorized, 'Outbound request not authorized', error_data) in { status: 409 } Util.error(:conflict, Util.error_text_from_response(response), error_data) else - Util.error(:error, "Outbound request failed", error_data) + Util.error(:error, 'Outbound request failed', error_data) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/create_folder_command.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/create_folder_command.rb index 103e537c1e76..60cfbbe4783d 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/create_folder_command.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/create_folder_command.rb @@ -60,21 +60,21 @@ def call(folder_path:) case response in { status: 200..299 } - ServiceResult.success(message: "Folder was successfully created.") + ServiceResult.success(message: 'Folder was successfully created.') in { status: 405 } - if Util.error_text_from_response(response) == "The resource you tried to create already exists" - ServiceResult.success(message: "Folder already exists.") + if Util.error_text_from_response(response) == 'The resource you tried to create already exists' + ServiceResult.success(message: 'Folder already exists.') else - Util.error(:not_allowed, "Outbound request method not allowed", error_data) + Util.error(:not_allowed, 'Outbound request method not allowed', error_data) end in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized", error_data) + Util.error(:unauthorized, 'Outbound request not authorized', error_data) in { status: 404 } - Util.error(:not_found, "Outbound request destination not found", error_data) + Util.error(:not_found, 'Outbound request destination not found', error_data) in { status: 409 } Util.error(:conflict, Util.error_text_from_response(response), error_data) else - Util.error(:error, "Outbound request failed", error_data) + Util.error(:error, 'Outbound request failed', error_data) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/download_link_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/download_link_query.rb index 7d5723749126..ba10f42b97d4 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/download_link_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/download_link_query.rb @@ -46,7 +46,7 @@ def call(user:, file_link:) direct_download_request(token, file_link).bind do |resp| # The nextcloud API returns a successful response with empty body if the authorization is missing or expired if resp.body.blank? - Util.error(:unauthorized, "Outbound request not authorized!") + Util.error(:unauthorized, 'Outbound request not authorized!') else ServiceResult.success(result: resp.body.to_s) end @@ -64,29 +64,29 @@ def direct_download_request(token, file_link) response = OpenProject .httpx .post( - Util.join_uri_path(@uri, "/ocs/v2.php/apps/dav/api/v1/direct"), + Util.join_uri_path(@uri, '/ocs/v2.php/apps/dav/api/v1/direct'), json: { fileId: file_link.origin_id }, headers: { - "Authorization" => "Bearer #{token.access_token}", - "OCS-APIRequest" => "true", - "Accept" => "application/json", - "Content-Type" => "application/json" + 'Authorization' => "Bearer #{token.access_token}", + 'OCS-APIRequest' => 'true', + 'Accept' => 'application/json', + 'Content-Type' => 'application/json' } ) case response in { status: 200..299 } ServiceResult.success(result: response) in { status: 404 } - Util.error(:not_found, "Outbound request destination not found!", response) + Util.error(:not_found, 'Outbound request destination not found!', response) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized!", response) + Util.error(:unauthorized, 'Outbound request not authorized!', response) else - Util.error(:error, "Outbound request failed!") + Util.error(:error, 'Outbound request failed!') end end def download_link(token, origin_name) - Util.join_uri_path(@uri, "index.php/apps/integration_openproject/direct", token, CGI.escape(origin_name)) + Util.join_uri_path(@uri, 'index.php/apps/integration_openproject/direct', token, CGI.escape(origin_name)) end def direct_download_token(body:) @@ -105,13 +105,13 @@ def parse_direct_download_token(body:) return nil end - direct_download_url = json.dig("ocs", "data", "url") + direct_download_url = json.dig('ocs', 'data', 'url') return nil if direct_download_url.blank? path = URI.parse(direct_download_url).path return nil if path.blank? - path.split("/").last + path.split('/').last end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_ids_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_ids_query.rb index 65eece537c05..b5cd033310c9 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_ids_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_ids_query.rb @@ -38,7 +38,7 @@ def self.call(storage:, path:) def call(path:) query_params = { - depth: "1", + depth: '1', path:, props: %w[oc:fileid] } diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb index f01c030fbf79..98c97fcb6a8a 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/file_info_query.rb @@ -32,7 +32,7 @@ module Storages::Peripherals::StorageInteraction::Nextcloud class FileInfoQuery using Storages::Peripherals::ServiceResultRefinements - FILE_INFO_PATH = "ocs/v1.php/apps/integration_openproject/fileinfo" + FILE_INFO_PATH = 'ocs/v1.php/apps/integration_openproject/fileinfo' def initialize(storage) @uri = storage.uri @@ -54,20 +54,20 @@ def call(user:, file_id:) def file_info(file_id, token) response = OpenProject .httpx - .with(headers: { "Authorization" => "Bearer #{token.access_token}", - "Accept" => "application/json", - "OCS-APIRequest" => "true" }) + .with(headers: { 'Authorization' => "Bearer #{token.access_token}", + 'Accept' => 'application/json', + 'OCS-APIRequest' => 'true' }) .get(Util.join_uri_path(@uri, FILE_INFO_PATH, file_id)) case response in { status: 200..299 } ServiceResult.success(result: response.body) in { status: 404 } - Util.error(:not_found, "Outbound request destination not found!", response) + Util.error(:not_found, 'Outbound request destination not found!', response) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized!", response) + Util.error(:unauthorized, 'Outbound request not authorized!', response) else - Util.error(:error, "Outbound request failed!") + Util.error(:error, 'Outbound request failed!') end end @@ -85,11 +85,11 @@ def handle_failure when 200..299 ServiceResult.success(result: response_object) when 403 - Util.error(:forbidden, "Access to storage file forbidden!", response_object) + Util.error(:forbidden, 'Access to storage file forbidden!', response_object) when 404 - Util.error(:not_found, "Storage file not found!", response_object) + Util.error(:not_found, 'Storage file not found!', response_object) else - Util.error(:error, "Outbound request failed!", response_object) + Util.error(:error, 'Outbound request failed!', response_object) end end end @@ -123,9 +123,9 @@ def create_storage_file_info # rubocop:enable Metrics/AbcSize def location(file_path) - prefix = "files/" + prefix = 'files/' idx = file_path.rindex(prefix) - return "/" if idx == nil + return '/' if idx == nil idx += prefix.length - 1 diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb index 929e27e06aa8..6b423df3fd86 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_info_query.rb @@ -32,7 +32,7 @@ module Storages::Peripherals::StorageInteraction::Nextcloud class FilesInfoQuery using Storages::Peripherals::ServiceResultRefinements - FILES_INFO_PATH = "ocs/v1.php/apps/integration_openproject/filesinfo" + FILES_INFO_PATH = 'ocs/v1.php/apps/integration_openproject/filesinfo' def initialize(storage) @uri = storage.uri @@ -45,7 +45,7 @@ def self.call(storage:, user:, file_ids: []) def call(user:, file_ids: []) if file_ids.nil? - return Util.error(:error, "File IDs can not be nil", file_ids) + return Util.error(:error, 'File IDs can not be nil', file_ids) end if file_ids.empty? @@ -62,10 +62,10 @@ def call(user:, file_ids: []) def files_info(file_ids, token) response = OpenProject .httpx - .with(headers: { "Authorization" => "Bearer #{token.access_token}", - "Accept" => "application/json", - "Content-Type" => "application/json", - "OCS-APIRequest" => "true" }) + .with(headers: { 'Authorization' => "Bearer #{token.access_token}", + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + 'OCS-APIRequest' => 'true' }) .post(Util.join_uri_path(@uri.to_s, FILES_INFO_PATH), json: { fileIds: file_ids }) @@ -73,11 +73,11 @@ def files_info(file_ids, token) in { status: 200..299 } ServiceResult.success(result: response.body.to_s) in { status: 404 } - Util.error(:not_found, "Outbound request destination not found!", response) + Util.error(:not_found, 'Outbound request destination not found!', response) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized!", response) + Util.error(:unauthorized, 'Outbound request not authorized!', response) else - Util.error(:error, "Outbound request failed!", response) + Util.error(:error, 'Outbound request failed!', response) end end @@ -91,10 +91,10 @@ def parse_json def handle_failure ->(response_object) do - if response_object.ocs.meta.status == "ok" + if response_object.ocs.meta.status == 'ok' ServiceResult.success(result: response_object) else - Util.error(:error, "Outbound request failed!", response_object) + Util.error(:error, 'Outbound request failed!', response_object) end end end @@ -137,14 +137,14 @@ def create_storage_file_infos # rubocop:enable Metrics/AbcSize def location(file_path, mimetype) - prefix = "files/" + prefix = 'files/' idx = file_path.rindex(prefix) - return "/" if idx == nil + return '/' if idx == nil idx += prefix.length - 1 # Remove the following when /filesinfo starts responding with a trailing slash for directory paths # in all supported versions of OpenProjectIntegation Nextcloud App. - file_path << "/" if mimetype == "application/x-op-directory" && file_path[-1] != "/" + file_path << '/' if mimetype == 'application/x-op-directory' && file_path[-1] != '/' Util.escape_path(file_path[idx..]) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb index d7a9eb0b0ea0..975347a1ee0e 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/files_query.rb @@ -28,69 +28,59 @@ module Storages::Peripherals::StorageInteraction::Nextcloud class FilesQuery - Auth = ::Storages::Peripherals::StorageInteraction::Authentication - - def self.call(storage:, auth_strategy:, folder:) - new(storage).call(auth_strategy:, folder:) + def initialize(storage) + @uri = storage.uri + @configuration = storage.oauth_configuration end - def initialize(storage) - @storage = storage + def self.call(storage:, user:, folder:) + new(storage).call(user:, folder:) end - def call(auth_strategy:, folder:) - if auth_strategy.user.nil? - error_data = Storages::StorageErrorData.new(source: self) - return Util.error(:error, "Cannot execute query without user context.", error_data) - end + def call(user:, folder:) + result = Util.token(user:, configuration: @configuration) do |token| + @location_prefix = Util.join_uri_path(@uri.path, "remote.php/dav/files", token.origin_user_id.gsub(' ', '%20')) - origin_user = origin_user_id(auth_strategy.user) - @location_prefix = Util.join_uri_path(@storage.uri.path, - "remote.php/dav/files", - origin_user.gsub(" ", "%20")) + response = OpenProject + .httpx + .request( + "PROPFIND", + Util.join_uri_path(@uri, + "remote.php/dav/files", + CGI.escapeURIComponent(token.origin_user_id), + requested_folder(folder)), + xml: requested_properties, + headers: { + 'Depth' => '1', + 'Authorization' => "Bearer #{token.access_token}" + } + ) + + handle_response(response) + end - result = make_request(auth_strategy:, folder:, user: auth_strategy.user) storage_files(result) end private - def make_request(auth_strategy:, folder:, user:) - origin_user = origin_user_id(user) - - Auth[auth_strategy].call(storage: @storage, - http_options: Util.webdav_request_with_depth(1)) do |http| - response = http.request("PROPFIND", - Util.join_uri_path(@storage.uri, - "remote.php/dav/files", - CGI.escapeURIComponent(origin_user), - requested_folder(folder)), - xml: requested_properties) - handle_response(response) - end - end - def handle_response(response) - error_data = Storages::StorageErrorData.new(source: self.class, payload: response) + error_data = Storages::StorageErrorData.new(source: self, payload: response) case response in { status: 200..299 } ServiceResult.success(result: response.body) in { status: 404 } - Util.error(:not_found, "Outbound request destination not found", error_data) + Util.error(:not_found, 'Outbound request destination not found', error_data) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized", error_data) + Util.error(:unauthorized, 'Outbound request not authorized', error_data) else - Util.error(:error, "Outbound request failed", error_data) + Util.error(:error, 'Outbound request failed', error_data) end end - def origin_user_id(user) - OAuthClientToken.find_by(user_id: user, oauth_client_id: @storage.oauth_client.id)&.origin_user_id || "" - end - def requested_folder(folder) - return "" if folder.root? + return '' if folder.root? Util.escape_path(folder.path) end @@ -98,17 +88,17 @@ def requested_folder(folder) # rubocop:disable Metrics/AbcSize def requested_properties Nokogiri::XML::Builder.new do |xml| - xml["d"].propfind( - "xmlns:d" => "DAV:", - "xmlns:oc" => "http://owncloud.org/ns" + xml['d'].propfind( + 'xmlns:d' => 'DAV:', + 'xmlns:oc' => 'http://owncloud.org/ns' ) do - xml["d"].prop do - xml["oc"].fileid - xml["oc"].size - xml["d"].getcontenttype - xml["d"].getlastmodified - xml["oc"].permissions - xml["oc"].send(:"owner-display-name") + xml['d'].prop do + xml['oc'].fileid + xml['oc'].size + xml['d'].getcontenttype + xml['d'].getlastmodified + xml['oc'].permissions + xml['oc'].send(:'owner-display-name') end end end.to_xml @@ -119,7 +109,7 @@ def requested_properties def storage_files(response) response.map do |xml| parent, *files = Nokogiri::XML(xml) - .xpath("//d:response") + .xpath('//d:response') .to_a .map { |file_element| storage_file(file_element) } @@ -128,12 +118,12 @@ def storage_files(response) end def ancestors(parent_location) - path = parent_location.split("/") + path = parent_location.split('/') return [] if path.count == 0 path.take(path.count - 1).reduce([]) do |list, item| last = list.last - prefix = last.nil? || last.location[-1] != "/" ? "/" : "" + prefix = last.nil? || last.location[-1] != '/' ? '/' : '' location = "#{last&.location}#{prefix}#{item}" list.append(forge_ancestor(location)) end @@ -146,7 +136,7 @@ def forge_ancestor(location) end def name(location) - location == "/" ? "Root" : CGI.unescape(location.split("/").last) + location == '/' ? 'Root' : CGI.unescape(location.split('/').last) end def storage_file(file_element) @@ -166,7 +156,7 @@ def storage_file(file_element) def id(element) element - .xpath(".//oc:fileid") + .xpath('.//oc:fileid') .map(&:inner_text) .reject(&:empty?) .first @@ -174,21 +164,21 @@ def id(element) def location(element) texts = element - .xpath("d:href") + .xpath('d:href') .map(&:inner_text) return nil if texts.empty? element_name = texts.first.delete_prefix(@location_prefix) - return element_name if element_name == "/" + return element_name if element_name == '/' - element_name.delete_suffix("/") + element_name.delete_suffix('/') end def size(element) element - .xpath(".//oc:size") + .xpath('.//oc:size') .map(&:inner_text) .map { |e| Integer(e) } .first @@ -196,22 +186,22 @@ def size(element) def mime_type(element) element - .xpath(".//d:getcontenttype") + .xpath('.//d:getcontenttype') .map(&:inner_text) .reject(&:empty?) - .first || "application/x-op-directory" + .first || 'application/x-op-directory' end def last_modified_at(element) element - .xpath(".//d:getlastmodified") + .xpath('.//d:getlastmodified') .map { |e| DateTime.parse(e) } .first end def created_by(element) element - .xpath(".//oc:owner-display-name") + .xpath('.//oc:owner-display-name') .map(&:inner_text) .reject(&:empty?) .first @@ -220,7 +210,7 @@ def created_by(element) def permissions(element) permissions_string = element - .xpath(".//oc:permissions") + .xpath('.//oc:permissions') .map(&:inner_text) .reject(&:empty?) .first @@ -228,7 +218,7 @@ def permissions(element) # Nextcloud Dav permissions: # https://github.com/nextcloud/server/blob/66648011c6bc278ace57230db44fd6d63d67b864/lib/public/Files/DavUtil.php result = [] - result << :readable if permissions_string.include?("G") + result << :readable if permissions_string.include?('G') result << :writeable if %w[CK W].reduce(false) { |s, v| s || permissions_string.include?(v) } result end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/folder_files_file_ids_deep_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/folder_files_file_ids_deep_query.rb index 21c2b7c901b7..71a5724dc144 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/folder_files_file_ids_deep_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/folder_files_file_ids_deep_query.rb @@ -35,7 +35,7 @@ def self.call(storage:, folder:) .resolve("nextcloud.queries.propfind") .call( storage:, - depth: "infinity", + depth: 'infinity', path: folder.path, # nc:acl-list is only required to avoid https://community.openproject.org/wp/49628. See comment #4. props: %w[oc:fileid nc:acl-list] diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/internal/propfind_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/internal/propfind_query.rb index 876ab27f04f8..05d7585c3678 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/internal/propfind_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/internal/propfind_query.rb @@ -76,14 +76,14 @@ def self.call(storage:, depth:, path:, props:) # rubocop:disable Metrics/AbcSize def call(depth:, path:, props:) body = Nokogiri::XML::Builder.new do |xml| - xml["d"].propfind( - "xmlns:d" => "DAV:", - "xmlns:oc" => "http://owncloud.org/ns", - "xmlns:nc" => "http://nextcloud.org/ns" + xml['d'].propfind( + 'xmlns:d' => 'DAV:', + 'xmlns:oc' => 'http://owncloud.org/ns', + 'xmlns:nc' => 'http://nextcloud.org/ns' ) do - xml["d"].prop do + xml['d'].prop do props.each do |prop| - namespace, property = prop.split(":") + namespace, property = prop.split(':') xml[namespace].send(property) end end @@ -98,7 +98,7 @@ def call(depth:, path:, props:) "PROPFIND", UTIL.join_uri_path( @uri, - "remote.php/dav/files", + 'remote.php/dav/files', CGI.escapeURIComponent(@username), UTIL.escape_path(path) ), @@ -111,7 +111,7 @@ def call(depth:, path:, props:) in { status: 200..299 } doc = Nokogiri::XML(response.body.to_s) result = {} - doc.xpath("/d:multistatus/d:response").each do |resource_section| + doc.xpath('/d:multistatus/d:response').each do |resource_section| resource = CGI.unescape(resource_section.xpath("d:href").text.strip) .gsub!(UTIL.join_uri_path(@uri.path, "/remote.php/dav/files/#{@username}/"), "") @@ -126,13 +126,13 @@ def call(depth:, path:, props:) ServiceResult.success(result:) in { status: 405 } - UTIL.error(:not_allowed, "Outbound request method not allowed", error_data) + UTIL.error(:not_allowed, 'Outbound request method not allowed', error_data) in { status: 401 } - UTIL.error(:unauthorized, "Outbound request not authorized", error_data) + UTIL.error(:unauthorized, 'Outbound request not authorized', error_data) in { status: 404 } - UTIL.error(:not_found, "Outbound request destination not found", error_data) + UTIL.error(:not_found, 'Outbound request destination not found', error_data) else - UTIL.error(:error, "Outbound request failed", error_data) + UTIL.error(:error, 'Outbound request failed', error_data) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query.rb index a512135ea1df..2aed80596f86 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query.rb @@ -43,7 +43,7 @@ def self.call(storage:, user:) # rubocop:disable Lint/UnusedMethodArgument def call(user:) - ServiceResult.success(result: Util.join_uri_path(@uri, "index.php/apps/files")) + ServiceResult.success(result: Util.join_uri_path(@uri, 'index.php/apps/files')) end # rubocop:enable Lint/UnusedMethodArgument diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/remove_user_from_group_command.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/remove_user_from_group_command.rb index 167dbc50557b..1972ed3e43ef 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/remove_user_from_group_command.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/remove_user_from_group_command.rb @@ -46,7 +46,7 @@ def call(user:, group: @group) response = OpenProject .httpx .basic_auth(@username, @password) - .with(headers: { "OCS-APIRequest" => "true" }) + .with(headers: { 'OCS-APIRequest' => 'true' }) .delete( Util.join_uri_path(@uri, "ocs/v1.php/cloud/users", @@ -58,7 +58,7 @@ def call(user:, group: @group) case response in { status: 200..299 } - statuscode = Nokogiri::XML(response.body.to_s).xpath("/ocs/meta/statuscode").text + statuscode = Nokogiri::XML(response.body.to_s).xpath('/ocs/meta/statuscode').text case statuscode when "100" ServiceResult.success(message: "User has been removed from group") @@ -71,19 +71,19 @@ def call(user:, group: @group) when "104" Util.error(:error, "Insufficient privileges", error_data) when "105" - message = Nokogiri::XML(response.body).xpath("/ocs/meta/message").text + message = Nokogiri::XML(response.body).xpath('/ocs/meta/message').text Util.error(:error, "Failed to remove user #{user} from group #{group}: #{message}", error_data) end in { status: 405 } - Util.error(:not_allowed, "Outbound request method not allowed", error_data) + Util.error(:not_allowed, 'Outbound request method not allowed', error_data) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized", error_data) + Util.error(:unauthorized, 'Outbound request not authorized', error_data) in { status: 404 } - Util.error(:not_found, "Outbound request destination not found", error_data) + Util.error(:not_found, 'Outbound request destination not found', error_data) in { status: 409 } Util.error(:conflict, Util.error_text_from_response(response), error_data) else - Util.error(:error, "Outbound request failed", error_data) + Util.error(:error, 'Outbound request failed', error_data) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command.rb index 12f4da101eec..9d8434a41dbf 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/rename_file_command.rb @@ -51,7 +51,7 @@ def call(source:, target:) "MOVE", Util.join_uri_path(@base_path, Util.escape_path(source)), headers: { - "Destination" => Util.join_uri_path(@uri.path, + 'Destination' => Util.join_uri_path(@uri.path, "remote.php/dav/files", CGI.escapeURIComponent(@username), Util.escape_path(target)) @@ -64,11 +64,11 @@ def call(source:, target:) in { status: 200..299 } ServiceResult.success in { status: 404 } - Util.error(:not_found, "Outbound request destination not found", error_data) + Util.error(:not_found, 'Outbound request destination not found', error_data) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized", error_data) + Util.error(:unauthorized, 'Outbound request not authorized', error_data) else - Util.error(:error, "Outbound request failed", error_data) + Util.error(:error, 'Outbound request failed', error_data) end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/set_permissions_command.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/set_permissions_command.rb index 09f239dd6d99..6f4d01e0f17b 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/set_permissions_command.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/set_permissions_command.rb @@ -51,27 +51,27 @@ def call(path:, permissions:) groups_permissions = permissions.fetch(:groups) body = Nokogiri::XML::Builder.new do |xml| - xml["d"].propertyupdate( - "xmlns:d" => "DAV:", - "xmlns:nc" => "http://nextcloud.org/ns" + xml['d'].propertyupdate( + 'xmlns:d' => 'DAV:', + 'xmlns:nc' => 'http://nextcloud.org/ns' ) do - xml["d"].set do - xml["d"].prop do - xml["nc"].send(:"acl-list") do + xml['d'].set do + xml['d'].prop do + xml['nc'].send(:'acl-list') do groups_permissions.each do |group, group_permissions| - xml["nc"].acl do - xml["nc"].send(:"acl-mapping-type", "group") - xml["nc"].send(:"acl-mapping-id", group) - xml["nc"].send(:"acl-mask", "31") - xml["nc"].send(:"acl-permissions", group_permissions.to_s) + xml['nc'].acl do + xml['nc'].send(:'acl-mapping-type', 'group') + xml['nc'].send(:'acl-mapping-id', group) + xml['nc'].send(:'acl-mask', '31') + xml['nc'].send(:'acl-permissions', group_permissions.to_s) end end users_permissions.each do |user, user_permissions| - xml["nc"].acl do - xml["nc"].send(:"acl-mapping-type", "user") - xml["nc"].send(:"acl-mapping-id", user) - xml["nc"].send(:"acl-mask", "31") - xml["nc"].send(:"acl-permissions", user_permissions.to_s) + xml['nc'].acl do + xml['nc'].send(:'acl-mapping-type', 'user') + xml['nc'].send(:'acl-mapping-id', user) + xml['nc'].send(:'acl-mask', '31') + xml['nc'].send(:'acl-permissions', user_permissions.to_s) end end end @@ -103,11 +103,11 @@ def call(path:, permissions:) Util.error(:error, "nc:acl properly has not been set for #{path}", error_data) end in { status: 404 } - Util.error(:not_found, "Outbound request destination not found", error_data) + Util.error(:not_found, 'Outbound request destination not found', error_data) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized", error_data) + Util.error(:unauthorized, 'Outbound request not authorized', error_data) else - Util.error(:error, "Outbound request failed", error_data) + Util.error(:error, 'Outbound request failed', error_data) end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query.rb index 256dd3711e62..3bd35834a489 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query.rb @@ -32,8 +32,8 @@ module Storages::Peripherals::StorageInteraction::Nextcloud class UploadLinkQuery using Storages::Peripherals::ServiceResultRefinements - URI_TOKEN_REQUEST = "index.php/apps/integration_openproject/direct-upload-token" - URI_UPLOAD_BASE_PATH = "index.php/apps/integration_openproject/direct-upload" + URI_TOKEN_REQUEST = 'index.php/apps/integration_openproject/direct-upload-token' + URI_UPLOAD_BASE_PATH = 'index.php/apps/integration_openproject/direct-upload' def initialize(storage) @uri = storage.uri @@ -46,12 +46,12 @@ def self.call(storage:, user:, data:) def call(user:, data:) Util.token(user:, configuration: @configuration) do |token| - if data.nil? || data["parent"].nil? - Util.error(:error, "Data is invalid", data) + if data.nil? || data['parent'].nil? + Util.error(:error, 'Data is invalid', data) else outbound_response( relative_path: URI_TOKEN_REQUEST, - payload: { folder_id: data["parent"] }, + payload: { folder_id: data['parent'] }, token: ).map do |response| Storages::UploadLink.new( @@ -67,9 +67,9 @@ def call(user:, data:) def outbound_response(relative_path:, payload:, token:) response = OpenProject .httpx - .with(headers: { "Authorization" => "Bearer #{token.access_token}", - "Accept" => "application/json", - "Content-Type" => "application/json" }) + .with(headers: { 'Authorization' => "Bearer #{token.access_token}", + 'Accept' => 'application/json', + 'Content-Type' => 'application/json' }) .post( Util.join_uri_path(@uri, relative_path), json: payload @@ -82,14 +82,14 @@ def outbound_response(relative_path:, payload:, token:) result: JSON.parse(response.body.to_s, object_class: OpenStruct) # rubocop:disable Style/OpenStructUse ) else - Util.error(:unauthorized, "Outbound request not authorized!") + Util.error(:unauthorized, 'Outbound request not authorized!') end in { status: 404 } - Util.error(:not_found, "Outbound request destination not found!", response) + Util.error(:not_found, 'Outbound request destination not found!', response) in { status: 401 } - Util.error(:unauthorized, "Outbound request not authorized!", response) + Util.error(:unauthorized, 'Outbound request not authorized!', response) else - Util.error(:error, "Outbound request failed!") + Util.error(:error, 'Outbound request failed!') end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/util.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/util.rb index e707eee5c6bf..c41aa76ffed7 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/util.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/util.rb @@ -38,12 +38,10 @@ def escape_path(path) escaped_path end - def ocs_api_request - { headers: { 'OCS-APIRequest' => 'true' } } - end - - def webdav_request_with_depth(number) - { headers: { 'Depth' => number } } + def basic_auth_header(username, password) + { + 'Authorization' => "Basic #{Base64::strict_encode64("#{username}:#{password}")}" + } end def error(code, log_message = nil, data = nil) diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb index 5aad9c649276..87333f07c45b 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb +++ b/modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/files_query.rb @@ -34,12 +34,11 @@ module StorageInteraction module OneDrive class FilesQuery FIELDS = "?$select=id,name,size,webUrl,lastModifiedBy,createdBy,fileSystemInfo,file,folder,parentReference" - Auth = ::Storages::Peripherals::StorageInteraction::Authentication using ServiceResultRefinements - def self.call(storage:, auth_strategy:, folder:) - new(storage).call(auth_strategy:, folder:) + def self.call(storage:, user:, folder:) + new(storage).call(user:, folder:) end def initialize(storage) @@ -47,16 +46,20 @@ def initialize(storage) @uri = storage.uri end - def call(auth_strategy:, folder:) - Auth[auth_strategy].call(storage: @storage) do |http| - call = http.get(Util.join_uri_path(@uri, children_uri_path_for(folder) + FIELDS)) - response = handle_response(call, :value) + def call(user:, folder:) + result = Util.using_user_token(@storage, user) do |token| + response = OpenProject.httpx.get( + Util.join_uri_path(@uri, children_uri_path_for(folder) + FIELDS), + headers: { 'Authorization' => "Bearer #{token.access_token}" } + ) + + handle_response(response, :value) + end - if response.result.empty? - empty_response(http, folder) - else - response.map { |json_files| storage_files(json_files) } - end + if result.result.empty? + empty_response(user, folder) + else + result.map { |json_files| storage_files(json_files) } end end @@ -100,11 +103,17 @@ def storage_file(json_file) ) end - def empty_response(http, folder) - response = http.get(Util.join_uri_path(@uri, location_uri_path_for(folder) + FIELDS)) - handle_response(response, :id).map do |parent_location_id| - empty_storage_files(folder.path, parent_location_id) + def empty_response(user, folder) + result = Util.using_user_token(@storage, user) do |token| + response = OpenProject.httpx.get( + Util.join_uri_path(@uri, location_uri_path_for(folder) + FIELDS), + headers: { 'Authorization' => "Bearer #{token.access_token}" } + ) + + handle_response(response, :id) end + + result.map { |parent_location_id| empty_storage_files(folder.path, parent_location_id) } end def empty_storage_files(path, parent_id) @@ -112,7 +121,7 @@ def empty_storage_files(path, parent_id) [], StorageFile.new( id: parent_id, - name: path.split("/").last, + name: path.split('/').last, location: path, permissions: %i[readable writeable] ), @@ -121,7 +130,7 @@ def empty_storage_files(path, parent_id) end def parent(parent_reference) - _, _, name = parent_reference[:path].gsub(/.*root:/, "").rpartition "/" + _, _, name = parent_reference[:path].gsub(/.*root:/, '').rpartition '/' if name.empty? root(parent_reference[:id]) @@ -136,10 +145,10 @@ def parent(parent_reference) end def forge_ancestors(parent_reference) - path_elements = parent_reference[:path].gsub(/.+root:/, "").split("/") + path_elements = parent_reference[:path].gsub(/.+root:/, '').split('/') path_elements[0..-2].map do |component| - next root(Digest::SHA256.hexdigest("i_am_root")) if component.blank? + next root(Digest::SHA256.hexdigest('i_am_root')) if component.blank? StorageFile.new( id: Digest::SHA256.hexdigest(component), @@ -169,7 +178,7 @@ def location_uri_path_for(folder) end def encode_path(path) - path.split("/").map { |fragment| URI.encode_uri_component(fragment) }.join("/") + path.split('/').map { |fragment| URI.encode_uri_component(fragment) }.join('/') end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb b/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb index 5a38f9e8ac60..5469199df27f 100644 --- a/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb +++ b/modules/storages/app/common/storages/peripherals/storage_parent_folder_extractor.rb @@ -35,7 +35,7 @@ def initialize(path) end def root? - @path == "/" + @path == '/' end def to_s @@ -45,7 +45,7 @@ def to_s module StorageParentFolderExtractor def extract_parent_folder(params) - ParentFolder.new(params[:parent].presence || "/") + ParentFolder.new(params[:parent].presence || '/') end end end diff --git a/modules/storages/app/components/storages/admin/forms/automatically_managed_project_folders_form_component.rb b/modules/storages/app/components/storages/admin/forms/automatically_managed_project_folders_form_component.rb index d44c4d47015e..b513850f7162 100644 --- a/modules/storages/app/components/storages/admin/forms/automatically_managed_project_folders_form_component.rb +++ b/modules/storages/app/components/storages/admin/forms/automatically_managed_project_folders_form_component.rb @@ -44,7 +44,7 @@ def form_url def submit_button_options { label: submit_button_label, - data: { "storages--automatically-managed-project-folders-form-target": "submitButton" }.tap do |data_hash| + data: { 'storages--automatically-managed-project-folders-form-target': 'submitButton' }.tap do |data_hash| # For create action, break from Turbo Frame and follow full page redirect data_hash[:turbo] = false if new_record? end @@ -91,8 +91,8 @@ def provider_credentials_instructions_link render( Primer::Beta::Link.new( href: Storages::Peripherals::StorageInteraction::Nextcloud::Util.join_uri_path(storage.host, - "settings/admin/openproject"), - target: "_blank" + 'settings/admin/openproject'), + target: '_blank' ) ) { I18n.t("storages.instructions.#{storage.short_provider_type}.integration") } end diff --git a/modules/storages/app/components/storages/admin/forms/general_info_form_component.rb b/modules/storages/app/components/storages/admin/forms/general_info_form_component.rb index e2799ad58107..0c483823c2e6 100644 --- a/modules/storages/app/components/storages/admin/forms/general_info_form_component.rb +++ b/modules/storages/app/components/storages/admin/forms/general_info_form_component.rb @@ -49,7 +49,7 @@ def cancel_button_options data: { turbo_stream: true } }.tap do |options_hash| if storage.new_record? options_hash[:data][:turbo_stream] = false - options_hash[:target] = "_top" # Break out of Turbo Frame, follow full page redirect + options_hash[:target] = '_top' # Break out of Turbo Frame, follow full page redirect end end end @@ -92,15 +92,15 @@ def caption_for_provider_type(provider_type) def information_for_one_drive_automatic_management href = ::OpenProject::Static::Links[:storage_docs][:one_drive_drive_id_guide][:href] I18n.t( - "storages.page_titles.managed_project_folders.one_drive_information", - drive_id_link_text: render(Primer::Beta::Link.new(href:, target: "_blank")) do - I18n.t("storages.instructions.one_drive.documentation_link_text") + 'storages.page_titles.managed_project_folders.one_drive_information', + drive_id_link_text: render(Primer::Beta::Link.new(href:, target: '_blank')) do + I18n.t('storages.instructions.one_drive.documentation_link_text') end ).html_safe end def application_link_text_for(href, link_text) - render(Primer::Beta::Link.new(href:, target: "_blank")) { link_text } + render(Primer::Beta::Link.new(href:, target: '_blank')) { link_text } end end end diff --git a/modules/storages/app/components/storages/admin/forms/oauth_client_form_component.rb b/modules/storages/app/components/storages/admin/forms/oauth_client_form_component.rb index 39da667990e3..52c4dc0c293e 100644 --- a/modules/storages/app/components/storages/admin/forms/oauth_client_form_component.rb +++ b/modules/storages/app/components/storages/admin/forms/oauth_client_form_component.rb @@ -55,15 +55,15 @@ def storage_provider_credentials_instructions private - def one_drive_integration_link(target: "_blank") + def one_drive_integration_link(target: '_blank') href = ::OpenProject::Static::Links[:storage_docs][:one_drive_oauth_application][:href] - render(Primer::Beta::Link.new(href:, target:)) { I18n.t("storages.instructions.one_drive.application_link_text") } + render(Primer::Beta::Link.new(href:, target:)) { I18n.t('storages.instructions.one_drive.application_link_text') } end - def nextcloud_integration_link(target: "_blank") + def nextcloud_integration_link(target: '_blank') href = Storages::Peripherals::StorageInteraction::Nextcloud::Util - .join_uri_path(storage.host, "settings/admin/openproject") - render(Primer::Beta::Link.new(href:, target:)) { I18n.t("storages.instructions.nextcloud.integration") } + .join_uri_path(storage.host, 'settings/admin/openproject') + render(Primer::Beta::Link.new(href:, target:)) { I18n.t('storages.instructions.nextcloud.integration') } end def first_time_configuration? diff --git a/modules/storages/app/components/storages/admin/health_status_component.rb b/modules/storages/app/components/storages/admin/health_status_component.rb index 0c2c31d041b5..0df9492fb92e 100644 --- a/modules/storages/app/components/storages/admin/health_status_component.rb +++ b/modules/storages/app/components/storages/admin/health_status_component.rb @@ -36,7 +36,7 @@ class HealthStatusComponent < ApplicationComponent # formatted manner. e.g. "Not found: Outbound request destination not found since 12/07/2023 03:45 PM" def formatted_health_reason "#{storage.health_reason_identifier.tr('_', ' ').strip.capitalize}: #{storage.health_reason_description} " + - I18n.t("storages.health.since", datetime: helpers.format_time(storage.health_changed_at)) + I18n.t('storages.health.since', datetime: helpers.format_time(storage.health_changed_at)) end end end diff --git a/modules/storages/app/components/storages/admin/oauth_access_grant_nudge_modal_component.rb b/modules/storages/app/components/storages/admin/oauth_access_grant_nudge_modal_component.rb index cfbd3ff4d80c..f52353c04da5 100644 --- a/modules/storages/app/components/storages/admin/oauth_access_grant_nudge_modal_component.rb +++ b/modules/storages/app/components/storages/admin/oauth_access_grant_nudge_modal_component.rb @@ -30,8 +30,8 @@ # module Storages::Admin class OAuthAccessGrantNudgeModalComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent - options dialog_id: "storages--oauth-grant-nudge-modal-component", - dialog_body_id: "storages--oauth-grant-nudge-modal-body-component", + options dialog_id: 'storages--oauth-grant-nudge-modal-component', + dialog_body_id: 'storages--oauth-grant-nudge-modal-body-component', authorized: false attr_reader :project_storage @@ -48,41 +48,41 @@ def render? private def confirm_button_text - I18n.t("storages.oauth_grant_nudge_modal.confirm_button_label") + I18n.t('storages.oauth_grant_nudge_modal.confirm_button_label') end def title if authorized - I18n.t("storages.oauth_grant_nudge_modal.access_granted_screen_reader", storage: project_storage.storage.name) + I18n.t('storages.oauth_grant_nudge_modal.access_granted_screen_reader', storage: project_storage.storage.name) else - I18n.t("storages.oauth_grant_nudge_modal.title") + I18n.t('storages.oauth_grant_nudge_modal.title') end end def waiting_title - I18n.t("storages.oauth_grant_nudge_modal.requesting_access_to", storage: project_storage.storage.name) + I18n.t('storages.oauth_grant_nudge_modal.requesting_access_to', storage: project_storage.storage.name) end def cancel_button_text if authorized - I18n.t("button_close") + I18n.t('button_close') else - I18n.t("storages.oauth_grant_nudge_modal.cancel_button_label") + I18n.t('storages.oauth_grant_nudge_modal.cancel_button_label') end end def body_text if authorized - success_title = I18n.t("storages.oauth_grant_nudge_modal.access_granted") - success_subtitle = I18n.t("storages.oauth_grant_nudge_modal.storage_ready", storage: project_storage.storage.name) + success_title = I18n.t('storages.oauth_grant_nudge_modal.access_granted') + success_subtitle = I18n.t('storages.oauth_grant_nudge_modal.storage_ready', storage: project_storage.storage.name) concat(render(Storages::OpenProjectStorageModalComponent::Body.new(:success, success_subtitle:, success_title:))) else - I18n.t("storages.oauth_grant_nudge_modal.body", storage: project_storage.storage.name) + I18n.t('storages.oauth_grant_nudge_modal.body', storage: project_storage.storage.name) end end def confirm_button_aria_label - I18n.t("storages.oauth_grant_nudge_modal.confirm_button_aria_label", storage: project_storage.storage.name) + I18n.t('storages.oauth_grant_nudge_modal.confirm_button_aria_label', storage: project_storage.storage.name) end def confirm_button_url diff --git a/modules/storages/app/components/storages/admin/oauth_application_info_copy_component.rb b/modules/storages/app/components/storages/admin/oauth_application_info_copy_component.rb index ca7390e835be..d5e9fe7e6c07 100644 --- a/modules/storages/app/components/storages/admin/oauth_application_info_copy_component.rb +++ b/modules/storages/app/components/storages/admin/oauth_application_info_copy_component.rb @@ -44,10 +44,10 @@ def oauth_application_details_link render( Primer::Beta::Link.new( href: Storages::Peripherals::StorageInteraction::Nextcloud::Util.join_uri_path(storage.host, - "settings/admin/openproject"), - target: "_blank" + 'settings/admin/openproject'), + target: '_blank' ) - ) { I18n.t("storages.instructions.oauth_application_details_link_text") } + ) { I18n.t('storages.instructions.oauth_application_details_link_text') } end def submit_button_options diff --git a/modules/storages/app/components/storages/admin/oauth_client_info_component.rb b/modules/storages/app/components/storages/admin/oauth_client_info_component.rb index 0fe220a80a67..1db9fb9af2a6 100644 --- a/modules/storages/app/components/storages/admin/oauth_client_info_component.rb +++ b/modules/storages/app/components/storages/admin/oauth_client_info_component.rb @@ -52,7 +52,7 @@ def edit_icon_button_options scheme: :invisible, aria: { label: }, data: edit_icon_button_data_options, - test_selector: "storage-edit-oauth-client-button" + test_selector: 'storage-edit-oauth-client-button' } end @@ -62,7 +62,7 @@ def edit_icon_button_data_options {}.tap do |data_h| if oauth_client_configured? provider_type = I18n.t("storages.provider_types.#{storage.short_provider_type}.name") - data_h[:confirm] = I18n.t("storages.confirm_replace_oauth_client", provider_type:) + data_h[:confirm] = I18n.t('storages.confirm_replace_oauth_client', provider_type:) end data_h[:turbo_stream] = true end diff --git a/modules/storages/app/components/storages/admin/redirect_uri_component.rb b/modules/storages/app/components/storages/admin/redirect_uri_component.rb index 48c0f5777ec9..6f5d5f5dbd53 100644 --- a/modules/storages/app/components/storages/admin/redirect_uri_component.rb +++ b/modules/storages/app/components/storages/admin/redirect_uri_component.rb @@ -48,7 +48,7 @@ def show_icon_button_options href: url_helpers.show_redirect_uri_admin_settings_storage_oauth_client_path(storage), scheme: :invisible, aria: { label: I18n.t("storages.label_show_storage_redirect_uri") }, - test_selector: "storage-show-redirect-uri-button" + test_selector: 'storage-show-redirect-uri-button' } end end diff --git a/modules/storages/app/components/storages/admin/row_component.rb b/modules/storages/app/components/storages/admin/row_component.rb index 29b8bd83e4d2..bba7d8ecd875 100644 --- a/modules/storages/app/components/storages/admin/row_component.rb +++ b/modules/storages/app/components/storages/admin/row_component.rb @@ -48,10 +48,10 @@ def name if configured? storage.name else - render(Primer::Beta::Octicon.new(:"alert-fill", size: :small, color: :severe)) + + render(Primer::Beta::Octicon.new(:'alert-fill', size: :small, color: :severe)) + content_tag(:span, storage.name, - class: "pl-2") + class: 'pl-2') end end @@ -65,18 +65,18 @@ def button_links end def delete_link - link_to "", + link_to '', admin_settings_storage_path(storage), - class: "icon icon-delete", - data: { confirm: I18n.t("storages.delete_warning.storage") }, + class: 'icon icon-delete', + data: { confirm: I18n.t('storages.delete_warning.storage') }, title: I18n.t(:button_delete), method: :delete end def edit_link - link_to "", + link_to '', edit_admin_settings_storage_path(storage), - class: "icon icon-edit", + class: 'icon icon-edit', accesskey: helpers.accesskey(:edit), title: I18n.t(:button_edit) end diff --git a/modules/storages/app/components/storages/admin/storage_view_information.rb b/modules/storages/app/components/storages/admin/storage_view_information.rb index 880c5a064240..c971ff0f34ab 100644 --- a/modules/storages/app/components/storages/admin/storage_view_information.rb +++ b/modules/storages/app/components/storages/admin/storage_view_information.rb @@ -11,7 +11,7 @@ def editable_storage? def storage_description [I18n.t("storages.provider_types.#{storage.short_provider_type}.name"), storage.name, - storage.host].compact.join(" - ") + storage.host].compact.join(' - ') end def configuration_check_label @@ -27,9 +27,9 @@ def configuration_check_label_for(*configs) return if storage.configuration_checks.values.none? if storage.configuration_checks.slice(*configs.map(&:to_sym)).values.all? - status_label(I18n.t("storages.label_completed"), scheme: :success, test_selector: "label-#{configs.join('-')}-status") + status_label(I18n.t('storages.label_completed'), scheme: :success, test_selector: "label-#{configs.join('-')}-status") else - status_label(I18n.t("storages.label_incomplete"), scheme: :attention, test_selector: "label-#{configs.join('-')}-status") + status_label(I18n.t('storages.label_incomplete'), scheme: :attention, test_selector: "label-#{configs.join('-')}-status") end end @@ -41,14 +41,14 @@ def automatically_managed_project_folders_status_label # do not show the status label, if storage is completely empty (initial state) return if storage.configuration_checks.values.none? - test_selector = "label-managed-project-folders-status" + test_selector = 'label-managed-project-folders-status' if storage.automatic_management_enabled? - status_label(I18n.t("storages.label_active"), scheme: :success, test_selector:) + status_label(I18n.t('storages.label_active'), scheme: :success, test_selector:) elsif storage.automatic_management_unspecified? - status_label(I18n.t("storages.label_incomplete"), scheme: :attention, test_selector:) + status_label(I18n.t('storages.label_incomplete'), scheme: :attention, test_selector:) else - status_label(I18n.t("storages.label_inactive"), scheme: :secondary, test_selector:) + status_label(I18n.t('storages.label_inactive'), scheme: :secondary, test_selector:) end end diff --git a/modules/storages/app/components/storages/admin/table_component.rb b/modules/storages/app/components/storages/admin/table_component.rb index dd845d427629..ff17ecd5f74b 100644 --- a/modules/storages/app/components/storages/admin/table_component.rb +++ b/modules/storages/app/components/storages/admin/table_component.rb @@ -52,25 +52,25 @@ def sortable? # Purpose: return the link to be used to create the storage def inline_create_link link_to(new_admin_settings_storage_path, - class: "wp-inline-create--add-link", - title: I18n.t("storages.label_new_storage")) do - helpers.op_icon("icon icon-add") + class: 'wp-inline-create--add-link', + title: I18n.t('storages.label_new_storage')) do + helpers.op_icon('icon icon-add') end end # Show this pretty message if there are now Storages::Storage objects in the system def empty_row_message - I18n.t "storages.no_results" + I18n.t 'storages.no_results' end # Definition of the table header using the keys from columns above. def headers [ - ["name", { caption: ::Storages::Storage.human_attribute_name(:name) }], - ["provider_type", { caption: I18n.t("storages.provider_types.label") }], - ["host", { caption: I18n.t("storages.label_host") }], - ["creator", { caption: I18n.t("storages.label_creator") }], - ["created_at", { caption: ::Storages::Storage.human_attribute_name(:created_at) }] + ['name', { caption: ::Storages::Storage.human_attribute_name(:name) }], + ['provider_type', { caption: I18n.t('storages.provider_types.label') }], + ['host', { caption: I18n.t('storages.label_host') }], + ['creator', { caption: I18n.t('storages.label_creator') }], + ['created_at', { caption: ::Storages::Storage.human_attribute_name(:created_at) }] ] end end diff --git a/modules/storages/app/components/storages/open_project_storage_modal_component.rb b/modules/storages/app/components/storages/open_project_storage_modal_component.rb index 6a7c740c7c2d..802f120ef4c1 100644 --- a/modules/storages/app/components/storages/open_project_storage_modal_component.rb +++ b/modules/storages/app/components/storages/open_project_storage_modal_component.rb @@ -27,10 +27,10 @@ class Storages::OpenProjectStorageModalComponent < ViewComponent::Base def initialize(project_storage_open_url:, redirect_url:, state:, **options) super - controller = "storages--open-project-storage-modal" + controller = 'storages--open-project-storage-modal' @data = { controller:, - "application-target": "dynamic", + 'application-target': 'dynamic', "#{controller}-project-storage-open-url-value": project_storage_open_url, "#{controller}-redirect-url-value": redirect_url } @@ -38,10 +38,10 @@ def initialize(project_storage_open_url:, redirect_url:, state:, **options) end def self.dialog_id - "open-project-storage-modal-component" + 'open-project-storage-modal-component' end def self.dialog_body_id - "open-project-storage-modal-body-component" + 'open-project-storage-modal-body-component' end end diff --git a/modules/storages/app/components/storages/open_project_storage_modal_component/body.rb b/modules/storages/app/components/storages/open_project_storage_modal_component/body.rb index 0b856713f408..007277da7c3f 100644 --- a/modules/storages/app/components/storages/open_project_storage_modal_component/body.rb +++ b/modules/storages/app/components/storages/open_project_storage_modal_component/body.rb @@ -25,10 +25,10 @@ #++ class Storages::OpenProjectStorageModalComponent::Body < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent - options success_title: I18n.t("storages.open_project_storage_modal.success.title"), - success_subtitle: I18n.t("storages.open_project_storage_modal.success.subtitle"), - waiting_title: I18n.t("storages.open_project_storage_modal.waiting.title"), - waiting_subtitle: I18n.t("storages.open_project_storage_modal.waiting.subtitle") + options success_title: I18n.t('storages.open_project_storage_modal.success.title'), + success_subtitle: I18n.t('storages.open_project_storage_modal.success.subtitle'), + waiting_title: I18n.t('storages.open_project_storage_modal.waiting.title'), + waiting_subtitle: I18n.t('storages.open_project_storage_modal.waiting.subtitle') def initialize(state, **options) @state = state diff --git a/modules/storages/app/components/storages/project_storages/members/row_component.rb b/modules/storages/app/components/storages/project_storages/members/row_component.rb index 62196a7274eb..4b7587a5a460 100644 --- a/modules/storages/app/components/storages/project_storages/members/row_component.rb +++ b/modules/storages/app/components/storages/project_storages/members/row_component.rb @@ -57,12 +57,12 @@ def status oauth_client_id: storage.oauth_client.client_id, storage_id: storage.id ) - helpers.op_icon("icon-warning -warning") + + helpers.op_icon('icon-warning -warning') + content_tag( :span, I18n.t("storages.member_connection_status.not_connected", link: link_to(I18n.t("link"), ensure_connection_url), - class: "pl-2").html_safe + class: 'pl-2').html_safe ) else I18n.t("storages.member_connection_status.#{connection_result}") diff --git a/modules/storages/app/components/storages/project_storages/members/table_component.rb b/modules/storages/app/components/storages/project_storages/members/table_component.rb index 216ed20ad323..12cec49d6c20 100644 --- a/modules/storages/app/components/storages/project_storages/members/table_component.rb +++ b/modules/storages/app/components/storages/project_storages/members/table_component.rb @@ -48,13 +48,13 @@ def sortable? end def empty_row_message - I18n.t "storages.members_no_results" + I18n.t 'storages.members_no_results' end def headers [ - ["name", { caption: I18n.t("storages.label_name") }], - ["status", { caption: I18n.t("storages.label_status") }] + ['name', { caption: I18n.t('storages.label_name') }], + ['status', { caption: I18n.t('storages.label_status') }] ] end end diff --git a/modules/storages/app/components/storages/project_storages/row_component.rb b/modules/storages/app/components/storages/project_storages/row_component.rb index a7e897ce79c8..cc52af6c0022 100644 --- a/modules/storages/app/components/storages/project_storages/row_component.rb +++ b/modules/storages/app/components/storages/project_storages/row_component.rb @@ -57,24 +57,24 @@ def button_links end def members_connection_status_link - link_to "", + link_to '', project_settings_project_storage_members_path(project_id: project_storage.project, project_storage_id: project_storage), - class: "icon icon-group", - title: I18n.t(:"storages.page_titles.project_settings.members_connection_status") + class: 'icon icon-group', + title: I18n.t(:'storages.page_titles.project_settings.members_connection_status') end def edit_link - link_to "", + link_to '', edit_project_settings_project_storage_path(project_id: project_storage.project, id: project_storage), - class: "icon icon-edit", + class: 'icon icon-edit', title: I18n.t(:button_edit) end def delete_link - link_to "", + link_to '', confirm_destroy_project_settings_project_storage_path(project_id: project_storage.project, id: project_storage), - class: "icon icon-delete", + class: 'icon icon-delete', title: I18n.t(:button_delete), method: :get end diff --git a/modules/storages/app/components/storages/project_storages/table_component.rb b/modules/storages/app/components/storages/project_storages/table_component.rb index 2af55d240329..bfc3fdf342f0 100644 --- a/modules/storages/app/components/storages/project_storages/table_component.rb +++ b/modules/storages/app/components/storages/project_storages/table_component.rb @@ -48,22 +48,22 @@ def sortable? def inline_create_link link_to(new_project_settings_project_storage_path, - class: "wp-inline-create--add-link", - title: I18n.t("storages.label_new_storage")) do - helpers.op_icon("icon icon-add") + class: 'wp-inline-create--add-link', + title: I18n.t('storages.label_new_storage')) do + helpers.op_icon('icon icon-add') end end def empty_row_message - I18n.t "storages.no_results" + I18n.t 'storages.no_results' end def headers [ - ["name", { caption: ::Storages::Storage.human_attribute_name(:name) }], - ["provider_type", { caption: I18n.t("storages.provider_types.label") }], - ["creator", { caption: I18n.t("storages.label_creator") }], - ["created_at", { caption: ::Storages::ProjectStorage.human_attribute_name(:created_at) }] + ['name', { caption: ::Storages::Storage.human_attribute_name(:name) }], + ['provider_type', { caption: I18n.t('storages.provider_types.label') }], + ['creator', { caption: I18n.t('storages.label_creator') }], + ['created_at', { caption: ::Storages::ProjectStorage.human_attribute_name(:created_at) }] ] end end diff --git a/modules/storages/app/constants/storages/admin.rb b/modules/storages/app/constants/storages/admin.rb index a155896ede2f..28785d3c3a21 100644 --- a/modules/storages/app/constants/storages/admin.rb +++ b/modules/storages/app/constants/storages/admin.rb @@ -30,10 +30,10 @@ module Storages module Admin - LABEL_OAUTH_CLIENT_ID = "OAuth Client ID" - LABEL_OAUTH_CLIENT_SECRET = "OAuth Client Secret" - LABEL_OAUTH_REDIRECT_URI = "OAuth Redirect URI" - LABEL_TENANT_ID = "Tenant ID" - LABEL_DRIVE_ID = "Drive ID" + LABEL_OAUTH_CLIENT_ID = 'OAuth Client ID' + LABEL_OAUTH_CLIENT_SECRET = 'OAuth Client Secret' + LABEL_OAUTH_REDIRECT_URI = 'OAuth Redirect URI' + LABEL_TENANT_ID = 'Tenant ID' + LABEL_DRIVE_ID = 'Drive ID' end end diff --git a/modules/storages/app/contracts/storages/file_links/create_contract.rb b/modules/storages/app/contracts/storages/file_links/create_contract.rb index e58444430475..153ea0148aa8 100644 --- a/modules/storages/app/contracts/storages/file_links/create_contract.rb +++ b/modules/storages/app/contracts/storages/file_links/create_contract.rb @@ -85,7 +85,7 @@ def validate_project_storage_link def require_ee_token_for_one_drive if model.storage && ::Storages::Storage.one_drive_without_ee_token?(model.storage.provider_type) - errors.add(:base, I18n.t("api_v3.errors.code_500_missing_enterprise_token")) + errors.add(:base, I18n.t('api_v3.errors.code_500_missing_enterprise_token')) end end end diff --git a/modules/storages/app/contracts/storages/storages/base_contract.rb b/modules/storages/app/contracts/storages/storages/base_contract.rb index 96508041aed9..a880f005c37b 100644 --- a/modules/storages/app/contracts/storages/storages/base_contract.rb +++ b/modules/storages/app/contracts/storages/storages/base_contract.rb @@ -28,8 +28,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "net/http" -require "uri" +require 'net/http' +require 'uri' # Purpose: common functionalities shared by CreateContract and UpdateContract # UpdateService by default checks if UpdateContract exists @@ -70,7 +70,7 @@ def provider_type_strategy def require_ee_token_for_one_drive if ::Storages::Storage.one_drive_without_ee_token?(provider_type) - errors.add(:base, I18n.t("api_v3.errors.code_500_missing_enterprise_token")) + errors.add(:base, I18n.t('api_v3.errors.code_500_missing_enterprise_token')) end end end diff --git a/modules/storages/app/contracts/storages/storages/nextcloud_contract.rb b/modules/storages/app/contracts/storages/storages/nextcloud_contract.rb index 304ddcbfcc56..feca633ea9de 100644 --- a/modules/storages/app/contracts/storages/storages/nextcloud_contract.rb +++ b/modules/storages/app/contracts/storages/storages/nextcloud_contract.rb @@ -31,7 +31,7 @@ module Storages::Storages class NextcloudContract < ::ModelContract attribute :host - validates :host, url: { message: I18n.t("activerecord.errors.messages.invalid_url") }, length: { maximum: 255 } + validates :host, url: { message: I18n.t('activerecord.errors.messages.invalid_url') }, length: { maximum: 255 } # Check that a host actually is a storage server. # But only do so if the validations above for URL were successful. validates :host, secure_context_uri: true, nextcloud_compatible_host: true, unless: -> { errors.include?(:host) } diff --git a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb index 34fedfb06b74..5fe20d91ec2c 100644 --- a/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb +++ b/modules/storages/app/controllers/storages/admin/automatically_managed_project_folders_controller.rb @@ -33,7 +33,7 @@ # class Storages::Admin::AutomaticallyManagedProjectFoldersController < ApplicationController # See https://guides.rubyonrails.org/layouts_and_rendering.html for reference on layout - layout "admin" + layout 'admin' # Before executing any action below: Make sure the current user is an admin # and set the @ variable to the object referenced in the URL. @@ -65,7 +65,7 @@ def new .result respond_to do |format| - format.html { render "/storages/admin/storages/automatically_managed_project_folders/edit" } + format.html { render '/storages/admin/storages/automatically_managed_project_folders/edit' } format.turbo_stream { render :edit } end end @@ -75,13 +75,13 @@ def create if service_result.success? flash[:primer_banner] = { - message: I18n.t(:"storages.notice_successful_storage_connection"), + message: I18n.t(:'storages.notice_successful_storage_connection'), scheme: :success } redirect_to admin_settings_storages_path else respond_to do |format| - format.html { render "/storages/admin/storages/automatically_managed_project_folders/edit" } + format.html { render '/storages/admin/storages/automatically_managed_project_folders/edit' } format.turbo_stream end end @@ -92,7 +92,7 @@ def create # Called by: Global app/config/routes.rb to serve Web page def edit respond_to do |format| - format.html { render "/storages/admin/storages/automatically_managed_project_folders/edit" } + format.html { render '/storages/admin/storages/automatically_managed_project_folders/edit' } format.turbo_stream end end @@ -106,7 +106,7 @@ def update if service_result.success? redirect_to edit_admin_settings_storage_path(@storage) else - render "/storages/admin/storages/automatically_managed_project_folders/edit" + render '/storages/admin/storages/automatically_managed_project_folders/edit' end end @@ -144,7 +144,7 @@ def permitted_storage_params_with_defaults permitted_storage_params.tap do |permitted_params| # If a checkbox is unchecked when its form is submitted, neither the name nor the value is submitted to the server. # See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/checkbox - permitted_params.merge!(automatic_management_enabled: false) unless permitted_params.key?("automatic_management_enabled") + permitted_params.merge!(automatic_management_enabled: false) unless permitted_params.key?('automatic_management_enabled') end end @@ -153,6 +153,6 @@ def permitted_storage_params_with_defaults def permitted_storage_params params .require(:storages_nextcloud_storage) - .permit("automatic_management_enabled", "password") + .permit('automatic_management_enabled', 'password') end end diff --git a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb index a1a5667c80ff..f7d1f35c11a5 100644 --- a/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb +++ b/modules/storages/app/controllers/storages/admin/oauth_clients_controller.rb @@ -30,7 +30,7 @@ class Storages::Admin::OAuthClientsController < ApplicationController # See https://guides.rubyonrails.org/layouts_and_rendering.html for reference on layout - layout "admin" + layout 'admin' # Before executing any action below: Make sure the current user is an admin # and set the @ variable to the object referenced in the URL. @@ -116,7 +116,7 @@ def show_redirect_uri end def finish_setup - flash[:primer_banner] = { message: I18n.t(:"storages.notice_successful_storage_connection"), scheme: :success } + flash[:primer_banner] = { message: I18n.t(:'storages.notice_successful_storage_connection'), scheme: :success } redirect_to admin_settings_storages_path end @@ -147,7 +147,7 @@ def prepare_storage_for_automatic_management_form def oauth_client_params params .require(:oauth_client) - .permit("client_id", "client_secret") + .permit('client_id', 'client_secret') end def find_storage diff --git a/modules/storages/app/controllers/storages/admin/project_storages_controller.rb b/modules/storages/app/controllers/storages/admin/project_storages_controller.rb index 60dbbfe08419..ebab6e43cfac 100644 --- a/modules/storages/app/controllers/storages/admin/project_storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/project_storages_controller.rb @@ -55,25 +55,25 @@ def index @project_storages = Storages::ProjectStorage.where(project: @project).includes(:storage) # Render the list storages using ViewComponents in the /app/components folder which defines # the ways rows are rendered in a table layout. - render "/storages/project_settings/index" + render '/storages/project_settings/index' end # Show a HTML page with a form in order to create a new ProjectStorage # Called by: When a user clicks on the "+New" button in Project -> Settings -> File Storages def new @available_storages = available_storages - project_folder_mode = Storages::ProjectStorage.project_folder_modes.values.find do |mode| - mode == params.dig(:storages_project_storage, :project_folder_mode) - end - storage = @available_storages.find { |s| s.id.to_s == params.dig(:storages_project_storage, :storage_id) } - @project_storage = - ::Storages::ProjectStorages::SetAttributesService - .new(user: current_user, model: Storages::ProjectStorage.new, contract_class: EmptyContract) - .call(project: @project, storage:, project_folder_mode:) - .result + @project_storage = ::Storages::ProjectStorages::SetAttributesService + .new(user: current_user, + model: Storages::ProjectStorage.new, + contract_class: EmptyContract) + .call(project: @project, + storage: @available_storages.find do |storage| + storage.id.to_s == params.dig(:storages_project_storage, :storage_id) + end) + .result @last_project_folders = {} - render template: "/storages/project_settings/new" + render template: '/storages/project_settings/new' end # Create a new ProjectStorage object. @@ -89,7 +89,7 @@ def create redirect_to_project_storages_path_with_oauth_access_grant_confirmation else @available_storages = available_storages - render "/storages/project_settings/new" + render '/storages/project_settings/new' end end @@ -128,7 +128,7 @@ def edit .pluck(:mode, :origin_folder_id) .to_h - render "/storages/project_settings/edit" + render '/storages/project_settings/edit' end # Update is similar to create above @@ -145,7 +145,7 @@ def update redirect_to project_settings_project_storages_path else @project_storage = @object - render "/storages/project_settings/edit" + render '/storages/project_settings/edit' end end @@ -167,7 +167,7 @@ def destroy def destroy_info @project_storage_to_destroy = @object - render "/storages/project_settings/destroy_info" + render '/storages/project_settings/destroy_info' end private @@ -178,7 +178,7 @@ def permitted_storage_settings_params # "params" is an instance of ActionController::Parameters params .require(:storages_project_storage) - .permit("storage_id", "project_folder_mode", "project_folder_id") + .permit('storage_id', 'project_folder_mode', 'project_folder_id') .to_h .reverse_merge(project_id: @project.id) end @@ -212,7 +212,7 @@ def redirect_to_project_storages_path_with_nudge_modal def oauth_access_grant_nudge_modal(authorized: false) { - type: "Storages::Admin::OAuthAccessGrantNudgeModalComponent", + type: 'Storages::Admin::OAuthAccessGrantNudgeModalComponent', parameters: { project_storage: @project_storage.id, authorized: diff --git a/modules/storages/app/controllers/storages/admin/storages_controller.rb b/modules/storages/app/controllers/storages/admin/storages_controller.rb index 7491bd2c6bd7..5359107e29fb 100644 --- a/modules/storages/app/controllers/storages/admin/storages_controller.rb +++ b/modules/storages/app/controllers/storages/admin/storages_controller.rb @@ -34,7 +34,7 @@ class Storages::Admin::StoragesController < ApplicationController include FlashMessagesHelper # See https://guides.rubyonrails.org/layouts_and_rendering.html for reference on layout - layout "admin" + layout 'admin' # specify which model #find_model_object should look up model_object Storages::Storage @@ -198,7 +198,7 @@ def replace_oauth_application # Breadcrumbs is something like OpenProject > Admin > Storages. # This returns the name of the last part (Storages admin page) def default_breadcrumb - if action_name == "index" + if action_name == 'index' t(:project_module_storages) else ActionController::Base.helpers.link_to(t(:project_module_storages), admin_settings_storages_path) @@ -216,7 +216,7 @@ def show_local_breadcrumb def ensure_valid_provider_type_selected short_provider_type = params[:provider] if short_provider_type.blank? || (@provider_type = ::Storages::Storage::PROVIDER_TYPE_SHORT_NAMES[short_provider_type]).blank? - flash[:primer_banner] = { message: I18n.t("storages.error_invalid_provider_type"), scheme: :danger } + flash[:primer_banner] = { message: I18n.t('storages.error_invalid_provider_type'), scheme: :danger } redirect_to admin_settings_storages_path end end @@ -230,14 +230,14 @@ def oauth_application(service_result) def permitted_storage_params(model_parameter_name = storage_provider_parameter_name) params .require(model_parameter_name) - .permit("name", - "provider_type", - "host", - "oauth_client_id", - "oauth_client_secret", - "tenant_id", - "drive_id", - "automatic_management_enabled") + .permit('name', + 'provider_type', + 'host', + 'oauth_client_id', + 'oauth_client_secret', + 'tenant_id', + 'drive_id', + 'automatic_management_enabled') end def storage_provider_parameter_name diff --git a/modules/storages/app/controllers/storages/project_settings/project_storage_members_controller.rb b/modules/storages/app/controllers/storages/project_settings/project_storage_members_controller.rb index f5f7de107e66..730279e39add 100644 --- a/modules/storages/app/controllers/storages/project_settings/project_storage_members_controller.rb +++ b/modules/storages/app/controllers/storages/project_settings/project_storage_members_controller.rb @@ -44,11 +44,11 @@ def index .includes(:principal, :oauth_client_tokens, roles: :role_permissions) .paginate(page: page_param, per_page: per_page_param) - render "/storages/project_settings/project_storage_members/index" + render '/storages/project_settings/project_storage_members/index' end def default_breadcrumb - t(:"storages.page_titles.project_settings.members_connection_status") + t(:'storages.page_titles.project_settings.members_connection_status') end def show_local_breadcrumb diff --git a/modules/storages/app/controllers/storages/project_storages_controller.rb b/modules/storages/app/controllers/storages/project_storages_controller.rb index f210a5c28549..ade361d55ebb 100644 --- a/modules/storages/app/controllers/storages/project_storages_controller.rb +++ b/modules/storages/app/controllers/storages/project_storages_controller.rb @@ -110,7 +110,7 @@ def redirect_to_project_overview_with_modal project_overview_path(project_id: @project.identifier), flash: { modal: { - type: "Storages::OpenProjectStorageModalComponent", + type: 'Storages::OpenProjectStorageModalComponent', parameters: { project_storage_open_url: request.path, redirect_url: api_v3_project_storage_open, diff --git a/modules/storages/app/forms/storages/admin/managed_project_folders/application_password_input.rb b/modules/storages/app/forms/storages/admin/managed_project_folders/application_password_input.rb index 2825ea15ccce..780a63cd8e5c 100644 --- a/modules/storages/app/forms/storages/admin/managed_project_folders/application_password_input.rb +++ b/modules/storages/app/forms/storages/admin/managed_project_folders/application_password_input.rb @@ -31,7 +31,7 @@ class ApplicationPasswordInput < ApplicationForm form do |application_password_form| application_password_form.text_field( name: :password, - label: I18n.t(:"storages.label_managed_project_folders.application_password"), + label: I18n.t(:'storages.label_managed_project_folders.application_password'), required: true, caption: application_password_caption, value: nil, # IMPORTANT: We don't want to show the password in the form @@ -48,7 +48,7 @@ def initialize(storage:) private def application_password_caption - I18n.t(:"storages.instructions.managed_project_folders_application_password_caption", + I18n.t(:'storages.instructions.managed_project_folders_application_password_caption', provider_type_link:).html_safe end @@ -56,8 +56,8 @@ def provider_type_link render( Primer::Beta::Link.new( href: Storages::Peripherals::StorageInteraction::Nextcloud::Util.join_uri_path(@storage.host, - "settings/admin/openproject"), - target: "_blank" + 'settings/admin/openproject'), + target: '_blank' ) ) { I18n.t("storages.instructions.#{@storage.short_provider_type}.integration") } end diff --git a/modules/storages/app/forms/storages/admin/managed_project_folders/automatic_management_checkbox.rb b/modules/storages/app/forms/storages/admin/managed_project_folders/automatic_management_checkbox.rb index ac6ff8742cf6..cfc7d0e54f38 100644 --- a/modules/storages/app/forms/storages/admin/managed_project_folders/automatic_management_checkbox.rb +++ b/modules/storages/app/forms/storages/admin/managed_project_folders/automatic_management_checkbox.rb @@ -31,11 +31,11 @@ class AutomaticManagementCheckbox < ApplicationForm form do |automatic_management_form| automatic_management_form.check_box( name: :automatic_management_enabled, - label: I18n.t(:"storages.label_managed_project_folders.automatically_managed_folders"), + label: I18n.t(:'storages.label_managed_project_folders.automatically_managed_folders'), checked: @storage.automatic_management_enabled?, required: true, data: { - action: "change->storages--automatically-managed-project-folders-form#updateDisplay" + action: 'change->storages--automatically-managed-project-folders-form#updateDisplay' } ) end diff --git a/modules/storages/app/forms/storages/admin/oauth_client_form.rb b/modules/storages/app/forms/storages/admin/oauth_client_form.rb index 3883dd6587bf..58304f42ad78 100644 --- a/modules/storages/app/forms/storages/admin/oauth_client_form.rb +++ b/modules/storages/app/forms/storages/admin/oauth_client_form.rb @@ -63,7 +63,7 @@ def default_client_secret_input_options def provider_default_client_secret_input_options {}.tap do |options_h| if @storage.provider_type_one_drive? - options_h[:caption] = I18n.t("storages.instructions.one_drive.oauth_client_secret") + options_h[:caption] = I18n.t('storages.instructions.one_drive.oauth_client_secret') end end end diff --git a/modules/storages/app/forms/storages/admin/provider_drive_id_input_form.rb b/modules/storages/app/forms/storages/admin/provider_drive_id_input_form.rb index 8ead4f90e7d3..0d53b78c5147 100644 --- a/modules/storages/app/forms/storages/admin/provider_drive_id_input_form.rb +++ b/modules/storages/app/forms/storages/admin/provider_drive_id_input_form.rb @@ -43,9 +43,9 @@ class ProviderDriveIdInputForm < ApplicationForm def caption href = ::OpenProject::Static::Links[:storage_docs][:one_drive_drive_id_guide][:href] - I18n.t("storages.instructions.one_drive.drive_id", - drive_id_link_text: render(Primer::Beta::Link.new(href:, target: "_blank")) do - I18n.t("storages.instructions.one_drive.documentation_link_text") + I18n.t('storages.instructions.one_drive.drive_id', + drive_id_link_text: render(Primer::Beta::Link.new(href:, target: '_blank')) do + I18n.t('storages.instructions.one_drive.documentation_link_text') end) end end diff --git a/modules/storages/app/forms/storages/admin/provider_host_input_form.rb b/modules/storages/app/forms/storages/admin/provider_host_input_form.rb index 43decb9dff4e..0e91e5215957 100644 --- a/modules/storages/app/forms/storages/admin/provider_host_input_form.rb +++ b/modules/storages/app/forms/storages/admin/provider_host_input_form.rb @@ -31,13 +31,13 @@ class ProviderHostInputForm < ApplicationForm form do |storage_form| storage_form.text_field( name: :host, - label: I18n.t("activerecord.attributes.storages/storage.host"), + label: I18n.t('activerecord.attributes.storages/storage.host'), visually_hide_label: false, required: true, type: :url, pattern: ".{1,255}", placeholder: "https://my-file-storage.com", - caption: I18n.t("storages.instructions.host"), + caption: I18n.t('storages.instructions.host'), input_width: :large ) end diff --git a/modules/storages/app/forms/storages/admin/provider_name_input_form.rb b/modules/storages/app/forms/storages/admin/provider_name_input_form.rb index 374d6ccf6e3b..5144ba6ad5a8 100644 --- a/modules/storages/app/forms/storages/admin/provider_name_input_form.rb +++ b/modules/storages/app/forms/storages/admin/provider_name_input_form.rb @@ -31,9 +31,9 @@ class ProviderNameInputForm < ApplicationForm form do |storage_form| storage_form.text_field( name: :name, - label: I18n.t("activerecord.attributes.storages/storage.name"), + label: I18n.t('activerecord.attributes.storages/storage.name'), required: true, - caption: I18n.t("storages.instructions.name"), + caption: I18n.t('storages.instructions.name'), placeholder: I18n.t("storages.label_file_storage"), input_width: :large ) diff --git a/modules/storages/app/forms/storages/admin/provider_tenant_id_input_form.rb b/modules/storages/app/forms/storages/admin/provider_tenant_id_input_form.rb index 8fc69ef10374..553f1536f733 100644 --- a/modules/storages/app/forms/storages/admin/provider_tenant_id_input_form.rb +++ b/modules/storages/app/forms/storages/admin/provider_tenant_id_input_form.rb @@ -31,11 +31,11 @@ class ProviderTenantIdInputForm < ApplicationForm form do |storage_form| storage_form.text_field( name: :tenant_id, - label: I18n.t("activerecord.attributes.storages/storage.tenant"), + label: I18n.t('activerecord.attributes.storages/storage.tenant'), visually_hide_label: false, required: true, caption: caption.html_safe, # rubocop:disable Rails/OutputSafety - placeholder: I18n.t("storages.instructions.one_drive.tenant_id_placeholder"), + placeholder: I18n.t('storages.instructions.one_drive.tenant_id_placeholder'), input_width: :large ) end @@ -44,9 +44,9 @@ class ProviderTenantIdInputForm < ApplicationForm def caption href = ::OpenProject::Static::Links[:storage_docs][:one_drive_oauth_application][:href] - I18n.t("storages.instructions.one_drive.tenant_id", - application_link_text: render(Primer::Beta::Link.new(href:, target: "_blank")) do - I18n.t("storages.instructions.one_drive.application_link_text") + I18n.t('storages.instructions.one_drive.tenant_id', + application_link_text: render(Primer::Beta::Link.new(href:, target: '_blank')) do + I18n.t('storages.instructions.one_drive.application_link_text') end) end end diff --git a/modules/storages/app/forms/storages/admin/provider_type_hidden_input_form.rb b/modules/storages/app/forms/storages/admin/provider_type_hidden_input_form.rb index df10652002bd..00d72f3c3b72 100644 --- a/modules/storages/app/forms/storages/admin/provider_type_hidden_input_form.rb +++ b/modules/storages/app/forms/storages/admin/provider_type_hidden_input_form.rb @@ -31,7 +31,7 @@ class ProviderTypeHiddenInputForm < ApplicationForm form do |storage_form| storage_form.hidden( name: :provider_type, - label: I18n.t("activerecord.attributes.storages/storage.provider_type"), + label: I18n.t('activerecord.attributes.storages/storage.provider_type'), required: true, value: @storage.provider_type ) diff --git a/modules/storages/app/forms/storages/admin/submit_or_cancel_form.rb b/modules/storages/app/forms/storages/admin/submit_or_cancel_form.rb index 5504347b3c3c..e6a8b227aca0 100644 --- a/modules/storages/app/forms/storages/admin/submit_or_cancel_form.rb +++ b/modules/storages/app/forms/storages/admin/submit_or_cancel_form.rb @@ -48,7 +48,7 @@ def default_submit_button_options { name: :submit, scheme: :primary, - label: I18n.t("storages.buttons.save_and_continue"), + label: I18n.t('storages.buttons.save_and_continue'), disabled: false } end @@ -58,8 +58,8 @@ def default_cancel_button_options name: :cancel, scheme: :default, tag: :a, - href: OpenProject::StaticRouting::StaticRouter.new.url_helpers.admin_settings_storages_path, - label: I18n.t("button_cancel") + href: Rails.application.routes.url_helpers.admin_settings_storages_path, + label: I18n.t('button_cancel') } end end diff --git a/modules/storages/app/models/queries/storages/file_links/filter/storage_filter.rb b/modules/storages/app/models/queries/storages/file_links/filter/storage_filter.rb index 929f8049521b..8bf46c738bb6 100644 --- a/modules/storages/app/models/queries/storages/file_links/filter/storage_filter.rb +++ b/modules/storages/app/models/queries/storages/file_links/filter/storage_filter.rb @@ -43,7 +43,7 @@ def allowed_values end def where - operator_strategy.sql_for_field(values, ::Storages::FileLink.table_name, "storage_id") + operator_strategy.sql_for_field(values, ::Storages::FileLink.table_name, 'storage_id') end end end diff --git a/modules/storages/app/models/queries/storages/project_storages/filter/storage_url_filter.rb b/modules/storages/app/models/queries/storages/project_storages/filter/storage_url_filter.rb index b381e33f22b0..cfb7d558abc2 100644 --- a/modules/storages/app/models/queries/storages/project_storages/filter/storage_url_filter.rb +++ b/modules/storages/app/models/queries/storages/project_storages/filter/storage_url_filter.rb @@ -49,13 +49,13 @@ def joins end def where - operator_strategy.sql_for_field(unescape_hosts(values), Storages::Storage.table_name, "host") + operator_strategy.sql_for_field(unescape_hosts(values), Storages::Storage.table_name, 'host') end private def unescape_hosts(hosts) - hosts.map { |host| CGI.unescape(host).gsub(/\/+$/, "") } + hosts.map { |host| CGI.unescape(host).gsub(/\/+$/, '') } end end end diff --git a/modules/storages/app/models/queries/storages/projects/filter/storage_id_filter.rb b/modules/storages/app/models/queries/storages/projects/filter/storage_id_filter.rb index 4f6b9a1ea4ee..f0ad24f67199 100644 --- a/modules/storages/app/models/queries/storages/projects/filter/storage_id_filter.rb +++ b/modules/storages/app/models/queries/storages/projects/filter/storage_id_filter.rb @@ -34,7 +34,7 @@ class StorageIdFilter < ::Queries::Projects::Filters::ProjectFilter private def filter_column - "id" + 'id' end end end diff --git a/modules/storages/app/models/queries/storages/projects/filter/storage_url_filter.rb b/modules/storages/app/models/queries/storages/projects/filter/storage_url_filter.rb index 9345b6895b81..ad5ffc066e95 100644 --- a/modules/storages/app/models/queries/storages/projects/filter/storage_url_filter.rb +++ b/modules/storages/app/models/queries/storages/projects/filter/storage_url_filter.rb @@ -34,11 +34,11 @@ class StorageUrlFilter < ::Queries::Projects::Filters::ProjectFilter private def filter_column - "host" + 'host' end def where_values - values.map { |host| CGI.unescape(host).gsub(/\/+$/, "") } + values.map { |host| CGI.unescape(host).gsub(/\/+$/, '') } end end end diff --git a/modules/storages/app/models/queries/storages/work_packages/filter/file_link_origin_id_filter.rb b/modules/storages/app/models/queries/storages/work_packages/filter/file_link_origin_id_filter.rb index d09d351b7b33..3f0162c41267 100644 --- a/modules/storages/app/models/queries/storages/work_packages/filter/file_link_origin_id_filter.rb +++ b/modules/storages/app/models/queries/storages/work_packages/filter/file_link_origin_id_filter.rb @@ -35,7 +35,7 @@ def filter_model end def filter_column - "origin_id" + 'origin_id' end def permission diff --git a/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_id_filter.rb b/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_id_filter.rb index bccc401daf6b..ca5bbcd169a6 100644 --- a/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_id_filter.rb +++ b/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_id_filter.rb @@ -35,7 +35,7 @@ def filter_model end def filter_column - "id" + 'id' end def permission diff --git a/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_url_filter.rb b/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_url_filter.rb index f2c590de89ff..0e48e89526bd 100644 --- a/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_url_filter.rb +++ b/modules/storages/app/models/queries/storages/work_packages/filter/linkable_to_storage_url_filter.rb @@ -35,7 +35,7 @@ def filter_model end def filter_column - "host" + 'host' end def permission diff --git a/modules/storages/app/models/queries/storages/work_packages/filter/storage_id_filter.rb b/modules/storages/app/models/queries/storages/work_packages/filter/storage_id_filter.rb index 5fb70bbb4503..0bd491f516bc 100644 --- a/modules/storages/app/models/queries/storages/work_packages/filter/storage_id_filter.rb +++ b/modules/storages/app/models/queries/storages/work_packages/filter/storage_id_filter.rb @@ -35,7 +35,7 @@ def filter_model end def filter_column - "storage_id" + 'storage_id' end def permission diff --git a/modules/storages/app/models/queries/storages/work_packages/filter/storage_url_filter.rb b/modules/storages/app/models/queries/storages/work_packages/filter/storage_url_filter.rb index dbdca749c340..865fecb2918f 100644 --- a/modules/storages/app/models/queries/storages/work_packages/filter/storage_url_filter.rb +++ b/modules/storages/app/models/queries/storages/work_packages/filter/storage_url_filter.rb @@ -35,7 +35,7 @@ def filter_model end def filter_column - "host" + 'host' end def permission diff --git a/modules/storages/app/models/queries/storages/work_packages/filter/storages_filter_mixin.rb b/modules/storages/app/models/queries/storages/work_packages/filter/storages_filter_mixin.rb index 0ece5f3f4107..49827f6b74f5 100644 --- a/modules/storages/app/models/queries/storages/work_packages/filter/storages_filter_mixin.rb +++ b/modules/storages/app/models/queries/storages/work_packages/filter/storages_filter_mixin.rb @@ -68,7 +68,7 @@ def where_values end def additional_where_condition - "" + '' end def joins @@ -76,6 +76,6 @@ def joins end def unescape_hosts(hosts) - hosts.map { |host| CGI.unescape(host).gsub(/\/+$/, "") } + hosts.map { |host| CGI.unescape(host).gsub(/\/+$/, '') } end end diff --git a/modules/storages/app/models/storages/file_link.rb b/modules/storages/app/models/storages/file_link.rb index caa3a54e5817..150f7eaa6d7b 100644 --- a/modules/storages/app/models/storages/file_link.rb +++ b/modules/storages/app/models/storages/file_link.rb @@ -31,7 +31,7 @@ # FileLinks are attached to a "container", which currently has to be a WorkPackage. class Storages::FileLink < ApplicationRecord belongs_to :storage - belongs_to :creator, class_name: "User" + belongs_to :creator, class_name: 'User' belongs_to :container, polymorphic: true validates :container_type, inclusion: { in: ["WorkPackage", nil] } diff --git a/modules/storages/app/models/storages/last_project_folder.rb b/modules/storages/app/models/storages/last_project_folder.rb index 8fb475940a30..613ad557caa2 100644 --- a/modules/storages/app/models/storages/last_project_folder.rb +++ b/modules/storages/app/models/storages/last_project_folder.rb @@ -27,7 +27,7 @@ #++ class Storages::LastProjectFolder < ApplicationRecord - belongs_to :project_storage, class_name: "Storages::ProjectStorage" + belongs_to :project_storage, class_name: 'Storages::ProjectStorage' - enum mode: { inactive: "inactive", manual: "manual", automatic: "automatic" }.freeze + enum mode: { inactive: 'inactive', manual: 'manual', automatic: 'automatic' }.freeze end diff --git a/modules/storages/app/models/storages/nextcloud_storage.rb b/modules/storages/app/models/storages/nextcloud_storage.rb index 6121dff82b3f..174321671979 100644 --- a/modules/storages/app/models/storages/nextcloud_storage.rb +++ b/modules/storages/app/models/storages/nextcloud_storage.rb @@ -32,7 +32,7 @@ module Storages class NextcloudStorage < Storage PROVIDER_FIELDS_DEFAULTS = { automatic_management_enabled: true, - username: "OpenProject" + username: 'OpenProject' }.freeze store_attribute :provider_fields, :automatically_managed, :boolean @@ -48,7 +48,7 @@ def oauth_configuration def automatic_management_new_record? if provider_fields_changed? previous_configuration = provider_fields_change.first - previous_configuration.values_at("automatically_managed", "password").compact.empty? + previous_configuration.values_at('automatically_managed', 'password').compact.empty? else automatic_management_unspecified? end diff --git a/modules/storages/app/models/storages/one_drive_storage.rb b/modules/storages/app/models/storages/one_drive_storage.rb index 5365da2b2914..57e2fc90f500 100644 --- a/modules/storages/app/models/storages/one_drive_storage.rb +++ b/modules/storages/app/models/storages/one_drive_storage.rb @@ -52,7 +52,7 @@ def oauth_configuration end def uri - @uri ||= URI("https://graph.microsoft.com").normalize + @uri ||= URI('https://graph.microsoft.com').normalize end def connect_src diff --git a/modules/storages/app/models/storages/project_storage.rb b/modules/storages/app/models/storages/project_storage.rb index 46ec7b7fde47..3ae6dcb71e4e 100644 --- a/modules/storages/app/models/storages/project_storage.rb +++ b/modules/storages/app/models/storages/project_storage.rb @@ -33,23 +33,23 @@ class ProjectStorage < ApplicationRecord using Peripherals::ServiceResultRefinements belongs_to :project, touch: true - belongs_to :storage, touch: true, class_name: "Storages::Storage" - belongs_to :creator, class_name: "User" + belongs_to :storage, touch: true, class_name: 'Storages::Storage' + belongs_to :creator, class_name: 'User' has_many :last_project_folders, - class_name: "Storages::LastProjectFolder", + class_name: 'Storages::LastProjectFolder', dependent: :destroy # There should be only one ProjectStorage per project and storage. validates :project, uniqueness: { scope: :storage } enum project_folder_mode: { - inactive: "inactive", - manual: "manual", - automatic: "automatic" - }.freeze, _prefix: "project_folder" + inactive: 'inactive', + manual: 'manual', + automatic: 'automatic' + }.freeze, _prefix: 'project_folder' - scope :automatic, -> { where(project_folder_mode: "automatic") } + scope :automatic, -> { where(project_folder_mode: 'automatic') } scope :active, -> { joins(:project).where(project: { active: true }) } scope :active_automatically_managed, -> do automatic @@ -92,10 +92,10 @@ def open(user) def open_with_connection_ensured return unless storage.configured? - url_helpers = OpenProject::StaticRouting::StaticRouter.new.url_helpers + url_helpers = Rails.application.routes.url_helpers open_project_storage_url = url_helpers.open_project_storage_url( host: Setting.host_name, - protocol: "https", + protocol: 'https', project_id: project.identifier, id: ) diff --git a/modules/storages/app/models/storages/storage_file_info.rb b/modules/storages/app/models/storages/storage_file_info.rb index 2e0397f24ab3..ccc1dddf772f 100644 --- a/modules/storages/app/models/storages/storage_file_info.rb +++ b/modules/storages/app/models/storages/storage_file_info.rb @@ -81,7 +81,7 @@ def initialize( end def self.from_id(file_id) - new(id: file_id, status: "OK", status_code: 200) + new(id: file_id, status: 'OK', status_code: 200) end end end diff --git a/modules/storages/app/models/storages/upload_link.rb b/modules/storages/app/models/storages/upload_link.rb index 7e27db1c4934..f6d26ffd38c3 100644 --- a/modules/storages/app/models/storages/upload_link.rb +++ b/modules/storages/app/models/storages/upload_link.rb @@ -29,7 +29,7 @@ class Storages::UploadLink attr_reader :destination, :method - def initialize(destination = "", method = :post) + def initialize(destination = '', method = :post) @destination = destination @method = method end diff --git a/modules/storages/app/services/storages/nextcloud_group_folder_properties_sync_service.rb b/modules/storages/app/services/storages/nextcloud_group_folder_properties_sync_service.rb index 9b59079297ab..4b1202e9fe13 100644 --- a/modules/storages/app/services/storages/nextcloud_group_folder_properties_sync_service.rb +++ b/modules/storages/app/services/storages/nextcloud_group_folder_properties_sync_service.rb @@ -160,7 +160,7 @@ def project_tokens(project_storage) def hide_inactive_folders(remote_folders) project_folder_ids = active_project_storages_scope.pluck(:project_folder_id).compact remote_folders.except("#{@storage.group_folder}/").each do |(path, attrs)| - next if project_folder_ids.include?(attrs["fileid"]) + next if project_folder_ids.include?(attrs['fileid']) command_params = { path:, @@ -174,13 +174,13 @@ def hide_inactive_folders(remote_folders) .resolve("nextcloud.commands.set_permissions") .call(storage: @storage, **command_params) .on_failure do |service_result| - format_and_log_error(service_result.errors, folder: path, context: "hide_folder") + format_and_log_error(service_result.errors, folder: path, context: 'hide_folder') end end end def ensure_folders_exist(remote_folders) - id_folder_map = remote_folders.to_h { |folder, properties| [properties["fileid"], folder] } + id_folder_map = remote_folders.to_h { |folder, properties| [properties['fileid'], folder] } active_project_storages_scope.includes(:project).map do |project_storage| next create_folder(project_storage) unless id_folder_map.key?(project_storage.project_folder_id) @@ -220,7 +220,7 @@ def create_folder(project_storage) end folder_id_result = Peripherals::Registry - .resolve("nextcloud.queries.file_ids") + .resolve('nextcloud.queries.file_ids') .call(storage: @storage, path: folder_path) .result_or do |error| format_and_log_error(error, path:) @@ -228,7 +228,7 @@ def create_folder(project_storage) return ServiceResult.failure(errors: error) end - project_folder_id = folder_id_result.dig(folder_path, "fileid") + project_folder_id = folder_id_result.dig(folder_path, 'fileid') last_project_folder = ::Storages::LastProjectFolder .find_by( project_storage_id: project_storage.id, diff --git a/modules/storages/app/services/storages/oauth_applications/create_service.rb b/modules/storages/app/services/storages/oauth_applications/create_service.rb index ff9a40ef9112..87906bac1a8d 100644 --- a/modules/storages/app/services/storages/oauth_applications/create_service.rb +++ b/modules/storages/app/services/storages/oauth_applications/create_service.rb @@ -47,7 +47,7 @@ def call .call({ name: "#{storage.name} (#{I18n.t("storages.provider_types.#{storage.short_provider_type}.name")})", redirect_uri: File.join(storage.host, "index.php/apps/integration_openproject/oauth-redirect"), - scopes: "api_v3", + scopes: 'api_v3', confidential: true, owner: storage.creator, integration: storage diff --git a/modules/storages/app/services/storages/one_drive_managed_folder_sync_service.rb b/modules/storages/app/services/storages/one_drive_managed_folder_sync_service.rb index 96d0e917833b..fdc349a39e14 100644 --- a/modules/storages/app/services/storages/one_drive_managed_folder_sync_service.rb +++ b/modules/storages/app/services/storages/one_drive_managed_folder_sync_service.rb @@ -75,7 +75,7 @@ def ensure_folders_exist(folder_map) end end - ServiceResult.success(result: "folders processed") + ServiceResult.success(result: 'folders processed') end def hide_inactive_folders(folder_map) @@ -84,7 +84,7 @@ def hide_inactive_folders(folder_map) Peripherals::Registry.resolve("one_drive.commands.set_permissions") .call(storage: @storage, path: item_id, permissions: { write: [], read: [] }) .on_failure do |service_result| - format_and_log_error(service_result.errors, folder: path, context: "hide_folder") + format_and_log_error(service_result.errors, folder: path, context: 'hide_folder') end end end @@ -109,14 +109,14 @@ def set_permissions(path, permissions) def rename_folder(source, target) Peripherals::Registry - .resolve("one_drive.commands.rename_file") + .resolve('one_drive.commands.rename_file') .call(storage: @storage, source:, target:) .result_or { |error| format_and_log_error(error, source:, target:) } end def create_folder(project_storage) Peripherals::Registry - .resolve("one_drive.commands.create_folder") + .resolve('one_drive.commands.create_folder') .call(storage: @storage, folder_path: project_storage.managed_project_folder_path) .match(on_failure: ->(error) { format_and_log_error(error, folder_path: project_storage.managed_project_folder_path) }, on_success: ->(folder_info) do diff --git a/modules/storages/app/services/storages/project_storages/set_attributes_service.rb b/modules/storages/app/services/storages/project_storages/set_attributes_service.rb index fd814e1115dd..4abf33871cc6 100644 --- a/modules/storages/app/services/storages/project_storages/set_attributes_service.rb +++ b/modules/storages/app/services/storages/project_storages/set_attributes_service.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ +# Used by: CreateService when setting attributes module Storages::ProjectStorages class SetAttributesService < ::BaseServices::SetAttributes - def set_default_attributes(params) + def set_default_attributes(_params) project_storage = model storage = project_storage.storage project_storage.creator ||= user + project_storage.project_folder_mode ||= - if params[:project_folder_mode].present? - params[:project_folder_mode] - elsif storage.present? && storage.automatic_management_enabled? + if storage.present? && storage.automatic_management_enabled? "automatic" else "inactive" diff --git a/modules/storages/app/services/storages/storages/set_attributes_service.rb b/modules/storages/app/services/storages/storages/set_attributes_service.rb index f35f6d5ab58b..62c2b46eaa22 100644 --- a/modules/storages/app/services/storages/storages/set_attributes_service.rb +++ b/modules/storages/app/services/storages/storages/set_attributes_service.rb @@ -43,13 +43,13 @@ def set_attributes(params) end def remove_host_trailing_slashes - storage.host = storage.host&.gsub(/\/+$/, "") + storage.host = storage.host&.gsub(/\/+$/, '') end def replace_empty_host_with_nil(params) cloned_param = params.clone - if cloned_param[:host] == "" + if cloned_param[:host] == '' cloned_param[:host] = nil end diff --git a/modules/storages/app/validator/nextcloud_compatible_host_validator.rb b/modules/storages/app/validator/nextcloud_compatible_host_validator.rb index e8b47b803f0b..1b522a651006 100644 --- a/modules/storages/app/validator/nextcloud_compatible_host_validator.rb +++ b/modules/storages/app/validator/nextcloud_compatible_host_validator.rb @@ -41,7 +41,7 @@ def validate_each(contract, attribute, value) private def validate_capabilities(contract, attribute, value) - uri = URI.parse(File.join(value, "/ocs/v2.php/cloud/capabilities")) + uri = URI.parse(File.join(value, '/ocs/v2.php/cloud/capabilities')) response = OpenProject.httpx .with(HTTPX_TIMEOUT_SETTINGS) @@ -69,7 +69,7 @@ def check_capabilities_response(response) # Apache strips that part of the request header by default. # https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/oauth2.html def validate_setup_completeness(contract, attribute, value) - uri = URI.parse(File.join(value, "index.php/apps/integration_openproject/check-config")) + uri = URI.parse(File.join(value, 'index.php/apps/integration_openproject/check-config')) response = OpenProject.httpx .with(HTTPX_TIMEOUT_SETTINGS) .get(uri, headers: { "Authorization" => AUTHORIZATION_HEADER }) @@ -117,13 +117,13 @@ def major_version_sufficient?(response) end def read_version(response) - response.json.dig("ocs", "data", "version", "major") + response.json.dig('ocs', 'data', 'version', 'major') rescue HTTPX::Error, MultiJson::ParseError false end def read_authorization_header(response) - response.json["authorization_header"] + response.json['authorization_header'] rescue HTTPX::Error, MultiJson::ParseError nil end diff --git a/modules/storages/app/views/storages/admin/storages/confirm_destroy.html.erb b/modules/storages/app/views/storages/admin/storages/confirm_destroy.html.erb index 5f33628f9f13..e19d43a5b368 100644 --- a/modules/storages/app/views/storages/admin/storages/confirm_destroy.html.erb +++ b/modules/storages/app/views/storages/admin/storages/confirm_destroy.html.erb @@ -50,7 +50,7 @@ See COPYRIGHT and LICENSE files for more details.

    <%= text_field_tag :delete_confirmation %> - <%= styled_button_tag title: t(:button_delete), class: '-primary', disabled: true do + <%= styled_button_tag title: t(:button_delete), class: '-highlight', disabled: true do concat content_tag :i, '', class: 'button--icon icon-delete' concat content_tag :span, t(:button_delete), class: 'button--text' end %> diff --git a/modules/storages/app/views/storages/admin/storages/edit.html.erb b/modules/storages/app/views/storages/admin/storages/edit.html.erb index c0035698bf10..ced7dadc37cf 100644 --- a/modules/storages/app/views/storages/admin/storages/edit.html.erb +++ b/modules/storages/app/views/storages/admin/storages/edit.html.erb @@ -74,7 +74,7 @@ See COPYRIGHT and LICENSE files for more details. <% end %> <% end %> -<% if @storage.automatic_management_enabled? %> +<% if @storage.provider_type_nextcloud? && @storage.automatic_management_enabled? %> <%= render(Primer::Alpha::Layout.new(stacking_breakpoint: :lg)) do |component| %> <% component.with_main() do %> <%= render(::Storages::Admin::StorageViewComponent.new(@storage)) %> diff --git a/modules/storages/app/views/storages/project_settings/_project_folder_form.html.erb b/modules/storages/app/views/storages/project_settings/_project_folder_form.html.erb index 871598437d5d..6306e76ab6d1 100644 --- a/modules/storages/app/views/storages/project_settings/_project_folder_form.html.erb +++ b/modules/storages/app/views/storages/project_settings/_project_folder_form.html.erb @@ -154,7 +154,7 @@ See COPYRIGHT and LICENSE files for more details.
    - <%= styled_button_tag class: "-primary" do %> + <%= styled_button_tag class: "-highlight" do %> <%= spot_icon('checkmark') %> <%= content_tag :span, submit_button_label %> <% end %> diff --git a/modules/storages/app/views/storages/project_settings/_storage_select_form.html.erb b/modules/storages/app/views/storages/project_settings/_storage_select_form.html.erb index a723e22d40d1..c6492937a803 100644 --- a/modules/storages/app/views/storages/project_settings/_storage_select_form.html.erb +++ b/modules/storages/app/views/storages/project_settings/_storage_select_form.html.erb @@ -44,7 +44,7 @@ See COPYRIGHT and LICENSE files for more details.
    - <%= styled_button_tag class: "-primary" do %> + <%= styled_button_tag class: "-highlight" do %> <%= spot_icon('checkmark') %> <%= content_tag :span, submit_button_label %> <% end %> diff --git a/modules/storages/app/views/storages/project_settings/destroy_info.html.erb b/modules/storages/app/views/storages/project_settings/destroy_info.html.erb index 9da3cc13f4b6..ccf209e08974 100644 --- a/modules/storages/app/views/storages/project_settings/destroy_info.html.erb +++ b/modules/storages/app/views/storages/project_settings/destroy_info.html.erb @@ -49,7 +49,7 @@ See COPYRIGHT and LICENSE files for more details.

    <%= text_field_tag :delete_confirmation %> - <%= styled_button_tag title: t(:button_delete), class: '-primary', disabled: true do + <%= styled_button_tag title: t(:button_delete), class: '-highlight', disabled: true do concat content_tag :i, '', class: 'button--icon icon-delete' concat content_tag :span, t(:button_delete), class: 'button--text' end %> diff --git a/modules/storages/app/views/storages/project_settings/index.html.erb b/modules/storages/app/views/storages/project_settings/index.html.erb index ab04939601b6..f8a608cbfb08 100644 --- a/modules/storages/app/views/storages/project_settings/index.html.erb +++ b/modules/storages/app/views/storages/project_settings/index.html.erb @@ -34,7 +34,7 @@ See COPYRIGHT and LICENSE files for more details.
  • <%= link_to new_project_settings_project_storage_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: { label: t(:'storages.label_new_storage') }, title: t(:'storages.label_new_storage') } do %> <%= op_icon('button--icon icon-add') %> diff --git a/modules/storages/app/workers/storages/cleanup_uncontainered_file_links_job.rb b/modules/storages/app/workers/storages/cleanup_uncontainered_file_links_job.rb index cc5dbf1048c1..0f47e0d6ef77 100644 --- a/modules/storages/app/workers/storages/cleanup_uncontainered_file_links_job.rb +++ b/modules/storages/app/workers/storages/cleanup_uncontainered_file_links_job.rb @@ -26,13 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class Storages::CleanupUncontaineredFileLinksJob < ApplicationJob +class Storages::CleanupUncontaineredFileLinksJob < Cron::CronJob queue_with_priority :low + self.cron_expression = '06 22 * * *' + def perform Storages::FileLink .where(container: nil) - .where("created_at <= ?", Time.current - OpenProject::Configuration.attachments_grace_period.minutes) + .where('created_at <= ?', Time.current - OpenProject::Configuration.attachments_grace_period.minutes) .delete_all end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/strategy.rb b/modules/storages/app/workers/storages/manage_nextcloud_integration_cron_job.rb similarity index 80% rename from modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/strategy.rb rename to modules/storages/app/workers/storages/manage_nextcloud_integration_cron_job.rb index a95b0d2eef85..9fdebaf62d4b 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/strategy.rb +++ b/modules/storages/app/workers/storages/manage_nextcloud_integration_cron_job.rb @@ -29,21 +29,18 @@ #++ module Storages - module Peripherals - module StorageInteraction - module AuthenticationStrategies - class Strategy - attr_reader :key, :user + class ManageNextcloudIntegrationCronJob < Cron::CronJob + include ManageNextcloudIntegrationJobMixin - def initialize(key) - @key = key - end + queue_with_priority :low - def with_user(user) - @user = user - self - end - end + self.cron_expression = '1 * * * *' + + def self.ensure_scheduled! + if ::Storages::ProjectStorage.active_automatically_managed.exists? + super + else + remove end end end diff --git a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/basic_auth.rb b/modules/storages/app/workers/storages/manage_nextcloud_integration_events_job.rb similarity index 57% rename from modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/basic_auth.rb rename to modules/storages/app/workers/storages/manage_nextcloud_integration_events_job.rb index cbf7f153698f..89485d35f3c0 100644 --- a/modules/storages/app/common/storages/peripherals/storage_interaction/authentication_strategies/basic_auth.rb +++ b/modules/storages/app/workers/storages/manage_nextcloud_integration_events_job.rb @@ -1,5 +1,3 @@ -# frozen_string_literal:true - #-- copyright # OpenProject is an open source project management software. # Copyright (C) 2012-2024 the OpenProject GmbH @@ -29,32 +27,37 @@ #++ module Storages - module Peripherals - module StorageInteraction - module AuthenticationStrategies - class BasicAuth - def self.strategy - Strategy.new(:basic_auth) - end + class ManageNextcloudIntegrationEventsJob < ApplicationJob + include ManageNextcloudIntegrationJobMixin - def call(storage:, http_options: {}) - username = storage.username - password = storage.password + SINGLE_THREAD_DEBOUNCE_TIME = 4.seconds.freeze + MULTI_THREAD_DEBOUNCE_TIME = 5.seconds.freeze + KEY = :manage_nextcloud_integration_events_job_debounce_happend_at - return build_failure(storage) if username.blank? || password.blank? + queue_with_priority :above_normal - yield OpenProject.httpx.basic_auth(username, password).with(http_options) + class << self + def debounce + unless debounce_happend_in_current_thread_recently? + Rails.cache.fetch(KEY, expires_in: MULTI_THREAD_DEBOUNCE_TIME) do + set(wait: MULTI_THREAD_DEBOUNCE_TIME).perform_later + RequestStore.store[KEY] = Time.current end + end + end - private + private - def build_failure(storage) - log_message = "Cannot authenticate storage with basic auth. Password or username not configured." - data = ::Storages::StorageErrorData.new(source: self.class, payload: storage) - Failures::Builder.call(code: :error, log_message:, data:) - end - end + def debounce_happend_in_current_thread_recently? + timestamp = RequestStore.store[KEY] + timestamp.present? && (timestamp + SINGLE_THREAD_DEBOUNCE_TIME) > Time.current end end + + def perform + lock_obtained = super + self.class.debounce unless lock_obtained + lock_obtained + end end end diff --git a/modules/storages/app/workers/storages/manage_nextcloud_integration_job.rb b/modules/storages/app/workers/storages/manage_nextcloud_integration_job.rb deleted file mode 100644 index fe38ffaea2c2..000000000000 --- a/modules/storages/app/workers/storages/manage_nextcloud_integration_job.rb +++ /dev/null @@ -1,109 +0,0 @@ -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -module Storages - class ManageNextcloudIntegrationJob < ApplicationJob - include GoodJob::ActiveJobExtensions::Concurrency - using ::Storages::Peripherals::ServiceResultRefinements - - good_job_control_concurrency_with( - total_limit: 2, - enqueue_limit: 1, - perform_limit: 1, - key: "ManageNextcloudIntegrationJob" - ) - SINGLE_THREAD_DEBOUNCE_TIME = 4.seconds.freeze - KEY = :manage_nextcloud_integration_job_debounce_happend_at - CRON_JOB_KEY = :'Storages::ManageNextcloudIntegrationJob' - - queue_with_priority :above_normal - - class << self - def debounce - if debounce_happend_in_current_thread_recently? - false - else - # TODO: - # Why there is 5 seconds delay? - # it is like that because for 1 thread and if there is no delay more than - # SINGLE_THREAD_DEBOUNCE_TIME(4.seconds) - # then some events can be lost - # - # Possibly "true" solutions are: - # 1. have after_request middleware to schedule one job after a request cycle - # 2. use concurrent ruby to have 'true' debounce. - result = set(wait: 5.seconds).perform_later - RequestStore.store[KEY] = Time.current - result - end - end - - def disable_cron_job_if_needed - if ::Storages::ProjectStorage.active_automatically_managed.exists? - GoodJob::Setting.cron_key_enable(CRON_JOB_KEY) unless GoodJob::Setting.cron_key_enabled?(CRON_JOB_KEY) - elsif GoodJob::Setting.cron_key_enabled?(CRON_JOB_KEY) - GoodJob::Setting.cron_key_disable(CRON_JOB_KEY) - end - end - - private - - def debounce_happend_in_current_thread_recently? - timestamp = RequestStore.store[KEY] - timestamp.present? && (timestamp + SINGLE_THREAD_DEBOUNCE_TIME) > Time.current - end - end - - def perform - find_storages do |storage| - next unless storage.configured? - result = service_for(storage).call(storage) - result.match( - on_success: ->(_) { storage.mark_as_healthy }, - on_failure: ->(errors) { storage.mark_as_unhealthy(reason: errors.to_s) } - ) - end - end - - private - - def find_storages(&) - ::Storages::Storage - .automatic_management_enabled - .includes(:oauth_client) - .find_each(&) - end - - def service_for(storage) - return NextcloudGroupFolderPropertiesSyncService if storage.provider_type_nextcloud? - return OneDriveManagedFolderSyncService if storage.provider_type_one_drive? - - raise 'Unknown Storage' - end - end -end diff --git a/db/migrate/20240306154736_remove_good_job_active_id_index.rb b/modules/storages/app/workers/storages/manage_nextcloud_integration_job_mixin.rb similarity index 55% rename from db/migrate/20240306154736_remove_good_job_active_id_index.rb rename to modules/storages/app/workers/storages/manage_nextcloud_integration_job_mixin.rb index f54d20488a16..21e096fa375c 100644 --- a/db/migrate/20240306154736_remove_good_job_active_id_index.rb +++ b/modules/storages/app/workers/storages/manage_nextcloud_integration_job_mixin.rb @@ -28,22 +28,41 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class RemoveGoodJobActiveIdIndex < ActiveRecord::Migration[7.1] - disable_ddl_transaction! +module Storages + module ManageNextcloudIntegrationJobMixin + using Peripherals::ServiceResultRefinements - def change - reversible do |dir| - dir.up do - if connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id) - remove_index :good_jobs, name: :index_good_jobs_on_active_job_id - end - end + def perform + OpenProject::Mutex.with_advisory_lock( + ::Storages::NextcloudStorage, + 'sync_all_group_folders', + timeout_seconds: 0, + transaction: false + ) do + ::Storages::Storage.automatic_management_enabled.includes(:oauth_client).find_each do |storage| + next unless storage.configured? - dir.down do - unless connection.index_name_exists?(:good_jobs, :index_good_jobs_on_active_job_id) - add_index :good_jobs, :active_job_id, name: :index_good_jobs_on_active_job_id + result = service_for(storage).call(storage) + result.match( + on_success: ->(_) do + storage.mark_as_healthy + end, + on_failure: ->(errors) do + storage.mark_as_unhealthy(reason: errors.to_s) + end + ) end + true end end + + private + + def service_for(storage) + return NextcloudGroupFolderPropertiesSyncService if storage.provider_type_nextcloud? + return OneDriveManagedFolderSyncService if storage.provider_type_one_drive? + + raise 'Unknown Storage' + end end end diff --git a/modules/storages/config/routes.rb b/modules/storages/config/routes.rb index ff40cca7728d..523ed7a55e13 100644 --- a/modules/storages/config/routes.rb +++ b/modules/storages/config/routes.rb @@ -31,14 +31,14 @@ Rails.application.routes.draw do namespace :admin do namespace :settings do - resources :storages, controller: "/storages/admin/storages", except: [:show] do - resource :oauth_client, controller: "/storages/admin/oauth_clients", only: %i[new create] do + resources :storages, controller: '/storages/admin/storages', except: [:show] do + resource :oauth_client, controller: '/storages/admin/oauth_clients', only: %i[new create] do patch :update, on: :member get :show_redirect_uri post :finish_setup end - resource :automatically_managed_project_folders, controller: "/storages/admin/automatically_managed_project_folders", + resource :automatically_managed_project_folders, controller: '/storages/admin/automatically_managed_project_folders', only: %i[new create edit update] get :select_provider, on: :collection @@ -55,21 +55,21 @@ end end - get "projects/:project_id/project_storages/:id/open", - controller: "storages/project_storages", - action: "open", - as: "open_project_storage" + get 'projects/:project_id/project_storages/:id/open', + controller: 'storages/project_storages', + action: 'open', + as: 'open_project_storage' - scope "projects/:project_id", as: "project" do - namespace "settings" do - resources :project_storages, controller: "/storages/admin/project_storages", except: %i[show] do + scope 'projects/:project_id', as: 'project' do + namespace 'settings' do + resources :project_storages, controller: '/storages/admin/project_storages', except: %i[show] do member do get :oauth_access_grant # Destroy uses a get request to prompt the user before the actual DELETE request - get :destroy_info, as: "confirm_destroy" + get :destroy_info, as: 'confirm_destroy' end - resources :members, controller: "/storages/project_settings/project_storage_members", only: %i[index] + resources :members, controller: '/storages/project_settings/project_storage_members', only: %i[index] end end end diff --git a/modules/storages/db/migrate/20220712165928_add_storages_permissions_to_roles.rb b/modules/storages/db/migrate/20220712165928_add_storages_permissions_to_roles.rb index 8a115eb3caad..d55d13f12e2f 100644 --- a/modules/storages/db/migrate/20220712165928_add_storages_permissions_to_roles.rb +++ b/modules/storages/db/migrate/20220712165928_add_storages_permissions_to_roles.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require Rails.root.join("db/migrate/migration_utils/permission_adder") +require Rails.root.join('db/migrate/migration_utils/permission_adder') class AddStoragesPermissionsToRoles < ActiveRecord::Migration[6.1] def up diff --git a/modules/storages/db/migrate/20230420063148_add_provider_fields_to_storages.rb b/modules/storages/db/migrate/20230420063148_add_provider_fields_to_storages.rb index c24a1b2faa6a..6fcf34f85424 100644 --- a/modules/storages/db/migrate/20230420063148_add_provider_fields_to_storages.rb +++ b/modules/storages/db/migrate/20230420063148_add_provider_fields_to_storages.rb @@ -27,6 +27,6 @@ class AddProviderFieldsToStorages < ActiveRecord::Migration[7.0] def change - add_column :storages, :provider_fields, :jsonb, null: false, default: "{}" + add_column :storages, :provider_fields, :jsonb, null: false, default: '{}' end end diff --git a/modules/storages/db/migrate/20230512153303_change_storage_provider_fields_default.rb b/modules/storages/db/migrate/20230512153303_change_storage_provider_fields_default.rb index 4f4c8411d454..53c653d50608 100644 --- a/modules/storages/db/migrate/20230512153303_change_storage_provider_fields_default.rb +++ b/modules/storages/db/migrate/20230512153303_change_storage_provider_fields_default.rb @@ -27,7 +27,7 @@ class ChangeStorageProviderFieldsDefault < ActiveRecord::Migration[7.0] def change - change_column_default(:storages, :provider_fields, from: "{}", to: {}) + change_column_default(:storages, :provider_fields, from: '{}', to: {}) reversible do |dir| dir.up do diff --git a/modules/storages/db/migrate/20230601082746_create_last_project_folders.rb b/modules/storages/db/migrate/20230601082746_create_last_project_folders.rb index 39dbf0705f73..bad50f97161b 100644 --- a/modules/storages/db/migrate/20230601082746_create_last_project_folders.rb +++ b/modules/storages/db/migrate/20230601082746_create_last_project_folders.rb @@ -29,7 +29,7 @@ class CreateLastProjectFolders < ActiveRecord::Migration[7.0] def change create_table :last_project_folders, - comment: "This table contains the last used project folder IDs for a project storage per mode." do |t| + comment: 'This table contains the last used project folder IDs for a project storage per mode.' do |t| t.references :projects_storage, null: false, foreign_key: { on_delete: :cascade } t.string :origin_folder_id t.enum :mode, enum_type: :project_folder_modes, default: :inactive, null: false diff --git a/modules/storages/db/migrate/20231009135807_remove_renamed_cronjobs.rb b/modules/storages/db/migrate/20231009135807_remove_renamed_cronjobs.rb index c6fe00093aeb..b4042f391e2e 100644 --- a/modules/storages/db/migrate/20231009135807_remove_renamed_cronjobs.rb +++ b/modules/storages/db/migrate/20231009135807_remove_renamed_cronjobs.rb @@ -28,8 +28,8 @@ class RemoveRenamedCronjobs < ActiveRecord::Migration[7.0] def up - execute("DELETE FROM delayed_jobs WHERE handler LIKE '%job_class: CleanupUncontaineredFileLinksJob%'") - execute("DELETE FROM delayed_jobs WHERE handler LIKE '%job_class: ManageNextcloudIntegrationJob%'") + Delayed::Job.where("handler LIKE '%job_class: CleanupUncontaineredFileLinksJob%'").delete_all + Delayed::Job.where("handler LIKE '%job_class: ManageNextcloudIntegrationJob%'").delete_all end def down; end diff --git a/modules/storages/db/migrate/20231109080454_add_health_info_to_storages.rb b/modules/storages/db/migrate/20231109080454_add_health_info_to_storages.rb index d5ffab7a5bab..76f953e1f927 100644 --- a/modules/storages/db/migrate/20231109080454_add_health_info_to_storages.rb +++ b/modules/storages/db/migrate/20231109080454_add_health_info_to_storages.rb @@ -30,8 +30,8 @@ def up execute <<-SQL.squish CREATE TYPE storage_health_statuses AS ENUM ('pending', 'healthy', 'unhealthy'); SQL - add_column(:storages, :health_status, :storage_health_statuses, null: false, default: "pending") - add_column(:storages, :health_changed_at, :datetime, null: false, default: -> { "current_timestamp" }) + add_column(:storages, :health_status, :storage_health_statuses, null: false, default: 'pending') + add_column(:storages, :health_changed_at, :datetime, null: false, default: -> { 'current_timestamp' }) add_column(:storages, :health_reason, :string) end diff --git a/modules/storages/db/migrate/20231208143303_add_health_checked_at_to_storages.rb b/modules/storages/db/migrate/20231208143303_add_health_checked_at_to_storages.rb index f874a875f8cd..65c9b5f5497f 100644 --- a/modules/storages/db/migrate/20231208143303_add_health_checked_at_to_storages.rb +++ b/modules/storages/db/migrate/20231208143303_add_health_checked_at_to_storages.rb @@ -1,6 +1,6 @@ class AddHealthCheckedAtToStorages < ActiveRecord::Migration[7.0] def up - add_column(:storages, :health_checked_at, :datetime, null: false, default: -> { "current_timestamp" }) + add_column(:storages, :health_checked_at, :datetime, null: false, default: -> { 'current_timestamp' }) end def down diff --git a/modules/storages/lib/api/v3/file_links/file_link_representer.rb b/modules/storages/lib/api/v3/file_links/file_link_representer.rb index d747a544322d..85bf00b127c0 100644 --- a/modules/storages/lib/api/v3/file_links/file_link_representer.rb +++ b/modules/storages/lib/api/v3/file_links/file_link_representer.rb @@ -35,19 +35,19 @@ module API::V3::FileLinks PERMISSION_LINKS = { view_allowed: { href: URN_PERMISSION_VIEW, - title: "View allowed" + title: 'View allowed' }, view_not_allowed: { href: URN_PERMISSION_NOT_ALLOWED, - title: "View not allowed" + title: 'View not allowed' }, not_found: { href: URN_STATUS_NOT_FOUND, - title: "Not found" + title: 'Not found' }, error: { href: URN_STATUS_ERROR, - title: "Error" + title: 'Error' } }.freeze @@ -118,9 +118,9 @@ class FileLinkRepresenter < ::API::Decorators::Single skip_render: ->(*) { true }, getter: ->(*) {}, setter: ->(fragment:, **) { - break if fragment["href"].blank? + break if fragment['href'].blank? - canonical_url = fragment["href"].gsub(/\/+$/, "") + canonical_url = fragment['href'].gsub(/\/+$/, '') represented.storage = ::Storages::Storage.find_by(host: canonical_url) represented.storage ||= ::Storages::Storage::InexistentStorage.new(host: canonical_url) } @@ -131,7 +131,7 @@ class FileLinkRepresenter < ::API::Decorators::Single skip_render: ->(*) { represented.container_id.nil? } def _type - "FileLink" + 'FileLink' end private @@ -160,10 +160,10 @@ def parse_origin_data(origin_data) origin_created_by_name: origin_data["createdByName"], origin_last_modified_by_name: origin_data["lastModifiedByName"], origin_created_at: ::API::V3::Utilities::DateTimeFormatter.parse_datetime(origin_data["createdAt"], - "originData.createdAt", + 'originData.createdAt', allow_nil: true), origin_updated_at: ::API::V3::Utilities::DateTimeFormatter.parse_datetime(origin_data["lastModifiedAt"], - "originData.lastModifiedAt", + 'originData.lastModifiedAt', allow_nil: true) } end diff --git a/modules/storages/lib/api/v3/file_links/file_links_api.rb b/modules/storages/lib/api/v3/file_links/file_links_api.rb index 35e6b789064b..c4b2fa44f911 100644 --- a/modules/storages/lib/api/v3/file_links/file_links_api.rb +++ b/modules/storages/lib/api/v3/file_links/file_links_api.rb @@ -42,7 +42,7 @@ class API::V3::FileLinks::FileLinksAPI < API::OpenProjectAPI # `route_param` extends the route by a route parameter of the endpoint. # The input parameter value is parsed into the `:file_link_id` symbol. - route_param :file_link_id, type: Integer, desc: "File link id" do + route_param :file_link_id, type: Integer, desc: 'File link id' do # The after validation hook executes after the validation of the request format, but before any execution # inside the endpoint context. Hence, it is a good place to actually fetch the handled resource. after_validation do diff --git a/modules/storages/lib/api/v3/file_links/work_packages_file_links_api.rb b/modules/storages/lib/api/v3/file_links/work_packages_file_links_api.rb index f020e5944a30..9575a206fe46 100644 --- a/modules/storages/lib/api/v3/file_links/work_packages_file_links_api.rb +++ b/modules/storages/lib/api/v3/file_links/work_packages_file_links_api.rb @@ -39,13 +39,13 @@ class API::V3::FileLinks::WorkPackagesFileLinksAPI < API::OpenProjectAPI .call(params) unless query.valid? - message = I18n.t("api_v3.errors.missing_or_malformed_parameter", parameter: "filters") + message = I18n.t('api_v3.errors.missing_or_malformed_parameter', parameter: 'filters') raise ::API::Errors::InvalidQuery.new(message) end result = if current_user.allowed_in_project?(:view_file_links, @work_package.project) file_links = query.results.where(container_id: @work_package.id, - container_type: "WorkPackage", + container_type: 'WorkPackage', storage: @work_package.project.storages) ::Storages::FileLinkSyncService .new(user: current_user) diff --git a/modules/storages/lib/api/v3/project_storages/project_storage_representer.rb b/modules/storages/lib/api/v3/project_storages/project_storage_representer.rb index 8a8302c64079..eb834cd77641 100644 --- a/modules/storages/lib/api/v3/project_storages/project_storage_representer.rb +++ b/modules/storages/lib/api/v3/project_storages/project_storage_representer.rb @@ -63,7 +63,7 @@ class ProjectStorageRepresenter < ::API::Decorators::Single skip_link: ->(*) { false } def _type - "ProjectStorage" + 'ProjectStorage' end end end diff --git a/modules/storages/lib/api/v3/project_storages/project_storages_api.rb b/modules/storages/lib/api/v3/project_storages/project_storages_api.rb index c83ab701fa88..0d4f9285434a 100644 --- a/modules/storages/lib/api/v3/project_storages/project_storages_api.rb +++ b/modules/storages/lib/api/v3/project_storages/project_storages_api.rb @@ -39,7 +39,7 @@ class ProjectStoragesAPI < API::OpenProjectAPI .call(params) unless query.valid? - message = I18n.t("api_v3.errors.missing_or_malformed_parameter", parameter: "filters") + message = I18n.t('api_v3.errors.missing_or_malformed_parameter', parameter: 'filters') raise ::API::Errors::InvalidQuery.new(message) end @@ -53,7 +53,7 @@ class ProjectStoragesAPI < API::OpenProjectAPI ) end - route_param :id, type: Integer, desc: "ProjectStorage id" do + route_param :id, type: Integer, desc: 'ProjectStorage id' do after_validation do @project_storage = Storages::ProjectStorage.find(params[:id]) diff --git a/modules/storages/lib/api/v3/storage_files/storage_file_representer.rb b/modules/storages/lib/api/v3/storage_files/storage_file_representer.rb index 174f9116b405..dcb1a95cfa72 100644 --- a/modules/storages/lib/api/v3/storage_files/storage_file_representer.rb +++ b/modules/storages/lib/api/v3/storage_files/storage_file_representer.rb @@ -55,7 +55,7 @@ def initialize(model, storage, current_user:) property :permissions def _type - Storages::StorageFile.name.split("::").last + Storages::StorageFile.name.split('::').last end end end diff --git a/modules/storages/lib/api/v3/storage_files/storage_files_api.rb b/modules/storages/lib/api/v3/storage_files/storage_files_api.rb index 96b2250a2c42..863541ed25ce 100644 --- a/modules/storages/lib/api/v3/storage_files/storage_files_api.rb +++ b/modules/storages/lib/api/v3/storage_files/storage_files_api.rb @@ -59,19 +59,16 @@ def fetch_upload_link .call(storage: @storage, user: current_user, data:) end end - - def auth_strategy - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken - .strategy - .with_user(current_user) - end end resources :files do get do Storages::Peripherals::Registry .resolve("#{@storage.short_provider_type}.queries.files") - .call(storage: @storage, auth_strategy:, folder: extract_parent_folder(params)) + .call( + storage: @storage, + user: current_user, folder: extract_parent_folder(params) + ) .match( on_success: ->(files) { API::V3::StorageFiles::StorageFilesRepresenter.new(files, @storage, current_user:) }, on_failure: ->(error) { raise_error(error) } diff --git a/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb b/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb index aa2e33bef1f8..d148bea077cc 100644 --- a/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb +++ b/modules/storages/lib/api/v3/storage_files/storage_files_representer.rb @@ -61,7 +61,7 @@ def initialize(model, storage, current_user:) exec_context: :decorator def _type - "StorageFiles" + 'StorageFiles' end end end diff --git a/modules/storages/lib/api/v3/storage_files/storage_upload_link_representer.rb b/modules/storages/lib/api/v3/storage_files/storage_upload_link_representer.rb index b0dec8173564..50b195186b4b 100644 --- a/modules/storages/lib/api/v3/storage_files/storage_upload_link_representer.rb +++ b/modules/storages/lib/api/v3/storage_files/storage_upload_link_representer.rb @@ -36,12 +36,12 @@ class StorageUploadLinkRepresenter < ::API::Decorators::Single { href: represented.destination, method: represented.method, - title: "Upload File" + title: 'Upload File' } end def _type - Storages::UploadLink.name.split("::").last + Storages::UploadLink.name.split('::').last end end end diff --git a/modules/storages/lib/api/v3/storages/storages_api.rb b/modules/storages/lib/api/v3/storages/storages_api.rb index 71557d77add9..c2599eea4392 100644 --- a/modules/storages/lib/api/v3/storages/storages_api.rb +++ b/modules/storages/lib/api/v3/storages/storages_api.rb @@ -36,7 +36,7 @@ class API::V3::Storages::StoragesAPI < API::OpenProjectAPI get &API::V3::Utilities::Endpoints::Index.new(model: Storages::Storage, scope: -> { visible_storages }).mount - route_param :storage_id, type: Integer, desc: "Storage id" do + route_param :storage_id, type: Integer, desc: 'Storage id' do after_validation do @storage = visible_storages.find(params[:storage_id]) end diff --git a/modules/storages/lib/open_project/storages.rb b/modules/storages/lib/open_project/storages.rb index 628afdb1ab88..b7ef4ce42ca6 100644 --- a/modules/storages/lib/open_project/storages.rb +++ b/modules/storages/lib/open_project/storages.rb @@ -29,7 +29,7 @@ # This file is required by `modules/storages/lib/openproject-storages.rb` and # loads the Rails engine associated with the plugin. -require "open_project/storages/engine" +require 'open_project/storages/engine' module OpenProject module Storages diff --git a/modules/storages/lib/open_project/storages/engine.rb b/modules/storages/lib/open_project/storages/engine.rb index db4a75c1ceae..d4a28a138a2d 100644 --- a/modules/storages/lib/open_project/storages/engine.rb +++ b/modules/storages/lib/open_project/storages/engine.rb @@ -46,11 +46,11 @@ def self.permissions # please see comments inside ActsAsOpEngine class include OpenProject::Plugins::ActsAsOpEngine - initializer "openproject_storages.feature_decisions" do + initializer 'openproject_storages.feature_decisions' do OpenProject::FeatureDecisions.add :storage_file_picking_select_all end - initializer "openproject_storages.event_subscriptions" do + initializer 'openproject_storages.event_subscriptions' do Rails.application.config.after_initialize do [ OpenProject::Events::MEMBER_CREATED, @@ -62,29 +62,29 @@ def self.permissions OpenProject::Events::PROJECT_UNARCHIVED ].each do |event| OpenProject::Notifications.subscribe(event) do |_payload| - ::Storages::ManageNextcloudIntegrationJob.debounce + ::Storages::ManageNextcloudIntegrationEventsJob.debounce end end OpenProject::Notifications.subscribe( OpenProject::Events::OAUTH_CLIENT_TOKEN_CREATED ) do |payload| - if payload[:integration_type] == "Storages::Storage" - ::Storages::ManageNextcloudIntegrationJob.debounce + if payload[:integration_type] == 'Storages::Storage' + ::Storages::ManageNextcloudIntegrationEventsJob.debounce end end OpenProject::Notifications.subscribe( OpenProject::Events::ROLE_UPDATED ) do |payload| if payload[:permissions_diff]&.intersect?(OpenProject::Storages::Engine.permissions) - ::Storages::ManageNextcloudIntegrationJob.debounce + ::Storages::ManageNextcloudIntegrationEventsJob.debounce end end OpenProject::Notifications.subscribe( OpenProject::Events::ROLE_DESTROYED ) do |payload| if payload[:permissions]&.intersect?(OpenProject::Storages::Engine.permissions) - ::Storages::ManageNextcloudIntegrationJob.debounce + ::Storages::ManageNextcloudIntegrationEventsJob.debounce end end @@ -95,8 +95,8 @@ def self.permissions ].each do |event| OpenProject::Notifications.subscribe(event) do |payload| if payload[:project_folder_mode] == :automatic - ::Storages::ManageNextcloudIntegrationJob.debounce - ::Storages::ManageNextcloudIntegrationJob.disable_cron_job_if_needed + ::Storages::ManageNextcloudIntegrationEventsJob.debounce + ::Storages::ManageNextcloudIntegrationCronJob.ensure_scheduled! end end end @@ -106,8 +106,8 @@ def self.permissions # For documentation see the definition of register in "ActsAsOpEngine" # This corresponds to the openproject-storage.gemspec # Pass a block to the plugin (for defining permissions, menu items and the like) - register "openproject-storages", - author_url: "https://www.openproject.org", + register 'openproject-storages', + author_url: 'https://www.openproject.org', bundled: true, settings: {} do # Defines permission constraints used in the module (controller, etc.) @@ -142,14 +142,14 @@ def self.permissions # condition ("if:"), caption and icon. menu :admin_menu, :storages_admin_settings, - { controller: "/storages/admin/storages", action: :index }, + { controller: '/storages/admin/storages', action: :index }, if: Proc.new { User.current.admin? }, caption: :project_module_storages, - icon: "hosting" + icon: 'hosting' menu :project_menu, :settings_project_storages, - { controller: "/storages/admin/project_storages", action: "index" }, + { controller: '/storages/admin/project_storages', action: 'index' }, caption: :project_module_storages, parent: :settings @@ -276,28 +276,21 @@ def self.permissions end # Add api endpoints specific to this module - add_api_endpoint "API::V3::Root" do + add_api_endpoint 'API::V3::Root' do mount ::API::V3::Storages::StoragesAPI mount ::API::V3::ProjectStorages::ProjectStoragesAPI mount ::API::V3::FileLinks::FileLinksAPI end - add_api_endpoint "API::V3::WorkPackages::WorkPackagesAPI", :id do + add_api_endpoint 'API::V3::WorkPackages::WorkPackagesAPI', :id do mount ::API::V3::FileLinks::WorkPackagesFileLinksAPI end add_cron_jobs do - { - 'Storages::CleanupUncontaineredFileLinksJob': { - cron: "06 22 * * *", - class: ::Storages::CleanupUncontaineredFileLinksJob.name - }, - - 'Storages::ManageNextcloudIntegrationJob': { - cron: "1 * * * *", - class: ::Storages::ManageNextcloudIntegrationJob.name - } - } + [ + Storages::CleanupUncontaineredFileLinksJob, + Storages::ManageNextcloudIntegrationCronJob + ] end end end diff --git a/modules/storages/lib/openproject-storages.rb b/modules/storages/lib/openproject-storages.rb index 0b8622e544c5..cf1697fc4360 100644 --- a/modules/storages/lib/openproject-storages.rb +++ b/modules/storages/lib/openproject-storages.rb @@ -3,4 +3,4 @@ # The OpenProject plugins, located in modules/, are defined in `Gemfile.modules`. # They are loaded from `config/application.rb` when the bundler group :opf_plugins is loaded. # This file is responsible for loading the module. -require "open_project/storages" +require 'open_project/storages' diff --git a/modules/storages/openproject-storages.gemspec b/modules/storages/openproject-storages.gemspec index c3fb7d170cdf..d25baefd6a8a 100644 --- a/modules/storages/openproject-storages.gemspec +++ b/modules/storages/openproject-storages.gemspec @@ -40,13 +40,13 @@ # References: https://guides.rubygems.org/specification-reference/ # rubocop:disable Gemspec/RequireMFA Gem::Specification.new do |s| - s.name = "openproject-storages" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject Storages" - s.description = "Allows linking work packages to files in external storages, such as Nextcloud." - s.license = "GPLv3" - s.files = Dir["{app,config,db,lib}/**/*"] + s.name = 'openproject-storages' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject Storages' + s.description = 'Allows linking work packages to files in external storages, such as Nextcloud.' + s.license = 'GPLv3' + s.files = Dir['{app,config,db,lib}/**/*'] end # rubocop:enable Gemspec/RequireMFA diff --git a/modules/storages/spec/common/storages/peripherals/registry_spec.rb b/modules/storages/spec/common/storages/peripherals/registry_spec.rb index 5fff3d2f780a..23d150a7b18d 100644 --- a/modules/storages/spec/common/storages/peripherals/registry_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/registry_spec.rb @@ -28,35 +28,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::Registry, :webmock do using Storages::Peripherals::ServiceResultRefinements let(:user) { create(:user) } - let(:url) { "https://example.com" } - let(:origin_user_id) { "admin" } - let(:storage) { build(:nextcloud_storage, :as_automatically_managed, host: url, password: "OpenProjectSecurePassword") } + let(:url) { 'https://example.com' } + let(:origin_user_id) { 'admin' } + let(:storage) { build(:nextcloud_storage, :as_automatically_managed, host: url, password: 'OpenProjectSecurePassword') } subject(:registry) { described_class } - context "when a key is not registered" do + context 'when a key is not registered' do it "raises a OperationNotSupported for a non-existent command/query" do - expect { registry.resolve("nextcloud.commands.destroy_alderaan") }.to raise_error Storages::Errors::OperationNotSupported - expect { registry.resolve("nextcloud.queries.alderaan") }.to raise_error Storages::Errors::OperationNotSupported + expect { registry.resolve('nextcloud.commands.destroy_alderaan') }.to raise_error Storages::Errors::OperationNotSupported + expect { registry.resolve('nextcloud.queries.alderaan') }.to raise_error Storages::Errors::OperationNotSupported end - it "raises a MissingContract for a non-existent contract" do + it 'raises a MissingContract for a non-existent contract' do expect { registry["warehouse.contracts.storage"] }.to raise_error Storages::Errors::MissingContract end - it "raises a ResolverStandardError in all other cases" do - expect { registry.resolve("it.is.a.trap") }.to raise_error Storages::Errors::ResolverStandardError + it 'raises a ResolverStandardError in all other cases' do + expect { registry.resolve('it.is.a.trap') }.to raise_error Storages::Errors::ResolverStandardError end end - describe "#group_users_query" do + describe '#group_users_query' do let(:expected_response_body) do <<~XML @@ -92,21 +92,21 @@ stub_request(:get, "https://example.com/ocs/v1.php/cloud/groups/#{storage.group}") .with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==", - "OCS-APIRequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==', + 'OCS-APIRequest' => 'true' } ) .to_return(expected_response) end - it "responds with a strings array with group users" do - result = registry.resolve("nextcloud.queries.group_users").call(storage:) + it 'responds with a strings array with group users' do + result = registry.resolve('nextcloud.queries.group_users').call(storage:) expect(result).to be_success expect(result.result).to eq(%w[admin OpenProject reader TestUser TestUser34]) end end - describe "#add_user_to_group_command" do + describe '#add_user_to_group_command' do let(:expected_response) do { status: 200, @@ -134,21 +134,21 @@ stub_request(:post, "https://example.com/ocs/v1.php/cloud/users/#{origin_user_id}/groups") .with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==", - "OCS-APIRequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==', + 'OCS-APIRequest' => 'true' } ) .to_return(expected_response) end - it "adds user to the group" do - result = registry.resolve("nextcloud.commands.add_user_to_group").call(storage:, user: origin_user_id) + it 'adds user to the group' do + result = registry.resolve('nextcloud.commands.add_user_to_group').call(storage:, user: origin_user_id) expect(result).to be_success expect(result.message).to eq("User has been added successfully") end end - describe "#remove_user_from_group" do + describe '#remove_user_from_group' do let(:expected_response) do { status: 200, @@ -176,20 +176,20 @@ stub_request(:delete, "https://example.com/ocs/v1.php/cloud/users/#{origin_user_id}/groups?groupid=#{storage.group}") .with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==", - "OCS-APIRequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==', + 'OCS-APIRequest' => 'true' } ) .to_return(expected_response) end - it "removes user from the group" do - result = registry.resolve("nextcloud.commands.remove_user_from_group").call(storage:, user: origin_user_id) + it 'removes user from the group' do + result = registry.resolve('nextcloud.commands.remove_user_from_group').call(storage:, user: origin_user_id) expect(result).to be_success expect(result.message).to eq("User has been removed from group") end - context "when Nextcloud reponds with 105 code in the response body" do + context 'when Nextcloud reponds with 105 code in the response body' do let(:expected_response_body) do <<~XML @@ -206,8 +206,8 @@ XML end - it "responds with a failure and parses message from the xml response" do - result = registry.resolve("nextcloud.commands.remove_user_from_group").call(storage:, user: origin_user_id) + it 'responds with a failure and parses message from the xml response' do + result = registry.resolve('nextcloud.commands.remove_user_from_group').call(storage:, user: origin_user_id) expect(result).to be_failure expect(result.errors.log_message).to eq( "Failed to remove user #{origin_user_id} from group OpenProject: " \ @@ -217,36 +217,36 @@ end end - describe "#create_folder_command" do - let(:folder_path) { "OpenProject/JediProject" } + describe '#create_folder_command' do + let(:folder_path) { 'OpenProject/JediProject' } before do stub_request(:mkcol, "https://example.com/remote.php/dav/files/OpenProject/OpenProject/JediProject") .with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==' } ) .to_return(expected_response) end - context "when folder does not exist yet" do + context 'when folder does not exist yet' do let(:expected_response) do { status: 201, - body: "", + body: '', headers: {} } end - it "creates a folder and responds with a success" do - result = registry.resolve("nextcloud.commands.create_folder").call(storage:, folder_path:) + it 'creates a folder and responds with a success' do + result = registry.resolve('nextcloud.commands.create_folder').call(storage:, folder_path:) expect(result).to be_success expect(result.message).to eq("Folder was successfully created.") end end - context "when folder exists already" do + context 'when folder exists already' do let(:expected_response_body) do <<~XML @@ -264,14 +264,14 @@ } end - it "does not create a folder and responds with a success" do - result = registry.resolve("nextcloud.commands.create_folder").call(storage:, folder_path:) + it 'does not create a folder and responds with a success' do + result = registry.resolve('nextcloud.commands.create_folder').call(storage:, folder_path:) expect(result).to be_success expect(result.message).to eq("Folder already exists.") end end - context "when parent folder is missing for any reason" do + context 'when parent folder is missing for any reason' do let(:expected_response_body) do <<~XML @@ -289,23 +289,23 @@ } end - it "does not create a folder and responds with a failure" do - result = registry.resolve("nextcloud.commands.create_folder").call(storage:, folder_path:) + it 'does not create a folder and responds with a failure' do + result = registry.resolve('nextcloud.commands.create_folder').call(storage:, folder_path:) expect(result).to be_failure expect(result.result).to eq(:conflict) - expect(result.errors.log_message).to eq("Parent node does not exist") + expect(result.errors.log_message).to eq('Parent node does not exist') end end end - describe "#set_permissions_command" do - let(:path) { "OpenProject/JediProject" } + describe '#set_permissions_command' do + let(:path) { 'OpenProject/JediProject' } let(:permissions) do { users: { OpenProject: 31, - "Obi-Wan": 31, - "Qui-Gon": 31 + 'Obi-Wan': 31, + 'Qui-Gon': 31 }, groups: { OpenProject: 0 @@ -351,20 +351,20 @@ XML end - context "with Nextcloud storage type selected" do - context "with outbound request" do + context 'with Nextcloud storage type selected' do + context 'with outbound request' do before do stub_request(:proppatch, "#{url}/remote.php/dav/files/OpenProject/OpenProject/JediProject") .with( body: expected_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==' } ) .to_return(expected_response) end - context "when permissions can be set" do + context 'when permissions can be set' do let(:expected_response_body) do <<~XML @@ -393,13 +393,13 @@ } end - it "returns success when permissions can be set" do - result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path:, permissions:) + it 'returns success when permissions can be set' do + result = registry.resolve('nextcloud.commands.set_permissions').call(storage:, path:, permissions:) expect(result).to be_success end end - context "when the password is wrong" do + context 'when the password is wrong' do let(:expected_response_body) do <<~XML @@ -419,13 +419,13 @@ } end - it "returns failure" do - result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path:, permissions:) + it 'returns failure' do + result = registry.resolve('nextcloud.commands.set_permissions').call(storage:, path:, permissions:) expect(result).to be_failure end end - context "when the NC control user cannot read(see) the project folder" do + context 'when the NC control user cannot read(see) the project folder' do let(:expected_response_body) do <<~XML @@ -445,31 +445,31 @@ } end - it "returns failure" do - result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path:, permissions:) + it 'returns failure' do + result = registry.resolve('nextcloud.commands.set_permissions').call(storage:, path:, permissions:) expect(result).to be_failure end end end - context "when forbidden values are given as folder" do - it "raises an ArgumentError on nil" do + context 'when forbidden values are given as folder' do + it 'raises an ArgumentError on nil' do expect do - registry.resolve("nextcloud.commands.set_permissions").call(storage:, path: nil, permissions:) + registry.resolve('nextcloud.commands.set_permissions').call(storage:, path: nil, permissions:) end.to raise_error(ArgumentError) end - it "raises an ArgumentError on empty string" do + it 'raises an ArgumentError on empty string' do expect do - registry.resolve("nextcloud.commands.set_permissions").call(path: "", permissions:) + registry.resolve('nextcloud.commands.set_permissions').call(path: '', permissions:) end.to raise_error(ArgumentError) end end end end - describe "#file_ids_query" do - let(:nextcloud_subpath) { "" } + describe '#file_ids_query' do + let(:nextcloud_subpath) { '' } let(:url) { "https://example.com#{nextcloud_subpath}" } let(:expected_request_body) do <<~XML @@ -560,15 +560,15 @@ stub_request(:propfind, "#{url}/remote.php/dav/files/OpenProject/OpenProject").with( body: expected_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==", - "Depth" => "1" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==', + 'Depth' => '1' } ).to_return(status: 200, body: expected_response_body, headers: {}) end - shared_examples "a file_ids_query response" do - it "responds with a list of paths and attributes for each of them" do - result = registry.resolve("nextcloud.queries.file_ids").call(storage:, path: "OpenProject") + shared_examples 'a file_ids_query response' do + it 'responds with a list of paths and attributes for each of them' do + result = registry.resolve('nextcloud.queries.file_ids').call(storage:, path: 'OpenProject') .result expect(result).to eq({ "OpenProject/" => { "fileid" => "349" }, "OpenProject/Project #2/" => { "fileid" => "381" }, @@ -580,45 +580,45 @@ end end - it_behaves_like "a file_ids_query response" + it_behaves_like 'a file_ids_query response' - context "when NC is deployed under subpath" do - let(:nexcloud_subpath) { "/subpath" } + context 'when NC is deployed under subpath' do + let(:nexcloud_subpath) { '/subpath' } - it_behaves_like "a file_ids_query response" + it_behaves_like 'a file_ids_query response' end end - describe "#rename_file_command" do + describe '#rename_file_command' do before do stub_request(:move, "https://example.com/remote.php/dav/files/OpenProject/OpenProject/asd") .with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==", - "Destination" => "/remote.php/dav/files/OpenProject/OpenProject/qwe" + 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==', + 'Destination' => '/remote.php/dav/files/OpenProject/OpenProject/qwe' } - ).to_return(status: 201, body: "", headers: {}) + ).to_return(status: 201, body: '', headers: {}) end - describe "with Nextcloud storage type selected" do - it "moves the file" do - result = registry.resolve("nextcloud.commands.rename_file").call(storage:, source: "OpenProject/asd", - target: "OpenProject/qwe") + describe 'with Nextcloud storage type selected' do + it 'moves the file' do + result = registry.resolve('nextcloud.commands.rename_file').call(storage:, source: 'OpenProject/asd', + target: 'OpenProject/qwe') expect(result).to be_success end end end - describe "#delete_folder_command" do + describe '#delete_folder_command' do before do stub_request(:delete, "https://example.com/remote.php/dav/files/OpenProject/OpenProject/Folder%201") - .with(headers: { "Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==" }) - .to_return(status: 204, body: "", headers: {}) + .with(headers: { 'Authorization' => 'Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA==' }) + .to_return(status: 204, body: '', headers: {}) end - describe "with Nextcloud storage type selected" do - it "deletes the folder" do - result = registry.resolve("nextcloud.commands.delete_folder").call(storage:, location: "OpenProject/Folder 1") + describe 'with Nextcloud storage type selected' do + it 'deletes the folder' do + result = registry.resolve('nextcloud.commands.delete_folder').call(storage:, location: 'OpenProject/Folder 1') expect(result).to be_success end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/authentication_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/authentication_spec.rb deleted file mode 100644 index 4de1a79830f3..000000000000 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/authentication_spec.rb +++ /dev/null @@ -1,270 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -require "spec_helper" -require_module_spec_helper - -RSpec.describe Storages::Peripherals::StorageInteraction::Authentication, :webmock do - using Storages::Peripherals::ServiceResultRefinements - - let(:user) { create(:user) } - - shared_examples_for "successful response" do |refreshed: false| - it "must #{refreshed ? 'refresh token and ' : ''}return success" do - result = described_class[auth_strategy].call(storage:, http_options:) { |http| make_request(http) } - expect(result).to be_success - - result.match( - on_failure: ->(error) { fail "Expected success, got #{error}" }, - on_success: ->(r) { expect(r).to eq("EXPECTED_RESULT") } - ) - end - end - - context "with a Nextcloud storage" do - let(:storage) do - create(:nextcloud_storage_with_local_connection, :as_not_automatically_managed, oauth_client_token_user: user) - end - let(:request_url) { "#{storage.uri}ocs/v1.php/cloud/user" } - let(:http_options) { { headers: { "OCS-APIRequest" => "true", "Accept" => "application/json" } } } - - context "with basic auth strategy" do - let(:auth_strategy) { Storages::Peripherals::StorageInteraction::AuthenticationStrategies::BasicAuth.strategy } - - context "with valid credentials", vcr: "auth/nextcloud/basic_auth" do - before do - # Those values are only used to record the vcr cassette - storage.username = "admin" - storage.password = "admin" - end - - it_behaves_like "successful response" - end - - context "with empty username and password" do - it "must return error" do - result = described_class[auth_strategy].call(storage:, http_options:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::BasicAuth) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:error) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - - context "with invalid username and/or password", vcr: "auth/nextcloud/basic_auth_password_invalid" do - before do - # Those values are only used to record the vcr cassette - storage.username = "admin" - storage.password = "YouShallNot(Multi)Pass" - end - - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:, http_options:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source).to eq("EXECUTING_QUERY") - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - end - - context "with user token strategy" do - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - end - - context "with not existent oauth token" do - let(:user_without_token) { create(:user) } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken - .strategy - .with_user(user_without_token) - end - - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:, http_options:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - - context "with invalid oauth refresh token", vcr: "auth/nextcloud/user_token_refresh_token_invalid" do - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:, http_options:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - - context "with invalid oauth access token", vcr: "auth/nextcloud/user_token_access_token_invalid" do - it_behaves_like "successful response", refreshed: true - end - end - end - - context "with a OneDrive/SharePoint storage" do - let(:storage) { create(:sharepoint_dev_drive_storage, oauth_client_token_user: user) } - let(:http_options) { {} } - - context "with client credentials strategy" do - let(:request_url) { "#{storage.uri}v1.0/drives" } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthClientCredentials.strategy - end - - context "with valid oauth credentials", vcr: "auth/one_drive/client_credentials" do - it_behaves_like "successful response" - end - - context "with invalid client secret", vcr: "auth/one_drive/client_credentials_invalid_client_secret" do - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthClientCredentials) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - - context "with invalid client id", vcr: "auth/one_drive/client_credentials_invalid_client_id" do - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthClientCredentials) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - end - - context "with user token strategy" do - let(:request_url) { "#{storage.uri}v1.0/me" } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - end - - context "with valid access token", vcr: "auth/one_drive/user_token" do - it_behaves_like "successful response" - end - - context "with not existent oauth token" do - let(:user_without_token) { create(:user) } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken - .strategy - .with_user(user_without_token) - end - - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - - context "with invalid oauth refresh token", vcr: "auth/one_drive/user_token_refresh_token_invalid" do - it "must return unauthorized" do - result = described_class[auth_strategy].call(storage:) { |http| make_request(http) } - expect(result).to be_failure - expect(result.error_source) - .to be(Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken) - - result.match( - on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, - on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } - ) - end - end - - context "with invalid oauth access token", vcr: "auth/one_drive/user_token_access_token_invalid" do - it_behaves_like "successful response", refreshed: true - end - end - end - - private - - def make_request(http) - handle_response http.get(request_url) - end - - def handle_response(response) - case response - in { status: 200..299 } - ServiceResult.success(result: "EXPECTED_RESULT") - in { status: 401 } - error(:unauthorized) - in { status: 403 } - error(:forbidden) - in { status: 404 } - error(:not_found) - else - error(:error) - end - end - - def error(code) - data = Storages::StorageErrorData.new(source: "EXECUTING_QUERY") - ServiceResult.failure(result: code, errors: Storages::StorageError.new(code:, data:)) - end -end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/network_error_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/network_error_spec.rb deleted file mode 100644 index 446e85889878..000000000000 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/network_error_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -require "spec_helper" -require_module_spec_helper - -# rubocop:disable RSpec/DescribeClass -RSpec.describe "network errors for storage interaction", :webmock do - using Storages::Peripherals::ServiceResultRefinements - - let(:user) { create(:user) } - let(:storage) { create(:sharepoint_dev_drive_storage, oauth_client_token_user: user) } - let(:fields) { Storages::Peripherals::StorageInteraction::OneDrive::FilesQuery::FIELDS } - let(:request_url) { "https://graph.microsoft.com/v1.0/drives/#{storage.drive_id}/root/children#{fields}" } - let(:folder) { Storages::Peripherals::ParentFolder.new("/") } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - end - - context "if a timeout happens" do - it "must return an error with wrapped network error response" do - # Test network error handling specifically with the files query. - # Other queries and commands should implement the network error handling in the same way. - stub_request(:get, request_url).to_timeout - result = Storages::Peripherals::StorageInteraction::OneDrive::FilesQuery.call(storage:, auth_strategy:, folder:) - - expect(result).to be_failure - expect(result.result).to eq(:error) - expect(result.error_source).to be(Storages::Peripherals::StorageInteraction::OneDrive::FilesQuery) - expect(result.error_payload).to be_a(HTTPX::ErrorResponse) - end - end -end -# rubocop:enable RSpec/DescribeClass diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/download_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/download_link_query_spec.rb index 51efef368754..9d2514d3b37f 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/download_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/download_link_query_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::DownloadLinkQuery, :webmock do @@ -41,9 +41,9 @@ { ocs: { meta: { - status: "ok", + status: 'ok', statuscode: 200, - message: "OK" + message: 'OK' }, data: { url: "https://example.com/remote.php/direct/#{download_token}" @@ -63,35 +63,35 @@ stub_request(:post, "#{url}/ocs/v2.php/apps/dav/api/v1/direct").to_return(status: 200, body: json, headers: {}) end - it "must return a download link URL" do + it 'must return a download link URL' do result = described_class.call(storage:, user:, file_link:) expect(result).to be_success expect(result.result).to eql(uri) end - context "if Nextcloud is running on a sub path" do - let(:storage) { create(:nextcloud_storage, :with_oauth_client, host: "https://example.com/html") } + context 'if Nextcloud is running on a sub path' do + let(:storage) { create(:nextcloud_storage, :with_oauth_client, host: 'https://example.com/html') } - it "must return a download link URL" do + it 'must return a download link URL' do result = described_class.call(storage:, user:, file_link:) expect(result).to be_success expect(result.result).to eql(uri) end end - describe "with outbound request returning 200 and an empty body" do + describe 'with outbound request returning 200 and an empty body' do before do - stub_request(:post, "#{url}/ocs/v2.php/apps/dav/api/v1/direct").to_return(status: 200, body: "") + stub_request(:post, "#{url}/ocs/v2.php/apps/dav/api/v1/direct").to_return(status: 200, body: '') end - it "must return :unauthorized ServiceResult" do + it 'must return :unauthorized ServiceResult' do result = described_class.call(user:, file_link:, storage:) expect(result).to be_failure expect(result.errors.code).to be(:unauthorized) end end - shared_examples_for "outbound is failing" do |code = 500, symbol = :error| + shared_examples_for 'outbound is failing' do |code = 500, symbol = :error| describe "with outbound request returning #{code}" do before do stub_request(:post, "#{url}/ocs/v2.php/apps/dav/api/v1/direct").to_return(status: code) @@ -105,7 +105,7 @@ end end - include_examples "outbound is failing", 404, :not_found - include_examples "outbound is failing", 401, :unauthorized - include_examples "outbound is failing", 500, :error + include_examples 'outbound is failing', 404, :not_found + include_examples 'outbound is failing', 401, :unauthorized + include_examples 'outbound is failing', 500, :error end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_info_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_info_query_spec.rb index a9e61226e7bd..cd8b755ea775 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_info_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_info_query_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::FilesInfoQuery, :webmock do @@ -42,12 +42,12 @@ subject { described_class.new(storage) } - describe "#call" do + describe '#call' do let(:file_ids) { %w[182 203 222] } - context "without outbound request involved" do - context "with an empty array of file ids" do - it "returns an empty array" do + context 'without outbound request involved' do + context 'with an empty array of file ids' do + it 'returns an empty array' do result = subject.call(user:, file_ids: []) expect(result).to be_success @@ -55,8 +55,8 @@ end end - context "with nil" do - it "returns an error" do + context 'with nil' do + it 'returns an error' do result = subject.call(user:, file_ids: nil) expect(result).to be_failure @@ -65,10 +65,10 @@ end end - context "with outbound request successful", - vcr: "nextcloud/files_info_query_success" do - context "with an array of file ids" do - it "must return an array of file information when called" do + context 'with outbound request successful', + vcr: 'nextcloud/files_info_query_success' do + context 'with an array of file ids' do + it 'must return an array of file information when called' do result = subject.call(user:, file_ids:) expect(result).to be_success @@ -83,9 +83,9 @@ end end - context "with outbound request not authorized", - vcr: "nextcloud/files_info_query_unauthorized" do - context "with an array of file ids" do + context 'with outbound request not authorized', + vcr: 'nextcloud/files_info_query_unauthorized' do + context 'with an array of file ids' do before do token = build_stubbed(:oauth_client_token, oauth_client: storage.oauth_client) allow(Storages::Peripherals::StorageInteraction::Nextcloud::Util) @@ -93,7 +93,7 @@ .and_yield(token) end - it "must return an error when called" do + it 'must return an error when called' do subject.call(user:, file_ids:).match( on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" }, on_failure: ->(error) { expect(error.code).to eq(:unauthorized) } @@ -102,16 +102,16 @@ end end - context "with outbound request not found" do - context "with a single file id", - vcr: "nextcloud/files_info_query_not_found" do + context 'with outbound request not found' do + context 'with a single file id', + vcr: 'nextcloud/files_info_query_not_found' do let(:file_ids) { %w[1234] } - it "returns an HTTP 200 with individual status code per file ID" do + it 'returns an HTTP 200 with individual status code per file ID' do subject.call(user:, file_ids:).match( on_success: ->(file_infos) do expect(file_infos.size).to eq(1) - expect(file_infos.first.to_h).to include(status: "Not Found", status_code: 404) + expect(file_infos.first.to_h).to include(status: 'Not Found', status_code: 404) end, on_failure: ->(error) { fail "Expected success, got #{error}" } ) @@ -119,12 +119,12 @@ end end - context "with outbound request not authorized" do - context "with multiple file IDs, one of which is not authorized", - vcr: "nextcloud/files_info_query_only_one_not_authorized" do + context 'with outbound request not authorized' do + context 'with multiple file IDs, one of which is not authorized', + vcr: 'nextcloud/files_info_query_only_one_not_authorized' do let(:file_ids) { %w[182 1234] } - it "returns an HTTP 200 with individual status code per file ID" do + it 'returns an HTTP 200 with individual status code per file ID' do subject.call(user:, file_ids:).match( on_success: ->(file_infos) do expect(file_infos.size).to eq(2) diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_query_spec.rb index 427180aba28a..4484bfc358cc 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/files_query_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::FilesQuery, :vcr, :webmock do @@ -38,26 +38,21 @@ let(:storage) do create(:nextcloud_storage_with_local_connection, :as_not_automatically_managed, oauth_client_token_user: user) end - let(:folder) { Storages::Peripherals::ParentFolder.new("/") } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - end + let(:folder) { Storages::Peripherals::ParentFolder.new('/') } - describe "#call" do - it "responds with correct parameters" do + describe '#call' do + it 'responds with correct parameters' do expect(described_class).to respond_to(:call) method = described_class.method(:call) - expect(method.parameters).to contain_exactly(%i[keyreq storage], - %i[keyreq auth_strategy], - %i[keyreq folder]) + expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user], %i[keyreq folder]) end - context "with outbound requests successful" do - context "with parent folder being root", vcr: "nextcloud/files_query_root" do + context 'with outbound requests successful' do + context 'with parent folder being root', vcr: 'nextcloud/files_query_root' do # rubocop:disable RSpec/ExampleLength - it "returns a StorageFiles object for root" do - storage_files = described_class.call(storage:, auth_strategy:, folder:).result + it 'returns a StorageFiles object for root' do + storage_files = described_class.call(storage:, user:, folder:).result expect(storage_files).to be_a(Storages::StorageFiles) expect(storage_files.ancestors).to be_empty @@ -67,48 +62,48 @@ expect(storage_files.files.map(&:to_h)) .to eq([ { - id: "172", - name: "Folder", + id: '172', + name: 'Folder', size: 982713473, created_at: nil, - created_by_name: "admin", - last_modified_at: "2023-11-29T15:31:30Z", + created_by_name: 'admin', + last_modified_at: '2023-11-29T15:31:30Z', last_modified_by_name: nil, - location: "/Folder", - mime_type: "application/x-op-directory", + location: '/Folder', + mime_type: 'application/x-op-directory', permissions: %i[readable writeable] }, { - id: "173", - name: "Folder with spaces", + id: '173', + name: 'Folder with spaces', size: 74, created_at: nil, - created_by_name: "admin", - last_modified_at: "2023-11-29T15:42:21Z", + created_by_name: 'admin', + last_modified_at: '2023-11-29T15:42:21Z', last_modified_by_name: nil, - location: "/Folder%20with%20spaces", - mime_type: "application/x-op-directory", + location: '/Folder%20with%20spaces', + mime_type: 'application/x-op-directory', permissions: %i[readable writeable] }, { - id: "211", - name: "Practical_guide_to_BAGGM_Digital.pdf", + id: '211', + name: 'Practical_guide_to_BAGGM_Digital.pdf', size: 154592937, created_at: nil, - created_by_name: "admin", - last_modified_at: "2022-08-09T06:53:12Z", + created_by_name: 'admin', + last_modified_at: '2022-08-09T06:53:12Z', last_modified_by_name: nil, - location: "/Practical_guide_to_BAGGM_Digital.pdf", - mime_type: "application/pdf", + location: '/Practical_guide_to_BAGGM_Digital.pdf', + mime_type: 'application/pdf', permissions: %i[readable writeable] }, { - id: "178", - name: "Readme.md", + id: '178', + name: 'Readme.md', size: 31, created_at: nil, - created_by_name: "admin", - last_modified_at: "2023-11-29T15:29:16Z", + created_by_name: 'admin', + last_modified_at: '2023-11-29T15:29:16Z', last_modified_by_name: nil, - location: "/Readme.md", - mime_type: "text/markdown", + location: '/Readme.md', + mime_type: 'text/markdown', permissions: %i[readable writeable] } ]) @@ -116,88 +111,88 @@ # rubocop:enable RSpec/ExampleLength end - context "with a given parent folder", vcr: "nextcloud/files_query_parent_folder" do - let(:folder) { Storages::Peripherals::ParentFolder.new("/Folder with spaces/New Requests") } + context 'with a given parent folder', vcr: 'nextcloud/files_query_parent_folder' do + let(:folder) { Storages::Peripherals::ParentFolder.new('/Folder with spaces/New Requests') } subject do - described_class.call(storage:, auth_strategy:, folder:).result + described_class.call(storage:, user:, folder:).result end # rubocop:disable RSpec/ExampleLength - it "returns the files content" do + it 'returns the files content' do expect(subject.files.size).to eq(2) expect(subject.files.map(&:to_h)) .to eq([ { - id: "181", - name: "request_001.md", + id: '181', + name: 'request_001.md', size: 48, created_at: nil, - created_by_name: "admin", - last_modified_at: "2023-11-29T15:35:25Z", + created_by_name: 'admin', + last_modified_at: '2023-11-29T15:35:25Z', last_modified_by_name: nil, - location: "/Folder%20with%20spaces/New%20Requests/request_001.md", - mime_type: "text/markdown", + location: '/Folder%20with%20spaces/New%20Requests/request_001.md', + mime_type: 'text/markdown', permissions: %i[readable writeable] }, { - id: "182", - name: "request_002.md", + id: '182', + name: 'request_002.md', size: 26, created_at: nil, - created_by_name: "admin", - last_modified_at: "2023-11-29T15:35:34Z", + created_by_name: 'admin', + last_modified_at: '2023-11-29T15:35:34Z', last_modified_by_name: nil, - location: "/Folder%20with%20spaces/New%20Requests/request_002.md", - mime_type: "text/markdown", + location: '/Folder%20with%20spaces/New%20Requests/request_002.md', + mime_type: 'text/markdown', permissions: %i[readable writeable] } ]) end # rubocop:enable RSpec/ExampleLength - it "returns ancestors with a forged id" do + it 'returns ancestors with a forged id' do expect(subject.ancestors.map { |a| { id: a.id, name: a.name, location: a.location } }) .to eq([ { - id: "8a5edab282632443219e051e4ade2d1d5bbc671c781051bf1437897cbdfea0f1", - name: "Root", - location: "/" + id: '8a5edab282632443219e051e4ade2d1d5bbc671c781051bf1437897cbdfea0f1', + name: 'Root', + location: '/' }, { - id: "c8776f1f6dd36c023c6615d39f01a71d68dd1707b232115b7a4f58bc6da94e2e", - name: "Folder with spaces", - location: "/Folder%20with%20spaces" + id: 'c8776f1f6dd36c023c6615d39f01a71d68dd1707b232115b7a4f58bc6da94e2e', + name: 'Folder with spaces', + location: '/Folder%20with%20spaces' } ]) end - it "returns the parent itself" do - expect(subject.parent.id).to eq("180") - expect(subject.parent.name).to eq("New Requests") - expect(subject.parent.location).to eq("/Folder%20with%20spaces/New%20Requests") + it 'returns the parent itself' do + expect(subject.parent.id).to eq('180') + expect(subject.parent.name).to eq('New Requests') + expect(subject.parent.location).to eq('/Folder%20with%20spaces/New%20Requests') end end - context "with parent folder being empty", vcr: "nextcloud/files_query_empty_folder" do - let(:folder) { Storages::Peripherals::ParentFolder.new("/Folder/empty") } + context 'with parent folder being empty', vcr: 'nextcloud/files_query_empty_folder' do + let(:folder) { Storages::Peripherals::ParentFolder.new('/Folder/empty') } - it "returns an empty StorageFiles object with parent and ancestors" do - storage_files = described_class.call(storage:, auth_strategy:, folder:).result + it 'returns an empty StorageFiles object with parent and ancestors' do + storage_files = described_class.call(storage:, user:, folder:).result expect(storage_files).to be_a(Storages::StorageFiles) expect(storage_files.files).to be_empty - expect(storage_files.parent.id).to eq("174") + expect(storage_files.parent.id).to eq('174') expect(storage_files.ancestors.map(&:name)).to eq(%w[Root Folder]) end end end - context "with not existent parent folder", vcr: "nextcloud/files_query_invalid_parent" do - let(:folder) { Storages::Peripherals::ParentFolder.new("/I/just/made/that/up") } + context 'with not existent parent folder', vcr: 'nextcloud/files_query_invalid_parent' do + let(:folder) { Storages::Peripherals::ParentFolder.new('/I/just/made/that/up') } - it "must return not found" do - result = described_class.call(storage:, auth_strategy:, folder:) + it 'must return not found' do + result = described_class.call(storage:, user:, folder:) expect(result).to be_failure - expect(result.error_source).to be(described_class) + expect(result.error_source).to be_a(described_class) result.match( on_failure: ->(error) { expect(error.code).to eq(:not_found) }, @@ -205,5 +200,39 @@ ) end end + + context 'with invalid oauth token', vcr: 'nextcloud/files_query_invalid_token' do + before do + token = build_stubbed(:oauth_client_token, oauth_client: storage.oauth_client) + allow(Storages::Peripherals::StorageInteraction::Nextcloud::Util) + .to receive(:token).and_yield(token) + end + + it 'must return unauthorized' do + result = described_class.call(storage:, user:, folder:) + expect(result).to be_failure + expect(result.error_source).to be_a(described_class) + + result.match( + on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, + on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } + ) + end + end + + context 'with not existent oauth token' do + let(:user_without_token) { create(:user) } + + it 'must return unauthorized' do + result = described_class.call(storage:, user: user_without_token, folder:) + expect(result).to be_failure + expect(result.error_source).to be_a(OAuthClients::ConnectionManager) + + result.match( + on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, + on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } + ) + end + end end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_file_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_file_link_query_spec.rb index 584f7ce1ee71..45a35f69b072 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_file_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_file_link_query_spec.rb @@ -28,35 +28,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::OpenFileLinkQuery do - let(:storage) { create(:nextcloud_storage, host: "https://example.com") } + let(:storage) { create(:nextcloud_storage, host: 'https://example.com') } let(:user) { create(:user) } - let(:file_id) { "1337" } + let(:file_id) { '1337' } - it "responds to .call" do + it 'responds to .call' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user], %i[keyreq file_id], %i[key open_location]) end - it "returns the url for opening the file on storage" do + it 'returns the url for opening the file on storage' do url = described_class.call(storage:, user:, file_id:).result expect(url).to eq("#{storage.host}/index.php/f/#{file_id}?openfile=1") end - it "returns the url for opening the file's location on storage" do + it 'returns the url for opening the file\'s location on storage' do url = described_class.call(storage:, user:, file_id:, open_location: true).result expect(url).to eq("#{storage.host}/index.php/f/#{file_id}?openfile=0") end - context "with a storage with host url with a sub path" do - let(:storage) { create(:nextcloud_storage, host: "https://example.com/html") } + context 'with a storage with host url with a sub path' do + let(:storage) { create(:nextcloud_storage, host: 'https://example.com/html') } - it "returns the url for opening the file on storage" do + it 'returns the url for opening the file on storage' do url = described_class.call(storage:, user:, file_id:).result expect(url).to eq("#{storage.host}/index.php/f/#{file_id}?openfile=1") end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query_spec.rb index a4a6c1d291b6..7f22330e23c4 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/open_storage_query_spec.rb @@ -28,29 +28,29 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::OpenStorageQuery do - let(:storage) { create(:nextcloud_storage, host: "https://example.com") } + let(:storage) { create(:nextcloud_storage, host: 'https://example.com') } let(:user) { create(:user) } - it "responds to .call" do + it 'responds to .call' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user]) end - it "returns the url for opening the file on storage" do + it 'returns the url for opening the file on storage' do url = described_class.call(storage:, user:).result expect(url).to eq("#{storage.host}/index.php/apps/files") end - context "with a storage with host url with a sub path" do - let(:storage) { create(:nextcloud_storage, host: "https://example.com/html") } + context 'with a storage with host url with a sub path' do + let(:storage) { create(:nextcloud_storage, host: 'https://example.com/html') } - it "returns the url for opening the file on storage" do + it 'returns the url for opening the file on storage' do url = described_class.call(storage:, user:).result expect(url).to eq("#{storage.host}/index.php/apps/files") end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb index 30344962814c..469863310eab 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/upload_link_query_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::UploadLinkQuery, :webmock do @@ -38,7 +38,7 @@ let(:url) { storage.uri.to_s } let(:query_payload) { Struct.new(:parent).new(42) } - let(:upload_token) { "valid-token" } + let(:upload_token) { 'valid-token' } subject(:query) { described_class } @@ -49,14 +49,14 @@ .to_return(status: 200, body: { token: upload_token, expires_on: 1673883865 }.to_json) end - it ".call requires 3 arguments: storage, user, and data" do + it '.call requires 3 arguments: storage, user, and data' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user], %i[keyreq data]) end - it "must return an upload link URL" do + it 'must return an upload link URL' do link = query.call(storage:, user:, data: query_payload).result expect(link.destination.path).to eql("/index.php/apps/integration_openproject/direct-upload/#{upload_token}") expect(link.destination.host).to eql(URI(url).host) @@ -66,7 +66,7 @@ expect(link.method).to eq(:post) end - shared_examples_for "outbound is failing" do |code, symbol| + shared_examples_for 'outbound is failing' do |code, symbol| describe "with outbound request returning #{code}" do before do stub_request(:post, "#{url}index.php/apps/integration_openproject/direct-upload-token").and_return(status: code) @@ -81,8 +81,8 @@ end end - include_examples "outbound is failing", 400, :error - include_examples "outbound is failing", 401, :unauthorized - include_examples "outbound is failing", 404, :not_found - include_examples "outbound is failing", 500, :error + include_examples 'outbound is failing', 400, :error + include_examples 'outbound is failing', 401, :unauthorized + include_examples 'outbound is failing', 404, :not_found + include_examples 'outbound is failing', 500, :error end diff --git a/db/migrate/20240306154737_create_index_good_job_jobs_for_candidate_lookup.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/util_spec.rb similarity index 61% rename from db/migrate/20240306154737_create_index_good_job_jobs_for_candidate_lookup.rb rename to modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/util_spec.rb index 318fc758d4e7..d84cc7a30f96 100644 --- a/db/migrate/20240306154737_create_index_good_job_jobs_for_candidate_lookup.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/nextcloud/util_spec.rb @@ -28,20 +28,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CreateIndexGoodJobJobsForCandidateLookup < ActiveRecord::Migration[7.1] - disable_ddl_transaction! +require 'spec_helper' +require_module_spec_helper - def change - reversible do |dir| - dir.up do - # Ensure this incremental update migration is idempotent - # with monolithic install migration. - return if connection.index_name_exists?(:good_jobs, :index_good_job_jobs_for_candidate_lookup) +RSpec.describe Storages::Peripherals::StorageInteraction::Nextcloud::Util do + describe '.basic_auth_header' do + subject { described_class.basic_auth_header(username, password) } + + context 'when password is more than 60 symbols' do + let(:username) { 'Dart Scuadron' } + let(:password) { "#{'StarWars' * 10}Forever!" } + + it 'has no newline characters in encoded string' do + expect(subject['Authorization']).not_to match(/\n/) + expect(subject).to eq( + { + "Authorization" => "Basic RGFydCBTY3VhZHJvbjpTdGFyV2Fyc1N0YXJXYXJzU3Rhcl" \ + "dhcnNTdGFyV2Fyc1N0YXJXYXJzU3RhcldhcnNTdGFyV2Fyc1N0YX" \ + "JXYXJzU3RhcldhcnNTdGFyV2Fyc0ZvcmV2ZXIh" + } + ) end end - - add_index :good_jobs, [:priority, :created_at], order: { priority: "ASC NULLS LAST", created_at: :asc }, - where: "finished_at IS NULL", name: :index_good_job_jobs_for_candidate_lookup, - algorithm: :concurrently end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/create_folder_command_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/create_folder_command_spec.rb index 08ade61f2d21..dc60261e6187 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/create_folder_command_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/create_folder_command_spec.rb @@ -28,34 +28,34 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::CreateFolderCommand, :vcr, :webmock do shared_let(:storage) { create(:sharepoint_dev_drive_storage) } - let(:delete_command) { Storages::Peripherals::Registry.resolve("one_drive.commands.delete_folder") } - let(:folder_path) { "Földer CreatedBy Çommand" } + let(:delete_command) { Storages::Peripherals::Registry.resolve('one_drive.commands.delete_folder') } + let(:folder_path) { 'Földer CreatedBy Çommand' } shared_let(:original_ids) do WebMock.enable! && VCR.turn_on! - VCR.use_cassette("one_drive/create_folder_setup") { original_files } + VCR.use_cassette('one_drive/create_folder_setup') { original_files } ensure VCR.turn_off! && WebMock.disable! end - it "responds to .call with correct parameters" do + it 'responds to .call with correct parameters' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq folder_path]) end - it "is registered as create_folder" do - expect(Storages::Peripherals::Registry.resolve("one_drive.commands.create_folder")).to eq(described_class) + it 'is registered as create_folder' do + expect(Storages::Peripherals::Registry.resolve('one_drive.commands.create_folder')).to eq(described_class) end - it "creates a folder and responds with a success", vcr: "one_drive/create_folder_base" do + it 'creates a folder and responds with a success', vcr: 'one_drive/create_folder_base' do result = described_class.call(storage:, folder_path:) expect(result).to be_success expect(result.message).to eq("Folder was successfully created.") @@ -65,7 +65,7 @@ delete_created_files end - it "creates a sub folder", vcr: "one_drive/create_folder_sub_folder" do + it 'creates a sub folder', vcr: 'one_drive/create_folder_sub_folder' do folder = described_class.call(storage:, folder_path:).result sub_folder = described_class.new(storage).call(folder_path: "Another Folder", parent_location: folder.id).result @@ -75,8 +75,8 @@ delete_created_files end - context "when the folder already exists", vcr: "one_drive/create_folder_already_exists" do - it "returns a failure" do + context 'when the folder already exists', vcr: 'one_drive/create_folder_already_exists' do + it 'returns a failure' do described_class.call(storage:, folder_path:) result = described_class.call(storage:, folder_path:) @@ -85,7 +85,7 @@ error_data = result.errors.data expect(error_data.payload.status).to eq(409) - expect(error_data.payload.json.dig("error", "code")).to match /nameAlreadyExists/ + expect(error_data.payload.json.dig('error', 'code')).to match /nameAlreadyExists/ ensure delete_created_files end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/delete_folder_command_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/delete_folder_command_spec.rb index d03e471382e2..ecd8d7b52d41 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/delete_folder_command_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/delete_folder_command_spec.rb @@ -28,35 +28,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::DeleteFolderCommand, :vcr, :webmock do let(:storage) { create(:sharepoint_dev_drive_storage) } - it "is registered as commands.one_drive.delete_folder" do - expect(Storages::Peripherals::Registry.resolve("one_drive.commands.delete_folder")).to eq(described_class) + it 'is registered as commands.one_drive.delete_folder' do + expect(Storages::Peripherals::Registry.resolve('one_drive.commands.delete_folder')).to eq(described_class) end - it ".call requires storage and location as keyword arguments" do + it '.call requires storage and location as keyword arguments' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq location]) end - it "deletes a folder", vcr: "one_drive/delete_folder" do + it 'deletes a folder', vcr: 'one_drive/delete_folder' do create_result = Storages::Peripherals::Registry - .resolve("one_drive.commands.create_folder") - .call(storage:, folder_path: "To Be Deleted Soon") + .resolve('one_drive.commands.create_folder') + .call(storage:, folder_path: 'To Be Deleted Soon') folder = create_result.result expect(described_class.call(storage:, location: folder.id)).to be_success end - it "when the folder is not found, returns a failure", vcr: "one_drive/delete_folder_not_found" do - result = described_class.call(storage:, location: "NOT_HERE") + it 'when the folder is not found, returns a failure', vcr: 'one_drive/delete_folder_not_found' do + result = described_class.call(storage:, location: 'NOT_HERE') expect(result).to be_failure expect(result.result).to eq(:not_found) end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/download_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/download_link_query_spec.rb index c46e1a5cae3e..f1c2728e3b2d 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/download_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/download_link_query_spec.rb @@ -28,11 +28,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::DownloadLinkQuery, :webmock do - let(:storage) { create(:one_drive_storage, :with_oauth_client, drive_id: "JUMBLEOFLETTERSANDNUMB3R5") } + let(:storage) { create(:one_drive_storage, :with_oauth_client, drive_id: 'JUMBLEOFLETTERSANDNUMB3R5') } let(:user) { create(:user) } let(:file_link) { create(:file_link) } let(:token) { create(:oauth_client_token, oauth_client: storage.oauth_client, user:) } @@ -42,21 +42,21 @@ before do allow(Storages::Peripherals::StorageInteraction::OneDrive).to receive(:token).and_yield(token) stub_request(:get, "https://graph.microsoft.com/v1.0/drives/#{storage.drive_id}/items/#{file_link.origin_id}/content") - .with(headers: { "Authorization" => "Bearer #{token.access_token}" }) - .and_return(status: 302, body: nil, headers: { "Location" => "https://somecool.link/from/microsoft" }) + .with(headers: { 'Authorization' => "Bearer #{token.access_token}" }) + .and_return(status: 302, body: nil, headers: { 'Location' => 'https://somecool.link/from/microsoft' }) end - it "returns a result with a download url" do + it 'returns a result with a download url' do download_link = download_link_query.call(user:, file_link:) expect(download_link).to be_success - expect(download_link.result).to eq("https://somecool.link/from/microsoft") + expect(download_link.result).to eq('https://somecool.link/from/microsoft') end - it "return an error if any other response is received" do + it 'return an error if any other response is received' do stub_request(:get, "https://graph.microsoft.com/v1.0/drives/#{storage.drive_id}/items/#{file_link.origin_id}/content") - .with(headers: { "Authorization" => "Bearer #{token.access_token}" }) - .and_return(status: 200, body: "") + .with(headers: { 'Authorization' => "Bearer #{token.access_token}" }) + .and_return(status: 200, body: '') download_link = download_link_query.call(user:, file_link:) diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb index ddb07c5c36d6..d3c9a3417663 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_info_query_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::FilesInfoQuery, :vcr, :webmock do @@ -39,17 +39,17 @@ subject { described_class.new(storage) } - describe "#call" do - it "responds with correct parameters" do + describe '#call' do + it 'responds with correct parameters' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user], %i[key file_ids]) end - context "without outbound request involved" do - context "with an empty array of file ids" do - it "returns an empty array" do + context 'without outbound request involved' do + context 'with an empty array of file ids' do + it 'returns an empty array' do result = subject.call(user:, file_ids: []) expect(result).to be_success @@ -57,8 +57,8 @@ end end - context "with nil" do - it "returns an error" do + context 'with nil' do + it 'returns an error' do result = subject.call(user:, file_ids: nil) expect(result).to be_failure @@ -67,8 +67,8 @@ end end - context "with outbound requests successful", vcr: "one_drive/files_info_query_success" do - context "with an array of file ids" do + context 'with outbound requests successful', vcr: 'one_drive/files_info_query_success' do + context 'with an array of file ids' do let(:file_ids) do %w( 01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU @@ -78,7 +78,7 @@ end # rubocop:disable RSpec/ExampleLength - it "must return an array of file information when called" do + it 'must return an array of file information when called' do result = subject.call(user:, file_ids:) expect(result).to be_success @@ -89,55 +89,55 @@ expect(file_infos.map(&:to_h)) .to eq([ { - status: "ok", + status: 'ok', status_code: 200, - id: "01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU", - name: "Folder with spaces", + id: '01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU', + name: 'Folder with spaces', size: 35141, - mime_type: "application/x-op-directory", - created_at: Time.parse("2023-09-26T14:38:57Z"), - last_modified_at: Time.parse("2023-09-26T14:38:57Z"), - owner_name: "Eric Schubert", - owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - last_modified_by_name: "Eric Schubert", - last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + mime_type: 'application/x-op-directory', + created_at: Time.parse('2023-09-26T14:38:57Z'), + last_modified_at: Time.parse('2023-09-26T14:38:57Z'), + owner_name: 'Eric Schubert', + owner_id: '0a0d38a9-a59b-4245-93fa-0d2cf727f17a', + last_modified_by_name: 'Eric Schubert', + last_modified_by_id: '0a0d38a9-a59b-4245-93fa-0d2cf727f17a', permissions: nil, trashed: false, - location: "/Folder with spaces" + location: '/Folder with spaces' }, { - status: "ok", + status: 'ok', status_code: 200, - id: "01AZJL5PJTICED3C5YSVAY6NWTBNA2XERU", - name: "Document.docx", + id: '01AZJL5PJTICED3C5YSVAY6NWTBNA2XERU', + name: 'Document.docx', size: 22514, - mime_type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - created_at: Time.parse("2023-09-26T14:40:58Z"), - last_modified_at: Time.parse("2023-09-26T14:42:03Z"), - owner_name: "Eric Schubert", - owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - last_modified_by_name: "Eric Schubert", - last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + mime_type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + created_at: Time.parse('2023-09-26T14:40:58Z'), + last_modified_at: Time.parse('2023-09-26T14:42:03Z'), + owner_name: 'Eric Schubert', + owner_id: '0a0d38a9-a59b-4245-93fa-0d2cf727f17a', + last_modified_by_name: 'Eric Schubert', + last_modified_by_id: '0a0d38a9-a59b-4245-93fa-0d2cf727f17a', permissions: nil, trashed: false, - location: "/Folder/Document.docx" + location: '/Folder/Document.docx' }, { - status: "ok", + status: 'ok', status_code: 200, - id: "01AZJL5PNCQCEBFI3N7JGZSX5AOX32Z3LA", - name: "NextcloudHub.md", + id: '01AZJL5PNCQCEBFI3N7JGZSX5AOX32Z3LA', + name: 'NextcloudHub.md', size: 1095, - mime_type: "application/octet-stream", - created_at: Time.parse("2023-09-26T14:45:25Z"), - last_modified_at: Time.parse("2023-09-26T14:46:13Z"), - owner_name: "Eric Schubert", - owner_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", - last_modified_by_name: "Eric Schubert", - last_modified_by_id: "0a0d38a9-a59b-4245-93fa-0d2cf727f17a", + mime_type: 'application/octet-stream', + created_at: Time.parse('2023-09-26T14:45:25Z'), + last_modified_at: Time.parse('2023-09-26T14:46:13Z'), + owner_name: 'Eric Schubert', + owner_id: '0a0d38a9-a59b-4245-93fa-0d2cf727f17a', + last_modified_by_name: 'Eric Schubert', + last_modified_by_id: '0a0d38a9-a59b-4245-93fa-0d2cf727f17a', permissions: nil, trashed: false, - location: "/Folder/Subfolder/NextcloudHub.md" + location: '/Folder/Subfolder/NextcloudHub.md' } ]) end, @@ -148,11 +148,11 @@ end end - context "with one outbound request returning not found", vcr: "one_drive/files_info_query_one_not_found" do - context "with an array of file ids" do + context 'with one outbound request returning not found', vcr: 'one_drive/files_info_query_one_not_found' do + context 'with an array of file ids' do let(:file_ids) { %w[01AZJL5PJTICED3C5YSVAY6NWTBNA2XERU not_existent] } - it "must return an array of file information when called" do + it 'must return an array of file information when called' do result = subject.call(user:, file_ids:) expect(result).to be_success @@ -160,8 +160,8 @@ on_success: ->(file_infos) do expect(file_infos.size).to eq(2) expect(file_infos).to all(be_a(Storages::StorageFileInfo)) - expect(file_infos[1].id).to eq("not_existent") - expect(file_infos[1].status).to eq("itemNotFound") + expect(file_infos[1].id).to eq('not_existent') + expect(file_infos[1].status).to eq('itemNotFound') expect(file_infos[1].status_code).to eq(404) end, on_failure: ->(error) { fail "Expected success, got #{error}" } @@ -170,7 +170,7 @@ end end - context "with invalid oauth token", vcr: "one_drive/files_info_query_invalid_token" do + context 'with invalid oauth token', vcr: 'one_drive/files_info_query_invalid_token' do before do token = build_stubbed(:oauth_client_token, oauth_client: storage.oauth_client) allow(Storages::Peripherals::StorageInteraction::OneDrive::Util) @@ -178,10 +178,10 @@ .and_yield(token) end - context "with an array of file ids" do + context 'with an array of file ids' do let(:file_ids) { %w[01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU] } - it "must return an array of file information when called" do + it 'must return an array of file information when called' do result = subject.call(user:, file_ids:) expect(result).to be_success @@ -189,8 +189,8 @@ on_success: ->(file_infos) do expect(file_infos.size).to eq(1) expect(file_infos).to all(be_a(Storages::StorageFileInfo)) - expect(file_infos[0].id).to eq("01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU") - expect(file_infos[0].status).to eq("InvalidAuthenticationToken") + expect(file_infos[0].id).to eq('01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU') + expect(file_infos[0].status).to eq('InvalidAuthenticationToken') expect(file_infos[0].status_code).to eq(401) end, on_failure: ->(error) { fail "Expected success, got #{error}" } @@ -199,11 +199,11 @@ end end - context "with not existent oauth token" do + context 'with not existent oauth token' do let(:file_ids) { %w[01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU] } let(:user_without_token) { create(:user) } - it "must return unauthorized when called" do + it 'must return unauthorized when called' do result = subject.call(user: user_without_token, file_ids:) expect(result).to be_failure expect(result.error_source).to be_a(OAuthClients::ConnectionManager) @@ -215,17 +215,17 @@ end end - context "with network errors" do + context 'with network errors' do let(:file_ids) { %w[01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU] } before do - request = HTTPX::Request.new(:get, "https://my.timeout.org/") - httpx_double = class_double(HTTPX, get: HTTPX::ErrorResponse.new(request, "Timeout happens", {})) + request = HTTPX::Request.new(:get, 'https://my.timeout.org/') + httpx_double = class_double(HTTPX, get: HTTPX::ErrorResponse.new(request, 'Timeout happens', {})) allow(OpenProject).to receive(:httpx).and_return(httpx_double) end - it "must return an array of file information when called" do + it 'must return an array of file information when called' do result = subject.call(user:, file_ids:) expect(result).to be_success @@ -233,8 +233,8 @@ on_success: ->(file_infos) do expect(file_infos.size).to eq(1) expect(file_infos).to all(be_a(Storages::StorageFileInfo)) - expect(file_infos[0].id).to eq("01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU") - expect(file_infos[0].status).to eq("Timeout happens") + expect(file_infos[0].id).to eq('01AZJL5PKU2WV3U3RKKFF2A7ZCWVBXRTEU') + expect(file_infos[0].status).to eq('Timeout happens') expect(file_infos[0].status_code).to eq(500) end, on_failure: ->(error) { fail "Expected success, got #{error}" } diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb index b2df40f1df66..1d84e155e20c 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/files_query_spec.rb @@ -37,22 +37,19 @@ let(:user) { create(:user) } let(:storage) { create(:sharepoint_dev_drive_storage, oauth_client_token_user: user) } let(:folder) { Storages::Peripherals::ParentFolder.new('/') } - let(:auth_strategy) do - Storages::Peripherals::StorageInteraction::AuthenticationStrategies::OAuthUserToken.strategy.with_user(user) - end describe '#call' do it 'responds with correct parameters' do expect(described_class).to respond_to(:call) method = described_class.method(:call) - expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq auth_strategy], %i[keyreq folder]) + expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user], %i[keyreq folder]) end context 'with outbound requests successful' do context 'with parent folder being root', vcr: 'one_drive/files_query_root' do it 'returns a StorageFiles object for root' do - storage_files = described_class.call(storage:, auth_strategy:, folder:).result + storage_files = described_class.call(storage:, user:, folder:).result expect(storage_files).to be_a(Storages::StorageFiles) expect(storage_files.ancestors).to be_empty @@ -76,7 +73,7 @@ let(:folder) { Storages::Peripherals::ParentFolder.new('/Folder/Subfolder') } subject do - described_class.call(storage:, auth_strategy:, folder:).result + described_class.call(storage:, user:, folder:).result end # rubocop:disable RSpec/ExampleLength @@ -136,7 +133,7 @@ let(:folder) { Storages::Peripherals::ParentFolder.new('/Folder with spaces/very empty folder') } it 'returns an empty StorageFiles object with parent and ancestors' do - storage_files = described_class.call(storage:, auth_strategy:, folder:).result + storage_files = described_class.call(storage:, user:, folder:).result expect(storage_files).to be_a(Storages::StorageFiles) expect(storage_files.files).to be_empty @@ -150,7 +147,7 @@ let(:folder) { Storages::Peripherals::ParentFolder.new('/Folder/Ümlæûts') } it 'returns the correct StorageFiles object' do - storage_files = described_class.call(storage:, auth_strategy:, folder:).result + storage_files = described_class.call(storage:, user:, folder:).result expect(storage_files).to be_a(Storages::StorageFiles) expect(storage_files.parent.id).to eq('01AZJL5PNQYF5NM3KWYNA3RJHJIB2XMMMB') @@ -179,7 +176,7 @@ let(:folder) { Storages::Peripherals::ParentFolder.new('/I/just/made/that/up') } it 'must return not found' do - result = described_class.call(storage:, auth_strategy:, folder:) + result = described_class.call(storage:, user:, folder:) expect(result).to be_failure expect(result.error_source).to be_a(described_class) @@ -189,5 +186,56 @@ ) end end + + context 'with invalid oauth token', vcr: 'one_drive/files_query_invalid_token' do + before do + token = build_stubbed(:oauth_client_token, oauth_client: storage.oauth_client) + allow(Storages::Peripherals::StorageInteraction::OneDrive::Util) + .to receive(:using_user_token) + .and_yield(token) + end + + it 'must return unauthorized' do + result = described_class.call(storage:, user:, folder:) + expect(result).to be_failure + expect(result.error_source).to be_a(described_class) + + result.match( + on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, + on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } + ) + end + end + + context 'with not existent oauth token' do + let(:user_without_token) { create(:user) } + + it 'must return unauthorized' do + result = described_class.call(storage:, user: user_without_token, folder:) + expect(result).to be_failure + expect(result.error_source).to be_a(OAuthClients::ConnectionManager) + + result.match( + on_failure: ->(error) { expect(error.code).to eq(:unauthorized) }, + on_success: ->(file_infos) { fail "Expected failure, got #{file_infos}" } + ) + end + end + + context 'with network errors' do + before do + request = HTTPX::Request.new(:get, 'https://my.timeout.org/') + httpx_double = class_double(HTTPX, get: HTTPX::ErrorResponse.new(request, 'Timeout happens', {})) + + allow(OpenProject).to receive(:httpx).and_return(httpx_double) + end + + it 'must return an error with wrapped network error response' do + error = described_class.call(storage:, user:, folder:) + expect(error).to be_failure + expect(error.result).to eq(:error) + expect(error.error_payload).to be_a(HTTPX::ErrorResponse) + end + end end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/rename_file_command_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/rename_file_command_spec.rb index 7109f67a52d7..f485a4d961c6 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/rename_file_command_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/rename_file_command_spec.rb @@ -28,31 +28,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::RenameFileCommand, :webmock do let(:storage) { create(:sharepoint_dev_drive_storage) } let(:folder) do Storages::Peripherals::Registry - .resolve("one_drive.commands.create_folder") + .resolve('one_drive.commands.create_folder') .call(storage:, folder_path: "Wrong Name") end subject(:command) { described_class.new(storage) } - it "is registered as rename_file" do - expect(Storages::Peripherals::Registry.resolve("one_drive.commands.rename_file")).to eq(described_class) + it 'is registered as rename_file' do + expect(Storages::Peripherals::Registry.resolve('one_drive.commands.rename_file')).to eq(described_class) end - it "responds to .call with correct parameters" do + it 'responds to .call with correct parameters' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq source], %i[keyreq target]) end - it "renames a folder", vcr: "one_drive/rename_folder_success" do + it 'renames a folder', vcr: 'one_drive/rename_folder_success' do file_info = folder.result result = command.call(source: file_info.id, target: "My Project No. 1 (19)") @@ -70,7 +70,7 @@ def delete_folder(folder_id) Storages::Peripherals::Registry - .resolve("one_drive.commands.delete_folder") + .resolve('one_drive.commands.delete_folder') .call(storage:, location: folder_id) end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/set_permissions_command_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/set_permissions_command_spec.rb index 8769edf4b867..b341f70bff59 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/set_permissions_command_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/set_permissions_command_spec.rb @@ -28,116 +28,116 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::SetPermissionsCommand, :webmock do let(:storage) do create(:sharepoint_dev_drive_storage, - drive_id: "b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy") + drive_id: 'b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy') end let(:permissions_command) { described_class.new(storage) } let(:folder) do Storages::Peripherals::Registry - .resolve("one_drive.commands.create_folder") + .resolve('one_drive.commands.create_folder') .call(storage:, folder_path: "Permission Test Folder") .result end let(:path) { folder.id } - it "is registered at commands.one_drive.set_permissions" do - expect(Storages::Peripherals::Registry.resolve("one_drive.commands.set_permissions")).to eq(described_class) + it 'is registered at commands.one_drive.set_permissions' do + expect(Storages::Peripherals::Registry.resolve('one_drive.commands.set_permissions')).to eq(described_class) end - it "responds to .call with storage, path and permissions keyword args" do + it 'responds to .call with storage, path and permissions keyword args' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq path], %i[keyreq permissions]) end - describe "#call" do + describe '#call' do after do Storages::Peripherals::Registry - .resolve("one_drive.commands.delete_folder") + .resolve('one_drive.commands.delete_folder') .call(storage:, location: path) end - context "when trying to access a non-existing driveItem" do - it "returns a failure", vcr: "one_drive/set_permissions_not_found_folder" do - result = permissions_command.call(path: "THIS_IS_NOT_THE_FOLDER_YOURE_LOOKING_FOR", permissions: { write: [] }) + context 'when trying to access a non-existing driveItem' do + it 'returns a failure', vcr: 'one_drive/set_permissions_not_found_folder' do + result = permissions_command.call(path: 'THIS_IS_NOT_THE_FOLDER_YOURE_LOOKING_FOR', permissions: { write: [] }) expect(result).to be_failure expect(result.result).to eq(:not_found) end end - context "when a permission set already exists" do - it "replaces the write permission grant with the provided list", - vcr: "one_drive/set_permissions_replace_permissions_write" do - permissions_command.call(path:, permissions: { write: ["84acc1d5-61be-470b-9d79-0d1f105c2c5f"] }) - expect(user_list("write")).to match_array("84acc1d5-61be-470b-9d79-0d1f105c2c5f") + context 'when a permission set already exists' do + it 'replaces the write permission grant with the provided list', + vcr: 'one_drive/set_permissions_replace_permissions_write' do + permissions_command.call(path:, permissions: { write: ['84acc1d5-61be-470b-9d79-0d1f105c2c5f'] }) + expect(user_list('write')).to match_array('84acc1d5-61be-470b-9d79-0d1f105c2c5f') - permissions_command.call(path:, permissions: { write: ["d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce"] }) - expect(user_list("write")).to match_array("d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce") + permissions_command.call(path:, permissions: { write: ['d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce'] }) + expect(user_list('write')).to match_array('d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce') end - it "replaces the read permission grant with the provided list", - vcr: "one_drive/set_permissions_replace_permissions_read" do - permissions_command.call(path:, permissions: { read: ["84acc1d5-61be-470b-9d79-0d1f105c2c5f"] }) - expect(user_list("read")).to match_array("84acc1d5-61be-470b-9d79-0d1f105c2c5f") + it 'replaces the read permission grant with the provided list', + vcr: 'one_drive/set_permissions_replace_permissions_read' do + permissions_command.call(path:, permissions: { read: ['84acc1d5-61be-470b-9d79-0d1f105c2c5f'] }) + expect(user_list('read')).to match_array('84acc1d5-61be-470b-9d79-0d1f105c2c5f') - permissions_command.call(path:, permissions: { read: ["d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce"] }) - expect(user_list("read")).to match_array("d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce") + permissions_command.call(path:, permissions: { read: ['d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce'] }) + expect(user_list('read')).to match_array('d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce') end end - context "when no expected permission exists" do - it "creates the write permission", vcr: "one_drive/set_permissions_create_permission_write" do + context 'when no expected permission exists' do + it 'creates the write permission', vcr: 'one_drive/set_permissions_create_permission_write' do current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).not_to include("write") + expect(current_roles).not_to include('write') - permissions_command.call(path:, permissions: { write: ["d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce"] }) + permissions_command.call(path:, permissions: { write: ['d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce'] }) current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).to include("write") + expect(current_roles).to include('write') end - it "creates the read permission", vcr: "one_drive/set_permissions_create_permission_read" do + it 'creates the read permission', vcr: 'one_drive/set_permissions_create_permission_read' do current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).not_to include("read") + expect(current_roles).not_to include('read') - permissions_command.call(path:, permissions: { read: ["d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce"] }) + permissions_command.call(path:, permissions: { read: ['d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce'] }) current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).to include("read") + expect(current_roles).to include('read') end end - context "when there are no user to set permissions" do - it "deletes the write permission", vcr: "one_drive/set_permissions_delete_permission_write" do - permissions_command.call(path:, permissions: { write: ["d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce"] }) + context 'when there are no user to set permissions' do + it 'deletes the write permission', vcr: 'one_drive/set_permissions_delete_permission_write' do + permissions_command.call(path:, permissions: { write: ['d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce'] }) current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).to include("write") + expect(current_roles).to include('write') permissions_command.call(path:, permissions: { write: [] }) current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).not_to include("write") + expect(current_roles).not_to include('write') end - it "deletes the read permission", vcr: "one_drive/set_permissions_delete_permission_read" do - permissions_command.call(path:, permissions: { read: ["d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce"] }) + it 'deletes the read permission', vcr: 'one_drive/set_permissions_delete_permission_read' do + permissions_command.call(path:, permissions: { read: ['d6e00f6d-1ae7-43e6-b0af-15d99a56d4ce'] }) current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).to include("read") + expect(current_roles).to include('read') permissions_command.call(path:, permissions: { read: [] }) current_roles = remote_permissions.map { |permission| permission[:roles].first } - expect(current_roles).not_to include("read") + expect(current_roles).not_to include('read') end end end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb index 0b36c3d23183..2ea2acbe02af 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/upload_link_query_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::UploadLinkQuery, :webmock do - let(:storage) { create(:one_drive_storage, :with_oauth_client, drive_id: "b!~bunchOfLettersAndNumb3rs") } + let(:storage) { create(:one_drive_storage, :with_oauth_client, drive_id: 'b!~bunchOfLettersAndNumb3rs') } let(:token) { create(:oauth_client_token, oauth_client: storage.oauth_client) } let(:user) { token.user } # Need to verify the actual object - let(:query_payload) { { "parent" => "LFHLUDSILANC", "file_name" => "it_is_a_trap.flac" } } + let(:query_payload) { { 'parent' => 'LFHLUDSILANC', 'file_name' => 'it_is_a_trap.flac' } } subject(:upload_query) { described_class.new(storage) } @@ -46,31 +46,31 @@ :post, "https://graph.microsoft.com/v1.0/drives/b!~bunchOfLettersAndNumb3rs/items/LFHLUDSILANC:/it_is_a_trap.flac:/createUploadSession" ).with( - headers: { "Authorization" => "Bearer #{token.access_token}", "Content-Type" => "application/json" }, - body: { item: { "@microsoft.graph.conflictBehavior" => "rename", name: query_payload["file_name"] } } + headers: { 'Authorization' => "Bearer #{token.access_token}", 'Content-Type' => 'application/json' }, + body: { item: { "@microsoft.graph.conflictBehavior" => "rename", name: query_payload['file_name'] } } ).to_return( status: 200, - headers: { "Content-Type" => "application/json" }, + headers: { 'Content-Type' => 'application/json' }, body: { uploadUrl: "https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337", expirationDateTime: "2015-01-29T09:21:55.523Z" }.to_json ) end - it ".call requires 3 arguments: storage, user, and data" do + it '.call requires 3 arguments: storage, user, and data' do expect(described_class).to respond_to(:call) method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[keyreq storage], %i[keyreq user], %i[keyreq data]) end - it "must return an upload link URL" do + it 'must return an upload link URL' do link = upload_query.call(user:, data: query_payload).result expect(link.destination).not_to be_nil expect(link.method).to eq(:put) end - shared_examples_for "outbound is failing" do |code, symbol| + shared_examples_for 'outbound is failing' do |code, symbol| describe "with outbound request returning #{code}" do before do stub_request( @@ -87,8 +87,8 @@ end end - include_examples "outbound is failing", 400, :error - include_examples "outbound is failing", 401, :unauthorized - include_examples "outbound is failing", 404, :not_found - include_examples "outbound is failing", 500, :error + include_examples 'outbound is failing', 400, :error + include_examples 'outbound is failing', 401, :unauthorized + include_examples 'outbound is failing', 404, :not_found + include_examples 'outbound is failing', 500, :error end diff --git a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/util_spec.rb b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/util_spec.rb index 8919c7aeb761..28a3795fa225 100644 --- a/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/util_spec.rb +++ b/modules/storages/spec/common/storages/peripherals/storage_interaction/one_drive/util_spec.rb @@ -28,45 +28,45 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Peripherals::StorageInteraction::OneDrive::Util do let(:storage) { create(:sharepoint_dev_drive_storage) } - describe ".using_admin_token" do - it "return a httpx session with an authorization header", vcr: "one_drive/utils_access_tokens" do + describe '.using_admin_token' do + it 'return a httpx session with an authorization header', vcr: 'one_drive/utils_access_tokens' do described_class.using_admin_token(storage) do |http| expect(http).to be_a(HTTPX::Session) - authorization_header = extract_headers(http)["authorization"] + authorization_header = extract_headers(http)['authorization'] expect(authorization_header).not_to be_nil expect(authorization_header).to match /Bearer .+$/ end end - it "caches the token", vcr: "one_drive/utils_access_token" do + it 'caches the token', vcr: 'one_drive/utils_access_token' do described_class.using_admin_token(storage) do |http| - cached = Rails.cache.fetch("storage.#{storage.id}.access_token") { fail "No value found in the cache" } - token = extract_headers(http)["authorization"].split.last + cached = Rails.cache.fetch("storage.#{storage.id}.access_token") { fail 'No value found in the cache' } + token = extract_headers(http)['authorization'].split.last expect(cached.result).not_to be_nil expect(cached.result.access_token).to eq(token) end end - context "when getting the token fails" do - it "returns a ServiceResult.failure", vcr: "one_drive/util_access_token_failure" do - storage.oauth_client.update(client_secret: "this_is_wrong") + context 'when getting the token fails' do + it 'returns a ServiceResult.failure', vcr: 'one_drive/util_access_token_failure' do + storage.oauth_client.update(client_secret: 'this_is_wrong') - result = described_class.using_admin_token(storage) { |_| fail "this should not run" } + result = described_class.using_admin_token(storage) { |_| fail 'this should not run' } expect(result).to be_failure end - it "does not store data in the cache", vcr: "one_drive/util_access_token_failure" do - storage.oauth_client.update(client_secret: "this_is_wrong") - described_class.using_admin_token(storage) { |_| fail "this should not run" } + it 'does not store data in the cache', vcr: 'one_drive/util_access_token_failure' do + storage.oauth_client.update(client_secret: 'this_is_wrong') + described_class.using_admin_token(storage) { |_| fail 'this should not run' } cached = Rails.cache.fetch("storage.#{storage.id}.access_token") expect(cached).to be_nil diff --git a/modules/storages/spec/components/project_storages/row_component_spec.rb b/modules/storages/spec/components/project_storages/row_component_spec.rb index 94d176a06c2f..b4bc90554af6 100644 --- a/modules/storages/spec/components/project_storages/row_component_spec.rb +++ b/modules/storages/spec/components/project_storages/row_component_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require_relative "../../spec_helper" +require_relative '../../spec_helper' RSpec.describe Storages::ProjectStorages::RowComponent, type: :component do - describe "#button_links" do - context "with non-automatic project storage" do - it "renders edit and delete buttons" do + describe '#button_links' do + context 'with non-automatic project storage' do + it 'renders edit and delete buttons' do project_storage = build_stubbed(:project_storage) expect(project_storage).not_to be_project_folder_automatic @@ -41,14 +41,14 @@ render_inline(component) - expect(page).to have_no_css("a.icon.icon-group") - expect(page).to have_css("a.icon.icon-edit") - expect(page).to have_css("a.icon.icon-delete") + expect(page).to have_no_css('a.icon.icon-group') + expect(page).to have_css('a.icon.icon-edit') + expect(page).to have_css('a.icon.icon-delete') end end - context "with automatic project storage" do - it "renders members connection status, edit and delete buttons" do + context 'with automatic project storage' do + it 'renders members connection status, edit and delete buttons' do project_storage = build_stubbed(:project_storage, :as_automatically_managed) expect(project_storage).to be_project_folder_automatic @@ -57,9 +57,9 @@ render_inline(component) - expect(page).to have_css("a.icon.icon-group") - expect(page).to have_css("a.icon.icon-edit") - expect(page).to have_css("a.icon.icon-delete") + expect(page).to have_css('a.icon.icon-group') + expect(page).to have_css('a.icon.icon-edit') + expect(page).to have_css('a.icon.icon-delete') end end end diff --git a/modules/storages/spec/components/storages/admin/health_status_component_spec.rb b/modules/storages/spec/components/storages/admin/health_status_component_spec.rb index efc6df63df9a..8a3f32857415 100644 --- a/modules/storages/spec/components/storages/admin/health_status_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/health_status_component_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Admin::HealthStatusComponent, type: :component do @@ -39,55 +39,55 @@ render_inline(health_status_component) end - context "with healthy storage" do + context 'with healthy storage' do shared_let(:storage) do travel_to(frozen_date_time) do create(:nextcloud_storage_with_complete_configuration, :as_healthy) end end - it "shows a healthy status" do - expect(page).to have_test_selector("storage-health-label-healthy", text: "Healthy") - expect(page).to have_test_selector("storage-health-checked-at", text: "Last checked 11/28/2023 01:02 AM") + it 'shows a healthy status' do + expect(page).to have_test_selector('storage-health-label-healthy', text: 'Healthy') + expect(page).to have_test_selector('storage-health-checked-at', text: "Last checked 11/28/2023 01:02 AM") end end - context "with storage health pending" do + context 'with storage health pending' do shared_let(:storage) do travel_to(frozen_date_time) do create(:nextcloud_storage_with_complete_configuration) end end - it "shows pending label" do - expect(page).to have_test_selector("storage-health-label-pending", text: "Pending") + it 'shows pending label' do + expect(page).to have_test_selector('storage-health-label-pending', text: 'Pending') end end - context "with unhealthy storage" do + context 'with unhealthy storage' do shared_let(:storage) do travel_to(frozen_date_time) do create(:nextcloud_storage_with_complete_configuration, :as_unhealthy) end end - it "shows an error status" do - expect(page).to have_test_selector("storage-health-label-error", text: "Error") - expect(page).to have_test_selector("storage-health-reason", text: "Error code: description since 11/28/2023 01:02 AM") + it 'shows an error status' do + expect(page).to have_test_selector('storage-health-label-error', text: 'Error') + expect(page).to have_test_selector('storage-health-reason', text: 'Error code: description since 11/28/2023 01:02 AM') end end - context "with unhealthy storage, long reason" do + context 'with unhealthy storage, long reason' do shared_let(:storage) do travel_to(frozen_date_time) do create(:nextcloud_storage_with_complete_configuration, :as_unhealthy_long_reason) end end - it "shows a formatted error reason" do - expect(page).to have_test_selector("storage-health-label-error", text: "Error") - expect(page).to have_test_selector("storage-health-reason", - text: "Unauthorized: Outbound request not authorized since 11/28/2023 01:02 AM") + it 'shows a formatted error reason' do + expect(page).to have_test_selector('storage-health-label-error', text: 'Error') + expect(page).to have_test_selector('storage-health-reason', + text: 'Unauthorized: Outbound request not authorized since 11/28/2023 01:02 AM') end end end diff --git a/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb b/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb index 1ded64dab4f8..3694a38b2013 100644 --- a/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/new_storage_button_component_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Admin::NewStorageButtonComponent, type: :component do @@ -34,9 +34,9 @@ it 'renders a "New Storage" Action Menu' do render_inline(described_class.new) - expect(page).to have_button "Storage", aria: { label: "Add new storage" } + expect(page).to have_button 'Storage', aria: { label: 'Add new storage' } - expect(page).to have_link "Nextcloud", href: select_provider_admin_settings_storages_path(provider: "nextcloud") - expect(page).to have_link "OneDrive/SharePoint", href: select_provider_admin_settings_storages_path(provider: "one_drive") + expect(page).to have_link 'Nextcloud', href: select_provider_admin_settings_storages_path(provider: 'nextcloud') + expect(page).to have_link 'OneDrive/SharePoint', href: select_provider_admin_settings_storages_path(provider: 'one_drive') end end diff --git a/modules/storages/spec/components/storages/admin/oauth_access_grant_nudge_modal_component_spec.rb b/modules/storages/spec/components/storages/admin/oauth_access_grant_nudge_modal_component_spec.rb index d8751f10a29e..03aea4066874 100644 --- a/modules/storages/spec/components/storages/admin/oauth_access_grant_nudge_modal_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/oauth_access_grant_nudge_modal_component_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Admin::OAuthAccessGrantNudgeModalComponent, type: :component do # rubocop:disable RSpec/SpecFilePathFormat @@ -36,52 +36,52 @@ render_inline(oauth_access_grant_nudge_modal_component) end - context "with access pending authorization" do + context 'with access pending authorization' do let(:oauth_access_grant_nudge_modal_component) { described_class.new(project_storage:) } - it "renders the nudge modal" do - expect(page).to have_css('[role="alert"]', text: "One more step...", aria: { live: :assertive }) + it 'renders the nudge modal' do + expect(page).to have_css('[role="alert"]', text: 'One more step...', aria: { live: :assertive }) expect(page).to have_test_selector( - "oauth-access-grant-nudge-modal-body", + 'oauth-access-grant-nudge-modal-body', text: "To get access to the project folder you need to login to #{project_storage.storage.name}.", aria: { hidden: false } ) - expect(page).to have_button("I will do it later") - expect(page).to have_button("Login", aria: { label: "Login to #{project_storage.storage.name}" }) + expect(page).to have_button('I will do it later') + expect(page).to have_button('Login', aria: { label: "Login to #{project_storage.storage.name}" }) end end - context "with access authorized" do + context 'with access authorized' do let(:oauth_access_grant_nudge_modal_component) do described_class.new(project_storage:, authorized: true) end - it "renders a success modal" do + it 'renders a success modal' do expect(page).to have_css( - "h1.sr-only", + 'h1.sr-only', text: "Access granted. You are now ready to use #{project_storage.storage.name}" ) expect(page).to have_test_selector( - "oauth-access-grant-nudge-modal-body", - text: "Access granted", + 'oauth-access-grant-nudge-modal-body', + text: 'Access granted', aria: { hidden: true } ) expect(page).to have_test_selector( - "oauth-access-grant-nudge-modal-body", + 'oauth-access-grant-nudge-modal-body', text: "You are now ready to use #{project_storage.storage.name}", aria: { hidden: true } ) - expect(page).to have_button("Close") + expect(page).to have_button('Close') end end - context "with no project storage" do + context 'with no project storage' do let(:oauth_access_grant_nudge_modal_component) { described_class.new(project_storage: nil) } - it "does not render" do + it 'does not render' do expect(page.text).to be_empty end end diff --git a/modules/storages/spec/components/storages/admin/oauth_client_info_component_spec.rb b/modules/storages/spec/components/storages/admin/oauth_client_info_component_spec.rb index e9942019b621..381532c65a8a 100644 --- a/modules/storages/spec/components/storages/admin/oauth_client_info_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/oauth_client_info_component_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Admin::OAuthClientInfoComponent, type: :component do # rubocop:disable RSpec/SpecFilePathFormat - describe "#edit_icon_button_options" do - context "with oauth client configured" do - it "returns false, does not render view component" do + describe '#edit_icon_button_options' do + context 'with oauth client configured' do + it 'returns false, does not render view component' do storage = build_stubbed(:nextcloud_storage, oauth_client: build_stubbed(:oauth_client)) component = described_class.new(storage:, oauth_client: storage.oauth_client) @@ -46,8 +46,8 @@ end end - context "without oauth client" do - it "returns true, renders view component" do + context 'without oauth client' do + it 'returns true, renders view component' do storage = build_stubbed(:nextcloud_storage) component = described_class.new(storage:, oauth_client: nil) diff --git a/modules/storages/spec/components/storages/admin/storage_list_component_spec.rb b/modules/storages/spec/components/storages/admin/storage_list_component_spec.rb index 22ca86a8eb87..dd688c6d41b6 100644 --- a/modules/storages/spec/components/storages/admin/storage_list_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/storage_list_component_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Admin::StorageListComponent, type: :component do @@ -41,18 +41,18 @@ render_inline(storage_list_component) end - context "with storages" do - it "lists all storages" do + context 'with storages' do + it 'lists all storages' do expect(page).to have_list_item(count: 2) expect(page).to have_list_item(nextcloud_storage.name) expect(page).to have_list_item(one_drive_storage.name) end end - context "with no storages" do + context 'with no storages' do let(:storages) { [] } - it "renders a blank slate" do + it 'renders a blank slate' do expect(page).to have_text("You don't have any storages yet.") end end diff --git a/modules/storages/spec/components/storages/admin/storage_row_component_spec.rb b/modules/storages/spec/components/storages/admin/storage_row_component_spec.rb index 0bf605083c0a..d9954ac0ed60 100644 --- a/modules/storages/spec/components/storages/admin/storage_row_component_spec.rb +++ b/modules/storages/spec/components/storages/admin/storage_row_component_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Admin::StorageRowComponent, type: :component do @@ -38,92 +38,92 @@ render_inline(storage_row_component) end - describe "Nextcloud storage" do - shared_examples "a Nextcloud storage row" do - it "render the storage name" do + describe 'Nextcloud storage' do + shared_examples 'a Nextcloud storage row' do + it 'render the storage name' do expect(page).to have_link(storage.name, href: edit_admin_settings_storage_path(storage)) end - it "renders the storage creator" do - pending "Invisible on small screens: Find a way to render inline" - expect(page).to have_test_selector("storage-creator", text: storage.creator.name) + it 'renders the storage creator' do + pending 'Invisible on small screens: Find a way to render inline' + expect(page).to have_test_selector('storage-creator', text: storage.creator.name) end - it "renders the storage provider" do - expect(page).to have_test_selector("storage-provider", text: "Nextcloud") + it 'renders the storage provider' do + expect(page).to have_test_selector('storage-provider', text: 'Nextcloud') end - it "renders the storage host" do - expect(page).to have_test_selector("storage-host", text: storage.host) + it 'renders the storage host' do + expect(page).to have_test_selector('storage-host', text: storage.host) end end - context "with complete storage" do + context 'with complete storage' do shared_let(:storage) { create(:nextcloud_storage_with_local_connection) } - it_behaves_like "a Nextcloud storage row" + it_behaves_like 'a Nextcloud storage row' - it "does not show an incomplete label" do - expect(page).not_to have_test_selector("label-incomplete") + it 'does not show an incomplete label' do + expect(page).not_to have_test_selector('label-incomplete') end end - context "with incomplete storage" do + context 'with incomplete storage' do shared_let(:storage) { create(:nextcloud_storage) } - it_behaves_like "a Nextcloud storage row" + it_behaves_like 'a Nextcloud storage row' it 'renders an "Incomplete" label' do - expect(page).to have_test_selector("label-incomplete", text: "Incomplete") + expect(page).to have_test_selector('label-incomplete', text: 'Incomplete') end end - context "with unhealthy storage" do + context 'with unhealthy storage' do shared_let(:storage) do create(:nextcloud_storage_with_complete_configuration, :as_unhealthy) end - it_behaves_like "a Nextcloud storage row" + it_behaves_like 'a Nextcloud storage row' it 'renders an "Error" label' do - expect(page).to have_test_selector("storage-health-label-error", text: "Error") + expect(page).to have_test_selector('storage-health-label-error', text: 'Error') end end end - describe "OneDrive/SharePoint storage" do - shared_examples "a OneDrive/SharePoint storage row" do - it "render the storage name" do + describe 'OneDrive/SharePoint storage' do + shared_examples 'a OneDrive/SharePoint storage row' do + it 'render the storage name' do expect(page).to have_link(storage.name, href: edit_admin_settings_storage_path(storage)) end - it "renders the storage creator" do - pending "Invisible on small screens: Find a way to render inline" - expect(page).to have_test_selector("storage-creator", text: storage.creator.name) + it 'renders the storage creator' do + pending 'Invisible on small screens: Find a way to render inline' + expect(page).to have_test_selector('storage-creator', text: storage.creator.name) end - it "renders the storage provider" do - expect(page).to have_test_selector("storage-provider", text: "OneDrive/SharePoint") + it 'renders the storage provider' do + expect(page).to have_test_selector('storage-provider', text: 'OneDrive/SharePoint') end end - context "with complete storage" do + context 'with complete storage' do shared_let(:storage) { create(:sharepoint_dev_drive_storage) } - it_behaves_like "a OneDrive/SharePoint storage row" + it_behaves_like 'a OneDrive/SharePoint storage row' - it "does not show an incomplete label" do - expect(page).not_to have_test_selector("label-incomplete") + it 'does not show an incomplete label' do + expect(page).not_to have_test_selector('label-incomplete') end end - context "with incomplete storage" do + context 'with incomplete storage' do shared_let(:storage) { create(:one_drive_storage) } - it_behaves_like "a OneDrive/SharePoint storage row" + it_behaves_like 'a OneDrive/SharePoint storage row' it 'renders an "Incomplete" label' do - expect(page).to have_test_selector("label-incomplete", text: "Incomplete") + expect(page).to have_test_selector('label-incomplete', text: 'Incomplete') end end end diff --git a/modules/storages/spec/contracts/storages/file_links/create_contract_spec.rb b/modules/storages/spec/contracts/storages/file_links/create_contract_spec.rb index 898afbaa5b13..04ec5bab054c 100644 --- a/modules/storages/spec/contracts/storages/file_links/create_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/file_links/create_contract_spec.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "shared_contract_examples" +require_relative 'shared_contract_examples' RSpec.describe Storages::FileLinks::CreateContract do - it_behaves_like "file_link contract" do + it_behaves_like 'file_link contract' do let(:contract) { described_class.new(file_link, current_user) } - context "when creator is not the current user" do + context 'when creator is not the current user' do let(:file_link_creator) { build_stubbed(:user) } - include_examples "contract is invalid", creator: :invalid + include_examples 'contract is invalid', creator: :invalid end - context "with one drive storage and missing ee token", with_ee: false do + context 'with one drive storage and missing ee token', with_ee: false do let(:storage) { create(:one_drive_storage) } - include_examples "contract is invalid", base: I18n.t("api_v3.errors.code_500_missing_enterprise_token") + include_examples 'contract is invalid', base: I18n.t('api_v3.errors.code_500_missing_enterprise_token') end - context "with one drive storage and valid ee token", with_ee: %i[one_drive_sharepoint_file_storage] do + context 'with one drive storage and valid ee token', with_ee: %i[one_drive_sharepoint_file_storage] do let(:storage) { create(:one_drive_storage) } - include_examples "contract is valid" + include_examples 'contract is valid' end end end diff --git a/modules/storages/spec/contracts/storages/file_links/delete_contract_spec.rb b/modules/storages/spec/contracts/storages/file_links/delete_contract_spec.rb index 744ea35af08b..d14a4ff24bc8 100644 --- a/modules/storages/spec/contracts/storages/file_links/delete_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/file_links/delete_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe Storages::FileLinks::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { create(:user) } let(:role) { create(:project_role, permissions: [:manage_file_links]) } @@ -46,17 +46,17 @@ # Default test setup should be valid ("happy test setup"). # This tests works with manage_storages_in_project permissions for current_user. - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' # Now we remove the permissions from the user by creating a role without special perms. - context "without manage_storages_in_project permission for project" do + context 'without manage_storages_in_project permission for project' do let(:role) { create(:project_role) } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end # Generic checks that the contract is valid for valid admin, but invalid otherwise - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/storages/spec/contracts/storages/file_links/shared_contract_examples.rb b/modules/storages/spec/contracts/storages/file_links/shared_contract_examples.rb index 9e2689f6dcd6..433fd71c7648 100644 --- a/modules/storages/spec/contracts/storages/file_links/shared_contract_examples.rb +++ b/modules/storages/spec/contracts/storages/file_links/shared_contract_examples.rb @@ -28,12 +28,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "file_link contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'file_link contract' do + include_context 'ModelContract shared context' let(:current_user) { create(:user) } let(:role) { create(:project_role, permissions: [:manage_file_links]) } @@ -50,125 +50,125 @@ let(:file_link_creator) { current_user } let(:file_link_attributes) { {} } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - describe "validations" do - context "when all attributes are valid" do - it_behaves_like "contract is valid" + describe 'validations' do + context 'when all attributes are valid' do + it_behaves_like 'contract is valid' end - describe "storage_id" do - context "when empty" do + describe 'storage_id' do + context 'when empty' do let(:storage_id) { "" } let(:file_link) { create(:file_link, container: work_package, storage_id:) } - include_examples "contract is invalid", storage: :blank + include_examples 'contract is invalid', storage: :blank end end - describe "origin_id" do - context "when empty" do - let(:file_link_attributes) { { origin_id: "" } } + describe 'origin_id' do + context 'when empty' do + let(:file_link_attributes) { { origin_id: '' } } - include_examples "contract is invalid", origin_id: %i[blank too_short] + include_examples 'contract is invalid', origin_id: %i[blank too_short] end - context "when nil" do + context 'when nil' do let(:file_link_attributes) { { origin_id: nil } } - include_examples "contract is invalid", origin_id: %i[blank too_short] + include_examples 'contract is invalid', origin_id: %i[blank too_short] end - context "when numeric" do + context 'when numeric' do let(:file_link_attributes) { { origin_id: 12345 } } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when uuid-like" do - let(:file_link_attributes) { { origin_id: "5eda571a-819e-44b2-939c-2301f9322ac6" } } + context 'when uuid-like' do + let(:file_link_attributes) { { origin_id: '5eda571a-819e-44b2-939c-2301f9322ac6' } } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when having non ascii characters" do - let(:file_link_attributes) { { origin_id: "Hëllò Wôrłd!" } } + context 'when having non ascii characters' do + let(:file_link_attributes) { { origin_id: 'Hëllò Wôrłd!' } } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when longer than 100 characters" do - let(:file_link_attributes) { { origin_id: "1" * 201 } } + context 'when longer than 100 characters' do + let(:file_link_attributes) { { origin_id: '1' * 201 } } - include_examples "contract is invalid", origin_id: :too_long + include_examples 'contract is invalid', origin_id: :too_long end end - describe "origin_name" do - context "when empty" do - let(:file_link_attributes) { { origin_name: "" } } + describe 'origin_name' do + context 'when empty' do + let(:file_link_attributes) { { origin_name: '' } } - include_examples "contract is invalid", origin_name: :blank + include_examples 'contract is invalid', origin_name: :blank end - context "when nil" do + context 'when nil' do let(:file_link_attributes) { { origin_name: nil } } - include_examples "contract is invalid", origin_name: :blank + include_examples 'contract is invalid', origin_name: :blank end end - describe "origin_mime_type" do - context "when empty" do - let(:file_link_attributes) { { origin_mime_type: "" } } + describe 'origin_mime_type' do + context 'when empty' do + let(:file_link_attributes) { { origin_mime_type: '' } } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when nil" do + context 'when nil' do let(:file_link_attributes) { { origin_mime_type: nil } } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when anything" do - let(:file_link_attributes) { { origin_mime_type: "abcdef/zyxwvut" } } + context 'when anything' do + let(:file_link_attributes) { { origin_mime_type: 'abcdef/zyxwvut' } } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when longer than 255 characters" do - let(:file_link_attributes) { { origin_mime_type: "a" * 256 } } + context 'when longer than 255 characters' do + let(:file_link_attributes) { { origin_mime_type: 'a' * 256 } } - include_examples "contract is invalid", origin_mime_type: :too_long + include_examples 'contract is invalid', origin_mime_type: :too_long end end - shared_examples_for "optional attribute" do |params| - context "when nil" do + shared_examples_for 'optional attribute' do |params| + context 'when nil' do let(:file_link_attributes) { params.transform_values { nil } } - include_examples "contract is valid" + include_examples 'contract is valid' end context "when #{params.inspect}" do let(:file_link_attributes) { params } - include_examples "contract is valid" + include_examples 'contract is valid' end end { - origin_created_by_name: "someone", - origin_last_modified_by_name: "someone", + origin_created_by_name: 'someone', + origin_last_modified_by_name: 'someone', origin_created_at: Time.zone.now, origin_updated_at: Time.zone.now }.each do |(attribute, a_valid_value)| describe attribute.name do - it_behaves_like "optional attribute", attribute => a_valid_value + it_behaves_like 'optional attribute', attribute => a_valid_value end end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/storages/spec/contracts/storages/last_project_folders/base_contract_spec.rb b/modules/storages/spec/contracts/storages/last_project_folders/base_contract_spec.rb index 2e2618a31a34..7562957cf4c1 100644 --- a/modules/storages/spec/contracts/storages/last_project_folders/base_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/last_project_folders/base_contract_spec.rb @@ -28,48 +28,48 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe Storages::LastProjectFolders::BaseContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:last_project_folder) { build(:last_project_folder) } let(:contract) { described_class.new(last_project_folder, build_stubbed(:admin)) } - context "if no project storage is given" do + context 'if no project storage is given' do before do last_project_folder.project_storage = nil end - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end - context "if the project folder mode is `inactive`" do + context 'if the project folder mode is `inactive`' do before do - last_project_folder.mode = "inactive" + last_project_folder.mode = 'inactive' end - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end - context "if the project folder mode is `manual`" do + context 'if the project folder mode is `manual`' do before do - last_project_folder.mode = "manual" + last_project_folder.mode = 'manual' end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "if the project folder mode is `automatic`" do + context 'if the project folder mode is `automatic`' do before do - last_project_folder.mode = "automatic" + last_project_folder.mode = 'automatic' end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/storages/spec/contracts/storages/project_storages/base_contract_spec.rb b/modules/storages/spec/contracts/storages/project_storages/base_contract_spec.rb index 1d364cf1e434..546c483d2018 100644 --- a/modules/storages/spec/contracts/storages/project_storages/base_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/project_storages/base_contract_spec.rb @@ -28,61 +28,61 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe Storages::ProjectStorages::BaseContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:contract) { described_class.new(project_storage, build_stubbed(:admin)) } let(:storage) { build_stubbed(:nextcloud_storage) } let(:project_storage) { build(:project_storage, storage:) } - context "if the project folder mode is `inactive`" do + context 'if the project folder mode is `inactive`' do before do - project_storage.project_folder_mode = "inactive" + project_storage.project_folder_mode = 'inactive' end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "if the project folder mode is `automatic`" do + context 'if the project folder mode is `automatic`' do before do - project_storage.project_folder_mode = "automatic" + project_storage.project_folder_mode = 'automatic' project_storage.storage.automatic_management_enabled = true end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when the project folder mode is `automatic` but the storage is not automatically managed" do + context 'when the project folder mode is `automatic` but the storage is not automatically managed' do before do - project_storage.project_folder_mode = "automatic" + project_storage.project_folder_mode = 'automatic' project_storage.storage.automatic_management_enabled = false end - it_behaves_like "contract is invalid", project_folder_mode: :mode_unavailable + it_behaves_like 'contract is invalid', project_folder_mode: :mode_unavailable end - context "if the project folder mode is `manual`" do + context 'if the project folder mode is `manual`' do before do - project_storage.project_folder_mode = "manual" + project_storage.project_folder_mode = 'manual' end - context "with no project_folder_id" do - it_behaves_like "contract is invalid", project_folder_id: :blank + context 'with no project_folder_id' do + it_behaves_like 'contract is invalid', project_folder_id: :blank end - context "with project_folder_id" do + context 'with project_folder_id' do before do - project_storage.project_folder_id = "Project#1" + project_storage.project_folder_id = 'Project#1' end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/storages/spec/contracts/storages/project_storages/create_contract_spec.rb b/modules/storages/spec/contracts/storages/project_storages/create_contract_spec.rb index d48546a5405d..0df3cc186d04 100644 --- a/modules/storages/spec/contracts/storages/project_storages/create_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/project_storages/create_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "shared_contract_examples" +require_relative 'shared_contract_examples' RSpec.describe Storages::ProjectStorages::CreateContract do - it_behaves_like "ProjectStorages contract" do + it_behaves_like 'ProjectStorages contract' do # current_user, project, storage and other objects defined in the shared_contract_examples # that includes all the stuff shared between create and update. let(:project_storage) do @@ -48,7 +48,7 @@ described_class.new(project_storage, current_user) end - context "when checking creator_id" do + context 'when checking creator_id' do let(:contract) { described_class.new(project_storage, current_user) } let(:project_storage) { build(:project_storage, creator:) } let(:current_user) { build_stubbed(:admin) } @@ -57,16 +57,16 @@ login_as(current_user) end - context "as creator_id == current_user_id" do + context 'as creator_id == current_user_id' do let(:creator) { current_user } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "as creator_id != current_user_id" do + context 'as creator_id != current_user_id' do let(:creator) { build_stubbed(:user) } - it_behaves_like "contract is invalid", creator: :invalid + it_behaves_like 'contract is invalid', creator: :invalid end end end diff --git a/modules/storages/spec/contracts/storages/project_storages/delete_contract_spec.rb b/modules/storages/spec/contracts/storages/project_storages/delete_contract_spec.rb index 612b6ffe51c0..305617a88a66 100644 --- a/modules/storages/spec/contracts/storages/project_storages/delete_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/project_storages/delete_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe Storages::ProjectStorages::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { create(:user) } let(:role) { create(:project_role, permissions: [:manage_storages_in_project]) } @@ -42,18 +42,18 @@ # Default test setup should be valid ("happy test setup"). # The example below was included above from "ModelContract shared context". # This tests works with manage_storages_in_project permissions for current_user. - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' # Now we remove the permissions from the user by creating a role without special perms. - context "without manage_storages_in_project permission for project" do + context 'without manage_storages_in_project permission for project' do # existing_role is a role _without_ the :manage_storages_in_project permission let(:role) { create(:project_role) } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end # Generic checks that the contract is valid for valid admin, but invalid otherwise - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/storages/spec/contracts/storages/project_storages/shared_contract_examples.rb b/modules/storages/spec/contracts/storages/project_storages/shared_contract_examples.rb index df44a81e358c..bea5e5e0164a 100644 --- a/modules/storages/spec/contracts/storages/project_storages/shared_contract_examples.rb +++ b/modules/storages/spec/contracts/storages/project_storages/shared_contract_examples.rb @@ -29,13 +29,13 @@ #++ # Include OpenProject support/*.rb files -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' # Purpose: Common testing logic shared between create and update specs. -RSpec.shared_examples_for "ProjectStorages contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'ProjectStorages contract' do + include_context 'ModelContract shared context' let(:current_user) { create(:user) } # The user needs "edit_project" to see the project's settings page @@ -51,35 +51,35 @@ # This is not 100% precise, as the required permission is not :admin # but :manage_storages_in_project, but let's still include this. - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - describe "validations" do - context "when authorized, with permissions and all attributes are valid" do - it_behaves_like "contract is valid" + describe 'validations' do + context 'when authorized, with permissions and all attributes are valid' do + it_behaves_like 'contract is valid' end - context "when project is invalid" do - context "as it is nil" do + context 'when project is invalid' do + context 'as it is nil' do let(:project) { nil } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end end - context "when storage is invalid" do - context "as it is nil" do + context 'when storage is invalid' do + context 'as it is nil' do let(:storage) { nil } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end end - context "when not the necessary permissions" do + context 'when not the necessary permissions' do let(:current_user) { build_stubbed(:user) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/modules/storages/spec/contracts/storages/storages/nextcloud_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/nextcloud_contract_spec.rb index b576fbf51f07..7f2bac5af98e 100644 --- a/modules/storages/spec/contracts/storages/storages/nextcloud_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/nextcloud_contract_spec.rb @@ -28,19 +28,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Storages::NextcloudContract, :storage_server_helpers, :webmock do let(:current_user) { create(:admin) } - let(:storage_host) { "https://host1.example.com" } + let(:storage_host) { 'https://host1.example.com' } let(:storage) { build(:nextcloud_storage, host: storage_host) } # As the NextcloudContract is selected by the BaseContract to make writable attributes available, # the BaseContract needs to be instantiated here. subject { Storages::Storages::BaseContract.new(storage, current_user) } - it "checks the storage url only when changed" do + it 'checks the storage url only when changed' do capabilities_request = mock_server_capabilities_response(storage_host) host_request = mock_server_config_check_response(storage_host) subject.validate @@ -54,8 +54,8 @@ expect(host_request).not_to have_been_made end - describe "Nextcloud application credentials validation" do - context "with valid credentials" do + describe 'Nextcloud application credentials validation' do + context 'with valid credentials' do let(:storage) { build(:nextcloud_storage, :as_automatically_managed) } before do @@ -63,17 +63,17 @@ mock_server_config_check_response(storage.host) end - it "passes validation" do + it 'passes validation' do credentials_request = mock_nextcloud_application_credentials_validation(storage.host) expect(subject).to be_valid expect(credentials_request).to have_been_made.once end - context "with invalid credentials" do + context 'with invalid credentials' do let(:storage) { build(:nextcloud_storage, :as_automatically_managed) } - it "fails validation" do + it 'fails validation' do credentials_request = mock_nextcloud_application_credentials_validation(storage.host, response_code: 401) expect(subject).not_to be_valid @@ -83,10 +83,10 @@ end end - context "with timeout" do + context 'with timeout' do let(:storage) { build(:nextcloud_storage, :as_automatically_managed) } - it "fails validation" do + it 'fails validation' do credentials_request = mock_nextcloud_application_credentials_validation(storage.host, timeout: true) expect(subject).not_to be_valid @@ -98,10 +98,10 @@ end end - context "with unknown error" do + context 'with unknown error' do let(:storage) { build(:nextcloud_storage, :as_automatically_managed) } - it "fails validation" do + it 'fails validation' do credentials_request = mock_nextcloud_application_credentials_validation(storage.host, response_code: 500) expect(subject).not_to be_valid @@ -112,10 +112,10 @@ end end - context "when the storage is not automatically managed" do + context 'when the storage is not automatically managed' do let(:storage) { build(:nextcloud_storage, :as_not_automatically_managed) } - it "skips credentials validation" do + it 'skips credentials validation' do credentials_request = mock_nextcloud_application_credentials_validation(storage.host) expect(subject).to be_valid @@ -123,10 +123,10 @@ end end - context "when the storage host has a subpath" do - let(:storage) { build(:nextcloud_storage, :as_automatically_managed, host: "https://host1.example.com/api") } + context 'when the storage host has a subpath' do + let(:storage) { build(:nextcloud_storage, :as_automatically_managed, host: 'https://host1.example.com/api') } - it "passes validation" do + it 'passes validation' do credentials_request = mock_nextcloud_application_credentials_validation(storage.host) expect(subject).to be_valid @@ -135,14 +135,14 @@ end end - context "when the storage host is nil" do + context 'when the storage host is nil' do let(:storage) { build(:nextcloud_storage, :as_automatically_managed, host: nil) } before do allow(NextcloudApplicationCredentialsValidator).to receive(:new).and_call_original end - it "fails validation" do + it 'fails validation' do expect(subject).not_to be_valid expect(subject.errors.to_hash).to eq({ host: ["is not a valid URL."] }) expect(NextcloudApplicationCredentialsValidator).not_to have_received(:new) diff --git a/modules/storages/spec/contracts/storages/storages/nextcloud_create_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/nextcloud_create_contract_spec.rb index 78604fdc5132..8eb7aabdf16c 100644 --- a/modules/storages/spec/contracts/storages/storages/nextcloud_create_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/nextcloud_create_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "shared_contract_examples" +require_relative 'shared_contract_examples' RSpec.describe Storages::Storages::CreateContract do - it_behaves_like "nextcloud storage contract" do + it_behaves_like 'nextcloud storage contract' do let(:storage) do build_stubbed(:nextcloud_storage, creator: storage_creator, @@ -41,10 +41,10 @@ end let(:contract) { described_class.new(storage, current_user) } - context "when creator is not the current user" do + context 'when creator is not the current user' do let(:storage_creator) { build_stubbed(:user) } - include_examples "contract is invalid", creator: :invalid + include_examples 'contract is invalid', creator: :invalid end end end diff --git a/modules/storages/spec/contracts/storages/storages/nextcloud_delete_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/nextcloud_delete_contract_spec.rb index c4e0b0768574..4b3f7ade1f1a 100644 --- a/modules/storages/spec/contracts/storages/storages/nextcloud_delete_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/nextcloud_delete_contract_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe Storages::Storages::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:storage) { create(:nextcloud_storage) } let(:contract) { described_class.new(storage, current_user) } # Generic checks that the contract is valid for valid admin, but invalid otherwise - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:current_user) { build_stubbed(:user) } end end diff --git a/modules/storages/spec/contracts/storages/storages/nextcloud_update_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/nextcloud_update_contract_spec.rb index 2ff68ae2759f..557ee7573241 100644 --- a/modules/storages/spec/contracts/storages/storages/nextcloud_update_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/nextcloud_update_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "shared_contract_examples" +require_relative 'shared_contract_examples' RSpec.describe Storages::Storages::UpdateContract do - it_behaves_like "nextcloud storage contract" do + it_behaves_like 'nextcloud storage contract' do let(:storage) do build_stubbed(:nextcloud_storage, creator: storage_creator, @@ -41,10 +41,10 @@ end let(:contract) { described_class.new(storage, current_user) } - context "when current user is not the initial storage creator" do + context 'when current user is not the initial storage creator' do let(:storage_creator) { build_stubbed(:user) } - include_examples "contract is valid" + include_examples 'contract is valid' end end end diff --git a/modules/storages/spec/contracts/storages/storages/one_drive_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/one_drive_contract_spec.rb index b40600e4aa9a..6b8c7cc38cb3 100644 --- a/modules/storages/spec/contracts/storages/storages/one_drive_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/one_drive_contract_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Storages::OneDriveContract, :storage_server_helpers, :webmock do @@ -39,20 +39,20 @@ # the BaseContract needs to be instantiated here. subject(:contract) { Storages::Storages::BaseContract.new(storage, current_user) } - describe "when a host is set" do + describe 'when a host is set' do before do storage.host = "https://exmaple.com/" end - it "must be invalid" do + it 'must be invalid' do expect(contract).not_to be_valid end end - context "with blank Drive ID" do - let(:storage) { build(:one_drive_storage, drive_id: "") } + context 'with blank Drive ID' do + let(:storage) { build(:one_drive_storage, drive_id: '') } - it "is invalid" do + it 'is invalid' do expect(contract).not_to be_valid expect(contract.errors[:drive_id]).to eq(["can't be blank."]) diff --git a/modules/storages/spec/contracts/storages/storages/one_drive_create_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/one_drive_create_contract_spec.rb index d33667ebc52e..838e1b948768 100644 --- a/modules/storages/spec/contracts/storages/storages/one_drive_create_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/one_drive_create_contract_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "shared_contract_examples" +require_relative 'shared_contract_examples' RSpec.describe Storages::Storages::CreateContract, with_ee: %i[one_drive_sharepoint_file_storage] do let(:storage) do @@ -39,15 +39,15 @@ end let(:contract) { described_class.new(storage, current_user) } - it_behaves_like "onedrive storage contract" do - context "when creator is not the current user" do + it_behaves_like 'onedrive storage contract' do + context 'when creator is not the current user' do let(:storage_creator) { build_stubbed(:user) } - include_examples "contract is invalid", creator: :invalid + include_examples 'contract is invalid', creator: :invalid end - context "without ee token", with_ee: false do - include_examples "contract is invalid", base: I18n.t("api_v3.errors.code_500_missing_enterprise_token") + context 'without ee token', with_ee: false do + include_examples 'contract is invalid', base: I18n.t('api_v3.errors.code_500_missing_enterprise_token') end end end diff --git a/modules/storages/spec/contracts/storages/storages/one_drive_delete_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/one_drive_delete_contract_spec.rb index 77e73f071ca5..24f29ff95ac8 100644 --- a/modules/storages/spec/contracts/storages/storages/one_drive_delete_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/one_drive_delete_contract_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe Storages::Storages::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:storage) { create(:one_drive_storage) } let(:contract) { described_class.new(storage, current_user) } # Generic checks that the contract is valid for valid admin, but invalid otherwise - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:current_user) { build_stubbed(:user) } end end diff --git a/modules/storages/spec/contracts/storages/storages/one_drive_update_contract_spec.rb b/modules/storages/spec/contracts/storages/storages/one_drive_update_contract_spec.rb index 7c86f8f27867..cf5e1d968557 100644 --- a/modules/storages/spec/contracts/storages/storages/one_drive_update_contract_spec.rb +++ b/modules/storages/spec/contracts/storages/storages/one_drive_update_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "shared_contract_examples" +require_relative 'shared_contract_examples' RSpec.describe Storages::Storages::UpdateContract do - it_behaves_like "onedrive storage contract" do + it_behaves_like 'onedrive storage contract' do let(:storage) do build_stubbed(:one_drive_storage, creator: storage_creator, @@ -40,10 +40,10 @@ end let(:contract) { described_class.new(storage, current_user) } - context "when current user is not the initial storage creator" do + context 'when current user is not the initial storage creator' do let(:storage_creator) { build_stubbed(:user) } - include_examples "contract is valid" + include_examples 'contract is valid' end end end diff --git a/modules/storages/spec/contracts/storages/storages/shared_contract_examples.rb b/modules/storages/spec/contracts/storages/storages/shared_contract_examples.rb index 2132f5dde839..ab76b5545399 100644 --- a/modules/storages/spec/contracts/storages/storages/shared_contract_examples.rb +++ b/modules/storages/spec/contracts/storages/storages/shared_contract_examples.rb @@ -28,75 +28,75 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "storage contract" do - describe "validations" do - context "when all attributes are valid" do - include_examples "contract is valid" +RSpec.shared_examples_for 'storage contract' do + describe 'validations' do + context 'when all attributes are valid' do + include_examples 'contract is valid' end - context "when name is invalid" do - context "as it is too long" do - let(:storage_name) { "X" * 257 } + context 'when name is invalid' do + context 'as it is too long' do + let(:storage_name) { 'X' * 257 } - include_examples "contract is invalid", name: :too_long + include_examples 'contract is invalid', name: :too_long end - context "as it is empty" do - let(:storage_name) { "" } + context 'as it is empty' do + let(:storage_name) { '' } - include_examples "contract is invalid", name: :blank + include_examples 'contract is invalid', name: :blank end - context "as it is nil" do + context 'as it is nil' do let(:storage_name) { nil } - include_examples "contract is invalid", name: :blank + include_examples 'contract is invalid', name: :blank end end - context "when provider_type is invalid" do - context "as it is empty" do - let(:storage_provider_type) { "" } + context 'when provider_type is invalid' do + context 'as it is empty' do + let(:storage_provider_type) { '' } - include_examples "contract is invalid", provider_type: :inclusion + include_examples 'contract is invalid', provider_type: :inclusion end - context "as it is nil" do + context 'as it is nil' do let(:storage_provider_type) { nil } - include_examples "contract is invalid", provider_type: :inclusion + include_examples 'contract is invalid', provider_type: :inclusion end end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end -RSpec.shared_examples_for "onedrive storage contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'onedrive storage contract' do + include_context 'ModelContract shared context' let(:current_user) { create(:admin) } - let(:storage_name) { "Storage 1" } + let(:storage_name) { 'Storage 1' } let(:storage_provider_type) { Storages::Storage::PROVIDER_TYPE_ONE_DRIVE } let(:storage_creator) { current_user } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - it_behaves_like "storage contract" + it_behaves_like 'storage contract' end -RSpec.shared_examples_for "nextcloud storage contract", :storage_server_helpers, :webmock do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'nextcloud storage contract', :storage_server_helpers, :webmock do + include_context 'ModelContract shared context' # Only admins have the right to create/delete storages. let(:current_user) { create(:admin) } - let(:storage_name) { "Storage 1" } + let(:storage_name) { 'Storage 1' } let(:storage_provider_type) { Storages::Storage::PROVIDER_TYPE_NEXTCLOUD } - let(:storage_host) { "https://host1.example.com" } + let(:storage_host) { 'https://host1.example.com' } let(:storage_creator) { current_user } before do @@ -107,49 +107,49 @@ end end - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - it_behaves_like "storage contract" + it_behaves_like 'storage contract' - describe "validations" do - context "when host is invalid" do - context "as host is not a URL" do - let(:storage_host) { "---invalid-url---" } + describe 'validations' do + context 'when host is invalid' do + context 'as host is not a URL' do + let(:storage_host) { '---invalid-url---' } - include_examples "contract is invalid", host: I18n.t("activerecord.errors.messages.invalid_url") + include_examples 'contract is invalid', host: I18n.t('activerecord.errors.messages.invalid_url') end - context "as host is an empty string" do - let(:storage_host) { "" } + context 'as host is an empty string' do + let(:storage_host) { '' } - include_examples "contract is invalid", host: I18n.t("activerecord.errors.messages.invalid_url") + include_examples 'contract is invalid', host: I18n.t('activerecord.errors.messages.invalid_url') end - context "as host is longer than 255" do + context 'as host is longer than 255' do let(:storage_host) { "http://#{'a' * 250}.com" } - include_examples "contract is invalid", host: :too_long + include_examples 'contract is invalid', host: :too_long end - context "as host is nil" do + context 'as host is nil' do let(:storage_host) { nil } - include_examples "contract is invalid", host: :url + include_examples 'contract is invalid', host: :url end - context "when host is an unsafe IP" do - let(:storage_host) { "http://172.16.193.146" } + context 'when host is an unsafe IP' do + let(:storage_host) { 'http://172.16.193.146' } - include_examples "contract is invalid", host: :url_not_secure_context + include_examples 'contract is invalid', host: :url_not_secure_context end - context "when host is an unsafe hostname" do - let(:storage_host) { "http://nc.openproject.com" } + context 'when host is an unsafe hostname' do + let(:storage_host) { 'http://nc.openproject.com' } - include_examples "contract is invalid", host: :url_not_secure_context + include_examples 'contract is invalid', host: :url_not_secure_context end - context "when provider_type is nextcloud" do + context 'when provider_type is nextcloud' do let(:capabilities_response_body) { nil } # use default let(:capabilities_response_code) { nil } # use default let(:capabilities_response_headers) { nil } # use default @@ -184,25 +184,25 @@ stub_config_check end - context "when connection fails" do - context "when server capabilities request times out" do + context 'when connection fails' do + context 'when server capabilities request times out' do let(:timeout_server_capabilities) { true } - include_examples "contract is invalid", host: :cannot_be_connected_to + include_examples 'contract is invalid', host: :cannot_be_connected_to - it "retries failed request once" do + it 'retries failed request once' do contract.validate # twice due to HTTPX retry plugin being enabled. expect(stub_server_capabilities).to have_been_made.twice end end - context "when server config check request times out" do + context 'when server config check request times out' do let(:timeout_server_config_check) { true } - include_examples "contract is invalid", host: :cannot_be_connected_to + include_examples 'contract is invalid', host: :cannot_be_connected_to - it "retries failed request once" do + it 'retries failed request once' do contract.validate # twice due to HTTPX retry plugin being enabled. @@ -211,133 +211,133 @@ end end - context "when response code is a 404 NOT FOUND" do + context 'when response code is a 404 NOT FOUND' do let(:capabilities_response_code) { 404 } - include_examples "contract is invalid", host: :cannot_be_connected_to + include_examples 'contract is invalid', host: :cannot_be_connected_to end - context "when response code is a 500 PERMISSION DENIED" do + context 'when response code is a 500 PERMISSION DENIED' do let(:capabilities_response_code) { 500 } - include_examples "contract is invalid", host: :cannot_be_connected_to + include_examples 'contract is invalid', host: :cannot_be_connected_to end - context "when response content type is not application/json" do + context 'when response content type is not application/json' do let(:capabilities_response_headers) do { - "Content-Type" => "text/html" + 'Content-Type' => 'text/html' } end - include_examples "contract is invalid", host: :not_nextcloud_server + include_examples 'contract is invalid', host: :not_nextcloud_server end - context "when response is unparsable JSON" do - let(:capabilities_response_body) { "{" } + context 'when response is unparsable JSON' do + let(:capabilities_response_body) { '{' } - include_examples "contract is invalid", host: :not_nextcloud_server + include_examples 'contract is invalid', host: :not_nextcloud_server end - context "when response is valid JSON but not the expected data" do - let(:capabilities_response_body) { "{}" } + context 'when response is valid JSON but not the expected data' do + let(:capabilities_response_body) { '{}' } - include_examples "contract is invalid", host: :not_nextcloud_server + include_examples 'contract is invalid', host: :not_nextcloud_server end - context "when Nextcloud version is below the required minimal version which is 22" do + context 'when Nextcloud version is below the required minimal version which is 22' do let(:capabilities_response_major_version) { 21 } - include_examples "contract is invalid", host: :minimal_nextcloud_version_unmet + include_examples 'contract is invalid', host: :minimal_nextcloud_version_unmet end context 'when Nextcloud instance is missing the "OpenProject integration" app' do let(:check_config_response_code) { 302 } - include_examples "contract is invalid", host: :op_application_not_installed + include_examples 'contract is invalid', host: :op_application_not_installed end - context "when Nextcloud instance is misconfigured and strips AUTHORIZATION header from HTTP request" do - let(:check_config_response_body) { { authorization_header: "" }.to_json } + context 'when Nextcloud instance is misconfigured and strips AUTHORIZATION header from HTTP request' do + let(:check_config_response_body) { { authorization_header: '' }.to_json } - include_examples "contract is invalid", host: :authorization_header_missing + include_examples 'contract is invalid', host: :authorization_header_missing end end end - context "when host secure" do - context "when host is localhost" do - let(:storage_host) { "http://localhost:1234" } + context 'when host secure' do + context 'when host is localhost' do + let(:storage_host) { 'http://localhost:1234' } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when host uses https protocol" do - let(:storage_host) { "https://172.16.193.146" } + context 'when host uses https protocol' do + let(:storage_host) { 'https://172.16.193.146' } - include_examples "contract is valid" + include_examples 'contract is valid' end end - context "when automatically managed, no username or password" do + context 'when automatically managed, no username or password' do before { storage.automatic_management_enabled = true } - it_behaves_like "contract is invalid", password: :blank + it_behaves_like 'contract is invalid', password: :blank end - context "when automatically managed, with username and password" do + context 'when automatically managed, with username and password' do before do - storage.assign_attributes(automatic_management_enabled: true, username: "OpenProject", password: "Password") + storage.assign_attributes(automatic_management_enabled: true, username: 'OpenProject', password: 'Password') end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when not automatically managed, no username or password" do + context 'when not automatically managed, no username or password' do before do storage.provider_fields = {} storage.assign_attributes(automatic_management_enabled: false) end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when not automatically managed, with username default and password" do + context 'when not automatically managed, with username default and password' do before do - storage.assign_attributes(automatic_management_enabled: false, username: "OpenProject", password: "Password") + storage.assign_attributes(automatic_management_enabled: false, username: 'OpenProject', password: 'Password') end - it_behaves_like "contract is invalid", password: :present + it_behaves_like 'contract is invalid', password: :present end - context "when not automatically managed, with user defined username and password" do + context 'when not automatically managed, with user defined username and password' do before do - storage.assign_attributes(automatic_management_enabled: false, username: "Username", password: "Password") + storage.assign_attributes(automatic_management_enabled: false, username: 'Username', password: 'Password') end - it_behaves_like "contract is invalid", username: :present, password: :present + it_behaves_like 'contract is invalid', username: :present, password: :present end - describe "provider_type_strategy" do + describe 'provider_type_strategy' do before do allow(contract).to receive(:provider_type_strategy) end - context "without `skip_provider_type_strategy` option" do - it "validates the provider type contract" do + context 'without `skip_provider_type_strategy` option' do + it 'validates the provider type contract' do contract.validate expect(contract).to have_received(:provider_type_strategy) end end - context "with `skip_provider_type_strategy` option" do + context 'with `skip_provider_type_strategy` option' do let(:contract) do described_class.new(storage, build_stubbed(:admin), options: { skip_provider_type_strategy: true }) end - it "does not validate the provider type" do + it 'does not validate the provider type' do contract.validate expect(contract).not_to have_received(:provider_type_strategy) diff --git a/modules/storages/spec/factories/file_link_element_factory.rb b/modules/storages/spec/factories/file_link_element_factory.rb index 54820243c235..af66880a6aa2 100644 --- a/modules/storages/spec/factories/file_link_element_factory.rb +++ b/modules/storages/spec/factories/file_link_element_factory.rb @@ -41,12 +41,12 @@ storage_url { "https://nextcloud.example.com" } trait :invalid do - origin_id { " " } + origin_id { ' ' } end initialize_with do - origin_data = attributes.select { |key, _| key.starts_with?("origin_") } - .transform_keys { |key| key.to_s.gsub("origin_", "").camelcase(:lower).to_sym } + origin_data = attributes.select { |key, _| key.starts_with?('origin_') } + .transform_keys { |key| key.to_s.gsub('origin_', '').camelcase(:lower).to_sym } .then { |data| data.transform_values { |v| v.respond_to?(:iso8601) ? v.iso8601 : v } } .then { |data| data.transform_keys { |k| k.to_sym == :updatedAt ? :lastModifiedAt : k } } { diff --git a/modules/storages/spec/factories/file_link_factory.rb b/modules/storages/spec/factories/file_link_factory.rb index 93177559d0a2..185fb9a3f6a6 100644 --- a/modules/storages/spec/factories/file_link_factory.rb +++ b/modules/storages/spec/factories/file_link_factory.rb @@ -28,7 +28,7 @@ # Expects parameters: storage FactoryBot.define do - factory :file_link, class: "::Storages::FileLink" do + factory :file_link, class: '::Storages::FileLink' do creator factory: :user sequence(:origin_id) { |n| "10000#{n}" } # ID within external storage (i.e. Nextcloud) sequence(:origin_name) { |n| "file_name_#{n}.txt" } # File name within external storage (i.e. Nextcloud) diff --git a/modules/storages/spec/factories/last_project_folder_factory.rb b/modules/storages/spec/factories/last_project_folder_factory.rb index bf4f424cb91c..66a96991a370 100644 --- a/modules/storages/spec/factories/last_project_folder_factory.rb +++ b/modules/storages/spec/factories/last_project_folder_factory.rb @@ -27,7 +27,7 @@ #++ FactoryBot.define do - factory :last_project_folder, class: "::Storages::LastProjectFolder" do + factory :last_project_folder, class: '::Storages::LastProjectFolder' do project_storage factory: :project_storage end end diff --git a/modules/storages/spec/factories/project_storage_factory.rb b/modules/storages/spec/factories/project_storage_factory.rb index f9ec495cc2c8..7112fdce1b5f 100644 --- a/modules/storages/spec/factories/project_storage_factory.rb +++ b/modules/storages/spec/factories/project_storage_factory.rb @@ -28,15 +28,15 @@ # Required parameters: project and storage FactoryBot.define do - factory :project_storage, class: "::Storages::ProjectStorage" do + factory :project_storage, class: '::Storages::ProjectStorage' do creator factory: :user storage factory: :nextcloud_storage project factory: :project project_folder_id { nil } - project_folder_mode { "inactive" } + project_folder_mode { 'inactive' } trait :as_automatically_managed do - project_folder_mode { "automatic" } + project_folder_mode { 'automatic' } end trait :with_historical_data do diff --git a/modules/storages/spec/factories/storage_factory.rb b/modules/storages/spec/factories/storage_factory.rb index 963a91a3e146..7aab75d834b6 100644 --- a/modules/storages/spec/factories/storage_factory.rb +++ b/modules/storages/spec/factories/storage_factory.rb @@ -44,6 +44,19 @@ trait :as_generic do provider_type { 'Storages::Storage' } end + end + + factory :nextcloud_storage, + parent: :storage, + class: '::Storages::NextcloudStorage' do + provider_type { Storages::Storage::PROVIDER_TYPE_NEXTCLOUD } + sequence(:host) { |n| "https://host#{n}.example.com" } + + trait :as_automatically_managed do + automatically_managed { true } + username { 'OpenProject' } + password { 'Password123' } + end trait :as_not_automatically_managed do automatically_managed { false } @@ -78,19 +91,6 @@ end end - factory :nextcloud_storage, - parent: :storage, - class: '::Storages::NextcloudStorage' do - provider_type { Storages::Storage::PROVIDER_TYPE_NEXTCLOUD } - sequence(:host) { |n| "https://host#{n}.example.com" } - - trait :as_automatically_managed do - automatically_managed { true } - username { 'OpenProject' } - password { 'Password123' } - end - end - factory :nextcloud_storage_configured, parent: :nextcloud_storage do after(:create) do |storage, _evaluator| create(:oauth_client, integration: storage) @@ -155,10 +155,6 @@ host { nil } tenant_id { SecureRandom.uuid } drive_id { SecureRandom.uuid } - - trait :as_automatically_managed do - automatically_managed { true } - end end factory :sharepoint_dev_drive_storage, diff --git a/modules/storages/spec/factories/storage_file_info_factory.rb b/modules/storages/spec/factories/storage_file_info_factory.rb index 78558f8de1f0..969ad8e201db 100644 --- a/modules/storages/spec/factories/storage_file_info_factory.rb +++ b/modules/storages/spec/factories/storage_file_info_factory.rb @@ -27,7 +27,7 @@ #++ FactoryBot.define do - factory :storage_file_info, class: "::Storages::StorageFileInfo" do + factory :storage_file_info, class: '::Storages::StorageFileInfo' do status { "OK" } status_code { 200 } sequence(:id) { |n| "20000#{n}" } # rubocop:disable FactoryBot/IdSequence diff --git a/modules/storages/spec/factories/webdav_data_factory.rb b/modules/storages/spec/factories/webdav_data_factory.rb index c3c98ca9da9e..02e50453f229 100644 --- a/modules/storages/spec/factories/webdav_data_factory.rb +++ b/modules/storages/spec/factories/webdav_data_factory.rb @@ -27,109 +27,109 @@ #++ FactoryBot.define do - factory :webdav_data, class: "String" do + factory :webdav_data, class: 'String' do transient do - origin_user_id { "admin" } - root_path { "" } - parent_path { "" } + origin_user_id { 'admin' } + root_path { '' } + parent_path { '' } end skip_create initialize_with do - url_safe_user_id = origin_user_id.gsub(" ", "%20") - base_path = File.join(root_path, "/remote.php/dav/files", url_safe_user_id, parent_path) + url_safe_user_id = origin_user_id.gsub(' ', '%20') + base_path = File.join(root_path, '/remote.php/dav/files', url_safe_user_id, parent_path) Nokogiri::XML::Builder.new do |xml| - xml["d"].multistatus( - "xmlns:d" => "DAV:", - "xmlns:s" => "http://sabredav.org/ns", - "xmlns:oc" => "http://owncloud.org/ns", - "xmlns:nc" => "http://nextcloud.org/ns" + xml['d'].multistatus( + 'xmlns:d' => 'DAV:', + 'xmlns:s' => 'http://sabredav.org/ns', + 'xmlns:oc' => 'http://owncloud.org/ns', + 'xmlns:nc' => 'http://nextcloud.org/ns' ) do - xml["d"].response do - xml["d"].href(base_path) - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("6") - xml["oc"].size("20028269") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:27:36 GMT") - xml["oc"].permissions("RGDNVCK") - xml["oc"].send(:"owner-display-name", url_safe_user_id) + xml['d'].response do + xml['d'].href(base_path) + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('6') + xml['oc'].size('20028269') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:27:36 GMT') + xml['oc'].permissions('RGDNVCK') + xml['oc'].send(:'owner-display-name', url_safe_user_id) end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end - xml["d"].propstat do - xml["d"].prop do - xml["d"].getcontenttype + xml['d'].propstat do + xml['d'].prop do + xml['d'].getcontenttype end - xml["d"].status("HTTP/1.1 404 Not Found") + xml['d'].status('HTTP/1.1 404 Not Found') end end - xml["d"].response do - xml["d"].href(File.join(base_path, "Folder1", "")) - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("11") - xml["oc"].size("6592") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:31:26 GMT") - xml["oc"].permissions("RGDNVCK") - xml["oc"].send(:"owner-display-name", url_safe_user_id) + xml['d'].response do + xml['d'].href(File.join(base_path, 'Folder1', '')) + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('11') + xml['oc'].size('6592') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') + xml['oc'].permissions('RGDNVCK') + xml['oc'].send(:'owner-display-name', url_safe_user_id) end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end - xml["d"].propstat do - xml["d"].prop do - xml["d"].getcontenttype + xml['d'].propstat do + xml['d'].prop do + xml['d'].getcontenttype end - xml["d"].status("HTTP/1.1 404 Not Found") + xml['d'].status('HTTP/1.1 404 Not Found') end end - xml["d"].response do - xml["d"].href(File.join(base_path, "Folder2", "")) - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("20") - xml["oc"].size("8592") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:43:26 GMT") - xml["oc"].permissions("RGDNV") - xml["oc"].send(:"owner-display-name", url_safe_user_id) + xml['d'].response do + xml['d'].href(File.join(base_path, 'Folder2', '')) + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('20') + xml['oc'].size('8592') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:43:26 GMT') + xml['oc'].permissions('RGDNV') + xml['oc'].send(:'owner-display-name', url_safe_user_id) end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end - xml["d"].propstat do - xml["d"].prop do - xml["d"].getcontenttype + xml['d'].propstat do + xml['d'].prop do + xml['d'].getcontenttype end - xml["d"].status("HTTP/1.1 404 Not Found") + xml['d'].status('HTTP/1.1 404 Not Found') end end - xml["d"].response do - xml["d"].href(File.join(base_path, "README.md")) - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("12") - xml["oc"].size("1024") - xml["d"].getcontenttype("text/markdown") - xml["d"].getlastmodified("Thu, 14 Jul 2022 08:42:15 GMT") - xml["oc"].permissions("RGDNVW") - xml["oc"].send(:"owner-display-name", url_safe_user_id) + xml['d'].response do + xml['d'].href(File.join(base_path, 'README.md')) + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('12') + xml['oc'].size('1024') + xml['d'].getcontenttype('text/markdown') + xml['d'].getlastmodified('Thu, 14 Jul 2022 08:42:15 GMT') + xml['oc'].permissions('RGDNVW') + xml['oc'].send(:'owner-display-name', url_safe_user_id) end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end end - xml["d"].response do - xml["d"].href(File.join(base_path, "Manual.pdf")) - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("13") - xml["oc"].size("12706214") - xml["d"].getcontenttype("application/pdf") - xml["d"].getlastmodified("Thu, 14 Jul 2022 08:42:15 GMT") - xml["oc"].permissions("RGDNV") - xml["oc"].send(:"owner-display-name", url_safe_user_id) + xml['d'].response do + xml['d'].href(File.join(base_path, 'Manual.pdf')) + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('13') + xml['oc'].size('12706214') + xml['d'].getcontenttype('application/pdf') + xml['d'].getlastmodified('Thu, 14 Jul 2022 08:42:15 GMT') + xml['oc'].permissions('RGDNV') + xml['oc'].send(:'owner-display-name', url_safe_user_id) end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end end end @@ -137,76 +137,76 @@ end end - factory :webdav_data_folder, class: "String" do + factory :webdav_data_folder, class: 'String' do skip_create initialize_with do Nokogiri::XML::Builder.new do |xml| - xml["d"].multistatus( - "xmlns:d" => "DAV:", - "xmlns:s" => "http://sabredav.org/ns", - "xmlns:oc" => "http://owncloud.org/ns", - "xmlns:nc" => "http://nextcloud.org/ns" + xml['d'].multistatus( + 'xmlns:d' => 'DAV:', + 'xmlns:s' => 'http://sabredav.org/ns', + 'xmlns:oc' => 'http://owncloud.org/ns', + 'xmlns:nc' => 'http://nextcloud.org/ns' ) do - xml["d"].response do - xml["d"].href("/remote.php/dav/files/admin/Folder1") - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("11") - xml["oc"].size("6592") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:31:26 GMT") - xml["oc"].permissions("RGDNVCK") - xml["oc"].send(:"owner-display-name", "admin") + xml['d'].response do + xml['d'].href('/remote.php/dav/files/admin/Folder1') + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('11') + xml['oc'].size('6592') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') + xml['oc'].permissions('RGDNVCK') + xml['oc'].send(:'owner-display-name', 'admin') end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end - xml["d"].propstat do - xml["d"].prop do - xml["d"].getcontenttype + xml['d'].propstat do + xml['d'].prop do + xml['d'].getcontenttype end - xml["d"].status("HTTP/1.1 404 Not Found") + xml['d'].status('HTTP/1.1 404 Not Found') end end - xml["d"].response do - xml["d"].href("/remote.php/dav/files/admin/Folder1/logo.png") - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("21") - xml["oc"].size("2048") - xml["d"].getcontenttype("image/png") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:31:26 GMT") - xml["oc"].permissions("RGDNVW") - xml["oc"].send(:"owner-display-name", "admin") + xml['d'].response do + xml['d'].href('/remote.php/dav/files/admin/Folder1/logo.png') + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('21') + xml['oc'].size('2048') + xml['d'].getcontenttype('image/png') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') + xml['oc'].permissions('RGDNVW') + xml['oc'].send(:'owner-display-name', 'admin') end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end end - xml["d"].response do - xml["d"].href("/remote.php/dav/files/admin/Folder1/jingle.ogg") - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("22") - xml["oc"].size("22736218") - xml["d"].getcontenttype("audio/ogg") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:31:26 GMT") - xml["oc"].permissions("RGDNVW") - xml["oc"].send(:"owner-display-name", "admin") + xml['d'].response do + xml['d'].href('/remote.php/dav/files/admin/Folder1/jingle.ogg') + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('22') + xml['oc'].size('22736218') + xml['d'].getcontenttype('audio/ogg') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') + xml['oc'].permissions('RGDNVW') + xml['oc'].send(:'owner-display-name', 'admin') end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end end - xml["d"].response do - xml["d"].href("/remote.php/dav/files/admin/Folder1/notes.txt") - xml["d"].propstat do - xml["d"].prop do - xml["oc"].fileid("23") - xml["oc"].size("128") - xml["d"].getcontenttype("text/plain") - xml["d"].getlastmodified("Fri, 28 Oct 2022 14:31:26 GMT") - xml["oc"].permissions("RGDNVW") - xml["oc"].send(:"owner-display-name", "admin") + xml['d'].response do + xml['d'].href('/remote.php/dav/files/admin/Folder1/notes.txt') + xml['d'].propstat do + xml['d'].prop do + xml['oc'].fileid('23') + xml['oc'].size('128') + xml['d'].getcontenttype('text/plain') + xml['d'].getlastmodified('Fri, 28 Oct 2022 14:31:26 GMT') + xml['oc'].permissions('RGDNVW') + xml['oc'].send(:'owner-display-name', 'admin') end - xml["d"].status("HTTP/1.1 200 OK") + xml['d'].status('HTTP/1.1 200 OK') end end end diff --git a/modules/storages/spec/features/create_file_links_spec.rb b/modules/storages/spec/features/create_file_links_spec.rb index e08534c17fe6..0221ffaabf79 100644 --- a/modules/storages/spec/features/create_file_links_spec.rb +++ b/modules/storages/spec/features/create_file_links_spec.rb @@ -28,21 +28,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Managing file links in work package", :js, :webmock do +RSpec.describe 'Managing file links in work package', :js, :webmock do let(:permissions) { %i(view_work_packages edit_work_packages view_file_links manage_file_links) } let(:project) { create(:project) } let(:current_user) { create(:user, member_with_permissions: { project => permissions }) } - let(:work_package) { create(:work_package, project:, description: "Initial description") } + let(:work_package) { create(:work_package, project:, description: 'Initial description') } let(:oauth_application) { create(:oauth_application) } - let(:storage) { create(:nextcloud_storage, name: "My Storage", oauth_application:) } + let(:storage) { create(:nextcloud_storage, name: 'My Storage', oauth_application:) } let(:oauth_client) { create(:oauth_client, integration: storage) } let(:oauth_client_token) { create(:oauth_client_token, oauth_client:, user: current_user) } - let(:project_storage) { create(:project_storage, project:, storage:, project_folder_id: nil, project_folder_mode: "inactive") } - let(:file_link) { create(:file_link, container: work_package, storage:, origin_id: "22", origin_name: "jingle.ogg") } + let(:project_storage) { create(:project_storage, project:, storage:, project_folder_id: nil, project_folder_mode: 'inactive') } + let(:file_link) { create(:file_link, container: work_package, storage:, origin_id: '22', origin_name: 'jingle.ogg') } let(:root_xml_response) { create(:webdav_data) } let(:folder1_xml_response) { create(:webdav_data_folder) } @@ -64,9 +64,9 @@ stub_request(:get, "#{storage.host}/ocs/v1.php/cloud/user") .with( headers: { - "Authorization" => "Bearer #{oauth_client_token.access_token}", - "Ocs-Apirequest" => "true", - "Accept" => "application/json" + 'Authorization' => "Bearer #{oauth_client_token.access_token}", + 'Ocs-Apirequest' => 'true', + 'Accept' => "application/json" } ) .to_return(status: 200, body: "", headers: {}) @@ -82,66 +82,66 @@ wp_page.visit_tab! :files end - context "with select all in file picker enabled", with_flag: { storage_file_picking_select_all: true } do - it "must enable the user to select files from file picker to create file links" do - within_test_selector("op-tab-content--tab-section", text: "MY STORAGE", wait: 25) do + context 'with select all in file picker enabled', with_flag: { storage_file_picking_select_all: true } do + it 'must enable the user to select files from file picker to create file links' do + within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE', wait: 25) do expect(page).to have_list_item(count: 1) - expect(page).to have_list_item(text: "jingle.ogg") - page.click_on("Link existing files") + expect(page).to have_list_item(text: 'jingle.ogg') + page.click_on('Link existing files') end modal.expect_open - modal.expect_title("Select files") + modal.expect_title('Select files') modal.within_modal do - expect(page).to have_button("Select files to link", disabled: true) + expect(page).to have_button('Select files to link', disabled: true) - within(:list_item, text: "Manual.pdf") { page.click } + within(:list_item, text: 'Manual.pdf') { page.click } - expect(page).to have_button("Link 1 file", disabled: false) + expect(page).to have_button('Link 1 file', disabled: false) - within(:list_item, text: "Folder1") { page.click } + within(:list_item, text: 'Folder1') { page.click } - within(:list_item, text: "jingle.ogg") do - expect(page).to have_field(type: "checkbox", checked: true, disabled: true) + within(:list_item, text: 'jingle.ogg') do + expect(page).to have_field(type: 'checkbox', checked: true, disabled: true) end - page.click_on("Select all") - expect(page).to have_button("Link 3 files", disabled: false) + page.click_on('Select all') + expect(page).to have_button('Link 3 files', disabled: false) - within(:list_item, text: "notes.txt") { page.click } - expect(page).to have_button("Link 2 files", disabled: false) + within(:list_item, text: 'notes.txt') { page.click } + expect(page).to have_button('Link 2 files', disabled: false) - page.click_on("My Storage") - within(:list_item, text: "Manual.pdf") do - expect(page).to have_field(type: "checkbox", checked: true, disabled: false) + page.click_on('My Storage') + within(:list_item, text: 'Manual.pdf') do + expect(page).to have_field(type: 'checkbox', checked: true, disabled: false) end - page.click_on("Link 2 files") + page.click_on('Link 2 files') end - within_test_selector("op-tab-content--tab-section", text: "MY STORAGE") do + within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE') do expect(page).to have_list_item(count: 3) - expect(page).to have_list_item(text: "jingle.ogg") - expect(page).to have_list_item(text: "Manual.pdf") - expect(page).to have_list_item(text: "logo.png") + expect(page).to have_list_item(text: 'jingle.ogg') + expect(page).to have_list_item(text: 'Manual.pdf') + expect(page).to have_list_item(text: 'logo.png') end end end - it "must enable the user to remove a file link" do - within_test_selector("op-tab-content--tab-section", text: "MY STORAGE") do - within(:list_item, text: "jingle.ogg") do - page.find("span", text: "jingle.ogg").hover - page.click_on("Remove file link") + it 'must enable the user to remove a file link' do + within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE') do + within(:list_item, text: 'jingle.ogg') do + page.find('span', text: 'jingle.ogg').hover + page.click_on('Remove file link') end end modal.expect_open - modal.expect_title("Remove file link") + modal.expect_title('Remove file link') modal.within_modal do - page.click_on("Remove link") + page.click_on('Remove link') end - expect(page).not_to have_list_item(text: "jingle.ogg") + expect(page).not_to have_list_item(text: 'jingle.ogg') end end diff --git a/modules/storages/spec/features/delete_project_storage_and_file_links_spec.rb b/modules/storages/spec/features/delete_project_storage_and_file_links_spec.rb index c432d4dec0f6..b5747553eb86 100644 --- a/modules/storages/spec/features/delete_project_storage_and_file_links_spec.rb +++ b/modules/storages/spec/features/delete_project_storage_and_file_links_spec.rb @@ -28,18 +28,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper # Test if the deletion of a ProjectStorage actually deletes related FileLink # objects. -RSpec.describe "Delete ProjectStorage with FileLinks", :js, :webmock do +RSpec.describe 'Delete ProjectStorage with FileLinks', :js, :webmock do let(:user) { create(:user) } let(:role) { create(:project_role, permissions: [:manage_storages_in_project]) } let(:project) do create(:project, - name: "Project 1", - identifier: "demo-project", + name: 'Project 1', + identifier: 'demo-project', members: { user => role }, enabled_module_names: %i[storages work_package_tracking]) end @@ -64,35 +64,35 @@ login_as user end - it "deletes ProjectStorage with dependent FileLinks" do + it 'deletes ProjectStorage with dependent FileLinks' do # Go to Projects -> Settings -> File Storages visit project_settings_project_storages_path(project) # The list of enabled file storages should now contain Storage 1 - expect(page).to have_text("File storages available in this project") - expect(page).to have_text("Storage 1") + expect(page).to have_text('File storages available in this project') + expect(page).to have_text('Storage 1') # Press Delete icon to remove the storage from the project - page.find(".icon.icon-delete").click + page.find('.icon.icon-delete').click # Danger zone confirmation flow - expect(page).to have_css(".form--section-title", text: "DELETE FILE STORAGE") - expect(page).to have_css(".danger-zone--warning", text: "Deleting a file storage is an irreversible action.") - expect(page).to have_button("Delete", disabled: true) + expect(page).to have_css('.form--section-title', text: "DELETE FILE STORAGE") + expect(page).to have_css('.danger-zone--warning', text: "Deleting a file storage is an irreversible action.") + expect(page).to have_button('Delete', disabled: true) # Cancel Confirmation - page.click_link("Cancel") + page.click_link('Cancel') expect(page).to have_current_path project_settings_project_storages_path(project) - page.find(".icon.icon-delete").click + page.find('.icon.icon-delete').click # Approve Confirmation - page.fill_in "delete_confirmation", with: storage.name - page.click_button("Delete") + page.fill_in 'delete_confirmation', with: storage.name + page.click_button('Delete') # List of ProjectStorages empty again expect(page).to have_current_path project_settings_project_storages_path(project) - expect(page).to have_text(I18n.t("storages.no_results")) + expect(page).to have_text(I18n.t('storages.no_results')) # Also check in the database that ProjectStorage and dependent FileLinks are gone expect(Storages::ProjectStorage.count).to be 0 diff --git a/modules/storages/spec/features/manage_project_storage_spec.rb b/modules/storages/spec/features/manage_project_storage_spec.rb index 3d4ed0a8eef9..f022db3f0f53 100644 --- a/modules/storages/spec/features/manage_project_storage_spec.rb +++ b/modules/storages/spec/features/manage_project_storage_spec.rb @@ -151,8 +151,7 @@ # Press Edit icon to change the project folder mode to inactive page.find('.icon.icon-edit').click expect(page).to have_current_path edit_project_settings_project_storage_path(project_id: project, - id: Storages::ProjectStorage.last, - storages_project_storage: {project_folder_mode: 'manual'}) + id: Storages::ProjectStorage.last) expect(page).to have_text('Edit the file storage to this project') expect(page).to have_no_select('storages_project_storage_storage_id') expect(page).to have_text(storage.name) @@ -171,8 +170,7 @@ # Click Edit icon again but cancel the edit page.find('.icon.icon-edit').click expect(page).to have_current_path edit_project_settings_project_storage_path(project_id: project, - id: Storages::ProjectStorage.last, - storages_project_storage: {project_folder_mode: 'inactive'}) + id: Storages::ProjectStorage.last) expect(page).to have_text('Edit the file storage to this project') page.click_link('Cancel') expect(page).to have_current_path project_settings_project_storages_path(project) diff --git a/modules/storages/spec/features/shared_context.rb b/modules/storages/spec/features/shared_context.rb index 1082fa16786d..fc3566c906d3 100644 --- a/modules/storages/spec/features/shared_context.rb +++ b/modules/storages/spec/features/shared_context.rb @@ -28,11 +28,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require_relative "../support/pages/storage_tab" +require_relative '../support/pages/storage_tab' -RSpec.shared_context "with storages full access" do +RSpec.shared_context 'with storages full access' do current_user { user } end diff --git a/modules/storages/spec/features/show_file_links_spec.rb b/modules/storages/spec/features/show_file_links_spec.rb index 3cad19dd1f93..441d07ca928b 100644 --- a/modules/storages/spec/features/show_file_links_spec.rb +++ b/modules/storages/spec/features/show_file_links_spec.rb @@ -28,21 +28,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Showing of file links in work package", :js do +RSpec.describe 'Showing of file links in work package', :js do let(:permissions) { %i(view_work_packages edit_work_packages view_file_links manage_file_links) } let(:project) { create(:project) } let(:current_user) { create(:user, member_with_permissions: { project => permissions }) } - let(:work_package) { create(:work_package, project:, description: "Initial description") } + let(:work_package) { create(:work_package, project:, description: 'Initial description') } let(:oauth_application) { create(:oauth_application) } - let(:storage) { create(:nextcloud_storage, name: "My storage", oauth_application:) } + let(:storage) { create(:nextcloud_storage, name: 'My storage', oauth_application:) } let(:oauth_client) { create(:oauth_client, integration: storage) } let(:oauth_client_token) { create(:oauth_client_token, oauth_client:, user: current_user) } let(:project_storage) { create(:project_storage, project:, storage:) } - let(:file_link) { create(:file_link, container: work_package, storage:, origin_id: "42", origin_name: "logo.png") } + let(:file_link) { create(:file_link, container: work_package, storage:, origin_id: '42', origin_name: 'logo.png') } let(:wp_page) { Pages::FullWorkPackage.new(work_package, project) } let(:connection_manager) { instance_double(OAuthClients::ConnectionManager) } @@ -71,57 +71,57 @@ wp_page.visit_tab! :files end - context "if work package has associated file links" do - it "must show associated file links" do - expect(page).to have_test_selector("op-tab-content--tab-section", count: 2) - within_test_selector("op-tab-content--tab-section", text: "MY STORAGE") do + context 'if work package has associated file links' do + it 'must show associated file links' do + expect(page).to have_test_selector('op-tab-content--tab-section', count: 2) + within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE') do expect(page).to have_list_item(count: 1) - expect(page).to have_list_item(text: "logo.png") + expect(page).to have_list_item(text: 'logo.png') end end end - context "if user has no permission to see file links" do + context 'if user has no permission to see file links' do let(:permissions) { %i(view_work_packages edit_work_packages) } - it "must not show a file links section" do - expect(page).to have_test_selector("op-tab-content--tab-section", count: 1) + it 'must not show a file links section' do + expect(page).to have_test_selector('op-tab-content--tab-section', count: 1) end end - context "if project has no storage" do + context 'if project has no storage' do let(:project_storage) { {} } - it "must not show a file links section" do - expect(page).to have_test_selector("op-tab-content--tab-section", count: 1) + it 'must not show a file links section' do + expect(page).to have_test_selector('op-tab-content--tab-section', count: 1) end end - context "if user is not authorized in Nextcloud" do + context 'if user is not authorized in Nextcloud' do before do allow(connection_manager).to receive_messages(authorization_state: :failed_authorization, - get_authorization_uri: "https://example.com/authorize") + get_authorization_uri: 'https://example.com/authorize') end - it "must show storage information box with login button" do - within_test_selector("op-tab-content--tab-section", text: "MY STORAGE", wait: 25) do - expect(page).to have_button("Nextcloud login") - expect(page).to have_text("Login to Nextcloud") - expect(page).to have_list_item(text: "logo.png") + it 'must show storage information box with login button' do + within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE', wait: 25) do + expect(page).to have_button('Nextcloud login') + expect(page).to have_text('Login to Nextcloud') + expect(page).to have_list_item(text: 'logo.png') end end end - context "if an error occurred while authorizing to Nextcloud" do + context 'if an error occurred while authorizing to Nextcloud' do before do allow(connection_manager).to receive(:authorization_state).and_return(:error) end - it "must show storage information box" do - within_test_selector("op-tab-content--tab-section", text: "MY STORAGE", wait: 25) do + it 'must show storage information box' do + within_test_selector('op-tab-content--tab-section', text: 'MY STORAGE', wait: 25) do expect(page).to have_no_button - expect(page).to have_text("No Nextcloud connection") - expect(page).to have_list_item(text: "logo.png") + expect(page).to have_text('No Nextcloud connection') + expect(page).to have_list_item(text: 'logo.png') end end end diff --git a/modules/storages/spec/features/storages/admin/create_storage_spec.rb b/modules/storages/spec/features/storages/admin/create_storage_spec.rb index 85e7892292f3..d21972003f23 100644 --- a/modules/storages/spec/features/storages/admin/create_storage_spec.rb +++ b/modules/storages/spec/features/storages/admin/create_storage_spec.rb @@ -28,153 +28,153 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Admin Create a new file storage", +RSpec.describe 'Admin Create a new file storage', :js, :storage_server_helpers do - shared_let(:admin) { create(:admin, preferences: { time_zone: "Etc/UTC" }) } + shared_let(:admin) { create(:admin, preferences: { time_zone: 'Etc/UTC' }) } current_user { admin } - context "with Nextcloud Storage" do - let(:secret) { "awesome_secret" } + context 'with Nextcloud Storage' do + let(:secret) { 'awesome_secret' } before do allow(Doorkeeper::OAuth::Helpers::UniqueToken).to receive(:generate).and_return(secret) end - it "renders a Nextcloud specific multi-step form", :webmock do + it 'renders a Nextcloud specific multi-step form', :webmock do visit admin_settings_storages_path - expect(page).to be_axe_clean.within "#content" + expect(page).to be_axe_clean.within '#content' - within(".PageHeader") { click_on("Storage") } - within_test_selector("storages-select-provider-action-menu") { click_on("Nextcloud") } + within('.PageHeader') { click_on("Storage") } + within_test_selector('storages-select-provider-action-menu') { click_on('Nextcloud') } - expect(page).to have_current_path(select_provider_admin_settings_storages_path(provider: "nextcloud")) + expect(page).to have_current_path(select_provider_admin_settings_storages_path(provider: 'nextcloud')) - aggregate_failures "Select provider view" do + aggregate_failures 'Select provider view' do # Page Header - expect(page).to have_test_selector("storage-new-page-header--title", text: "New Nextcloud storage") - expect(page).to have_test_selector("storage-new-page-header--description", + expect(page).to have_test_selector('storage-new-page-header--title', text: 'New Nextcloud storage') + expect(page).to have_test_selector('storage-new-page-header--description', text: "Read our documentation on setting up a Nextcloud file storage " \ "integration for more information.") # General information - expect(page).to have_test_selector("storage-provider-configuration-instructions", + expect(page).to have_test_selector('storage-provider-configuration-instructions', text: "Please make sure you have administration privileges in your " \ "Nextcloud instance and the application “Integration OpenProject” " \ "is installed before doing the setup.") # OAuth application - expect(page).to have_test_selector("storage-openproject-oauth-label", text: "OpenProject OAuth") - expect(page).not_to have_test_selector("label-openproject_oauth_application_configured-status") + expect(page).to have_test_selector('storage-openproject-oauth-label', text: 'OpenProject OAuth') + expect(page).not_to have_test_selector('label-openproject_oauth_application_configured-status') # OAuth client - wait_for(page).to have_test_selector("storage-oauth-client-label", text: "Nextcloud OAuth") - expect(page).not_to have_test_selector("label-storage_oauth_client_configured-status") - expect(page).to have_test_selector("storage-oauth-client-id-description", + wait_for(page).to have_test_selector('storage-oauth-client-label', text: 'Nextcloud OAuth') + expect(page).not_to have_test_selector('label-storage_oauth_client_configured-status') + expect(page).to have_test_selector('storage-oauth-client-id-description', text: "Allow OpenProject to access Nextcloud data using OAuth.") # Automatically managed project folders - expect(page).to have_test_selector("storage-managed-project-folders-label", - text: "Automatically managed folders") - expect(page).not_to have_test_selector("label-managed-project-folders-status") - expect(page).to have_test_selector("storage-automatically-managed-project-folders-description", - text: "Let OpenProject create folders per project automatically.") + expect(page).to have_test_selector('storage-managed-project-folders-label', + text: 'Automatically managed folders') + expect(page).not_to have_test_selector('label-managed-project-folders-status') + expect(page).to have_test_selector('storage-automatically-managed-project-folders-description', + text: 'Let OpenProject create folders per project automatically.') end - aggregate_failures "General information" do - within_test_selector("storage-general-info-form") do - fill_in "Name", with: "My Nextcloud", fill_options: { clear: :backspace } - click_on "Save and continue" + aggregate_failures 'General information' do + within_test_selector('storage-general-info-form') do + fill_in 'Name', with: 'My Nextcloud', fill_options: { clear: :backspace } + click_on 'Save and continue' expect(page).to have_text("Host is not a valid URL.") mock_server_capabilities_response("https://example.com") mock_server_config_check_response("https://example.com") - fill_in "Host", with: "https://example.com" - click_on "Save and continue" + fill_in 'Host', with: 'https://example.com' + click_on 'Save and continue' end - expect(page).to have_test_selector("label-host_name_configured-status", text: "Completed") - expect(page).to have_test_selector("storage-description", text: "Nextcloud - My Nextcloud - https://example.com") + expect(page).to have_test_selector('label-host_name_configured-status', text: 'Completed') + expect(page).to have_test_selector('storage-description', text: "Nextcloud - My Nextcloud - https://example.com") end - aggregate_failures "OAuth application" do - within_test_selector("storage-openproject-oauth-application-form") do - warning_section = find_test_selector("storage-openproject_oauth_application_warning") - expect(warning_section).to have_text("The client secret value will not be accessible again after you close " \ - "this window. Please copy these values into the Nextcloud " \ - "OpenProject Integration settings.") - expect(warning_section).to have_link("Nextcloud OpenProject Integration settings", + aggregate_failures 'OAuth application' do + within_test_selector('storage-openproject-oauth-application-form') do + warning_section = find_test_selector('storage-openproject_oauth_application_warning') + expect(warning_section).to have_text('The client secret value will not be accessible again after you close ' \ + 'this window. Please copy these values into the Nextcloud ' \ + 'OpenProject Integration settings.') + expect(warning_section).to have_link('Nextcloud OpenProject Integration settings', href: "https://example.com/settings/admin/openproject") - storage = Storages::NextcloudStorage.find_by(host: "https://example.com") - expect(page).to have_css("#openproject_oauth_application_uid", + storage = Storages::NextcloudStorage.find_by(host: 'https://example.com') + expect(page).to have_css('#openproject_oauth_application_uid', value: storage.reload.oauth_application.uid) - expect(page).to have_css("#openproject_oauth_application_secret", + expect(page).to have_css('#openproject_oauth_application_secret', value: secret) - click_on "Done, continue" + click_on 'Done, continue' end end - aggregate_failures "OAuth Client" do - within_test_selector("storage-oauth-client-form") do - expect(page).to have_test_selector("storage-provider-credentials-instructions", - text: "Copy these values from Nextcloud Administration / OpenProject.") + aggregate_failures 'OAuth Client' do + within_test_selector('storage-oauth-client-form') do + expect(page).to have_test_selector('storage-provider-credentials-instructions', + text: 'Copy these values from Nextcloud Administration / OpenProject.') # With null values, form should render inline errors - expect(page).to have_css("#oauth_client_client_id", value: "") - expect(page).to have_css("#oauth_client_client_secret", value: "") - click_on "Save and continue" + expect(page).to have_css('#oauth_client_client_id', value: '') + expect(page).to have_css('#oauth_client_client_secret', value: '') + click_on 'Save and continue' expect(page).to have_text("Client ID can't be blank.") expect(page).to have_text("Client secret can't be blank.") # Happy path - Submit valid values - fill_in "Nextcloud OAuth Client ID", with: "1234567890" - fill_in "Nextcloud OAuth Client Secret", with: "0987654321" - click_on "Save and continue" + fill_in 'Nextcloud OAuth Client ID', with: '1234567890' + fill_in 'Nextcloud OAuth Client Secret', with: '0987654321' + click_on 'Save and continue' end - expect(page).to have_test_selector("label-storage_oauth_client_configured-status", text: "Completed") - expect(page).to have_test_selector("storage-oauth-client-id-description", text: "OAuth Client ID: 1234567890") + expect(page).to have_test_selector('label-storage_oauth_client_configured-status', text: 'Completed') + expect(page).to have_test_selector('storage-oauth-client-id-description', text: "OAuth Client ID: 1234567890") end - aggregate_failures "Automatically managed project folders" do - within_test_selector("storage-automatically-managed-project-folders-form") do + aggregate_failures 'Automatically managed project folders' do + within_test_selector('storage-automatically-managed-project-folders-form') do automatically_managed_switch = page.find('[name="storages_nextcloud_storage[automatic_management_enabled]"]') - application_password_input = page.find_by_id("storages_nextcloud_storage_password") + application_password_input = page.find_by_id('storages_nextcloud_storage_password') expect(automatically_managed_switch).to be_checked expect(application_password_input.value).to be_empty # Clicking submit with application password empty should show an error - click_on("Done, complete setup") + click_on('Done, complete setup') expect(page).to have_text("Password can't be blank.") # Test the error path for an invalid storage password. # Mock a valid response (=401) for example.com, so the password validation should fail - mock_nextcloud_application_credentials_validation("https://example.com", password: "1234567890", + mock_nextcloud_application_credentials_validation('https://example.com', password: "1234567890", response_code: 401) automatically_managed_switch = page.find('[name="storages_nextcloud_storage[automatic_management_enabled]"]') expect(automatically_managed_switch).to be_checked - fill_in "Application password", with: "1234567890" + fill_in 'Application password', with: "1234567890" # Clicking submit with application password empty should show an error - click_on("Done, complete setup") + click_on('Done, complete setup') expect(page).to have_text("Password is not valid.") # Test the happy path for a valid storage password. # Mock a valid response (=200) for example.com, so the password validation should succeed # Fill in application password and submit - mock_nextcloud_application_credentials_validation("https://example.com", password: "1234567890") + mock_nextcloud_application_credentials_validation('https://example.com', password: "1234567890") automatically_managed_switch = page.find('[name="storages_nextcloud_storage[automatic_management_enabled]"]') expect(automatically_managed_switch).to be_checked - fill_in "Application password", with: "1234567890" - click_on("Done, complete setup") + fill_in 'Application password', with: "1234567890" + click_on('Done, complete setup') end expect(page).to have_current_path(admin_settings_storages_path) @@ -187,14 +187,14 @@ end end - context "with OneDrive Storage and enterprise token missing", with_ee: false do - it "renders enterprise icon and redirects to upsale", :webmock do + context 'with OneDrive Storage and enterprise token missing', with_ee: false do + it 'renders enterprise icon and redirects to upsale', :webmock do visit admin_settings_storages_path - within(".PageHeader") { click_on("Storage") } + within('.PageHeader') { click_on("Storage") } - within_test_selector("storages-select-provider-action-menu") do - expect(page).to have_css(".octicon-op-enterprise-addons") - click_on("OneDrive/SharePoint") + within_test_selector('storages-select-provider-action-menu') do + expect(page).to have_css('.octicon-op-enterprise-addons') + click_on('OneDrive/SharePoint') end expect(page).to have_current_path(upsale_admin_settings_storages_path) @@ -202,81 +202,81 @@ end end - context "with OneDrive Storage", with_ee: %i[one_drive_sharepoint_file_storage] do - it "renders a One Drive specific multi-step form", :webmock do + context 'with OneDrive Storage', with_ee: %i[one_drive_sharepoint_file_storage] do + it 'renders a One Drive specific multi-step form', :webmock do visit admin_settings_storages_path - expect(page).to be_axe_clean.within "#content" + expect(page).to be_axe_clean.within '#content' - within(".PageHeader") { click_on("Storage") } - within_test_selector("storages-select-provider-action-menu") { click_on("OneDrive/SharePoint") } + within('.PageHeader') { click_on("Storage") } + within_test_selector('storages-select-provider-action-menu') { click_on('OneDrive/SharePoint') } - expect(page).to have_current_path(select_provider_admin_settings_storages_path(provider: "one_drive")) + expect(page).to have_current_path(select_provider_admin_settings_storages_path(provider: 'one_drive')) - aggregate_failures "Select provider view" do + aggregate_failures 'Select provider view' do # Page Header - expect(page).to have_test_selector("storage-new-page-header--title", text: "New OneDrive/SharePoint storage") - expect(page).to have_test_selector("storage-new-page-header--description", + expect(page).to have_test_selector('storage-new-page-header--title', text: 'New OneDrive/SharePoint storage') + expect(page).to have_test_selector('storage-new-page-header--description', text: "Read our documentation on setting up a OneDrive/SharePoint " \ "file storage integration for more information.") # General information - expect(page).to have_test_selector("storage-provider-configuration-instructions", + expect(page).to have_test_selector('storage-provider-configuration-instructions', text: "Please make sure you have administration privileges in the " \ "Azure portal or contact your Microsoft administrator before " \ "doing the setup. In the portal, you also need to register an " \ "Azure application or use an existing one for authentication.") # OAuth client - wait_for(page).to have_test_selector("storage-oauth-client-label", text: "Azure OAuth") - expect(page).not_to have_test_selector("label-storage_oauth_client_configured-status") - expect(page).to have_test_selector("storage-oauth-client-id-description", + wait_for(page).to have_test_selector('storage-oauth-client-label', text: 'Azure OAuth') + expect(page).not_to have_test_selector('label-storage_oauth_client_configured-status') + expect(page).to have_test_selector('storage-oauth-client-id-description', text: "Allow OpenProject to access Azure data using OAuth " \ "to connect OneDrive/Sharepoint.") - expect(page).to have_test_selector("storage-redirect-uri-description", + expect(page).to have_test_selector('storage-redirect-uri-description', text: "Complete the setup with the correct URI redirection.") end - aggregate_failures "General information" do - within_test_selector("storage-general-info-form") do - fill_in "Name", with: "My OneDrive", fill_options: { clear: :backspace } - fill_in "Directory (tenant) ID", with: "029d4741-a4be-44c6-a8e4-e4eff7b19f65" - click_on "Save and continue" + aggregate_failures 'General information' do + within_test_selector('storage-general-info-form') do + fill_in 'Name', with: 'My OneDrive', fill_options: { clear: :backspace } + fill_in 'Directory (tenant) ID', with: '029d4741-a4be-44c6-a8e4-e4eff7b19f65' + click_on 'Save and continue' expect(page).to have_text("Drive ID can't be blank.") - fill_in "Drive ID", with: "1234567890" - click_on "Save and continue" + fill_in 'Drive ID', with: '1234567890' + click_on 'Save and continue' end - wait_for(page).to have_test_selector("label-host_name_configured-storage_tenant_drive_configured-status", - text: "Completed") - expect(page).to have_test_selector("storage-description", text: "OneDrive/SharePoint - My OneDrive") + wait_for(page).to have_test_selector('label-host_name_configured-storage_tenant_drive_configured-status', + text: 'Completed') + expect(page).to have_test_selector('storage-description', text: 'OneDrive/SharePoint - My OneDrive') end - aggregate_failures "OAuth Client" do - within_test_selector("storage-oauth-client-form") do - expect(page).to have_test_selector("storage-provider-credentials-instructions", - text: "Copy these values from the desired application in the " \ - "Azure portal.") + aggregate_failures 'OAuth Client' do + within_test_selector('storage-oauth-client-form') do + expect(page).to have_test_selector('storage-provider-credentials-instructions', + text: 'Copy these values from the desired application in the ' \ + 'Azure portal.') # With null values, upon submit validation errors are show - expect(page).to have_css("#oauth_client_client_id", value: "") - expect(page).to have_css("#oauth_client_client_secret", value: "") - click_on "Save and continue" + expect(page).to have_css('#oauth_client_client_id', value: '') + expect(page).to have_css('#oauth_client_client_secret', value: '') + click_on 'Save and continue' expect(page).to have_text("Client ID can't be blank.") expect(page).to have_text("Client secret can't be blank.") # Happy path - Submit valid values - fill_in "Azure OAuth Application (client) ID", with: "1234567890" - fill_in "Azure OAuth Client Secret Value", with: "0987654321" - expect(find_test_selector("storage-oauth-client-submit-button")).not_to be_disabled - click_on "Save and continue" + fill_in 'Azure OAuth Application (client) ID', with: '1234567890' + fill_in 'Azure OAuth Client Secret Value', with: '0987654321' + expect(find_test_selector('storage-oauth-client-submit-button')).not_to be_disabled + click_on 'Save and continue' - expect(page).to have_test_selector("storage-oauth-client-redirect-uri") + expect(page).to have_test_selector('storage-oauth-client-redirect-uri') - click_on "Done, complete setup" + click_on 'Done, complete setup' end expect(page).to have_current_path(admin_settings_storages_path) @@ -289,9 +289,9 @@ end end - describe "Select provider page" do - context "when navigating directly to the page" do - it "redirects you back to the index page" do + describe 'Select provider page' do + context 'when navigating directly to the page' do + it 'redirects you back to the index page' do visit select_provider_admin_settings_storages_path expect(page).to have_current_path(admin_settings_storages_path) @@ -299,9 +299,9 @@ end end - context "when navigating to the page with an invalid provider" do - it "redirects you back to the index page" do - visit select_provider_admin_settings_storages_path(provider: "foobar") + context 'when navigating to the page with an invalid provider' do + it 'redirects you back to the index page' do + visit select_provider_admin_settings_storages_path(provider: 'foobar') expect(page).to have_current_path(admin_settings_storages_path) wait_for(page).to have_text("Please select a valid storage provider.") diff --git a/modules/storages/spec/features/storages/admin/edit_storage_spec.rb b/modules/storages/spec/features/storages/admin/edit_storage_spec.rb index bd50ffc47659..cc1a7de8142a 100644 --- a/modules/storages/spec/features/storages/admin/edit_storage_spec.rb +++ b/modules/storages/spec/features/storages/admin/edit_storage_spec.rb @@ -227,18 +227,8 @@ end end - context 'with Nextcloud Storage and not automatically managed' do - let(:storage) { create(:nextcloud_storage, :as_not_automatically_managed, name: 'Cloud Storage') } - - it 'does not render health status information' do - visit edit_admin_settings_storage_path(storage) - - expect(page).not_to have_test_selector('storage-health-label-pending', text: 'Pending') - end - end - - context 'with OneDrive/SharePoint Storage' do - let(:storage) { create(:one_drive_storage, :as_automatically_managed, name: 'Test Drive') } + context 'with OneDrive Storage' do + let(:storage) { create(:one_drive_storage, name: 'Test Drive') } let(:oauth_client) { create(:oauth_client, integration: storage) } before { oauth_client } @@ -246,9 +236,7 @@ it 'renders an edit view', :webmock do visit edit_admin_settings_storage_path(storage) - expect(page).to be_axe_clean - .within('#content') - .skipping('heading-order') + expect(page).to be_axe_clean.within '#content' expect(page).to have_test_selector('storage-new-page-header--title', text: 'Test Drive (OneDrive/SharePoint)') @@ -326,21 +314,5 @@ expect(page).to have_test_selector('storage-oauth-client-id-description', text: "OAuth Client ID: 1234567890") end end - - it 'renders health status information' do - visit edit_admin_settings_storage_path(storage) - - expect(page).to have_test_selector('storage-health-label-pending', text: 'Pending') - end - end - - context 'with OneDrive/SharePoint Storage and not automatically managed' do - let(:storage) { create(:one_drive_storage, :as_not_automatically_managed, name: 'Cloud Storage') } - - it 'does not render health status information' do - visit edit_admin_settings_storage_path(storage) - - expect(page).not_to have_test_selector('storage-health-label-pending', text: 'Pending') - end end end diff --git a/modules/storages/spec/features/storages/admin/index_storages_spec.rb b/modules/storages/spec/features/storages/admin/index_storages_spec.rb index 1d7e00cb790d..5ee804522e3f 100644 --- a/modules/storages/spec/features/storages/admin/index_storages_spec.rb +++ b/modules/storages/spec/features/storages/admin/index_storages_spec.rb @@ -28,17 +28,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Admin List File storages", +RSpec.describe 'Admin List File storages', :js, :storage_server_helpers do - shared_let(:admin) { create(:admin, preferences: { time_zone: "Etc/UTC" }) } + shared_let(:admin) { create(:admin, preferences: { time_zone: 'Etc/UTC' }) } current_user { admin } - context "with storages" do + context 'with storages' do shared_let(:nextcloud_storage) { create(:nextcloud_storage) } shared_let(:one_drive_storage) { create(:one_drive_storage) } @@ -46,32 +46,32 @@ visit admin_settings_storages_path end - it "renders a list of all storages" do - within :css, "#content" do + it 'renders a list of all storages' do + within :css, '#content' do expect(page).to have_list_item(count: 2) expect(page).to have_list_item(nextcloud_storage.name) expect(page).to have_list_item(one_drive_storage.name) end end - it "renders content that is accessible" do - expect(page).to be_axe_clean.within("#content") + it 'renders content that is accessible' do + expect(page).to be_axe_clean.within('#content') end end - context "with no storages" do + context 'with no storages' do before do visit admin_settings_storages_path end - it "renders a blank slate" do - expect(page).to have_title("File storages") - expect(page.find(".PageHeader-title")).to have_text("File storages") + it 'renders a blank slate' do + expect(page).to have_title('File storages') + expect(page.find('.PageHeader-title')).to have_text('File storages') expect(page).to have_text("You don't have any storages yet.") end - it "renders content that is accessible" do - expect(page).to be_axe_clean.within("#content") + it 'renders content that is accessible' do + expect(page).to be_axe_clean.within('#content') end end end diff --git a/modules/storages/spec/features/storages/project_settings/oauth_access_grant_spec.rb b/modules/storages/spec/features/storages/project_settings/oauth_access_grant_spec.rb index bdbc78c13065..18e74a656954 100644 --- a/modules/storages/spec/features/storages/project_settings/oauth_access_grant_spec.rb +++ b/modules/storages/spec/features/storages/project_settings/oauth_access_grant_spec.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "OAuth Access Grant Nudge upon adding a storage to a project", +RSpec.describe 'OAuth Access Grant Nudge upon adding a storage to a project', :js, :webmock do - shared_let(:user) { create(:user, preferences: { time_zone: "Etc/UTC" }) } + shared_let(:user) { create(:user, preferences: { time_zone: 'Etc/UTC' }) } shared_let(:role) do create(:project_role, permissions: %i[manage_storages_in_project @@ -54,7 +54,7 @@ current_user { user } - let(:nonce) { "57a17c3f-b2ed-446e-9dd8-651ba3aec37d" } + let(:nonce) { '57a17c3f-b2ed-446e-9dd8-651ba3aec37d' } let(:redirect_uri) do "#{CGI.escape(OpenProject::Application.root_url)}/oauth_clients/#{storage.oauth_client.client_id}/callback" end @@ -64,24 +64,24 @@ allow(SecureRandom).to receive(:uuid).and_return(nonce).ordered end - it "adds a storage, nudges the project admin to grant OAuth access" do + it 'adds a storage, nudges the project admin to grant OAuth access' do visit project_settings_project_storages_path(project_id: project) - click_on("Storage") + click_on('Storage') - expect(page).to have_select("Storage", options: ["#{storage.name} (nextcloud)"]) - click_on("Continue") + expect(page).to have_select('Storage', options: ["#{storage.name} (nextcloud)"]) + click_on('Continue') expect(page).to have_checked_field("New folder with automatically managed permissions") - click_on("Add") + click_on('Add') - expect(page).to have_text("File storages available in this project") + expect(page).to have_text('File storages available in this project') expect(page).to have_text(storage.name) - within_test_selector("oauth-access-grant-nudge-modal") do + within_test_selector('oauth-access-grant-nudge-modal') do expect(page).to be_axe_clean - expect(page).to have_text("One more step...") - click_on("Login") + expect(page).to have_text('One more step...') + click_on('Login') wait_for(page).to have_current_path("/index.php/apps/oauth2/authorize?client_id=#{storage.oauth_client.client_id}&" \ "redirect_uri=#{redirect_uri}&response_type=code&state=#{nonce}") end diff --git a/modules/storages/spec/features/storages_menu_links_spec.rb b/modules/storages/spec/features/storages_menu_links_spec.rb index 63d4347af018..969b12c2ad73 100644 --- a/modules/storages/spec/features/storages_menu_links_spec.rb +++ b/modules/storages/spec/features/storages_menu_links_spec.rb @@ -31,25 +31,23 @@ require 'spec_helper' require_module_spec_helper -RSpec.describe 'Storage links in project menu' do +RSpec.describe 'Storage links in project menu', :js, :with_cuprite do include EnsureConnectionPathHelper - shared_let(:project) { create(:project, enabled_module_names: %i[storages]) } - shared_let(:storage_configured_linked1) { create(:nextcloud_storage_configured, :as_automatically_managed, name: "Storage 1") } - shared_let(:project_storage1) do - create(:project_storage, :as_automatically_managed, project:, storage: storage_configured_linked1) - end - shared_let(:storage_configured_linked2) { create(:nextcloud_storage_configured, name: "Storage 2") } - shared_let(:project_storage2) do + let!(:storage_configured_linked1) { create(:nextcloud_storage_configured, :as_automatically_managed, name: "Storage 1") } + let!(:project_storage1) { create(:project_storage, :as_automatically_managed, project:, storage: storage_configured_linked1) } + let!(:storage_configured_linked2) { create(:nextcloud_storage_configured, name: "Storage 2") } + let!(:project_storage2) do create(:project_storage, project_folder_mode: 'inactive', project:, storage: storage_configured_linked2) end - shared_let(:storage_configured_linked3) { create(:nextcloud_storage_configured, name: "Storage 3") } - shared_let(:project_storage3) do + let!(:storage_configured_linked3) { create(:nextcloud_storage_configured, name: "Storage 3") } + let!(:project_storage3) do create(:project_storage, project_folder_mode: 'manual', project:, storage: storage_configured_linked3) end - shared_let(:storage_configured_unlinked) { create(:nextcloud_storage_configured, name: "Storage 4") } - shared_let(:storage_unconfigured_linked) { create(:nextcloud_storage, name: "Storage 5") } - shared_let(:project_storage4) { create(:project_storage, project:, storage: storage_unconfigured_linked) } + let!(:storage_configured_unlinked) { create(:nextcloud_storage_configured, name: "Storage 4") } + let!(:storage_unconfigured_linked) { create(:nextcloud_storage, name: "Storage 5") } + let!(:project_storage4) { create(:project_storage, project:, storage: storage_unconfigured_linked) } + let!(:project) { create(:project, enabled_module_names: %i[storages]) } let(:user) { create(:user, member_with_permissions: { project => permissions }) } before do @@ -84,22 +82,6 @@ expect(page).to have_no_link(storage_configured_unlinked.name) expect(page).to have_no_link(storage_unconfigured_linked.name) end - - context 'when OP has been installed behind prefix' do - let(:prefix) { '/qwerty' } - - before { allow(OpenProject::Configuration).to receive(:rails_relative_url_root).and_return(prefix) } - - it 'has all links prefixed' do - visit(project_path(id: project.id)) - - expect(page).to have_link(storage_configured_linked1.name, href: ensure_connection_path(project_storage1)) - expect(page).to have_link(storage_configured_linked2.name, href: ensure_connection_path(project_storage2)) - expect(page).to have_link(storage_configured_linked3.name, href: ensure_connection_path(project_storage3)) - expect(page).to have_no_link(storage_configured_unlinked.name) - expect(page).to have_no_link(storage_unconfigured_linked.name) - end - end end context 'read_files' do diff --git a/modules/storages/spec/features/storages_module_spec.rb b/modules/storages/spec/features/storages_module_spec.rb index 06af43e500ae..5b17f8fe2d2b 100644 --- a/modules/storages/spec/features/storages_module_spec.rb +++ b/modules/storages/spec/features/storages_module_spec.rb @@ -28,116 +28,116 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Storages module", :js do +RSpec.describe 'Storages module', :js do current_user { create(:admin) } let(:role) { create(:project_role, permissions: %i[manage_storages_in_project select_project_modules edit_project]) } let(:storage) { create(:nextcloud_storage, name: "Storage 1") } let(:project) { create(:project, enabled_module_names: %i[storages work_package_tracking]) } - shared_examples_for "content section has storages module" do |is_upcase = false| + shared_examples_for 'content section has storages module' do |is_upcase = false| it 'must show "storages" in content section' do - within "#content" do + within '#content' do text = I18n.t(:project_module_storages) expect(page).to have_text(is_upcase ? text.upcase : text) end end end - shared_examples_for "sidebar has storages module" do + shared_examples_for 'sidebar has storages module' do it 'must show "storages" in sidebar' do - within "#menu-sidebar" do + within '#menu-sidebar' do expect(page).to have_text(I18n.t(:project_module_storages)) end end end - shared_examples_for "has storages module" do |sections: %i[content sidebar], is_upcase: false| + shared_examples_for 'has storages module' do |sections: %i[content sidebar], is_upcase: false| before do visit(path) end - include_examples "content section has storages module", is_upcase if sections.include?(:content) - include_examples "sidebar has storages module" if sections.include?(:sidebar) + include_examples 'content section has storages module', is_upcase if sections.include?(:content) + include_examples 'sidebar has storages module' if sections.include?(:sidebar) end - context "when in administration" do - context "when showing index page" do - it_behaves_like "has storages module" do + context 'when in administration' do + context 'when showing index page' do + it_behaves_like 'has storages module' do let(:path) { admin_index_path } end end - context "when showing system project settings page" do - it_behaves_like "has storages module", sections: [:content] do + context 'when showing system project settings page' do + it_behaves_like 'has storages module', sections: [:content] do let(:path) { admin_settings_projects_path } end end - context "when showing system storage settings page" do + context 'when showing system storage settings page' do before do visit admin_settings_storages_path end - it "must show the page" do + it 'must show the page' do expect(page).to have_text(I18n.t(:project_module_storages)) end end - context "when creating a new role" do - it_behaves_like "has storages module", sections: [:content], is_upcase: true do + context 'when creating a new role' do + it_behaves_like 'has storages module', sections: [:content], is_upcase: true do let(:path) { new_role_path } end end - context "when editing a role" do - it_behaves_like "has storages module", sections: [:content], is_upcase: true do + context 'when editing a role' do + it_behaves_like 'has storages module', sections: [:content], is_upcase: true do let(:path) { edit_role_path(role) } end end - context "when showing the role permissions report" do - it_behaves_like "has storages module", sections: [:content], is_upcase: true do + context 'when showing the role permissions report' do + it_behaves_like 'has storages module', sections: [:content], is_upcase: true do let(:path) { report_roles_path(role) } end end end - context "when in project administration" do + context 'when in project administration' do before do storage project end - context "when showing the project module settings" do - it_behaves_like "has storages module" do + context 'when showing the project module settings' do + it_behaves_like 'has storages module' do let(:path) { project_settings_modules_path(project) } end end - context "when showing project storages settings page" do - context "with storages module is enabled" do + context 'when showing project storages settings page' do + context 'with storages module is enabled' do before do visit project_settings_project_storages_path(project) end - it "must show the page" do - expect(page).to have_text(I18n.t("storages.page_titles.project_settings.index")) + it 'must show the page' do + expect(page).to have_text(I18n.t('storages.page_titles.project_settings.index')) end end - context "with storages module is disabled" do + context 'with storages module is disabled' do let(:project) { create(:project, enabled_module_names: %i[work_package_tracking]) } before do visit project_settings_project_storages_path(project) end - it "mustn't show the page" do - expect(page).to have_no_text(I18n.t("storages.page_titles.project_settings.index")) + it 'mustn\'t show the page' do + expect(page).to have_no_text(I18n.t('storages.page_titles.project_settings.index')) end end end diff --git a/modules/storages/spec/features/view_project_storage_members_spec.rb b/modules/storages/spec/features/view_project_storage_members_spec.rb index 5a05e768a6de..24a2f9d44387 100644 --- a/modules/storages/spec/features/view_project_storage_members_spec.rb +++ b/modules/storages/spec/features/view_project_storage_members_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Project storage members connection status view" do +RSpec.describe 'Project storage members connection status view' do let(:user) { create(:user) } let(:admin_user) { create(:admin) } let(:connected_user) { create(:user) } @@ -49,34 +49,34 @@ connected_no_permissions_user]) end - it "cannot be accessed without being logged in" do + it 'cannot be accessed without being logged in' do visit project_settings_project_storage_members_path(project, project_storage_id: project_storage.id) - expect(page).to have_title("Sign in | OpenProject") - expect(page).to have_no_text("Members connection status") + expect(page).to have_title('Sign in | OpenProject') + expect(page).to have_no_text('Members connection status') end - it "lists project members connection statuses" do + it 'lists project members connection statuses' do login_as user # Go to Projects -> Settings -> File Storages visit project_settings_project_storages_path(project) - expect(page).to have_title("File storages") + expect(page).to have_title('File storages') expect(page).to have_text(storage.name) - page.find(".icon.icon-group").click + page.find('.icon.icon-group').click # Members connection status page expect(page).to have_current_path project_settings_project_storage_members_path(project_id: project, project_storage_id: project_storage) - aggregate_failures "Verifying Connection Statuses" do + aggregate_failures 'Verifying Connection Statuses' do [ - [user, "Not connected. The user should login to the storage via the following link."], - [admin_user, "Connected"], - [connected_user, "Connected"], - [connected_no_permissions_user, "User role has no storages permissions"], - [disconnected_user, "Not connected. The user should login to the storage via the following link."] + [user, 'Not connected. The user should login to the storage via the following link.'], + [admin_user, 'Connected'], + [connected_user, 'Connected'], + [connected_no_permissions_user, 'User role has no storages permissions'], + [disconnected_user, 'Not connected. The user should login to the storage via the following link.'] ].each do |(principal, status)| expect(page).to have_css("#member-#{principal.id} .name", text: principal.name) expect(page).to have_css("#member-#{principal.id} .status", text: status) @@ -84,7 +84,7 @@ end end - it "lists no results when there are no project members" do + it 'lists no results when there are no project members' do login_as admin_user project_no_members = create(:project, enabled_module_names: %i[storages]) project_storage_no_members = create(:project_storage, :as_automatically_managed, project: project_no_members, storage:) @@ -92,16 +92,16 @@ # Go to Projects -> Settings -> File Storages visit project_settings_project_storages_path(project_no_members) - expect(page).to have_title("File storages") + expect(page).to have_title('File storages') expect(page).to have_text(storage.name) - page.find(".icon.icon-group").click + page.find('.icon.icon-group').click # Members connection status page expected_current_path = project_settings_project_storage_members_path(project_id: project_no_members, project_storage_id: project_storage_no_members) expect(page).to have_current_path(expected_current_path) - expect(page).to have_text("No members to display.") + expect(page).to have_text('No members to display.') end def create_project_with_storage_and_members diff --git a/modules/storages/spec/lib/api/v3/file_links/file_link_representer_parsing_spec.rb b/modules/storages/spec/lib/api/v3/file_links/file_link_representer_parsing_spec.rb index 00bedb0b16d9..397683dfc1a0 100644 --- a/modules/storages/spec/lib/api/v3/file_links/file_link_representer_parsing_spec.rb +++ b/modules/storages/spec/lib/api/v3/file_links/file_link_representer_parsing_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe API::V3::FileLinks::FileLinkRepresenter, "parsing" do +RSpec.describe API::V3::FileLinks::FileLinkRepresenter, 'parsing' do include API::V3::Utilities::PathHelper let(:file_link) { build_stubbed(:file_link) } @@ -45,7 +45,7 @@ .and_return storage end - describe "parsing" do + describe 'parsing' do subject(:parsed) { representer.from_hash parsed_hash } let(:representer) do @@ -71,8 +71,8 @@ } end - describe "storage" do - context "if storage url is given with trailing slashes" do + describe 'storage' do + context 'if storage url is given with trailing slashes' do let(:parsed_hash) do { "_links" => { @@ -83,12 +83,12 @@ } end - it "is parsed correctly" do + it 'is parsed correctly' do expect(parsed).to have_attributes(storage_id: storage.id) end end - context "if storage is given as resource" do + context 'if storage is given as resource' do let(:parsed_hash) do { "_links" => { @@ -99,22 +99,22 @@ } end - it "is parsed correctly" do + it 'is parsed correctly' do expect(parsed).to have_attributes(storage_id: storage.id) end end end - describe "originData" do - it "is parsed correctly" do + describe 'originData' do + it 'is parsed correctly' do expect(parsed).to have_attributes(storage_id: storage.id, origin_id: "5503", origin_name: "logo.png", origin_mime_type: "image/png", origin_created_by_name: "Luke Skywalker", origin_last_modified_by_name: "Anakin Skywalker", - origin_created_at: DateTime.new(2021, 12, 19, 9, 42, 10.17, "+00:00").in_time_zone, - origin_updated_at: DateTime.new(2021, 12, 20, 14, 0, 13.987, "+00:00").in_time_zone) + origin_created_at: DateTime.new(2021, 12, 19, 9, 42, 10.17, '+00:00').in_time_zone, + origin_updated_at: DateTime.new(2021, 12, 20, 14, 0, 13.987, '+00:00').in_time_zone) end end end diff --git a/modules/storages/spec/lib/api/v3/file_links/file_link_representer_rendering_spec.rb b/modules/storages/spec/lib/api/v3/file_links/file_link_representer_rendering_spec.rb index ff4d5bcc29d4..c9c706618b77 100644 --- a/modules/storages/spec/lib/api/v3/file_links/file_link_representer_rendering_spec.rb +++ b/modules/storages/spec/lib/api/v3/file_links/file_link_representer_rendering_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe API::V3::FileLinks::FileLinkRepresenter, "rendering" do +RSpec.describe API::V3::FileLinks::FileLinkRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:storage) { build_stubbed(:nextcloud_storage) } let(:container) { build_stubbed(:work_package) } let(:project) { container.project } - let(:creator) { build_stubbed(:user, firstname: "Rey", lastname: "Palpatine") } + let(:creator) { build_stubbed(:user, firstname: 'Rey', lastname: 'Palpatine') } let(:origin_status) { :view_allowed } let(:file_link) { build_stubbed(:file_link, storage:, container:, creator:, origin_status:) } let(:user) { build_stubbed(:user) } @@ -45,162 +45,162 @@ subject(:generated) { representer.to_json } - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { "/api/v3/file_links/#{file_link.id}" } let(:title) { file_link.name } end end - describe "storage" do - it_behaves_like "has a titled link" do - let(:link) { "storage" } + describe 'storage' do + it_behaves_like 'has a titled link' do + let(:link) { 'storage' } let(:href) { "/api/v3/storages/#{storage.id}" } let(:title) { storage.name } end end - describe "container" do - it_behaves_like "has a titled link" do - let(:link) { "container" } + describe 'container' do + it_behaves_like 'has a titled link' do + let(:link) { 'container' } let(:href) { "/api/v3/work_packages/#{container.id}" } let(:title) { container.name } end end - describe "creator" do - it_behaves_like "has a titled link" do - let(:link) { "creator" } + describe 'creator' do + it_behaves_like 'has a titled link' do + let(:link) { 'creator' } let(:href) { "/api/v3/users/#{creator.id}" } let(:title) { creator.name } end end - describe "delete" do + describe 'delete' do let(:permission) { :manage_file_links } - it_behaves_like "has an untitled action link" do - let(:link) { "delete" } + it_behaves_like 'has an untitled action link' do + let(:link) { 'delete' } let(:href) { "/api/v3/file_links/#{file_link.id}" } let(:method) { :delete } end end - describe "status" do - context "with permission" do - it_behaves_like "has a titled link" do - let(:link) { "status" } - let(:href) { "urn:openproject-org:api:v3:file-links:permission:ViewAllowed" } - let(:title) { "View allowed" } + describe 'status' do + context 'with permission' do + it_behaves_like 'has a titled link' do + let(:link) { 'status' } + let(:href) { 'urn:openproject-org:api:v3:file-links:permission:ViewAllowed' } + let(:title) { 'View allowed' } end end - context "without permission" do + context 'without permission' do let(:origin_status) { :view_not_allowed } - it_behaves_like "has a titled link" do - let(:link) { "status" } - let(:href) { "urn:openproject-org:api:v3:file-links:permission:ViewNotAllowed" } - let(:title) { "View not allowed" } + it_behaves_like 'has a titled link' do + let(:link) { 'status' } + let(:href) { 'urn:openproject-org:api:v3:file-links:permission:ViewNotAllowed' } + let(:title) { 'View not allowed' } end end - context "if not found" do + context 'if not found' do let(:origin_status) { :not_found } - it_behaves_like "has a titled link" do - let(:link) { "status" } - let(:href) { "urn:openproject-org:api:v3:file-links:NotFound" } - let(:title) { "Not found" } + it_behaves_like 'has a titled link' do + let(:link) { 'status' } + let(:href) { 'urn:openproject-org:api:v3:file-links:NotFound' } + let(:title) { 'Not found' } end end - context "with status not defined (nil)" do + context 'with status not defined (nil)' do let(:origin_status) { nil } - it_behaves_like "has no link" do - let(:link) { "status" } + it_behaves_like 'has no link' do + let(:link) { 'status' } end end - context "with status check had an error" do + context 'with status check had an error' do let(:origin_status) { :error } - it_behaves_like "has a titled link" do - let(:link) { "status" } - let(:href) { "urn:openproject-org:api:v3:file-links:Error" } - let(:title) { "Error" } + it_behaves_like 'has a titled link' do + let(:link) { 'status' } + let(:href) { 'urn:openproject-org:api:v3:file-links:Error' } + let(:title) { 'Error' } end end end - describe "staticOriginOpen" do - it_behaves_like "has an untitled link" do - let(:link) { "staticOriginOpen" } + describe 'staticOriginOpen' do + it_behaves_like 'has an untitled link' do + let(:link) { 'staticOriginOpen' } let(:href) { "/api/v3/file_links/#{file_link.id}/open" } end end - describe "staticOriginOpenLocation" do - it_behaves_like "has an untitled link" do - let(:link) { "staticOriginOpenLocation" } + describe 'staticOriginOpenLocation' do + it_behaves_like 'has an untitled link' do + let(:link) { 'staticOriginOpenLocation' } let(:href) { "/api/v3/file_links/#{file_link.id}/open?location=true" } end end - describe "staticOriginDownload" do - it_behaves_like "has an untitled link" do - let(:link) { "staticOriginDownload" } + describe 'staticOriginDownload' do + it_behaves_like 'has an untitled link' do + let(:link) { 'staticOriginDownload' } let(:href) { "/api/v3/file_links/#{file_link.id}/download" } end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "FileLink" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'FileLink' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { file_link.id } end - it_behaves_like "datetime property", :createdAt do + it_behaves_like 'datetime property', :createdAt do let(:value) { file_link.created_at } end - it_behaves_like "datetime property", :updatedAt do + it_behaves_like 'datetime property', :updatedAt do let(:value) { file_link.updated_at } end - describe "originData" do - it_behaves_like "property", "originData/id" do + describe 'originData' do + it_behaves_like 'property', 'originData/id' do let(:value) { file_link.origin_id } end - it_behaves_like "property", "originData/name" do + it_behaves_like 'property', 'originData/name' do let(:value) { file_link.origin_name } end - it_behaves_like "property", "originData/mimeType" do + it_behaves_like 'property', 'originData/mimeType' do let(:value) { file_link.origin_mime_type } end - it_behaves_like "datetime property", "originData/createdAt" do + it_behaves_like 'datetime property', 'originData/createdAt' do let(:value) { file_link.origin_created_at } end - it_behaves_like "datetime property", "originData/lastModifiedAt" do + it_behaves_like 'datetime property', 'originData/lastModifiedAt' do let(:value) { file_link.origin_updated_at } end - it_behaves_like "property", "originData/createdByName" do + it_behaves_like 'property', 'originData/createdByName' do let(:value) { file_link.origin_created_by_name } end - it_behaves_like "property", "originData/lastModifiedByName" do + it_behaves_like 'property', 'originData/lastModifiedByName' do let(:value) { file_link.origin_last_modified_by_name } end end diff --git a/modules/storages/spec/lib/api/v3/project_storages/project_storage_representer_spec.rb b/modules/storages/spec/lib/api/v3/project_storages/project_storage_representer_spec.rb index 1fbfa228d1f1..01b27131d0f3 100644 --- a/modules/storages/spec/lib/api/v3/project_storages/project_storage_representer_spec.rb +++ b/modules/storages/spec/lib/api/v3/project_storages/project_storage_representer_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::ProjectStorages::ProjectStorageRepresenter do @@ -37,73 +37,73 @@ let(:user) { build_stubbed(:user) } - let(:project_storage) { build_stubbed(:project_storage, project_folder_mode: "manual", project_folder_id: "1337") } + let(:project_storage) { build_stubbed(:project_storage, project_folder_mode: 'manual', project_folder_id: '1337') } let(:representer) { described_class.new(project_storage, current_user: user) } subject { representer.to_json } - describe "properties" do - it_behaves_like "property", :_type do + describe 'properties' do + it_behaves_like 'property', :_type do let(:value) { representer._type } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { project_storage.id } end - it_behaves_like "datetime property", :createdAt do + it_behaves_like 'datetime property', :createdAt do let(:value) { project_storage.created_at } end - it_behaves_like "datetime property", :updatedAt do + it_behaves_like 'datetime property', :updatedAt do let(:value) { project_storage.updated_at } end - it_behaves_like "property", :projectFolderMode do + it_behaves_like 'property', :projectFolderMode do let(:value) { project_storage.project_folder_mode } end - it_behaves_like "has a titled link" do - let(:link) { "storage" } + it_behaves_like 'has a titled link' do + let(:link) { 'storage' } let(:href) { api_v3_paths.storage(project_storage.storage.id) } let(:title) { project_storage.storage.name } end - it_behaves_like "has a titled link" do - let(:link) { "project" } + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project(project_storage.project.id) } let(:title) { project_storage.project.name } end - it_behaves_like "has a titled link" do - let(:link) { "creator" } + it_behaves_like 'has a titled link' do + let(:link) { 'creator' } let(:href) { api_v3_paths.user(project_storage.creator.id) } let(:title) { project_storage.creator.name } end - it_behaves_like "has an untitled link" do - let(:link) { "projectFolder" } + it_behaves_like 'has an untitled link' do + let(:link) { 'projectFolder' } let(:href) { api_v3_paths.storage_file(project_storage.storage.id, project_storage.project_folder_id) } end - it_behaves_like "has an untitled link" do - let(:link) { "open" } + it_behaves_like 'has an untitled link' do + let(:link) { 'open' } let(:href) { api_v3_paths.project_storage_open(project_storage.id) } end - context "when storage is not configured" do - it_behaves_like "has an untitled link" do - let(:link) { "openWithConnectionEnsured" } + context 'when storage is not configured' do + it_behaves_like 'has an untitled link' do + let(:link) { 'openWithConnectionEnsured' } let(:href) { nil } end end - context "when storage is not configured" do + context 'when storage is not configured' do before { project_storage.storage = create(:nextcloud_storage_configured) } - it_behaves_like "has an untitled link" do - let(:link) { "openWithConnectionEnsured" } + it_behaves_like 'has an untitled link' do + let(:link) { 'openWithConnectionEnsured' } let(:href) { ensure_connection_path(project_storage) } end end diff --git a/modules/storages/spec/lib/api/v3/storage_files/storage_file_representer_spec.rb b/modules/storages/spec/lib/api/v3/storage_files/storage_file_representer_spec.rb index 66c21f64b297..84e088d34b00 100644 --- a/modules/storages/spec/lib/api/v3/storage_files/storage_file_representer_spec.rb +++ b/modules/storages/spec/lib/api/v3/storage_files/storage_file_representer_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::StorageFiles::StorageFileRepresenter do @@ -39,14 +39,14 @@ let(:file) do Storages::StorageFile.new( id: 42, - name: "readme.md", + name: 'readme.md', size: 4096, - mime_type: "text/plain", + mime_type: 'text/plain', created_at:, last_modified_at:, - created_by_name: "admin", - last_modified_by_name: "admin", - location: "/readme.md", + created_by_name: 'admin', + last_modified_by_name: 'admin', + location: '/readme.md', permissions: %i[readable writeable] ) end @@ -54,56 +54,56 @@ subject { representer.to_json } - describe "properties" do - it_behaves_like "property", :_type do + describe 'properties' do + it_behaves_like 'property', :_type do let(:value) { representer._type } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { file.id } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { file.name } end - it_behaves_like "property", :size do + it_behaves_like 'property', :size do let(:value) { file.size } end - it_behaves_like "property", :mimeType do + it_behaves_like 'property', :mimeType do let(:value) { file.mime_type } end - it_behaves_like "datetime property", :createdAt do + it_behaves_like 'datetime property', :createdAt do let(:value) { file.created_at } end - it_behaves_like "datetime property", :lastModifiedAt do + it_behaves_like 'datetime property', :lastModifiedAt do let(:value) { file.last_modified_at } end - it_behaves_like "property", :createdByName do + it_behaves_like 'property', :createdByName do let(:value) { file.created_by_name } end - it_behaves_like "property", :lastModifiedByName do + it_behaves_like 'property', :lastModifiedByName do let(:value) { file.last_modified_by_name } end - it_behaves_like "property", :location do + it_behaves_like 'property', :location do let(:value) { file.location } end - it_behaves_like "property", :permissions do + it_behaves_like 'property', :permissions do let(:value) { file.permissions } end end - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { "/api/v3/storages/#{storage.id}/files/#{file.id}" } let(:title) { file.name } end diff --git a/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb b/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb index 960cc52c1f0a..8d5778cbe9cc 100644 --- a/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb +++ b/modules/storages/spec/lib/api/v3/storage_files/storage_files_representer_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe API::V3::StorageFiles::StorageFilesRepresenter do @@ -40,14 +40,14 @@ let(:parent) do Storages::StorageFile.new( id: 23, - name: "Documents", + name: 'Documents', size: 2048, - mime_type: "application/x-op-directory", + mime_type: 'application/x-op-directory', created_at:, last_modified_at:, - created_by_name: "admin", - last_modified_by_name: "admin", - location: "/Documents", + created_by_name: 'admin', + last_modified_by_name: 'admin', + location: '/Documents', permissions: %i[readable writeable] ) end @@ -55,14 +55,14 @@ let(:file) do Storages::StorageFile.new( id: 42, - name: "readme.md", + name: 'readme.md', size: 4096, - mime_type: "text/plain", + mime_type: 'text/plain', created_at:, last_modified_at:, - created_by_name: "admin", - last_modified_by_name: "admin", - location: "/Documents/readme.md", + created_by_name: 'admin', + last_modified_by_name: 'admin', + location: '/Documents/readme.md', permissions: %i[readable writeable] ) end @@ -70,14 +70,14 @@ let(:ancestor) do Storages::StorageFile.new( id: 47, - name: "/", + name: '/', size: 4096, - mime_type: "application/x-op-directory", + mime_type: 'application/x-op-directory', created_at:, last_modified_at:, - created_by_name: "admin", - last_modified_by_name: "admin", - location: "/", + created_by_name: 'admin', + last_modified_by_name: 'admin', + location: '/', permissions: %i[readable writeable] ) end @@ -90,26 +90,26 @@ subject { representer.to_json } - describe "properties" do - it_behaves_like "property", :_type do + describe 'properties' do + it_behaves_like 'property', :_type do let(:value) { representer._type } end - it_behaves_like "collection", :files do + it_behaves_like 'collection', :files do let(:value) { files.files } let(:element_decorator) do ->(value) { API::V3::StorageFiles::StorageFileRepresenter.new(value, storage, current_user: user) } end end - it_behaves_like "collection", :ancestors do + it_behaves_like 'collection', :ancestors do let(:value) { files.ancestors } let(:element_decorator) do ->(value) { API::V3::StorageFiles::StorageFileRepresenter.new(value, storage, current_user: user) } end end - it_behaves_like "property", :parent do + it_behaves_like 'property', :parent do let(:value) { API::V3::StorageFiles::StorageFileRepresenter.new(files.parent, storage, current_user: user) } end end diff --git a/modules/storages/spec/lib/api/v3/storage_files/storage_upload_link_representer_spec.rb b/modules/storages/spec/lib/api/v3/storage_files/storage_upload_link_representer_spec.rb index faee87adc671..ea98d586da16 100644 --- a/modules/storages/spec/lib/api/v3/storage_files/storage_upload_link_representer_spec.rb +++ b/modules/storages/spec/lib/api/v3/storage_files/storage_upload_link_representer_spec.rb @@ -28,14 +28,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe API::V3::StorageFiles::StorageUploadLinkRepresenter, "rendering" do +RSpec.describe API::V3::StorageFiles::StorageUploadLinkRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:user) { build_stubbed(:user) } - let(:token) { "xyz123" } + let(:token) { 'xyz123' } let(:destination) { "https://example.com/upload/#{token}" } let(:upload_link) do Storages::UploadLink.new("https://example.com/upload/#{token}") @@ -44,28 +44,28 @@ subject { representer.to_json } - describe "links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe 'links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - describe "to self" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe 'to self' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { "#{API::V3::URN_PREFIX}storages:upload_link:no_link_provided" } end end - describe "without finalize link" do - describe "to destination" do - it_behaves_like "has a titled link" do - let(:link) { "destination" } + describe 'without finalize link' do + describe 'to destination' do + it_behaves_like 'has a titled link' do + let(:link) { 'destination' } let(:href) { destination } - let(:title) { "Upload File" } + let(:title) { 'Upload File' } end end - describe "not to finalize" do - it_behaves_like "has no link" do - let(:link) { "finalize" } + describe 'not to finalize' do + it_behaves_like 'has no link' do + let(:link) { 'finalize' } end end end diff --git a/modules/storages/spec/lib/api/v3/storages/storages_representer_parsing_spec.rb b/modules/storages/spec/lib/api/v3/storages/storages_representer_parsing_spec.rb index 576043ba878c..4f28cf83b85c 100644 --- a/modules/storages/spec/lib/api/v3/storages/storages_representer_parsing_spec.rb +++ b/modules/storages/spec/lib/api/v3/storages/storages_representer_parsing_spec.rb @@ -28,14 +28,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe API::V3::Storages::StorageRepresenter, "parsing" do +RSpec.describe API::V3::Storages::StorageRepresenter, 'parsing' do let(:storage) { build_stubbed(:nextcloud_storage) } let(:current_user) { build_stubbed(:user) } - describe "parsing" do + describe 'parsing' do subject(:parsed) { representer.from_hash parsed_hash } let(:representer) { described_class.new(storage, current_user:) } @@ -54,50 +54,50 @@ } end - context "with basic attributes" do - it "is parsed correctly" do - expect(parsed).to have_attributes(name: "Nextcloud Local", host: storage.host, + context 'with basic attributes' do + it 'is parsed correctly' do + expect(parsed).to have_attributes(name: 'Nextcloud Local', host: storage.host, provider_type: "Storages::NextcloudStorage") - aggregate_failures "does not parse nextcloud provider fields" do + aggregate_failures 'does not parse nextcloud provider fields' do expect(parsed.provider_fields).to eq({}) end end end - describe "automatically managed project folders" do - context "with applicationPassword" do + describe 'automatically managed project folders' do + context 'with applicationPassword' do let(:parsed_hash) do super().merge( "applicationPassword" => "secret" ) end - it "is parsed correctly" do - expect(parsed).to have_attributes(automatically_managed: true, password: "secret") + it 'is parsed correctly' do + expect(parsed).to have_attributes(automatically_managed: true, password: 'secret') end end - context "with applicationPassword null" do + context 'with applicationPassword null' do let(:parsed_hash) do super().merge( "applicationPassword" => nil ) end - it "is parsed as automatic folder management disabled" do + it 'is parsed as automatic folder management disabled' do expect(parsed).to have_attributes(automatically_managed: false, password: nil) end end - context "with applicationPassword blank" do + context 'with applicationPassword blank' do let(:parsed_hash) do super().merge( - "applicationPassword" => "" + "applicationPassword" => '' ) end - it "is parsed as automatic folder management disabled" do + it 'is parsed as automatic folder management disabled' do expect(parsed).to have_attributes(automatically_managed: false, password: nil) end end diff --git a/modules/storages/spec/lib/append_storages_hosts_to_csp_hook_spec.rb b/modules/storages/spec/lib/append_storages_hosts_to_csp_hook_spec.rb index 2a8f48f0a9ef..7ce24de46e6f 100644 --- a/modules/storages/spec/lib/append_storages_hosts_to_csp_hook_spec.rb +++ b/modules/storages/spec/lib/append_storages_hosts_to_csp_hook_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper # These specs mainly check that error messages from a sub-service @@ -52,53 +52,53 @@ def trigger_application_controller_before_action_hook hook_listener.application_controller_before_action(controller:) end - shared_examples "content security policy directives" do - it "adds CSP connect_src directives" do + shared_examples 'content security policy directives' do + it 'adds CSP connect_src directives' do trigger_application_controller_before_action_hook expect(controller).to have_received(:append_content_security_policy_directives).with(connect_src: [storage.host]) end end - shared_examples "does not change CSP" do - it "does not change CSP directives" do + shared_examples 'does not change CSP' do + it 'does not change CSP directives' do trigger_application_controller_before_action_hook expect(controller).not_to have_received(:append_content_security_policy_directives) end end - context "with a project with an active Nextcloud storage" do - context "when current user is an admin without being a member of any project" do + context 'with a project with an active Nextcloud storage' do + context 'when current user is an admin without being a member of any project' do current_user { admin } - include_examples "content security policy directives" + include_examples 'content security policy directives' end - context "when current user is a member of the project with permission to manage file links" do + context 'when current user is a member of the project with permission to manage file links' do current_user { create(:user, member_with_permissions: { project => %i[manage_file_links] }) } - include_examples "content security policy directives" + include_examples 'content security policy directives' end - context "when current user is a member of the project without permission to manage file links" do + context 'when current user is a member of the project without permission to manage file links' do current_user { create(:user, member_with_permissions: { project => [] }) } - it "does not add CSP connect_src directive" do + it 'does not add CSP connect_src directive' do trigger_application_controller_before_action_hook expect(controller).not_to have_received(:append_content_security_policy_directives).with(connect_src: [storage.host]) end end - context "when the project is archived" do + context 'when the project is archived' do current_user { admin } before do project.update(active: false) end - it "does not add CSP connect_src directive" do + it 'does not add CSP connect_src directive' do trigger_application_controller_before_action_hook expect(controller).not_to have_received(:append_content_security_policy_directives).with(connect_src: [storage.host]) @@ -106,45 +106,45 @@ def trigger_application_controller_before_action_hook end end - context "with a project without an active storage" do + context 'with a project without an active storage' do current_user { admin } let(:project_storage) { nil } - include_examples "does not change CSP" + include_examples 'does not change CSP' end - context "with a project without any storages configured" do + context 'with a project without any storages configured' do current_user { admin } let(:project_storage) { nil } let(:storage) { nil } - include_examples "does not change CSP" + include_examples 'does not change CSP' end - context "with an active Nextcloud storage having a host with a non-standard port" do - let(:storage) { create(:nextcloud_storage, host: "http://somehost.com:8080") } + context 'with an active Nextcloud storage having a host with a non-standard port' do + let(:storage) { create(:nextcloud_storage, host: 'http://somehost.com:8080') } current_user { admin } - it "adds the port to the CSP directive" do + it 'adds the port to the CSP directive' do trigger_application_controller_before_action_hook expect(controller).to have_received(:append_content_security_policy_directives) do |args| - expect(args).to eq(connect_src: ["http://somehost.com:8080"]) + expect(args).to eq(connect_src: ['http://somehost.com:8080']) end end end - context "with an active Nextcloud storage having a host with a path" do - let(:storage) { create(:nextcloud_storage, host: "https://my.server.com/nextcloud") } + context 'with an active Nextcloud storage having a host with a path' do + let(:storage) { create(:nextcloud_storage, host: 'https://my.server.com/nextcloud') } current_user { admin } - it "removes the path from the host for the CSP directive" do + it 'removes the path from the host for the CSP directive' do trigger_application_controller_before_action_hook expect(controller).to have_received(:append_content_security_policy_directives) do |args| - expect(args).to eq(connect_src: ["https://my.server.com"]) + expect(args).to eq(connect_src: ['https://my.server.com']) end end end diff --git a/modules/storages/spec/models/storages/file_link_spec.rb b/modules/storages/spec/models/storages/file_link_spec.rb index b46d82f77ec0..a619cf68ca6f 100644 --- a/modules/storages/spec/models/storages/file_link_spec.rb +++ b/modules/storages/spec/models/storages/file_link_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::FileLink do @@ -50,7 +50,7 @@ } end - describe "#create" do + describe '#create' do it "creates an instance" do file_link = described_class.create attributes expect(file_link).to be_valid @@ -67,7 +67,7 @@ end end - describe "#destroy" do + describe '#destroy' do let(:file_link_to_destroy) { described_class.create(attributes) } before do diff --git a/modules/storages/spec/models/storages/last_project_folder_spec.rb b/modules/storages/spec/models/storages/last_project_folder_spec.rb index 74059939d6d1..5dbfa50b88b4 100644 --- a/modules/storages/spec/models/storages/last_project_folder_spec.rb +++ b/modules/storages/spec/models/storages/last_project_folder_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::LastProjectFolder do - describe "#mode" do + describe '#mode' do let(:last_project_folder) { build(:last_project_folder) } it do expect(last_project_folder).to define_enum_for(:mode) - .with_values(inactive: "inactive", manual: "manual", automatic: "automatic") + .with_values(inactive: 'inactive', manual: 'manual', automatic: 'automatic') .backed_by_column_of_type(:string) end end diff --git a/modules/storages/spec/models/storages/nextcloud_storage_spec.rb b/modules/storages/spec/models/storages/nextcloud_storage_spec.rb index 15c9c801b98a..eae9c58e41bd 100644 --- a/modules/storages/spec/models/storages/nextcloud_storage_spec.rb +++ b/modules/storages/spec/models/storages/nextcloud_storage_spec.rb @@ -28,59 +28,59 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_base_storage_spec" +require 'spec_helper' +require_relative 'shared_base_storage_spec' require_module_spec_helper RSpec.describe Storages::NextcloudStorage do let(:storage) { create(:nextcloud_storage) } - it_behaves_like "base storage" + it_behaves_like 'base storage' - describe ".automatic_management_enabled" do + describe '.automatic_management_enabled' do let!(:automatically_managed_storage) { create(:nextcloud_storage, :as_automatically_managed) } let!(:not_automatically_managed_storage) { create(:nextcloud_storage, :as_not_automatically_managed) } - it "returns only storages with automatic management enabled" do + it 'returns only storages with automatic management enabled' do expect(described_class.automatic_management_enabled).to contain_exactly(automatically_managed_storage) end end - describe "#provider_type?" do + describe '#provider_type?' do it { expect(storage).to be_a_provider_type_nextcloud } it { expect(storage).not_to be_a_provider_type_one_drive } end - describe "health attributes" do - it "can be marked as healthy or unhealthy" do - healthy_time = Time.parse "2021-03-14T15:17:00Z" - unhealthy_time = Time.parse "2023-03-14T15:17:00Z" + describe 'health attributes' do + it 'can be marked as healthy or unhealthy' do + healthy_time = Time.parse '2021-03-14T15:17:00Z' + unhealthy_time = Time.parse '2023-03-14T15:17:00Z' Timecop.freeze(healthy_time) do expect do storage.mark_as_healthy end.to(change(storage, :health_changed_at).to(healthy_time) - .and(change(storage, :health_status).from("pending").to("healthy"))) + .and(change(storage, :health_status).from('pending').to('healthy'))) expect(storage.health_healthy?).to be(true) expect(storage.health_unhealthy?).to be(false) end Timecop.freeze(unhealthy_time) do expect do - storage.mark_as_unhealthy(reason: "thou_shall_not_pass_error") + storage.mark_as_unhealthy(reason: 'thou_shall_not_pass_error') end.to(change(storage, :health_changed_at).from(healthy_time).to(unhealthy_time) - .and(change(storage, :health_status).from("healthy").to("unhealthy")) - .and(change(storage, :health_reason).from(nil).to("thou_shall_not_pass_error"))) + .and(change(storage, :health_status).from('healthy').to('unhealthy')) + .and(change(storage, :health_reason).from(nil).to('thou_shall_not_pass_error'))) end expect(storage.health_healthy?).to be(false) expect(storage.health_unhealthy?).to be(true) end - it "has the correct changed_at and checked_at attributes" do - healthy_time = Time.parse "2021-03-14T15:17:00Z" - unhealthy_time_a = Time.parse "2023-03-14T00:00:00Z" - unhealthy_time_b = Time.parse "2023-03-14T22:22:00Z" - unhealthy_time_c = Time.parse "2023-03-14T11:11:00Z" + it 'has the correct changed_at and checked_at attributes' do + healthy_time = Time.parse '2021-03-14T15:17:00Z' + unhealthy_time_a = Time.parse '2023-03-14T00:00:00Z' + unhealthy_time_b = Time.parse '2023-03-14T22:22:00Z' + unhealthy_time_c = Time.parse '2023-03-14T11:11:00Z' reason_a = "thou_shall_not_pass_error" reason_b = "inception_error" @@ -116,18 +116,18 @@ end end - describe "#configured?" do - context "with a complete configuration" do + describe '#configured?' do + context 'with a complete configuration' do let(:storage) do build(:nextcloud_storage, oauth_application: build(:oauth_application), oauth_client: build(:oauth_client)) end - it "returns true" do + it 'returns true' do expect(storage.configured?).to be(true) - aggregate_failures "configuration_checks" do + aggregate_failures 'configuration_checks' do expect(storage.configuration_checks) .to eq(host_name_configured: true, storage_oauth_client_configured: true, @@ -136,26 +136,26 @@ end end - context "without host name" do + context 'without host name' do let(:storage) { build(:nextcloud_storage, host: nil, name: nil) } - it "returns false" do + it 'returns false' do aggregate_failures do expect(storage.configured?).to be(false) - aggregate_failures "configuration_checks" do + aggregate_failures 'configuration_checks' do expect(storage.configuration_checks[:host_name_configured]).to be(false) end end end end - context "without openproject and storage integrations" do + context 'without openproject and storage integrations' do let(:storage) { build(:nextcloud_storage) } - it "returns false" do + it 'returns false' do expect(storage.configured?).to be(false) - aggregate_failures "configuration_checks" do + aggregate_failures 'configuration_checks' do expect(storage.configuration_checks[:openproject_oauth_application_configured]).to be(false) expect(storage.configuration_checks[:storage_oauth_client_configured]).to be(false) end @@ -163,7 +163,7 @@ end end - shared_examples "a stored attribute with default value" do |attribute, default_value| + shared_examples 'a stored attribute with default value' do |attribute, default_value| context "when the provider fields are empty" do let(:storage) { build(:nextcloud_storage, provider_fields: {}) } @@ -175,26 +175,26 @@ context "with a new value of 'foo'" do it "sets the value to 'foo'" do - storage.public_send(:"#{attribute}=", "foo") - expect(storage.public_send(attribute)).to eq("foo") + storage.public_send(:"#{attribute}=", 'foo') + expect(storage.public_send(attribute)).to eq('foo') end end end - describe "#username" do - it_behaves_like "a stored attribute with default value", :username, "OpenProject" + describe '#username' do + it_behaves_like 'a stored attribute with default value', :username, 'OpenProject' end - describe "#group" do - it_behaves_like "a stored attribute with default value", :group, "OpenProject" + describe '#group' do + it_behaves_like 'a stored attribute with default value', :group, 'OpenProject' end - describe "#group_folder" do - it_behaves_like "a stored attribute with default value", :group_folder, "OpenProject" + describe '#group_folder' do + it_behaves_like 'a stored attribute with default value', :group_folder, 'OpenProject' end - describe "#automatic_management_new_record?" do - context "when automatic management has just been specified but not yet persisted" do + describe '#automatic_management_new_record?' do + context 'when automatic management has just been specified but not yet persisted' do let(:storage) { build_stubbed(:nextcloud_storage, provider_fields: {}) } before { storage.automatic_management_enabled = false } @@ -203,14 +203,14 @@ it { expect(storage).to be_automatic_management_new_record } end - context "when automatic management was already specified" do + context 'when automatic management was already specified' do let(:storage) { build_stubbed(:nextcloud_storage, :as_not_automatically_managed) } it { expect(storage).not_to be_provider_fields_changed } it { expect(storage).not_to be_automatic_management_new_record } end - context "when automatic management is unspecified" do + context 'when automatic management is unspecified' do let(:storage) { build_stubbed(:nextcloud_storage, provider_fields: {}) } it { expect(storage).not_to be_provider_fields_changed } @@ -218,31 +218,31 @@ end end - describe "#automatic_management_unspecified?" do - context "when automatic management enabled is nil" do + describe '#automatic_management_unspecified?' do + context 'when automatic management enabled is nil' do let(:storage) { build(:nextcloud_storage, automatic_management_enabled: nil) } it { expect(storage).to be_automatic_management_unspecified } end - context "when automatic management enabled is true" do + context 'when automatic management enabled is true' do let(:storage) { build(:nextcloud_storage, automatic_management_enabled: true) } it { expect(storage).not_to be_automatic_management_unspecified } end - context "when automatic management enabled is false" do + context 'when automatic management enabled is false' do let(:storage) { build(:nextcloud_storage, automatic_management_enabled: false) } it { expect(storage).not_to be_automatic_management_unspecified } end end - describe "#provider_fields_defaults" do + describe '#provider_fields_defaults' do let(:storage) { build(:nextcloud_storage) } - it "returns the default values for nextcloud" do - expect(storage.provider_fields_defaults).to eq({ automatic_management_enabled: true, username: "OpenProject" }) + it 'returns the default values for nextcloud' do + expect(storage.provider_fields_defaults).to eq({ automatic_management_enabled: true, username: 'OpenProject' }) end end end diff --git a/modules/storages/spec/models/storages/one_drive_storage_spec.rb b/modules/storages/spec/models/storages/one_drive_storage_spec.rb index dfbdd1cf64ba..d4c5c48cf146 100644 --- a/modules/storages/spec/models/storages/one_drive_storage_spec.rb +++ b/modules/storages/spec/models/storages/one_drive_storage_spec.rb @@ -28,27 +28,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_base_storage_spec" +require 'spec_helper' +require_relative 'shared_base_storage_spec' RSpec.describe Storages::OneDriveStorage do let(:storage) { build(:one_drive_storage) } - it_behaves_like "base storage" + it_behaves_like 'base storage' - describe "#provider_type?" do + describe '#provider_type?' do it { expect(storage).to be_a_provider_type_one_drive } it { expect(storage).not_to be_a_provider_type_nextcloud } end - describe "#configured?" do - context "with a complete configuration" do + describe '#configured?' do + context 'with a complete configuration' do let(:storage) { build(:one_drive_storage, oauth_client: build(:oauth_client)) } - it "returns true" do + it 'returns true' do expect(storage.configured?).to be(true) - aggregate_failures "configuration_checks" do + aggregate_failures 'configuration_checks' do expect(storage.configuration_checks) .to eq(host_name_configured: true, storage_oauth_client_configured: true, @@ -57,13 +57,13 @@ end end - context "without oauth client" do + context 'without oauth client' do let(:storage) { build(:one_drive_storage) } - it "returns false" do + it 'returns false' do expect(storage.configured?).to be(false) - aggregate_failures "configuration_checks" do + aggregate_failures 'configuration_checks' do expect(storage.configuration_checks[:storage_oauth_client_configured]).to be(false) end end diff --git a/modules/storages/spec/models/storages/project_storage_spec.rb b/modules/storages/spec/models/storages/project_storage_spec.rb index 61ef1f8d33ee..79f49229c539 100644 --- a/modules/storages/spec/models/storages/project_storage_spec.rb +++ b/modules/storages/spec/models/storages/project_storage_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::ProjectStorage do @@ -44,7 +44,7 @@ } end - describe "#create" do + describe '#create' do it "creates an instance" do project_storage = described_class.create attributes expect(project_storage).to be_valid @@ -63,7 +63,7 @@ end end - describe "#destroy" do + describe '#destroy' do let(:project_storage_to_destroy) { described_class.create(attributes) } let(:work_package) { create(:work_package, project:) } let(:file_link) { create(:file_link, storage:, container_id: work_package.id) } @@ -81,10 +81,10 @@ end end - describe "#automatic_management_possible?" do + describe '#automatic_management_possible?' do let(:project_storage) { build_stubbed(:project_storage, storage:) } - context "when the storage is not a NextcloudStorage" do + context 'when the storage is not a NextcloudStorage' do let(:storage) { build_stubbed(:storage, :as_generic) } it "returns false" do @@ -92,16 +92,16 @@ end end - context "when the storage is a NextcloudStorage" do + context 'when the storage is a NextcloudStorage' do let(:storage) { build_stubbed(:nextcloud_storage) } - context "when the storage is not automatically managed" do + context 'when the storage is not automatically managed' do it "returns false" do expect(project_storage.automatic_management_possible?).to be false end end - context "when the storage is automatically managed" do + context 'when the storage is automatically managed' do before do storage.automatically_managed = true end @@ -113,18 +113,18 @@ end end - describe "#project_folder_mode" do + describe '#project_folder_mode' do let(:project_storage) { build(:project_storage) } it do expect(project_storage).to define_enum_for(:project_folder_mode) - .with_values(inactive: "inactive", manual: "manual", automatic: "automatic") + .with_values(inactive: 'inactive', manual: 'manual', automatic: 'automatic') .with_prefix(:project_folder) .backed_by_column_of_type(:string) end end - describe "#open" do + describe '#open' do let(:user) { create(:user, member_with_permissions: { project => permissions }) } let(:permissions) { %i[] } let(:project_storage) do @@ -136,56 +136,56 @@ end let(:project_folder_id) { nil } - context "when inactive" do - let(:project_folder_mode) { "inactive" } + context 'when inactive' do + let(:project_folder_mode) { 'inactive' } - it "opens storage" do + it 'opens storage' do expect(project_storage.open(user).result).to eq("#{storage.host}/index.php/apps/files") end end - context "when manual" do - let(:project_folder_mode) { "manual" } + context 'when manual' do + let(:project_folder_mode) { 'manual' } - context "when project_folder_id is missing" do - it "opens storage" do + context 'when project_folder_id is missing' do + it 'opens storage' do expect(project_storage.open(user).result).to eq("#{storage.host}/index.php/apps/files") end end - context "when project_folder_id is present" do - let(:project_folder_id) { "123" } + context 'when project_folder_id is present' do + let(:project_folder_id) { '123' } - it "opens project_folder" do + it 'opens project_folder' do expect(project_storage.open(user).result).to eq("#{storage.host}/index.php/f/123?openfile=1") end end end - context "when automatic" do - let(:project_folder_mode) { "automatic" } + context 'when automatic' do + let(:project_folder_mode) { 'automatic' } - context "when user has no permissions to read files in storage" do - let(:project_folder_mode) { "automatic" } + context 'when user has no permissions to read files in storage' do + let(:project_folder_mode) { 'automatic' } - it "opens storage" do + it 'opens storage' do expect(project_storage.open(user).result).to eq("#{storage.host}/index.php/apps/files") end end - context "when user has permissions to read files in storage" do + context 'when user has permissions to read files in storage' do let(:permissions) { %i[read_files] } - context "when project_folder_id is missing" do - it "opens storage" do + context 'when project_folder_id is missing' do + it 'opens storage' do expect(project_storage.open(user).result).to eq("#{storage.host}/index.php/apps/files") end end - context "when project_folder_id is present" do - let(:project_folder_id) { "123" } + context 'when project_folder_id is present' do + let(:project_folder_id) { '123' } - it "opens project_folder" do + it 'opens project_folder' do expect(project_storage.open(user).result).to eq("#{storage.host}/index.php/f/123?openfile=1") end end diff --git a/modules/storages/spec/models/storages/shared_base_storage_spec.rb b/modules/storages/spec/models/storages/shared_base_storage_spec.rb index 5ec1b5575a1b..03b7fe0c4ab7 100644 --- a/modules/storages/spec/models/storages/shared_base_storage_spec.rb +++ b/modules/storages/spec/models/storages/shared_base_storage_spec.rb @@ -28,46 +28,46 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "base storage" do +RSpec.shared_examples_for 'base storage' do let(:default_attributes) do { - name: "My storage", - host: "https://example.com", + name: 'My storage', + host: 'https://example.com', creator: create(:user) } end - describe ".shorten_provider_type" do - context "when provider_type matches the signature" do - it "responds with shortened provider type" do + describe '.shorten_provider_type' do + context 'when provider_type matches the signature' do + it 'responds with shortened provider type' do expect( described_class.shorten_provider_type(described_class::PROVIDER_TYPE_NEXTCLOUD) - ).to eq("nextcloud") + ).to eq('nextcloud') expect( described_class.shorten_provider_type(described_class::PROVIDER_TYPE_ONE_DRIVE) - ).to eq("one_drive") + ).to eq('one_drive') end end - context "when provider_type does not match the signature" do - it "raises an error", :aggregate_failures do + context 'when provider_type does not match the signature' do + it 'raises an error', :aggregate_failures do expect do - described_class.shorten_provider_type("Storages::Nextcloud") - end.to raise_error("Unknown provider_type! Given: Storages::Nextcloud. " \ - "Expected the following signature: Storages::{Name of the provider}Storage") + described_class.shorten_provider_type('Storages::Nextcloud') + end.to raise_error('Unknown provider_type! Given: Storages::Nextcloud. ' \ + 'Expected the following signature: Storages::{Name of the provider}Storage') expect do - described_class.shorten_provider_type("Storages:NextcloudStorage") - end.to raise_error("Unknown provider_type! Given: Storages:NextcloudStorage. " \ - "Expected the following signature: Storages::{Name of the provider}Storage") + described_class.shorten_provider_type('Storages:NextcloudStorage') + end.to raise_error('Unknown provider_type! Given: Storages:NextcloudStorage. ' \ + 'Expected the following signature: Storages::{Name of the provider}Storage') expect do - described_class.shorten_provider_type("Storages::NextcloudStorag") - end.to raise_error("Unknown provider_type! Given: Storages::NextcloudStorag. " \ - "Expected the following signature: Storages::{Name of the provider}Storage") + described_class.shorten_provider_type('Storages::NextcloudStorag') + end.to raise_error('Unknown provider_type! Given: Storages::NextcloudStorag. ' \ + 'Expected the following signature: Storages::{Name of the provider}Storage') end end end - describe "#create" do + describe '#create' do it "creates an instance" do storage = described_class.create default_attributes expect(storage).to be_valid @@ -81,16 +81,16 @@ end it "fails the validation if name is not unique" do - expect(described_class.create(default_attributes.merge({ host: "https://example2.com" }))).not_to be_valid + expect(described_class.create(default_attributes.merge({ host: 'https://example2.com' }))).not_to be_valid end it "fails the validation if host is not unique" do - expect(described_class.create(default_attributes.merge({ name: "Another storage" }))).not_to be_valid + expect(described_class.create(default_attributes.merge({ name: 'Another storage' }))).not_to be_valid end end end - describe "#destroy" do + describe '#destroy' do let(:project) { create(:project) } let(:storage) { described_class.create(default_attributes) } let(:project_storage) { create(:project_storage, project:, storage:, creator: create(:user)) } diff --git a/modules/storages/spec/models/storages/storage_spec.rb b/modules/storages/spec/models/storages/storage_spec.rb index 358a850879cd..0b55a825b24d 100644 --- a/modules/storages/spec/models/storages/storage_spec.rb +++ b/modules/storages/spec/models/storages/storage_spec.rb @@ -28,19 +28,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Storage do describe "provider_fields" do let(:storage) { build(:storage, provider_fields: {}) } - shared_examples "a stored boolean attribute" do |attribute| + shared_examples 'a stored boolean attribute' do |attribute| it "#{attribute} has a default value of false" do expect(storage.public_send(:"#{attribute}?")).to be(false) end - ["1", "true", true].each do |boolean_like| + ['1', 'true', true].each do |boolean_like| context "with truthy value #{boolean_like}" do it "sets #{attribute} to true" do storage.public_send(:"#{attribute}=", boolean_like) @@ -57,24 +57,24 @@ end end - describe "#automatically_managed" do - it_behaves_like "a stored boolean attribute", :automatically_managed + describe '#automatically_managed' do + it_behaves_like 'a stored boolean attribute', :automatically_managed end - describe "#automatic_management_enabled?" do - context "when automatic management enabled is true" do + describe '#automatic_management_enabled?' do + context 'when automatic management enabled is true' do let(:storage) { build(:storage, automatic_management_enabled: true) } it { expect(storage).to be_automatic_management_enabled } end - context "when automatic management enabled is false" do + context 'when automatic management enabled is false' do let(:storage) { build(:storage, automatic_management_enabled: false) } it { expect(storage).not_to be_automatic_management_enabled } end - context "when automatic management enabled is nil" do + context 'when automatic management enabled is nil' do let(:storage) { build(:storage, automatic_management_enabled: nil) } it { expect(storage.automatic_management_enabled?).to be(false) } diff --git a/modules/storages/spec/permissions/manage_storage_in_project_spec.rb b/modules/storages/spec/permissions/manage_storage_in_project_spec.rb index 659be862fbf9..ce5787ac0451 100644 --- a/modules/storages/spec/permissions/manage_storage_in_project_spec.rb +++ b/modules/storages/spec/permissions/manage_storage_in_project_spec.rb @@ -28,11 +28,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper # rubocop:disable RSpec/EmptyExampleGroup -RSpec.describe Storages::Admin::ProjectStoragesController, "manage_storage_in_project permission", type: :controller do +RSpec.describe Storages::Admin::ProjectStoragesController, 'manage_storage_in_project permission', type: :controller do include PermissionSpecs controller_actions.each do |action| diff --git a/modules/storages/spec/requests/api/v3/file_links/file_links_api_spec.rb b/modules/storages/spec/requests/api/v3/file_links/file_links_api_spec.rb index c1d5cf5b3ff4..ea1b41122211 100644 --- a/modules/storages/spec/requests/api/v3/file_links/file_links_api_spec.rb +++ b/modules/storages/spec/requests/api/v3/file_links/file_links_api_spec.rb @@ -36,13 +36,13 @@ include UserPermissionsHelper def enable_module(project, modul) - project.enabled_modules.create(name: modul) + project.enabled_module_names = project.enabled_module_names + [modul] + project.save end def disable_module(project, modul) - # Avoid project.enabled_module_names and a subsequent save as that would create an AnonymousUser in an - # after(:all) block, which persists the user in the RequestStore. - project.enabled_modules.where(name: modul).destroy_all + project.enabled_module_names = project.enabled_module_names - [modul] + project.save end shared_association_default(:priority) { create(:priority) } diff --git a/modules/storages/spec/requests/api/v3/file_links/mixed_case_file_links_integration_spec.rb b/modules/storages/spec/requests/api/v3/file_links/mixed_case_file_links_integration_spec.rb index e4a3729c7ee6..52ce9309fd27 100644 --- a/modules/storages/spec/requests/api/v3/file_links/mixed_case_file_links_integration_spec.rb +++ b/modules/storages/spec/requests/api/v3/file_links/mixed_case_file_links_integration_spec.rb @@ -28,11 +28,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper # We want to check the case of file_links from multiple storages -RSpec.describe "API v3 file links resource" do +RSpec.describe 'API v3 file links resource' do include API::V3::Utilities::PathHelper let(:project) { create(:project) } @@ -72,8 +72,8 @@ # No token for oauth_client_notoken! let(:file_link_happy) { create(:file_link, origin_id: "24", storage: storage_good, container: work_package) } - let(:file_link_other_user) { create(:file_link, origin_id: "25", storage: storage_good, container: work_package) } - let(:file_link_deleted) { create(:file_link, origin_id: "26", storage: storage_good, container: work_package) } + let(:file_link_other_user) { create(:file_link, origin_id: '25', storage: storage_good, container: work_package) } + let(:file_link_deleted) { create(:file_link, origin_id: '26', storage: storage_good, container: work_package) } let(:file_link_unauth_happy) { create(:file_link, origin_id: "28", storage: storage_unauth, container: work_package) } let(:file_link_error_happy) { create(:file_link, origin_id: "29", storage: storage_error, container: work_package) } @@ -129,16 +129,16 @@ login_as user end - describe "GET /api/v3/work_packages/:work_package_id/file_links", :webmock do + describe 'GET /api/v3/work_packages/:work_package_id/file_links', :webmock do let(:path) { api_v3_paths.file_links(work_package.id) } let(:response_host_happy) do { ocs: { meta: ocs_meta_s200, data: { - "24": file_info_happy, - "25": file_info_s403, - "26": file_info_s404 + '24': file_info_happy, + '25': file_info_s403, + '26': file_info_s404 } } }.to_json @@ -148,12 +148,12 @@ oauth_client_token_good # https://host-good/: Simulate a successfully authorized reply with updates from Nextcloud - stub_request(:post, File.join(host_good, "/ocs/v1.php/apps/integration_openproject/filesinfo")) - .to_return(status: 200, headers: { "Content-Type": "application/json" }, body: response_host_happy) + stub_request(:post, File.join(host_good, '/ocs/v1.php/apps/integration_openproject/filesinfo')) + .to_return(status: 200, headers: { 'Content-Type': 'application/json' }, body: response_host_happy) # https://host-unauth/: Simulates a Nextcloud with Bearer token expired or non existing - stub_request(:post, File.join(host_unauth, "/ocs/v1.php/apps/integration_openproject/filesinfo")) - .to_return(status: 200, headers: { "Content-Type": "application/json" }, body: response_host_happy) + stub_request(:post, File.join(host_unauth, '/ocs/v1.php/apps/integration_openproject/filesinfo')) + .to_return(status: 200, headers: { 'Content-Type': 'application/json' }, body: response_host_happy) # https://host-error/: Simulates a Nextcloud with network timeout stub_request(:post, host_error).to_return(status: 500) @@ -162,14 +162,14 @@ stub_request(:post, host_timeout).to_timeout # https://host-notoken/: Simulate a Nextcloud with no oauth_token yet - stub_request(:post, File.join(host_notoken, "/ocs/v1.php/apps/integration_openproject/filesinfo")) - .to_return(status: 200, headers: { "Content-Type": "application/json" }, body: response_host_happy) + stub_request(:post, File.join(host_notoken, '/ocs/v1.php/apps/integration_openproject/filesinfo')) + .to_return(status: 200, headers: { 'Content-Type': 'application/json' }, body: response_host_happy) get path end # total, count, element_type, collection_type = 'Collection' - it_behaves_like "API V3 collection response", 6, 6, "FileLink", "Collection" do + it_behaves_like 'API V3 collection response', 6, 6, 'FileLink', 'Collection' do let(:elements) do [ file_link_timeout_happy, @@ -182,7 +182,7 @@ end end - it "returns the file_links with correct Nextcloud data applied" do + it 'returns the file_links with correct Nextcloud data applied' do # GET returns a collection of FileLinks in "_embedded/elements" elements = JSON.parse(subject.body).dig("_embedded", "elements") @@ -199,7 +199,7 @@ # The deleted_file_link should not even appear in the Database anymore deleted_file_link = elements.detect { |e| e["originData"]["id"] == "27" } expect(deleted_file_link).to be_nil - expect(Storages::FileLink.where(origin_id: "27").count).to be 0 + expect(Storages::FileLink.where(origin_id: '27').count).to be 0 # The FileLink from a Nextcloud with error should have origin_status=:error error_file_link = elements.detect { |e| e["originData"]["id"] == "29" } diff --git a/modules/storages/spec/requests/api/v3/project_storages/project_storages_spec.rb b/modules/storages/spec/requests/api/v3/project_storages/project_storages_spec.rb index 0fd70f3a284c..d79ea2ecfa52 100644 --- a/modules/storages/spec/requests/api/v3/project_storages/project_storages_spec.rb +++ b/modules/storages/spec/requests/api/v3/project_storages/project_storages_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "API v3 project storages resource", :webmock, content_type: :json do +RSpec.describe 'API v3 project storages resource', :webmock, content_type: :json do include API::V3::Utilities::PathHelper let(:view_permissions) { %i(view_work_packages view_file_links) } @@ -52,16 +52,16 @@ before { login_as current_user } - describe "GET /api/v3/project_storages" do + describe 'GET /api/v3/project_storages' do let(:path) { api_v3_paths.project_storages } - context "as admin" do + context 'as admin' do let(:current_user) { create(:admin) } subject { last_response.body } - describe "gets full project storage collection" do - it_behaves_like "API V3 collection response", 6, 6, "ProjectStorage", "Collection" do + describe 'gets full project storage collection' do + it_behaves_like 'API V3 collection response', 6, 6, 'ProjectStorage', 'Collection' do let(:elements) do [ project_storage31, @@ -75,99 +75,99 @@ end end - context "with project filter" do + context 'with project filter' do let(:filters) { [{ projectId: { operator: "=", values: [project_id] } }] } let(:path) { api_v3_paths.path_for(:project_storages, filters:) } - describe "gets all project storages of the filtered project" do + describe 'gets all project storages of the filtered project' do let(:project_id) { project2.id } - it_behaves_like "API V3 collection response", 2, 2, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 2, 2, 'ProjectStorage', 'Collection' do let(:elements) { [project_storage21, project_storage23] } end end - context "with invalid project id" do - let(:project_id) { "1337" } + context 'with invalid project id' do + let(:project_id) { '1337' } - it_behaves_like "invalid filters" + it_behaves_like 'invalid filters' end - context "with project id of project with no storages" do + context 'with project id of project with no storages' do let(:project) { create(:project) } let(:project_id) { project.id } - it_behaves_like "API V3 collection response", 0, 0, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'ProjectStorage', 'Collection' do let(:elements) { [] } end end end - context "with storage id filter" do + context 'with storage id filter' do let(:filters) { [{ storageId: { operator: "=", values: [storage_id] } }] } let(:path) { api_v3_paths.path_for(:project_storages, filters:) } - describe "gets all project storages of the filtered project" do + describe 'gets all project storages of the filtered project' do let(:storage_id) { storage3.id } - it_behaves_like "API V3 collection response", 2, 2, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 2, 2, 'ProjectStorage', 'Collection' do let(:elements) { [project_storage23, project_storage13] } end end - context "with unknown storage id" do - let(:storage_id) { "1337" } + context 'with unknown storage id' do + let(:storage_id) { '1337' } - it_behaves_like "API V3 collection response", 0, 0, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'ProjectStorage', 'Collection' do let(:elements) { [] } end end - context "with storage id of storage with no linked projects" do + context 'with storage id of storage with no linked projects' do let(:storage) { create(:nextcloud_storage) } let(:storage_id) { storage.id } - it_behaves_like "API V3 collection response", 0, 0, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'ProjectStorage', 'Collection' do let(:elements) { [] } end end end - context "with storage url filter" do + context 'with storage url filter' do let(:filters) { [{ storageUrl: { operator: "=", values: [storage_url] } }] } let(:path) { api_v3_paths.path_for(:project_storages, filters:) } - describe "gets all project storages of the filtered project" do + describe 'gets all project storages of the filtered project' do let(:storage_url) { CGI.escape(storage3.host) } - it_behaves_like "API V3 collection response", 2, 2, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 2, 2, 'ProjectStorage', 'Collection' do let(:elements) { [project_storage23, project_storage13] } end end - context "with invalid storage url" do + context 'with invalid storage url' do let(:storage_url) { nil } - it_behaves_like "invalid filters" + it_behaves_like 'invalid filters' end - context "with storage url of storage with no linked projects" do + context 'with storage url of storage with no linked projects' do let(:storage) { create(:nextcloud_storage) } let(:storage_url) { storage.host } - it_behaves_like "API V3 collection response", 0, 0, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'ProjectStorage', 'Collection' do let(:elements) { [] } end end end end - context "as user with permissions" do + context 'as user with permissions' do let(:current_user) do create(:user, member_with_permissions: { project1 => view_permissions, project3 => view_permissions }) end - it_behaves_like "API V3 collection response", 4, 4, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 4, 4, 'ProjectStorage', 'Collection' do let(:elements) do [ project_storage31, @@ -179,24 +179,24 @@ end end - context "as user without permissions" do + context 'as user without permissions' do let(:current_user) do create(:user, member_with_permissions: { project1 => [], project2 => [], project3 => [] }) end - it_behaves_like "API V3 collection response", 0, 0, "ProjectStorage", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'ProjectStorage', 'Collection' do let(:elements) { [] } end end end - describe "GET /api/v3/project_storages/:id" do + describe 'GET /api/v3/project_storages/:id' do let(:project_storage) do create(:project_storage, project: project3, storage: storage3, - project_folder_id: "1337", - project_folder_mode: "manual") + project_folder_id: '1337', + project_folder_mode: 'manual') end let(:project_storage_id) { project_storage.id } let(:path) { api_v3_paths.project_storage(project_storage_id) } @@ -206,94 +206,94 @@ subject { last_response.body } - it_behaves_like "successful response" + it_behaves_like 'successful response' - it { is_expected.to be_json_eql(api_v3_paths.storage_file(storage3.id, "1337").to_json).at_path("_links/projectFolder/href") } + it { is_expected.to be_json_eql(api_v3_paths.storage_file(storage3.id, '1337').to_json).at_path('_links/projectFolder/href') } - it { is_expected.to be_json_eql("manual".to_json).at_path("projectFolderMode") } + it { is_expected.to be_json_eql('manual'.to_json).at_path('projectFolderMode') } - context "if user has permission to see file storages in project" do + context 'if user has permission to see file storages in project' do let(:current_user) do create(:user, member_with_permissions: { project3 => [] }) end - it_behaves_like "not found" + it_behaves_like 'not found' end - context "if user is not member in related project" do + context 'if user is not member in related project' do let(:project_storage_id) { project_storage11.id } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "if project storage does not exists" do - let(:project_storage_id) { "1337" } + context 'if project storage does not exists' do + let(:project_storage_id) { '1337' } - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "GET /api/v3/project_storages/:id/open" do + describe 'GET /api/v3/project_storages/:id/open' do let(:path) { api_v3_paths.project_storage_open(project_storage11.id) } - let(:location) { "https://deathstar.storage.org/files" } - let(:location_project_folder) { "https://deathstar.storage.org/files/data/project_destroy_alderan" } + let(:location) { 'https://deathstar.storage.org/files' } + let(:location_project_folder) { 'https://deathstar.storage.org/files/data/project_destroy_alderan' } let(:current_user) do create(:user, member_with_permissions: { project1 => view_permissions }) end before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.open_storage", + 'nextcloud.queries.open_storage', ->(_) { ServiceResult.success(result: location) } ) Storages::Peripherals::Registry.stub( - "nextcloud.queries.open_file_link", + 'nextcloud.queries.open_file_link', ->(_) { ServiceResult.success(result: location_project_folder) } ) end - context "as admin" do + context 'as admin' do let(:current_user) { create(:admin) } - it_behaves_like "redirect response" + it_behaves_like 'redirect response' end - context "if user belongs to a project related to project storage" do - it_behaves_like "redirect response" + context 'if user belongs to a project related to project storage' do + it_behaves_like 'redirect response' - context "if project storage has a configured project folder" do + context 'if project storage has a configured project folder' do before(:all) do project_storage12.update( - project_folder_id: "1337", - project_folder_mode: "manual" + project_folder_id: '1337', + project_folder_mode: 'manual' ) end after(:all) do project_storage12.update( project_folder_id: nil, - project_folder_mode: "inactive" + project_folder_mode: 'inactive' ) end let(:path) { api_v3_paths.project_storage_open(project_storage12.id) } - it_behaves_like "redirect response" do + it_behaves_like 'redirect response' do let(:location) { location_project_folder } end end - context "if user is missing permission view_file_links" do + context 'if user is missing permission view_file_links' do let(:view_permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "if user is not member of the project" do + context 'if user is not member of the project' do let(:path) { api_v3_paths.project_storage_open(project_storage21.id) } - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/modules/storages/spec/requests/api/v3/projects/projects_storages_filter_spec.rb b/modules/storages/spec/requests/api/v3/projects/projects_storages_filter_spec.rb index 50edb46fbe32..12d3e22380c0 100644 --- a/modules/storages/spec/requests/api/v3/projects/projects_storages_filter_spec.rb +++ b/modules/storages/spec/requests/api/v3/projects/projects_storages_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "API v3 projects resource with filters for the linked storages", +RSpec.describe 'API v3 projects resource with filters for the linked storages', content_type: :json do include API::V3::Utilities::PathHelper @@ -63,58 +63,58 @@ def disable_module(project, modul) before { login_as user } - describe "GET /api/v3/projects" do + describe 'GET /api/v3/projects' do let(:path) { api_v3_paths.path_for :projects, filters: } before { get path } - context "with filter for storage id" do + context 'with filter for storage id' do let(:storage_id) { storage1.id } - let(:filters) { [{ storageId: { operator: "=", values: [storage_id] } }] } + let(:filters) { [{ storageId: { operator: '=', values: [storage_id] } }] } - it_behaves_like "API V3 collection response", 3, 3, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 3, 3, 'Project', 'Collection' do let(:elements) { [project3, project2, project1] } end - context "if a project has the storages module deactivated" do - before(:all) { disable_module(project1, "storages") } - after(:all) { enable_module(project1, "storages") } + context 'if a project has the storages module deactivated' do + before(:all) { disable_module(project1, 'storages') } + after(:all) { enable_module(project1, 'storages') } - it_behaves_like "API V3 collection response", 2, 2, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 2, 2, 'Project', 'Collection' do let(:elements) { [project3, project2] } end end - context "if the filter is set to an unknown storage id" do - let(:storage_id) { "1337" } + context 'if the filter is set to an unknown storage id' do + let(:storage_id) { '1337' } - it_behaves_like "API V3 collection response", 0, 0, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'Project', 'Collection' do let(:elements) { [] } end end end - context "with filter for storage url" do + context 'with filter for storage url' do let(:storage_url) { CGI.escape(storage1.host) } - let(:filters) { [{ storageUrl: { operator: "=", values: [storage_url] } }] } + let(:filters) { [{ storageUrl: { operator: '=', values: [storage_url] } }] } - it_behaves_like "API V3 collection response", 3, 3, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 3, 3, 'Project', 'Collection' do let(:elements) { [project3, project2, project1] } end - context "if a project has the storages module deactivated" do - before(:all) { disable_module(project1, "storages") } - after(:all) { enable_module(project1, "storages") } + context 'if a project has the storages module deactivated' do + before(:all) { disable_module(project1, 'storages') } + after(:all) { enable_module(project1, 'storages') } - it_behaves_like "API V3 collection response", 2, 2, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 2, 2, 'Project', 'Collection' do let(:elements) { [project3, project2] } end end - context "if the filter is set to an unknown storage url" do + context 'if the filter is set to an unknown storage url' do let(:storage_url) { CGI.escape("https://not.my-domain.org") } - it_behaves_like "API V3 collection response", 0, 0, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 0, 0, 'Project', 'Collection' do let(:elements) { [] } end end diff --git a/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb b/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb index afe0bd2febe5..aef42954a19b 100644 --- a/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb +++ b/modules/storages/spec/requests/api/v3/storages/storage_files_api_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "API v3 storage files", :webmock, content_type: :json do +RSpec.describe 'API v3 storage files', :webmock, content_type: :json do include API::V3::Utilities::PathHelper include StorageServerHelpers @@ -55,7 +55,7 @@ login_as current_user end - describe "GET /api/v3/storages/:storage_id/files" do + describe 'GET /api/v3/storages/:storage_id/files' do let(:path) { api_v3_paths.storage_files(storage.id) } let(:response) do @@ -63,148 +63,148 @@ [ Storages::StorageFile.new( id: 1, - name: "new_younglings.md", + name: 'new_younglings.md', size: 4096, - mime_type: "text/markdown", + mime_type: 'text/markdown', created_at: DateTime.now, last_modified_at: DateTime.now, - created_by_name: "Obi-Wan Kenobi", - last_modified_by_name: "Obi-Wan Kenobi", - location: "/", + created_by_name: 'Obi-Wan Kenobi', + last_modified_by_name: 'Obi-Wan Kenobi', + location: '/', permissions: %i[readable] ), Storages::StorageFile.new( id: 2, - name: "holocron_inventory.md", + name: 'holocron_inventory.md', size: 4096, - mime_type: "text/markdown", + mime_type: 'text/markdown', created_at: DateTime.now, last_modified_at: DateTime.now, - created_by_name: "Obi-Wan Kenobi", - last_modified_by_name: "Obi-Wan Kenobi", - location: "/", + created_by_name: 'Obi-Wan Kenobi', + last_modified_by_name: 'Obi-Wan Kenobi', + location: '/', permissions: %i[readable writeable] ) ], Storages::StorageFile.new( id: 32, - name: "/", + name: '/', size: 4096 * 2, - mime_type: "application/x-op-directory", + mime_type: 'application/x-op-directory', created_at: DateTime.now, last_modified_at: DateTime.now, - created_by_name: "Obi-Wan Kenobi", - last_modified_by_name: "Obi-Wan Kenobi", - location: "/", + created_by_name: 'Obi-Wan Kenobi', + last_modified_by_name: 'Obi-Wan Kenobi', + location: '/', permissions: %i[readable writeable] ), [] ) end - context "with successful response" do + context 'with successful response' do before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.files", + 'nextcloud.queries.files', ->(_) { ServiceResult.success(result: response) } ) end subject { last_response.body } - it "responds with appropriate JSON" do - expect(subject).to be_json_eql(response.files[0].id.to_json).at_path("files/0/id") - expect(subject).to be_json_eql(response.files[0].name.to_json).at_path("files/0/name") - expect(subject).to be_json_eql(response.files[1].id.to_json).at_path("files/1/id") - expect(subject).to be_json_eql(response.files[1].name.to_json).at_path("files/1/name") - expect(subject).to be_json_eql(response.files[0].permissions.to_json).at_path("files/0/permissions") - expect(subject).to be_json_eql(response.files[1].permissions.to_json).at_path("files/1/permissions") - expect(subject).to be_json_eql(response.parent.id.to_json).at_path("parent/id") - expect(subject).to be_json_eql(response.parent.name.to_json).at_path("parent/name") - expect(subject).to be_json_eql(response.ancestors.to_json).at_path("ancestors") + it 'responds with appropriate JSON' do + expect(subject).to be_json_eql(response.files[0].id.to_json).at_path('files/0/id') + expect(subject).to be_json_eql(response.files[0].name.to_json).at_path('files/0/name') + expect(subject).to be_json_eql(response.files[1].id.to_json).at_path('files/1/id') + expect(subject).to be_json_eql(response.files[1].name.to_json).at_path('files/1/name') + expect(subject).to be_json_eql(response.files[0].permissions.to_json).at_path('files/0/permissions') + expect(subject).to be_json_eql(response.files[1].permissions.to_json).at_path('files/1/permissions') + expect(subject).to be_json_eql(response.parent.id.to_json).at_path('parent/id') + expect(subject).to be_json_eql(response.parent.name.to_json).at_path('parent/name') + expect(subject).to be_json_eql(response.ancestors.to_json).at_path('ancestors') end end - context "with query failed" do + context 'with query failed' do before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.files", + 'nextcloud.queries.files', ->(_) { ServiceResult.failure(result: error, errors: Storages::StorageError.new(code: error)) } ) end - context "with authorization failure" do + context 'with authorization failure' do let(:error) { :unauthorized } it { expect(last_response.status).to be(500) } end - context "with internal error" do + context 'with internal error' do let(:error) { :error } it { expect(last_response.status).to be(500) } end - context "with not found" do + context 'with not found' do let(:error) { :not_found } - it "fails with outbound request failure" do + it 'fails with outbound request failure' do expect(last_response.status).to be(500) body = JSON.parse(last_response.body) - expect(body["message"]).to eq(I18n.t("api_v3.errors.code_500_outbound_request_failure", status_code: 404)) - expect(body["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:OutboundRequest:NotFound") + expect(body['message']).to eq(I18n.t('api_v3.errors.code_500_outbound_request_failure', status_code: 404)) + expect(body['errorIdentifier']).to eq('urn:openproject-org:api:v3:errors:OutboundRequest:NotFound') end end end end - describe "GET /api/v3/storages/:storage_id/files/:file_id" do - let(:file_id) { "42" } + describe 'GET /api/v3/storages/:storage_id/files/:file_id' do + let(:file_id) { '42' } let(:path) { api_v3_paths.storage_file(storage.id, file_id) } - context "with successful response" do + context 'with successful response' do let(:response) do Storages::StorageFileInfo.new( - status: "OK", + status: 'OK', status_code: 200, id: file_id, name: "Documents", last_modified_at: DateTime.now, created_at: DateTime.now, - mime_type: "application/x-op-directory", + mime_type: 'application/x-op-directory', size: 1108864, - owner_name: "Darth Vader", - owner_id: "darthvader", + owner_name: 'Darth Vader', + owner_id: 'darthvader', trashed: false, - last_modified_by_name: "Darth Sidious", - last_modified_by_id: "palpatine", - permissions: "RGDNVCK", - location: "/Documents" + last_modified_by_name: 'Darth Sidious', + last_modified_by_id: 'palpatine', + permissions: 'RGDNVCK', + location: '/Documents' ) end before do files_info_query = ->(_) { ServiceResult.success(result: response) } - Storages::Peripherals::Registry.stub("nextcloud.queries.file_info", files_info_query) + Storages::Peripherals::Registry.stub('nextcloud.queries.file_info', files_info_query) end subject { last_response.body } - it "responds with appropriate JSON" do - expect(subject).to be_json_eql("StorageFile".to_json).at_path("_type") - expect(subject).to be_json_eql(response.id.to_json).at_path("id") - expect(subject).to be_json_eql(response.name.to_json).at_path("name") - expect(subject).to be_json_eql(response.size.to_json).at_path("size") - expect(subject).to be_json_eql(response.mime_type.to_json).at_path("mimeType") - expect(subject).to be_json_eql(response.owner_name.to_json).at_path("createdByName") - expect(subject).to be_json_eql(response.last_modified_by_name.to_json).at_path("lastModifiedByName") - expect(subject).to be_json_eql(response.location.to_json).at_path("location") - expect(subject).to be_json_eql(response.permissions.to_json).at_path("permissions") + it 'responds with appropriate JSON' do + expect(subject).to be_json_eql('StorageFile'.to_json).at_path('_type') + expect(subject).to be_json_eql(response.id.to_json).at_path('id') + expect(subject).to be_json_eql(response.name.to_json).at_path('name') + expect(subject).to be_json_eql(response.size.to_json).at_path('size') + expect(subject).to be_json_eql(response.mime_type.to_json).at_path('mimeType') + expect(subject).to be_json_eql(response.owner_name.to_json).at_path('createdByName') + expect(subject).to be_json_eql(response.last_modified_by_name.to_json).at_path('lastModifiedByName') + expect(subject).to be_json_eql(response.location.to_json).at_path('location') + expect(subject).to be_json_eql(response.permissions.to_json).at_path('permissions') end end - context "with query failed" do + context 'with query failed' do before do clazz = Storages::Peripherals::StorageInteraction::Nextcloud::FileInfoQuery instance = instance_double(clazz) @@ -214,109 +214,109 @@ ) end - context "with authorization failure" do + context 'with authorization failure' do let(:error) { :forbidden } - it "fails with outbound request failure" do + it 'fails with outbound request failure' do expect(last_response.status).to be(500) body = JSON.parse(last_response.body) - expect(body["message"]).to eq(I18n.t("api_v3.errors.code_500_outbound_request_failure", status_code: 403)) - expect(body["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:OutboundRequest:Forbidden") + expect(body['message']).to eq(I18n.t('api_v3.errors.code_500_outbound_request_failure', status_code: 403)) + expect(body['errorIdentifier']).to eq('urn:openproject-org:api:v3:errors:OutboundRequest:Forbidden') end end - context "with internal error" do + context 'with internal error' do let(:error) { :error } it { expect(last_response.status).to be(500) } end - context "with not found" do + context 'with not found' do let(:error) { :not_found } - it "fails with outbound request failure" do + it 'fails with outbound request failure' do expect(last_response.status).to be(500) body = JSON.parse(last_response.body) - expect(body["message"]).to eq(I18n.t("api_v3.errors.code_500_outbound_request_failure", status_code: 404)) - expect(body["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:OutboundRequest:NotFound") + expect(body['message']).to eq(I18n.t('api_v3.errors.code_500_outbound_request_failure', status_code: 404)) + expect(body['errorIdentifier']).to eq('urn:openproject-org:api:v3:errors:OutboundRequest:NotFound') end end end end - describe "POST /api/v3/storages/:storage_id/files/prepare_upload" do + describe 'POST /api/v3/storages/:storage_id/files/prepare_upload' do let(:permissions) { %i(view_work_packages view_file_links manage_file_links) } let(:path) { api_v3_paths.prepare_upload(storage.id) } - let(:upload_link) { Storages::UploadLink.new("https://example.com/upload/xyz123") } + let(:upload_link) { Storages::UploadLink.new('https://example.com/upload/xyz123') } let(:body) { { fileName: "ape.png", parent: "/Pictures", projectId: project.id }.to_json } subject(:last_response) do post(path, body) end - describe "with successful response" do + describe 'with successful response' do before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.upload_link", + 'nextcloud.queries.upload_link', ->(_) { ServiceResult.success(result: upload_link) } ) end subject { last_response.body } - it "responds with appropriate JSON" do - expect(subject).to be_json_eql(Storages::UploadLink.name.split("::").last.to_json).at_path("_type") + it 'responds with appropriate JSON' do + expect(subject).to be_json_eql(Storages::UploadLink.name.split('::').last.to_json).at_path('_type') expect(subject) .to(be_json_eql("#{API::V3::URN_PREFIX}storages:upload_link:no_link_provided".to_json) - .at_path("_links/self/href")) - expect(subject).to be_json_eql(upload_link.destination.to_json).at_path("_links/destination/href") - expect(subject).to be_json_eql("post".to_json).at_path("_links/destination/method") - expect(subject).to be_json_eql("Upload File".to_json).at_path("_links/destination/title") + .at_path('_links/self/href')) + expect(subject).to be_json_eql(upload_link.destination.to_json).at_path('_links/destination/href') + expect(subject).to be_json_eql("post".to_json).at_path('_links/destination/method') + expect(subject).to be_json_eql("Upload File".to_json).at_path('_links/destination/title') end end - context "with query failed" do + context 'with query failed' do before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.upload_link", + 'nextcloud.queries.upload_link', ->(_) { ServiceResult.failure(result: error, errors: Storages::StorageError.new(code: error)) } ) end - describe "due to authorization failure" do + describe 'due to authorization failure' do let(:error) { :unauthorized } it { expect(last_response.status).to be(500) } end - describe "due to internal error" do + describe 'due to internal error' do let(:error) { :error } it { expect(last_response.status).to be(500) } end - describe "due to not found" do + describe 'due to not found' do let(:error) { :not_found } - it "fails with outbound request failure" do + it 'fails with outbound request failure' do expect(last_response.status).to be(500) body = JSON.parse(last_response.body) - expect(body["message"]).to eq(I18n.t("api_v3.errors.code_500_outbound_request_failure", status_code: 404)) - expect(body["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:OutboundRequest:NotFound") + expect(body['message']).to eq(I18n.t('api_v3.errors.code_500_outbound_request_failure', status_code: 404)) + expect(body['errorIdentifier']).to eq('urn:openproject-org:api:v3:errors:OutboundRequest:NotFound') end end end - context "with invalid request body" do + context 'with invalid request body' do let(:body) { { fileNam_: "ape.png", parent: "/Pictures", projectId: project.id }.to_json } it { expect(last_response.status).to be(400) } end - context "without ee token", with_ee: false do + context 'without ee token', with_ee: false do let(:storage) { create(:one_drive_storage, creator: current_user) } it { expect(last_response.status).to be(500) } diff --git a/modules/storages/spec/requests/api/v3/work_packages/work_packages_linkable_filter_spec.rb b/modules/storages/spec/requests/api/v3/work_packages/work_packages_linkable_filter_spec.rb index 429e011c219a..b0bbb754072a 100644 --- a/modules/storages/spec/requests/api/v3/work_packages/work_packages_linkable_filter_spec.rb +++ b/modules/storages/spec/requests/api/v3/work_packages/work_packages_linkable_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "API v3 work packages resource with filters for the linkable to storage attribute", +RSpec.describe 'API v3 work packages resource with filters for the linkable to storage attribute', content_type: :json do include API::V3::Utilities::PathHelper @@ -73,92 +73,92 @@ login_as current_user end - describe "GET /api/v3/work_packages" do + describe 'GET /api/v3/work_packages' do let(:path) { api_v3_paths.path_for :work_packages, filters: } before do get path end - context "with filter for storage id" do + context 'with filter for storage id' do let(:storage_id) { storage.id } let(:filters) do [ { linkable_to_storage_id: { - operator: "=", + operator: '=', values: [storage_id] } } ] end - it_behaves_like "API V3 collection response", 4, 4, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 4, 4, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package2, work_package3, work_package4] } end - context "if user has no sufficient permissions in one project" do + context 'if user has no sufficient permissions in one project' do let(:role2) { create(:project_role, permissions: %i(view_work_packages view_file_links)) } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package2] } end end - context "if a project has the storages module deactivated" do + context 'if a project has the storages module deactivated' do let(:project1) { create(:project, disable_modules: :storages, members: { current_user => role1 }) } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package3, work_package4] } end end - context "if the filter is set to an unknown storage id" do + context 'if the filter is set to an unknown storage id' do let(:storage_id) { "1337" } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end end - context "with filter for storage url" do + context 'with filter for storage url' do let(:storage_url) { CGI.escape(storage.host) } let(:filters) do [ { linkable_to_storage_url: { - operator: "=", + operator: '=', values: [storage_url] } } ] end - it_behaves_like "API V3 collection response", 4, 4, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 4, 4, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package2, work_package3, work_package4] } end - context "if user has no sufficient permissions in one project" do + context 'if user has no sufficient permissions in one project' do let(:role2) { create(:project_role, permissions: %i(view_work_packages view_file_links)) } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package2] } end end - context "if a project has the storages module deactivated" do + context 'if a project has the storages module deactivated' do let(:project1) { create(:project, disable_modules: :storages, members: { current_user => role1 }) } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package3, work_package4] } end end - context "if the filter is set to an unknown storage url" do + context 'if the filter is set to an unknown storage url' do let(:storage_url) { CGI.escape("https://not.my-domain.org") } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end diff --git a/modules/storages/spec/requests/api/v3/work_packages/work_packages_linked_filter_spec.rb b/modules/storages/spec/requests/api/v3/work_packages/work_packages_linked_filter_spec.rb index 35137b2abb69..0808fbc1e672 100644 --- a/modules/storages/spec/requests/api/v3/work_packages/work_packages_linked_filter_spec.rb +++ b/modules/storages/spec/requests/api/v3/work_packages/work_packages_linked_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "API v3 work packages resource with filters for linked storage file", +RSpec.describe 'API v3 work packages resource with filters for linked storage file', content_type: :json do include API::V3::Utilities::PathHelper @@ -81,208 +81,208 @@ login_as current_user end - describe "GET /api/v3/work_packages" do + describe 'GET /api/v3/work_packages' do let(:path) { api_v3_paths.path_for :work_packages, filters: } before do get path end - context "with single filter for file id" do + context 'with single filter for file id' do let(:origin_id_value) { file_link1.origin_id.to_s } let(:filters) do [ { file_link_origin_id: { - operator: "=", + operator: '=', values: [origin_id_value] } } ] end - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package3] } end - context "if one project has not sufficient permissions" do + context 'if one project has not sufficient permissions' do let(:role2) { create(:project_role, permissions: %i(view_work_packages)) } - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1] } end end - context "if a project has the storages module deactivated" do + context 'if a project has the storages module deactivated' do let(:project1) { create(:project, disable_modules: :storages, members: { current_user => role1 }) } - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package3] } end end - context "if the filter is set to an unknown file id from origin" do + context 'if the filter is set to an unknown file id from origin' do let(:origin_id_value) { "1337" } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end - context "if the filter is set to a file linked to a work package in an unlinked project" do + context 'if the filter is set to a file linked to a work package in an unlinked project' do let(:origin_id_value) { file_link4.origin_id.to_s } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end - context "if using signaling" do - let(:path) { api_v3_paths.path_for :work_packages, select: "total,count,_type,elements/*", filters: } + context 'if using signaling' do + let(:path) { api_v3_paths.path_for :work_packages, select: 'total,count,_type,elements/*', filters: } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package3] } end end end - context "with single filter for storage id" do + context 'with single filter for storage id' do let(:storage_id_value) { storage1.id.to_s } let(:filters) do [ { storage_id: { - operator: "=", + operator: '=', values: [storage_id_value] } } ] end - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package2] } end - context "if one project has not sufficient permissions" do + context 'if one project has not sufficient permissions' do let(:role1) { create(:project_role, permissions: %i(view_work_packages)) } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end - context "if the filter is set to an unknown storage id" do + context 'if the filter is set to an unknown storage id' do let(:storage_id_value) { "1337" } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end end - context "with single filter for storage url" do + context 'with single filter for storage url' do let(:storage_url_value) { CGI.escape(storage2.host) } let(:filters) do [ { storage_url: { - operator: "=", + operator: '=', values: [storage_url_value] } } ] end - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package3] } end - context "if any of the matching work packages is in a project without a mapping to that storage" do + context 'if any of the matching work packages is in a project without a mapping to that storage' do let(:storage_url_value) { CGI.escape(storage1.host) } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1, work_package2] } end end - context "if one project has not sufficient permissions" do + context 'if one project has not sufficient permissions' do let(:role2) { create(:project_role, permissions: %i(view_work_packages)) } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end - context "if the filter is set to an unknown storage url" do + context 'if the filter is set to an unknown storage url' do let(:storage_url_value) { "https://not.my-domain.org" } - it_behaves_like "API V3 collection response", 0, 0, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 0, 0, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [] } end end end - context "with combined filter of file id and storage id" do + context 'with combined filter of file id and storage id' do let(:origin_id_value) { file_link1.origin_id } let(:storage_id_value) { storage1.id } let(:filters) do [ { file_link_origin_id: { - operator: "=", + operator: '=', values: [origin_id_value] } }, { storage_id: { - operator: "=", + operator: '=', values: [storage_id_value] } } ] end - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1] } end - context "if just the storage id is switched" do + context 'if just the storage id is switched' do let(:storage_id_value) { storage2.id } - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package3] } end end end - context "with combined filter of file id and storage url" do + context 'with combined filter of file id and storage url' do let(:origin_id_value) { file_link1.origin_id } let(:storage_url_value) { CGI.escape(storage1.host) } let(:filters) do [ { file_link_origin_id: { - operator: "=", + operator: '=', values: [origin_id_value] } }, { storage_url: { - operator: "=", + operator: '=', values: [storage_url_value] } } ] end - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package1] } end - context "if just the storage url is switched" do + context 'if just the storage url is switched' do let(:storage_url_value) { CGI.escape(storage2.host) } - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_package3] } end end diff --git a/modules/storages/spec/requests/append_content_security_policy_spec.rb b/modules/storages/spec/requests/append_content_security_policy_spec.rb index 8571a1894f99..ddfb510166cd 100644 --- a/modules/storages/spec/requests/append_content_security_policy_spec.rb +++ b/modules/storages/spec/requests/append_content_security_policy_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "Appendix of default CSP for external file storage hosts" do +RSpec.describe 'Appendix of default CSP for external file storage hosts' do def parse_csp(csp_string) csp_string - .split("; ") + .split('; ') .map(&:split) .each_with_object({}) { |csp_part, csp_hash_map| csp_hash_map[csp_part[0]] = csp_part[1..] } end @@ -41,24 +41,24 @@ def parse_csp(csp_string) shared_let(:storage) { create(:nextcloud_storage) } shared_let(:project_storage) { create(:project_storage, project:, storage:) } - describe "GET /" do - context "when logged in" do + describe 'GET /' do + context 'when logged in' do current_user { create(:user, member_with_permissions: { project => %i[manage_file_links] }) } - it "appends storage host to the connect-src CSP" do - get "/" + it 'appends storage host to the connect-src CSP' do + get '/' - csp = parse_csp(last_response.headers["Content-Security-Policy"]) - expect(csp["connect-src"]).to include(storage.host) + csp = parse_csp(last_response.headers['Content-Security-Policy']) + expect(csp['connect-src']).to include(storage.host) end end - context "when not logged in" do - it "does not append host to connect-src CSP" do - get "/" + context 'when not logged in' do + it 'does not append host to connect-src CSP' do + get '/' - csp = parse_csp(last_response.headers["Content-Security-Policy"]) - expect(csp["connect-src"]).not_to include(storage.host) + csp = parse_csp(last_response.headers['Content-Security-Policy']) + expect(csp['connect-src']).not_to include(storage.host) end end end diff --git a/modules/storages/spec/requests/project_storages_open_spec.rb b/modules/storages/spec/requests/project_storages_open_spec.rb index 9db041b8c55e..535065e24c96 100644 --- a/modules/storages/spec/requests/project_storages_open_spec.rb +++ b/modules/storages/spec/requests/project_storages_open_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe "projects/:project_id/project_storages/:id/open" do +RSpec.describe 'projects/:project_id/project_storages/:id/open' do let(:expected_redirect_path) do API::V3::Utilities::PathHelper::ApiV3Path.project_storage_open(project_storage.id) end @@ -42,37 +42,37 @@ shared_let(:project) { create(:project) } shared_let(:storage) { create(:nextcloud_storage_configured) } - context "when user is logged in" do + context 'when user is logged in' do current_user { create(:user, member_with_permissions: { project => permissions }) } - context "when user has permissions" do + context 'when user has permissions' do let(:permissions) { %i[view_file_links] } - context "when project_folder is automatic" do + context 'when project_folder is automatic' do let(:project_storage) { create(:project_storage, :as_automatically_managed, project:, storage:) } - context "when project_folder_id has been set by background job already" do - before { project_storage.update_attribute(:project_folder_id, "123") } + context 'when project_folder_id has been set by background job already' do + before { project_storage.update_attribute(:project_folder_id, '123') } - context "when user is able to read project_folder" do + context 'when user is able to read project_folder' do before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.file_info", ->(_) { ServiceResult.success } + 'nextcloud.queries.file_info', ->(_) { ServiceResult.success } ) end - context "html" do - it "redirects to api_v3_projects_storage_open_url" do - get route, {}, { "HTTP_ACCEPT" => "text/html" } + context 'html' do + it 'redirects to api_v3_projects_storage_open_url' do + get route, {}, { 'HTTP_ACCEPT' => 'text/html' } expect(last_response.status).to eq (302) expect(last_response.headers["Location"]).to eq(expected_redirect_url) end end - context "turbo_stream" do - it "renders an appropirate turbo_stream" do - get route, {}, { "HTTP_ACCEPT" => "text/vnd.turbo-stream.html" } + context 'turbo_stream' do + it 'renders an appropirate turbo_stream' do + get route, {}, { 'HTTP_ACCEPT' => 'text/vnd.turbo-stream.html' } expect(last_response.status).to eq (200) expect(last_response.body).to eq ("\n \n\n\n") @@ -80,24 +80,24 @@ end end - context "when user is not able to read project_folder" do + context 'when user is not able to read project_folder' do let(:code) { :forbidden } before do Storages::Peripherals::Registry.stub( - "nextcloud.queries.file_info", ->(_) do + 'nextcloud.queries.file_info', ->(_) do ServiceResult.failure(result: code, errors: Storages::StorageError.new(code:)) end ) end - context "html" do - context "when error code is unauthorized" do + context 'html' do + context 'when error code is unauthorized' do let(:code) { :unauthorized } - it "redirects to ensure_connection url with current request url as a destination_url" do - get route, {}, { "HTTP_ACCEPT" => "text/html" } + it 'redirects to ensure_connection url with current request url as a destination_url' do + get route, {}, { 'HTTP_ACCEPT' => 'text/html' } expect(last_response.status).to eq (302) expect(last_response.headers["Location"]).to eq ( @@ -106,13 +106,13 @@ end end - context "when error code is forbidden" do - it "redirects to project overview page with modal flash set up" do - get route, {}, { "HTTP_ACCEPT" => "text/html" } + context 'when error code is forbidden' do + it 'redirects to project overview page with modal flash set up' do + get route, {}, { 'HTTP_ACCEPT' => 'text/html' } expect(last_response.status).to eq (302) expect(last_response.headers["Location"]).to eq ("http://example.org/projects/#{project.identifier}") - expect(last_request.session["flash"]["flashes"]) + expect(last_request.session['flash']['flashes']) .to eq({ "modal" => { type: "Storages::OpenProjectStorageModalComponent", @@ -125,9 +125,9 @@ end end - context "turbo_stream" do - it "responds with 204 no content" do - get route, {}, { "HTTP_ACCEPT" => "text/vnd.turbo-stream.html" } + context 'turbo_stream' do + it 'responds with 204 no content' do + get route, {}, { 'HTTP_ACCEPT' => 'text/vnd.turbo-stream.html' } expect(last_response.status).to eq (204) expect(last_response.body).to eq ("") @@ -136,14 +136,14 @@ end end - context "when project_folder_id has not been set by background job yet" do - context "html" do - it "redirects to project overview page with modal flash set up" do - get route, {}, { "HTTP_ACCEPT" => "text/html" } + context 'when project_folder_id has not been set by background job yet' do + context 'html' do + it 'redirects to project overview page with modal flash set up' do + get route, {}, { 'HTTP_ACCEPT' => 'text/html' } expect(last_response.status).to eq (302) expect(last_response.headers["Location"]).to eq ("http://example.org/projects/#{project.identifier}") - expect(last_request.session["flash"]["flashes"]) + expect(last_request.session['flash']['flashes']) .to eq({ "modal" => { type: "Storages::OpenProjectStorageModalComponent", @@ -155,9 +155,9 @@ end end - context "turbo_stream" do - it "responds with 204 no content" do - get route, {}, { "HTTP_ACCEPT" => "text/vnd.turbo-stream.html" } + context 'turbo_stream' do + it 'responds with 204 no content' do + get route, {}, { 'HTTP_ACCEPT' => 'text/vnd.turbo-stream.html' } expect(last_response.status).to eq (204) expect(last_response.body).to eq ("") @@ -166,9 +166,9 @@ end end - context "when project_folder is not automatic" do - it "redirects to storage_open_url" do - get route, {}, { "HTTP_ACCEPT" => "text/html" } + context 'when project_folder is not automatic' do + it 'redirects to storage_open_url' do + get route, {}, { 'HTTP_ACCEPT' => 'text/html' } expect(last_response.status).to eq (302) expect(last_response.headers["Location"]).to eq (expected_redirect_url) @@ -176,18 +176,18 @@ end end - context "when user has no permissions" do + context 'when user has no permissions' do let(:permissions) { %i[] } - it "responds with 403" do - get route, {}, { "HTTP_ACCEPT" => "text/html" } + it 'responds with 403' do + get route, {}, { 'HTTP_ACCEPT' => 'text/html' } expect(last_response.status).to eq(403) end end end - context "when user is not logged in" do - it "responds with 401" do + context 'when user is not logged in' do + it 'responds with 401' do get route expect(last_response.status).to eq(401) end diff --git a/modules/storages/spec/requests/storages/project_settings/oauth_access_grant_flow_spec.rb b/modules/storages/spec/requests/storages/project_settings/oauth_access_grant_flow_spec.rb index 86647c0c511b..0a0954c6de76 100644 --- a/modules/storages/spec/requests/storages/project_settings/oauth_access_grant_flow_spec.rb +++ b/modules/storages/spec/requests/storages/project_settings/oauth_access_grant_flow_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe "GET /projects/:project_id/settings/project_storages/:id/oauth_access_grant", :webmock do - shared_let(:user) { create(:user, preferences: { time_zone: "Etc/UTC" }) } + shared_let(:user) { create(:user, preferences: { time_zone: 'Etc/UTC' }) } shared_let(:role) do create(:project_role, permissions: %i[manage_storages_in_project @@ -49,8 +49,8 @@ end shared_let(:project_storage) { create(:project_storage, project:, storage:) } - context "when user is not logged in" do - it "requires login" do + context 'when user is not logged in' do + it 'requires login' do get oauth_access_grant_project_settings_project_storage_path( project_id: project_storage.project.id, id: project_storage @@ -59,11 +59,11 @@ end end - context "when user is logged in" do + context 'when user is logged in' do before { login_as(user) } context 'when user is not "connected"' do - let(:nonce) { "57a17c3f-b2ed-446e-9dd8-651ba3aec37d" } + let(:nonce) { '57a17c3f-b2ed-446e-9dd8-651ba3aec37d' } let(:redirect_uri) do CGI.escape("#{OpenProject::Application.root_url}/oauth_clients/#{storage.oauth_client.client_id}/callback") end @@ -73,7 +73,7 @@ allow(SecureRandom).to receive(:uuid).and_return(nonce).ordered end - it "redirects to storage authorization_uri with oauth_state_* cookie set" do + it 'redirects to storage authorization_uri with oauth_state_* cookie set' do get oauth_access_grant_project_settings_project_storage_path( project_id: project_storage.project.id, id: project_storage @@ -98,14 +98,14 @@ stub_request(:get, "#{storage.host}/ocs/v1.php/cloud/user") .with( headers: { - "Accept" => "application/json", - "Authorization" => "Bearer #{oauth_client_token.access_token}", - "Ocs-Apirequest" => "true" + 'Accept' => 'application/json', + 'Authorization' => "Bearer #{oauth_client_token.access_token}", + 'Ocs-Apirequest' => 'true' } ).to_return(status: 200, body: "", headers: {}) end - it "redirects to destination_url" do + it 'redirects to destination_url' do get oauth_access_grant_project_settings_project_storage_path( project_id: project_storage.project.id, id: project_storage diff --git a/modules/storages/spec/seeders/seeder_spec.rb b/modules/storages/spec/seeders/seeder_spec.rb index 4c9f0f225a00..f3f1dedb833e 100644 --- a/modules/storages/spec/seeders/seeder_spec.rb +++ b/modules/storages/spec/seeders/seeder_spec.rb @@ -28,11 +28,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe RootSeeder, "Storage module" do - it "seeds role permissions for Storages" do +RSpec.describe RootSeeder, 'Storage module' do + it 'seeds role permissions for Storages' do described_class.new.seed_data! expect(RolePermission.where(permission: :view_file_links).count).to eq 7 diff --git a/modules/storages/spec/services/principals/replace_references_service_call_integration_spec.rb b/modules/storages/spec/services/principals/replace_references_service_call_integration_spec.rb index 1eadf7a0b417..8033f8f480de 100644 --- a/modules/storages/spec/services/principals/replace_references_service_call_integration_spec.rb +++ b/modules/storages/spec/services/principals/replace_references_service_call_integration_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.describe Principals::ReplaceReferencesService, "#call", type: :model do +RSpec.describe Principals::ReplaceReferencesService, '#call', type: :model do shared_let(:principal) { create(:user) } shared_let(:to_principal) { create(:user) } @@ -41,17 +41,17 @@ described_class.new end - shared_examples "replaces the creator" do + shared_examples 'replaces the creator' do before do model end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "replaces principal with to_principal" do + it 'replaces principal with to_principal' do service_call model.reload @@ -59,20 +59,20 @@ end end - context "with Storage" do - it_behaves_like "replaces the creator" do + context 'with Storage' do + it_behaves_like 'replaces the creator' do let(:model) { create(:nextcloud_storage, creator: principal) } end end - context "with ProjectStorage" do - it_behaves_like "replaces the creator" do + context 'with ProjectStorage' do + it_behaves_like 'replaces the creator' do let(:model) { create(:project_storage, creator: principal) } end end - context "with FileLink" do - it_behaves_like "replaces the creator" do + context 'with FileLink' do + it_behaves_like 'replaces the creator' do let(:work_package) { create(:work_package) } let(:model) { create(:file_link, creator: principal, container: work_package) } end diff --git a/modules/storages/spec/services/storages/file_links/create_service_spec.rb b/modules/storages/spec/services/storages/file_links/create_service_spec.rb index 72535c1a21fa..8e9f368dbe6b 100644 --- a/modules/storages/spec/services/storages/file_links/create_service_spec.rb +++ b/modules/storages/spec/services/storages/file_links/create_service_spec.rb @@ -28,17 +28,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_create_service" +require 'services/base_services/behaves_like_create_service' RSpec.describe Storages::FileLinks::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:factory) { :file_link } end - it "creates a journal entry for its container" do + it 'creates a journal entry for its container' do project_storage = create(:project_storage) storage = project_storage.storage @@ -49,7 +49,7 @@ user = create(:admin) service = described_class.new(user:, contract_class: Storages::FileLinks::CreateContract) - params = { creator: user, container: work_package, origin_id: 200, origin_name: "bob_the_fake_file.png", storage: } + params = { creator: user, container: work_package, origin_id: 200, origin_name: 'bob_the_fake_file.png', storage: } expect do result = service.call(params) diff --git a/modules/storages/spec/services/storages/file_links/delete_service_spec.rb b/modules/storages/spec/services/storages/file_links/delete_service_spec.rb index 1ab5cada3fef..db4a4c6b4acd 100644 --- a/modules/storages/spec/services/storages/file_links/delete_service_spec.rb +++ b/modules/storages/spec/services/storages/file_links/delete_service_spec.rb @@ -28,17 +28,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_delete_service" +require 'services/base_services/behaves_like_delete_service' RSpec.describe Storages::FileLinks::DeleteService, type: :model do - it_behaves_like "BaseServices delete service" do + it_behaves_like 'BaseServices delete service' do let(:factory) { :file_link } end - it "creates a journal entry for its container", with_settings: { journal_aggregation_time_minutes: 0 } do + it 'creates a journal entry for its container', with_settings: { journal_aggregation_time_minutes: 0 } do project_storage = create(:project_storage) # Tap as the changes would otherwise mess with the journal creation i.e. the updated_at timestamp work_package = create(:work_package, project: project_storage.project).tap(&:clear_changes_information) diff --git a/modules/storages/spec/services/storages/file_links/file_link_sync_service_spec.rb b/modules/storages/spec/services/storages/file_links/file_link_sync_service_spec.rb index 688b31fec162..9b19425db8cf 100644 --- a/modules/storages/spec/services/storages/file_links/file_link_sync_service_spec.rb +++ b/modules/storages/spec/services/storages/file_links/file_link_sync_service_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::FileLinkSyncService, type: :model do @@ -47,17 +47,17 @@ subject(:service) { described_class.new(user:).call(file_links) } - describe "#call" do - context "with one file link" do + describe '#call' do + context 'with one file link' do let(:file_info) { build(:storage_file_info) } let(:file_link_one) { create(:file_link, origin_id: file_info.id, storage: storage_one, container: work_package) } before do Storages::Peripherals::Registry - .stub("nextcloud.queries.files_info", ->(_) { ServiceResult.success(result: [file_info]) }) + .stub('nextcloud.queries.files_info', ->(_) { ServiceResult.success(result: [file_info]) }) end - it "updates all origin_* fields" do + it 'updates all origin_* fields' do expect(service.success).to be_truthy expect(service.result.count).to be 1 expect(service.result.first).to be_a Storages::FileLink @@ -71,22 +71,22 @@ end end - context "without permission to read file (403)" do + context 'without permission to read file (403)' do let(:file_info) { build(:storage_file_info, status_code: 403) } let(:file_link_one) { create(:file_link, origin_id: file_info.id, storage: storage_one, container: work_package) } before do Storages::Peripherals::Registry - .stub("nextcloud.queries.files_info", ->(_) { ServiceResult.success(result: [file_info]) }) + .stub('nextcloud.queries.files_info', ->(_) { ServiceResult.success(result: [file_info]) }) end - it "returns a FileLink with #origin_status :not_allowed" do + it 'returns a FileLink with #origin_status :not_allowed' do expect(service.success).to be_truthy expect(service.result.first.origin_status).to be :view_not_allowed end end - context "with two file links, one updated and other not allowed" do + context 'with two file links, one updated and other not allowed' do let(:file_info_one) { build(:storage_file_info) } let(:file_info_two) { build(:storage_file_info, status_code: 403) } @@ -97,11 +97,11 @@ before do Storages::Peripherals::Registry - .stub("nextcloud.queries.files_info", + .stub('nextcloud.queries.files_info', ->(_) { ServiceResult.success(result: [file_info_one, file_info_two]) }) end - it "returns a successful result with two file links with different permissions" do + it 'returns a successful result with two file links with different permissions' do expect(service.success).to be_truthy expect(service.result.count).to be 2 expect(service.result[0].origin_id).to eql file_info_one.id @@ -111,16 +111,16 @@ end end - context "when file was not found (404)" do + context 'when file was not found (404)' do let(:file_info) { build(:storage_file_info, status_code: 404) } let(:file_link_one) { create(:file_link, origin_id: file_info.id, storage: storage_one, container: work_package) } before do Storages::Peripherals::Registry - .stub("nextcloud.queries.files_info", ->(_) { ServiceResult.success(result: [file_info]) }) + .stub('nextcloud.queries.files_info', ->(_) { ServiceResult.success(result: [file_info]) }) end - it "returns the file link with a status set to :not_found" do + it 'returns the file link with a status set to :not_found' do expect(service.success).to be_truthy expect(service.result.count).to be 1 expect(Storages::FileLink.count).to be 1 @@ -128,16 +128,16 @@ end end - context "when file has a different error (555)" do + context 'when file has a different error (555)' do let(:file_info) { build(:storage_file_info, status_code: 555) } let(:file_link_one) { create(:file_link, origin_id: file_info.id, storage: storage_one, container: work_package) } before do Storages::Peripherals::Registry - .stub("nextcloud.queries.files_info", ->(_) { ServiceResult.success(result: [file_info]) }) + .stub('nextcloud.queries.files_info', ->(_) { ServiceResult.success(result: [file_info]) }) end - it "returns the file link with a status set to :error" do + it 'returns the file link with a status set to :error' do expect(service.success).to be_truthy expect(service.result.count).to be 1 expect(Storages::FileLink.count).to be 1 @@ -145,14 +145,14 @@ end end - context "with files_info_query failing" do + context 'with files_info_query failing' do before do Storages::Peripherals::Registry - .stub("nextcloud.queries.files_info", + .stub('nextcloud.queries.files_info', ->(_) { ServiceResult.failure(result: :error, errors: Storages::StorageError.new(code: :error)) }) end - it "leaves the list of file_links unchanged with permissions = :error" do + it 'leaves the list of file_links unchanged with permissions = :error' do expect(service.success).to be_truthy expect(service.result.first.origin_status).to be :error end diff --git a/modules/storages/spec/services/storages/file_links/set_attributes_service_spec.rb b/modules/storages/spec/services/storages/file_links/set_attributes_service_spec.rb index 50f73f17407a..c5cfdfd350c5 100644 --- a/modules/storages/spec/services/storages/file_links/set_attributes_service_spec.rb +++ b/modules/storages/spec/services/storages/file_links/set_attributes_service_spec.rb @@ -28,20 +28,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::FileLinks::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:admin) } let(:contract_instance) do - contract = instance_double(Storages::Storages::BaseContract, "contract_instance") + contract = instance_double(Storages::Storages::BaseContract, 'contract_instance') allow(contract) .to receive_messages(validate: contract_valid, errors: contract_errors) contract end - let(:contract_errors) { instance_double(ActiveModel::Errors, "contract_errors") } + let(:contract_errors) { instance_double(ActiveModel::Errors, 'contract_errors') } let(:contract_valid) { true } let(:model_valid) { true } @@ -70,34 +70,34 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result) .to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with params" do + context 'with params' do let(:params) do { - name: "Foobar" + name: 'Foobar' } end - it "assigns the params" do + it 'assigns the params' do subject - expect(model_instance.name).to eq "Foobar" + expect(model_instance.name).to eq 'Foobar' end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } - it "returns failure" do + it 'returns failure' do expect(subject).not_to be_success end diff --git a/modules/storages/spec/services/storages/nextcloud_group_folder_properties_sync_service_spec.rb b/modules/storages/spec/services/storages/nextcloud_group_folder_properties_sync_service_spec.rb index 2541490f6f6c..a61675ce848b 100644 --- a/modules/storages/spec/services/storages/nextcloud_group_folder_properties_sync_service_spec.rb +++ b/modules/storages/spec/services/storages/nextcloud_group_folder_properties_sync_service_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::NextcloudGroupFolderPropertiesSyncService, :webmock do @@ -540,28 +540,28 @@ let(:project1) do create(:project, - name: "[Sample] Project Name / Ehuu", + name: '[Sample] Project Name / Ehuu', members: { multiple_projects_user => ordinary_role, single_project_user => ordinary_role }) end let(:project2) do create(:project, - name: "Jedi Project Folder ///", + name: 'Jedi Project Folder ///', members: { multiple_projects_user => ordinary_role }) end let(:project3) do create(:project, - name: "Project3", + name: 'Project3', members: { multiple_projects_user => ordinary_role }) end let(:project_not_active) do create(:project, - name: "NOT ACTIVE PROJECT", + name: 'NOT ACTIVE PROJECT', active: false, members: { multiple_projects_user => ordinary_role }) end let(:project_public) do create(:public_project, - name: "PUBLIC PROJECT", + name: 'PUBLIC PROJECT', active: true) end @@ -572,27 +572,27 @@ let(:ordinary_role) { create(:project_role, permissions: %w[read_files write_files]) } let!(:non_member_role) { create(:non_member, permissions: %w[read_files]) } - let(:storage) { create(:nextcloud_storage, :with_oauth_client, :as_automatically_managed, password: "12345678") } + let(:storage) { create(:nextcloud_storage, :with_oauth_client, :as_automatically_managed, password: '12345678') } let!(:project_storage1) do create(:project_storage, :with_historical_data, - project_folder_mode: "automatic", + project_folder_mode: 'automatic', project: project1, storage:) end let!(:project_storage2) do create(:project_storage, :with_historical_data, - project_folder_mode: "automatic", + project_folder_mode: 'automatic', project: project2, storage:, - project_folder_id: "123") + project_folder_id: '123') end let!(:project_storage3) do create(:project_storage, :with_historical_data, - project_folder_mode: "automatic", + project_folder_mode: 'automatic', project: project3, storage:, project_folder_id: nil) @@ -600,112 +600,112 @@ let!(:project_storage4) do create(:project_storage, :with_historical_data, - project_folder_mode: "automatic", + project_folder_mode: 'automatic', project: project_not_active, storage:, - project_folder_id: "778") + project_folder_id: '778') end let!(:project_storage5) do create(:project_storage, :with_historical_data, - project_folder_mode: "automatic", + project_folder_mode: 'automatic', project: project_public, storage:, - project_folder_id: "999") + project_folder_id: '999') end let(:oauth_client) { storage.oauth_client } # rubocop:enable RSpec/IndexedLet - describe "#call" do + describe '#call' do before do - create(:oauth_client_token, origin_user_id: "Obi-Wan", user: multiple_projects_user, oauth_client:) - create(:oauth_client_token, origin_user_id: "Yoda", user: single_project_user, oauth_client:) - create(:oauth_client_token, origin_user_id: "Darth Vader", user: admin, oauth_client:) + create(:oauth_client_token, origin_user_id: 'Obi-Wan', user: multiple_projects_user, oauth_client:) + create(:oauth_client_token, origin_user_id: 'Yoda', user: single_project_user, oauth_client:) + create(:oauth_client_token, origin_user_id: 'Darth Vader', user: admin, oauth_client:) setup_request_stubs end - it "sets project folders properties" do + it 'sets project folders properties' do expect(project_storage1.project_folder_id).to be_nil - expect(project_storage2.project_folder_id).to eq("123") + expect(project_storage2.project_folder_id).to eq('123') expect(project_storage3.project_folder_id).to be_nil expect(project_storage1.last_project_folders.pluck(:origin_folder_id)).to eq([nil]) - expect(project_storage2.last_project_folders.pluck(:origin_folder_id)).to eq(["123"]) + expect(project_storage2.last_project_folders.pluck(:origin_folder_id)).to eq(['123']) expect(project_storage3.last_project_folders.pluck(:origin_folder_id)).to eq([nil]) described_class.new(storage).call - expect(project_storage1.reload.project_folder_id).to eq("819") - expect(project_storage2.reload.project_folder_id).to eq("123") - expect(project_storage3.reload.project_folder_id).to eq("2600003") + expect(project_storage1.reload.project_folder_id).to eq('819') + expect(project_storage2.reload.project_folder_id).to eq('123') + expect(project_storage3.reload.project_folder_id).to eq('2600003') - expect(project_storage1.last_project_folders.pluck(:origin_folder_id)).to eq(["819"]) - expect(project_storage2.last_project_folders.pluck(:origin_folder_id)).to eq(["123"]) - expect(project_storage3.last_project_folders.pluck(:origin_folder_id)).to eq(["2600003"]) + expect(project_storage1.last_project_folders.pluck(:origin_folder_id)).to eq(['819']) + expect(project_storage2.last_project_folders.pluck(:origin_folder_id)).to eq(['123']) + expect(project_storage3.last_project_folders.pluck(:origin_folder_id)).to eq(['2600003']) expect(request_stubs).to all have_been_requested end - describe "error handling and flow control" do - context "when getting the root folder properties fail" do - context "on a handled error case" do + describe 'error handling and flow control' do + context 'when getting the root folder properties fail' do + context 'on a handled error case' do before do request_stubs[0] = stub_request(:propfind, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject") .with( body: propfind_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Depth" => "1" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Depth' => '1' } ).to_return(status: 404, body: "", headers: {}) end - it "stops the flow immediately if the response is anything but a success" do + it 'stops the flow immediately if the response is anything but a success' do described_class.new(storage).call request_stubs[1..].each { |request| expect(request).not_to have_been_requested } end - it "logs an error message" do + it 'logs an error message' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call expect(OpenProject.logger) .to have_received(:warn) - .with(folder: "OpenProject", + .with(folder: 'OpenProject', command: Storages::Peripherals::StorageInteraction::Nextcloud::Internal::PropfindQuery, - message: "Outbound request destination not found", - data: { status: 404, body: "" }) + message: 'Outbound request destination not found', + data: { status: 404, body: '' }) end - it "returns a failure" do + it 'returns a failure' do result = described_class.new(storage).call expect(result).to be_failure end end - it "raises an error when dealing with an unhandled error case" do + it 'raises an error when dealing with an unhandled error case' do request_stubs[0] = stub_request(:propfind, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject") .with( body: propfind_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Depth" => "1" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Depth' => '1' } ).to_return(status: 500, body: "", headers: {}) expect(described_class.new(storage).call).to be_failure end - it "raises an error when dealing with a socket or connection error" do + it 'raises an error when dealing with a socket or connection error' do request_stubs[0] = stub_request(:propfind, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject") .with( body: propfind_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Depth" => "1" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Depth' => '1' } ).to_timeout @@ -713,38 +713,38 @@ end end - context "when setting the root folder permissions fail" do - context "on a handled error case" do + context 'when setting the root folder permissions fail' do + context 'on a handled error case' do before do request_stubs[1] = stub_request(:proppatch, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject") .with( body: root_folder_set_permissions_request_body, - headers: { "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" } - ).to_return(status: 401, body: "Heute nicht", headers: {}) + headers: { 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } + ).to_return(status: 401, body: 'Heute nicht', headers: {}) end - it "interrupts the flow" do + it 'interrupts the flow' do described_class.new(storage).call expect(request_stubs[0..1]).to all(have_been_requested) request_stubs[2..].each { |request| expect(request).not_to have_been_requested } end - it "logs an error message" do + it 'logs an error message' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call expect(OpenProject.logger) .to have_received(:warn) - .with(folder: "OpenProject", + .with(folder: 'OpenProject', command: Storages::Peripherals::StorageInteraction::Nextcloud::SetPermissionsCommand, - message: "Outbound request not authorized", - data: { status: 401, body: "Heute nicht" }) + message: 'Outbound request not authorized', + data: { status: 401, body: 'Heute nicht' }) end end end - context "when folder creation fails" do + context 'when folder creation fails' do before do request_stubs[2] = stub_request( :mkcol, @@ -752,12 +752,12 @@ "%5BSample%5D%20Project%20Name%20%7C%20Ehuu%20(#{project1.id})/" ).with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 404, body: "", headers: {}) end - it "continues normally ignoring that folder" do + it 'continues normally ignoring that folder' do expect { described_class.new(storage).call }.not_to change(project_storage1, :project_folder_id) expect(request_stubs.delete_at(5)).not_to have_been_requested @@ -765,7 +765,7 @@ expect(request_stubs).to all(have_been_requested) end - it "logs the occurrence" do + it 'logs the occurrence' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call @@ -773,29 +773,29 @@ .to have_received(:warn) .with(folder: "OpenProject/[Sample] Project Name | Ehuu (#{project1.id})/", command: Storages::Peripherals::StorageInteraction::Nextcloud::CreateFolderCommand, - message: "Outbound request destination not found", - data: { status: 404, body: "" }) + message: 'Outbound request destination not found', + data: { status: 404, body: '' }) end end - context "when renaming a folder fail" do + context 'when renaming a folder fail' do before do request_stubs[4] = stub_request(:move, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject/" \ "Lost%20Jedi%20Project%20Folder%20%233/") .with(headers: - { "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Destination" => "/remote.php/dav/files/OpenProject/OpenProject/" \ + { 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Destination' => "/remote.php/dav/files/OpenProject/OpenProject/" \ "Jedi%20Project%20Folder%20%7C%7C%7C%20%28#{project2.id}%29/" }) .to_return(status: 404, body: "", headers: {}) end - it "we stop processing to avoid issues with permissions" do + it 'we stop processing to avoid issues with permissions' do described_class.new(storage).call request_stubs[5..].each { |request| expect(request).not_to have_been_requested } end - it "logs the occurrence" do + it 'logs the occurrence' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call @@ -804,62 +804,62 @@ .with(source: "OpenProject/Lost Jedi Project Folder #3/", target: project_storage2.managed_project_folder_path, command: Storages::Peripherals::StorageInteraction::Nextcloud::RenameFileCommand, - message: "Outbound request destination not found", - data: { status: 404, body: "" }) + message: 'Outbound request destination not found', + data: { status: 404, body: '' }) end end - context "when hiding a folder fail" do + context 'when hiding a folder fail' do before do request_stubs[6] = stub_request(:proppatch, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject/" \ "Lost%20Jedi%20Project%20Folder%20%232/") .with(body: hide_folder_set_permissions_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' }) - .to_return(status: 500, body: "A server error occurred", headers: {}) + .to_return(status: 500, body: 'A server error occurred', headers: {}) end - it "does not interrupt the flow" do + it 'does not interrupt the flow' do described_class.new(storage).call expect(request_stubs).to all(have_been_requested) end - it "logs the occurrence" do + it 'logs the occurrence' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call expect(OpenProject.logger) .to have_received(:warn) - .with(context: "hide_folder", - folder: "OpenProject/Lost Jedi Project Folder #2/", + .with(context: 'hide_folder', + folder: 'OpenProject/Lost Jedi Project Folder #2/', command: Storages::Peripherals::StorageInteraction::Nextcloud::SetPermissionsCommand, - message: "Outbound request failed", - data: { status: 500, body: "A server error occurred" }) + message: 'Outbound request failed', + data: { status: 500, body: 'A server error occurred' }) end end - context "when setting project folder permissions fail" do + context 'when setting project folder permissions fail' do before do request_stubs[8] = stub_request(:proppatch, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject/" \ "Jedi%20Project%20Folder%20%7C%7C%7C%20%28#{project2.id}%29/") .with(body: set_permissions_request_body, - headers: { "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" }) + headers: { 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' }) .to_return(status: 500, - body: "Divide by cucumber error. Please reinstall universe and reboot.", + body: 'Divide by cucumber error. Please reinstall universe and reboot.', headers: {}) end - it "does not interrupt the flow" do + it 'does not interrupt the flow' do described_class.new(storage).call expect(request_stubs).to all(have_been_requested) end - it "logs the occurrence" do + it 'logs the occurrence' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call @@ -867,44 +867,44 @@ .to have_received(:warn) .with(folder: "OpenProject/Jedi Project Folder ||| (#{project2.id})/", command: Storages::Peripherals::StorageInteraction::Nextcloud::SetPermissionsCommand, - message: "Outbound request failed", - data: { status: 500, body: "Divide by cucumber error. Please reinstall universe and reboot." }) + message: 'Outbound request failed', + data: { status: 500, body: 'Divide by cucumber error. Please reinstall universe and reboot.' }) end end - context "when adding a user to the group fails" do + context 'when adding a user to the group fails' do before do request_stubs[12] = stub_request(:post, "#{storage.host}/ocs/v1.php/cloud/users/Obi-Wan/groups") .with( body: "groupid=OpenProject", headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Ocs-Apirequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Ocs-Apirequest' => 'true' } - ).to_return(status: 302, body: "", headers: {}) + ).to_return(status: 302, body: '', headers: {}) end - it "does not interrupt te flow" do + it 'does not interrupt te flow' do described_class.new(storage).call expect(request_stubs).to all have_been_requested end - it "logs the occurrence" do + it 'logs the occurrence' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call expect(OpenProject.logger) .to have_received(:warn) - .with(group: "OpenProject", - user: "Obi-Wan", + .with(group: 'OpenProject', + user: 'Obi-Wan', command: Storages::Peripherals::StorageInteraction::Nextcloud::AddUserToGroupCommand, - message: "Outbound request failed", - data: { status: 302, body: "" }) + message: 'Outbound request failed', + data: { status: 302, body: '' }) end end - context "when removing a user to the group fails" do + context 'when removing a user to the group fails' do let(:remove_user_from_group_response) do <<~XML @@ -919,23 +919,23 @@ XML end - it "does not interrupt the flow" do + it 'does not interrupt the flow' do described_class.new(storage).call expect(request_stubs).to all have_been_requested end - it "logs the occurrence and continues the flow" do + it 'logs the occurrence and continues the flow' do allow(OpenProject.logger).to receive(:warn) described_class.new(storage).call expect(OpenProject.logger) .to have_received(:warn) - .with(group: "OpenProject", - user: "Darth Maul", + .with(group: 'OpenProject', + user: 'Darth Maul', command: Storages::Peripherals::StorageInteraction::Nextcloud::RemoveUserFromGroupCommand, - message: "Failed to remove user Darth Maul from group OpenProject: " \ - "Not viable to remove user from the last group you are SubAdmin of", + message: 'Failed to remove user Darth Maul from group OpenProject: ' \ + 'Not viable to remove user from the last group you are SubAdmin of', data: { status: 200, body: remove_user_from_group_response }) end end @@ -950,8 +950,8 @@ def setup_request_stubs .with( body: propfind_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Depth" => "1" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Depth' => '1' } ).to_return(status: 207, body: root_folder_propfind_response_body, headers: {}) @@ -960,7 +960,7 @@ def setup_request_stubs .with( body: root_folder_set_permissions_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: root_folder_set_permissions_response_body, headers: {}) @@ -971,7 +971,7 @@ def setup_request_stubs "%5BSample%5D%20Project%20Name%20%7C%20Ehuu%20(#{project1.id})/" ).with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 201, body: "", headers: {}) @@ -983,8 +983,8 @@ def setup_request_stubs ).with( body: propfind_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Depth" => "1" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Depth' => '1' } ).to_return(status: 207, body: created_folder_propfind_response_body, headers: {}) @@ -994,8 +994,8 @@ def setup_request_stubs "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject/Lost%20Jedi%20Project%20Folder%20%233/" ).with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Destination" => "/remote.php/dav/files/OpenProject/OpenProject/" \ + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Destination' => "/remote.php/dav/files/OpenProject/OpenProject/" \ "Jedi%20Project%20Folder%20%7C%7C%7C%20%28#{project2.id}%29/" } ).to_return(status: 201, body: "", headers: {}) @@ -1008,7 +1008,7 @@ def setup_request_stubs ).with( body: created_folder_set_permissions_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: created_folder_set_permissions_response_body, headers: {}) @@ -1019,7 +1019,7 @@ def setup_request_stubs ).with( body: hide_folder_set_permissions_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: hide_folder_set_permissions_response_body, headers: {}) @@ -1030,7 +1030,7 @@ def setup_request_stubs ).with( body: set_permissions_request_body5, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: set_permissions_response_body5, headers: {}) @@ -1042,7 +1042,7 @@ def setup_request_stubs ).with( body: set_permissions_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: set_permissions_response_body, headers: {}) @@ -1053,7 +1053,7 @@ def setup_request_stubs ).with( body: set_permissions_request_body6, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: set_permissions_response_body6, headers: {}) @@ -1063,7 +1063,7 @@ def setup_request_stubs ).with( body: set_permissions_request_body, headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 207, body: set_permissions_response_body7, headers: {}) @@ -1071,8 +1071,8 @@ def setup_request_stubs request_stubs << stub_request(:get, "#{storage.host}/ocs/v1.php/cloud/groups/#{storage.group}") .with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "OCS-APIRequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'OCS-APIRequest' => 'true' } ).to_return(status: 200, body: group_users_response_body, headers: {}) @@ -1081,8 +1081,8 @@ def setup_request_stubs .with( body: "groupid=OpenProject", headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Ocs-Apirequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Ocs-Apirequest' => 'true' } ).to_return(status: 200, body: add_user_to_group_response_body, headers: {}) @@ -1090,8 +1090,8 @@ def setup_request_stubs .with( body: "groupid=OpenProject", headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Ocs-Apirequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Ocs-Apirequest' => 'true' } ).to_return(status: 200, body: add_user_to_group_response_body, headers: {}) @@ -1099,8 +1099,8 @@ def setup_request_stubs .with( body: "groupid=OpenProject", headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Ocs-Apirequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Ocs-Apirequest' => 'true' } ).to_return(status: 200, body: add_user_to_group_response_body, headers: {}) @@ -1110,8 +1110,8 @@ def setup_request_stubs "#{storage.host}/ocs/v1.php/cloud/users/Darth%20Maul/groups?groupid=OpenProject" ).with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=", - "Ocs-Apirequest" => "true" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=', + 'Ocs-Apirequest' => 'true' } ).to_return(status: 200, body: remove_user_from_group_response, headers: {}) @@ -1121,7 +1121,7 @@ def setup_request_stubs "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject/Project3%20(#{project3.id})/" ).with( headers: { - "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" + 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' } ).to_return(status: 405, body: <<~XML, headers: {}) @@ -1136,7 +1136,7 @@ def setup_request_stubs :propfind, "#{storage.host}/remote.php/dav/files/OpenProject/OpenProject/Project3%20(#{project3.id})/" ).with( - headers: { "Authorization" => "Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=" }, + headers: { 'Authorization' => 'Basic T3BlblByb2plY3Q6MTIzNDU2Nzg=' }, body: propfind_request_body ).to_return(status: 200, body: propfind_response_body3, headers: {}) end diff --git a/modules/storages/spec/services/storages/oauth_applications/create_service_spec.rb b/modules/storages/spec/services/storages/oauth_applications/create_service_spec.rb index 061680296ceb..fb3393aa31a5 100644 --- a/modules/storages/spec/services/storages/oauth_applications/create_service_spec.rb +++ b/modules/storages/spec/services/storages/oauth_applications/create_service_spec.rb @@ -28,20 +28,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_create_service" +require 'services/base_services/behaves_like_create_service' RSpec.describe Storages::OAuthApplications::CreateService, type: :model do let(:user) { create(:admin) } let(:storage) { create(:nextcloud_storage, creator: user) } let(:instance) { described_class.new(user:, storage:) } - describe "#call" do + describe '#call' do subject { instance.call } - it "returns a OAuthApplication" do + it 'returns a OAuthApplication' do expect(subject).to be_a ServiceResult expect(subject).to be_success expect(subject.result).to be_a Doorkeeper::Application @@ -49,7 +49,7 @@ expect(subject.result.name).to include I18n.t("storages.provider_types.#{storage.short_provider_type}.name") expect(subject.result.scopes.to_s).to eql "api_v3" expect(subject.result.redirect_uri).to include storage.host - expect(subject.result.redirect_uri).to include "apps/integration_openproject/oauth-redirect" + expect(subject.result.redirect_uri).to include 'apps/integration_openproject/oauth-redirect' expect(subject.result.integration).to eql storage expect(subject.result.confidential).to be_truthy expect(subject.result.owner).to eql user diff --git a/modules/storages/spec/services/storages/one_drive_managed_folder_sync_service_spec.rb b/modules/storages/spec/services/storages/one_drive_managed_folder_sync_service_spec.rb index de0d3ffcd495..d186e321c838 100644 --- a/modules/storages/spec/services/storages/one_drive_managed_folder_sync_service_spec.rb +++ b/modules/storages/spec/services/storages/one_drive_managed_folder_sync_service_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec::Matchers.define_negated_matcher :not_change, :change @@ -39,7 +39,7 @@ shared_let(:storage) do # Automatically Managed Project Folder Drive create(:sharepoint_dev_drive_storage, - drive_id: "b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy", + drive_id: 'b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2ODRDvn3haLiQIhB5UYNdqMy', oauth_client_token_user: admin) end @@ -49,7 +49,7 @@ create(:oauth_client_token, user: single_project_user, oauth_client: storage.oauth_client, - origin_user_id: "2ff33b8f-2843-40c1-9a17-d786bca17fba") + origin_user_id: '2ff33b8f-2843-40c1-9a17-d786bca17fba') end shared_let(:multiple_projects_user) { create(:user) } @@ -57,7 +57,7 @@ create(:oauth_client_token, user: multiple_projects_user, oauth_client: storage.oauth_client, - origin_user_id: "248aeb72-b231-4e71-a466-67fa7df2a285") + origin_user_id: '248aeb72-b231-4e71-a466-67fa7df2a285') end # ROLE FACTORIES @@ -68,37 +68,37 @@ # PROJECT FACTORIES shared_let(:project) do create(:project, - name: "[Sample] Project Name / Ehuu", + name: '[Sample] Project Name / Ehuu', members: { multiple_projects_user => ordinary_role, single_project_user => ordinary_role }) end shared_let(:project_storage) do - create(:project_storage, :with_historical_data, project_folder_mode: "automatic", storage:, project:) + create(:project_storage, :with_historical_data, project_folder_mode: 'automatic', storage:, project:) end shared_let(:disallowed_chars_project) do create(:project, name: '<=o=> | "Jedi" Project Folder ///', members: { multiple_projects_user => ordinary_role }) end shared_let(:disallowed_chars_project_storage) do - create(:project_storage, :with_historical_data, project_folder_mode: "automatic", project: disallowed_chars_project, storage:) + create(:project_storage, :with_historical_data, project_folder_mode: 'automatic', project: disallowed_chars_project, storage:) end shared_let(:inactive_project) do - create(:project, name: "INACTIVE PROJECT! f0r r34lz", active: false, members: { multiple_projects_user => ordinary_role }) + create(:project, name: 'INACTIVE PROJECT! f0r r34lz', active: false, members: { multiple_projects_user => ordinary_role }) end shared_let(:inactive_project_storage) do - create(:project_storage, :with_historical_data, project_folder_mode: "automatic", project: inactive_project, storage:) + create(:project_storage, :with_historical_data, project_folder_mode: 'automatic', project: inactive_project, storage:) end - shared_let(:public_project) { create(:public_project, name: "PUBLIC PROJECT", active: true) } + shared_let(:public_project) { create(:public_project, name: 'PUBLIC PROJECT', active: true) } shared_let(:public_project_storage) do - create(:project_storage, :with_historical_data, project_folder_mode: "automatic", project: public_project, storage:) + create(:project_storage, :with_historical_data, project_folder_mode: 'automatic', project: public_project, storage:) end shared_let(:unmanaged_project) do - create(:project, name: "Non Managed Project", active: true, members: { multiple_projects_user => ordinary_role }) + create(:project, name: 'Non Managed Project', active: true, members: { multiple_projects_user => ordinary_role }) end shared_let(:unmanaged_project_storage) do - create(:project_storage, :with_historical_data, project_folder_mode: "manual", project: unmanaged_project, storage:) + create(:project_storage, :with_historical_data, project_folder_mode: 'manual', project: unmanaged_project, storage:) end # This is a remote service call. We need to enable WebMock and VCR in order to record it, @@ -106,7 +106,7 @@ # Then we disable both VCR and WebMock to return to the usual state shared_let(:original_folder_ids) do WebMock.enable! && VCR.turn_on! - VCR.use_cassette("one_drive/sync_service_original_folders") do + VCR.use_cassette('one_drive/sync_service_original_folders') do original_folders(storage) end ensure @@ -115,23 +115,23 @@ subject(:service) { described_class.new(storage) } - it "responds to .call" do + it 'responds to .call' do method = described_class.method(:call) expect(method.parameters).to contain_exactly(%i[req storage]) end - it "return if the storage is not automatically managed" do + it 'return if the storage is not automatically managed' do expect(described_class.call(storage)).to be_falsey end - describe "#call" do + describe '#call' do before { storage.update(automatically_managed: true) } after { delete_created_folders } - context "when successful" do - it "updates the project folder id for all active automatically managed projects", - vcr: "one_drive/sync_service_create_folder" do + context 'when successful' do + it 'updates the project folder id for all active automatically managed projects', + vcr: 'one_drive/sync_service_create_folder' do expect { service.call }.to change { disallowed_chars_project_storage.reload.project_folder_id } .from(nil).to(String) .and(change { project_storage.reload.project_folder_id }.from(nil).to(String)) @@ -140,8 +140,8 @@ .and(not_change { unmanaged_project_storage.reload.project_folder_id }) end - it "adds a record to the LastProjectFolder for each new folder", - vcr: "one_drive/sync_service_create_folder" do + it 'adds a record to the LastProjectFolder for each new folder', + vcr: 'one_drive/sync_service_create_folder' do scope = ->(project_storage) { Storages::LastProjectFolder.where(project_storage:).last } expect { service.call }.to not_change { scope[unmanaged_project_storage].reload.origin_folder_id } @@ -153,8 +153,8 @@ .to eq(disallowed_chars_project_storage.reload.project_folder_id) end - it "creates the remote folders for all projects with automatically managed folders enabled", - vcr: "one_drive/sync_service_create_folder" do + it 'creates the remote folders for all projects with automatically managed folders enabled', + vcr: 'one_drive/sync_service_create_folder' do service.call [project_storage, disallowed_chars_project_storage, public_project_storage].each do |proj_storage| @@ -162,8 +162,8 @@ end end - it "makes sure that the last_project_folder.origin_folder_id match the current project_folder_id", - vcr: "one_drive/sync_service_create_folder" do + it 'makes sure that the last_project_folder.origin_folder_id match the current project_folder_id', + vcr: 'one_drive/sync_service_create_folder' do service.call [project_storage, disallowed_chars_project_storage, public_project_storage].each do |proj_storage| @@ -175,7 +175,7 @@ end end - it "renames an already existing project folder", vcr: "one_drive/sync_service_rename_folder" do + it 'renames an already existing project folder', vcr: 'one_drive/sync_service_rename_folder' do original_folder = create_folder_for(disallowed_chars_project_storage, "Old Jedi Project") disallowed_chars_project_storage.update(project_folder_id: original_folder.result.id) @@ -186,16 +186,16 @@ expect(result[:name]).to match(/_=o=_ _ _Jedi_ Project Folder ___ \(\d+\)/) end - it "hides (removes all permissions) from inactive project folders", vcr: "one_drive/sync_service_hide_inactive" do + it 'hides (removes all permissions) from inactive project folders', vcr: 'one_drive/sync_service_hide_inactive' do original_folder = create_folder_for(inactive_project_storage) inactive_project_storage.update(project_folder_id: original_folder.result.id) set_permissions_on(original_folder.result.id, - { read: ["2ff33b8f-2843-40c1-9a17-d786bca17fba"], + { read: ['2ff33b8f-2843-40c1-9a17-d786bca17fba'], write: %w[33db2c84-275d-46af-afb0-c26eb786b194 248aeb72-b231-4e71-a466-67fa7df2a285] }) expect(permissions_for(inactive_project_storage)) - .to eq({ read: ["2ff33b8f-2843-40c1-9a17-d786bca17fba"], + .to eq({ read: ['2ff33b8f-2843-40c1-9a17-d786bca17fba'], write: %w[248aeb72-b231-4e71-a466-67fa7df2a285 33db2c84-275d-46af-afb0-c26eb786b194] }) service.call @@ -203,7 +203,7 @@ expect(permissions_for(inactive_project_storage)).to be_empty end - it "adds already logged in users to the project folder", vcr: "one_drive/sync_service_set_permissions" do + it 'adds already logged in users to the project folder', vcr: 'one_drive/sync_service_set_permissions' do original_folder = create_folder_for(inactive_project_storage) inactive_project_storage.update(project_folder_id: original_folder.result.id) @@ -220,20 +220,20 @@ expect(permissions_for(inactive_project_storage)).to be_empty end - it "if the project is public allows any logged in user to read the files", - vcr: "one_drive/sync_service_public_project" do + it 'if the project is public allows any logged in user to read the files', + vcr: 'one_drive/sync_service_public_project' do service.call expect(permissions_for(public_project_storage)) .to eq({ read: %w[248aeb72-b231-4e71-a466-67fa7df2a285 2ff33b8f-2843-40c1-9a17-d786bca17fba], - write: ["33db2c84-275d-46af-afb0-c26eb786b194"] }) + write: ['33db2c84-275d-46af-afb0-c26eb786b194'] }) end - it "ensures that admins have full access to all folders", vcr: "one_drive/sync_service_admin_access" do + it 'ensures that admins have full access to all folders', vcr: 'one_drive/sync_service_admin_access' do service.call [project_storage, disallowed_chars_project_storage, public_project_storage].each do |ps| - expect(permissions_for(ps)[:write]).to include("33db2c84-275d-46af-afb0-c26eb786b194") + expect(permissions_for(ps)[:write]).to include('33db2c84-275d-46af-afb0-c26eb786b194') end end @@ -241,13 +241,13 @@ before { allow(OpenProject.logger).to receive(:warn) } context "when reading the root folder fails" do - it "returns a failure in case retrieving the root list fails", vcr: "one_drive/sync_service_root_read_failure" do - storage.update(drive_id: "THIS-IS-NOT-A-DRIVE-ID") + it 'returns a failure in case retrieving the root list fails', vcr: 'one_drive/sync_service_root_read_failure' do + storage.update(drive_id: 'THIS-IS-NOT-A-DRIVE-ID') expect(service.call).to be_failure end - it "logs the occurrence", vcr: "one_drive/sync_service_root_read_failure" do - storage.update(drive_id: "THIS-IS-NOT-A-DRIVE-ID") + it 'logs the occurrence', vcr: 'one_drive/sync_service_root_read_failure' do + storage.update(drive_id: 'THIS-IS-NOT-A-DRIVE-ID') service.call expect(OpenProject.logger) @@ -258,8 +258,8 @@ end end - context "when folder creation fails" do - it "doesn't update the project_storage", vcr: "one_drive/sync_service_creation_fail" do + context 'when folder creation fails' do + it "doesn't update the project_storage", vcr: 'one_drive/sync_service_creation_fail' do already_existing_folder = create_folder_for(project_storage).result expect { service.call }.not_to change(project_storage, :project_folder_id) @@ -267,7 +267,7 @@ delete_folder(already_existing_folder.id) end - it "logs the occurrence", vcr: "one_drive/sync_service_creation_fail" do + it 'logs the occurrence', vcr: 'one_drive/sync_service_creation_fail' do already_existing_folder = create_folder_for(project_storage).result service.call @@ -282,8 +282,8 @@ end end - context "when folder renaming fails" do - it "logs the occurrence", vcr: "one_drive/sync_service_rename_failed" do + context 'when folder renaming fails' do + it 'logs the occurrence', vcr: 'one_drive/sync_service_rename_failed' do already_existing_folder = create_folder_for(project_storage) original_folder = create_folder_for(project_storage, "Flawless Death Star Blueprints") project_storage.update(project_folder_id: original_folder.result.id) @@ -302,9 +302,9 @@ end end - context "when setting permission fails" do - it "logs the occurrence", vcr: "one_drive/sync_service_fail_add_user" do - single_project_user_token.update(origin_user_id: "my_name_is_mud") + context 'when setting permission fails' do + it 'logs the occurrence', vcr: 'one_drive/sync_service_fail_add_user' do + single_project_user_token.update(origin_user_id: 'my_name_is_mud') service.call expect(OpenProject.logger) @@ -325,7 +325,7 @@ def permissions_for(project_storage) Storages::Peripherals::StorageInteraction::OneDrive::Util.using_admin_token(storage) do |http| response = http.get("/v1.0/drives/#{storage.drive_id}/items/#{project_storage.project_folder_id}/permissions") response.json(symbolize_keys: true).fetch(:value, []).each_with_object({}) do |grant, hash| - next if grant[:roles].member?("owner") + next if grant[:roles].member?('owner') hash[grant[:roles].first.to_sym] ||= [] hash[grant[:roles].first.to_sym] << grant.dig(:grantedToV2, :user, :id) @@ -360,12 +360,12 @@ def project_folder_info(project_storage) def create_folder_for(project_storage, folder_override = nil) folder_path = folder_override || project_storage.managed_project_folder_path - Storages::Peripherals::Registry.resolve("one_drive.commands.create_folder") + Storages::Peripherals::Registry.resolve('one_drive.commands.create_folder') .call(storage: project_storage.storage, folder_path:) end def set_permissions_on(item_id, permissions) - Storages::Peripherals::Registry.resolve("one_drive.commands.set_permissions") + Storages::Peripherals::Registry.resolve('one_drive.commands.set_permissions') .call(storage:, path: item_id, permissions:) end @@ -377,6 +377,6 @@ def delete_created_folders end def delete_folder(item_id) - Storages::Peripherals::Registry.resolve("one_drive.commands.delete_folder").call(storage:, location: item_id) + Storages::Peripherals::Registry.resolve('one_drive.commands.delete_folder').call(storage:, location: item_id) end end diff --git a/modules/storages/spec/services/storages/project_storages/create_service_spec.rb b/modules/storages/spec/services/storages/project_storages/create_service_spec.rb index 5f360213b71e..bf555fb9ec19 100644 --- a/modules/storages/spec/services/storages/project_storages/create_service_spec.rb +++ b/modules/storages/spec/services/storages/project_storages/create_service_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_create_service" -require_relative "shared_event_gun_examples" +require 'services/base_services/behaves_like_create_service' +require_relative 'shared_event_gun_examples' RSpec.describe Storages::ProjectStorages::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:factory) { :project_storage } - it_behaves_like("an event gun", OpenProject::Events::PROJECT_STORAGE_CREATED) + it_behaves_like('an event gun', OpenProject::Events::PROJECT_STORAGE_CREATED) end end diff --git a/modules/storages/spec/services/storages/project_storages/delete_service_spec.rb b/modules/storages/spec/services/storages/project_storages/delete_service_spec.rb index 00b9572f9353..bbd2f192a260 100644 --- a/modules/storages/spec/services/storages/project_storages/delete_service_spec.rb +++ b/modules/storages/spec/services/storages/project_storages/delete_service_spec.rb @@ -28,54 +28,54 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_delete_service" -require_relative "shared_event_gun_examples" +require 'services/base_services/behaves_like_delete_service' +require_relative 'shared_event_gun_examples' RSpec.describe Storages::ProjectStorages::DeleteService, :webmock, type: :model do - shared_examples_for "deleting project storages with project folders" do + shared_examples_for 'deleting project storages with project folders' do let(:delete_folder_stub) do stub_request(:delete, delete_folder_url).to_return(status: 204, body: nil, headers: {}) end before { delete_folder_stub } - context "if project folder mode is set to automatic" do + context 'if project folder mode is set to automatic' do let(:project_storage) do - create(:project_storage, project:, storage:, project_folder_id: "1337", project_folder_mode: "automatic") + create(:project_storage, project:, storage:, project_folder_id: '1337', project_folder_mode: 'automatic') end - it "tries to remove the project folder at the remote storage" do + it 'tries to remove the project folder at the remote storage' do expect(described_class.new(model: project_storage, user:).call).to be_success expect(delete_folder_stub).to have_been_requested end - context "if project folder deletion request fails" do + context 'if project folder deletion request fails' do let(:delete_folder_stub) do stub_request(:delete, delete_folder_url).to_return(status: 404, body: nil, headers: {}) end - it "tries to remove the project folder at the remote storage and still succeed with deletion" do + it 'tries to remove the project folder at the remote storage and still succeed with deletion' do expect(described_class.new(model: project_storage, user:).call).to be_success expect(delete_folder_stub).to have_been_requested end end end - context "if project folder mode is set to manual" do + context 'if project folder mode is set to manual' do let(:project_storage) do - create(:project_storage, project:, storage:, project_folder_id: "1337", project_folder_mode: "manual") + create(:project_storage, project:, storage:, project_folder_id: '1337', project_folder_mode: 'manual') end - it "must not try to delete manual project folders" do + it 'must not try to delete manual project folders' do expect(described_class.new(model: project_storage, user:).call).to be_success expect(delete_folder_stub).not_to have_been_requested end end end - context "with records written to DB" do + context 'with records written to DB' do let(:user) { create(:user) } let(:role) { create(:project_role, permissions: [:manage_storages_in_project]) } let(:project) { create(:project, members: { user => role }) } @@ -87,14 +87,14 @@ let(:file_link) { create(:file_link, container: work_package, storage:) } let(:other_file_link) { create(:file_link, container: other_work_package, storage:) } - it "destroys the record" do + it 'destroys the record' do project_storage described_class.new(model: project_storage, user:).call expect(Storages::ProjectStorage.where(id: project_storage.id)).not_to exist end - it "deletes all FileLinks that belong to containers of the related project" do + it 'deletes all FileLinks that belong to containers of the related project' do file_link other_file_link @@ -104,15 +104,15 @@ expect(Storages::FileLink.where(id: other_file_link.id)).to exist end - context "with Nextcloud storage" do + context 'with Nextcloud storage' do let(:delete_folder_url) do "#{storage.host}/remote.php/dav/files/#{storage.username}/#{project_storage.project_folder_location}" end - it_behaves_like "deleting project storages with project folders" + it_behaves_like 'deleting project storages with project folders' end - context "with OneDrive storage" do + context 'with OneDrive storage' do let(:storage) { create(:one_drive_storage) } let(:delete_folder_url) do "https://graph.microsoft.com/v1.0/drives/#{storage.drive_id}/items/#{project_storage.project_folder_location}" @@ -124,11 +124,11 @@ .and_yield(HTTPX.with(origin: storage.uri)) end - it_behaves_like "deleting project storages with project folders" + it_behaves_like 'deleting project storages with project folders' end end - it_behaves_like "BaseServices delete service" do + it_behaves_like 'BaseServices delete service' do let(:factory) { :project_storage } let(:host) { model_instance.storage.host } let(:username) { model_instance.storage.username } @@ -141,6 +141,6 @@ stub_request(:delete, delete_folder_url).to_return(status: 204, body: nil, headers: {}) end - it_behaves_like("an event gun", OpenProject::Events::PROJECT_STORAGE_DESTROYED) + it_behaves_like('an event gun', OpenProject::Events::PROJECT_STORAGE_DESTROYED) end end diff --git a/modules/storages/spec/services/storages/project_storages/set_attributes_service_spec.rb b/modules/storages/spec/services/storages/project_storages/set_attributes_service_spec.rb index 2bc58c3d43a2..03da16866a83 100644 --- a/modules/storages/spec/services/storages/project_storages/set_attributes_service_spec.rb +++ b/modules/storages/spec/services/storages/project_storages/set_attributes_service_spec.rb @@ -28,20 +28,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::ProjectStorages::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:admin) } let(:contract_instance) do - contract = instance_double(Storages::ProjectStorages::BaseContract, "contract_instance") + contract = instance_double(Storages::ProjectStorages::BaseContract, 'contract_instance') allow(contract) .to receive_messages(validate: contract_valid, errors: contract_errors) contract end - let(:contract_errors) { instance_double(ActiveModel::Errors, "contract_errors") } + let(:contract_errors) { instance_double(ActiveModel::Errors, 'contract_errors') } let(:contract_valid) { true } let(:model_valid) { true } @@ -70,34 +70,34 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result) .to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with new record" do - it "sets creator to current user" do + context 'with new record' do + it 'sets creator to current user' do expect(subject.result.creator).to eq current_user end end - context "with existing record" do + context 'with existing record' do let(:model_instance) { build_stubbed(:project_storage, creator: build_stubbed(:user)) } - it "keeps its creator" do + it 'keeps its creator' do expect(subject.result.creator).not_to eq current_user end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } - it "returns failure" do + it 'returns failure' do expect(subject).not_to be_success end diff --git a/modules/storages/spec/services/storages/project_storages/shared_event_gun_examples.rb b/modules/storages/spec/services/storages/project_storages/shared_event_gun_examples.rb index 7039fbf212ac..9386eb5326e1 100644 --- a/modules/storages/spec/services/storages/project_storages/shared_event_gun_examples.rb +++ b/modules/storages/spec/services/storages/project_storages/shared_event_gun_examples.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -RSpec.shared_examples "an event gun" do |event| +RSpec.shared_examples 'an event gun' do |event| %i[automatic manual inactive].each do |mode| context "when project_folder mode is #{mode}" do - it "fires an appropriate event" do + it 'fires an appropriate event' do allow(OpenProject::Notifications).to(receive(:send)) model_instance.project_folder_mode = mode diff --git a/modules/storages/spec/services/storages/project_storages/update_service_spec.rb b/modules/storages/spec/services/storages/project_storages/update_service_spec.rb index 26fa762f5792..b65fc29bd06f 100644 --- a/modules/storages/spec/services/storages/project_storages/update_service_spec.rb +++ b/modules/storages/spec/services/storages/project_storages/update_service_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_update_service" -require_relative "shared_event_gun_examples" +require 'services/base_services/behaves_like_update_service' +require_relative 'shared_event_gun_examples' RSpec.describe Storages::ProjectStorages::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:factory) { :project_storage } - it_behaves_like("an event gun", OpenProject::Events::PROJECT_STORAGE_UPDATED) + it_behaves_like('an event gun', OpenProject::Events::PROJECT_STORAGE_UPDATED) end end diff --git a/modules/storages/spec/services/storages/storages/create_service_spec.rb b/modules/storages/spec/services/storages/storages/create_service_spec.rb index 353b72ff5b24..f7edfcc03fa4 100644 --- a/modules/storages/spec/services/storages/storages/create_service_spec.rb +++ b/modules/storages/spec/services/storages/storages/create_service_spec.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_create_service" +require 'services/base_services/behaves_like_create_service' RSpec.describe Storages::Storages::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:factory) { :storage } let!(:user) { create(:admin) } @@ -46,9 +46,9 @@ let(:call_attributes) do { - name: "My storage", - host: "https://example.org", - provider_type: "Storages::NextcloudStorage" + name: 'My storage', + host: 'https://example.org', + provider_type: 'Storages::NextcloudStorage' } end diff --git a/modules/storages/spec/services/storages/storages/delete_service_spec.rb b/modules/storages/spec/services/storages/storages/delete_service_spec.rb index 387f40875254..9bc95f258a4a 100644 --- a/modules/storages/spec/services/storages/storages/delete_service_spec.rb +++ b/modules/storages/spec/services/storages/storages/delete_service_spec.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_delete_service" +require 'services/base_services/behaves_like_delete_service' RSpec.describe Storages::Storages::DeleteService, type: :model do - it_behaves_like "BaseServices delete service" do + it_behaves_like 'BaseServices delete service' do let(:factory) { :storage } end end diff --git a/modules/storages/spec/services/storages/storages/set_attributes_service_spec.rb b/modules/storages/spec/services/storages/storages/set_attributes_service_spec.rb index e5fe1297283c..1e36ddeeaa35 100644 --- a/modules/storages/spec/services/storages/storages/set_attributes_service_spec.rb +++ b/modules/storages/spec/services/storages/storages/set_attributes_service_spec.rb @@ -28,19 +28,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Storages::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:admin) } let(:contract_instance) do - contract = instance_double(Storages::Storages::CreateContract, "contract_instance") + contract = instance_double(Storages::Storages::CreateContract, 'contract_instance') allow(contract).to receive_messages(validate: contract_valid, errors: contract_errors) contract end - let(:contract_errors) { instance_double(ActiveModel::Errors, "contract_errors") } + let(:contract_errors) { instance_double(ActiveModel::Errors, 'contract_errors') } let(:contract_valid) { true } let(:model_valid) { true } @@ -69,53 +69,53 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result) .to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with new record" do - it "sets creator to current user" do + context 'with new record' do + it 'sets creator to current user' do expect(subject.result.creator).to eq current_user end - it "sets provider_type to nextcloud" do + it 'sets provider_type to nextcloud' do expect(subject.result.provider_type).to eq Storages::Storage::PROVIDER_TYPE_NEXTCLOUD end - context "when setting host" do + context 'when setting host' do before do params[:host] = "https://some.host.com//" end - it "removes trailing slashes from host" do + it 'removes trailing slashes from host' do expect(subject.result.host).to eq("https://some.host.com") end end end - context "with existing record" do - let(:model_instance) { build_stubbed(:nextcloud_storage, name: "My Storage", creator: build_stubbed(:user)) } + context 'with existing record' do + let(:model_instance) { build_stubbed(:nextcloud_storage, name: 'My Storage', creator: build_stubbed(:user)) } - it "keeps its name" do - expect(subject.result.name).to eq "My Storage" + it 'keeps its name' do + expect(subject.result.name).to eq 'My Storage' end - it "keeps its creator" do + it 'keeps its creator' do expect(subject.result.creator).not_to eq current_user end end - context "with params" do + context 'with params' do let(:params) do { - name: "Foobar", - provider_type: "foo provider" + name: 'Foobar', + provider_type: 'foo provider' } end @@ -123,16 +123,16 @@ subject end - it "assigns the params" do - expect(model_instance.name).to eq "Foobar" - expect(model_instance.provider_type).to eq "foo provider" + it 'assigns the params' do + expect(model_instance.name).to eq 'Foobar' + expect(model_instance.provider_type).to eq 'foo provider' end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } - it "returns failure" do + it 'returns failure' do expect(subject).not_to be_success end @@ -142,10 +142,10 @@ end end - describe "automatically managed project folders" do + describe 'automatically managed project folders' do let(:model_instance) { build_stubbed(:nextcloud_storage) } - context "with password" do + context 'with password' do let(:params) do super().merge( "automatically_managed" => true, @@ -153,33 +153,33 @@ ) end - it "enables automatic folder management with password" do - expect(subject.result).to have_attributes(automatically_managed: true, username: "OpenProject", - password: "secret") + it 'enables automatic folder management with password' do + expect(subject.result).to have_attributes(automatically_managed: true, username: 'OpenProject', + password: 'secret') end end - context "with automatically_managed false" do + context 'with automatically_managed false' do let(:params) do super().merge( "automatically_managed" => false ) end - it "disables automatic folder management" do + it 'disables automatic folder management' do expect(subject.result).to have_attributes(automatically_managed: false) expect(subject.result.attributes.keys).not_to include(:username, :password) end end - context "with automatically_managed nil" do + context 'with automatically_managed nil' do let(:params) do super().merge( "automatically_managed" => nil ) end - it "does not change the value" do + it 'does not change the value' do expect(subject.result).to have_attributes(automatically_managed: nil) expect(subject.result.attributes.keys).not_to include(:username, :password) end diff --git a/modules/storages/spec/services/storages/storages/set_provider_fields_attributes_service_spec.rb b/modules/storages/spec/services/storages/storages/set_provider_fields_attributes_service_spec.rb index dabd89e4bff6..94ee6d974605 100644 --- a/modules/storages/spec/services/storages/storages/set_provider_fields_attributes_service_spec.rb +++ b/modules/storages/spec/services/storages/storages/set_provider_fields_attributes_service_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::Storages::SetProviderFieldsAttributesService, type: :model do @@ -42,59 +42,59 @@ before { allow(storage).to receive(:valid?).and_return(true) } - context "when automatically_managed is not set" do + context 'when automatically_managed is not set' do let(:storage) { build(:nextcloud_storage, provider_fields: {}) } - it "sets automatically_managed to true" do + it 'sets automatically_managed to true' do expect { provider_fields_attributes_service } - .to change(storage, :provider_fields).from({}).to({ "automatically_managed" => true }) + .to change(storage, :provider_fields).from({}).to({ 'automatically_managed' => true }) - aggregate_failures "returns the storage model object as the result" do + aggregate_failures 'returns the storage model object as the result' do expect(provider_fields_attributes_service.result).to eq(storage) end - aggregate_failures "is valid contract" do + aggregate_failures 'is valid contract' do expect(provider_fields_attributes_service).to be_a_success end end end - context "when automatically_managed is already set as true" do + context 'when automatically_managed is already set as true' do let(:storage) { build(:nextcloud_storage, :as_automatically_managed) } - it "retains the set value, does not change the object" do + it 'retains the set value, does not change the object' do expect { provider_fields_attributes_service }.not_to change(storage, :provider_fields) expect(provider_fields_attributes_service.result.automatically_managed).to be(true) - aggregate_failures "returns the storage model object as the result" do + aggregate_failures 'returns the storage model object as the result' do expect(provider_fields_attributes_service.result).to eq(storage) end - aggregate_failures "is valid contract" do + aggregate_failures 'is valid contract' do expect(provider_fields_attributes_service).to be_a_success end end end - context "when automatically_managed is set as false" do + context 'when automatically_managed is set as false' do let(:storage) { build(:nextcloud_storage, :as_not_automatically_managed) } - it "retains the set value, does not change the object" do + it 'retains the set value, does not change the object' do expect { provider_fields_attributes_service }.not_to change(storage, :provider_fields) expect(provider_fields_attributes_service.result.automatically_managed).to be(false) - aggregate_failures "returns the storage model object as the result" do + aggregate_failures 'returns the storage model object as the result' do expect(provider_fields_attributes_service.result).to eq(storage) end - aggregate_failures "is valid contract" do + aggregate_failures 'is valid contract' do expect(provider_fields_attributes_service).to be_a_success end end end def stub_valid_contract(contract_class) - contract_errors = instance_double(ActiveModel::Errors, "contract_errors") + contract_errors = instance_double(ActiveModel::Errors, 'contract_errors') contract_valid = true contract_instance = stub_contract_instance(contract_class, contract_valid, contract_errors) allow(contract_class).to receive(:new).and_return(contract_instance) @@ -103,7 +103,7 @@ def stub_valid_contract(contract_class) end def stub_contract_instance(contract_class, contract_valid, contract_errors) - contract_instance = instance_double(contract_class, "contract_instance") + contract_instance = instance_double(contract_class, 'contract_instance') allow(contract_instance).to receive_messages(validate: contract_valid, errors: contract_errors) contract_instance end diff --git a/modules/storages/spec/services/storages/storages/update_service_spec.rb b/modules/storages/spec/services/storages/storages/update_service_spec.rb index 9982c41ec300..3ecfb18d2f2b 100644 --- a/modules/storages/spec/services/storages/storages/update_service_spec.rb +++ b/modules/storages/spec/services/storages/storages/update_service_spec.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "services/base_services/behaves_like_update_service" +require 'services/base_services/behaves_like_update_service' RSpec.describe Storages::Storages::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:factory) { :nextcloud_storage } let!(:user) { create(:admin) } @@ -46,16 +46,16 @@ let(:call_attributes) do { - name: "My updated storage", - host: "https://new.example.org" + name: 'My updated storage', + host: 'https://new.example.org' } end let!(:model_instance) do build_stubbed(factory, creator: user, - name: "My updated storage", - host: "https://updated.example.org") + name: 'My updated storage', + host: 'https://updated.example.org') end let!(:oauth_application) { create(:oauth_application, integration: model_instance) } @@ -63,12 +63,12 @@ it "creates an OAuth application (::Doorkeeper::Application)" do expect(subject).to be_success expect(subject.result.oauth_application).to be_a(Doorkeeper::Application) - expect(subject.result.oauth_application.name).to include "My updated storage" - expect(subject.result.oauth_application.redirect_uri).to include "https://updated.example.org" + expect(subject.result.oauth_application.name).to include 'My updated storage' + expect(subject.result.oauth_application.redirect_uri).to include 'https://updated.example.org' end end - it "cannot update storage creator" do + it 'cannot update storage creator' do storage_creator = create(:admin, login: "storage_creator") storage = create(:nextcloud_storage, creator: storage_creator) service = described_class.new(user: create(:admin), @@ -81,11 +81,11 @@ expect(storage.reload.creator).to eq(storage_creator) end - describe "updates the nested OAuth application" do + describe 'updates the nested OAuth application' do let(:storage) { create(:nextcloud_storage) } let!(:oauth_application) { create(:oauth_application, integration: storage) } let(:user) { create(:admin) } - let(:name) { "Awesome Storage" } + let(:name) { 'Awesome Storage' } subject do described_class @@ -93,7 +93,7 @@ .call({ name: }) end - it "must update the name of the OAuth application" do + it 'must update the name of the OAuth application' do expect(subject.result.oauth_application.name).to eq("Awesome Storage (Nextcloud)") end end diff --git a/modules/storages/spec/spec_helper.rb b/modules/storages/spec/spec_helper.rb index 73dc77606672..dea4304f0878 100644 --- a/modules/storages/spec/spec_helper.rb +++ b/modules/storages/spec/spec_helper.rb @@ -33,22 +33,22 @@ # Loads spec_helper from OpenProject core # This will include any support file from OpenProject core -require "spec_helper" -require "dry/container/stub" +require 'spec_helper' +require 'dry/container/stub' # Record Storages Cassettes in module VCR.configure do |config| - config.cassette_library_dir = "modules/storages/spec/support/fixtures/vcr_cassettes" - config.filter_sensitive_data("") do - ENV.fetch("ONE_DRIVE_TEST_OAUTH_CLIENT_ACCESS_TOKEN", "MISSING_ONE_DRIVE_TEST_OAUTH_CLIENT_ACCESS_TOKEN") + config.cassette_library_dir = 'modules/storages/spec/support/fixtures/vcr_cassettes' + config.filter_sensitive_data('') do + ENV.fetch('ONE_DRIVE_TEST_OAUTH_CLIENT_ACCESS_TOKEN', 'MISSING_ONE_DRIVE_TEST_OAUTH_CLIENT_ACCESS_TOKEN') end - config.filter_sensitive_data("") do - ENV.fetch("NEXTCLOUD_LOCAL_OAUTH_CLIENT_ACCESS_TOKEN", "MISSING_NEXTCLOUD_LOCAL_OAUTH_CLIENT_ACCESS_TOKEN") + config.filter_sensitive_data('') do + ENV.fetch('NEXTCLOUD_LOCAL_OAUTH_CLIENT_ACCESS_TOKEN', 'MISSING_NEXTCLOUD_LOCAL_OAUTH_CLIENT_ACCESS_TOKEN') end end # Loads files from relative support/ directory -Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each { |f| require f } +Dir[File.join(File.dirname(__FILE__), 'support/**/*.rb')].each { |f| require f } RSpec.configure do |config| config.prepend_before { Storages::Peripherals::Registry.enable_stubs! } diff --git a/modules/storages/spec/support/components/file_picker_dialog.rb b/modules/storages/spec/support/components/file_picker_dialog.rb index cfb0bbbefc0e..507ed9e6d92b 100644 --- a/modules/storages/spec/support/components/file_picker_dialog.rb +++ b/modules/storages/spec/support/components/file_picker_dialog.rb @@ -45,10 +45,10 @@ def confirm_button_state(selection_count:) case selection_count when 0 expect(page).to have_button(disabled: true, - exact_text: I18n.t("js.storages.file_links.selection.zero")) + exact_text: I18n.t('js.storages.file_links.selection.zero')) else expect(page).to have_button(disabled: false, - exact_text: I18n.t("js.storages.file_links.selection", count: selection_count)) + exact_text: I18n.t('js.storages.file_links.selection', count: selection_count)) end end end @@ -74,7 +74,7 @@ def select_file(text) def has_list_item?(text:, checked:, disabled:) page.within(container) do expect(page.find('[data-test-selector="op-files-picker-modal--list-item"]', text:)) - .to have_field(type: "checkbox", checked:, disabled:) + .to have_field(type: 'checkbox', checked:, disabled:) end end @@ -92,17 +92,17 @@ def select_all end end - def use_breadcrumb(position: "root" | "grandparent" | "parent") + def use_breadcrumb(position: 'root' | 'grandparent' | 'parent') page.within(container) do crumbs = page.all('[data-test-selector="op-breadcrumb"]') case position - when "root" + when 'root' expect(crumbs.size).to be > 1 crumbs[0].click - when "parent" + when 'parent' expect(crumbs.size).to be > 2 crumbs[-2].click - when "grandparent" + when 'grandparent' expect(crumbs.size).to be > 3 crumbs[-3].click end diff --git a/modules/storages/spec/support/ensure_connection_path_helper.rb b/modules/storages/spec/support/ensure_connection_path_helper.rb index ee5a63ff5f85..82d621094f03 100644 --- a/modules/storages/spec/support/ensure_connection_path_helper.rb +++ b/modules/storages/spec/support/ensure_connection_path_helper.rb @@ -30,12 +30,11 @@ module EnsureConnectionPathHelper def ensure_connection_path(project_storage) - url_helpers = OpenProject::StaticRouting::StaticRouter.new.url_helpers - url_helpers.oauth_clients_ensure_connection_path( + oauth_clients_ensure_connection_path( oauth_client_id: project_storage.storage.oauth_client.client_id, storage_id: project_storage.storage.id, - destination_url: url_helpers.open_project_storage_url( - protocol: "https", + destination_url: open_project_storage_url( + protocol: 'https', project_id: project_storage.project.identifier, id: project_storage.id ) diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/basic_auth.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/basic_auth.yml deleted file mode 100644 index 167e84304c58..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/basic_auth.yml +++ /dev/null @@ -1,78 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://nextcloud.local/ocs/v1.php/cloud/user - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Basic - Ocs-Apirequest: - - 'true' - Accept: - - application/json - User-Agent: - - httpx.rb/1.2.3 - Accept-Encoding: - - gzip, deflate - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache, no-store, must-revalidate - Content-Encoding: - - gzip - Content-Security-Policy: - - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' - Content-Type: - - application/json; charset=utf-8 - Date: - - Fri, 08 Mar 2024 08:56:52 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Feature-Policy: - - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone - 'none';payment 'none' - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=5493b458c5edc569998af2a938a9ecae; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=NHZ%2BN0amCVQHv6ahVDPyyFOksinMG062jNl6c5jjkDhmh7ITHbUjqv5JlcTPON28x7grqeOFYWlrnRJcG4eXfCVy62nmjhezAhkIVpyHXiCPRMtWe9KB%2FychAQJ%2BiLGG; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=5493b458c5edc569998af2a938a9ecae; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=5493b458c5edc569998af2a938a9ecae; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=5493b458c5edc569998af2a938a9ecae; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=a0fdf49e46837e242aeaa08c4eeb9d41; - path=/; secure; HttpOnly; SameSite=Lax, cookie_test=test; expires=Fri, 08 - Mar 2024 09:56:53 GMT; Max-Age=3600 - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Request-Id: - - CsPiZvs47I8ubFZtVXa5 - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '492' - body: - encoding: UTF-8 - string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"enabled":true,"storageLocation":"\/var\/www\/html\/data\/admin","id":"admin","lastLogin":1709888213000,"backend":"Database","subadmin":[],"quota":{"free":961968066560,"used":1137306515,"total":963105373075,"relative":0.12,"quota":-3},"manager":"","avatarScope":"v2-federated","email":null,"emailScope":"v2-federated","additional_mail":[],"additional_mailScope":[],"displayname":"admin","display-name":"admin","displaynameScope":"v2-federated","phone":"","phoneScope":"v2-local","address":"","addressScope":"v2-local","website":"","websiteScope":"v2-local","twitter":"","twitterScope":"v2-local","fediverse":"","fediverseScope":"v2-local","organisation":"","organisationScope":"v2-local","role":"","roleScope":"v2-local","headline":"","headlineScope":"v2-local","biography":"","biographyScope":"v2-local","profile_enabled":"1","profile_enabledScope":"v2-local","groups":["admin"],"language":"en","locale":"","notify_email":null,"backendCapabilities":{"setDisplayName":true,"setPassword":true}}}}' - recorded_at: Fri, 08 Mar 2024 08:56:53 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/basic_auth_password_invalid.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/basic_auth_password_invalid.yml deleted file mode 100644 index 5fa325bb2c6c..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/basic_auth_password_invalid.yml +++ /dev/null @@ -1,84 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://nextcloud.local/ocs/v1.php/cloud/user - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Basic - Ocs-Apirequest: - - 'true' - Accept: - - application/json - User-Agent: - - httpx.rb/1.2.3 - Accept-Encoding: - - gzip, deflate - response: - status: - code: 401 - message: Unauthorized - headers: - Cache-Control: - - no-store, no-cache, must-revalidate - Content-Security-Policy: - - 'default-src ''self''; script-src ''self'' ''nonce-WENJZ21RWmVoNGsrd09QWGJkZkIxTkZvSE1EMTdQcUtnbWFXemhCYVR1OD06YkU1WnpsVTczdHhva29Dd0JMLzE0cXNwVnZhOGg1Qzc1Z2ovbkZNeEk1dz0=''; - style-src ''self'' ''unsafe-inline''; frame-src *; img-src * data: blob:; - font-src ''self'' data:; media-src *; connect-src *; object-src ''none''; - base-uri ''self'';' - Content-Type: - - text/xml; charset=UTF-8 - Date: - - Fri, 08 Mar 2024 08:56:53 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=d2d84a2d68a663a91cf467ae11e98410; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=K8zJAF%2Fu8CsRxAISeRQdl1nP2BMN26QcYbeTLrz9tKI8RR%2F%2FqTPahXTqKqX6Y%2Bd%2Fq76Ubz0uPRCruH7SJNILoVmjdA5KUXqLnt6nnb1vqrOBnN4UNOSwyWTXuipHsAZ5; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=d2d84a2d68a663a91cf467ae11e98410; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=d2d84a2d68a663a91cf467ae11e98410; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=d2d84a2d68a663a91cf467ae11e98410; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=1ed4494a8003474f1979d6c194617924; - path=/; secure; HttpOnly; SameSite=Lax - Www-Authenticate: - - Basic realm="Authorisation Required" - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '153' - body: - encoding: UTF-8 - string: | - - - - failure - 997 - Unauthorised - - - - recorded_at: Fri, 08 Mar 2024 08:56:54 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/user_token_access_token_invalid.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/user_token_access_token_invalid.yml deleted file mode 100644 index 4fdeeb62ec21..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/user_token_access_token_invalid.yml +++ /dev/null @@ -1,234 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://nextcloud.local/ocs/v1.php/cloud/user - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Bearer - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - response: - status: - code: 401 - message: Unauthorized - headers: - Cache-Control: - - no-cache, no-store, must-revalidate - Content-Security-Policy: - - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' - Content-Type: - - application/xml; charset=utf-8 - Date: - - Fri, 08 Mar 2024 09:27:40 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Feature-Policy: - - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone - 'none';payment 'none' - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=c7e0c4a6c6d3bc29a2e1acbe831870d9; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=aK6rp4uRxDhSdbFlsS2wwbV0GtDKFTm%2BS20i427N16mObEOZ3sJx8JkhZg3Z5y5mald%2BtyNRj61cR38tPXAISfUHlzFDqgcybJZnpYOpS3ryIE6AgbGKhWfC9uwFlmy0; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=c7e0c4a6c6d3bc29a2e1acbe831870d9; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=c7e0c4a6c6d3bc29a2e1acbe831870d9; - path=/; secure; HttpOnly; SameSite=Lax - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Request-Id: - - gA5FAKPA4oYwmVQaEXPq - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '230' - body: - encoding: UTF-8 - string: | - - - - failure - 997 - Current user is not logged in - - - - - - recorded_at: Fri, 08 Mar 2024 09:27:40 GMT -- request: - method: post - uri: https://nextcloud.local/index.php/apps/oauth2/api/v1/token - body: - encoding: ASCII-8BIT - string: grant_type=refresh_token&scope=&client_id=7fj7lpG0GOqwOGhHAyfGwd1oEgtbTto7mctu0IaSN3SE79o9Xs0q8k3kDiEwXDrM&client_secret=j7RoyauWeIpMc7cYdY3lewCGKxdgiAowonpGzmAuj9iRSvYBAGXhP7hvz9Hp7skR&refresh_token=HRrpqZowJjD6OzBnwkpFTJAnAGQFUkhJ7En4ZpPtkhrPEIuRohVY56ooknlsrRVdIUOUPvyqtTzXomxDcOXvjnXhpREA18CkYOYQ3s2fxqOlk9u9mNrSTxHaqD0mpItw - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '328' - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache, no-store, must-revalidate - Content-Encoding: - - gzip - Content-Security-Policy: - - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' - Content-Type: - - application/json; charset=utf-8 - Date: - - Fri, 08 Mar 2024 09:27:40 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Feature-Policy: - - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone - 'none';payment 'none' - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=3aacffae684309baee15b9c37fdc5d6f; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=NWWi25ZMVtFYunofSBJ%2FURKXYfXSZcL7xY6suwb880gAnfhY0aIxdy4UkUy0ZvP8Ef4YLHIA7hIkpGcTpGwVw8v9j8L9Wbqs45Cx2dIfrcWxhhdLDWuyN74rOsRSE9JR; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=3aacffae684309baee15b9c37fdc5d6f; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=3aacffae684309baee15b9c37fdc5d6f; - path=/; secure; HttpOnly; SameSite=Lax - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Nextcloud-Bruteforce-Throttled: - - 200ms - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Request-Id: - - NQjl2frIpdjcHCrSVhdL - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '270' - body: - encoding: UTF-8 - string: '{"access_token":"","token_type":"Bearer","expires_in":3600,"refresh_token":"pF4QFI0ncfUUunsKCIauOUXUm8TQXrEEOvpfE2sGXPxYTsNr4FtPg0sxORfYXdxa5B98McVn3vbKblLwtA8QnKq7ATZAxtjDnDBBBXy7nUe5Z3exYeFaHcZdWwcYzv1w","user_id":"admin"}' - recorded_at: Fri, 08 Mar 2024 09:27:41 GMT -- request: - method: get - uri: https://nextcloud.local/ocs/v1.php/cloud/user - body: - encoding: US-ASCII - string: '' - headers: - Ocs-Apirequest: - - 'true' - Accept: - - application/json - User-Agent: - - httpx.rb/1.2.3 - Accept-Encoding: - - gzip, deflate - Authorization: - - Bearer - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache, no-store, must-revalidate - Content-Encoding: - - gzip - Content-Security-Policy: - - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' - Content-Type: - - application/json; charset=utf-8 - Date: - - Fri, 08 Mar 2024 09:27:41 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Feature-Policy: - - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone - 'none';payment 'none' - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=LcCCzBcktAmO9u5darmcMbX1GfvpLBkrSIyqOXu%2Bs0sfHD60nfff%2BuXHIaMRh9AhQXAzOvPgXFsekDAjqvbFn%2FswvgJMJyWt3w9bVSzDoQ8c%2BZmsdnzpaIyZXSnfTgAm; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=e0e76ba543cb281d8c6de45f13379227; - path=/; secure; HttpOnly; SameSite=Lax - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Request-Id: - - SIriQ7P07385wqbUaP7M - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '496' - body: - encoding: UTF-8 - string: '{"ocs":{"meta":{"status":"ok","statuscode":100,"message":"OK","totalitems":"","itemsperpage":""},"data":{"enabled":true,"storageLocation":"\/var\/www\/html\/data\/admin","id":"admin","lastLogin":1709888213000,"backend":"Database","subadmin":[],"quota":{"free":962269761536,"used":1137306515,"total":963407068051,"relative":0.12,"quota":-3},"manager":"","avatarScope":"v2-federated","email":null,"emailScope":"v2-federated","additional_mail":[],"additional_mailScope":[],"displayname":"admin","display-name":"admin","displaynameScope":"v2-federated","phone":"","phoneScope":"v2-local","address":"","addressScope":"v2-local","website":"","websiteScope":"v2-local","twitter":"","twitterScope":"v2-local","fediverse":"","fediverseScope":"v2-local","organisation":"","organisationScope":"v2-local","role":"","roleScope":"v2-local","headline":"","headlineScope":"v2-local","biography":"","biographyScope":"v2-local","profile_enabled":"1","profile_enabledScope":"v2-local","groups":["admin"],"language":"en","locale":"","notify_email":null,"backendCapabilities":{"setDisplayName":true,"setPassword":true}}}}' - recorded_at: Fri, 08 Mar 2024 09:27:41 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/user_token_refresh_token_invalid.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/user_token_refresh_token_invalid.yml deleted file mode 100644 index 4fd947950820..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/nextcloud/user_token_refresh_token_invalid.yml +++ /dev/null @@ -1,154 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://nextcloud.local/ocs/v1.php/cloud/user - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Bearer - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - response: - status: - code: 401 - message: Unauthorized - headers: - Cache-Control: - - no-cache, no-store, must-revalidate - Content-Security-Policy: - - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' - Content-Type: - - application/xml; charset=utf-8 - Date: - - Fri, 08 Mar 2024 09:21:35 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Feature-Policy: - - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone - 'none';payment 'none' - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=410bba53b25e4fd84d9fe3918b13fa65; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=rhdZ5dSY6QfUvYnUjhpWAmbCJACGZQpf1Zp4nOjHopkd7CxTWkVdFw8HYXqdmyPsykVZ0j7imva9IX4IktTStww2ASUuMHY%2BZzjOG7B2%2F1GkO6%2BYIvbxvAkIVsP3NUzK; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=410bba53b25e4fd84d9fe3918b13fa65; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=410bba53b25e4fd84d9fe3918b13fa65; - path=/; secure; HttpOnly; SameSite=Lax - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Request-Id: - - e9FlTXYXJZM3Iqux61Qg - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '230' - body: - encoding: UTF-8 - string: | - - - - failure - 997 - Current user is not logged in - - - - - - recorded_at: Fri, 08 Mar 2024 09:21:35 GMT -- request: - method: post - uri: https://nextcloud.local/index.php/apps/oauth2/api/v1/token - body: - encoding: ASCII-8BIT - string: grant_type=refresh_token&scope=&client_id=7fj7lpG0GOqwOGhHAyfGwd1oEgtbTto7mctu0IaSN3SE79o9Xs0q8k3kDiEwXDrM&client_secret=j7RoyauWeIpMc7cYdY3lewCGKxdgiAowonpGzmAuj9iRSvYBAGXhP7hvz9Hp7skR&refresh_token= - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '204' - response: - status: - code: 400 - message: Bad Request - headers: - Cache-Control: - - no-cache, no-store, must-revalidate - Content-Security-Policy: - - default-src 'none';base-uri 'none';manifest-src 'self';frame-ancestors 'none' - Content-Type: - - application/json; charset=utf-8 - Date: - - Fri, 08 Mar 2024 09:21:35 GMT - Expires: - - Thu, 19 Nov 1981 08:52:00 GMT - Feature-Policy: - - autoplay 'none';camera 'none';fullscreen 'none';geolocation 'none';microphone - 'none';payment 'none' - Pragma: - - no-cache - Referrer-Policy: - - no-referrer - Server: - - Apache/2.4.57 (Debian) - Set-Cookie: - - ocirabgzify6=9affd4b9d9c040cc5d392a26e06d1bb3; path=/; secure; HttpOnly; SameSite=Lax, - oc_sessionPassphrase=iTHBtQPtpepw9rKgYTH6DUaJ%2BduE0rPGbQEjiFg2jf%2BigbTIwnAd9hwnz8n8rRFmvpbVatLM0N06C5%2BNRYAXXXpNtm3THjp6avx1968ATrWtUW7h7nGoKi%2BGRzL8cEeb; - path=/; secure; HttpOnly; SameSite=Lax, ocirabgzify6=9affd4b9d9c040cc5d392a26e06d1bb3; - path=/; secure; HttpOnly; SameSite=Lax, __Host-nc_sameSiteCookielax=true; - path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax, - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, - 31-Dec-2100 23:59:59 GMT; SameSite=strict, ocirabgzify6=9affd4b9d9c040cc5d392a26e06d1bb3; - path=/; secure; HttpOnly; SameSite=Lax - X-Content-Type-Options: - - nosniff - X-Frame-Options: - - SAMEORIGIN - X-Nextcloud-Bruteforce-Throttled: - - 200ms - X-Permitted-Cross-Domain-Policies: - - none - X-Powered-By: - - PHP/8.2.16 - X-Request-Id: - - 6P1BayresgCTVsAE5yQh - X-Robots-Tag: - - noindex, nofollow - X-Xss-Protection: - - 1; mode=block - Content-Length: - - '27' - body: - encoding: UTF-8 - string: '{"error":"invalid_request"}' - recorded_at: Fri, 08 Mar 2024 09:21:35 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials.yml deleted file mode 100644 index 11b292388f31..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials.yml +++ /dev/null @@ -1,105 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_id=4262df2b-77bb-49c2-a5df-28355da676d2&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '186' - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 45f8bf00-42a6-47e6-87fc-2f44cd886301 - X-Ms-Ests-Server: - - 2.1.17396.8 - SEC ProdSlices - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=AkLiVHzNibJCs_PG8YKAj9ekbDoXAQAAAMjVfN0OAAAA; expires=Sun, 07-Apr-2024 - 09:47:52 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Fri, 08 Mar 2024 09:47:51 GMT - Content-Length: - - '1708' - body: - encoding: UTF-8 - string: '{"token_type":"Bearer","expires_in":3599,"ext_expires_in":3599,"access_token":""}' - recorded_at: Fri, 08 Mar 2024 09:47:52 GMT -- request: - method: get - uri: https://graph.microsoft.com/v1.0/drives - body: - encoding: US-ASCII - string: '' - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Authorization: - - Bearer - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-store, no-cache - Content-Type: - - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8 - Content-Encoding: - - gzip - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - 7fa0054b-7957-4ef6-b464-5668fa6f632e - Client-Request-Id: - - 7fa0054b-7957-4ef6-b464-5668fa6f632e - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"West Europe","Slice":"E","Ring":"5","ScaleUnit":"009","RoleInstance":"AM1PEPF00030089"}}' - Odata-Version: - - '4.0' - Date: - - Fri, 08 Mar 2024 09:47:52 GMT - body: - encoding: UTF-8 - string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#drives","value":[{"createdDateTime":"2014-07-03T15:53:23Z","description":"","id":"b!kTAW5Yf7f0qq6g_lYINMuB4uOjja01JIjQ_dr7ZjNIH6z0ctGr_6Tp8_tQ7NLb-_","lastModifiedDateTime":"2022-06-03T09:26:04Z","name":"Documents","webUrl":"https://finn.sharepoint.com/Shared%20Documents","driveType":"documentLibrary","createdBy":{"user":{"displayName":"System - Account"}},"lastModifiedBy":{"user":{"email":"j.ulferts@finn.onmicrosoft.com","id":"b0870935-81a9-4ef3-a144-850121c00bcf","displayName":"Jens - Ulferts"}},"owner":{"group":{"id":"068eacfd-365f-4cf5-848b-6a1977a314c4","displayName":"Company - Administrator"}},"quota":{"deleted":0,"remaining":11168733510,"state":"normal","total":18253611008,"used":7084877498}}]}' - recorded_at: Fri, 08 Mar 2024 09:47:53 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials_invalid_client_id.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials_invalid_client_id.yml deleted file mode 100644 index 155b8a50b5b9..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials_invalid_client_id.yml +++ /dev/null @@ -1,65 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_id=4262df2b-77bb-49c2-a5df-28355da676d4&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '186' - response: - status: - code: 400 - message: Bad Request - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 46f282b7-d885-4d58-acb8-8bb329c85e01 - X-Ms-Ests-Server: - - 2.1.17396.8 - FRC ProdSlices - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=Au-85Vpu5bdCuNKPnVwy3iWOYfFZAQAAAOPWfN0OAAAA; expires=Sun, 07-Apr-2024 - 09:52:35 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Fri, 08 Mar 2024 09:52:34 GMT - Content-Length: - - '750' - body: - encoding: UTF-8 - string: '{"error":"unauthorized_client","error_description":"AADSTS700016: Application - with identifier ''4262df2b-77bb-49c2-a5df-28355da676d4'' was not found in - the directory ''OpenProject GmbH''. This can happen if the application has - not been installed by the administrator of the tenant or consented to by any - user in the tenant. You may have sent your authentication request to the wrong - tenant. Trace ID: 46f282b7-d885-4d58-acb8-8bb329c85e01 Correlation ID: bffb3977-30e2-49bc-aa3b-d5fe640495b8 - Timestamp: 2024-03-08 09:52:35Z","error_codes":[700016],"timestamp":"2024-03-08 - 09:52:35Z","trace_id":"46f282b7-d885-4d58-acb8-8bb329c85e01","correlation_id":"bffb3977-30e2-49bc-aa3b-d5fe640495b8","error_uri":"https://login.microsoftonline.com/error?code=700016"}' - recorded_at: Fri, 08 Mar 2024 09:52:35 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials_invalid_client_secret.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials_invalid_client_secret.yml deleted file mode 100644 index 45252eda5e50..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/client_credentials_invalid_client_secret.yml +++ /dev/null @@ -1,63 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=client_credentials&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_id=4262df2b-77bb-49c2-a5df-28355da676d2&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB%2F%2F%2F - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '195' - response: - status: - code: 401 - message: Unauthorized - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 79dc9e93-53b2-4aae-ab6c-ef5aade86b01 - X-Ms-Ests-Server: - - 2.1.17396.8 - FRC ProdSlices - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=ArsWju6XLfdBv1FghfJshtekbDoXAQAAAELXfN0OAAAA; expires=Sun, 07-Apr-2024 - 09:54:10 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Fri, 08 Mar 2024 09:54:10 GMT - Content-Length: - - '623' - body: - encoding: UTF-8 - string: '{"error":"invalid_client","error_description":"AADSTS7000215: Invalid - client secret provided. Ensure the secret being sent in the request is the - client secret value, not the client secret ID, for a secret added to app ''4262df2b-77bb-49c2-a5df-28355da676d2''. - Trace ID: 79dc9e93-53b2-4aae-ab6c-ef5aade86b01 Correlation ID: 6e8fd83c-7b73-4af3-abf0-dd6f7ac4586a - Timestamp: 2024-03-08 09:54:10Z","error_codes":[7000215],"timestamp":"2024-03-08 - 09:54:10Z","trace_id":"79dc9e93-53b2-4aae-ab6c-ef5aade86b01","correlation_id":"6e8fd83c-7b73-4af3-abf0-dd6f7ac4586a","error_uri":"https://login.microsoftonline.com/error?code=7000215"}' - recorded_at: Fri, 08 Mar 2024 09:54:10 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token.yml deleted file mode 100644 index 1ca4d619f7a1..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token.yml +++ /dev/null @@ -1,50 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://graph.microsoft.com/v1.0/me - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Bearer - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache - Content-Type: - - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8 - Content-Encoding: - - gzip - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - 8880066a-b15a-4140-8389-0831db4b84e5 - Client-Request-Id: - - 8880066a-b15a-4140-8389-0831db4b84e5 - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"5","ScaleUnit":"005","RoleInstance":"FR3PEPF00000368"}}' - X-Ms-Resource-Unit: - - '1' - Odata-Version: - - '4.0' - Date: - - Fri, 08 Mar 2024 10:07:54 GMT - body: - encoding: UTF-8 - string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users/$entity","businessPhones":[],"displayName":"Eric - Schubert","givenName":"Eric","jobTitle":"Developer","mail":"eschubert.op@outlook.com","mobilePhone":null,"officeLocation":null,"preferredLanguage":null,"surname":"Schubert","userPrincipalName":"eschubert.op_outlook.com#EXT#@finn.onmicrosoft.com","id":"0a0d38a9-a59b-4245-93fa-0d2cf727f17a"}' - recorded_at: Fri, 08 Mar 2024 10:07:55 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token_access_token_invalid.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token_access_token_invalid.yml deleted file mode 100644 index e9e541cb2b79..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token_access_token_invalid.yml +++ /dev/null @@ -1,154 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://graph.microsoft.com/v1.0/me - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Bearer - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - response: - status: - code: 401 - message: Unauthorized - headers: - Content-Type: - - application/json - Content-Encoding: - - gzip - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - ad0aa0d8-97e8-4c7f-9569-f4363f882e4a - Client-Request-Id: - - ad0aa0d8-97e8-4c7f-9569-f4363f882e4a - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"5","ScaleUnit":"005","RoleInstance":"FR3PEPF00000355"}}' - Www-Authenticate: - - Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", - client_id="00000003-0000-0000-c000-000000000000" - Date: - - Fri, 08 Mar 2024 10:12:12 GMT - body: - encoding: UTF-8 - string: '{"error":{"code":"InvalidAuthenticationToken","message":"IDX14100: - JWT is not well formed, there are no dots (.).\nThe token needs to be in JWS - or JWE Compact Serialization Format. (JWS): ''EncodedHeader.EndcodedPayload.EncodedSignature''. - (JWE): ''EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag''.","innerError":{"date":"2024-03-08T10:12:12","request-id":"ad0aa0d8-97e8-4c7f-9569-f4363f882e4a","client-request-id":"ad0aa0d8-97e8-4c7f-9569-f4363f882e4a"}}}' - recorded_at: Fri, 08 Mar 2024 10:12:13 GMT -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=refresh_token&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_id=4262df2b-77bb-49c2-a5df-28355da676d2&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB&refresh_token=0.AQkANr9ETVabwEWIB7vzht0EfyvfYkK7d8JJpd8oNV2mdtIJAK8.AgABAAEAAADnfolhJpSnRYB1SVj-Hgd8AgDs_wUA9P8ntRuLW080vHVlO5D6JSD0duXIRciAKS285L-3UTLSPQV-sTbd39NDX8E5Iy6IzOQ1Ts_e7pRRtcSpfdJUkSYHWw8EzTo4AVpgiSL1z2nQGrKMBB7zdUmhWtVCC6vWnvlq6MEMJVnRX_99r1lpt09J3LV237zUcinactOxgRUjvUsMtn-1Dy43hRj3zjBjiC0RrePD_hQ7MVcBX15u4VxUDzCzOOquPtJoai0aQ7W8PSDakrIvYiDzdCZVWuxmLDM-rmGu8dJyuLzTBszQGqCUnH4CamL-9GgZExZK1_YrMoB7kei2ByHN_EZ2NCvEPXZlLZWBy_DC8Chp2CdamK2ViuUrLEh90Iu5UpiYQhpJ_CBJjHlWHcMjE_SYkPlyKekogTpNbAFxlx5-mzEpfPFX3f8JdzMem4-LTV3SOAmXHUcsH00qk-n_Gz8wAK06kxj5xe8KPObw3DfBlL9A15V4gzLW_1yP7SH8MpU2E_88-hP74nMs9suaTX9Pd5Nf3xpYMge0G4rAxj7VWKiVTkmhoct_9sbf-FxIUfFeaNwkZlTxhsPow_t0uwSFUzwUT-JCxlqBiDBqMSdrdEkzf2vPDIHkoMgIkKT_7vxhzTIjOPsiXbZz_tQztqjGNchmJyYQ6oqRU1prLCFQ4XZ-fCg8JjovSebsaj22VVo4dVQV6LHL6JXC4yLrLDwhLtLaGZcOj-QQzWspofBGWvTEn5g0CIFdBkeZkWSYfULwczOJNVgiq1yG1D1OVpGpc0ij6FnS6ax2_bVBt6Ms8gIUUivrZ99Hy4Uydo4UGJfaQFT5GJ6rLe5s_j6fg7JgbjW2GEZPxbugGaNpfq_4IZGXJJ5T9qXhnGsAIddS0KG8e0UO3ZR0ZZx3f40fofawZ-P4PK2HPatd4q2wze4R9uS_7weE8-kS43xCHiokvI0ghcWETLh-l_hJYkhFJfLGD0AdHtvSqTlLot3ErGYrczhWJMQtF-P4_r2tGR8119PE5Ud-8rhwe_ufFRvBe93HJ_imWATrao4EKkBl_NGb18z0SvZ2wdYZRz6l5WCzXfbgxAVRzuCeVw9xaBFakGg0xJg_7jQ0qx7tR9p4jdyiIcu6IK3agzXQ7xFTlgb-paiqhU8S_r0w-_KgBLpBGa3ECHquPWwOjenBxrA8ue5KZLTHW3Q7u9w4TOzb0JcvbAvbQ95MpHJju8TJ24ik1e6ADlILtsoQhp29FBYrDt_s3AuGFG4iBoZSgw-quGc59uCWJqIchq5y7xYg4EHAY9njXojlGIuIjEdl1Rc4g1bCguLkrSYIXAQSNW6ujqOmfNSjXMze3siHey1WLBQ1FeU2C9f9AdiiCtEORwLR54oPGIGjc_3kINecU1YptbzkvLPoy5aS5d_SjZmSy1Yl6JMDZ8QH8wm8Bu0kLvxnlWMHTMw5gjQpoeBhUsh9wQJn0lUGO14D5lXJJZlBrYDaZ0ee8T7lKPeaazkVF2kh-gwgdSNLXagTkhgQdmLVtMAUrqLH2Q - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '1804' - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - e821fe8d-3b01-4b6b-84a4-9ea1ad989e01 - X-Ms-Ests-Server: - - 2.1.17396.8 - SEC ProdSlices - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=ArOzgq1vi4pDjjvHIUkf75pjrVfjAQAAAHzbfN0OAAAA; expires=Sun, 07-Apr-2024 - 10:12:13 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Fri, 08 Mar 2024 10:12:13 GMT - Content-Length: - - '4400' - body: - encoding: UTF-8 - string: '{"token_type":"Bearer","scope":"profile openid email https://graph.microsoft.com/Directory.ReadWrite.All - https://graph.microsoft.com/Files.ReadWrite.All https://graph.microsoft.com/Sites.Read.All - https://graph.microsoft.com/Sites.ReadWrite.All https://graph.microsoft.com/User.Read - https://graph.microsoft.com/.default","expires_in":3924,"ext_expires_in":3924,"access_token":"","refresh_token":"0.AQkANr9ETVabwEWIB7vzht0EfyvfYkK7d8JJpd8oNV2mdtIJAK8.AgABAAEAAADnfolhJpSnRYB1SVj-Hgd8AgDs_wUA9P8lgegjoHlDEVPHGZ5FBon869Xv5-c9gQV0LKbMA9Wmq-BRtWBTZbAn3-GH1LZEjk8ZIpuiyHsXCBfhudmlW8BlxIjr-AVqZVY59pZfPQ7kW-EiETxysRxvb6-KqsT8CGjYcbQb_hRpBJXaQwtBOu6rh6Noie1K_pzq3D8R8QEwnLMlfwWj_63iVWf5IfNposuZ40WQcYmwiQpHfmNy-mq1kD35YQrjaEGDW1vs_9tT-sS7GnkmxvzvUkiOxrOc9c69se7DU4fjX9PuSxy4q8u44kr5BifW6D3IdM0Ow6_y0bC75hhf78OyKMLrUjvICd7_STcsjyjWB3x3QRABNEJrNpHRTJ1_WmQmwOwRPzr4kCGyRWUTLqgJL96fzDUb_stnmjo_tEI1AAUSk4MO5lXpatzfihKJviKMUxGKFYb5PMKlMUBaBiM1kJKPoQyduw21jfJGXfe8NsrgSC3_FU_khY3xC-hYU_9m5AMTe2RtvQG6k-IciyyoHDfD0KHN9el8-zSu0euwkU39OnkV5H2LNN9UeTdzJQj5ZKoOXhI3xFW9z4nFJT3pO0VmbyWUvPM_8HkJafEujt1DO6ocD9COZq4mudVUdRNoRvTOBeu3FtEt6X80OyPawO5fPLh_JuvhG_ff_jBEUX1wJwpnBykdczoA37P1p6KSbB6h3_ZoB5harlzv1KjKFyKpyNGnNAkrEqAr3nX2MEWTuurGPDw1psrHpvTODWXcM_EAJ5HG2j4-ET7XZjTQr9dq1jhHiXiHtGZdJ2R0aThe1Cye7fx7MSzNIE36HtpOns9gfa40oi5IC9be2BwYJPcGc9rXOFAT-tfjumitN8UJi5uzkHJ2-tzA9DkrE2fGDMaNtEgYsyBfDjeVbgio5n2nXIu9zHht_y3KDLRYV4XqIxCRSIyqy513WdR3jRrLB1bIflBNtgqdinQlWXM3e9jm9kBisBTjPR4Iq0NE-GPUg0-8jDEBZ11ZvrttDx1jtc5mxdSMYP7oSLG7sMOBxDmff0xMl05Wv-4j54830ebY2sF_lrJ78qpnaePen0ANgODMug28dCJ2yStzMW2ZyGqdurhRp_8sh09W3Q3xkto-OPuHLjYZDqCMfU03DcPk61BQJPRWKtvTSvfHDOzh9COmQI7qxzsJmv-MIIQ9tS12Lm6sxivJH-PAa7INrxHESf7UOgepp6onZiQKXvLuYUJK4hmP8SVMG-y-H3bPxFmS-lM3w5w-s_4wRHY6Xrj8MmSf_92_oekEK71K2pRQqlRj79g6ReZh5bDF2lZRDPX6gqE3LFa7FicUAyRuZY3CtnfK4S84fuzeU5X9V7Vs2kXymj_TSTbhnkAkRpYjj8wXUMqTuR4ggeRCapJGWGXDItJHDlpVyzdNa3128LZ2aChbbHctY_nqloDhUOfq_LeuD5w2Ud6cysbI7kMHp6VUrSZdSp8CKSM_z-E6HCtMXi4bYjYNwFBcKvhXoBbduPMwTjDxIzPhPvciL1TAMRa1g1DPRQ"}' - recorded_at: Fri, 08 Mar 2024 10:12:13 GMT -- request: - method: get - uri: https://graph.microsoft.com/v1.0/me - body: - encoding: US-ASCII - string: '' - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Authorization: - - Bearer - response: - status: - code: 200 - message: OK - headers: - Cache-Control: - - no-cache - Content-Type: - - application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8 - Content-Encoding: - - gzip - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - ab1dd57e-6196-46f6-9387-e6c679b666c2 - Client-Request-Id: - - ab1dd57e-6196-46f6-9387-e6c679b666c2 - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"5","ScaleUnit":"005","RoleInstance":"FR3PEPF000002D8"}}' - X-Ms-Resource-Unit: - - '1' - Odata-Version: - - '4.0' - Date: - - Fri, 08 Mar 2024 10:12:13 GMT - body: - encoding: UTF-8 - string: '{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users/$entity","businessPhones":[],"displayName":"Eric - Schubert","givenName":"Eric","jobTitle":"Developer","mail":"eschubert.op@outlook.com","mobilePhone":null,"officeLocation":null,"preferredLanguage":null,"surname":"Schubert","userPrincipalName":"eschubert.op_outlook.com#EXT#@finn.onmicrosoft.com","id":"0a0d38a9-a59b-4245-93fa-0d2cf727f17a"}' - recorded_at: Fri, 08 Mar 2024 10:12:13 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token_refresh_token_invalid.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token_refresh_token_invalid.yml deleted file mode 100644 index 8695eb3b2600..000000000000 --- a/modules/storages/spec/support/fixtures/vcr_cassettes/auth/one_drive/user_token_refresh_token_invalid.yml +++ /dev/null @@ -1,109 +0,0 @@ ---- -http_interactions: -- request: - method: get - uri: https://graph.microsoft.com/v1.0/me - body: - encoding: US-ASCII - string: '' - headers: - Authorization: - - Bearer - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - response: - status: - code: 401 - message: Unauthorized - headers: - Content-Type: - - application/json - Content-Encoding: - - gzip - Vary: - - Accept-Encoding - Strict-Transport-Security: - - max-age=31536000 - Request-Id: - - bd58ebc4-22ab-4c8e-83db-4e768e3e027b - Client-Request-Id: - - bd58ebc4-22ab-4c8e-83db-4e768e3e027b - X-Ms-Ags-Diagnostic: - - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"5","ScaleUnit":"004","RoleInstance":"FR2PEPF0000038F"}}' - Www-Authenticate: - - Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", - client_id="00000003-0000-0000-c000-000000000000" - Date: - - Fri, 08 Mar 2024 10:19:25 GMT - body: - encoding: UTF-8 - string: '{"error":{"code":"InvalidAuthenticationToken","message":"Lifetime validation - failed, the token is expired.","innerError":{"date":"2024-03-08T10:19:25","request-id":"bd58ebc4-22ab-4c8e-83db-4e768e3e027b","client-request-id":"bd58ebc4-22ab-4c8e-83db-4e768e3e027b"}}}' - recorded_at: Fri, 08 Mar 2024 10:19:25 GMT -- request: - method: post - uri: https://login.microsoftonline.com/4d44bf36-9b56-45c0-8807-bbf386dd047f/oauth2/v2.0/token - body: - encoding: ASCII-8BIT - string: grant_type=refresh_token&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_id=4262df2b-77bb-49c2-a5df-28355da676d2&client_secret=Vwk8Q%7EJTuPh.pAjvPiWBQBdTFMDK%7EAIwxbj9_axB&refresh_token=0.Aa8AvB1v4679fkK2Gw2W3fuBpFS7pbiyXw5OlCedJNusMv-sAG8.AgABAAEAAADnfolhJpSnRYB1SVj-Hgd8AgDs_wUA9P8Z061joKlEcPUtDzyw_gVnTjiopiJDS5ytd7dL84d96fn-6ZLCxNaGgq--SyccONngEfxC4dPXkrI91EryFG6Gc5M3Ols5wM2DCRSDrPHhik0q7Jyg2COnCW7CkRGpFw73snV_HcUj_16JgSABTdK4bZkodfS9fb58jpydgORme7boXgT0m5g3_XPp7WSr3Ux8AwM4NCJD9NWuJeVMuDuRLwF1Ro_yC3QDfBvKbJ72PpEmII_1m2FqRoDHJguXkEyXQrjBjVo6oosKRgZk_F04OFvCZsZAqnRDEcJ4Ut_wKODky_tvEVrKHvM48XLI5lKblCLBqd1alnfPIG_jUs4K_HnpJWIhYPwTuGM3ZVWsLSRhsvvRgYwiph_HDysTUlEJvtVR51L3AT4WXnuQ6vgUxFKOj0nrxJKP6cL7g9-d7Z9pc5Avc79fwOE_eCqcdAQFmhfhRafxfTi-lQpBJ3AV0KO-9WmdshPlxvbVsNr1widcQEKA8Jp16wOdqxOiWGQvZdFXn1xLksKGSvAwxZ96xMitU-Wy4hobpSO2emf1Z_0Snz43kBRM6pOBQmO12mQH3FsYeK7QyRIyoLd6qbn63_SjBGoujZExMlFl2oApUVhqo1GU2eMtpn7U9YWCikztHrJQKicYPqHBb60e1i1h69XieYrbzlgd6FHzsyHNHYsek9eZntuXRU6vA7-xkJC9wlBPaUYpZQG0LSFZkhpu19okyEmXjIG6iU7kd4-rTTrMGAv8ld17OuqMCkA188PxNHp4fe3FK0Pq12Oyu_y3PPpG1RvkkntaVQJPn-CB_hRzAlCc1iCbbiEt - headers: - User-Agent: - - httpx.rb/1.2.3 - Accept: - - "*/*" - Accept-Encoding: - - gzip, deflate - Content-Type: - - application/x-www-form-urlencoded - Content-Length: - - '1118' - response: - status: - code: 400 - message: Bad Request - headers: - Cache-Control: - - no-store, no-cache - Pragma: - - no-cache - Content-Type: - - application/json; charset=utf-8 - Expires: - - "-1" - Strict-Transport-Security: - - max-age=31536000; includeSubDomains - X-Content-Type-Options: - - nosniff - P3p: - - CP="DSP CUR OTPi IND OTRi ONL FIN" - X-Ms-Request-Id: - - 5caa14c3-739a-485e-8435-5953a8871b01 - X-Ms-Ests-Server: - - 2.1.17396.8 - NEULR1 ProdSlices - X-Xss-Protection: - - '0' - Set-Cookie: - - fpc=Au5UpfkLa3xArxbExNnpxbwf1m9OAQAAAC7dfN0OAAAA; expires=Sun, 07-Apr-2024 - 10:19:26 GMT; path=/; secure; HttpOnly; SameSite=None, x-ms-gateway-slice=estsfd; - path=/; secure; samesite=none; httponly, stsservicecookie=estsfd; path=/; - secure; samesite=none; httponly - Date: - - Fri, 08 Mar 2024 10:19:25 GMT - Content-Length: - - '750' - body: - encoding: UTF-8 - string: '{"error":"unauthorized_client","error_description":"AADSTS700016: Application - with identifier ''b8a5bb54-5fb2-4e0e-9427-9d24dbac32ff'' was not found in - the directory ''OpenProject GmbH''. This can happen if the application has - not been installed by the administrator of the tenant or consented to by any - user in the tenant. You may have sent your authentication request to the wrong - tenant. Trace ID: 5caa14c3-739a-485e-8435-5953a8871b01 Correlation ID: c1b246e2-1f45-4bcc-bd5e-c49dee897791 - Timestamp: 2024-03-08 10:19:26Z","error_codes":[700016],"timestamp":"2024-03-08 - 10:19:26Z","trace_id":"5caa14c3-739a-485e-8435-5953a8871b01","correlation_id":"c1b246e2-1f45-4bcc-bd5e-c49dee897791","error_uri":"https://login.microsoftonline.com/error?code=700016"}' - recorded_at: Fri, 08 Mar 2024 10:19:26 GMT -recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/files_query_invalid_token.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/files_query_invalid_token.yml new file mode 100644 index 000000000000..329fda315822 --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/nextcloud/files_query_invalid_token.yml @@ -0,0 +1,88 @@ +--- +http_interactions: +- request: + method: propfind + uri: https://nextcloud.local/remote.php/dav/files/admin/ + body: + encoding: UTF-8 + string: | + + + + + + + + + + + + headers: + Depth: + - '1' + Authorization: + - Bearer 1234567890-1 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 401 + message: Unauthorized + headers: + Cache-Control: + - no-store, no-cache, must-revalidate + Content-Length: + - '476' + Content-Security-Policy: + - default-src 'none'; + Content-Type: + - application/xml; charset=utf-8 + Date: + - Wed, 29 Nov 2023 15:45:31 GMT + Expires: + - Thu, 19 Nov 1981 08:52:00 GMT + Pragma: + - no-cache + Referrer-Policy: + - no-referrer + Server: + - Apache/2.4.57 (Debian) + Set-Cookie: + - __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 + 23:59:59 GMT; SameSite=lax + - __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, + 31-Dec-2100 23:59:59 GMT; SameSite=strict + - oc_sessionPassphrase=UXh8eFuRtTRf9T7iZTT0kzicJGCTmNYEv3KVKHQGG%2BZr8KS8oJPhgRClJm2zErUam7AK8qAWgc%2FVXHitCHegMiwPALDz14awrmo1H7qHMrZaDdGjwvfN7d%2Bcul%2BFa9YB; + path=/; secure; HttpOnly; SameSite=Lax + - ocirabgzify6=633a1046540dd6fb7ce9e41e77b73076; path=/; secure; HttpOnly; SameSite=Lax + - ocirabgzify6=633a1046540dd6fb7ce9e41e77b73076; path=/; secure; HttpOnly; SameSite=Lax + - ocirabgzify6=633a1046540dd6fb7ce9e41e77b73076; path=/; secure; HttpOnly; SameSite=Lax + - ocirabgzify6=f939fd60240f843f64f1a146dac38aef; path=/; secure; HttpOnly; SameSite=Lax + Www-Authenticate: + - Basic realm="Nextcloud", charset="UTF-8" + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Powered-By: + - PHP/8.2.13 + X-Robots-Tag: + - noindex, nofollow + X-Xss-Protection: + - 1; mode=block + body: + encoding: UTF-8 + string: | + + + Sabre\DAV\Exception\NotAuthenticated + No public access to this resource., No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, Bearer token was incorrect, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured + + recorded_at: Wed, 29 Nov 2023 15:45:31 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/files_query_invalid_token.yml b/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/files_query_invalid_token.yml new file mode 100644 index 000000000000..421e55301ffc --- /dev/null +++ b/modules/storages/spec/support/fixtures/vcr_cassettes/one_drive/files_query_invalid_token.yml @@ -0,0 +1,51 @@ +--- +http_interactions: +- request: + method: get + uri: https://graph.microsoft.com/v1.0/drives/b!dmVLG22QlE2PSW0AqVB7UOhZ8n7tjkVGkgqLNnuw2OBb-brzKzZAR4DYT1k9KPXs/root/children?$select=id,name,size,webUrl,lastModifiedBy,createdBy,fileSystemInfo,file,folder,parentReference + body: + encoding: US-ASCII + string: '' + headers: + Authorization: + - Bearer + User-Agent: + - httpx.rb/1.2.1 + Accept: + - "*/*" + Accept-Encoding: + - gzip, deflate + response: + status: + code: 401 + message: Unauthorized + headers: + Transfer-Encoding: + - chunked + Content-Type: + - application/json + Content-Encoding: + - gzip + Vary: + - Accept-Encoding + Strict-Transport-Security: + - max-age=31536000 + Request-Id: + - 0116dfa7-1f73-4738-8fc1-666cacd957ae + Client-Request-Id: + - 0116dfa7-1f73-4738-8fc1-666cacd957ae + X-Ms-Ags-Diagnostic: + - '{"ServerInfo":{"DataCenter":"Germany West Central","Slice":"E","Ring":"5","ScaleUnit":"005","RoleInstance":"FR3PEPF00000368"}}' + Www-Authenticate: + - Bearer realm="", authorization_uri="https://login.microsoftonline.com/common/oauth2/authorize", + client_id="00000003-0000-0000-c000-000000000000" + Date: + - Tue, 30 Jan 2024 11:56:00 GMT + body: + encoding: UTF-8 + string: '{"error":{"code":"InvalidAuthenticationToken","message":"IDX14100: + JWT is not well formed, there are no dots (.).\nThe token needs to be in JWS + or JWE Compact Serialization Format. (JWS): ''EncodedHeader.EndcodedPayload.EncodedSignature''. + (JWE): ''EncodedProtectedHeader.EncodedEncryptedKey.EncodedInitializationVector.EncodedCiphertext.EncodedAuthenticationTag''.","innerError":{"date":"2024-01-30T11:56:00","request-id":"0116dfa7-1f73-4738-8fc1-666cacd957ae","client-request-id":"0116dfa7-1f73-4738-8fc1-666cacd957ae"}}}' + recorded_at: Tue, 30 Jan 2024 11:56:00 GMT +recorded_with: VCR 6.2.0 diff --git a/modules/storages/spec/support/json_response_helper.rb b/modules/storages/spec/support/json_response_helper.rb index c83f67794f20..20a0dbf8bf56 100644 --- a/modules/storages/spec/support/json_response_helper.rb +++ b/modules/storages/spec/support/json_response_helper.rb @@ -36,18 +36,18 @@ def read_json(name) private def payload_path - Pathname.new(Rails.root).join("modules/storages/spec/support/payloads/") + Pathname.new(Rails.root).join('modules/storages/spec/support/payloads/') end def not_found_response { error: { - code: "itemNotFound", - message: "The resource could not be found.", + code: 'itemNotFound', + message: 'The resource could not be found.', innerError: { - date: "2023-09-08T08:20:55", - "request-id": "286b0215-7f33-46dc-b1fe-67720fe1616a", - "client-request-id": "286b0215-7f33-46dc-b1fe-67720fe1616a" + date: '2023-09-08T08:20:55', + 'request-id': '286b0215-7f33-46dc-b1fe-67720fe1616a', + 'client-request-id': '286b0215-7f33-46dc-b1fe-67720fe1616a' } } }.to_json @@ -56,12 +56,12 @@ def not_found_response def forbidden_response { error: { - code: "accessDenied", - message: "Access denied", + code: 'accessDenied', + message: 'Access denied', innerError: { - date: "2023-09-08T08:20:55", - "request-id": "286b0215-7f33-46dc-b1fe-67720fe1616f", - "client-request-id": "286b0215-7f33-46dc-b1fe-67720fe1616b" + date: '2023-09-08T08:20:55', + 'request-id': '286b0215-7f33-46dc-b1fe-67720fe1616f', + 'client-request-id': '286b0215-7f33-46dc-b1fe-67720fe1616b' } } }.to_json diff --git a/modules/storages/spec/support/storage_server_helpers.rb b/modules/storages/spec/support/storage_server_helpers.rb index 2074e627f1ce..33d5d91c314d 100644 --- a/modules/storages/spec/support/storage_server_helpers.rb +++ b/modules/storages/spec/support/storage_server_helpers.rb @@ -35,7 +35,7 @@ def mock_server_capabilities_response(nextcloud_host, response_nextcloud_major_version: 22) response_code ||= 200 response_headers ||= { - "Content-Type" => "application/json; charset=utf-8" + 'Content-Type' => 'application/json; charset=utf-8' } response_body ||= %{ @@ -56,7 +56,7 @@ def mock_server_capabilities_response(nextcloud_host, } stub = stub_request( :get, - File.join(nextcloud_host, "/ocs/v2.php/cloud/capabilities") + File.join(nextcloud_host, '/ocs/v2.php/cloud/capabilities') ) if timeout stub.to_timeout @@ -76,7 +76,7 @@ def mock_server_config_check_response(nextcloud_host, response_body: nil) response_code ||= 200 response_headers ||= { - "Content-Type" => "application/json; charset=utf-8" + 'Content-Type' => 'application/json; charset=utf-8' } response_body ||= @@ -88,7 +88,7 @@ def mock_server_config_check_response(nextcloud_host, } stub = stub_request( :get, - File.join(nextcloud_host, "index.php/apps/integration_openproject/check-config") + File.join(nextcloud_host, 'index.php/apps/integration_openproject/check-config') ) if timeout stub.to_timeout @@ -102,21 +102,21 @@ def mock_server_config_check_response(nextcloud_host, end def mock_nextcloud_application_credentials_validation(nextcloud_host, - username: "OpenProject", - password: "Password123", + username: 'OpenProject', + password: 'Password123', timeout: false, response_code: nil, response_headers: nil, response_body: nil) response_code ||= 200 response_headers ||= { - "Content-Type" => "text/html; charset=UTF-8", - "Authorization" => "Basic #{Base64::strict_encode64("#{username}:#{password}")}" + 'Content-Type' => 'text/html; charset=UTF-8', + 'Authorization' => "Basic #{Base64::strict_encode64("#{username}:#{password}")}" } stub = stub_request( :head, - File.join(nextcloud_host, "remote.php/dav") + File.join(nextcloud_host, 'remote.php/dav') ) if timeout stub.to_timeout diff --git a/modules/storages/spec/support/user_permissions_helper.rb b/modules/storages/spec/support/user_permissions_helper.rb index 3626323d1213..0a1ed24d3757 100644 --- a/modules/storages/spec/support/user_permissions_helper.rb +++ b/modules/storages/spec/support/user_permissions_helper.rb @@ -30,13 +30,13 @@ module UserPermissionsHelper def add_permissions(user, *) - role = Role.joins(members: :principal).where("users.id": user).first + role = Role.joins(members: :principal).where('users.id': user).first role.add_permission!(*) user.reload # clear user's project_role_cache end def remove_permissions(user, *) - role = Role.joins(members: :principal).where("users.id": user).first + role = Role.joins(members: :principal).where('users.id': user).first role.remove_permission!(*) user.reload # clear user's project_role_cache end diff --git a/modules/storages/spec/workers/storages/cleanup_uncontainered_file_links_job_spec.rb b/modules/storages/spec/workers/storages/cleanup_uncontainered_file_links_job_spec.rb index f60f3286a663..7f6ee5ad25d2 100644 --- a/modules/storages/spec/workers/storages/cleanup_uncontainered_file_links_job_spec.rb +++ b/modules/storages/spec/workers/storages/cleanup_uncontainered_file_links_job_spec.rb @@ -28,41 +28,43 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe Storages::CleanupUncontaineredFileLinksJob, type: :job do - describe "#perform" do - it "removes uncontainered file_links which are old enough" do - grace_period = 10 - allow(OpenProject::Configuration) - .to receive(:attachments_grace_period) - .and_return(grace_period) + it 'has a schedule set' do + expect(described_class.cron_expression).to eq('06 22 * * *') + end - expect(Storages::FileLink.count).to eq(0) + it 'removes uncontainered file_links which are old enough' do + grace_period = 10 + allow(OpenProject::Configuration) + .to receive(:attachments_grace_period) + .and_return(grace_period) - uncontainered_old = create(:file_link, - container_id: nil, - container_type: nil, - created_at: Time.current - grace_period.minutes - 1.second) - uncontainered_young = create(:file_link, - container_id: nil, - container_type: nil) - containered_old = create(:file_link, - container_id: 1, + expect(Storages::FileLink.count).to eq(0) + + uncontainered_old = create(:file_link, + container_id: nil, + container_type: nil, created_at: Time.current - grace_period.minutes - 1.second) - containered_young = create(:file_link, - container_id: 1) + uncontainered_young = create(:file_link, + container_id: nil, + container_type: nil) + containered_old = create(:file_link, + container_id: 1, + created_at: Time.current - grace_period.minutes - 1.second) + containered_young = create(:file_link, + container_id: 1) - expect(Storages::FileLink.count).to eq(4) + expect(Storages::FileLink.count).to eq(4) - described_class.new.perform + described_class.new.perform - expect(Storages::FileLink.count).to eq(3) - file_link_ids = Storages::FileLink.pluck(:id).sort - expected_file_link_ids = [uncontainered_young.id, containered_old.id, containered_young.id].sort - expect(file_link_ids).to eq(expected_file_link_ids) - expect(file_link_ids).not_to include(uncontainered_old.id) - end + expect(Storages::FileLink.count).to eq(3) + file_link_ids = Storages::FileLink.pluck(:id).sort + expected_file_link_ids = [uncontainered_young.id, containered_old.id, containered_young.id].sort + expect(file_link_ids).to eq(expected_file_link_ids) + expect(file_link_ids).not_to include(uncontainered_old.id) end end diff --git a/modules/storages/spec/workers/storages/manage_nextcloud_integration_cron_job_spec.rb b/modules/storages/spec/workers/storages/manage_nextcloud_integration_cron_job_spec.rb new file mode 100644 index 000000000000..507e361a4ff8 --- /dev/null +++ b/modules/storages/spec/workers/storages/manage_nextcloud_integration_cron_job_spec.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' +require_module_spec_helper + +RSpec.describe Storages::ManageNextcloudIntegrationCronJob, :webmock, type: :job do + it 'has a schedule set' do + expect(described_class.cron_expression).to eq('1 * * * *') + end + + describe '.ensure_scheduled!' do + before { ActiveJob::Base.disable_test_adapter } + + subject { described_class.ensure_scheduled! } + + context 'when there is active nextcloud project storage' do + shared_let(:storage1) { create(:nextcloud_storage, :as_automatically_managed) } + shared_let(:project_storage) { create(:project_storage, :as_automatically_managed, storage: storage1) } + + it 'schedules cron_job if not scheduled' do + expect(described_class.scheduled?).to be(false) + expect(described_class.delayed_job_query.count).to eq(0) + + subject + + expect(described_class.scheduled?).to be(true) + expect(described_class.delayed_job_query.count).to eq(1) + end + + it 'does not schedules cron_job if already scheduled' do + described_class.ensure_scheduled! + expect(described_class.scheduled?).to be(true) + expect(described_class.delayed_job_query.count).to eq(1) + + subject + + expect(described_class.scheduled?).to be(true) + expect(described_class.delayed_job_query.count).to eq(1) + end + end + + context 'when there is no active nextcloud project storage' do + it 'does nothing but removes cron_job' do + described_class.set(cron: described_class.cron_expression).perform_later + expect(described_class.scheduled?).to be(true) + expect(described_class.delayed_job_query.count).to eq(1) + + subject + + expect(described_class.scheduled?).to be(false) + expect(described_class.delayed_job_query.count).to eq(0) + end + end + end + + describe '.perform' do + subject { described_class.new.perform } + + context 'when lock is free' do + let(:storage1) { create(:nextcloud_storage_configured, :as_automatically_managed) } + + it 'responds with true' do + expect(subject).to be(true) + end + + it 'calls GroupFolderPropertiesSyncService for each automatically managed storage' do + storage2 = create(:nextcloud_storage, :as_not_automatically_managed) + storage3 = create(:nextcloud_storage, :as_automatically_managed) + + allow(Storages::NextcloudGroupFolderPropertiesSyncService) + .to receive(:call).with(storage1).and_return(ServiceResult.success) + + expect(subject).to be(true) + + expect(Storages::NextcloudGroupFolderPropertiesSyncService).to have_received(:call).with(storage1).once + expect(Storages::NextcloudGroupFolderPropertiesSyncService).not_to have_received(:call).with(storage2) + expect(Storages::NextcloudGroupFolderPropertiesSyncService).not_to have_received(:call).with(storage3) + end + + it 'marks storage as healthy if sync was successful' do + allow(Storages::NextcloudGroupFolderPropertiesSyncService) + .to receive(:call).with(storage1).and_return(ServiceResult.success) + + Timecop.freeze('2023-03-14T15:17:00Z') do + expect do + subject + storage1.reload + end.to( + change(storage1, :health_changed_at).to(Time.now.utc) + .and(change(storage1, :health_status).from('pending').to('healthy')) + ) + end + end + + it 'marks storage as unhealthy if sync was unsuccessful' do + allow(Storages::NextcloudGroupFolderPropertiesSyncService) + .to receive(:call) + .with(storage1) + .and_return(ServiceResult.failure(errors: Storages::StorageError.new(code: :not_found))) + + Timecop.freeze('2023-03-14T15:17:00Z') do + expect do + subject + storage1.reload + end.to( + change(storage1, :health_changed_at).to(Time.now.utc) + .and(change(storage1, :health_status).from('pending').to('unhealthy')) + .and(change(storage1, :health_reason).from(nil).to('not_found')) + ) + end + end + end + + context 'when lock is unfree' do + it 'responds with false' do + allow(ApplicationRecord).to receive(:with_advisory_lock).and_return(false) + + expect(subject).to be(false) + expect(ApplicationRecord).to have_received(:with_advisory_lock).with( + 'sync_all_group_folders', + timeout_seconds: 0, + transaction: false + ).once + end + end + end +end diff --git a/modules/storages/spec/workers/storages/manage_nextcloud_integration_events_job_spec.rb b/modules/storages/spec/workers/storages/manage_nextcloud_integration_events_job_spec.rb new file mode 100644 index 000000000000..4a2001334264 --- /dev/null +++ b/modules/storages/spec/workers/storages/manage_nextcloud_integration_events_job_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) 2012-2024 the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +require 'spec_helper' +require_module_spec_helper + +RSpec.describe Storages::ManageNextcloudIntegrationEventsJob, type: :job do + describe '.priority' do + it 'has a maximum priority' do + expect(described_class.priority).to eq(7) + end + end + + describe '.debounce' do + context 'when has been debounced by other thread' do + before do + Rails.cache.write(described_class::KEY, Time.current) + end + + it 'does nothing' do + expect { described_class.debounce }.not_to change(enqueued_jobs, :count) + end + end + + context 'when has not been debounced by other thread' do + it 'schedules a job' do + expect { described_class.debounce }.to change(enqueued_jobs, :count).from(0).to(1) + end + + it 'hits cache once when called 1000 times in a short period of time' do + allow(Rails.cache).to receive(:fetch).and_call_original + + expect do + 1000.times { described_class.debounce } + end.to change(enqueued_jobs, :count).from(0).to(1) + + expect(Rails.cache).to have_received(:fetch).once + end + end + end + + describe '#perform' do + it 'responds with true when parent perform responds with true' do + allow(OpenProject::Mutex).to receive(:with_advisory_lock).and_return(true) + allow(described_class).to receive(:debounce) + + expect(described_class.new.perform).to be(true) + + expect(described_class).not_to have_received(:debounce) + end + + it 'debounces itself when parent perform responds with false' do + allow(OpenProject::Mutex).to receive(:with_advisory_lock).and_return(false) + allow(described_class).to receive(:debounce) + + expect(described_class.new.perform).to be(false) + + expect(described_class).to have_received(:debounce).once + end + end +end diff --git a/modules/storages/spec/workers/storages/manage_nextcloud_integration_job_spec.rb b/modules/storages/spec/workers/storages/manage_nextcloud_integration_job_spec.rb deleted file mode 100644 index 7e150dbed67a..000000000000 --- a/modules/storages/spec/workers/storages/manage_nextcloud_integration_job_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -# frozen_string_literal: true - -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -require "spec_helper" -require_module_spec_helper - -RSpec.describe Storages::ManageNextcloudIntegrationJob, :webmock, type: :job do - describe ".debounce" do - context "when has been debounced by other thread" do - before { ActiveJob::Base.disable_test_adapter } - - it "does not change the number of enqueued jobs" do - expect(GoodJob::Job.count).to eq(0) - expect(described_class.perform_later.successfully_enqueued?).to be(true) - expect(described_class.perform_later).to be(false) - expect(GoodJob::Job.count).to eq(1) - - expect { described_class.debounce }.not_to change(GoodJob::Job, :count) - end - end - - context "when has not been debounced by other thread" do - it "schedules a job" do - expect { described_class.debounce }.to change(enqueued_jobs, :count).from(0).to(1) - end - - it "tries to schedule once when called 1000 times in a short period of time" do - expect_any_instance_of(ActiveJob::ConfiguredJob) - .to receive(:perform_later).once.and_call_original - - expect do - 1000.times { described_class.debounce } - end.to change(enqueued_jobs, :count).from(0).to(1) - end - end - end - - describe ".disable_cron_job_if_needed" do - before { ActiveJob::Base.disable_test_adapter } - - subject { described_class.disable_cron_job_if_needed } - - context "when there is an active nextcloud project storage" do - shared_let(:storage1) { create(:nextcloud_storage, :as_automatically_managed) } - shared_let(:project_storage) { create(:project_storage, :as_automatically_managed, storage: storage1) } - - it "enables the cron_job if was disabled before" do - GoodJob::Setting.cron_key_disable(described_class::CRON_JOB_KEY) - - good_job_setting = GoodJob::Setting.first - expect(good_job_setting.key).to eq("cron_keys_disabled") - expect(good_job_setting.value).to eq(["Storages::ManageNextcloudIntegrationJob"]) - - expect { subject }.not_to change(GoodJob::Setting, :count).from(1) - - good_job_setting.reload - expect(good_job_setting.key).to eq("cron_keys_disabled") - expect(good_job_setting.value).to eq([]) - end - - it "does nothing if the cron_job is not disabled" do - expect(GoodJob::Setting.cron_key_enabled?(described_class::CRON_JOB_KEY)).to be(true) - - expect { subject }.not_to change(GoodJob::Setting, :count).from(0) - - expect(GoodJob::Setting.cron_key_enabled?(described_class::CRON_JOB_KEY)).to be(true) - end - end - - context "when there is no active nextcloud project storage" do - it "disables the cron job" do - expect { subject }.to change(GoodJob::Setting, :count).from(0).to(1) - - good_job_setting = GoodJob::Setting.first - expect(good_job_setting.key).to eq("cron_keys_disabled") - expect(good_job_setting.value).to eq(["Storages::ManageNextcloudIntegrationJob"]) - end - end - end - - describe ".perform" do - let(:storage1) { create(:nextcloud_storage_configured, :as_automatically_managed) } - - subject { described_class.new.perform } - - it "calls NextcloudGroupFolderPropertiesSyncService for each automatically managed storage" do - storage2 = create(:nextcloud_storage, :as_not_automatically_managed) - storage3 = create(:nextcloud_storage, :as_automatically_managed) - - allow(Storages::NextcloudGroupFolderPropertiesSyncService) - .to receive(:call).with(storage1).and_return(ServiceResult.success) - - subject - - expect(Storages::NextcloudGroupFolderPropertiesSyncService).to have_received(:call).with(storage1).once - expect(Storages::NextcloudGroupFolderPropertiesSyncService).not_to have_received(:call).with(storage2) - expect(Storages::NextcloudGroupFolderPropertiesSyncService).not_to have_received(:call).with(storage3) - end - - it "marks storage as healthy if sync was successful" do - allow(Storages::NextcloudGroupFolderPropertiesSyncService) - .to receive(:call).with(storage1).and_return(ServiceResult.success) - - Timecop.freeze("2023-03-14T15:17:00Z") do - expect do - subject - storage1.reload - end.to( - change(storage1, :health_changed_at).to(Time.now.utc) - .and(change(storage1, :health_status).from("pending").to("healthy")) - ) - end - end - - it "marks storage as unhealthy if sync was unsuccessful" do - allow(Storages::NextcloudGroupFolderPropertiesSyncService) - .to receive(:call) - .with(storage1) - .and_return(ServiceResult.failure(errors: Storages::StorageError.new(code: :not_found))) - - Timecop.freeze("2023-03-14T15:17:00Z") do - expect do - subject - storage1.reload - end.to( - change(storage1, :health_changed_at).to(Time.now.utc) - .and(change(storage1, :health_status).from("pending").to("unhealthy")) - .and(change(storage1, :health_reason).from(nil).to("not_found")) - ) - end - end - end -end diff --git a/modules/team_planner/app/components/team_planner/add_button_component.rb b/modules/team_planner/app/components/team_planner/add_button_component.rb index a824a55a6546..3804d9a6f83b 100644 --- a/modules/team_planner/app/components/team_planner/add_button_component.rb +++ b/modules/team_planner/app/components/team_planner/add_button_component.rb @@ -44,15 +44,15 @@ def dynamic_path end def id - "add-team-planner-button" + 'add-team-planner-button' end def accessibility_label_text - I18n.t("team_planner.label_create_new_team_planner") + I18n.t('team_planner.label_create_new_team_planner') end def label_text - t(:"team_planner.label_team_planner") + t(:'team_planner.label_team_planner') end end end diff --git a/modules/team_planner/app/components/team_planner/overview/table_component.rb b/modules/team_planner/app/components/team_planner/overview/table_component.rb index f6fce2c8575d..8a6858511fd7 100644 --- a/modules/team_planner/app/components/team_planner/overview/table_component.rb +++ b/modules/team_planner/app/components/team_planner/overview/table_component.rb @@ -34,13 +34,13 @@ class TableComponent < ::TableComponent sortable_columns :name, :project_name, :created_at def initial_sort_correlation - ["queries.name", "asc"] + ['queries.name', 'asc'] end def sortable_columns_correlation - super.merge(name: "queries.name", - project_name: "projects.name", - created_at: "queries.created_at") + super.merge(name: 'queries.name', + project_name: 'projects.name', + created_at: 'queries.created_at') end def paginated? diff --git a/modules/team_planner/app/components/team_planner/row_component.rb b/modules/team_planner/app/components/team_planner/row_component.rb index 4294462b31c0..c9d625b672bb 100644 --- a/modules/team_planner/app/components/team_planner/row_component.rb +++ b/modules/team_planner/app/components/team_planner/row_component.rb @@ -56,13 +56,13 @@ def button_links def delete_link if table.current_user.allowed_in_project?(:manage_team_planner, project) link_to( - "", + '', project_team_planner_path(project, query.id), - class: "spot-link icon icon-delete", + class: 'spot-link icon icon-delete', method: :delete, data: { confirm: I18n.t(:text_are_you_sure), - "test-selector": "team-planner-remove-#{query.id}" + 'test-selector': "team-planner-remove-#{query.id}" }, title: t(:button_delete) ) diff --git a/modules/team_planner/app/components/team_planner/table_component.rb b/modules/team_planner/app/components/team_planner/table_component.rb index 42b6277934ff..d7b4df5e462c 100644 --- a/modules/team_planner/app/components/team_planner/table_component.rb +++ b/modules/team_planner/app/components/team_planner/table_component.rb @@ -37,9 +37,9 @@ def sortable? def headers [ - ["name", { caption: I18n.t(:label_name) }], - ["assignees", { caption: I18n.t("team_planner.label_assignees") }], - ["created_at", { caption: I18n.t("attributes.created_at") }] + ['name', { caption: I18n.t(:label_name) }], + ['assignees', { caption: I18n.t('team_planner.label_assignees') }], + ['created_at', { caption: I18n.t('attributes.created_at') }] ] end end diff --git a/modules/team_planner/app/controllers/team_planner/team_planner_controller.rb b/modules/team_planner/app/controllers/team_planner/team_planner_controller.rb index aecacbec217b..c4ff4690694d 100644 --- a/modules/team_planner/app/controllers/team_planner/team_planner_controller.rb +++ b/modules/team_planner/app/controllers/team_planner/team_planner_controller.rb @@ -17,7 +17,7 @@ def index def overview @views = visible_plans - render layout: "global" + render layout: 'global' end def new; end @@ -37,7 +37,7 @@ def create end def show - render layout: "angular/angular" + render layout: 'angular/angular' end def upsale; end @@ -94,11 +94,11 @@ def visible_plans(project = nil) .includes(:project) .joins(:views) .references(:projects) - .where("views.type" => "team_planner") - .order("queries.name ASC") + .where('views.type' => 'team_planner') + .order('queries.name ASC') if project - query = query.where("queries.project_id" => project.id) + query = query.where('queries.project_id' => project.id) else allowed_projects = Project.allowed_to(User.current, :view_team_planner) query = query.where(queries: { project: allowed_projects }) diff --git a/modules/team_planner/app/services/team_planner/views/global_create_service.rb b/modules/team_planner/app/services/team_planner/views/global_create_service.rb index 8c43fdd47194..d099700ca30c 100644 --- a/modules/team_planner/app/services/team_planner/views/global_create_service.rb +++ b/modules/team_planner/app/services/team_planner/views/global_create_service.rb @@ -34,7 +34,7 @@ class GlobalCreateService < ::Views::GlobalCreateService private def view_type - "team_planner" + 'team_planner' end end end diff --git a/modules/team_planner/app/views/team_planner/team_planner/new.html.erb b/modules/team_planner/app/views/team_planner/team_planner/new.html.erb index 19f56dc6dfac..2789ec04a676 100644 --- a/modules/team_planner/app/views/team_planner/team_planner/new.html.erb +++ b/modules/team_planner/app/views/team_planner/team_planner/new.html.erb @@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details. <%= toolbar title: t('team_planner.label_new_team_planner') %> <%= labelled_tabular_form_for @view, url: { controller: '/team_planner/team_planner', action: 'create' }, :html => {:id => 'team-planner-form'} do |f| -%> <%= render :partial => 'form', :locals => {:f => f} %> - <%= styled_button_tag t(:button_create), class: '-primary' %> + <%= styled_button_tag t(:button_create), class: '-highlight' %> <%= link_to t(:button_cancel), { controller: 'team_planner/team_planner', action: 'overview' }, class: 'button' %> <% end %> diff --git a/modules/team_planner/config/locales/crowdin/js-af.yml b/modules/team_planner/config/locales/crowdin/js-af.yml index 6a513735a315..cde2a8aee752 100644 --- a/modules/team_planner/config/locales/crowdin/js-af.yml +++ b/modules/team_planner/config/locales/crowdin/js-af.yml @@ -12,8 +12,6 @@ af: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-ar.yml b/modules/team_planner/config/locales/crowdin/js-ar.yml index 7242a923df80..f59fbcccd641 100644 --- a/modules/team_planner/config/locales/crowdin/js-ar.yml +++ b/modules/team_planner/config/locales/crowdin/js-ar.yml @@ -12,8 +12,6 @@ ar: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-az.yml b/modules/team_planner/config/locales/crowdin/js-az.yml index 6bddab1a00a2..392a3ef22835 100644 --- a/modules/team_planner/config/locales/crowdin/js-az.yml +++ b/modules/team_planner/config/locales/crowdin/js-az.yml @@ -12,8 +12,6 @@ az: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-be.yml b/modules/team_planner/config/locales/crowdin/js-be.yml index 67d14201817e..a40cfab1fa3b 100644 --- a/modules/team_planner/config/locales/crowdin/js-be.yml +++ b/modules/team_planner/config/locales/crowdin/js-be.yml @@ -12,8 +12,6 @@ be: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-bg.yml b/modules/team_planner/config/locales/crowdin/js-bg.yml index 602750cfb684..eb07582e53c1 100644 --- a/modules/team_planner/config/locales/crowdin/js-bg.yml +++ b/modules/team_planner/config/locales/crowdin/js-bg.yml @@ -12,8 +12,6 @@ bg: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Днес' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-ca.yml b/modules/team_planner/config/locales/crowdin/js-ca.yml index de88017b4620..133c4e5dc4d3 100644 --- a/modules/team_planner/config/locales/crowdin/js-ca.yml +++ b/modules/team_planner/config/locales/crowdin/js-ca.yml @@ -12,8 +12,6 @@ ca: remove_assignee: 'Elimina assignats' two_weeks: '2 setmanes' one_week: '1 setmana' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Setmana laboral' today: 'Avui' drag_here_to_remove: 'Arrossega aquí per eliminar l''usuari assignat i les dates d''inici i final.' diff --git a/modules/team_planner/config/locales/crowdin/js-ckb-IR.yml b/modules/team_planner/config/locales/crowdin/js-ckb-IR.yml index 94669ed48855..ae3669ddeea6 100644 --- a/modules/team_planner/config/locales/crowdin/js-ckb-IR.yml +++ b/modules/team_planner/config/locales/crowdin/js-ckb-IR.yml @@ -12,8 +12,6 @@ ckb-IR: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-cs.yml b/modules/team_planner/config/locales/crowdin/js-cs.yml index 04c7da07b66f..8115fbf799f7 100644 --- a/modules/team_planner/config/locales/crowdin/js-cs.yml +++ b/modules/team_planner/config/locales/crowdin/js-cs.yml @@ -12,8 +12,6 @@ cs: remove_assignee: 'Odstranit řešitele' two_weeks: '2 týdny' one_week: '1 týden' - four_weeks: '4 týdny' - eight_weeks: '8 týdnů' work_week: 'Pracovní týden' today: 'Dnes' drag_here_to_remove: 'Přetažením sem odstraníte pověřenou osobu a datum začátku a ukončení.' diff --git a/modules/team_planner/config/locales/crowdin/js-da.yml b/modules/team_planner/config/locales/crowdin/js-da.yml index 776de6c3e61f..71282d0fe90c 100644 --- a/modules/team_planner/config/locales/crowdin/js-da.yml +++ b/modules/team_planner/config/locales/crowdin/js-da.yml @@ -12,8 +12,6 @@ da: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-de.yml b/modules/team_planner/config/locales/crowdin/js-de.yml index 9df5aab46c72..2f9ab1664491 100644 --- a/modules/team_planner/config/locales/crowdin/js-de.yml +++ b/modules/team_planner/config/locales/crowdin/js-de.yml @@ -12,8 +12,6 @@ de: remove_assignee: 'Zugewiesenen Benutzer entfernen' two_weeks: '2 Wochen' one_week: '1 Woche' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Arbeitswoche' today: 'Heute' drag_here_to_remove: 'Hierher ziehen, um den zugewiesenen Benutzer zu entfernen und die Start- und Enddaten zu löschen.' diff --git a/modules/team_planner/config/locales/crowdin/js-el.yml b/modules/team_planner/config/locales/crowdin/js-el.yml index 96efc089149b..433ced75bedf 100644 --- a/modules/team_planner/config/locales/crowdin/js-el.yml +++ b/modules/team_planner/config/locales/crowdin/js-el.yml @@ -12,8 +12,6 @@ el: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Σήμερα ' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-eo.yml b/modules/team_planner/config/locales/crowdin/js-eo.yml index ef131aa9acba..2ee592fdc160 100644 --- a/modules/team_planner/config/locales/crowdin/js-eo.yml +++ b/modules/team_planner/config/locales/crowdin/js-eo.yml @@ -12,8 +12,6 @@ eo: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-es.yml b/modules/team_planner/config/locales/crowdin/js-es.yml index f303e2293625..2d1fac06d457 100644 --- a/modules/team_planner/config/locales/crowdin/js-es.yml +++ b/modules/team_planner/config/locales/crowdin/js-es.yml @@ -12,8 +12,6 @@ es: remove_assignee: 'Eliminar asignado' two_weeks: '2 semanas' one_week: '1 semana' - four_weeks: '4 semanas' - eight_weeks: '8 semanas' work_week: 'Semana laboral' today: 'Hoy' drag_here_to_remove: 'Arrastre aquí para quitar el usuario asignado y las fechas de inicio y finalización.' diff --git a/modules/team_planner/config/locales/crowdin/js-et.yml b/modules/team_planner/config/locales/crowdin/js-et.yml index 83cfdeaa2a55..308ed274f5b7 100644 --- a/modules/team_planner/config/locales/crowdin/js-et.yml +++ b/modules/team_planner/config/locales/crowdin/js-et.yml @@ -12,8 +12,6 @@ et: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-eu.yml b/modules/team_planner/config/locales/crowdin/js-eu.yml index d6ce9f425276..1f5c16258c1a 100644 --- a/modules/team_planner/config/locales/crowdin/js-eu.yml +++ b/modules/team_planner/config/locales/crowdin/js-eu.yml @@ -12,8 +12,6 @@ eu: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-fa.yml b/modules/team_planner/config/locales/crowdin/js-fa.yml index 57132f30507b..7b5d42a9776c 100644 --- a/modules/team_planner/config/locales/crowdin/js-fa.yml +++ b/modules/team_planner/config/locales/crowdin/js-fa.yml @@ -12,8 +12,6 @@ fa: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-fi.yml b/modules/team_planner/config/locales/crowdin/js-fi.yml index dded465f0dc6..860005221778 100644 --- a/modules/team_planner/config/locales/crowdin/js-fi.yml +++ b/modules/team_planner/config/locales/crowdin/js-fi.yml @@ -12,8 +12,6 @@ fi: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Tänään' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-fil.yml b/modules/team_planner/config/locales/crowdin/js-fil.yml index 4a74933a4466..8131a52c77b1 100644 --- a/modules/team_planner/config/locales/crowdin/js-fil.yml +++ b/modules/team_planner/config/locales/crowdin/js-fil.yml @@ -12,8 +12,6 @@ fil: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-fr.yml b/modules/team_planner/config/locales/crowdin/js-fr.yml index cf37b555424a..e036e1530f9f 100644 --- a/modules/team_planner/config/locales/crowdin/js-fr.yml +++ b/modules/team_planner/config/locales/crowdin/js-fr.yml @@ -12,8 +12,6 @@ fr: remove_assignee: 'Supprimer l''assignation' two_weeks: '2 semaines' one_week: '1 semaine' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Semaine de travail' today: 'Aujourd''hui' drag_here_to_remove: 'Faites glisser ici pour supprimer le responsable et les dates de début et de fin.' diff --git a/modules/team_planner/config/locales/crowdin/js-he.yml b/modules/team_planner/config/locales/crowdin/js-he.yml index d7669cba50e0..607f74c342cb 100644 --- a/modules/team_planner/config/locales/crowdin/js-he.yml +++ b/modules/team_planner/config/locales/crowdin/js-he.yml @@ -12,8 +12,6 @@ he: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-hi.yml b/modules/team_planner/config/locales/crowdin/js-hi.yml index 30ba48aad5d3..eb08cb6709dd 100644 --- a/modules/team_planner/config/locales/crowdin/js-hi.yml +++ b/modules/team_planner/config/locales/crowdin/js-hi.yml @@ -12,8 +12,6 @@ hi: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-hr.yml b/modules/team_planner/config/locales/crowdin/js-hr.yml index 5f0350f867c5..b02a2533825f 100644 --- a/modules/team_planner/config/locales/crowdin/js-hr.yml +++ b/modules/team_planner/config/locales/crowdin/js-hr.yml @@ -12,8 +12,6 @@ hr: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-hu.yml b/modules/team_planner/config/locales/crowdin/js-hu.yml index d8a69d7bd543..5ceac7e094c5 100644 --- a/modules/team_planner/config/locales/crowdin/js-hu.yml +++ b/modules/team_planner/config/locales/crowdin/js-hu.yml @@ -12,8 +12,6 @@ hu: remove_assignee: 'Megbízott eltávolítása' two_weeks: '2 hét' one_week: '1 hét' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Ma' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-id.yml b/modules/team_planner/config/locales/crowdin/js-id.yml index 5a016a77856e..175276e521ed 100644 --- a/modules/team_planner/config/locales/crowdin/js-id.yml +++ b/modules/team_planner/config/locales/crowdin/js-id.yml @@ -12,8 +12,6 @@ id: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-it.yml b/modules/team_planner/config/locales/crowdin/js-it.yml index 0e5aa13cb3cf..6c1b42c7b2a7 100644 --- a/modules/team_planner/config/locales/crowdin/js-it.yml +++ b/modules/team_planner/config/locales/crowdin/js-it.yml @@ -12,8 +12,6 @@ it: remove_assignee: 'Rimuovi assegnatario' two_weeks: '2 settimane' one_week: '1 settimana' - four_weeks: '4 settimane' - eight_weeks: '8 settimane' work_week: 'Settimana lavorativa' today: 'Oggi' drag_here_to_remove: 'Trascina qui per rimuovere l''assegnatario e le date di inizio e fine.' diff --git a/modules/team_planner/config/locales/crowdin/js-ja.yml b/modules/team_planner/config/locales/crowdin/js-ja.yml index afff219ce7cd..0a67cf6cb94a 100644 --- a/modules/team_planner/config/locales/crowdin/js-ja.yml +++ b/modules/team_planner/config/locales/crowdin/js-ja.yml @@ -12,8 +12,6 @@ ja: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: '今日' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-ka.yml b/modules/team_planner/config/locales/crowdin/js-ka.yml index fa6b060cd961..503f1a1151ae 100644 --- a/modules/team_planner/config/locales/crowdin/js-ka.yml +++ b/modules/team_planner/config/locales/crowdin/js-ka.yml @@ -12,8 +12,6 @@ ka: remove_assignee: 'Remove assignee' two_weeks: '2 კვირა' one_week: '1 კვირა' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'სამუშაო კვირა' today: 'დღეს' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-kk.yml b/modules/team_planner/config/locales/crowdin/js-kk.yml index 954cf6ca563d..98d3cd285812 100644 --- a/modules/team_planner/config/locales/crowdin/js-kk.yml +++ b/modules/team_planner/config/locales/crowdin/js-kk.yml @@ -12,8 +12,6 @@ kk: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-ko.yml b/modules/team_planner/config/locales/crowdin/js-ko.yml index d15e3ceb745d..37be053b5168 100644 --- a/modules/team_planner/config/locales/crowdin/js-ko.yml +++ b/modules/team_planner/config/locales/crowdin/js-ko.yml @@ -12,8 +12,6 @@ ko: remove_assignee: '담당자 제거' two_weeks: '2주' one_week: '1주' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: '근무 주' today: '오늘' drag_here_to_remove: '담당자와 시작 날짜 및 종료 날짜를 제거하려면 여기로 드래그하세요.' diff --git a/modules/team_planner/config/locales/crowdin/js-lt.yml b/modules/team_planner/config/locales/crowdin/js-lt.yml index 4212797c6c8e..34de9d988d09 100644 --- a/modules/team_planner/config/locales/crowdin/js-lt.yml +++ b/modules/team_planner/config/locales/crowdin/js-lt.yml @@ -12,8 +12,6 @@ lt: remove_assignee: 'Išimti paskirtąjį' two_weeks: '2-savaitės' one_week: '1-savaitė' - four_weeks: '4-savaitės' - eight_weeks: '8-savaitės' work_week: 'Darbo savaitė' today: 'Šiandien' drag_here_to_remove: 'Pertempkite čia, kad išimtumėte paskirtąjį ir pradžios bei pabaigos datas.' diff --git a/modules/team_planner/config/locales/crowdin/js-lv.yml b/modules/team_planner/config/locales/crowdin/js-lv.yml index 389b8cdf7e2b..bf24a419d8ff 100644 --- a/modules/team_planner/config/locales/crowdin/js-lv.yml +++ b/modules/team_planner/config/locales/crowdin/js-lv.yml @@ -12,8 +12,6 @@ lv: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-mn.yml b/modules/team_planner/config/locales/crowdin/js-mn.yml index 12daab690f49..f7caa435099a 100644 --- a/modules/team_planner/config/locales/crowdin/js-mn.yml +++ b/modules/team_planner/config/locales/crowdin/js-mn.yml @@ -12,8 +12,6 @@ mn: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-ms.yml b/modules/team_planner/config/locales/crowdin/js-ms.yml index 457c4074e2f2..58d22685a088 100644 --- a/modules/team_planner/config/locales/crowdin/js-ms.yml +++ b/modules/team_planner/config/locales/crowdin/js-ms.yml @@ -12,8 +12,6 @@ ms: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-ne.yml b/modules/team_planner/config/locales/crowdin/js-ne.yml index 46b800b5d775..70f6c4690116 100644 --- a/modules/team_planner/config/locales/crowdin/js-ne.yml +++ b/modules/team_planner/config/locales/crowdin/js-ne.yml @@ -12,8 +12,6 @@ ne: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-nl.yml b/modules/team_planner/config/locales/crowdin/js-nl.yml index 85fae6b826e5..cd415ca5f839 100644 --- a/modules/team_planner/config/locales/crowdin/js-nl.yml +++ b/modules/team_planner/config/locales/crowdin/js-nl.yml @@ -12,8 +12,6 @@ nl: remove_assignee: 'Verwijder verantwoordelijke' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Werkweek' today: 'Vandaag' drag_here_to_remove: 'Sleep hierheen om taakontvanger en start- en einddata te verwijderen.' diff --git a/modules/team_planner/config/locales/crowdin/js-no.yml b/modules/team_planner/config/locales/crowdin/js-no.yml index 926db38ff055..584b43b10359 100644 --- a/modules/team_planner/config/locales/crowdin/js-no.yml +++ b/modules/team_planner/config/locales/crowdin/js-no.yml @@ -12,8 +12,6 @@ remove_assignee: 'Fjern deltaker' two_weeks: 'Andre uke' one_week: 'Første uke' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Arbeidsuke' today: 'I dag' drag_here_to_remove: 'Dra hit for å fjerne deltker og start og sluttdato.' diff --git a/modules/team_planner/config/locales/crowdin/js-pl.yml b/modules/team_planner/config/locales/crowdin/js-pl.yml index 7ae7f8144cb8..1188ffd36a8b 100644 --- a/modules/team_planner/config/locales/crowdin/js-pl.yml +++ b/modules/team_planner/config/locales/crowdin/js-pl.yml @@ -12,8 +12,6 @@ pl: remove_assignee: 'Usuń osobę przypisaną' two_weeks: '2 tygodnie' one_week: '1 tydzień' - four_weeks: '4 tygodnie' - eight_weeks: '8 tygodni' work_week: 'Tydzień roboczy' today: 'Dzisiaj' drag_here_to_remove: 'Przeciągnij tutaj, aby usunąć przypisaną osobę oraz daty rozpoczęcia i zakończenia.' diff --git a/modules/team_planner/config/locales/crowdin/js-pt-BR.yml b/modules/team_planner/config/locales/crowdin/js-pt-BR.yml index 0958589eee05..4b78496fcd9c 100644 --- a/modules/team_planner/config/locales/crowdin/js-pt-BR.yml +++ b/modules/team_planner/config/locales/crowdin/js-pt-BR.yml @@ -12,8 +12,6 @@ pt: remove_assignee: 'Remover responsável' two_weeks: '2 semanas' one_week: '1 semana' - four_weeks: '4 semanas' - eight_weeks: '8 semanas' work_week: 'Semana de trabalho' today: 'Hoje' drag_here_to_remove: 'Arraste aqui para remover o responsável e as datas de início e término.' diff --git a/modules/team_planner/config/locales/crowdin/js-pt-PT.yml b/modules/team_planner/config/locales/crowdin/js-pt-PT.yml index c89ddb8bf191..560997823d7a 100644 --- a/modules/team_planner/config/locales/crowdin/js-pt-PT.yml +++ b/modules/team_planner/config/locales/crowdin/js-pt-PT.yml @@ -12,8 +12,6 @@ pt: remove_assignee: 'Remover responsável' two_weeks: '2 semanas' one_week: '1 semana' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Semana de trabalho' today: 'Hoje' drag_here_to_remove: 'Arraste aqui para remover o responsável e as datas de início e término.' diff --git a/modules/team_planner/config/locales/crowdin/js-ro.yml b/modules/team_planner/config/locales/crowdin/js-ro.yml index 3a01cf765381..f5e4ed694bf2 100644 --- a/modules/team_planner/config/locales/crowdin/js-ro.yml +++ b/modules/team_planner/config/locales/crowdin/js-ro.yml @@ -12,8 +12,6 @@ ro: remove_assignee: 'Înlăturați responsabilul' two_weeks: '2-săptămână' one_week: '1-săptămână' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Săptămână de lucru' today: 'Azi' drag_here_to_remove: 'Trageți aici pentru a elimina responsabilul și a începe și a termina datele.' diff --git a/modules/team_planner/config/locales/crowdin/js-ru.yml b/modules/team_planner/config/locales/crowdin/js-ru.yml index 4ebbff4f71d9..feab4e8939a6 100644 --- a/modules/team_planner/config/locales/crowdin/js-ru.yml +++ b/modules/team_planner/config/locales/crowdin/js-ru.yml @@ -12,8 +12,6 @@ ru: remove_assignee: 'Удалить ответственного' two_weeks: '2 недели' one_week: '1 неделя' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Рабочая неделя' today: 'Сегодня' drag_here_to_remove: 'Перетащите сюда, чтобы удалить ответственного, а также даты начала и окончания.' diff --git a/modules/team_planner/config/locales/crowdin/js-rw.yml b/modules/team_planner/config/locales/crowdin/js-rw.yml index 8277afa9ba0c..111640d1e747 100644 --- a/modules/team_planner/config/locales/crowdin/js-rw.yml +++ b/modules/team_planner/config/locales/crowdin/js-rw.yml @@ -12,8 +12,6 @@ rw: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-si.yml b/modules/team_planner/config/locales/crowdin/js-si.yml index a1137c778b0a..30fb7ea56360 100644 --- a/modules/team_planner/config/locales/crowdin/js-si.yml +++ b/modules/team_planner/config/locales/crowdin/js-si.yml @@ -12,8 +12,6 @@ si: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-sk.yml b/modules/team_planner/config/locales/crowdin/js-sk.yml index 9297e53dc2bd..a6df38309ded 100644 --- a/modules/team_planner/config/locales/crowdin/js-sk.yml +++ b/modules/team_planner/config/locales/crowdin/js-sk.yml @@ -12,8 +12,6 @@ sk: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Dnes' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-sl.yml b/modules/team_planner/config/locales/crowdin/js-sl.yml index 5402801ada95..4216d8574b2e 100644 --- a/modules/team_planner/config/locales/crowdin/js-sl.yml +++ b/modules/team_planner/config/locales/crowdin/js-sl.yml @@ -12,8 +12,6 @@ sl: remove_assignee: 'Odstrani prevzemnika' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Danes' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-sr.yml b/modules/team_planner/config/locales/crowdin/js-sr.yml index 4b25f8ef823d..902aad9ee303 100644 --- a/modules/team_planner/config/locales/crowdin/js-sr.yml +++ b/modules/team_planner/config/locales/crowdin/js-sr.yml @@ -12,8 +12,6 @@ sr: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-sv.yml b/modules/team_planner/config/locales/crowdin/js-sv.yml index 5510c6fa81ae..e1d0a707a31b 100644 --- a/modules/team_planner/config/locales/crowdin/js-sv.yml +++ b/modules/team_planner/config/locales/crowdin/js-sv.yml @@ -12,8 +12,6 @@ sv: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-th.yml b/modules/team_planner/config/locales/crowdin/js-th.yml index 49e73aa6cf82..a37084a91382 100644 --- a/modules/team_planner/config/locales/crowdin/js-th.yml +++ b/modules/team_planner/config/locales/crowdin/js-th.yml @@ -12,8 +12,6 @@ th: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-tr.yml b/modules/team_planner/config/locales/crowdin/js-tr.yml index ae47060a5788..0059afd2cc35 100644 --- a/modules/team_planner/config/locales/crowdin/js-tr.yml +++ b/modules/team_planner/config/locales/crowdin/js-tr.yml @@ -12,8 +12,6 @@ tr: remove_assignee: 'Atananı kaldır' two_weeks: '2 hafta' one_week: '1 hafta' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Çalışma Haftası' today: 'Bugün' drag_here_to_remove: 'Atanan kişiyi ve başlangıç ve bitiş tarihlerini kaldırmak için buraya sürükleyin.' diff --git a/modules/team_planner/config/locales/crowdin/js-uk.yml b/modules/team_planner/config/locales/crowdin/js-uk.yml index 44598c6b0254..b0fafb69e522 100644 --- a/modules/team_planner/config/locales/crowdin/js-uk.yml +++ b/modules/team_planner/config/locales/crowdin/js-uk.yml @@ -12,8 +12,6 @@ uk: remove_assignee: 'Вилучити виконавця' two_weeks: '2 тижні' one_week: '1 тиждень' - four_weeks: '4 тижні' - eight_weeks: '8 тижнів' work_week: 'Робочий тиждень' today: 'Сьогодні' drag_here_to_remove: 'Перетягніть сюди, щоб вилучити виконавця, а також дати початку й закінчення.' diff --git a/modules/team_planner/config/locales/crowdin/js-uz.yml b/modules/team_planner/config/locales/crowdin/js-uz.yml index bc6897f6363a..cdb26a57e436 100644 --- a/modules/team_planner/config/locales/crowdin/js-uz.yml +++ b/modules/team_planner/config/locales/crowdin/js-uz.yml @@ -12,8 +12,6 @@ uz: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-vi.yml b/modules/team_planner/config/locales/crowdin/js-vi.yml index d1fb2f683c49..562b2c1768f3 100644 --- a/modules/team_planner/config/locales/crowdin/js-vi.yml +++ b/modules/team_planner/config/locales/crowdin/js-vi.yml @@ -12,8 +12,6 @@ vi: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/crowdin/js-zh-CN.yml b/modules/team_planner/config/locales/crowdin/js-zh-CN.yml index 7c8cba732398..9a5f6fece813 100644 --- a/modules/team_planner/config/locales/crowdin/js-zh-CN.yml +++ b/modules/team_planner/config/locales/crowdin/js-zh-CN.yml @@ -12,8 +12,6 @@ zh-CN: remove_assignee: '移除受理人' two_weeks: '2 周' one_week: '1 周' - four_weeks: '4 周' - eight_weeks: '8 周' work_week: '工作周' today: '今天' drag_here_to_remove: '拖动到此处可移除受理人及开始日期和结束日期。' diff --git a/modules/team_planner/config/locales/crowdin/js-zh-TW.yml b/modules/team_planner/config/locales/crowdin/js-zh-TW.yml index 341c62640f36..58c94b625091 100644 --- a/modules/team_planner/config/locales/crowdin/js-zh-TW.yml +++ b/modules/team_planner/config/locales/crowdin/js-zh-TW.yml @@ -12,8 +12,6 @@ zh-TW: remove_assignee: '刪除執行者' two_weeks: '兩週' one_week: '1週' - four_weeks: '4 週' - eight_weeks: '8 週' work_week: '工作週' today: '今日' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/locales/js-en.yml b/modules/team_planner/config/locales/js-en.yml index 1b6d9007d6f9..f6f6bec45409 100644 --- a/modules/team_planner/config/locales/js-en.yml +++ b/modules/team_planner/config/locales/js-en.yml @@ -12,8 +12,6 @@ en: remove_assignee: 'Remove assignee' two_weeks: '2-week' one_week: '1-week' - four_weeks: '4-week' - eight_weeks: '8-week' work_week: 'Work week' today: 'Today' drag_here_to_remove: 'Drag here to remove assignee and start and end dates.' diff --git a/modules/team_planner/config/routes.rb b/modules/team_planner/config/routes.rb index 2f694e154101..8922404f2b9f 100644 --- a/modules/team_planner/config/routes.rb +++ b/modules/team_planner/config/routes.rb @@ -1,26 +1,26 @@ Rails.application.routes.draw do resources :team_planners, - controller: "team_planner/team_planner", + controller: 'team_planner/team_planner', only: %i[create] do collection do - get "/", to: "team_planner/team_planner#overview" - get "/new", to: "team_planner/team_planner#new" - get "/upsale", to: "team_planner/team_planner#upsale", as: :upsale + get '/', to: 'team_planner/team_planner#overview' + get '/new', to: 'team_planner/team_planner#new' + get '/upsale', to: 'team_planner/team_planner#upsale', as: :upsale end end - scope "projects/:project_id", as: "project" do + scope 'projects/:project_id', as: 'project' do resources :team_planners, - controller: "team_planner/team_planner", + controller: 'team_planner/team_planner', only: %i[index destroy], as: :team_planners do collection do - get "/upsale", to: "team_planner/team_planner#upsale", as: :upsale - get "/new", to: "team_planner/team_planner#show", as: :new + get '/upsale', to: 'team_planner/team_planner#upsale', as: :upsale + get '/new', to: 'team_planner/team_planner#show', as: :new end member do - get "(/*state)" => "team_planner/team_planner#show", as: "" + get '(/*state)' => 'team_planner/team_planner#show', as: '' end end end diff --git a/modules/team_planner/lib/open_project/team_planner.rb b/modules/team_planner/lib/open_project/team_planner.rb index d84f5da7e26a..693b37db10e3 100644 --- a/modules/team_planner/lib/open_project/team_planner.rb +++ b/modules/team_planner/lib/open_project/team_planner.rb @@ -28,6 +28,6 @@ module OpenProject module TeamPlanner - require "open_project/team_planner/engine" + require 'open_project/team_planner/engine' end end diff --git a/modules/team_planner/lib/open_project/team_planner/engine.rb b/modules/team_planner/lib/open_project/team_planner/engine.rb index c60fdf5fbc57..ede95f00f612 100644 --- a/modules/team_planner/lib/open_project/team_planner/engine.rb +++ b/modules/team_planner/lib/open_project/team_planner/engine.rb @@ -32,18 +32,18 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-team_planner", - author_url: "https://www.openproject.org", + register 'openproject-team_planner', + author_url: 'https://www.openproject.org', bundled: true, settings: {} do project_module :team_planner_view, dependencies: :work_package_tracking, enterprise_feature: true do permission :view_team_planner, - { "team_planner/team_planner": %i[index show upsale overview] }, + { 'team_planner/team_planner': %i[index show upsale overview] }, permissible_on: :project, dependencies: %i[view_work_packages], contract_actions: { team_planner: %i[read] } permission :manage_team_planner, - { "team_planner/team_planner": %i[index show new create destroy upsale] }, + { 'team_planner/team_planner': %i[index show new create destroy upsale] }, permissible_on: :project, dependencies: %i[view_team_planner add_work_packages @@ -60,42 +60,42 @@ class Engine < ::Rails::Engine menu :global_menu, :team_planners, - { controller: "/team_planner/team_planner", action: :overview }, - caption: :"team_planner.label_team_planner_plural", + { controller: '/team_planner/team_planner', action: :overview }, + caption: :'team_planner.label_team_planner_plural', before: :boards, after: :calendar_view, - icon: "team-planner", + icon: 'team-planner', if: should_render_global_menu_item, - enterprise_feature: "team_planner_view" + enterprise_feature: 'team_planner_view' menu :project_menu, :team_planner_view, - { controller: "/team_planner/team_planner", action: :index }, - caption: :"team_planner.label_team_planner_plural", + { controller: '/team_planner/team_planner', action: :index }, + caption: :'team_planner.label_team_planner_plural', after: :work_packages, - icon: "team-planner", - enterprise_feature: "team_planner_view" + icon: 'team-planner', + enterprise_feature: 'team_planner_view' menu :project_menu, :team_planner_menu, - { controller: "/team_planner/team_planner", action: :index }, + { controller: '/team_planner/team_planner', action: :index }, parent: :team_planner_view, - partial: "team_planner/team_planner/menu", + partial: 'team_planner/team_planner/menu', last: true, - caption: :"team_planner.label_team_planner_plural" + caption: :'team_planner.label_team_planner_plural' menu :top_menu, - :team_planners, { controller: "/team_planner/team_planner", action: :overview }, + :team_planners, { controller: '/team_planner/team_planner', action: :overview }, context: :modules, - caption: :"team_planner.label_team_planner_plural", + caption: :'team_planner.label_team_planner_plural', before: :boards, after: :calendar_view, - icon: "team-planner", + icon: 'team-planner', if: should_render_global_menu_item, - enterprise_feature: "team_planner_view" + enterprise_feature: 'team_planner_view' end add_view :TeamPlanner, - contract_strategy: "TeamPlanner::Views::ContractStrategy" + contract_strategy: 'TeamPlanner::Views::ContractStrategy' end end diff --git a/modules/team_planner/lib/openproject-team_planner.rb b/modules/team_planner/lib/openproject-team_planner.rb index 3da00db4f605..1a33de790065 100644 --- a/modules/team_planner/lib/openproject-team_planner.rb +++ b/modules/team_planner/lib/openproject-team_planner.rb @@ -1 +1 @@ -require "open_project/team_planner" +require 'open_project/team_planner' diff --git a/modules/team_planner/openproject-team_planner.gemspec b/modules/team_planner/openproject-team_planner.gemspec index 41eef6c2fbe8..edb46f1e78fc 100644 --- a/modules/team_planner/openproject-team_planner.gemspec +++ b/modules/team_planner/openproject-team_planner.gemspec @@ -1,12 +1,12 @@ Gem::Specification.new do |s| - s.name = "openproject-team_planner" - s.version = "1.0.0" - s.authors = "OpenProject GmbH" - s.email = "info@openproject.com" - s.summary = "OpenProject Team Planner" - s.description = "Provides team planner views" - s.license = "GPLv3" + s.name = 'openproject-team_planner' + s.version = '1.0.0' + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.summary = 'OpenProject Team Planner' + s.description = 'Provides team planner views' + s.license = 'GPLv3' - s.files = Dir["{app,config,db,lib}/**/*"] - s.metadata["rubygems_mfa_required"] = "true" + s.files = Dir['{app,config,db,lib}/**/*'] + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/team_planner/spec/contracts/views/create_contract_team_planner_spec.rb b/modules/team_planner/spec/contracts/views/create_contract_team_planner_spec.rb index 2d17f3bd81ea..1cabdc8f6244 100644 --- a/modules/team_planner/spec/contracts/views/create_contract_team_planner_spec.rb +++ b/modules/team_planner/spec/contracts/views/create_contract_team_planner_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" -require "contracts/views/shared_contract_examples" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' +require 'contracts/views/shared_contract_examples' RSpec.describe Views::CreateContract do - it_behaves_like "view contract", true do + it_behaves_like 'view contract', true do let(:view) do View.new(query: view_query, type: view_type) end let(:view_type) do - "team_planner" + 'team_planner' end let(:permissions) { %i[view_work_packages save_queries manage_team_planner] } @@ -45,23 +45,23 @@ described_class.new(view, current_user) end - describe "validation" do - context "with the type being nil" do + describe 'validation' do + context 'with the type being nil' do let(:view_type) { nil } - it_behaves_like "contract is invalid", type: :inclusion + it_behaves_like 'contract is invalid', type: :inclusion end - context "with the type not being one of the configured" do - let(:view_type) { "blubs" } + context 'with the type not being one of the configured' do + let(:view_type) { 'blubs' } - it_behaves_like "contract is invalid", type: :inclusion + it_behaves_like 'contract is invalid', type: :inclusion end - context "without the :manage_team_planner permission" do + context 'without the :manage_team_planner permission' do let(:permissions) { %i[view_work_packages save_queries] } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end end end diff --git a/modules/team_planner/spec/features/onboarding/team_planner_onboarding_tour_spec.rb b/modules/team_planner/spec/features/onboarding/team_planner_onboarding_tour_spec.rb index d01ce86a0338..5f3359d9822f 100644 --- a/modules/team_planner/spec/features/onboarding/team_planner_onboarding_tour_spec.rb +++ b/modules/team_planner/spec/features/onboarding/team_planner_onboarding_tour_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../../support/onboarding/onboarding_steps" +require 'spec_helper' +require_relative '../../support/onboarding/onboarding_steps' -RSpec.describe "team planner onboarding tour", +RSpec.describe 'team planner onboarding tour', :js, with_cuprite: false, with_ee: %i[team_planner_view], @@ -37,12 +37,12 @@ # of the JS code rely on something triggering the Angular change detection. # This is usually done by the notification polling, but we don't want to wait with_settings: { notifications_polling_interval: 1_000 } do - let(:next_button) { find(".enjoyhint_next_btn") } + let(:next_button) { find('.enjoyhint_next_btn') } let(:demo_project) do create(:project, - name: "Demo project", - identifier: "demo-project", + name: 'Demo project', + identifier: 'demo-project', public: true, enabled_module_names: %w[work_package_tracking gantt wiki team_planner_view]) end @@ -62,7 +62,7 @@ due_date: Time.zone.today) end - let(:query) { create(:query, user:, project: demo_project, public: true, name: "Team planner") } + let(:query) { create(:query, user:, project: demo_project, public: true, name: 'Team planner') } let(:team_plan) do create(:view_team_planner, query:, @@ -83,8 +83,8 @@ page.execute_script("window.sessionStorage.clear();") end - context "as a new user" do - it "I see the team planner onboarding tour in the demo project" do + context 'as a new user' do + it 'I see the team planner onboarding tour in the demo project' do # Set the tour parameter so that we can start on the wp page visit "/projects/#{demo_project.identifier}/work_packages?start_onboarding_tour=true" diff --git a/modules/team_planner/spec/features/query_handling_spec.rb b/modules/team_planner/spec/features/query_handling_spec.rb index 7388ee6f9f8f..6a9417c99e9e 100644 --- a/modules/team_planner/spec/features/query_handling_spec.rb +++ b/modules/team_planner/spec/features/query_handling_spec.rb @@ -28,11 +28,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/pages/team_planner" -require_relative "../../../../spec/features/views/shared_examples" +require 'spec_helper' +require_relative '../support/pages/team_planner' +require_relative '../../../../spec/features/views/shared_examples' -RSpec.describe "Team planner query handling", :js, with_ee: %i[team_planner_view] do +RSpec.describe 'Team planner query handling', :js, with_ee: %i[team_planner_view] do shared_let(:type_task) { create(:type_task) } shared_let(:type_bug) { create(:type_bug) } shared_let(:project) do @@ -60,7 +60,7 @@ assigned_to: user, start_date: Time.zone.today - 1.day, due_date: Time.zone.today + 1.day, - subject: "A task for the user") + subject: 'A task for the user') end shared_let(:bug) do create(:work_package, @@ -69,7 +69,7 @@ assigned_to: user, start_date: Time.zone.today - 1.day, due_date: Time.zone.today + 1.day, - subject: "A bug for the user") + subject: 'A bug for the user') end let(:team_planner) { Pages::TeamPlanner.new project } @@ -92,11 +92,11 @@ end end - it "allows saving the team planner" do + it 'allows saving the team planner' do filters.expect_filter_count("1") filters.open - filters.add_filter_by("Type", "is (OR)", [type_bug.name]) + filters.add_filter_by('Type', 'is (OR)', [type_bug.name]) filters.expect_filter_count("2") @@ -109,35 +109,35 @@ query_title.press_save_button - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_create")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_create')) end - it "shows only team planner queries" do + it 'shows only team planner queries' do # Go to team planner where no query is shown, only the create option query_menu.expect_no_menu_entry - expect(page).to have_test_selector("team-planner--create-button") + expect(page).to have_test_selector('team-planner--create-button') # Change filter filters.open - filters.add_filter_by("Type", "is (OR)", [type_bug.name]) + filters.add_filter_by('Type', 'is (OR)', [type_bug.name]) filters.expect_filter_count("2") # Save current filters query_title.expect_changed - query_title.rename "I am your Query" - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_create")) + query_title.rename 'I am your Query' + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_create')) # The saved query appears in the side menu... - query_menu.expect_menu_entry "I am your Query" + query_menu.expect_menu_entry 'I am your Query' # .. but not in the work packages module work_package_page.visit! - query_menu.expect_menu_entry_not_visible "I am your Query" + query_menu.expect_menu_entry_not_visible 'I am your Query' end - it_behaves_like "module specific query view management" do + it_behaves_like 'module specific query view management' do let(:module_page) { team_planner } - let(:default_name) { "Unnamed team planner" } + let(:default_name) { 'Unnamed team planner' } let(:initial_filter_count) { 1 } end end diff --git a/modules/team_planner/spec/features/shared_context.rb b/modules/team_planner/spec/features/shared_context.rb index ba86b0b64b3d..bdb1ad3b363a 100644 --- a/modules/team_planner/spec/features/shared_context.rb +++ b/modules/team_planner/spec/features/shared_context.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/pages/team_planner" +require 'spec_helper' +require_relative '../support/pages/team_planner' -RSpec.shared_context "with team planner full access" do +RSpec.shared_context 'with team planner full access' do shared_let(:project) do create(:project) end diff --git a/modules/team_planner/spec/features/team_planner_add_existing_work_packages_spec.rb b/modules/team_planner/spec/features/team_planner_add_existing_work_packages_spec.rb index e7149f7aedd2..38e6afc02a93 100644 --- a/modules/team_planner/spec/features/team_planner_add_existing_work_packages_spec.rb +++ b/modules/team_planner/spec/features/team_planner_add_existing_work_packages_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" -require_relative "../support/components/add_existing_pane" +require 'spec_helper' +require_relative 'shared_context' +require_relative '../support/components/add_existing_pane' -RSpec.describe "Team planner add existing work packages", :js do - include_context "with team planner full access" +RSpec.describe 'Team planner add existing work packages', :js do + include_context 'with team planner full access' let(:closed_status) { create(:status, is_closed: true) } let(:start_of_week) { Time.zone.today.beginning_of_week(:sunday) } let!(:other_user) do create(:user, - firstname: "Bernd", + firstname: 'Bernd', member_with_permissions: { project => %w[view_work_packages view_team_planner] }) end let!(:first_wp) do create(:work_package, project:, - subject: "Task 1", + subject: 'Task 1', assigned_to: user, start_date: start_of_week.next_occurring(:tuesday), due_date: start_of_week.next_occurring(:thursday)) @@ -53,7 +53,7 @@ let!(:second_wp) do create(:work_package, project:, - subject: "Task 2", + subject: 'Task 2', parent: first_wp, assigned_to: other_user, start_date: 10.days.from_now, @@ -62,14 +62,14 @@ let!(:third_wp) do create(:work_package, project:, - subject: "TA Aufgabe 3", + subject: 'TA Aufgabe 3', status: closed_status) end let(:add_existing_pane) { Components::AddExistingPane.new } let(:filters) { Components::WorkPackages::Filters.new } - context "with full permissions", with_ee: %i[team_planner_view] do + context 'with full permissions', with_ee: %i[team_planner_view] do before do team_planner.visit! @@ -86,17 +86,17 @@ add_existing_pane.expect_empty end - context "with a removable item" do + context 'with a removable item' do let!(:second_wp) do create(:work_package, project:, - subject: "Task 2", + subject: 'Task 2', assigned_to: other_user, start_date: 10.days.from_now, due_date: 12.days.from_now) end - it "shows work packages removed from the team planner" do + it 'shows work packages removed from the team planner' do team_planner.within_lane(user) do team_planner.expect_event first_wp end @@ -113,9 +113,9 @@ end end - it "allows to click cards to open split view when open" do + it 'allows to click cards to open split view when open' do # Search for a work package - add_existing_pane.search "Task" + add_existing_pane.search 'Task' add_existing_pane.expect_result second_wp # Open first wp @@ -130,9 +130,9 @@ expect(page).to have_current_path /\/details\/#{second_wp.id}/ end - it "allows to add work packages via drag&drop from the left hand shortlist" do + it 'allows to add work packages via drag&drop from the left hand shortlist' do # Search for a work package - add_existing_pane.search "Task" + add_existing_pane.search 'Task' add_existing_pane.expect_result second_wp sleep 2 @@ -149,7 +149,7 @@ expect(second_wp.assigned_to_id).to eq(user.id) # Search for another work package - add_existing_pane.search "Ta" + add_existing_pane.search 'Ta' add_existing_pane.expect_result third_wp sleep 2 @@ -170,9 +170,9 @@ split_view.expect_open end - it "the search applies the filter from the team planner" do + it 'the search applies the filter from the team planner' do # Search for a work package - add_existing_pane.search "Task" + add_existing_pane.search 'Task' add_existing_pane.expect_result second_wp add_existing_pane.expect_result third_wp, visible: false @@ -181,23 +181,23 @@ filters.expect_filter_count 1 filters.open - filters.expect_filter_by "Status", "is not empty", nil + filters.expect_filter_by 'Status', 'is not empty', nil # Change the filter for the whole page - filters.set_filter "Status", "open", nil + filters.set_filter 'Status', 'open', nil # Expect the filter to auto update add_existing_pane.expect_result second_wp add_existing_pane.expect_result third_wp, visible: false end - context "with a subproject" do + context 'with a subproject' do let!(:sub_project) do - create(:project, name: "Child", parent: project, enabled_module_names: %w[work_package_tracking]) + create(:project, name: 'Child', parent: project, enabled_module_names: %w[work_package_tracking]) end let!(:sub_work_package) do - create(:work_package, subject: "Subtask", project: sub_project) + create(:work_package, subject: 'Subtask', project: sub_project) end let(:permissions) do @@ -214,9 +214,9 @@ let(:dropdown) { Components::ProjectIncludeComponent.new } - it "applies the project include filter" do + it 'applies the project include filter' do # Search for the work package in the child project - add_existing_pane.search "Subtask" + add_existing_pane.search 'Subtask' add_existing_pane.expect_empty add_existing_pane.expect_result sub_work_package, visible: false @@ -229,7 +229,7 @@ dropdown.expect_checkbox(project.id, true) dropdown.expect_checkbox(sub_project.id, false) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 1 dropdown.toggle! @@ -240,7 +240,7 @@ dropdown.expect_checkbox(project.id, true) dropdown.expect_checkbox(sub_project.id, true) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 2 @@ -250,15 +250,15 @@ end end - context "without permission to edit" do + context 'without permission to edit' do current_user { other_user } before do team_planner.visit! end - it "does not show the button to add existing work packages" do - expect(page).not_to have_test_selector("op-team-planner--add-existing-toggle") + it 'does not show the button to add existing work packages' do + expect(page).not_to have_test_selector('op-team-planner--add-existing-toggle') add_existing_pane.expect_closed end end diff --git a/modules/team_planner/spec/features/team_planner_context_menu_spec.rb b/modules/team_planner/spec/features/team_planner_context_menu_spec.rb index 45cb6f9b1a99..6813a415f088 100644 --- a/modules/team_planner/spec/features/team_planner_context_menu_spec.rb +++ b/modules/team_planner/spec/features/team_planner_context_menu_spec.rb @@ -1,12 +1,12 @@ -require "spec_helper" -require_relative "shared_context" -require "features/work_packages/table/context_menu/context_menu_shared_examples" +require 'spec_helper' +require_relative 'shared_context' +require 'features/work_packages/table/context_menu/context_menu_shared_examples' -RSpec.describe "Work package table context menu", +RSpec.describe 'Work package table context menu', :js, with_ee: %i[team_planner_view], with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' let!(:work_package) do create(:work_package, @@ -37,7 +37,7 @@ end end - it_behaves_like "provides a single WP context menu" do + it_behaves_like 'provides a single WP context menu' do let(:open_context_menu) do -> { team_planner.visit! diff --git a/modules/team_planner/spec/features/team_planner_create_spec.rb b/modules/team_planner/spec/features/team_planner_create_spec.rb index cb98f3814024..7bc0eee95ce5 100644 --- a/modules/team_planner/spec/features/team_planner_create_spec.rb +++ b/modules/team_planner/spec/features/team_planner_create_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner create new work package", :js, with_ee: %i[team_planner_view] do - include_context "with team planner full access" +RSpec.describe 'Team planner create new work package', :js, with_ee: %i[team_planner_view] do + include_context 'with team planner full access' let(:type_task) { create(:type_task) } let!(:status) { create(:default_status) } @@ -40,8 +40,8 @@ project.types << type_task end - shared_examples "can create a new work package" do - it "creates a new work package for the given user" do + shared_examples 'can create a new work package' do + it 'creates a new work package for the given user' do start_of_week = Time.zone.today.beginning_of_week(:sunday) team_planner.expect_assignee(user) split_create = team_planner.add_item "/api/v3/users/#{user.id}", @@ -49,19 +49,19 @@ start_of_week.iso8601 subject = split_create.edit_field(:subject) - subject.set_value "Newly planned task" + subject.set_value 'Newly planned task' split_create.save! - split_create.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_create")) + split_create.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_create')) split_create.expect_attributes( - combinedDate: start_of_week.strftime("%m/%d/%Y"), + combinedDate: start_of_week.strftime('%m/%d/%Y'), assignee: user.name ) wp = WorkPackage.last - expect(wp.subject).to eq "Newly planned task" + expect(wp.subject).to eq 'Newly planned task' expect(wp.start_date).to eq start_of_week expect(wp.due_date).to eq start_of_week @@ -71,7 +71,7 @@ end end - context "with a single user" do + context 'with a single user' do before do team_planner.visit! @@ -80,14 +80,14 @@ team_planner.add_assignee user.name end - it_behaves_like "can create a new work package" + it_behaves_like 'can create a new work package' end - context "with multiple users added" do + context 'with multiple users added' do let!(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_permissions: { project => %w[ view_work_packages edit_work_packages add_work_packages view_team_planner manage_team_planner @@ -98,8 +98,8 @@ let!(:third_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_permissions: { project => %w[ view_work_packages edit_work_packages add_work_packages view_team_planner manage_team_planner @@ -120,6 +120,6 @@ team_planner.add_assignee user.name end - it_behaves_like "can create a new work package" + it_behaves_like 'can create a new work package' end end diff --git a/modules/team_planner/spec/features/team_planner_dates_spec.rb b/modules/team_planner/spec/features/team_planner_dates_spec.rb index 4712b00eecea..50d521d2b9f3 100644 --- a/modules/team_planner/spec/features/team_planner_dates_spec.rb +++ b/modules/team_planner/spec/features/team_planner_dates_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner working days", :js, +RSpec.describe 'Team planner working days', :js, with_ee: %i[team_planner_view], with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' - context "with week days defined" do + context 'with week days defined' do let!(:week_days) { week_with_saturday_and_sunday_as_weekend } it 'hides sat and sun in the "Work week" view andd renders sat and sun as non working in the "1-week" view' do @@ -44,37 +44,37 @@ team_planner.add_assignee user.name # Initially, in the "Work week" view, non working days are hidden - expect(page).to have_css(".fc-day-mon") - expect(page).to have_css(".fc-day-tue") - expect(page).to have_css(".fc-day-wed") - expect(page).to have_css(".fc-day-thu") - expect(page).to have_css(".fc-day-fri") + expect(page).to have_css('.fc-day-mon') + expect(page).to have_css('.fc-day-tue') + expect(page).to have_css('.fc-day-wed') + expect(page).to have_css('.fc-day-thu') + expect(page).to have_css('.fc-day-fri') - expect(page).to have_no_css(".fc-day-sat") - expect(page).to have_no_css(".fc-day-sun") + expect(page).to have_no_css('.fc-day-sat') + expect(page).to have_no_css('.fc-day-sun') # In the "1-week" view, non working days are displayed but marked - team_planner.switch_view_mode "1-week" + team_planner.switch_view_mode '1-week' - expect(page).to have_css(".fc-day-sat.fc-non-working-day", minimum: 1, wait: 10) - expect(page).to have_css(".fc-day-sun.fc-non-working-day", minimum: 1) + expect(page).to have_css('.fc-day-sat.fc-non-working-day', minimum: 1, wait: 10) + expect(page).to have_css('.fc-day-sun.fc-non-working-day', minimum: 1) - expect(page).to have_no_css(".fc-day-mon.fc-non-working-day") - expect(page).to have_no_css(".fc-day-tue.fc-non-working-day") - expect(page).to have_no_css(".fc-day-wed.fc-non-working-day") - expect(page).to have_no_css(".fc-day-thu.fc-non-working-day") - expect(page).to have_no_css(".fc-day-fri.fc-non-working-day") + expect(page).to have_no_css('.fc-day-mon.fc-non-working-day') + expect(page).to have_no_css('.fc-day-tue.fc-non-working-day') + expect(page).to have_no_css('.fc-day-wed.fc-non-working-day') + expect(page).to have_no_css('.fc-day-thu.fc-non-working-day') + expect(page).to have_no_css('.fc-day-fri.fc-non-working-day') - find(".fc-next-button").click + find('.fc-next-button').click - expect(page).to have_css(".fc-day-sat.fc-non-working-day", minimum: 1, wait: 10) - expect(page).to have_css(".fc-day-sun.fc-non-working-day", minimum: 1) + expect(page).to have_css('.fc-day-sat.fc-non-working-day', minimum: 1, wait: 10) + expect(page).to have_css('.fc-day-sun.fc-non-working-day', minimum: 1) - expect(page).to have_no_css(".fc-day-mon.fc-non-working-day") - expect(page).to have_no_css(".fc-day-tue.fc-non-working-day") - expect(page).to have_no_css(".fc-day-wed.fc-non-working-day") - expect(page).to have_no_css(".fc-day-thu.fc-non-working-day") - expect(page).to have_no_css(".fc-day-fri.fc-non-working-day") + expect(page).to have_no_css('.fc-day-mon.fc-non-working-day') + expect(page).to have_no_css('.fc-day-tue.fc-non-working-day') + expect(page).to have_no_css('.fc-day-wed.fc-non-working-day') + expect(page).to have_no_css('.fc-day-thu.fc-non-working-day') + expect(page).to have_no_css('.fc-day-fri.fc-non-working-day') end end end diff --git a/modules/team_planner/spec/features/team_planner_error_handling_spec.rb b/modules/team_planner/spec/features/team_planner_error_handling_spec.rb index b08930fb21ef..923ed7167655 100644 --- a/modules/team_planner/spec/features/team_planner_error_handling_spec.rb +++ b/modules/team_planner/spec/features/team_planner_error_handling_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner error handling", :js, +RSpec.describe 'Team planner error handling', :js, with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' let!(:work_package) do create(:work_package, @@ -51,7 +51,7 @@ let(:type) { create(:type, custom_fields: [custom_field]) } - context "with full permissions", with_ee: %i[team_planner_view] do + context 'with full permissions', with_ee: %i[team_planner_view] do before do project.types << type project.save! @@ -65,7 +65,7 @@ end end - it "cannot change the wp because of required fields not being set" do + it 'cannot change the wp because of required fields not being set' do custom_field.is_required = true custom_field.save! @@ -80,10 +80,10 @@ end end - it "cannot change the wp because of conflicting modifications" do + it 'cannot change the wp because of conflicting modifications' do # Try to move the wp retry_block do - wp_strip = page.find(".fc-event", text: work_package.subject) + wp_strip = page.find('.fc-event', text: work_package.subject) page .driver @@ -105,7 +105,7 @@ .perform end - team_planner.expect_toast(type: :error, message: I18n.t("api_v3.errors.code_409")) + team_planner.expect_toast(type: :error, message: I18n.t('api_v3.errors.code_409')) work_package.reload expect(work_package.start_date).to eq(Time.zone.today.beginning_of_week.next_occurring(:tuesday)) diff --git a/modules/team_planner/spec/features/team_planner_global_create_spec.rb b/modules/team_planner/spec/features/team_planner_global_create_spec.rb index d523e7332dff..f369d1f28bf5 100644 --- a/modules/team_planner/spec/features/team_planner_global_create_spec.rb +++ b/modules/team_planner/spec/features/team_planner_global_create_spec.rb @@ -28,43 +28,43 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team Planner", - "Creating a view from a Global Context", +RSpec.describe 'Team Planner', + 'Creating a view from a Global Context', :js, :with_cuprite, with_ee: %i[team_planner_view] do - include_context "with team planner full access" + include_context 'with team planner full access' - context "within the overview page" do + context 'within the overview page' do before do visit team_planners_path end - context "when clicking on the create button" do + context 'when clicking on the create button' do before do team_planner.click_on_create_button end - it "navigates to the global create form" do + it 'navigates to the global create form' do expect(page).to have_current_path(new_team_planners_path) - expect(page).to have_content I18n.t("team_planner.label_new_team_planner") + expect(page).to have_content I18n.t('team_planner.label_new_team_planner') end end end - context "within the global create page" do + context 'within the global create page' do before do visit new_team_planners_path end - context "with all fields set" do + context 'with all fields set' do before do wait_for_reload # Halt until the project autocompleter is ready - team_planner.set_title("Gotham Renewal") + team_planner.set_title('Gotham Renewal') team_planner.set_project(project) team_planner.set_public team_planner.set_favoured @@ -73,15 +73,15 @@ wait_for_reload end - it "creates a view and redirects me to it" do + it 'creates a view and redirects me to it' do expect(page).to have_text(I18n.t(:notice_successful_create)) expect(page).to have_current_path(project_team_planner_path(project, Query.last), ignore_query: true) - expect(page).to have_text("Gotham Renewal") + expect(page).to have_text('Gotham Renewal') end end - context "when missing a required field" do - describe "title" do + context 'when missing a required field' do + describe 'title' do before do wait_for_reload # Halt until the project autocompleter is ready @@ -89,7 +89,7 @@ team_planner.click_on_submit end - it "renders a required attribute validation error" do + it 'renders a required attribute validation error' do expect(Query.all).to be_empty # Required HTML attribute just warns @@ -97,15 +97,15 @@ end end - describe "project_id" do + describe 'project_id' do before do - team_planner.set_title("Gotham Renewal") + team_planner.set_title('Gotham Renewal') team_planner.click_on_submit wait_for_reload end - it "renders a required attribute validation error" do + it 'renders a required attribute validation error' do expect(Query.all).to be_empty expect(page).to have_text("Project can't be blank.") @@ -113,13 +113,13 @@ end end - describe "cancel button" do + describe 'cancel button' do context "when it's clicked" do before do team_planner.click_on_cancel_button end - it "navigates back to the overview page" do + it 'navigates back to the overview page' do expect(page).to have_current_path(team_planners_path) end end diff --git a/modules/team_planner/spec/features/team_planner_index_spec.rb b/modules/team_planner/spec/features/team_planner_index_spec.rb index 067fbb09ec3e..f0db27a51432 100644 --- a/modules/team_planner/spec/features/team_planner_index_spec.rb +++ b/modules/team_planner/spec/features/team_planner_index_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner index", :js, :with_cuprite, with_ee: %i[team_planner_view] do +RSpec.describe 'Team planner index', :js, :with_cuprite, with_ee: %i[team_planner_view] do shared_let(:project) do create(:project) end @@ -45,7 +45,7 @@ end shared_let(:user_with_limited_permissions) do create(:user, - firstname: "Bernd", + firstname: 'Bernd', member_with_permissions: { project => %w[view_work_packages view_team_planner] }) end @@ -58,24 +58,24 @@ visit project_team_planners_path(project) end - it "shows a create button" do + it 'shows a create button' do team_planner.expect_create_button end - it "can create an action through the sidebar" do - find_test_selector("team-planner--create-button").click + it 'can create an action through the sidebar' do + find_test_selector('team-planner--create-button').click team_planner.expect_no_toaster team_planner.expect_title end - context "with no views" do - it "shows an empty index action" do + context 'with no views' do + it 'shows an empty index action' do team_planner.expect_no_views_rendered end end - context "with existing views" do + context 'with existing views' do shared_let(:query) do create(:public_query, user: user_with_full_permissions, project:) end @@ -97,19 +97,19 @@ create(:view_team_planner, query: private_query) end - context "as a user with full permissions within a project" do + context 'as a user with full permissions within a project' do let(:current_user) { user_with_full_permissions } - it "shows views" do + it 'shows views' do team_planner.expect_views_rendered(query, private_query, other_query) end - it "shows management buttons" do + it 'shows management buttons' do team_planner.expect_delete_buttons_for(query, private_query, other_query) end - context "and as the author of a private view" do - it "shows my private view" do + context 'and as the author of a private view' do + it 'shows my private view' do team_planner.expect_views_rendered(query, private_query, other_query) team_planner.expect_delete_buttons_for(query, private_query, other_query) @@ -117,15 +117,15 @@ end end - context "as a user with limited permissions within a project" do + context 'as a user with limited permissions within a project' do let(:current_user) { user_with_limited_permissions } - it "does not show the management buttons" do + it 'does not show the management buttons' do team_planner.expect_no_create_button team_planner.expect_no_delete_buttons_for(query, other_query) end - it "shows public views only" do + it 'shows public views only' do team_planner.expect_views_rendered(query, other_query) end end diff --git a/modules/team_planner/spec/features/team_planner_menu_spec.rb b/modules/team_planner/spec/features/team_planner_menu_spec.rb index 0732a7378215..a7377ee05e28 100644 --- a/modules/team_planner/spec/features/team_planner_menu_spec.rb +++ b/modules/team_planner/spec/features/team_planner_menu_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Team planner Menu Item", :js, :with_cuprite do +RSpec.describe 'Team planner Menu Item', :js, :with_cuprite do shared_let(:project) do create(:project, enabled_module_names: %w[work_package_tracking team_planner_view]) end @@ -47,77 +47,77 @@ ] }) end - context "within the global menu" do + context 'within the global menu' do before do login_as user_without_rights visit root_path - within "#main-menu" do - click_link "Team planners" + within '#main-menu' do + click_link 'Team planners' end end - context "when EE enabled", with_ee: %i[team_planner_view] do - it "navigates to the global index page" do + context 'when EE enabled', with_ee: %i[team_planner_view] do + it 'navigates to the global index page' do expect(page).to have_current_path(team_planners_path) end end end - context "within the project side menu" do - context "as a user that does not have create rights" do + context 'within the project side menu' do + context 'as a user that does not have create rights' do current_user { user_without_rights } - context "when EE disabled" do - it "does not show the create team planner option" do + context 'when EE disabled' do + it 'does not show the create team planner option' do visit project_path(project) - within "#main-menu" do - click_link "Team planners" + within '#main-menu' do + click_link 'Team planners' end - expect(page).not_to have_test_selector("team-planner--create-button") + expect(page).not_to have_test_selector('team-planner--create-button') end end - context "when EE enabled", with_ee: %i[team_planner_view] do - it "does not show the create team planner option" do + context 'when EE enabled', with_ee: %i[team_planner_view] do + it 'does not show the create team planner option' do visit project_path(project) - within "#main-menu" do - click_link "Team planners" + within '#main-menu' do + click_link 'Team planners' end - expect(page).not_to have_test_selector("team-planner--create-button") + expect(page).not_to have_test_selector('team-planner--create-button') end end end - context "as a user that has create rights" do + context 'as a user that has create rights' do current_user { user_with_rights } - context "when EE disabled" do - it "does not show the create team planner option" do + context 'when EE disabled' do + it 'does not show the create team planner option' do visit project_path(project) - within "#main-menu" do - click_link "Team planners" + within '#main-menu' do + click_link 'Team planners' end - expect(page).not_to have_test_selector("team-planner--create-button") + expect(page).not_to have_test_selector('team-planner--create-button') end end - context "when EE enabled", with_ee: %i[team_planner_view] do - it "shows the create team planner option" do + context 'when EE enabled', with_ee: %i[team_planner_view] do + it 'shows the create team planner option' do visit project_path(project) - within "#main-menu" do - click_link "Team planners" + within '#main-menu' do + click_link 'Team planners' end - expect(page).to have_test_selector("team-planner--create-button") + expect(page).to have_test_selector('team-planner--create-button') end end end diff --git a/modules/team_planner/spec/features/team_planner_overview_spec.rb b/modules/team_planner/spec/features/team_planner_overview_spec.rb index c48758d8d251..4f72fd148952 100644 --- a/modules/team_planner/spec/features/team_planner_overview_spec.rb +++ b/modules/team_planner/spec/features/team_planner_overview_spec.rb @@ -29,17 +29,17 @@ # ++ # -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner overview", +RSpec.describe 'Team planner overview', :with_cuprite, with_ee: %i[team_planner_view] do # The order the Projects are created in is important. By naming `project` alphanumerically # after `other_project`, we can ensure that subsequent specs that assert sorting is # correct for the right reasons (sorting by Project name and not id) - shared_let(:project) { create(:project, name: "Project 2") } - shared_let(:other_project) { create(:project, name: "Project 1") } + shared_let(:project) { create(:project, name: 'Project 2') } + shared_let(:other_project) { create(:project, name: 'Project 1') } shared_let(:admin) { create(:admin) } shared_let(:user_with_full_permissions) do @@ -53,7 +53,7 @@ end shared_let(:user_with_limited_permissions) do create(:user, - firstname: "Bernd", + firstname: 'Bernd', member_with_permissions: { project => %w[view_work_packages view_team_planner] }) end @@ -66,23 +66,23 @@ visit team_planners_path end - it "renders a global menu with its item selected" do - within "#main-menu" do - expect(page).to have_css ".selected", text: "Team planners" + it 'renders a global menu with its item selected' do + within '#main-menu' do + expect(page).to have_css '.selected', text: 'Team planners' end end - it "shows a create button" do + it 'shows a create button' do team_planner.expect_create_button end - context "with no views" do - it "shows an empty overview action" do + context 'with no views' do + it 'shows an empty overview action' do team_planner.expect_no_views_rendered end end - context "with existing views" do + context 'with existing views' do shared_let(:query) do create(:public_query, user: user_with_full_permissions, project:) end @@ -111,27 +111,27 @@ create(:view_team_planner, query: other_project_query) end - context "as an admin" do + context 'as an admin' do let(:current_user) { admin } - it "shows those views" do + it 'shows those views' do team_planner.expect_views_rendered(query, other_query, other_project_query) team_planner.expect_no_delete_buttons_for(query, other_query, other_project_query) end end - context "as a user with full permissions within a project" do + context 'as a user with full permissions within a project' do let(:current_user) { user_with_full_permissions } - it "shows views in projects the user is a member of" do + it 'shows views in projects the user is a member of' do team_planner.expect_views_rendered(query, private_query, other_query) team_planner.expect_no_delete_buttons_for(query, private_query, other_query) end - context "and as the author of a private view" do - it "shows my private view" do + context 'and as the author of a private view' do + it 'shows my private view' do team_planner.expect_views_rendered(query, private_query, other_query) team_planner.expect_no_delete_buttons_for(query, private_query, other_query) @@ -139,36 +139,36 @@ end end - context "as a user with limited permissions within a project" do + context 'as a user with limited permissions within a project' do let(:current_user) { user_with_limited_permissions } - it "does not show the management buttons" do + it 'does not show the management buttons' do team_planner.expect_no_create_button team_planner.expect_no_delete_buttons_for(query, other_query) end - it "shows views in projects the user is a member of" do + it 'shows views in projects the user is a member of' do team_planner.expect_views_rendered(query, other_query) end end - describe "sorting" do + describe 'sorting' do let(:current_user) { admin } - it "allows sorting by all columns" do + it 'allows sorting by all columns' do # Initial sort is Name ASC # We can assert this by expecting the order to be # 1. query # 2. other_query # 3. other_project_query - aggregate_failures "Sorting by Name" do + aggregate_failures 'Sorting by Name' do team_planner.expect_views_listed_in_order(query, other_query, other_project_query) - team_planner.click_to_sort_by("Name") + team_planner.click_to_sort_by('Name') team_planner.expect_views_listed_in_order(other_project_query, other_query, query) end - aggregate_failures "Sorting by Project" do - team_planner.click_to_sort_by("Project") + aggregate_failures 'Sorting by Project' do + team_planner.click_to_sort_by('Project') # Sorting is performed on multiple columns at a time, taking into account # previous sorting criteria and using the latest clicked column as # the first column in the +ORDER BY+ clause and previously sorted by columns after. @@ -180,14 +180,14 @@ # visual feedback of all columns currently being taken into account for # sorting. team_planner.expect_views_listed_in_order(other_project_query, other_query, query) - team_planner.click_to_sort_by("Project") + team_planner.click_to_sort_by('Project') team_planner.expect_views_listed_in_order(other_query, query, other_project_query) end - aggregate_failures "Sorting by Created on" do - team_planner.click_to_sort_by("Created on") + aggregate_failures 'Sorting by Created on' do + team_planner.click_to_sort_by('Created on') team_planner.expect_views_listed_in_order(query, other_query, other_project_query) - team_planner.click_to_sort_by("Created on") + team_planner.click_to_sort_by('Created on') team_planner.expect_views_listed_in_order(other_project_query, other_query, query) end end diff --git a/modules/team_planner/spec/features/team_planner_project_include_spec.rb b/modules/team_planner/spec/features/team_planner_project_include_spec.rb index 42c0856d2ef3..3d5a42ad9a7c 100644 --- a/modules/team_planner/spec/features/team_planner_project_include_spec.rb +++ b/modules/team_planner/spec/features/team_planner_project_include_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/project_include/project_include_shared_examples" -require_relative "../support/pages/team_planner" +require 'spec_helper' +require 'features/work_packages/project_include/project_include_shared_examples' +require_relative '../support/pages/team_planner' -RSpec.describe "Team planner project include", :js, with_ee: %i[team_planner_view] do +RSpec.describe 'Team planner project include', :js, with_ee: %i[team_planner_view] do shared_let(:enabled_modules) { %w[work_package_tracking team_planner_view] } shared_let(:permissions) do %w[view_work_packages edit_work_packages add_work_packages @@ -38,17 +38,17 @@ save_queries manage_public_queries] end - it_behaves_like "has a project include dropdown" do + it_behaves_like 'has a project include dropdown' do let(:work_package_view) { Pages::TeamPlanner.new(project) } let(:dropdown) { Components::ProjectIncludeComponent.new } - it "correctly filters work packages by project" do + it 'correctly filters work packages by project' do dropdown.expect_count 1 # Make sure the filter gets set once dropdown.toggle! dropdown.expect_open - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed work_package_view.expect_empty_state @@ -79,7 +79,7 @@ dropdown.toggle! dropdown.toggle_checkbox(sub_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_count 1 work_package_view.within_lane(user) do @@ -90,7 +90,7 @@ dropdown.toggle! dropdown.toggle_checkbox(other_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_count 2 work_package_view.within_lane(other_user) do diff --git a/modules/team_planner/spec/features/team_planner_remove_event_spec.rb b/modules/team_planner/spec/features/team_planner_remove_event_spec.rb index 620b1df7caa0..ff9fa67f6203 100644 --- a/modules/team_planner/spec/features/team_planner_remove_event_spec.rb +++ b/modules/team_planner/spec/features/team_planner_remove_event_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" -require_relative "../support/components/add_existing_pane" +require 'spec_helper' +require_relative 'shared_context' +require_relative '../support/components/add_existing_pane' -RSpec.describe "Team planner remove event", +RSpec.describe 'Team planner remove event', :js, with_ee: %i[team_planner_view], with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' let!(:viewer_role) { create(:project_role, permissions: [:view_work_packages]) } let!(:other_user) do create(:user, - firstname: "Bernd", + firstname: 'Bernd', member_with_permissions: { project => %w[ view_work_packages view_team_planner ] }) @@ -49,7 +49,7 @@ let!(:removable_wp) do create(:work_package, project:, - subject: "Some task", + subject: 'Some task', assigned_to: other_user, start_date: Time.zone.today.beginning_of_week.next_occurring(:tuesday), due_date: Time.zone.today.beginning_of_week.next_occurring(:thursday)) @@ -58,7 +58,7 @@ let!(:non_removable_wp) do create(:work_package, project:, - subject: "Parent work package", + subject: 'Parent work package', assigned_to: other_user, start_date: Time.zone.today.beginning_of_week.next_occurring(:wednesday), due_date: Time.zone.today.beginning_of_week.next_occurring(:thursday), @@ -87,21 +87,21 @@ sleep 2 end - it "can remove one of the work packages" do + it 'can remove one of the work packages' do team_planner.drag_to_remove_dropzone non_removable_wp, expect_removable: false team_planner.drag_to_remove_dropzone removable_wp, expect_removable: true end - context "with the add existing open searching for the task" do + context 'with the add existing open searching for the task' do let(:add_existing_pane) { Components::AddExistingPane.new } - it "the removed task shows up again" do + it 'the removed task shows up again' do # Open the left hand pane add_existing_pane.open add_existing_pane.expect_empty # Search for the task, expect empty - add_existing_pane.search "task" + add_existing_pane.search 'task' add_existing_pane.expect_empty # Remove the task diff --git a/modules/team_planner/spec/features/team_planner_spec.rb b/modules/team_planner/spec/features/team_planner_spec.rb index a426f08a70f5..7326ac8e795e 100644 --- a/modules/team_planner/spec/features/team_planner_spec.rb +++ b/modules/team_planner/spec/features/team_planner_spec.rb @@ -26,24 +26,24 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner", +RSpec.describe 'Team planner', :js, with_ee: %i[team_planner_view], with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' - it "hides the internally used filters" do + it 'hides the internally used filters' do visit project_path(project) - within "#main-menu" do - click_link "Team planners" + within '#main-menu' do + click_link 'Team planners' end - expect(page).to have_content "There is currently nothing to display." - click_on "Create", match: :first + expect(page).to have_content 'There is currently nothing to display.' + click_on 'Create', match: :first team_planner.expect_title @@ -51,26 +51,26 @@ filters.open filters.open_available_filter_list - filters.expect_available_filter "Author", present: true - filters.expect_available_filter "Subject", present: true - filters.expect_available_filter "Finish date", present: false - filters.expect_available_filter "Start date", present: false - filters.expect_available_filter "Assignee", present: false - filters.expect_available_filter "Assignee or belonging group", present: false + filters.expect_available_filter 'Author', present: true + filters.expect_available_filter 'Subject', present: true + filters.expect_available_filter 'Finish date', present: false + filters.expect_available_filter 'Start date', present: false + filters.expect_available_filter 'Assignee', present: false + filters.expect_available_filter 'Assignee or belonging group', present: false filters.expect_available_filter "Assignee's group", present: false filters.expect_available_filter "Assignee's role", present: false end - context "with an assigned work package", with_settings: { working_days: [1, 2, 3, 4, 5] } do + context 'with an assigned work package', with_settings: { working_days: [1, 2, 3, 4, 5] } do let!(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_permissions: { project => %w[ view_work_packages edit_work_packages view_team_planner manage_team_planner ] }) end - let!(:user_outside_project) { create(:user, firstname: "Not", lastname: "In Project") } + let!(:user_outside_project) { create(:user, firstname: 'Not', lastname: 'In Project') } let(:type_task) { create(:type_task) } let(:type_bug) { create(:type_bug) } let(:closed_status) { create(:status, is_closed: true) } @@ -82,7 +82,7 @@ assigned_to: other_user, start_date: Time.zone.today.monday + 1.day, due_date: Time.zone.today.monday + 3.days, - subject: "A task for the other user") + subject: 'A task for the other user') end let!(:other_bug) do create(:work_package, @@ -91,7 +91,7 @@ assigned_to: other_user, start_date: Time.zone.today.monday + 1.day, due_date: Time.zone.today.monday + 3.days, - subject: "Another task for the other user") + subject: 'Another task for the other user') end let!(:closed_bug) do create(:work_package, @@ -101,7 +101,7 @@ status: closed_status, start_date: Time.zone.today.monday + 1.day, due_date: Time.zone.today.monday + 3.days, - subject: "Closed bug") + subject: 'Closed bug') end let!(:user_bug) do create(:work_package, @@ -110,7 +110,7 @@ assigned_to: user, start_date: Time.zone.today - 10.days, due_date: Time.zone.today + 20.days, - subject: "A task for the logged in user") + subject: 'A task for the logged in user') end let!(:user_bug_next_week) do create(:work_package, @@ -119,7 +119,7 @@ assigned_to: user, start_date: Time.zone.today.monday + 7.days, due_date: Time.zone.today.monday + 12.days, - subject: "A task for the logged in user in the next week") + subject: 'A task for the logged in user in the next week') end let!(:user_bug_last_week) do create(:work_package, @@ -128,7 +128,7 @@ assigned_to: user, start_date: Time.zone.today.monday - 7.days, due_date: Time.zone.today.monday - 5.days, - subject: "A task for the logged in user in the last week") + subject: 'A task for the logged in user in the last week') end let!(:user_bug_on_weekend) do create(:work_package, @@ -137,7 +137,7 @@ assigned_to: user, start_date: Time.zone.today.monday + 5.days, due_date: Time.zone.today.monday + 6.days, - subject: "A task for the logged in user on the weekend") + subject: 'A task for the logged in user on the weekend') end before do @@ -145,7 +145,7 @@ project.types << type_task end - it "renders a team planner displaying work packages by assignee and date" do + it 'renders a team planner displaying work packages by assignee and date' do team_planner.visit! team_planner.title @@ -184,7 +184,7 @@ # Switching to the '1-week' view means that # work packages on the weekend are displayed now but # those outside of the current week are still hidden. - team_planner.switch_view_mode("1-week") + team_planner.switch_view_mode('1-week') team_planner.within_lane(user) do team_planner.expect_event user_bug @@ -197,7 +197,7 @@ # work packages on the weekend and those of the upcoming week are displayed. # Those in the last week are still hidden. - team_planner.switch_view_mode("2-week") + team_planner.switch_view_mode('2-week') team_planner.within_lane(user) do team_planner.expect_event user_bug @@ -210,8 +210,8 @@ filters.expect_filter_count("1") filters.open - filters.add_filter_by("Type", "is (OR)", [type_task.name]) - filters.expect_filter_by("Type", "is (OR)", [type_task.name]) + filters.add_filter_by('Type', 'is (OR)', [type_task.name]) + filters.expect_filter_by('Type', 'is (OR)', [type_task.name]) filters.expect_filter_count("2") team_planner.expect_assignee(user, present: true) @@ -234,7 +234,7 @@ team_planner.expect_empty_state(present: false) end - it "can add and remove assignees" do + it 'can add and remove assignees' do team_planner.visit! team_planner.expect_empty_state @@ -270,12 +270,12 @@ team_planner.expect_assignee(other_user, present: false) end - it "filters possible assignees correctly" do + it 'filters possible assignees correctly' do team_planner.visit! team_planner.search_assignee(user_outside_project.name) - expect(page).to have_css(".ng-option-disabled", text: "No items found") + expect(page).to have_css('.ng-option-disabled', text: "No items found") retry_block do team_planner.select_user_to_add user.name @@ -285,17 +285,17 @@ team_planner.search_assignee user.name - expect(page).to have_css(".ng-option-disabled", text: "No items found") + expect(page).to have_css('.ng-option-disabled', text: "No items found") end - context "when the page size is smaller than the number of assignees" do + context 'when the page size is smaller than the number of assignees' do before do allow(Setting) .to receive(:per_page_options_array) .and_return([1]) end - it "renders assignees and assignee dropdown correctly" do + it 'renders assignees and assignee dropdown correctly' do team_planner.visit! team_planner.wait_for_loaded @@ -308,7 +308,7 @@ team_planner.add_assignee user team_planner.add_assignee other_user - team_planner.save_as("TP1") + team_planner.save_as('TP1') page.refresh team_planner.wait_for_loaded @@ -324,7 +324,7 @@ end end - context "with a readonly work package" do + context 'with a readonly work package' do let(:readonly_status) { create(:status, is_readonly: true) } let!(:blocked_task) do @@ -334,10 +334,10 @@ status: readonly_status, start_date: Time.zone.today - 1.day, due_date: Time.zone.today + 1.day, - subject: "A blocked task") + subject: 'A blocked task') end - it "disables editing on readonly tasks", with_ee: %i[team_planner_view readonly_work_packages] do + it 'disables editing on readonly tasks', with_ee: %i[team_planner_view readonly_work_packages] do team_planner.visit! team_planner.wait_for_loaded diff --git a/modules/team_planner/spec/features/team_planner_split_view_spec.rb b/modules/team_planner/spec/features/team_planner_split_view_spec.rb index d765a35aa267..173b02309d9d 100644 --- a/modules/team_planner/spec/features/team_planner_split_view_spec.rb +++ b/modules/team_planner/spec/features/team_planner_split_view_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner split view navigation", :js, with_ee: %i[team_planner_view] do - include_context "with team planner full access" +RSpec.describe 'Team planner split view navigation', :js, with_ee: %i[team_planner_view] do + include_context 'with team planner full access' let!(:view) { create(:view_team_planner, query:) } let!(:query) { create(:query, user:, project:, public: true) } @@ -40,7 +40,7 @@ let!(:work_package1) do create(:work_package, project:, - subject: "First task", + subject: 'First task', assigned_to: user, start_date: start_of_week.next_occurring(:tuesday), due_date: start_of_week.next_occurring(:thursday)) @@ -49,13 +49,13 @@ let!(:work_package2) do create(:work_package, project:, - subject: "Another task", + subject: 'Another task', assigned_to: user, start_date: start_of_week.next_occurring(:tuesday), due_date: start_of_week.next_occurring(:thursday)) end - it "allows to navigate to the split view" do + it 'allows to navigate to the split view' do team_planner.visit! team_planner.add_assignee user @@ -65,7 +65,7 @@ end # Expect clicking on a work package does not open the details - page.find_test_selector("op-wp-single-card--content-subject", text: work_package1.subject).click + page.find_test_selector('op-wp-single-card--content-subject', text: work_package1.subject).click expect(page).to have_no_current_path /team_planners\/new\/details\/#{work_package1.id}/ # Open split view through info icon @@ -76,7 +76,7 @@ card1.expect_selected # now clicking on another card switches - page.find_test_selector("op-wp-single-card--content-subject", text: work_package2.subject).click + page.find_test_selector('op-wp-single-card--content-subject', text: work_package2.subject).click expect(page).to have_current_path /team_planners\/new\/details\/#{work_package2.id}/ card2 = Pages::WorkPackageCard.new work_package2 diff --git a/modules/team_planner/spec/features/team_planner_subproject_constraints_spec.rb b/modules/team_planner/spec/features/team_planner_subproject_constraints_spec.rb index 55c76a623845..c3ff5fc2a77b 100644 --- a/modules/team_planner/spec/features/team_planner_subproject_constraints_spec.rb +++ b/modules/team_planner/spec/features/team_planner_subproject_constraints_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner constraints for a subproject", +RSpec.describe 'Team planner constraints for a subproject', :js, with_ee: %i[team_planner_view], with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' let!(:other_user) do create(:user, - firstname: "Bernd", + firstname: 'Bernd', member_with_permissions: { project => %w[view_work_packages view_team_planner work_package_assigned] }) end @@ -54,7 +54,7 @@ due_date: Time.zone.today.beginning_of_week.next_occurring(:thursday)) end - it "shows a visual aid that the other user cannot be assigned" do + it 'shows a visual aid that the other user cannot be assigned' do team_planner.visit! team_planner.add_assignee user @@ -63,7 +63,7 @@ # Include the subproject project_include.toggle! project_include.toggle_checkbox(subproject.id) - project_include.click_button "Apply" + project_include.click_button 'Apply' project_include.expect_count 1 team_planner.within_lane(user) do diff --git a/modules/team_planner/spec/features/team_planner_upsale_spec.rb b/modules/team_planner/spec/features/team_planner_upsale_spec.rb index 33a21f6c9564..f93714bdcacc 100644 --- a/modules/team_planner/spec/features/team_planner_upsale_spec.rb +++ b/modules/team_planner/spec/features/team_planner_upsale_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner index", :js, :with_cuprite do - include_context "with team planner full access" +RSpec.describe 'Team planner index', :js, :with_cuprite do + include_context 'with team planner full access' let(:current_user) { user } @@ -38,21 +38,21 @@ login_as current_user end - it "redirects routes to upsale" do + it 'redirects routes to upsale' do visit team_planners_path - expect(page).to have_text "Upgrade now" + expect(page).to have_text 'Upgrade now' visit project_team_planners_path(project) - expect(page).to have_text "Upgrade now" + expect(page).to have_text 'Upgrade now' visit new_project_team_planners_path(project) - expect(page).to have_text "Upgrade now" + expect(page).to have_text 'Upgrade now' - visit project_team_planner_path(project, id: "new") + visit project_team_planner_path(project, id: 'new') - expect(page).to have_text "Upgrade now" + expect(page).to have_text 'Upgrade now' end end diff --git a/modules/team_planner/spec/features/team_planner_user_interaction_spec.rb b/modules/team_planner/spec/features/team_planner_user_interaction_spec.rb index 36e6ee4a703c..460e46f86d52 100644 --- a/modules/team_planner/spec/features/team_planner_user_interaction_spec.rb +++ b/modules/team_planner/spec/features/team_planner_user_interaction_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner drag&dop and resizing", +RSpec.describe 'Team planner drag&dop and resizing', :js, with_ee: %i[team_planner_view], with_settings: { start_of_week: 1 } do - include_context "with team planner full access" + include_context 'with team planner full access' let!(:other_user) do create(:user, - firstname: "Bernd", + firstname: 'Bernd', member_with_permissions: { project => %w[view_work_packages view_team_planner work_package_assigned] }) end @@ -74,7 +74,7 @@ due_date: Time.zone.today.beginning_of_week.next_occurring(:tuesday)) end - context "with full permissions" do + context 'with full permissions' do before do team_planner.visit! @@ -96,12 +96,12 @@ end end - it "allows to drag&drop between the lanes to change the assignee" do + it 'allows to drag&drop between the lanes to change the assignee' do # Move first wp to the user retry_block do team_planner.drag_wp_to_lane(first_wp, user) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) team_planner.within_lane(user) do team_planner.expect_event first_wp @@ -121,7 +121,7 @@ retry_block do team_planner.drag_wp_to_lane(second_wp, user) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) team_planner.within_lane(user) do team_planner.expect_event first_wp @@ -141,7 +141,7 @@ retry_block do team_planner.drag_wp_to_lane(third_wp, other_user) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) team_planner.within_lane(user) do team_planner.expect_event first_wp @@ -161,7 +161,7 @@ retry_block do team_planner.drag_wp_to_lane(fourth_wp, other_user) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) team_planner.within_lane(user) do team_planner.expect_event first_wp @@ -178,13 +178,13 @@ end end - it "allows to resize to change the dates of a wp" do + it 'allows to resize to change the dates of a wp' do retry_block do # Change date of second_wp by resizing it team_planner.change_wp_date_by_resizing(second_wp, number_of_days: 1, is_start_date: true) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) # The date has changed, but the assignee remains unchanged. # Because of the hierarchy, the first wp is updated, too. @@ -204,7 +204,7 @@ retry_block do team_planner.drag_wp_by_pixel(second_wp, -150, 0) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) first_wp.reload second_wp.reload @@ -229,7 +229,7 @@ retry_block do team_planner.drag_wp_by_pixel(fourth_wp, 150, 0) end - team_planner.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_update")) + team_planner.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_update')) fourth_wp.reload expect(fourth_wp.start_date).to eq(Time.zone.today.beginning_of_week.next_occurring(:wednesday)) @@ -238,7 +238,7 @@ end end - context "without permission to edit" do + context 'without permission to edit' do current_user { other_user } before do @@ -248,7 +248,7 @@ team_planner.add_assignee other_user end - it "allows neither dragging nor resizing any wp" do + it 'allows neither dragging nor resizing any wp' do team_planner.expect_wp_not_resizable(first_wp) team_planner.expect_wp_not_resizable(second_wp) team_planner.expect_wp_not_resizable(third_wp) diff --git a/modules/team_planner/spec/features/team_planner_view_modes_spec.rb b/modules/team_planner/spec/features/team_planner_view_modes_spec.rb index 9bd264483650..56ded17546f8 100644 --- a/modules/team_planner/spec/features/team_planner_view_modes_spec.rb +++ b/modules/team_planner/spec/features/team_planner_view_modes_spec.rb @@ -26,44 +26,44 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_context" +require 'spec_helper' +require_relative 'shared_context' -RSpec.describe "Team planner", :js, with_ee: %i[team_planner_view] do - include_context "with team planner full access" +RSpec.describe 'Team planner', :js, with_ee: %i[team_planner_view] do + include_context 'with team planner full access' - it "allows switching of view modes", with_settings: { working_days: [1, 2, 3, 4, 5] } do + it 'allows switching of view modes', with_settings: { working_days: [1, 2, 3, 4, 5] } do team_planner.visit! team_planner.expect_empty_state team_planner.add_assignee user.name - team_planner.expect_view_mode "Work week" - expect(page).to have_css(".fc-timeline-slot-frame", count: 5) + team_planner.expect_view_mode 'Work week' + expect(page).to have_css('.fc-timeline-slot-frame', count: 5) # weekly: Expect 7 slots - team_planner.switch_view_mode "1-week" - expect(page).to have_css(".fc-timeline-slot-frame", count: 7) + team_planner.switch_view_mode '1-week' + expect(page).to have_css('.fc-timeline-slot-frame', count: 7) # 2 weeks: expect 14 slots - team_planner.switch_view_mode "2-week" - expect(page).to have_css(".fc-timeline-slot-frame", count: 14) + team_planner.switch_view_mode '2-week' + expect(page).to have_css('.fc-timeline-slot-frame', count: 14) start_of_week = Time.zone.today.beginning_of_week(:sunday) - start_date = start_of_week.strftime("%d %a") - end_date = (start_of_week + 13.days).strftime("%d %a") + start_date = start_of_week.strftime('%d %a') + end_date = (start_of_week + 13.days).strftime('%d %a') - expect(page).to have_css(".fc-timeline-slot", text: start_date) - expect(page).to have_css(".fc-timeline-slot", text: end_date) + expect(page).to have_css('.fc-timeline-slot', text: start_date) + expect(page).to have_css('.fc-timeline-slot', text: end_date) # Click next button, advance one week - find(".fc-next-button").click + find('.fc-next-button').click start_of_week = (Time.zone.today + 1.week).beginning_of_week(:sunday) - start_date = start_of_week.strftime("%d %a") - end_date = (start_of_week + 13.days).strftime("%d %a") + start_date = start_of_week.strftime('%d %a') + end_date = (start_of_week + 13.days).strftime('%d %a') - expect(page).to have_css(".fc-timeline-slot", text: start_date) - expect(page).to have_css(".fc-timeline-slot", text: end_date) + expect(page).to have_css('.fc-timeline-slot', text: start_date) + expect(page).to have_css('.fc-timeline-slot', text: end_date) end end diff --git a/modules/team_planner/spec/permissions/view_team_planner_spec.rb b/modules/team_planner/spec/permissions/view_team_planner_spec.rb index 115767b52d0d..395b4b4aaf46 100644 --- a/modules/team_planner/spec/permissions/view_team_planner_spec.rb +++ b/modules/team_planner/spec/permissions/view_team_planner_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/permission_specs" +require 'spec_helper' +require 'support/permission_specs' -RSpec.describe TeamPlanner::TeamPlannerController, "view_team_planner permission", type: :controller do +RSpec.describe TeamPlanner::TeamPlannerController, 'view_team_planner permission', type: :controller do include PermissionSpecs - check_permission_required_for("team_planner/team_planner#index", :view_team_planner) + check_permission_required_for('team_planner/team_planner#index', :view_team_planner) end diff --git a/modules/team_planner/spec/requests/api/v3/views/create_resource_spec.rb b/modules/team_planner/spec/requests/api/v3/views/create_resource_spec.rb index 936e42baae79..3afeb541f10c 100644 --- a/modules/team_planner/spec/requests/api/v3/views/create_resource_spec.rb +++ b/modules/team_planner/spec/requests/api/v3/views/create_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Views::ViewsAPI, - "create", + 'create', content_type: :json do include API::V3::Utilities::PathHelper @@ -65,7 +65,7 @@ end let(:send_request) do - post api_v3_paths.views_type("team_planner"), body + post api_v3_paths.views_type('team_planner'), body end current_user { permitted_user } @@ -78,25 +78,25 @@ send_request end - describe "POST /api/v3/views/team_planner" do - context "with a user allowed to save the query" do - it "returns 201 CREATED" do + describe 'POST /api/v3/views/team_planner' do + context 'with a user allowed to save the query' do + it 'returns 201 CREATED' do expect(response.status) .to eq(201) end - it "returns the view" do + it 'returns the view' do expect(response.body) - .to be_json_eql("Views::TeamPlanner".to_json) - .at_path("_type") + .to be_json_eql('Views::TeamPlanner'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(View.last.id.to_json) - .at_path("id") + .at_path('id') end end - context "with a user not allowed to manage team planners" do + context 'with a user not allowed to manage team planners' do let(:additional_setup) do role.update_attribute(:permissions, %w[view_work_packages @@ -104,7 +104,7 @@ manage_public_queries]) end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/modules/team_planner/spec/routing/team_planner_routing_spec.rb b/modules/team_planner/spec/routing/team_planner_routing_spec.rb index 3bb81a2d0ee1..b19c3fcefdba 100644 --- a/modules/team_planner/spec/routing/team_planner_routing_spec.rb +++ b/modules/team_planner/spec/routing/team_planner_routing_spec.rb @@ -26,71 +26,71 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Team planner routing" do - it "routes to team_planner#overview" do +RSpec.describe 'Team planner routing' do + it 'routes to team_planner#overview' do expect(subject) - .to route(:get, "/team_planners") - .to(controller: "team_planner/team_planner", action: :overview) + .to route(:get, '/team_planners') + .to(controller: 'team_planner/team_planner', action: :overview) end - it "routes to team_planner#index" do + it 'routes to team_planner#index' do expect(subject) - .to route(:get, "/projects/foobar/team_planners") - .to(controller: "team_planner/team_planner", action: :index, project_id: "foobar") + .to route(:get, '/projects/foobar/team_planners') + .to(controller: 'team_planner/team_planner', action: :index, project_id: 'foobar') end - it "routes to team_planner#show" do + it 'routes to team_planner#show' do expect(subject) - .to route(:get, "/projects/foobar/team_planners/1234") - .to(controller: "team_planner/team_planner", action: :show, project_id: "foobar", id: "1234") + .to route(:get, '/projects/foobar/team_planners/1234') + .to(controller: 'team_planner/team_planner', action: :show, project_id: 'foobar', id: '1234') end - context "with :project_id" do - it "routes to team_planner#upsale" do + context 'with :project_id' do + it 'routes to team_planner#upsale' do expect(subject) - .to route(:get, "/projects/foobar/team_planners/upsale") - .to(controller: "team_planner/team_planner", action: :upsale, project_id: "foobar") + .to route(:get, '/projects/foobar/team_planners/upsale') + .to(controller: 'team_planner/team_planner', action: :upsale, project_id: 'foobar') end - it "routes to team_planner#show" do + it 'routes to team_planner#show' do expect(subject) - .to route(:get, "/projects/foobar/team_planners/new") - .to(controller: "team_planner/team_planner", action: :show, project_id: "foobar") + .to route(:get, '/projects/foobar/team_planners/new') + .to(controller: 'team_planner/team_planner', action: :show, project_id: 'foobar') end end - context "without :project_id" do - it "routes to team_planner#upsale" do + context 'without :project_id' do + it 'routes to team_planner#upsale' do expect(subject) - .to route(:get, "/team_planners/upsale") - .to(controller: "team_planner/team_planner", action: :upsale) + .to route(:get, '/team_planners/upsale') + .to(controller: 'team_planner/team_planner', action: :upsale) end - it "routes to team_planner#new" do + it 'routes to team_planner#new' do expect(subject) - .to route(:get, "/team_planners/new") - .to(controller: "team_planner/team_planner", action: :new) + .to route(:get, '/team_planners/new') + .to(controller: 'team_planner/team_planner', action: :new) end end - it "routes to team_planner#create" do + it 'routes to team_planner#create' do expect(subject) - .to route(:post, "/team_planners") - .to(controller: "team_planner/team_planner", action: :create) + .to route(:post, '/team_planners') + .to(controller: 'team_planner/team_planner', action: :create) end - it "routes to team_planner#show with state" do + it 'routes to team_planner#show with state' do expect(subject) - .to route(:get, "/projects/foobar/team_planners/1234/details/555") - .to(controller: "team_planner/team_planner", action: :show, project_id: "foobar", id: "1234", - state: "details/555") + .to route(:get, '/projects/foobar/team_planners/1234/details/555') + .to(controller: 'team_planner/team_planner', action: :show, project_id: 'foobar', id: '1234', + state: 'details/555') end - it "routes to team_planner#destroy" do + it 'routes to team_planner#destroy' do expect(subject) - .to route(:delete, "/projects/foobar/team_planners/1234") - .to(controller: "team_planner/team_planner", action: :destroy, project_id: "foobar", id: "1234") + .to route(:delete, '/projects/foobar/team_planners/1234') + .to(controller: 'team_planner/team_planner', action: :destroy, project_id: 'foobar', id: '1234') end end diff --git a/modules/team_planner/spec/services/team_planner/views/global_create_service_spec.rb b/modules/team_planner/spec/services/team_planner/views/global_create_service_spec.rb index a804b663e5e3..c790749f6233 100644 --- a/modules/team_planner/spec/services/team_planner/views/global_create_service_spec.rb +++ b/modules/team_planner/spec/services/team_planner/views/global_create_service_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TeamPlanner::Views::GlobalCreateService, with_ee: %i[team_planner_view] do shared_let(:project) { create(:project) } @@ -37,27 +37,27 @@ subject { instance.call(params) } - context "with all valid params" do + context 'with all valid params' do let(:params) do { - name: "Gotham Renewal", + name: 'Gotham Renewal', project_id: project.id, public: true, starred: false } end - it "is successful" do + it 'is successful' do expect(subject).to be_success end - it "creates a team planner view and its query" do + it 'creates a team planner view and its query' do view = subject.result query = view.query - expect(view.type).to eq "team_planner" + expect(view.type).to eq 'team_planner' - expect(query.name).to eq "Gotham Renewal" + expect(query.name).to eq 'Gotham Renewal' expect(query.project).to eql(project) expect(query).to be_public expect(query).not_to be_starred diff --git a/modules/team_planner/spec/support/onboarding/onboarding_steps.rb b/modules/team_planner/spec/support/onboarding/onboarding_steps.rb index cb73b8d271da..2b9022d594f3 100644 --- a/modules/team_planner/spec/support/onboarding/onboarding_steps.rb +++ b/modules/team_planner/spec/support/onboarding/onboarding_steps.rb @@ -29,7 +29,7 @@ module OnboardingSteps def step_through_onboarding_team_planner_tour next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.team_planner.overview")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.team_planner.overview')), normalize_ws: true next_button.click # The team planner (and in fact every PartitionedQuerySpacePageComponent page) suffers from not being shown upon @@ -43,22 +43,22 @@ def step_through_onboarding_team_planner_tour retry_block do page.execute_script("document.querySelector('#content').dispatchEvent(new MouseEvent('mouseover'));") - page.find(".enjoy_hint_label", - text: sanitize_string(I18n.t("js.onboarding.steps.team_planner.calendar")), + page.find('.enjoy_hint_label', + text: sanitize_string(I18n.t('js.onboarding.steps.team_planner.calendar')), normalize_ws: true) end next_button.click expect(page) - .to have_text sanitize_string(I18n.t("js.onboarding.steps.team_planner.add_assignee")), normalize_ws: true + .to have_text sanitize_string(I18n.t('js.onboarding.steps.team_planner.add_assignee')), normalize_ws: true next_button.click expect(page) - .to have_text sanitize_string(I18n.t("js.onboarding.steps.team_planner.add_existing")), normalize_ws: true + .to have_text sanitize_string(I18n.t('js.onboarding.steps.team_planner.add_existing')), normalize_ws: true next_button.click expect(page) - .to have_text sanitize_string(I18n.t("js.onboarding.steps.team_planner.card")), normalize_ws: true + .to have_text sanitize_string(I18n.t('js.onboarding.steps.team_planner.card')), normalize_ws: true end end diff --git a/modules/team_planner/spec/support/pages/team_planner.rb b/modules/team_planner/spec/support/pages/team_planner.rb index 6332f6a38663..5b83fd3f574c 100644 --- a/modules/team_planner/spec/support/pages/team_planner.rb +++ b/modules/team_planner/spec/support/pages/team_planner.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/work_package_cards" +require 'support/pages/page' +require 'support/pages/work_packages/work_package_cards' module Pages class TeamPlanner < ::Pages::WorkPackageCards @@ -45,18 +45,18 @@ def path new_project_team_planners_path(project) end - def expect_title(title = "Unnamed team planner") - expect(page).to have_css(".editable-toolbar-title--input") { |node| node.value == title } + def expect_title(title = 'Unnamed team planner') + expect(page).to have_css('.editable-toolbar-title--input') { |node| node.value == title } end def save_as(name) - click_setting_item "Save as" + click_setting_item 'Save as' - fill_in "save-query-name", with: name + fill_in 'save-query-name', with: name - click_button "Save" + click_button 'Save' - expect_toast message: "Successful creation." + expect_toast message: 'Successful creation.' expect_title name end @@ -67,17 +67,17 @@ def click_setting_item(label) def expect_empty_state(present: true) expect(page).to have_conditional_selector(present, - ".op-team-planner--no-data", - text: "Add assignees to set up your team planner.") + '.op-team-planner--no-data', + text: 'Add assignees to set up your team planner.') end def expect_view_mode(text) expect(page).to have_css('[data-test-selector="op-team-planner--view-select-dropdown"]', text:) param = { - "Work week" => :resourceTimelineWorkWeek, - "1-week" => :resourceTimelineWeek, - "2-week" => :resourceTimelineTwoWeeks + 'Work week' => :resourceTimelineWorkWeek, + '1-week' => :resourceTimelineWeek, + '2-week' => :resourceTimelineTwoWeeks }[text] expect(page).to have_current_path(/cview=#{param}/) @@ -87,7 +87,7 @@ def switch_view_mode(text) retry_block do find('[data-test-selector="op-team-planner--view-select-dropdown"]').click - within("#op-team-planner--view-select-dropdown") do + within('#op-team-planner--view-select-dropdown') do click_button(text) end end @@ -97,7 +97,7 @@ def switch_view_mode(text) def expect_assignee(user, present: true) name = user.is_a?(User) ? user.name : user.to_s - expect(page).to have_conditional_selector(present, ".fc-resource", text: name, wait: 10) + expect(page).to have_conditional_selector(present, '.fc-resource', text: name, wait: 10) end def add_item(assignee, start_date, end_date) @@ -131,26 +131,26 @@ def within_lane(user, &) def expect_event(work_package, present: true) if present - expect(page).to have_css(".fc-event", text: work_package.subject, wait: 10) + expect(page).to have_css('.fc-event', text: work_package.subject, wait: 10) else - expect(page).to have_no_css(".fc-event", text: work_package.subject) + expect(page).to have_no_css('.fc-event', text: work_package.subject) end end def expect_resizable(work_package, resizable: true) if resizable - expect(page).to have_css(".fc-event.fc-event-resizable", text: work_package.subject, wait: 10) + expect(page).to have_css('.fc-event.fc-event-resizable', text: work_package.subject, wait: 10) else - expect(page).to have_css(".fc-event:not(.fc-event-resizable)", text: work_package.subject, wait: 10) + expect(page).to have_css('.fc-event:not(.fc-event-resizable)', text: work_package.subject, wait: 10) end end def expect_no_views_rendered - expect(page).to have_text "There is currently nothing to display." + expect(page).to have_text 'There is currently nothing to display.' end def expect_views_rendered(*queries) - rendered_query_names = all("td.name").map(&:text) + rendered_query_names = all('td.name').map(&:text) expect(rendered_query_names).to match_array(queries.map(&:name)) end @@ -168,65 +168,65 @@ def expect_no_delete_buttons_for(*queries) end def expect_view_not_rendered(query) - expect(page).to have_no_css "td", text: query.name + expect(page).to have_no_css 'td', text: query.name end def expect_create_button - within ".toolbar-items" do - expect(page).to have_link text: "Team planner" + within '.toolbar-items' do + expect(page).to have_link text: 'Team planner' end end def expect_no_create_button - within ".toolbar-items" do - expect(page).to have_no_link text: "Team planner" + within '.toolbar-items' do + expect(page).to have_no_link text: 'Team planner' end end def expect_views_listed_in_order(*queries) - within ".generic-table tbody" do - listed_view_names = all("tr td.name").map(&:text) + within '.generic-table tbody' do + listed_view_names = all('tr td.name').map(&:text) expect(listed_view_names).to eq(queries.map(&:name)) end end def click_on_create_button - within ".toolbar-items" do - click_link "Team planner" + within '.toolbar-items' do + click_link 'Team planner' end end def click_on_cancel_button - click_on "Cancel" + click_on 'Cancel' end def set_title(title) - fill_in "Title", with: title + fill_in 'Title', with: title end def set_project(project) select_autocomplete(find('[data-test-selector="project_id"]'), query: project, - results_selector: "body", + results_selector: 'body', wait_for_fetched_options: false) end def set_public - check "Public" + check 'Public' end def set_favoured - check "Favoured" + check 'Favoured' end def click_on_submit - click_on "Create" + click_on 'Create' end def add_assignee(name) retry_block do - return if page.has_selector?(".fc-resource", text: name, wait: 0) + return if page.has_selector?('.fc-resource', text: name, wait: 0) click_add_user page.find("#{page.test_selector('tp-add-assignee')} input") @@ -240,7 +240,7 @@ def search_assignee(name) page.find("#{page.test_selector('tp-add-assignee')} input") search_autocomplete page.find('[data-test-selector="tp-add-assignee"]'), query: name, - results_selector: "body" + results_selector: 'body' end end @@ -254,7 +254,7 @@ def click_add_user def select_user_to_add(name) select_autocomplete page.find('[data-test-selector="tp-add-assignee"]'), query: name, - results_selector: "body" + results_selector: 'body' end def expect_user_selectable(user, present: true) @@ -262,7 +262,7 @@ def expect_user_selectable(user, present: true) expect_ng_option page.find('[data-test-selector="tp-add-assignee"]'), name, - results_selector: "body", + results_selector: 'body', present: end @@ -276,7 +276,7 @@ def change_wp_date_by_resizing(work_package, number_of_days:, is_start_date:) .move_to(wp_strip.native) .perform - resizer = is_start_date ? wp_strip.find(".fc-event-resizer-start") : wp_strip.find(".fc-event-resizer-end") + resizer = is_start_date ? wp_strip.find('.fc-event-resizer-start') : wp_strip.find('.fc-event-resizer-end') drag_by_pixel(element: resizer, by_x: number_of_days * 250, by_y: 0) unless resizer.nil? end @@ -310,9 +310,9 @@ def drag_to_remove_dropzone(work_package, expect_removable: true) drag_element_to(dropzone) if expect_removable - expect(page).to have_css("span", text: I18n.t("js.team_planner.drag_here_to_remove")) + expect(page).to have_css('span', text: I18n.t('js.team_planner.drag_here_to_remove')) else - expect(page).to have_css("span", text: I18n.t("js.team_planner.cannot_drag_here")) + expect(page).to have_css('span', text: I18n.t('js.team_planner.cannot_drag_here')) end drag_release @@ -328,7 +328,7 @@ def drag_to_remove_dropzone(work_package, expect_removable: true) end def event(work_package) - page.find(".fc-event", text: work_package.subject) + page.find('.fc-event', text: work_package.subject) end def lane(user) @@ -339,15 +339,15 @@ def lane(user) end def expect_wp_not_resizable(work_package) - expect(page).to have_css(".fc-event:not(.fc-event-resizable)", text: work_package.subject) + expect(page).to have_css('.fc-event:not(.fc-event-resizable)', text: work_package.subject) end def expect_wp_not_draggable(work_package) - expect(page).to have_css(".fc-event:not(.fc-event-draggable)", text: work_package.subject) + expect(page).to have_css('.fc-event:not(.fc-event-draggable)', text: work_package.subject) end def expect_no_menu_item(name) - expect(page).to have_no_css(".op-sidemenu--item-title", text: name) + expect(page).to have_no_css('.op-sidemenu--item-title', text: name) end def y_distance(from:, to:) @@ -359,8 +359,8 @@ def y_center(element) end def wait_for_loaded - expect(page).to have_css(".op-team-planner--wp-loading-skeleton") - expect(page).to have_no_css(".op-team-planner--wp-loading-skeleton", wait: 10) + expect(page).to have_css('.op-team-planner--wp-loading-skeleton') + expect(page).to have_no_css('.op-team-planner--wp-loading-skeleton', wait: 10) end end end diff --git a/modules/two_factor_authentication/Gemfile b/modules/two_factor_authentication/Gemfile index 3be9c3cd812e..851fabc21ddb 100644 --- a/modules/two_factor_authentication/Gemfile +++ b/modules/two_factor_authentication/Gemfile @@ -1,2 +1,2 @@ -source "https://rubygems.org" +source 'https://rubygems.org' gemspec diff --git a/modules/two_factor_authentication/app/components/two_factor_authentication/devices/row_component.rb b/modules/two_factor_authentication/app/components/two_factor_authentication/devices/row_component.rb index df46c05bfd9c..f5fb85361938 100644 --- a/modules/two_factor_authentication/app/components/two_factor_authentication/devices/row_component.rb +++ b/modules/two_factor_authentication/app/components/two_factor_authentication/devices/row_component.rb @@ -17,21 +17,21 @@ def device_type def default if device.default - helpers.op_icon "icon-yes" + helpers.op_icon 'icon-yes' else - "-" + '-' end end def confirmed if device.active - helpers.op_icon "icon-yes" + helpers.op_icon 'icon-yes' elsif table.self_table? - link_to t("two_factor_authentication.devices.confirm_now"), + link_to t('two_factor_authentication.devices.confirm_now'), { controller: table.target_controller, action: :confirm, device_id: device.id } else - helpers.op_icon "icon-no" + helpers.op_icon 'icon-no' end end @@ -49,17 +49,17 @@ def make_default_link device, url: { controller: table.target_controller, action: :make_default, device_id: device.id }, method: :post, - html: { id: "two_factor_make_default_form", class: "form--inline" } + html: { id: 'two_factor_make_default_form', class: 'form--inline' } ) do |f| f.submit I18n.t(:button_make_default), - class: "button--link two-factor--mark-default-button" + class: 'button--link two-factor--mark-default-button' end end def delete_link title = if deletion_blocked? - I18n.t("two_factor_authentication.devices.is_default_cannot_delete") + I18n.t('two_factor_authentication.devices.is_default_cannot_delete') else I18n.t(:button_delete) end @@ -68,10 +68,10 @@ def delete_link device, url: { controller: table.target_controller, action: :destroy, device_id: device.id }, method: :delete, - html: { id: "two_factor_delete_form", class: "" } + html: { id: 'two_factor_delete_form', class: '' } ) do |f| f.submit I18n.t(:button_delete), - class: "button--link two-factor--delete-button", + class: 'button--link two-factor--delete-button', disabled: deletion_blocked?, title: end @@ -85,7 +85,7 @@ def deletion_blocked? def column_css_class(_column) if device.default - "mobile-otp--device-default" + 'mobile-otp--device-default' end end end diff --git a/modules/two_factor_authentication/app/components/two_factor_authentication/devices/table_component.rb b/modules/two_factor_authentication/app/components/two_factor_authentication/devices/table_component.rb index ce1bb3df4022..e689d01a5ab9 100644 --- a/modules/two_factor_authentication/app/components/two_factor_authentication/devices/table_component.rb +++ b/modules/two_factor_authentication/app/components/two_factor_authentication/devices/table_component.rb @@ -18,9 +18,9 @@ def admin_table? def target_controller if self_table? - "two_factor_authentication/my/two_factor_devices" + 'two_factor_authentication/my/two_factor_devices' else - "two_factor_authentication/users/two_factor_devices" + 'two_factor_authentication/users/two_factor_devices' end end @@ -31,9 +31,9 @@ def sortable? def inline_create_link if self_table? link_to({ controller: target_controller, action: :new }, - class: "budget-add-row wp-inline-create--add-link", - title: I18n.t("two_factor_authentication.devices.add_new")) do - helpers.op_icon("icon icon-add") + class: 'budget-add-row wp-inline-create--add-link', + title: I18n.t('two_factor_authentication.devices.add_new')) do + helpers.op_icon('icon icon-add') end end end @@ -46,17 +46,17 @@ def strategy_manager def empty_row_message if admin_table? - I18n.t "two_factor_authentication.admin.no_devices_for_user" + I18n.t 'two_factor_authentication.admin.no_devices_for_user' else - I18n.t "two_factor_authentication.devices.not_existing" + I18n.t 'two_factor_authentication.devices.not_existing' end end def headers [ - ["device_type", { caption: I18n.t("two_factor_authentication.label_device_type") }], - ["default", { caption: I18n.t(:label_default) }], - ["confirmed", { caption: I18n.t(:label_confirmed) }] + ['device_type', { caption: I18n.t('two_factor_authentication.label_device_type') }], + ['default', { caption: I18n.t(:label_default) }], + ['confirmed', { caption: I18n.t(:label_confirmed) }] ] end end diff --git a/modules/two_factor_authentication/app/controllers/concerns/two_factor_authentication/backup_codes.rb b/modules/two_factor_authentication/app/controllers/concerns/two_factor_authentication/backup_codes.rb index c5d1eace0985..b13833e99d86 100644 --- a/modules/two_factor_authentication/app/controllers/concerns/two_factor_authentication/backup_codes.rb +++ b/modules/two_factor_authentication/app/controllers/concerns/two_factor_authentication/backup_codes.rb @@ -12,14 +12,14 @@ def enter_backup_code # Verify backup code def verify_backup_code code = params[:backup_code] - return fail_login(t("two_factor_authentication.error_invalid_backup_code")) unless code.present? + return fail_login(t('two_factor_authentication.error_invalid_backup_code')) unless code.present? service = TwoFactorAuthentication::UseBackupCodeService.new user: @authenticated_user result = service.verify code if result.success? complete_stage_redirect else - fail_login(t("two_factor_authentication.error_invalid_backup_code")) + fail_login(t('two_factor_authentication.error_invalid_backup_code')) end end end diff --git a/modules/two_factor_authentication/app/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller.rb b/modules/two_factor_authentication/app/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller.rb index 384d95fec427..bedf5f1dcf69 100644 --- a/modules/two_factor_authentication/app/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller.rb +++ b/modules/two_factor_authentication/app/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller.rb @@ -41,13 +41,13 @@ def register # rubocop:disable Metrics/AbcSize if needs_confirmation redirect_to action: :confirm, device_id: @device.id else - flash[:notice] = t("two_factor_authentication.devices.registration_complete") + flash[:notice] = t('two_factor_authentication.devices.registration_complete') @device.confirm_registration_and_save redirect_to registration_success_path end else Rails.logger.warn { "User ##{target_user.id} forced to register failed for #{@device_type}." } - render "two_factor_authentication/two_factor_devices/new" + render 'two_factor_authentication/two_factor_devices/new' end end @@ -76,7 +76,7 @@ def registration_failure_path ## # Ensure the authentication stage from the core provided the authenticated user def require_authenticated_user - raise ArgumentError, "Missing param" unless session[:authenticated_user_force_2fa] + raise ArgumentError, 'Missing param' unless session[:authenticated_user_force_2fa] @authenticated_user = User.find(session[:authenticated_user_id]) true diff --git a/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/backup_codes_controller.rb b/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/backup_codes_controller.rb index 9ed10ef1d1ed..d76c26b22150 100644 --- a/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/backup_codes_controller.rb +++ b/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/backup_codes_controller.rb @@ -11,7 +11,7 @@ class BackupCodesController < ::ApplicationController # Verify that flash was set (coming from create) before_action :check_regenerate_done, only: [:show] - layout "my" + layout 'my' menu_item :two_factor_authentication def create diff --git a/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/remember_cookie_controller.rb b/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/remember_cookie_controller.rb index 3f9d0d520557..ae7b5c8c56ac 100644 --- a/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/remember_cookie_controller.rb +++ b/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/remember_cookie_controller.rb @@ -7,14 +7,14 @@ class RememberCookieController < ::ApplicationController # Ensure user is logged in before_action :require_login - layout "my" + layout 'my' menu_item :two_factor_authentication ## # Remove the remember token def destroy clear_remember_token! - flash[:notice] = I18n.t("two_factor_authentication.remember.cookie_removed") + flash[:notice] = I18n.t('two_factor_authentication.remember.cookie_removed') redirect_to my_2fa_devices_path end end diff --git a/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/two_factor_devices_controller.rb b/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/two_factor_devices_controller.rb index d8d2844cbf06..7ffaccafaafb 100644 --- a/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/two_factor_devices_controller.rb +++ b/modules/two_factor_authentication/app/controllers/two_factor_authentication/my/two_factor_devices_controller.rb @@ -19,7 +19,7 @@ class TwoFactorDevicesController < ::TwoFactorAuthentication::BaseController # Delete remember token on destroy before_action :clear_remember_token!, only: [:destroy] - layout "my" + layout 'my' menu_item :two_factor_authentication def index @@ -51,13 +51,13 @@ def register # rubocop:disable Metrics/AbcSize if needs_confirmation redirect_to action: :confirm, device_id: @device.id else - flash[:notice] = t("two_factor_authentication.devices.registration_complete") + flash[:notice] = t('two_factor_authentication.devices.registration_complete') @device.confirm_registration_and_save redirect_to registration_success_path end else Rails.logger.warn { "User ##{current_user.id} failed to register a device #{@device_type}." } - render "two_factor_authentication/two_factor_devices/new" + render 'two_factor_authentication/two_factor_devices/new' end end @@ -81,8 +81,8 @@ def request_device_confirmation_token request_token_for_device( @device, confirm_path: url_for(action: :confirm, device_id: @device.id), - title: I18n.t("two_factor_authentication.devices.confirm_device"), - message: I18n.t("two_factor_authentication.devices.text_confirm_to_complete_html", identifier: @device.identifier) + title: I18n.t('two_factor_authentication.devices.confirm_device'), + message: I18n.t('two_factor_authentication.devices.text_confirm_to_complete_html', identifier: @device.identifier) ) end @@ -93,10 +93,10 @@ def request_token_for_device(device, locals) flash[:notice] = transmit.result if transmit.result.present? # Request confirmation from user as in the regular login flow - render "two_factor_authentication/two_factor_devices/confirm", layout: "base", locals: + render 'two_factor_authentication/two_factor_devices/confirm', layout: 'base', locals: else error = transmit.errors.full_messages.join(". ") - default_message = t("two_factor_authentication.devices.confirm_send_failed") + default_message = t('two_factor_authentication.devices.confirm_send_failed') flash[:error] = "#{default_message} #{error}" redirect_to action: :index diff --git a/modules/two_factor_authentication/app/controllers/two_factor_authentication/two_factor_settings_controller.rb b/modules/two_factor_authentication/app/controllers/two_factor_authentication/two_factor_settings_controller.rb index 41d46935a51b..c1e74978c7dd 100644 --- a/modules/two_factor_authentication/app/controllers/two_factor_authentication/two_factor_settings_controller.rb +++ b/modules/two_factor_authentication/app/controllers/two_factor_authentication/two_factor_settings_controller.rb @@ -4,11 +4,11 @@ class TwoFactorSettingsController < ApplicationController before_action :require_admin before_action :check_enabled - layout "admin" + layout 'admin' menu_item :two_factor_authentication def show - render template: "two_factor_authentication/settings", + render template: 'two_factor_authentication/settings', locals: { settings: Setting.plugin_openproject_two_factor_authentication, strategy_manager: manager, @@ -24,7 +24,7 @@ def update flash[:notice] = I18n.t(:notice_successful_update) rescue ArgumentError => e Setting.plugin_openproject_two_factor_authentication = current_settings - flash[:error] = I18n.t("two_factor_authentication.settings.failed_to_save_settings", message: e.message) + flash[:error] = I18n.t('two_factor_authentication.settings.failed_to_save_settings', message: e.message) Rails.logger.error "Failed to save 2FA settings: #{e.message}" end @@ -53,7 +53,7 @@ def manager end def default_breadcrumb - t("two_factor_authentication.settings.title") + t('two_factor_authentication.settings.title') end def show_local_breadcrumb diff --git a/modules/two_factor_authentication/app/controllers/two_factor_authentication/users/two_factor_devices_controller.rb b/modules/two_factor_authentication/app/controllers/two_factor_authentication/users/two_factor_devices_controller.rb index 7d438e05e25a..f41a771062f0 100644 --- a/modules/two_factor_authentication/app/controllers/two_factor_authentication/users/two_factor_devices_controller.rb +++ b/modules/two_factor_authentication/app/controllers/two_factor_authentication/users/two_factor_devices_controller.rb @@ -34,7 +34,7 @@ def register redirect_to index_path else Rails.logger.info "Admin ##{current_user.id} failed to register a new device #{@device_type} for #{@user.id}." - render "two_factor_authentication/two_factor_devices/new" + render 'two_factor_authentication/two_factor_devices/new' end end @@ -42,7 +42,7 @@ def register # Delete all devices def delete_all @user.otp_devices.delete_all - flash[:notice] = I18n.t("two_factor_authentication.admin.all_devices_deleted") + flash[:notice] = I18n.t('two_factor_authentication.admin.all_devices_deleted') redirect_to index_path end @@ -54,7 +54,7 @@ def make_default if @device.make_default! flash[:notice] = t(:notice_successful_update) else - flash[:error] = t("two_factor_authentication.devices.make_default_failed") + flash[:error] = t('two_factor_authentication.devices.make_default_failed') end redirect_to index_path @@ -64,14 +64,14 @@ def make_default # Destroy the given device if its not the default def destroy if @device.default && strategy_manager.enforced? - render_400 message: t("two_factor_authentication.devices.is_default_cannot_delete") + render_400 message: t('two_factor_authentication.devices.is_default_cannot_delete') return end if @device.destroy flash[:notice] = t(:notice_successful_delete) else - flash[:error] = t("two_factor_authentication.devices.failed_to_delete") + flash[:error] = t('two_factor_authentication.devices.failed_to_delete') Rails.logger.error "Failed to delete #{@device.id} of user#{@user.id}. Errors: #{@device.errors.full_messages.join(' ')}" end @@ -81,9 +81,9 @@ def destroy private def ensure_only_sms_type - return if params[:type] == "sms" + return if params[:type] == 'sms' - render_400(message: I18n.t("two_factor_authentication.admin.only_sms_allowed")) + render_400(message: I18n.t('two_factor_authentication.admin.only_sms_allowed')) end def new_device_params @@ -115,7 +115,7 @@ def target_user def require_not_self if current_user.id == @user.id - render_403(message: I18n.t("two_factor_authentication.admin.self_edit_forbidden")) + render_403(message: I18n.t('two_factor_authentication.admin.self_edit_forbidden')) end end end diff --git a/modules/two_factor_authentication/app/models/two_factor_authentication.rb b/modules/two_factor_authentication/app/models/two_factor_authentication.rb index b56bf137a297..ece37388ac85 100644 --- a/modules/two_factor_authentication/app/models/two_factor_authentication.rb +++ b/modules/two_factor_authentication/app/models/two_factor_authentication.rb @@ -1,5 +1,5 @@ module TwoFactorAuthentication def self.table_name_prefix - "two_factor_authentication_" + 'two_factor_authentication_' end end diff --git a/modules/two_factor_authentication/app/models/two_factor_authentication/device.rb b/modules/two_factor_authentication/app/models/two_factor_authentication/device.rb index 9c47b969f396..9618588635c8 100644 --- a/modules/two_factor_authentication/app/models/two_factor_authentication/device.rb +++ b/modules/two_factor_authentication/app/models/two_factor_authentication/device.rb @@ -1,6 +1,6 @@ module TwoFactorAuthentication class Device < ApplicationRecord - default_scope { order("id ASC") } + default_scope { order('id ASC') } belongs_to :user validates_presence_of :user_id diff --git a/modules/two_factor_authentication/app/models/two_factor_authentication/device/sms.rb b/modules/two_factor_authentication/app/models/two_factor_authentication/device/sms.rb index b8640ef04dcc..54496f4774f2 100644 --- a/modules/two_factor_authentication/app/models/two_factor_authentication/device/sms.rb +++ b/modules/two_factor_authentication/app/models/two_factor_authentication/device/sms.rb @@ -43,19 +43,19 @@ def default_identifier def request_2fa_identifier(channel) channel_name = if channel == :sms - "SMS" + 'SMS' else - "Voice" + 'Voice' end - I18n.t "two_factor_authentication.devices.sms.request_2fa_identifier", + I18n.t 'two_factor_authentication.devices.sms.request_2fa_identifier', redacted_identifier:, delivery_channel: channel_name end def redacted_identifier number = phone_number.dup - number[1..-3] = "*" * number[1..-3].length - I18n.t "two_factor_authentication.devices.sms.redacted_identifier", + number[1..-3] = '*' * number[1..-3].length + I18n.t 'two_factor_authentication.devices.sms.redacted_identifier', redacted_number: number end diff --git a/modules/two_factor_authentication/app/models/two_factor_authentication/device/totp.rb b/modules/two_factor_authentication/app/models/two_factor_authentication/device/totp.rb index cfee774b9918..a4570de8a15b 100644 --- a/modules/two_factor_authentication/app/models/two_factor_authentication/device/totp.rb +++ b/modules/two_factor_authentication/app/models/two_factor_authentication/device/totp.rb @@ -1,4 +1,4 @@ -require "rotp" +require 'rotp' module TwoFactorAuthentication class Device::Totp < Device @@ -57,11 +57,11 @@ def provisioning_url end def allowed_drift - self.class.manager.configuration["otp_drift_window"] || 60 + self.class.manager.configuration['otp_drift_window'] || 60 end def totp - @totp ||= ::ROTP::TOTP.new otp_secret, issuer: Setting.app_title.presence || "OpenProject" + @totp ||= ::ROTP::TOTP.new otp_secret, issuer: Setting.app_title.presence || 'OpenProject' end end end diff --git a/modules/two_factor_authentication/app/models/two_factor_authentication/login_token.rb b/modules/two_factor_authentication/app/models/two_factor_authentication/login_token.rb index 4ce92b142366..846376fe21ec 100644 --- a/modules/two_factor_authentication/app/models/two_factor_authentication/login_token.rb +++ b/modules/two_factor_authentication/app/models/two_factor_authentication/login_token.rb @@ -8,7 +8,7 @@ def self.validity_time def self.generate_token_value chars = ("0".."9").to_a - password = "" + password = '' 6.times { |_i| password << chars[rand(chars.size - 1)] } password end diff --git a/modules/two_factor_authentication/app/models/two_factor_authentication/remembered_auth_token.rb b/modules/two_factor_authentication/app/models/two_factor_authentication/remembered_auth_token.rb index 730d7a69b717..09f8c3b9f60d 100644 --- a/modules/two_factor_authentication/app/models/two_factor_authentication/remembered_auth_token.rb +++ b/modules/two_factor_authentication/app/models/two_factor_authentication/remembered_auth_token.rb @@ -22,7 +22,7 @@ def single_value? def validate_remember_time unless self.class.allow_remember_for_days > 0 - errors.add :base, "Invalid remember time" + errors.add :base, 'Invalid remember time' end end diff --git a/modules/two_factor_authentication/app/services/two_factor_authentication/token_service.rb b/modules/two_factor_authentication/app/services/two_factor_authentication/token_service.rb index 84a0ff401b04..f8e8e021f189 100644 --- a/modules/two_factor_authentication/app/services/two_factor_authentication/token_service.rb +++ b/modules/two_factor_authentication/app/services/two_factor_authentication/token_service.rb @@ -88,13 +88,13 @@ def get_matching_strategy ## # Perform service checks for the request and validate endpoints of this service def verify_device_and_strategy - raise I18n.t("two_factor_authentication.error_2fa_disabled") unless manager.enabled? + raise I18n.t('two_factor_authentication.error_2fa_disabled') unless manager.enabled? # Ensure the user's default device for OTP exists - raise I18n.t("two_factor_authentication.error_no_device") if device.nil? + raise I18n.t('two_factor_authentication.error_no_device') if device.nil? # Ensure a matching registered strategy for the device's channel exists - raise I18n.t("two_factor_authentication.error_no_matching_strategy") if strategy.nil? + raise I18n.t('two_factor_authentication.error_no_matching_strategy') if strategy.nil? end def manager diff --git a/modules/two_factor_authentication/app/services/two_factor_authentication/use_backup_code_service.rb b/modules/two_factor_authentication/app/services/two_factor_authentication/use_backup_code_service.rb index 19d9d160adb1..1a90bfbb8448 100644 --- a/modules/two_factor_authentication/app/services/two_factor_authentication/use_backup_code_service.rb +++ b/modules/two_factor_authentication/app/services/two_factor_authentication/use_backup_code_service.rb @@ -13,7 +13,7 @@ def initialize(user:) def verify(code) token = user.otp_backup_codes.find_by_plaintext_value(code) - raise I18n.t("two_factor_authentication.error_invalid_backup_code") if token.nil? + raise I18n.t('two_factor_authentication.error_invalid_backup_code') if token.nil? use_valid_token! token rescue StandardError => e diff --git a/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/enter_backup_code.html.erb b/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/enter_backup_code.html.erb index 4406a7d07c03..bbcb4b808abe 100644 --- a/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/enter_backup_code.html.erb +++ b/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/enter_backup_code.html.erb @@ -11,8 +11,9 @@ <%= styled_text_field_tag 'backup_code', nil, required: true, autocomplete: 'off', size: 20, maxlength: 20, tabindex: 1, autofocus: true %> - - + <% end %> diff --git a/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/request_otp.html.erb b/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/request_otp.html.erb index d4298e181254..55a88d9159b3 100644 --- a/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/request_otp.html.erb +++ b/modules/two_factor_authentication/app/views/two_factor_authentication/authentication/request_otp.html.erb @@ -43,20 +43,24 @@ <% end %> - - <% if resend_supported || has_other_devices || has_backup_codes %> -
  • <%= link_to new_my_2fa_device_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t('two_factor_authentication.label_device')}, title: t('two_factor_authentication.devices.add_new')} do %> <%= op_icon('button--icon icon-add') %> diff --git a/modules/two_factor_authentication/app/views/two_factor_authentication/settings.html.erb b/modules/two_factor_authentication/app/views/two_factor_authentication/settings.html.erb index 6c43855e3d51..91e5de1eee6c 100644 --- a/modules/two_factor_authentication/app/views/two_factor_authentication/settings.html.erb +++ b/modules/two_factor_authentication/app/views/two_factor_authentication/settings.html.erb @@ -69,6 +69,6 @@ - <%= styled_submit_tag t(:button_apply), class: '-primary' %> + <%= styled_submit_tag t(:button_apply), class: '-highlight' %> <% end %> diff --git a/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/confirm.html.erb b/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/confirm.html.erb index 44c45f1da3fd..3b1fcb07c865 100644 --- a/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/confirm.html.erb +++ b/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/confirm.html.erb @@ -13,7 +13,7 @@ <%= styled_text_field_tag 'otp', nil, required: true, autocomplete: 'off', size: 6, maxlength: 6, tabindex: 1, autofocus: true %> -
    - + <% end %> diff --git a/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/new.html.erb b/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/new.html.erb index 5786e8c970b3..af4dbe010d09 100644 --- a/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/new.html.erb +++ b/modules/two_factor_authentication/app/views/two_factor_authentication/two_factor_devices/new.html.erb @@ -15,7 +15,7 @@ <%= hidden_field_tag 'key', @device_type %> <%= render partial: "two_factor_authentication/two_factor_devices/form", locals: { f: f, device_type: @device_type, device: @device, user: @user } %>

    - <%= styled_button_tag t(:button_continue), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_continue), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), index_path, class: 'button -with-icon icon-cancel' %>

    <% end %> diff --git a/modules/two_factor_authentication/app/views/users/_two_factor_authentication_admin.html.erb b/modules/two_factor_authentication/app/views/users/_two_factor_authentication_admin.html.erb index a1aa59dffc0d..306cbc837628 100644 --- a/modules/two_factor_authentication/app/views/users/_two_factor_authentication_admin.html.erb +++ b/modules/two_factor_authentication/app/views/users/_two_factor_authentication_admin.html.erb @@ -39,7 +39,7 @@ <% end %> <% if ::OpenProject::TwoFactorAuthentication::TokenStrategyManager.admin_register_sms_strategy.present? %>
  • - <%= link_to new_user_2fa_device_path(@user, type: :sms), class: 'button -primary' do %> + <%= link_to new_user_2fa_device_path(@user, type: :sms), class: 'button -alt-highlight' do %> <%= op_icon 'button--icon icon-add' %> <%= t 'two_factor_authentication.admin.button_register_mobile_phone_for_user' %> <% end %> diff --git a/modules/two_factor_authentication/config/locales/crowdin/ru.yml b/modules/two_factor_authentication/config/locales/crowdin/ru.yml index 6bb673a4ff41..3239661bdeae 100644 --- a/modules/two_factor_authentication/config/locales/crowdin/ru.yml +++ b/modules/two_factor_authentication/config/locales/crowdin/ru.yml @@ -174,7 +174,7 @@ ru: label_expiration_hint: "%{date} или при выходе из системы" label_actions: "Действия" label_confirmed: "Подтвержден" - button_continue: "Далее" + button_continue: "Продолжить" button_make_default: "Задать по умолчанию" label_unverified_phone: "Сотовый телефон еще не подтвержден" notice_phone_number_format: "Введите номер в следующем формате: +XX XXXXXXXX." diff --git a/modules/two_factor_authentication/config/locales/crowdin/uk.yml b/modules/two_factor_authentication/config/locales/crowdin/uk.yml index 128e5436d546..e1e0d01331c8 100644 --- a/modules/two_factor_authentication/config/locales/crowdin/uk.yml +++ b/modules/two_factor_authentication/config/locales/crowdin/uk.yml @@ -114,7 +114,7 @@ uk: failed_to_delete: "Не вдалося видалити пристрій 2FA." is_default_cannot_delete: "Пристрій позначено як типовий і його не можна видалити через активну політику безпеки. Перед видаленням позначте інший пристрій як стандартний." not_existing: "Для вашого облікового запису не зареєстровано жодного пристрою 2FA." - 2fa_from_input: Введіть код, що надійшов на пристрій %{device_name}, щоб підтвердити свою особу. + 2fa_from_input: Введіть код, отриманий на пристрій %{device_name}, щоб підтвердити свою особу. 2fa_from_webauthn: Укажіть пристрій WebAuthn %{device_name}. Якщо це USB-пристрій, переконайтеся, що його підключено, і торкніться його. Потім натисніть кнопку входу. webauthn: title: "WebAuthn" diff --git a/modules/two_factor_authentication/config/routes.rb b/modules/two_factor_authentication/config/routes.rb index 27fbab7b1430..b3c15627233a 100644 --- a/modules/two_factor_authentication/config/routes.rb +++ b/modules/two_factor_authentication/config/routes.rb @@ -1,24 +1,24 @@ Rails.application.routes.draw do - namespace "two_factor_authentication" do - get :request, to: "authentication#request_otp" - post :confirm, to: "authentication#confirm_otp" - post :retry, to: "authentication#retry" - get :backup_code, to: "authentication#enter_backup_code" - post :backup_code, to: "authentication#verify_backup_code" + namespace 'two_factor_authentication' do + get :request, to: 'authentication#request_otp' + post :confirm, to: 'authentication#confirm_otp' + post :retry, to: 'authentication#retry' + get :backup_code, to: 'authentication#enter_backup_code' + post :backup_code, to: 'authentication#verify_backup_code' - get :settings, to: "two_factor_settings#show", as: "settings_2fa" - post :settings, to: "two_factor_settings#update", as: "update_settings_2fa" + get :settings, to: 'two_factor_settings#show', as: 'settings_2fa' + post :settings, to: 'two_factor_settings#update', as: 'update_settings_2fa' # Request a challenge for WebAuthn - get :webauthn_challenge, to: "authentication#webauthn_challenge", as: "webauthn_challenge" + get :webauthn_challenge, to: 'authentication#webauthn_challenge', as: 'webauthn_challenge' end - scope "two_factor_authentication" do # Avoids adding the namespace prefix + scope 'two_factor_authentication' do # Avoids adding the namespace prefix # forced registration - scope "device_registration", controller: "two_factor_authentication/forced_registration/two_factor_devices" do - get :new, action: :new, as: "new_forced_2fa_device" - post :register, action: :register, as: "register_forced_2fa_device" - match "/:device_id/confirm", action: :confirm, via: %i[get post], as: "confirm_forced_2fa_device" + scope 'device_registration', controller: 'two_factor_authentication/forced_registration/two_factor_devices' do + get :new, action: :new, as: 'new_forced_2fa_device' + post :register, action: :register, as: 'register_forced_2fa_device' + match '/:device_id/confirm', action: :confirm, via: %i[get post], as: 'confirm_forced_2fa_device' # Request a challenge for WebAuthn get :webauthn_challenge @@ -29,8 +29,8 @@ member do resources :two_factor_devices, param: :device_id, - controller: "two_factor_authentication/users/two_factor_devices", - as: "user_2fa_devices", + controller: 'two_factor_authentication/users/two_factor_devices', + as: 'user_2fa_devices', only: %i[new create destroy] do # Register new device ( 'create' ) post :register, on: :collection @@ -44,21 +44,21 @@ end end - scope "my" do + scope 'my' do resource :backup_codes, - controller: "two_factor_authentication/my/backup_codes", - as: "my_2fa_backup_codes", + controller: 'two_factor_authentication/my/backup_codes', + as: 'my_2fa_backup_codes', only: %i[show create] resource :remember_cookie, - controller: "two_factor_authentication/my/remember_cookie", - as: "my_2fa_remember_cookie", + controller: 'two_factor_authentication/my/remember_cookie', + as: 'my_2fa_remember_cookie', only: [:destroy] resources :two_factor_devices, - controller: "two_factor_authentication/my/two_factor_devices", + controller: 'two_factor_authentication/my/two_factor_devices', param: :device_id, - as: "my_2fa_devices", + as: 'my_2fa_devices', only: %i[index new destroy] do # Register new device ( 'create' ) post :register, on: :collection diff --git a/modules/two_factor_authentication/db/migrate/20120214103300_aggregated_mobile_otp_migrations.rb b/modules/two_factor_authentication/db/migrate/20120214103300_aggregated_mobile_otp_migrations.rb index c50a84634baf..205526f0b008 100644 --- a/modules/two_factor_authentication/db/migrate/20120214103300_aggregated_mobile_otp_migrations.rb +++ b/modules/two_factor_authentication/db/migrate/20120214103300_aggregated_mobile_otp_migrations.rb @@ -28,7 +28,7 @@ require Rails.root.join("db/migrate/migration_utils/migration_squasher").to_s require Rails.root.join("db/migrate/migration_utils/setting_renamer").to_s -require "open_project/plugins/migration_mapping" +require 'open_project/plugins/migration_mapping' # This migration aggregates the migrations detailed in MIGRATION_FILES class AggregatedMobileOtpMigrations < ActiveRecord::Migration[5.0] diff --git a/modules/two_factor_authentication/db/migrate/20130214130336_add_default_otp_channel_to_user.rb b/modules/two_factor_authentication/db/migrate/20130214130336_add_default_otp_channel_to_user.rb index c4ae6a4318b7..6133bab639c2 100644 --- a/modules/two_factor_authentication/db/migrate/20130214130336_add_default_otp_channel_to_user.rb +++ b/modules/two_factor_authentication/db/migrate/20130214130336_add_default_otp_channel_to_user.rb @@ -28,7 +28,7 @@ class AddDefaultOtpChannelToUser < ActiveRecord::Migration[5.0] def self.up - add_column :users, :default_otp_channel, :string, default: "text" + add_column :users, :default_otp_channel, :string, default: 'text' end def self.down diff --git a/modules/two_factor_authentication/db/migrate/20160331190036_change_default_channel.rb b/modules/two_factor_authentication/db/migrate/20160331190036_change_default_channel.rb index 341bc62bcb00..b9583c128b4b 100644 --- a/modules/two_factor_authentication/db/migrate/20160331190036_change_default_channel.rb +++ b/modules/two_factor_authentication/db/migrate/20160331190036_change_default_channel.rb @@ -28,12 +28,12 @@ class ChangeDefaultChannel < ActiveRecord::Migration[5.0] def self.up - change_column_default(:users, :default_otp_channel, "sms") - User.where(default_otp_channel: "text").update_all(default_otp_channel: "sms") + change_column_default(:users, :default_otp_channel, 'sms') + User.where(default_otp_channel: 'text').update_all(default_otp_channel: 'sms') end def self.down - change_column_default(:users, :default_otp_channel, "text") - User.where(default_otp_channel: "sms").update_all(default_otp_channel: "text") + change_column_default(:users, :default_otp_channel, 'text') + User.where(default_otp_channel: 'sms').update_all(default_otp_channel: 'text') end end diff --git a/modules/two_factor_authentication/db/migrate/20171023190036_model_reorganization.rb b/modules/two_factor_authentication/db/migrate/20171023190036_model_reorganization.rb index 02b677236d15..53a58d84075a 100644 --- a/modules/two_factor_authentication/db/migrate/20171023190036_model_reorganization.rb +++ b/modules/two_factor_authentication/db/migrate/20171023190036_model_reorganization.rb @@ -55,7 +55,7 @@ def self.up t.integer "last_used_at", null: true # OTP secret for totp - t.text "otp_secret", null: true + t.text 'otp_secret', null: true end add_reference :two_factor_authentication_devices, :user, foreign_key: true, type: :integer @@ -67,7 +67,7 @@ def self.up sms = ::TwoFactorAuthentication::Device::Sms.create!( user_id: user.id, - identifier: "Mobile", + identifier: 'Mobile', channel: user.default_otp_channel, phone_number: phone, active: true @@ -76,7 +76,7 @@ def self.up end end - change_table "users" do |t| + change_table 'users' do |t| t.remove :verified_phone t.remove :unverified_phone t.remove :default_otp_channel @@ -84,10 +84,10 @@ def self.up end def self.down - change_table "users" do |t| + change_table 'users' do |t| t.string :verified_phone t.string :unverified_phone - t.string :default_otp_channel, default: "sms" + t.string :default_otp_channel, default: 'sms' end # Write back information from sms devices to table diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb index becd5206b7d0..6b7a9cfc16be 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/engine.rb @@ -1,5 +1,5 @@ -require "open_project/plugins" -require "webauthn" +require 'open_project/plugins' +require 'webauthn' module OpenProject::TwoFactorAuthentication class Engine < ::Rails::Engine @@ -7,8 +7,8 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-two_factor_authentication", - author_url: "https://www.openproject.org", + register 'openproject-two_factor_authentication', + author_url: 'https://www.openproject.org', settings: { default: { # Only app-based 2FA allowed per default @@ -19,21 +19,21 @@ class Engine < ::Rails::Engine # Don't allow remember cookie allow_remember_for_days: 0 }, - env_alias: "OPENPROJECT_2FA" + env_alias: 'OPENPROJECT_2FA' }, bundled: true do menu :my_menu, :two_factor_authentication, - { controller: "/two_factor_authentication/my/two_factor_devices", action: :index }, - caption: ->(*) { I18n.t("two_factor_authentication.label_two_factor_authentication") }, + { controller: '/two_factor_authentication/my/two_factor_devices', action: :index }, + caption: ->(*) { I18n.t('two_factor_authentication.label_two_factor_authentication') }, after: :password, if: ->(*) { ::OpenProject::TwoFactorAuthentication::TokenStrategyManager.enabled? }, - icon: "two-factor-authentication" + icon: 'two-factor-authentication' menu :admin_menu, :two_factor_authentication, - { controller: "/two_factor_authentication/two_factor_settings", action: :show }, - caption: ->(*) { I18n.t("two_factor_authentication.label_two_factor_authentication") }, + { controller: '/two_factor_authentication/two_factor_settings', action: :show }, + caption: ->(*) { I18n.t('two_factor_authentication.label_two_factor_authentication') }, parent: :authentication, if: ->(*) { ::OpenProject::TwoFactorAuthentication::TokenStrategyManager.configurable_by_ui? } end @@ -41,10 +41,10 @@ class Engine < ::Rails::Engine patches %i[User] add_tab_entry :user, - name: "two_factor_authentication", - partial: "users/two_factor_authentication", + name: 'two_factor_authentication', + partial: 'users/two_factor_authentication', path: ->(params) { edit_user_path(params[:user], tab: :two_factor_authentication) }, - label: "two_factor_authentication.label_two_factor_authentication", + label: 'two_factor_authentication.label_two_factor_authentication', only_if: ->(*) { User.current.admin? && OpenProject::TwoFactorAuthentication::TokenStrategyManager.enabled? } config.to_prepare do diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/patches/user_patch.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/patches/user_patch.rb index 6c4f8d001952..47318247dfb5 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/patches/user_patch.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/patches/user_patch.rb @@ -2,9 +2,9 @@ module OpenProject::TwoFactorAuthentication::Patches module UserPatch def self.included(base) base.class_eval do - has_many :otp_tokens, class_name: "TwoFactorAuthentication::LoginToken", dependent: :destroy - has_many :otp_devices, class_name: "TwoFactorAuthentication::Device", dependent: :destroy - has_many :otp_backup_codes, class_name: "TwoFactorAuthentication::BackupCode", dependent: :destroy + has_many :otp_tokens, class_name: 'TwoFactorAuthentication::LoginToken', dependent: :destroy + has_many :otp_devices, class_name: 'TwoFactorAuthentication::Device', dependent: :destroy + has_many :otp_backup_codes, class_name: 'TwoFactorAuthentication::BackupCode', dependent: :destroy end end end diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/base.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/base.rb index d2db49090035..f17222a067e0 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/base.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/base.rb @@ -7,7 +7,7 @@ def initialize(user:, device:, channel: nil) @channel = channel.presence || device.channel unless self.class.supported?(device.channel) - raise ArgumentError, I18n.t("two_factor_authentication.channel_unavailable", channel: device.channel) + raise ArgumentError, I18n.t('two_factor_authentication.channel_unavailable', channel: device.channel) end @user = user @@ -16,7 +16,7 @@ def initialize(user:, device:, channel: nil) def verify(input_token, **) # Ensure this strategy uses mobile tokens or overrode this method - raise "Cannot verify mobile token" unless self.class.mobile_token? + raise 'Cannot verify mobile token' unless self.class.mobile_token? token = user.otp_tokens.find_by_plaintext_value(input_token) @@ -44,7 +44,7 @@ def identifier end def transmit_success_message - I18n.t("two_factor_authentication.mobile_transmit_notification") + I18n.t('two_factor_authentication.mobile_transmit_notification') end def self.mobile_token? diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/message_bird.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/message_bird.rb index 336360644196..eef8f1387ac2 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/message_bird.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/message_bird.rb @@ -1,11 +1,11 @@ -require "messagebird" +require 'messagebird' module OpenProject::TwoFactorAuthentication module TokenStrategy class MessageBird < Base def self.validate! if configuration_params.nil? - raise ArgumentError, "Missing configuration hash" + raise ArgumentError, 'Missing configuration hash' end validate_params configuration_params @@ -35,16 +35,16 @@ def send_sms params[:message], validity: 720 - raise "Failed to deliver SMS" if response.recipients["totalDeliveryFailedCount"] > 0 + raise "Failed to deliver SMS" if response.recipients['totalDeliveryFailedCount'] > 0 rescue StandardError => e Rails.logger.error("[2FA] MessageBird SMS delivery failed for user #{user.login}. Error: #{e} #{e.message}") - raise I18n.t("two_factor_authentication.message_bird.sms_delivery_failed") + raise I18n.t('two_factor_authentication.message_bird.sms_delivery_failed') end ## # TODO ensure the originator cannot be larger than 11 characters def originator - "OpenProject" + 'OpenProject' end def send_voice @@ -56,14 +56,14 @@ def send_voice ifMachine: :continue, language: params[:language] - raise "Failed to initiate voice message" if response.recipients["totalDeliveryFailedCount"] > 0 + raise "Failed to initiate voice message" if response.recipients['totalDeliveryFailedCount'] > 0 rescue StandardError => e Rails.logger.error("[2FA] MessageBird VOICE delivery failed for user #{user.login}. Error: #{e} #{e.message}") - raise I18n.t("two_factor_authentication.message_bird.voice_delivery_failed") + raise I18n.t('two_factor_authentication.message_bird.voice_delivery_failed') end def message_bird_client - ::MessageBird::Client.new(configuration_params["apikey"]) + ::MessageBird::Client.new(configuration_params['apikey']) end ## @@ -136,7 +136,7 @@ def get_matching_language(language) ## # Fallback language def fallback_language - :"en-us" + :'en-us' end ## @@ -151,11 +151,11 @@ def has_localized_text?(locale_key) ## # Localize the message def localized_message(locale_key, token_value, fallback: true, raise_on_missing: false) - pause = "" + pause = '' # Output pauses for TTS in voice mode if channel.to_sym == :voice - token_value = token_value.split("").join('') + token_value = token_value.split('').join('') pause = '' end @@ -173,7 +173,7 @@ def localized_message(locale_key, token_value, fallback: true, raise_on_missing: # Output format: xxyyyyyyyyyy def build_recipients(params) phone = device.phone_number - phone.gsub!(/[+\s]/, "") + phone.gsub!(/[+\s]/, '') params[:recipients] = phone end diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/sns.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/sns.rb index bf75a9ce96d9..b6514851a602 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/sns.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/sns.rb @@ -1,5 +1,5 @@ -require "net/http" -require "aws-sdk-sns" +require 'net/http' +require 'aws-sdk-sns' module OpenProject::TwoFactorAuthentication module TokenStrategy @@ -48,7 +48,7 @@ def build_sms_params end def build_token_text(token) - I18n.t("two_factor_authentication.text_otp_delivery_message_sms", app_title: Setting.app_title, token:) + I18n.t('two_factor_authentication.text_otp_delivery_message_sms', app_title: Setting.app_title, token:) end ## @@ -57,24 +57,24 @@ def build_token_text(token) # Stored format: +xx yyy yyy yyyy (optional whitespacing) def build_user_phone phone = device.phone_number - phone.gsub!(/\s/, "") + phone.gsub!(/\s/, '') phone end # rubocop:disable Metrics/AbcSize def submit - aws_params = configuration_params.slice "region", "access_key_id", "secret_access_key" + aws_params = configuration_params.slice 'region', 'access_key_id', 'secret_access_key' sns = ::Aws::SNS::Client.new aws_params sns.set_sms_attributes( attributes: { # Use transactional message type to ensure timely delivery. # Amazon SNS optimizes the message delivery to achieve the highest reliability. - "DefaultSMSType" => "Transactional", + 'DefaultSMSType' => 'Transactional', # Set sender ID name (may not be supported in all countries) - "DefaultSenderID" => configuration_params.fetch("sender_id", "OpenProject") + 'DefaultSenderID' => configuration_params.fetch('sender_id', 'OpenProject') } ) @@ -94,7 +94,7 @@ def submit "[2FA] SNS delivery failed for user #{user.login} (Error: #{e})" end - raise I18n.t("two_factor_authentication.sns.delivery_failed") + raise I18n.t('two_factor_authentication.sns.delivery_failed') end # rubocop:enable Metrics/AbcSize end diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/totp.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/totp.rb index d1431aad5fb9..4221c8cd5a99 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/totp.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/totp.rb @@ -1,4 +1,4 @@ -require "rotp" +require 'rotp' module OpenProject::TwoFactorAuthentication module TokenStrategy diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/webauthn.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/webauthn.rb index 6a511ee78135..3c035a22130c 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/webauthn.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy/webauthn.rb @@ -1,4 +1,4 @@ -require "webauthn" +require 'webauthn' module OpenProject::TwoFactorAuthentication module TokenStrategy diff --git a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy_manager.rb b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy_manager.rb index a212beced7e7..558adf26bcbb 100644 --- a/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy_manager.rb +++ b/modules/two_factor_authentication/lib/open_project/two_factor_authentication/token_strategy_manager.rb @@ -51,17 +51,17 @@ def admin_register_sms_strategy ## # Whether the system requires 2FA for all users def enforced? - !!configuration["enforced"] + !!configuration['enforced'] end ## # Determine whether the plugin settings can be changed from the UI def configurable_by_ui? - !configuration["hide_settings_menu_item"] + !configuration['hide_settings_menu_item'] end def allow_remember_for_days - configuration["allow_remember_for_days"].to_i + configuration['allow_remember_for_days'].to_i end ## @@ -73,7 +73,7 @@ def invalid_configuration? ## # Fetch all active strategies def active_strategies - configuration.fetch("active_strategies", []) + configuration.fetch('active_strategies', []) .map(&:to_s) .uniq .map { |strategy| lookup_active_strategy strategy } @@ -107,18 +107,18 @@ def configuration end def enforced_by_configuration? - enforced = (OpenProject::Configuration["2fa"] || {})["enforced"] + enforced = (OpenProject::Configuration['2fa'] || {})['enforced'] ActiveModel::Type::Boolean.new.cast enforced end def merge_with_settings!(config) - config["active_strategies"] ||= [] + config['active_strategies'] ||= [] # Always enable webauthn and totp if nothing is enabled - config["active_strategies"] += %i[totp webauthn] if add_default_strategy?(config) + config['active_strategies'] += %i[totp webauthn] if add_default_strategy?(config) end def add_default_strategy?(config) - config["active_strategies"].empty? && config["disabled"].blank? + config['active_strategies'].empty? && config['disabled'].blank? end def available_strategies diff --git a/modules/two_factor_authentication/lib/openproject-two_factor_authentication.rb b/modules/two_factor_authentication/lib/openproject-two_factor_authentication.rb index e5913b2cef82..520554f8269a 100644 --- a/modules/two_factor_authentication/lib/openproject-two_factor_authentication.rb +++ b/modules/two_factor_authentication/lib/openproject-two_factor_authentication.rb @@ -1 +1 @@ -require "open_project/two_factor_authentication" +require 'open_project/two_factor_authentication' diff --git a/modules/two_factor_authentication/openproject-two_factor_authentication.gemspec b/modules/two_factor_authentication/openproject-two_factor_authentication.gemspec index ed69c02057e4..369b9e4377c8 100644 --- a/modules/two_factor_authentication/openproject-two_factor_authentication.gemspec +++ b/modules/two_factor_authentication/openproject-two_factor_authentication.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "openproject-two_factor_authentication" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" s.summary = "OpenProject Two-factor authentication" @@ -10,10 +10,10 @@ Gem::Specification.new do |s| s.files = Dir["{app,config,db,lib}/**/*", "CHANGELOG.md", "README.rdoc"] - s.add_dependency "messagebird-rest", "~> 1.4.2" - s.add_dependency "rotp", "~> 6.1" - s.add_dependency "webauthn", "~> 3.0" + s.add_dependency 'messagebird-rest', '~> 1.4.2' + s.add_dependency 'rotp', '~> 6.1' + s.add_dependency 'webauthn', '~> 3.0' - s.add_dependency "aws-sdk-sns", "~> 1.72.0" - s.metadata["rubygems_mfa_required"] = "true" + s.add_dependency 'aws-sdk-sns', '~> 1.72.0' + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_shared_examples.rb b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_shared_examples.rb index 4224071927c0..cb6ea2cefd6a 100644 --- a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_shared_examples.rb +++ b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_shared_examples.rb @@ -1,7 +1,7 @@ -require_relative "../../spec_helper" +require_relative '../../spec_helper' -RSpec.shared_examples "immediate success login" do - context "with valid credentials" do +RSpec.shared_examples 'immediate success login' do + context 'with valid credentials' do it "does not yet log in user" do expect(User.current).not_to eq(user) end @@ -11,12 +11,12 @@ end it "renders redirect" do - expect(response).to redirect_to stage_success_path(stage: :two_factor_authentication, secret: "asdf") + expect(response).to redirect_to stage_success_path(stage: :two_factor_authentication, secret: 'asdf') end end end -RSpec.shared_examples "2FA forced registry" do +RSpec.shared_examples '2FA forced registry' do it "does not log in user" do expect(User.current).not_to eq(user) end @@ -35,7 +35,7 @@ end end -RSpec.shared_examples "2FA response failure" do |expected_error| +RSpec.shared_examples '2FA response failure' do |expected_error| it "does not log in user" do expect(User.current).not_to eq(user) end @@ -50,17 +50,17 @@ end end -RSpec.shared_examples "2FA login request failure" do |expected_error| +RSpec.shared_examples '2FA login request failure' do |expected_error| before do session[:authenticated_user_id] = user.id get :request_otp end - it_behaves_like "2FA response failure", expected_error + it_behaves_like '2FA response failure', expected_error end -RSpec.shared_examples "2FA credentials authentication success" do - describe "requesting the token" do +RSpec.shared_examples '2FA credentials authentication success' do + describe 'requesting the token' do before do session[:authenticated_user_id] = user.id get :request_otp @@ -75,17 +75,17 @@ end it "renders the login_otp" do - expect(response).to render_template "request_otp" + expect(response).to render_template 'request_otp' end end end -RSpec.shared_examples "2FA login_otp fails without authenticated user" do - describe "follow-up post of the login token without authenticated user" do +RSpec.shared_examples '2FA login_otp fails without authenticated user' do + describe 'follow-up post of the login token without authenticated user' do before do # Assume the user is NOT pending session[:authenticated_user_id] = nil - post :confirm_otp, params: { otp: "does not matter" } + post :confirm_otp, params: { otp: 'does not matter' } end it "redirects to login page" do @@ -98,15 +98,15 @@ end end -RSpec.shared_examples "2FA TOTP request success" do +RSpec.shared_examples '2FA TOTP request success' do # 1FA redirects to login_otp - it_behaves_like "2FA credentials authentication success" + it_behaves_like '2FA credentials authentication success' # Cannot post to login_otp without authenticated user session - it_behaves_like "2FA login_otp fails without authenticated user" + it_behaves_like '2FA login_otp fails without authenticated user' # Can post to login_otp with pending and token - describe "follow-up post of a login token" do + describe 'follow-up post of a login token' do before do # Assume the user is pending session[:authenticated_user_id] = user.id @@ -114,36 +114,36 @@ post :confirm_otp, params: { otp: token } end - context "with a valid token" do + context 'with a valid token' do let(:token) { device.totp.now } - it_behaves_like "immediate success login" + it_behaves_like 'immediate success login' end - context "with an invalid token" do - let(:token) { "bogus" } + context 'with an invalid token' do + let(:token) { 'bogus' } - it_behaves_like "2FA response failure", I18n.t(:notice_account_otp_invalid) + it_behaves_like '2FA response failure', I18n.t(:notice_account_otp_invalid) end end end -RSpec.shared_examples "2FA SMS request success" do +RSpec.shared_examples '2FA SMS request success' do # 1FA redirects to login_otp - it_behaves_like "2FA credentials authentication success" + it_behaves_like '2FA credentials authentication success' # Cannot post to login_otp without pending user session - it_behaves_like "2FA login_otp fails without authenticated user" + it_behaves_like '2FA login_otp fails without authenticated user' - describe "follow-up post of a login token" do - let(:valid_token) { instance_double(TwoFactorAuthentication::LoginToken, value: "123456") } + describe 'follow-up post of a login token' do + let(:valid_token) { instance_double(TwoFactorAuthentication::LoginToken, value: '123456') } before do # Assume the user is pending session[:authenticated_user_id] = user.id end - context "with a valid token" do + context 'with a valid token' do before do # Return the value upon find expect(TwoFactorAuthentication::LoginToken) @@ -155,31 +155,31 @@ post :confirm_otp, params: { otp: valid_token.value } end - context "when not expired" do + context 'when not expired' do let(:expired) { false } - it_behaves_like "immediate success login" + it_behaves_like 'immediate success login' end - context "when expired" do + context 'when expired' do let(:expired) { true } - it_behaves_like "2FA response failure", I18n.t(:notice_account_otp_invalid) + it_behaves_like '2FA response failure', I18n.t(:notice_account_otp_invalid) end end - context "with an invalid token" do + context 'with an invalid token' do before do # Return the value upon find expect(TwoFactorAuthentication::LoginToken) .to receive(:find_by_plaintext_value) - .with("bogus") + .with('bogus') .and_return(nil) - post :confirm_otp, params: { otp: "bogus" } + post :confirm_otp, params: { otp: 'bogus' } end - it_behaves_like "2FA response failure", I18n.t(:notice_account_otp_invalid) + it_behaves_like '2FA response failure', I18n.t(:notice_account_otp_invalid) end end end diff --git a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_spec.rb b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_spec.rb index 82208614009b..a8233f4c85d6 100644 --- a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_spec.rb +++ b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/authentication_controller_spec.rb @@ -1,29 +1,29 @@ -require_relative "../../spec_helper" -require_relative "authentication_controller_shared_examples" +require_relative '../../spec_helper' +require_relative 'authentication_controller_shared_examples' RSpec.describe TwoFactorAuthentication::AuthenticationController, with_settings: { login_required?: true } do let(:valid_credentials) do - { username: "foobar", password: "AAA1111!!!!" } + { username: 'foobar', password: 'AAA1111!!!!' } end - let(:user) { create(:user, login: "foobar", password: "AAA1111!!!!", password_confirmation: "AAA1111!!!!") } + let(:user) { create(:user, login: 'foobar', password: 'AAA1111!!!!', password_confirmation: 'AAA1111!!!!') } before do # Assume the user has any memberships - session[:stage_secrets] = { two_factor_authentication: "asdf" } + session[:stage_secrets] = { two_factor_authentication: 'asdf' } allow_any_instance_of(User).to receive(:any_active_memberships?).and_return(true) end - describe "with no active strategy", with_settings: { "plugin_openproject_two_factor_authentication" => {} } do + describe 'with no active strategy', with_settings: { 'plugin_openproject_two_factor_authentication' => {} } do before do session[:authenticated_user_id] = user.id get :request_otp end - it_behaves_like "immediate success login" + it_behaves_like 'immediate success login' end - describe "with no active strategy, but 2FA enforced as configuration", - with_settings: { "plugin_openproject_two_factor_authentication" => { active_strategies: [], enforced: true } } do + describe 'with no active strategy, but 2FA enforced as configuration', + with_settings: { 'plugin_openproject_two_factor_authentication' => { active_strategies: [], enforced: true } } do before do allow(OpenProject::TwoFactorAuthentication::TokenStrategyManager) .to receive(:add_default_strategy?) @@ -32,37 +32,37 @@ get :request_otp end - it "returns a 500" do + it 'returns a 500' do expect(response.status).to eq 500 end end - describe "with one active strategy, enforced", with_settings: { - "plugin_openproject_two_factor_authentication" => { active_strategies: [:developer], enforced: true } + describe 'with one active strategy, enforced', with_settings: { + 'plugin_openproject_two_factor_authentication' => { active_strategies: [:developer], enforced: true } } do - context "with no device" do + context 'with no device' do before do session[:authenticated_user_id] = user.id get :request_otp end - it_behaves_like "2FA forced registry" + it_behaves_like '2FA forced registry' end end - describe "with one active strategy", - with_settings: { "plugin_openproject_two_factor_authentication" => { active_strategies: [:developer] } } do - context "with no device" do + describe 'with one active strategy', + with_settings: { 'plugin_openproject_two_factor_authentication' => { active_strategies: [:developer] } } do + context 'with no device' do before do session[:authenticated_user_id] = user.id get :request_otp end # User can login without 2FA, since its not enforced - it_behaves_like "immediate success login" + it_behaves_like 'immediate success login' end - context "with a non-default device" do + context 'with a non-default device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, default: false, channel: :sms) } before do @@ -71,38 +71,38 @@ end # User can login without 2FA, since its not enforced - it_behaves_like "immediate success login" + it_behaves_like 'immediate success login' end - context "with an invalid device" do + context 'with an invalid device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, channel: :totp) } - it_behaves_like "2FA login request failure", I18n.t("two_factor_authentication.error_no_matching_strategy") + it_behaves_like '2FA login request failure', I18n.t('two_factor_authentication.error_no_matching_strategy') end - context "with an active device" do + context 'with an active device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, channel: :sms) } - it_behaves_like "2FA SMS request success" + it_behaves_like '2FA SMS request success' end end - describe "with two active strategy", - with_settings: { "plugin_openproject_two_factor_authentication" => { active_strategies: %i[developer totp] } } do - context "with a totp device" do + describe 'with two active strategy', + with_settings: { 'plugin_openproject_two_factor_authentication' => { active_strategies: %i[developer totp] } } do + context 'with a totp device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, channel: :totp) } - it_behaves_like "2FA TOTP request success" + it_behaves_like '2FA TOTP request success' end - context "with an sms device" do + context 'with an sms device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, channel: :sms) } - it_behaves_like "2FA SMS request success" + it_behaves_like '2FA SMS request success' end end - describe "#login_otp", "for a get request" do + describe '#login_otp', "for a get request" do before do get :confirm_otp end diff --git a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller_spec.rb b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller_spec.rb index 914fefebb05e..3bdd4bb7c322 100644 --- a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller_spec.rb +++ b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/forced_registration/two_factor_devices_controller_spec.rb @@ -1,19 +1,19 @@ -require_relative "../../../spec_helper" -require_relative "../authentication_controller_shared_examples" +require_relative '../../../spec_helper' +require_relative '../authentication_controller_shared_examples' RSpec.describe TwoFactorAuthentication::ForcedRegistration::TwoFactorDevicesController do - let(:user) { create(:user, login: "foobar") } + let(:user) { create(:user, login: 'foobar') } let(:logged_in_user) { User.anonymous } let(:active_strategies) { [] } let(:authenticated_user_id) { user.id } let(:user_force_2fa) { true } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: { - "active_strategies" => active_strategies + 'active_strategies' => active_strategies } } end @@ -23,161 +23,161 @@ allow(User).to receive(:current).and_return(User.anonymous) session[:authenticated_user_id] = authenticated_user_id session[:authenticated_user_force_2fa] = user_force_2fa - session[:stage_secrets] = { two_factor_authentication: "asdf" } + session[:stage_secrets] = { two_factor_authentication: 'asdf' } allow(OpenProject::TwoFactorAuthentication::TokenStrategyManager) .to receive(:add_default_strategy?) .and_return false end - describe "accessing" do + describe 'accessing' do before do get :new end - context "when no authenticated_user present" do + context 'when no authenticated_user present' do let(:active_strategies) { [:developer] } let(:authenticated_user_id) { nil } let(:user_force_2fa) { nil } - it "does not give access" do + it 'does not give access' do expect(response).to be_redirect expect(response).to redirect_to stage_failure_path(stage: :two_factor_authentication) end end - context "when logged in, but not enabled" do - it "does not give access" do + context 'when logged in, but not enabled' do + it 'does not give access' do expect(response.status).to eq 404 end end - context "when authenticated in and active strategies" do + context 'when authenticated in and active strategies' do let(:active_strategies) { [:developer] } - it "renders the new page" do + it 'renders the new page' do expect(response).to be_successful - expect(response).to render_template "two_factor_authentication/two_factor_devices/new_type" + expect(response).to render_template 'two_factor_authentication/two_factor_devices/new_type' end end end - describe "with active strategy" do + describe 'with active strategy' do let(:active_strategies) { [:developer] } - describe "#new" do - context "without type" do + describe '#new' do + context 'without type' do before do get :new end - it "renders the new form" do + it 'renders the new form' do expect(response).to be_successful - expect(response).to render_template "new_type" + expect(response).to render_template 'new_type' end end - context "with type" do + context 'with type' do before do get :new, params: { type: :sms } end - it "renders the new form" do + it 'renders the new form' do expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end end end - describe "#register" do + describe '#register' do before do post :register, params: { key: :sms, device: params } end - context "with missing phone" do - let(:params) { { identifier: "foo" } } + context 'with missing phone' do + let(:params) { { identifier: 'foo' } } - it "renders action new" do + it 'renders action new' do expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' expect(assigns[:device]).to be_invalid end end - context "with valid params" do - let(:params) { { phone_number: "+49123456789", identifier: "foo" } } + context 'with valid params' do + let(:params) { { phone_number: '+49123456789', identifier: 'foo' } } - it "redirects to confirm" do + it 'redirects to confirm' do device = user.otp_devices.reload.last expect(response).to redirect_to action: :confirm, device_id: device.id - expect(device.identifier).to eq "foo (+49123456789)" - expect(device.phone_number).to eq "+49123456789" + expect(device.identifier).to eq 'foo (+49123456789)' + expect(device.phone_number).to eq '+49123456789' expect(device.default).to be_falsey expect(device.active).to be_falsey end end end - describe "#confirm" do - describe "#get" do - it "croaks on missing id" do + describe '#confirm' do + describe '#get' do + it 'croaks on missing id' do get :confirm, params: { device_id: 1234 } expect(response.status).to eq 404 end - describe "and registered totp device" do + describe 'and registered totp device' do let(:active_strategies) { [:totp] } let!(:device) { create(:two_factor_authentication_device_totp, user:, active: false, default: false) } - it "renders the confirmation page" do + it 'renders the confirmation page' do get :confirm, params: { device_id: device.id } expect(response).to be_successful - expect(response).to render_template "confirm" + expect(response).to render_template 'confirm' expect(flash[:notice]).not_to be_present end end - describe "with registered device" do + describe 'with registered device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, active: false, default: false) } - it "renders the confirmation page" do + it 'renders the confirmation page' do get :confirm, params: { device_id: device.id } expect(response).to be_successful - expect(response).to render_template "confirm" + expect(response).to render_template 'confirm' end - it "redirects to failure path if token request failed" do + it 'redirects to failure path if token request failed' do allow_any_instance_of(TwoFactorAuthentication::TokenService) .to receive(:request) .and_return(ServiceResult.failure) get :confirm, params: { device_id: device.id } expect(response).to redirect_to stage_failure_path(stage: :two_factor_authentication) - expect(flash[:error]).to include I18n.t("two_factor_authentication.devices.confirm_send_failed") + expect(flash[:error]).to include I18n.t('two_factor_authentication.devices.confirm_send_failed') end end end - describe "#post" do - it "croaks on missing id" do + describe '#post' do + it 'croaks on missing id' do get :confirm, params: { device_id: 1234 } expect(response.status).to eq 404 end - describe "and registered totp device" do + describe 'and registered totp device' do let(:active_strategies) { [:totp] } let!(:device) { create(:two_factor_authentication_device_totp, user:, active: false, default: false) } - it "renders a 400 on missing token" do + it 'renders a 400 on missing token' do post :confirm, params: { device_id: device.id } expect(response).to redirect_to stage_failure_path(stage: :two_factor_authentication) end - it "redirects to the confirmation on faulty entry" do - post :confirm, params: { device_id: device.id, otp: "1234" } + it 'redirects to the confirmation on faulty entry' do + post :confirm, params: { device_id: device.id, otp: '1234' } expect(response).to redirect_to action: :confirm, device_id: device.id - expect(flash[:error]).to include I18n.t("two_factor_authentication.devices.registration_failed_token_invalid") + expect(flash[:error]).to include I18n.t('two_factor_authentication.devices.registration_failed_token_invalid') device.reload @@ -185,20 +185,20 @@ expect(device.default).to be false end - it "activates the device when entered correctly and logs out the user" do + it 'activates the device when entered correctly and logs out the user' do allow(Sessions::DropAllSessionsService) .to receive(:call) # rubocop:disable RSpec/AnyInstance allow_any_instance_of(TwoFactorAuthentication::TokenService) .to receive(:verify) - .with("1234") + .with('1234') .and_return(ServiceResult.success) # rubocop:enable RSpec/AnyInstance - post :confirm, params: { device_id: device.id, otp: "1234" } - expect(response).to redirect_to stage_success_path(stage: :two_factor_authentication, secret: "asdf") - expect(flash[:notice]).to include I18n.t("two_factor_authentication.devices.registration_complete") + post :confirm, params: { device_id: device.id, otp: '1234' } + expect(response).to redirect_to stage_success_path(stage: :two_factor_authentication, secret: 'asdf') + expect(flash[:notice]).to include I18n.t('two_factor_authentication.devices.registration_complete') device.reload expect(device.active).to be true expect(device.default).to be true diff --git a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/remember_cookie_controller_spec.rb b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/remember_cookie_controller_spec.rb index 8a8ff06ef27d..61ecaf90aa40 100644 --- a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/remember_cookie_controller_spec.rb +++ b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/remember_cookie_controller_spec.rb @@ -1,30 +1,30 @@ -require_relative "../../../spec_helper" -require_relative "../authentication_controller_shared_examples" +require_relative '../../../spec_helper' +require_relative '../authentication_controller_shared_examples' RSpec.describe TwoFactorAuthentication::My::RememberCookieController do - let(:user) { create(:user, login: "foobar") } + let(:user) { create(:user, login: 'foobar') } let(:logged_in_user) { user } before do allow(User).to receive(:current).and_return(logged_in_user) end - describe "#destroy" do + describe '#destroy' do before do delete :destroy end - context "when not logged in" do + context 'when not logged in' do let(:logged_in_user) { User.anonymous } - it "does not give access" do + it 'does not give access' do expect(response).to be_redirect expect(response).to redirect_to signin_path(back_url: my_2fa_remember_cookie_url) end end - context "when logged in and active strategies" do - it "renders the index page" do + context 'when logged in and active strategies' do + it 'renders the index page' do expect(response).to be_redirect expect(flash[:notice]).to be_present end diff --git a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/two_factor_devices_controller_spec.rb b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/two_factor_devices_controller_spec.rb index 3715283ff620..7eb1064e14f8 100644 --- a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/two_factor_devices_controller_spec.rb +++ b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/my/two_factor_devices_controller_spec.rb @@ -1,18 +1,18 @@ -require_relative "../../../spec_helper" -require_relative "../authentication_controller_shared_examples" +require_relative '../../../spec_helper' +require_relative '../authentication_controller_shared_examples' RSpec.describe TwoFactorAuthentication::My::TwoFactorDevicesController do - let(:user) { create(:user, login: "foobar") } + let(:user) { create(:user, login: 'foobar') } let(:other_user) { create(:user) } let(:logged_in_user) { user } let(:active_strategies) { [] } let(:config) { {} } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: { - "active_strategies" => active_strategies + 'active_strategies' => active_strategies }.merge(config) } end @@ -25,153 +25,153 @@ .and_return false end - describe "accessing" do + describe 'accessing' do before do get :index end - context "when not logged in" do + context 'when not logged in' do let(:active_strategies) { [:developer] } let(:logged_in_user) { User.anonymous } - it "does not give access" do + it 'does not give access' do expect(response).to be_redirect expect(response).to redirect_to signin_path(back_url: my_2fa_devices_url) end end - context "when logged in, but not enabled" do - it "does not give access" do + context 'when logged in, but not enabled' do + it 'does not give access' do expect(response.status).to eq 404 end end - context "when logged in and active strategies" do + context 'when logged in and active strategies' do let(:active_strategies) { [:developer] } - it "renders the index page" do + it 'renders the index page' do expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end end end - describe "with active strategy" do + describe 'with active strategy' do let(:active_strategies) { [:developer] } - describe "#new" do - context "without type" do + describe '#new' do + context 'without type' do before do get :new end - it "renders the new form" do + it 'renders the new form' do expect(response).to be_successful - expect(response).to render_template "new_type" + expect(response).to render_template 'new_type' end end - context "with type" do + context 'with type' do before do get :new, params: { type: :sms } end - it "renders the new form" do + it 'renders the new form' do expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end end end - describe "#register" do + describe '#register' do before do post :register, params: { key: :sms, device: params } end - context "with missing phone" do - let(:params) { { identifier: "foo" } } + context 'with missing phone' do + let(:params) { { identifier: 'foo' } } - it "renders action new" do + it 'renders action new' do expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' expect(assigns[:device]).to be_invalid end end - context "with valid params" do - let(:params) { { phone_number: "+49123456789", identifier: "foo" } } + context 'with valid params' do + let(:params) { { phone_number: '+49123456789', identifier: 'foo' } } - it "redirects to confirm" do + it 'redirects to confirm' do device = user.otp_devices.reload.last expect(response).to redirect_to action: :confirm, device_id: device.id - expect(device.identifier).to eq "foo (+49123456789)" - expect(device.phone_number).to eq "+49123456789" + expect(device.identifier).to eq 'foo (+49123456789)' + expect(device.phone_number).to eq '+49123456789' expect(device.default).to be_falsey expect(device.active).to be_falsey end end end - describe "#confirm" do - describe "#get" do - it "croaks on missing id" do + describe '#confirm' do + describe '#get' do + it 'croaks on missing id' do get :confirm, params: { device_id: 1234 } expect(response.status).to eq 404 end - describe "and registered totp device" do + describe 'and registered totp device' do let(:active_strategies) { [:totp] } let!(:device) { create(:two_factor_authentication_device_totp, user:, active: false, default: false) } - it "renders the confirmation page" do + it 'renders the confirmation page' do get :confirm, params: { device_id: device.id } expect(response).to be_successful - expect(response).to render_template "confirm" + expect(response).to render_template 'confirm' expect(flash[:notice]).not_to be_present end end - describe "with registered device" do + describe 'with registered device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, active: false, default: false) } - it "renders the confirmation page" do + it 'renders the confirmation page' do get :confirm, params: { device_id: device.id } expect(response).to be_successful - expect(response).to render_template "confirm" + expect(response).to render_template 'confirm' end - it "redirects to index if token request failed" do + it 'redirects to index if token request failed' do allow_any_instance_of(TwoFactorAuthentication::TokenService) .to receive(:request) .and_return(ServiceResult.failure) get :confirm, params: { device_id: device.id } expect(response).to redirect_to action: :index - expect(flash[:error]).to include I18n.t("two_factor_authentication.devices.confirm_send_failed") + expect(flash[:error]).to include I18n.t('two_factor_authentication.devices.confirm_send_failed') end end end - describe "#post" do - it "croaks on missing id" do + describe '#post' do + it 'croaks on missing id' do get :confirm, params: { device_id: 1234 } expect(response.status).to eq 404 end - describe "and registered totp device" do + describe 'and registered totp device' do let(:active_strategies) { [:totp] } let!(:device) { create(:two_factor_authentication_device_totp, user:, active: false, default: false) } - it "renders a 400 on missing token" do + it 'renders a 400 on missing token' do post :confirm, params: { device_id: device.id } expect(response).to redirect_to action: :index end - it "redirects to the confirmation on faulty entry" do - post :confirm, params: { device_id: device.id, otp: "1234" } + it 'redirects to the confirmation on faulty entry' do + post :confirm, params: { device_id: device.id, otp: '1234' } expect(response).to redirect_to action: :confirm, device_id: device.id - expect(flash[:error]).to include I18n.t("two_factor_authentication.devices.registration_failed_token_invalid") + expect(flash[:error]).to include I18n.t('two_factor_authentication.devices.registration_failed_token_invalid') device.reload @@ -179,39 +179,39 @@ expect(device.default).to be false end - context "when user has another active session" do + context 'when user has another active session' do let!(:plain_session) { create(:user_session, user:) } let!(:user_session) { Sessions::UserSession.find_by(session_id: plain_session.session_id) } - it "activates the device when entered correctly and clears other sessions" do + it 'activates the device when entered correctly and clears other sessions' do allow_any_instance_of(TwoFactorAuthentication::TokenService) .to receive(:verify) - .with("1234") + .with('1234') .and_return(ServiceResult.success) - post :confirm, params: { device_id: device.id, otp: "1234" } + post :confirm, params: { device_id: device.id, otp: '1234' } expect(response).to redirect_to action: :index - expect(flash[:notice]).to include I18n.t("two_factor_authentication.devices.registration_complete") + expect(flash[:notice]).to include I18n.t('two_factor_authentication.devices.registration_complete') device.reload expect(device.active).to be true expect(device.default).to be true expect { user_session.reload }.to raise_error(ActiveRecord::RecordNotFound) end - context "with another default device present" do + context 'with another default device present' do let!(:default_device) { create(:two_factor_authentication_device_totp, user:, default: true) } - it "activates the device when entered correctly" do + it 'activates the device when entered correctly' do # rubocop:disable RSpec/AnyInstance allow_any_instance_of(TwoFactorAuthentication::TokenService) .to receive(:verify) - .with("1234") + .with('1234') .and_return(ServiceResult.success) # rubocop:enable RSpec/AnyInstance - post :confirm, params: { device_id: device.id, otp: "1234" } + post :confirm, params: { device_id: device.id, otp: '1234' } expect(response).to redirect_to action: :index - expect(flash[:notice]).to include I18n.t("two_factor_authentication.devices.registration_complete") + expect(flash[:notice]).to include I18n.t('two_factor_authentication.devices.registration_complete') device.reload expect(device.active).to be true # but does not set default @@ -223,42 +223,42 @@ end end - describe "#destroy" do - it "croaks on missing id" do - delete :destroy, params: { device_id: "1234" } + describe '#destroy' do + it 'croaks on missing id' do + delete :destroy, params: { device_id: '1234' } expect(response.status).to eq 404 end - context "assuming password check is valid" do + context 'assuming password check is valid' do before do expect(controller).to receive(:check_password_confirmation).and_return true end - context "with existing non-default device" do + context 'with existing non-default device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: false) } - it "deletes it" do + it 'deletes it' do delete :destroy, params: { device_id: device.id } expect(response).to redirect_to action: :index expect(user.otp_devices.reload).to eq [] end end - context "with existing default device" do + context 'with existing default device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } - it "deletes it" do + it 'deletes it' do delete :destroy, params: { device_id: device.id } expect(response).to redirect_to action: :index expect(user.otp_devices.reload).to eq [] end end - context "with existing default device AND enforced" do + context 'with existing default device AND enforced' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } let(:config) { { enforced: true } } - it "cannot be deleted" do + it 'cannot be deleted' do delete :destroy, params: { device_id: device.id } expect(user.otp_devices.reload).to eq [device] end diff --git a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/users/two_factor_devices_controller_spec.rb b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/users/two_factor_devices_controller_spec.rb index a3765104c703..828d1e29bd78 100644 --- a/modules/two_factor_authentication/spec/controllers/two_factor_authentication/users/two_factor_devices_controller_spec.rb +++ b/modules/two_factor_authentication/spec/controllers/two_factor_authentication/users/two_factor_devices_controller_spec.rb @@ -1,19 +1,19 @@ -require_relative "../../../spec_helper" -require_relative "../authentication_controller_shared_examples" +require_relative '../../../spec_helper' +require_relative '../authentication_controller_shared_examples' RSpec.describe TwoFactorAuthentication::Users::TwoFactorDevicesController do let(:admin) { create(:admin) } - let(:user) { create(:user, login: "foobar") } + let(:user) { create(:user, login: 'foobar') } let(:other_user) { create(:user) } let(:logged_in_user) { admin } let(:active_strategies) { [:developer] } let(:config) { {} } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: { - "active_strategies" => active_strategies + 'active_strategies' => active_strategies }.merge(config) } end @@ -26,110 +26,110 @@ .and_return false end - describe "accessing" do + describe 'accessing' do before do get :new, params: { id: user.id, type: :sms } end - context "when the same user" do + context 'when the same user' do let(:logged_in_user) { other_user } - it "does not give access" do + it 'does not give access' do expect(response.status).to eq 403 end end - context "when not the same user" do + context 'when not the same user' do let(:logged_in_user) { user } - it "does not give access" do + it 'does not give access' do expect(response.status).to eq 403 end end - context "when not the same user and admin" do + context 'when not the same user and admin' do let(:logged_in_user) { admin } - it "renders the page" do + it 'renders the page' do expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end - context "when no active strategies" do + context 'when no active strategies' do let(:active_strategies) { [] } - it "renders a 404 because no strategies enabled" do + it 'renders a 404 because no strategies enabled' do expect(response.status).to eq 404 end end end end - describe "with active strategy" do + describe 'with active strategy' do let(:active_strategies) { [:developer] } - describe "#new" do - context "without type" do + describe '#new' do + context 'without type' do before do get :new, params: { id: user.id } end - it "shows an error" do + it 'shows an error' do expect(response).to have_http_status(:bad_request) end end - context "with unsupported type" do + context 'with unsupported type' do before do get :new, params: { id: user.id, type: :totp } end - it "shows an error" do + it 'shows an error' do expect(response).to have_http_status(:bad_request) end end - context "with type" do + context 'with type' do before do get :new, params: { id: user.id, type: :sms } end - it "renders the new form" do + it 'renders the new form' do expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end end end - describe "#register" do - context "with missing phone" do - let(:params) { { identifier: "foo" } } + describe '#register' do + context 'with missing phone' do + let(:params) { { identifier: 'foo' } } - it "renders action new" do + it 'renders action new' do post :register, params: { id: user.id, key: :sms, device: params } expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' expect(assigns[:device]).to be_invalid end end - context "with valid params" do - let(:params) { { phone_number: "+49123456789", identifier: "foo" } } + context 'with valid params' do + let(:params) { { phone_number: '+49123456789', identifier: 'foo' } } - it "redirects to result" do + it 'redirects to result' do post :register, params: { id: user.id, key: :sms, device: params } device = user.otp_devices.reload.last expect(response).to redirect_to edit_user_path(user.id, tab: :two_factor_authentication) - expect(device.identifier).to eq "foo (+49123456789)" - expect(device.phone_number).to eq "+49123456789" + expect(device.identifier).to eq 'foo (+49123456789)' + expect(device.phone_number).to eq '+49123456789' expect(device.default).to be_truthy expect(device.active).to be_truthy end - context "when user has active sessions" do + context 'when user has active sessions' do let!(:plain_session1) { create(:user_session, user:) } let!(:user_session1) { Sessions::UserSession.find_by(session_id: plain_session1.session_id) } @@ -139,7 +139,7 @@ let!(:other_plain_session) { create(:user_session, user: other_user) } let!(:other_session) { Sessions::UserSession.find_by(session_id: other_plain_session.session_id) } - it "drops all sessions of that user" do + it 'drops all sessions of that user' do post :register, params: { id: user.id, key: :sms, device: params } expect { user_session1.reload }.to raise_error(ActiveRecord::RecordNotFound) @@ -148,10 +148,10 @@ expect { other_session.reload }.not_to raise_error end - context "when user has an active device" do + context 'when user has an active device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } - it "does nothing" do + it 'does nothing' do post :register, params: { id: user.id, key: :sms, device: params } expect(user.otp_devices.count).to eq 2 @@ -169,47 +169,47 @@ end end - describe "#confirm" do - it "fails on GET" do + describe '#confirm' do + it 'fails on GET' do expect { get :confirm }.to raise_error(ActionController::UrlGenerationError) end - it "fails on POST" do + it 'fails on POST' do expect { post :confirm }.to raise_error(ActionController::UrlGenerationError) end end - describe "#destroy" do - it "croaks on missing id" do - delete :destroy, params: { id: user.id, device_id: "1234" } + describe '#destroy' do + it 'croaks on missing id' do + delete :destroy, params: { id: user.id, device_id: '1234' } expect(response.status).to eq 404 end - context "with existing non-default device" do + context 'with existing non-default device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: false) } - it "deletes it" do + it 'deletes it' do delete :destroy, params: { id: user.id, device_id: device.id } expect(response).to redirect_to edit_user_path(user, tab: :two_factor_authentication) expect(user.otp_devices.reload).to eq [] end end - context "with existing default device" do + context 'with existing default device' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } - it "deletes it" do + it 'deletes it' do delete :destroy, params: { id: user.id, device_id: device.id } expect(response).to redirect_to edit_user_path(user, tab: :two_factor_authentication) expect(user.otp_devices.reload).to eq [] end end - context "with existing default device AND enforced" do + context 'with existing default device AND enforced' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } let(:config) { { enforced: true } } - it "cannot be deleted" do + it 'cannot be deleted' do delete :destroy, params: { id: user.id, device_id: device.id } expect(user.otp_devices.reload).to eq [device] end diff --git a/modules/two_factor_authentication/spec/factories/two_factor_authentication_device_factory.rb b/modules/two_factor_authentication/spec/factories/two_factor_authentication_device_factory.rb index f4ab1f841e44..50ff998750b5 100644 --- a/modules/two_factor_authentication/spec/factories/two_factor_authentication_device_factory.rb +++ b/modules/two_factor_authentication/spec/factories/two_factor_authentication_device_factory.rb @@ -1,11 +1,11 @@ FactoryBot.define do - factory :two_factor_authentication_device_sms, class: "::TwoFactorAuthentication::Device::Sms" do + factory :two_factor_authentication_device_sms, class: '::TwoFactorAuthentication::Device::Sms' do user channel { :sms } active { true } default { true } - phone_number { "+49 123456789" } - identifier { "Phone number (+49 123456789)" } + phone_number { '+49 123456789' } + identifier { 'Phone number (+49 123456789)' } transient do make_default { false } @@ -16,12 +16,12 @@ end end - factory :two_factor_authentication_device_totp, class: "::TwoFactorAuthentication::Device::Totp" do + factory :two_factor_authentication_device_totp, class: '::TwoFactorAuthentication::Device::Totp' do user channel { :totp } active { true } default { true } - identifier { "TOTP device" } + identifier { 'TOTP device' } transient do make_default { false } @@ -32,12 +32,12 @@ end end - factory :two_factor_authentication_device_webauthn, class: "::TwoFactorAuthentication::Device::Webauthn" do + factory :two_factor_authentication_device_webauthn, class: '::TwoFactorAuthentication::Device::Webauthn' do user channel { :webauthn } active { true } default { true } - identifier { "WebAuthn device" } + identifier { 'WebAuthn device' } webauthn_external_id { "foo" } webauthn_public_key { "bar" } diff --git a/modules/two_factor_authentication/spec/features/account_activation_spec.rb b/modules/two_factor_authentication/spec/features/account_activation_spec.rb index 7d1f3118bd5e..c89014c1a97e 100644 --- a/modules/two_factor_authentication/spec/features/account_activation_spec.rb +++ b/modules/two_factor_authentication/spec/features/account_activation_spec.rb @@ -1,9 +1,9 @@ -require_relative "../spec_helper" -require_relative "shared_2fa_examples" +require_relative '../spec_helper' +require_relative 'shared_2fa_examples' -RSpec.describe "activating an invited account", :js, +RSpec.describe 'activating an invited account', :js, with_settings: { - plugin_openproject_two_factor_authentication: { "active_strategies" => [:developer] } + plugin_openproject_two_factor_authentication: { 'active_strategies' => [:developer] } } do let(:user) do user = build(:user, first_login: true) @@ -21,25 +21,25 @@ def activate! expect(page).to have_current_path account_register_path - fill_in I18n.t("attributes.password"), with: "Password1234" - fill_in I18n.t("activerecord.attributes.user.password_confirmation"), with: "Password1234" + fill_in I18n.t('attributes.password'), with: 'Password1234' + fill_in I18n.t('activerecord.attributes.user.password_confirmation'), with: 'Password1234' click_button I18n.t(:button_create) end - context "when not enforced and no device present" do - it "redirects to active" do + context 'when not enforced and no device present' do + it 'redirects to active' do activate! visit my_account_path - expect(page).to have_css(".form--field-container", text: user.login) + expect(page).to have_css('.form--field-container', text: user.login) end end - context "when not enforced, but device present" do + context 'when not enforced, but device present' do let!(:device) { create(:two_factor_authentication_device_sms, user:, default: true) } - it "requests a OTP" do + it 'requests a OTP' do sms_token = nil # rubocop:disable RSpec/AnyInstance allow_any_instance_of(OpenProject::TwoFactorAuthentication::TokenStrategy::Developer) @@ -50,22 +50,22 @@ def activate! activate! - expect(page).to have_css(".op-toast.-success", text: "Developer strategy generated the following one-time password:") + expect(page).to have_css('.op-toast.-success', text: 'Developer strategy generated the following one-time password:') SeleniumHubWaiter.wait fill_in I18n.t(:field_otp), with: sms_token click_button I18n.t(:button_login) visit my_account_path - expect(page).to have_css(".form--field-container", text: user.login) + expect(page).to have_css('.form--field-container', text: user.login) end - it "handles faulty user input on two factor authentication" do + it 'handles faulty user input on two factor authentication' do activate! - expect(page).to have_css(".op-toast.-success", text: "Developer strategy generated the following one-time password:") + expect(page).to have_css('.op-toast.-success', text: 'Developer strategy generated the following one-time password:') - fill_in I18n.t(:field_otp), with: "asdf" # faulty token + fill_in I18n.t(:field_otp), with: 'asdf' # faulty token click_button I18n.t(:button_login) expect(page).to have_current_path signin_path @@ -73,17 +73,17 @@ def activate! end end - context "when enforced", + context 'when enforced', with_settings: { plugin_openproject_two_factor_authentication: { - "active_strategies" => [:developer], - "enforced" => true + 'active_strategies' => [:developer], + 'enforced' => true } } do before do activate! end - it_behaves_like "create enforced sms device" + it_behaves_like 'create enforced sms device' end end diff --git a/modules/two_factor_authentication/spec/features/admin_edit_two_factor_devices_spec.rb b/modules/two_factor_authentication/spec/features/admin_edit_two_factor_devices_spec.rb index 86c5d6230c37..205aa53ded80 100644 --- a/modules/two_factor_authentication/spec/features/admin_edit_two_factor_devices_spec.rb +++ b/modules/two_factor_authentication/spec/features/admin_edit_two_factor_devices_spec.rb @@ -1,11 +1,11 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "Admin 2FA management", :js, with_settings: { - plugin_openproject_two_factor_authentication: { "active_strategies" => %i[developer totp] } +RSpec.describe 'Admin 2FA management', :js, with_settings: { + plugin_openproject_two_factor_authentication: { 'active_strategies' => %i[developer totp] } } do let(:dialog) { Components::PasswordConfirmationDialog.new } - let(:user_password) { "admin!" * 4 } - let(:other_user) { create(:user, login: "bob") } + let(:user_password) { 'admin!' * 4 } + let(:other_user) { create(:user, login: 'bob') } let(:admin) do create(:admin, password: user_password, @@ -16,69 +16,69 @@ login_as admin end - it "forbids the admin editing his own account" do + it 'forbids the admin editing his own account' do visit edit_user_path(admin, tab: :two_factor_authentication) - expect(page).to have_css(".on-off-status.-disabled") + expect(page).to have_css('.on-off-status.-disabled') - expect(page).to have_no_css(".generic-table--empty-row", wait: 1) - page.find(".admin--edit-section a").click + expect(page).to have_no_css('.generic-table--empty-row', wait: 1) + page.find('.admin--edit-section a').click - expect(page).to have_css(".generic-table--empty-row") + expect(page).to have_css('.generic-table--empty-row') expect(page).to have_current_path my_2fa_devices_path end - it "allows 2FA device management of the user" do + it 'allows 2FA device management of the user' do visit edit_user_path(other_user, tab: :two_factor_authentication) # Visit empty index - expect(page).to have_css(".generic-table--empty-row", - text: I18n.t("two_factor_authentication.admin.no_devices_for_user")) - expect(page).to have_css(".on-off-status.-disabled") + expect(page).to have_css('.generic-table--empty-row', + text: I18n.t('two_factor_authentication.admin.no_devices_for_user')) + expect(page).to have_css('.on-off-status.-disabled') # Visit inline create - find(".button", text: I18n.t("two_factor_authentication.admin.button_register_mobile_phone_for_user")).click + find('.button', text: I18n.t('two_factor_authentication.admin.button_register_mobile_phone_for_user')).click SeleniumHubWaiter.wait # Try to save with invalid phone number - fill_in "device_phone_number", with: "invalid!" + fill_in 'device_phone_number', with: 'invalid!' click_button I18n.t(:button_continue) # Enter valid phone number - expect(page).to have_css("#errorExplanation", text: "Phone number must be of format +XX XXXXXXXXX") + expect(page).to have_css('#errorExplanation', text: 'Phone number must be of format +XX XXXXXXXXX') SeleniumHubWaiter.wait - fill_in "device_phone_number", with: "+49 123456789" + fill_in 'device_phone_number', with: '+49 123456789' click_button I18n.t(:button_continue) - expect(page).to have_css(".mobile-otp--two-factor-device-row td", text: "Mobile phone (bob) (+49 123456789)") - expect(page).to have_css(".mobile-otp--two-factor-device-row td .icon-yes", count: 2) - expect(page).to have_css(".on-off-status.-enabled") + expect(page).to have_css('.mobile-otp--two-factor-device-row td', text: 'Mobile phone (bob) (+49 123456789)') + expect(page).to have_css('.mobile-otp--two-factor-device-row td .icon-yes', count: 2) + expect(page).to have_css('.on-off-status.-enabled') SeleniumHubWaiter.wait # Delete the one - find(".two-factor--delete-button").click + find('.two-factor--delete-button').click dialog.confirm_flow_with user_password, should_fail: false - expect(page).to have_css(".mobile-otp--two-factor-device-row", count: 0) - expect(page).to have_css(".on-off-status.-disabled") + expect(page).to have_css('.mobile-otp--two-factor-device-row', count: 0) + expect(page).to have_css('.on-off-status.-disabled') expect(other_user.otp_devices.count).to eq 0 end - context "with multiple devices registered" do + context 'with multiple devices registered' do let!(:device1) { create(:two_factor_authentication_device_sms, user: other_user) } let!(:device2) { create(:two_factor_authentication_device_totp, user: other_user, default: false) } - it "allows to delete all" do + it 'allows to delete all' do visit edit_user_path(other_user, tab: :two_factor_authentication) - expect(page).to have_css(".mobile-otp--two-factor-device-row", count: 2) - expect(page).to have_css(".on-off-status.-enabled") - find(".button", text: I18n.t("two_factor_authentication.admin.button_delete_all_devices")).click + expect(page).to have_css('.mobile-otp--two-factor-device-row', count: 2) + expect(page).to have_css('.on-off-status.-enabled') + find('.button', text: I18n.t('two_factor_authentication.admin.button_delete_all_devices')).click page.driver.browser.switch_to.alert.accept - expect(page).to have_css(".generic-table--empty-row", - text: I18n.t("two_factor_authentication.admin.no_devices_for_user"), wait: 20) - expect(page).to have_css(".on-off-status.-disabled") + expect(page).to have_css('.generic-table--empty-row', + text: I18n.t('two_factor_authentication.admin.no_devices_for_user'), wait: 20) + expect(page).to have_css('.on-off-status.-disabled') end end end diff --git a/modules/two_factor_authentication/spec/features/backup_codes/generate_backup_codes_spec.rb b/modules/two_factor_authentication/spec/features/backup_codes/generate_backup_codes_spec.rb index 681720b9900e..d09416616080 100644 --- a/modules/two_factor_authentication/spec/features/backup_codes/generate_backup_codes_spec.rb +++ b/modules/two_factor_authentication/spec/features/backup_codes/generate_backup_codes_spec.rb @@ -1,11 +1,11 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Generate 2FA backup codes", :js, with_config: { "2fa": { active_strategies: [:developer] } } do - let(:user_password) { "bob!" * 4 } +RSpec.describe 'Generate 2FA backup codes', :js, with_config: { '2fa': { active_strategies: [:developer] } } do + let(:user_password) { 'bob!' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end @@ -15,7 +15,7 @@ login_as user end - it "allows generating backup codes" do + it 'allows generating backup codes' do visit my_2fa_devices_path # Log token for next access @@ -27,18 +27,18 @@ end # Confirm with wrong password - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.backup_codes.plural")) - click_on I18n.t("two_factor_authentication.backup_codes.generate.title") - dialog.confirm_flow_with "wrong_password", should_fail: true + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.backup_codes.plural')) + click_on I18n.t('two_factor_authentication.backup_codes.generate.title') + dialog.confirm_flow_with 'wrong_password', should_fail: true # Confirm with correct password - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.backup_codes.plural")) - click_on I18n.t("two_factor_authentication.backup_codes.generate.title") + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.backup_codes.plural')) + click_on I18n.t('two_factor_authentication.backup_codes.generate.title') dialog.confirm_flow_with user_password, should_fail: false - expect(page).to have_css(".op-toast.-warning") + expect(page).to have_css('.op-toast.-warning') backup_codes.each do |code| - expect(page).to have_css(".two-factor-authentication--backup-codes li", text: code) + expect(page).to have_css('.two-factor-authentication--backup-codes li', text: code) end end end diff --git a/modules/two_factor_authentication/spec/features/backup_codes/login_with_backup_code_spec.rb b/modules/two_factor_authentication/spec/features/backup_codes/login_with_backup_code_spec.rb index 628c10f9e54a..5f670c2f9acd 100644 --- a/modules/two_factor_authentication/spec/features/backup_codes/login_with_backup_code_spec.rb +++ b/modules/two_factor_authentication/spec/features/backup_codes/login_with_backup_code_spec.rb @@ -1,37 +1,37 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Login with 2FA backup code", :js, with_settings: { - plugin_openproject_two_factor_authentication: { "active_strategies" => [:developer] } +RSpec.describe 'Login with 2FA backup code', :js, with_settings: { + plugin_openproject_two_factor_authentication: { 'active_strategies' => [:developer] } } do - let(:user_password) { "bob!" * 4 } + let(:user_password) { 'bob!' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end let!(:device) { create(:two_factor_authentication_device_sms, user:, active: true, default: true) } - context "when user has no backup code" do - it "does not show the backup code link" do + context 'when user has no backup code' do + it 'does not show the backup code link' do first_login_step # Open other options - find_by_id("toggle_resend_form").click - expect(page).to have_no_css("a", text: I18n.t("two_factor_authentication.login.enter_backup_code_title")) + find_by_id('toggle_resend_form').click + expect(page).to have_no_css('a', text: I18n.t('two_factor_authentication.login.enter_backup_code_title')) end end - context "when user has backup codes" do + context 'when user has backup codes' do let!(:valid_backup_codes) { TwoFactorAuthentication::BackupCode.regenerate! user } - it "allows entering a backup code" do + it 'allows entering a backup code' do expect(valid_backup_codes.length).to eq(10) first_login_step - expect(page).to have_css("#toggle_resend_form", wait: 10) + expect(page).to have_css('#toggle_resend_form', wait: 10) # Wait for the frontend to be loaded and initialized # On downstream configurations, this might take longer than marionette selecting the element @@ -40,30 +40,30 @@ # Open other options # This may fail on the first request when the assets aren't ready yet SeleniumHubWaiter.wait - find_by_id("toggle_resend_form").click + find_by_id('toggle_resend_form').click SeleniumHubWaiter.wait - find("a", text: I18n.t("two_factor_authentication.login.enter_backup_code_title"), wait: 2).click + find('a', text: I18n.t('two_factor_authentication.login.enter_backup_code_title'), wait: 2).click - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.login.enter_backup_code_title")) + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.login.enter_backup_code_title')) SeleniumHubWaiter.wait - fill_in "backup_code", with: "whatever" - click_on "Submit" + fill_in 'backup_code', with: 'whatever' + click_on 'Submit' # Expect failure - expect(page).to have_css(".op-toast.-error", text: I18n.t("two_factor_authentication.error_invalid_backup_code")) + expect(page).to have_css('.op-toast.-error', text: I18n.t('two_factor_authentication.error_invalid_backup_code')) expect(page).to have_current_path signin_path # Try again! first_login_step SeleniumHubWaiter.wait - find_by_id("toggle_resend_form").click + find_by_id('toggle_resend_form').click SeleniumHubWaiter.wait - find("a", text: I18n.t("two_factor_authentication.login.enter_backup_code_title")).click + find('a', text: I18n.t('two_factor_authentication.login.enter_backup_code_title')).click - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.login.enter_backup_code_title")) + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.login.enter_backup_code_title')) SeleniumHubWaiter.wait - fill_in "backup_code", with: valid_backup_codes.first - click_on "Submit" + fill_in 'backup_code', with: valid_backup_codes.first + click_on 'Submit' expect_logged_in end diff --git a/modules/two_factor_authentication/spec/features/login/login_enforced_2fa_spec.rb b/modules/two_factor_authentication/spec/features/login/login_enforced_2fa_spec.rb index 18f840fdacdb..d98ce73f099c 100644 --- a/modules/two_factor_authentication/spec/features/login/login_enforced_2fa_spec.rb +++ b/modules/two_factor_authentication/spec/features/login/login_enforced_2fa_spec.rb @@ -1,24 +1,24 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Login with enforced 2FA", :js, with_settings: { +RSpec.describe 'Login with enforced 2FA', :js, with_settings: { plugin_openproject_two_factor_authentication: { - "active_strategies" => [:developer], - "enforced" => true + 'active_strategies' => [:developer], + 'enforced' => true } } do - let(:user_password) { "bob!" * 4 } + let(:user_password) { 'bob!' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end - context "with a default device" do + context 'with a default device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, active: true, default: true) } - it "requests a 2FA" do + it 'requests a 2FA' do sms_token = nil # rubocop:disable RSpec/AnyInstance allow_any_instance_of(OpenProject::TwoFactorAuthentication::TokenStrategy::Developer) @@ -32,20 +32,20 @@ expect_logged_in end - it "returns to 2FA page if invalid" do + it 'returns to 2FA page if invalid' do first_login_step - two_factor_step("whatever") + two_factor_step('whatever') - expect(page).to have_css(".op-toast.-error", text: I18n.t(:notice_account_otp_invalid)) + expect(page).to have_css('.op-toast.-error', text: I18n.t(:notice_account_otp_invalid)) expect(page).to have_current_path signin_path end end - context "without a device" do + context 'without a device' do before do first_login_step end - it_behaves_like "create enforced sms device" + it_behaves_like 'create enforced sms device' end end diff --git a/modules/two_factor_authentication/spec/features/login/login_with_2fa_spec.rb b/modules/two_factor_authentication/spec/features/login/login_with_2fa_spec.rb index 52a93882d145..14dafa042d59 100644 --- a/modules/two_factor_authentication/spec/features/login/login_with_2fa_spec.rb +++ b/modules/two_factor_authentication/spec/features/login/login_with_2fa_spec.rb @@ -1,23 +1,23 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Login with 2FA device", :js, with_settings: { +RSpec.describe 'Login with 2FA device', :js, with_settings: { plugin_openproject_two_factor_authentication: { - "active_strategies" => [:developer] + 'active_strategies' => [:developer] } } do - let(:user_password) { "bob!" * 4 } + let(:user_password) { 'bob!' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end - context "with a default device" do + context 'with a default device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, active: true, default: true) } - it "requests a 2FA" do + it 'requests a 2FA' do sms_token = nil # rubocop:disable RSpec/AnyInstance allow_any_instance_of(OpenProject::TwoFactorAuthentication::TokenStrategy::Developer) @@ -31,11 +31,11 @@ expect_logged_in end - it "returns to 2FA page if invalid" do + it 'returns to 2FA page if invalid' do first_login_step - two_factor_step("whatever") + two_factor_step('whatever') - expect(page).to have_css(".op-toast.-error", text: I18n.t(:notice_account_otp_invalid)) + expect(page).to have_css('.op-toast.-error', text: I18n.t(:notice_account_otp_invalid)) expect(page).to have_current_path signin_path end end diff --git a/modules/two_factor_authentication/spec/features/login/login_without_2fa_spec.rb b/modules/two_factor_authentication/spec/features/login/login_without_2fa_spec.rb index 0ee982a3e077..b328710607c9 100644 --- a/modules/two_factor_authentication/spec/features/login/login_without_2fa_spec.rb +++ b/modules/two_factor_authentication/spec/features/login/login_without_2fa_spec.rb @@ -1,27 +1,27 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Login with no required OTP", :js, with_config: { "2fa": { active_strategies: [:developer] } } do - let(:user_password) { "bob!" * 4 } +RSpec.describe 'Login with no required OTP', :js, with_config: { '2fa': { active_strategies: [:developer] } } do + let(:user_password) { 'bob!' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end - context "non-default device" do + context 'non-default device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, active: true, default: false) } - it_behaves_like "login without 2FA" + it_behaves_like 'login without 2FA' end - context "not enabled", - with_config: { "2fa": { active_strategies: [] } } do - it_behaves_like "login without 2FA" + context 'not enabled', + with_config: { '2fa': { active_strategies: [] } } do + it_behaves_like 'login without 2FA' end - context "no device" do - it_behaves_like "login without 2FA" + context 'no device' do + it_behaves_like 'login without 2FA' end end diff --git a/modules/two_factor_authentication/spec/features/login/switch_available_devices_spec.rb b/modules/two_factor_authentication/spec/features/login/switch_available_devices_spec.rb index 015a621fc6a9..5b35d5e456e7 100644 --- a/modules/two_factor_authentication/spec/features/login/switch_available_devices_spec.rb +++ b/modules/two_factor_authentication/spec/features/login/switch_available_devices_spec.rb @@ -1,35 +1,35 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Login by switching 2FA device", :js, with_settings: { - plugin_openproject_two_factor_authentication: { "active_strategies" => %i[developer totp] } +RSpec.describe 'Login by switching 2FA device', :js, with_settings: { + plugin_openproject_two_factor_authentication: { 'active_strategies' => %i[developer totp] } } do - let(:user_password) { "bob!" * 4 } + let(:user_password) { 'bob!' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end - context "with two default device" do + context 'with two default device' do let!(:device) { create(:two_factor_authentication_device_sms, user:, active: true, default: true) } let!(:device2) { create(:two_factor_authentication_device_totp, user:, active: true, default: false) } - it "requests a 2FA and allows switching" do + it 'requests a 2FA and allows switching' do first_login_step - expect(page).to have_css("input#otp") + expect(page).to have_css('input#otp') SeleniumHubWaiter.wait # Toggle device to TOTP - find_by_id("toggle_resend_form").click + find_by_id('toggle_resend_form').click SeleniumHubWaiter.wait find(".button--link[value='#{device2.redacted_identifier}']").click - expect(page).to have_css("input#otp") - expect(page).to have_css("#submit_otp p", text: device2.redacted_identifier) + expect(page).to have_css('input#otp') + expect(page).to have_css('#submit_otp p', text: device2.redacted_identifier) two_factor_step(device2.totp.now) expect_logged_in diff --git a/modules/two_factor_authentication/spec/features/my_two_factor_devices_spec.rb b/modules/two_factor_authentication/spec/features/my_two_factor_devices_spec.rb index 5187f9b91cd3..bb9dd2886111 100644 --- a/modules/two_factor_authentication/spec/features/my_two_factor_devices_spec.rb +++ b/modules/two_factor_authentication/spec/features/my_two_factor_devices_spec.rb @@ -1,13 +1,13 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "My Account 2FA configuration", :js, with_settings: { - plugin_openproject_two_factor_authentication: { "active_strategies" => %i[developer totp] } +RSpec.describe 'My Account 2FA configuration', :js, with_settings: { + plugin_openproject_two_factor_authentication: { 'active_strategies' => %i[developer totp] } } do let(:dialog) { Components::PasswordConfirmationDialog.new } - let(:user_password) { "boB!4" * 4 } + let(:user_password) { 'boB!4' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end @@ -16,31 +16,31 @@ login_as user end - it "allows 2FA device management" do + it 'allows 2FA device management' do # Visit empty index visit my_2fa_devices_path - expect(page).to have_css(".generic-table--empty-row", text: I18n.t("two_factor_authentication.devices.not_existing")) - expect(page).to have_css(".on-off-status.-disabled") + expect(page).to have_css('.generic-table--empty-row', text: I18n.t('two_factor_authentication.devices.not_existing')) + expect(page).to have_css('.on-off-status.-disabled') # Visit inline create - find(".wp-inline-create--add-link").click - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.add_new")) + find('.wp-inline-create--add-link').click + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.devices.add_new')) expect(page).to have_current_path new_my_2fa_device_path # Select SMS - find(".mobile-otp-new-device-sms .button").click + find('.mobile-otp-new-device-sms .button').click # Try to save with invalid phone number - fill_in "device_phone_number", with: "invalid!" + fill_in 'device_phone_number', with: 'invalid!' click_button I18n.t(:button_continue) # Enter valid phone number - expect(page).to have_css("#errorExplanation", text: "Phone number must be of format +XX XXXXXXXXX") - fill_in "device_phone_number", with: "+49 123456789" + expect(page).to have_css('#errorExplanation', text: 'Phone number must be of format +XX XXXXXXXXX') + fill_in 'device_phone_number', with: '+49 123456789' click_button I18n.t(:button_continue) # Fill in wrong token - fill_in "otp", with: "whatever" + fill_in 'otp', with: 'whatever' # Log token for next access sms_token = nil @@ -53,51 +53,51 @@ click_button I18n.t(:button_continue) - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.confirm_device")) - expect(page).to have_css("input#otp") - expect(page).to have_css(".op-toast.-error", - text: I18n.t("two_factor_authentication.devices.registration_failed_token_invalid")) + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.devices.confirm_device')) + expect(page).to have_css('input#otp') + expect(page).to have_css('.op-toast.-error', + text: I18n.t('two_factor_authentication.devices.registration_failed_token_invalid')) # Fill in correct token - fill_in "otp", with: sms_token + fill_in 'otp', with: sms_token click_button I18n.t(:button_continue) # Assert that it exists and is default - expect(page).to have_css(".mobile-otp--two-factor-device-row td", text: "Mobile phone (bob) (+49 123456789)") - expect(page).to have_css(".mobile-otp--two-factor-device-row td .icon-yes", count: 2) - expect(page).to have_css(".on-off-status.-enabled") + expect(page).to have_css('.mobile-otp--two-factor-device-row td', text: 'Mobile phone (bob) (+49 123456789)') + expect(page).to have_css('.mobile-otp--two-factor-device-row td .icon-yes', count: 2) + expect(page).to have_css('.on-off-status.-enabled') # Create another one as totp # Visit create button visit my_2fa_devices_path - find(".toolbar-item .button", text: "2FA device").click - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.add_new")) + find('.toolbar-item .button', text: '2FA device').click + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.devices.add_new')) expect(page).to have_current_path new_my_2fa_device_path, ignore_query: true # Select totp - find(".mobile-otp-new-device-totp .button").click + find('.mobile-otp-new-device-totp .button').click # Change identifier - fill_in "device_identifier", with: "custom identifier" + fill_in 'device_identifier', with: 'custom identifier' click_button I18n.t(:button_continue) # Confirm token - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.confirm_device")) - expect(page).to have_css("input#otp") + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.devices.confirm_device')) + expect(page).to have_css('input#otp') device = user.otp_devices.order(:id).last - expect(device.identifier).to eq "custom identifier" + expect(device.identifier).to eq 'custom identifier' expect(device.default).to be_falsey expect(device.active).to be_falsey - fill_in "otp", with: device.totp.now + fill_in 'otp', with: device.totp.now click_button I18n.t(:button_continue) - expect(page).to have_css(".mobile-otp--two-factor-device-row", count: 2) - rows = page.all(".mobile-otp--two-factor-device-row") - expect(rows[0]).to have_css(".mobile-otp--two-factor-device-row td .icon-yes", count: 2) - expect(rows[1]).to have_css(".mobile-otp--two-factor-device-row td", text: "custom identifier") - expect(rows[1]).to have_css(".mobile-otp--two-factor-device-row td .icon-yes", count: 1) + expect(page).to have_css('.mobile-otp--two-factor-device-row', count: 2) + rows = page.all('.mobile-otp--two-factor-device-row') + expect(rows[0]).to have_css('.mobile-otp--two-factor-device-row td .icon-yes', count: 2) + expect(rows[1]).to have_css('.mobile-otp--two-factor-device-row td', text: 'custom identifier') + expect(rows[1]).to have_css('.mobile-otp--two-factor-device-row td .icon-yes', count: 1) device.reload expect(device.active).to be_truthy @@ -105,42 +105,42 @@ # Make the second one the default # Confirm the password wrongly - find(".two-factor--mark-default-button").click - dialog.confirm_flow_with "wrong_password", should_fail: true + find('.two-factor--mark-default-button').click + dialog.confirm_flow_with 'wrong_password', should_fail: true # Confirm again - find(".two-factor--mark-default-button").click + find('.two-factor--mark-default-button').click dialog.confirm_flow_with user_password, should_fail: false - expect(page).to have_css(".mobile-otp--two-factor-device-row", count: 2) - rows = page.all(".mobile-otp--two-factor-device-row") - expect(rows[0]).to have_css(".mobile-otp--two-factor-device-row td .icon-yes", count: 1) - expect(rows[1]).to have_css(".mobile-otp--two-factor-device-row td .icon-yes", count: 2) + expect(page).to have_css('.mobile-otp--two-factor-device-row', count: 2) + rows = page.all('.mobile-otp--two-factor-device-row') + expect(rows[0]).to have_css('.mobile-otp--two-factor-device-row td .icon-yes', count: 1) + expect(rows[1]).to have_css('.mobile-otp--two-factor-device-row td .icon-yes', count: 2) device.reload expect(device.default).to be_truthy # Delete the sms device - rows[0].find(".two-factor--delete-button").click + rows[0].find('.two-factor--delete-button').click dialog.confirm_flow_with user_password, should_fail: false - expect(page).to have_css(".mobile-otp--two-factor-device-row", count: 1) - expect(page).to have_css(".on-off-status.-enabled") + expect(page).to have_css('.mobile-otp--two-factor-device-row', count: 1) + expect(page).to have_css('.on-off-status.-enabled') expect(user.otp_devices.count).to eq 1 # Delete the totp device - find(".two-factor--delete-button").click + find('.two-factor--delete-button').click dialog.confirm_flow_with user_password, should_fail: false - expect(page).to have_css(".generic-table--empty-row", text: I18n.t("two_factor_authentication.devices.not_existing")) - expect(page).to have_css(".on-off-status.-disabled") + expect(page).to have_css('.generic-table--empty-row', text: I18n.t('two_factor_authentication.devices.not_existing')) + expect(page).to have_css('.on-off-status.-disabled') expect(user.otp_devices.count).to eq 0 end - context "when a device has been registered already" do + context 'when a device has been registered already' do let!(:device) { create(:two_factor_authentication_device_totp, user:) } - it "loads the page correctly (Regression #41719)" do + it 'loads the page correctly (Regression #41719)' do visit my_2fa_devices_path expect(page).to have_content device.identifier diff --git a/modules/two_factor_authentication/spec/features/password_change_spec.rb b/modules/two_factor_authentication/spec/features/password_change_spec.rb index 414b7475957a..90a22195cece 100644 --- a/modules/two_factor_authentication/spec/features/password_change_spec.rb +++ b/modules/two_factor_authentication/spec/features/password_change_spec.rb @@ -1,15 +1,15 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' -RSpec.describe "Password change with OTP", :js, with_settings: { +RSpec.describe 'Password change with OTP', :js, with_settings: { plugin_openproject_two_factor_authentication: { - "active_strategies" => [:developer] + 'active_strategies' => [:developer] } } do - let(:user_password) { "boB&" * 4 } - let(:new_user_password) { "%obB" * 4 } + let(:user_password) { 'boB&' * 4 } + let(:new_user_password) { '%obB' * 4 } let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end @@ -17,9 +17,9 @@ def handle_password_change(requires_otp: true) visit signin_path - within("#login-form") do - fill_in("username", with: user.login) - fill_in("password", with: user_password) + within('#login-form') do + fill_in('username', with: user.login) + fill_in('password', with: user_password) click_link_or_button I18n.t(:button_login) end @@ -31,35 +31,35 @@ def handle_password_change(requires_otp: true) end # rubocop:enable RSpec/AnyInstance - expect(page).to have_css("h2", text: I18n.t(:button_change_password)) - within("#content") do + expect(page).to have_css('h2', text: I18n.t(:button_change_password)) + within('#content') do SeleniumHubWaiter.wait - fill_in("password", with: user_password) - fill_in("new_password", with: new_user_password) - fill_in("new_password_confirmation", with: new_user_password) + fill_in('password', with: user_password) + fill_in('new_password', with: new_user_password) + fill_in('new_password_confirmation', with: new_user_password) click_link_or_button I18n.t(:button_save) end if requires_otp - expect(page).to have_css("input#otp") + expect(page).to have_css('input#otp') SeleniumHubWaiter.wait - fill_in "otp", with: sms_token + fill_in 'otp', with: sms_token click_button I18n.t(:button_login) end expect(page).to have_current_path(expected_path_after_login, ignore_query: true) end - context "when password is expired", + context 'when password is expired', with_settings: { password_days_valid: 7 } do before do user end - context "when device present" do + context 'when device present' do let!(:device) { create(:two_factor_authentication_device_sms, user:, default: true) } - it "requires the password change after expired" do + it 'requires the password change after expired' do expect(user.current_password).not_to be_expired Timecop.travel(2.weeks.from_now) do @@ -72,10 +72,10 @@ def handle_password_change(requires_otp: true) end end - context "when no device present" do + context 'when no device present' do let!(:device) { nil } - it "requires the password change after expired" do + it 'requires the password change after expired' do expect(user.current_password).not_to be_expired Timecop.travel(2.weeks.from_now) do @@ -89,12 +89,12 @@ def handle_password_change(requires_otp: true) end end - context "when force password change is set" do + context 'when force password change is set' do let(:user) do create(:user, force_password_change: true, first_login: true, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end @@ -104,18 +104,18 @@ def handle_password_change(requires_otp: true) user end - context "when device present" do + context 'when device present' do let!(:device) { create(:two_factor_authentication_device_sms, user:, default: true) } - it "requires the password change" do + it 'requires the password change' do handle_password_change end end - context "when no device present" do + context 'when no device present' do let!(:device) { nil } - it "requires the password change without otp" do + it 'requires the password change without otp' do handle_password_change(requires_otp: false) end end diff --git a/modules/two_factor_authentication/spec/features/remember_cookie/login_with_remember_cookie_spec.rb b/modules/two_factor_authentication/spec/features/remember_cookie/login_with_remember_cookie_spec.rb index dc11cfc15754..af0ce3b0e716 100644 --- a/modules/two_factor_authentication/spec/features/remember_cookie/login_with_remember_cookie_spec.rb +++ b/modules/two_factor_authentication/spec/features/remember_cookie/login_with_remember_cookie_spec.rb @@ -1,7 +1,7 @@ -require_relative "../../spec_helper" -require_relative "../shared_2fa_examples" +require_relative '../../spec_helper' +require_relative '../shared_2fa_examples' -RSpec.describe "Login with 2FA remember cookie", :js, with_settings: { +RSpec.describe 'Login with 2FA remember cookie', :js, with_settings: { plugin_openproject_two_factor_authentication: { active_strategies: [:developer], allow_remember_for_days: 30 @@ -26,9 +26,9 @@ def login_with_cookie first_login_step - expect(page).to have_css("input#remember_me") + expect(page).to have_css('input#remember_me') SeleniumHubWaiter.wait - check "remember_me" + check 'remember_me' two_factor_step sms_token expect_logged_in @@ -37,42 +37,42 @@ def login_with_cookie def expect_no_autologin first_login_step - expect(page).to have_css("input#otp") + expect(page).to have_css('input#otp') expect_not_logged_in end - context "when not enabled", + context 'when not enabled', with_settings: { plugin_openproject_two_factor_authentication: { active_strategies: [:developer], allow_remember_for_days: 0 } } do - it "does not show the save form" do + it 'does not show the save form' do first_login_step - expect(page).to have_no_css("input#remember_me") + expect(page).to have_no_css('input#remember_me') end end - context "when user has no remember cookie" do - it "can remove the autologin cookie after login" do + context 'when user has no remember cookie' do + it 'can remove the autologin cookie after login' do login_with_cookie visit my_2fa_devices_path - find(".two-factor-authentication--remove-remember-cookie-link").click - expect(page).to have_css(".op-toast.-success") - expect(page).to have_no_css(".two-factor-authentication--remove-remember-cookie-link") + find('.two-factor-authentication--remove-remember-cookie-link').click + expect(page).to have_css('.op-toast.-success') + expect(page).to have_no_css('.two-factor-authentication--remove-remember-cookie-link') # Log out and in again - visit "/logout" + visit '/logout' expect_no_autologin end - it "allows to save a cookie on the login step for subsequent steps" do + it 'allows to save a cookie on the login step for subsequent steps' do login_with_cookie # Log out and in again - visit "/logout" + visit '/logout' first_login_step # Expect no OTP required @@ -84,7 +84,7 @@ def expect_no_autologin token.update_columns(expires_on: 1.day.ago, created_at: 31.days.ago) # Log out and in again - visit "/logout" + visit '/logout' expect_no_autologin # Login to save cookie again @@ -96,7 +96,7 @@ def expect_no_autologin .and_return(0) # Log out and in again - visit "/logout" + visit '/logout' expect_no_autologin # Enable functionality diff --git a/modules/two_factor_authentication/spec/features/shared_2fa_examples.rb b/modules/two_factor_authentication/spec/features/shared_2fa_examples.rb index 461a35b159bc..998043be12e4 100644 --- a/modules/two_factor_authentication/spec/features/shared_2fa_examples.rb +++ b/modules/two_factor_authentication/spec/features/shared_2fa_examples.rb @@ -1,64 +1,64 @@ def first_login_step visit signin_path SeleniumHubWaiter.wait - within("#login-form") do - fill_in("username", with: user.login) - fill_in("password", with: user_password) + within('#login-form') do + fill_in('username', with: user.login) + fill_in('password', with: user_password) click_link_or_button I18n.t(:button_login) end end def two_factor_step(token) - expect(page).to have_css("input#otp") + expect(page).to have_css('input#otp') SeleniumHubWaiter.wait - fill_in "otp", with: token + fill_in 'otp', with: token click_button I18n.t(:button_login) end def expect_logged_in visit my_account_path SeleniumHubWaiter.wait - expect(page).to have_css(".form--field-container", text: user.login) + expect(page).to have_css('.form--field-container', text: user.login) end def expect_not_logged_in visit my_account_path - expect(page).to have_no_css(".form--field-container", text: user.login) + expect(page).to have_no_css('.form--field-container', text: user.login) end -RSpec.shared_examples "login without 2FA" do - it "logs in the user without any active devices" do +RSpec.shared_examples 'login without 2FA' do + it 'logs in the user without any active devices' do first_login_step expect_logged_in end end -RSpec.shared_examples "create enforced sms device" do +RSpec.shared_examples 'create enforced sms device' do it do - expect(page).to have_css(".op-toast.-info", - text: I18n.t("two_factor_authentication.forced_registration.required_to_add_device")) + expect(page).to have_css('.op-toast.-info', + text: I18n.t('two_factor_authentication.forced_registration.required_to_add_device')) SeleniumHubWaiter.wait # Create SMS device - find(".mobile-otp-new-device-sms .button--tiny").click + find('.mobile-otp-new-device-sms .button--tiny').click SeleniumHubWaiter.wait - fill_in "device_phone_number", with: "invalid" - click_on "Continue" + fill_in 'device_phone_number', with: 'invalid' + click_on 'Continue' # Expect error on invalid phone - expect(page).to have_css("#errorExplanation", text: "Phone number must be of format +XX XXXXXXXXX") + expect(page).to have_css('#errorExplanation', text: 'Phone number must be of format +XX XXXXXXXXX') SeleniumHubWaiter.wait - fill_in "device_phone_number", with: "+49 123456789" - click_on "Continue" + fill_in 'device_phone_number', with: '+49 123456789' + click_on 'Continue' # Confirm page - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.confirm_device")) - expect(page).to have_css("input#otp") + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.devices.confirm_device')) + expect(page).to have_css('input#otp') SeleniumHubWaiter.wait # Fill in wrong token - fill_in "otp", with: "whatever" + fill_in 'otp', with: 'whatever' # Log token for next access sms_token = nil @@ -69,14 +69,14 @@ def expect_not_logged_in click_button I18n.t(:button_continue) - expect(page).to have_css("h2", text: I18n.t("two_factor_authentication.devices.confirm_device")) - expect(page).to have_css("input#otp") - expect(page).to have_css(".op-toast.-error", - text: I18n.t("two_factor_authentication.devices.registration_failed_token_invalid")) + expect(page).to have_css('h2', text: I18n.t('two_factor_authentication.devices.confirm_device')) + expect(page).to have_css('input#otp') + expect(page).to have_css('.op-toast.-error', + text: I18n.t('two_factor_authentication.devices.registration_failed_token_invalid')) SeleniumHubWaiter.wait # Fill in wrong token - fill_in "otp", with: sms_token + fill_in 'otp', with: sms_token click_button I18n.t(:button_continue) # Expected logged in after correct registration diff --git a/modules/two_factor_authentication/spec/lib/token_strategies/message_bird_spec.rb b/modules/two_factor_authentication/spec/lib/token_strategies/message_bird_spec.rb index 4134dc85c170..6c49196a1825 100644 --- a/modules/two_factor_authentication/spec/lib/token_strategies/message_bird_spec.rb +++ b/modules/two_factor_authentication/spec/lib/token_strategies/message_bird_spec.rb @@ -1,69 +1,69 @@ -require_relative "../../spec_helper" -require "messagebird" +require_relative '../../spec_helper' +require 'messagebird' RSpec.describe OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird do let(:channel) { :sms } - let(:locale) { "en" } + let(:locale) { 'en' } let(:user) { create(:user, language: locale) } let(:device) { create(:two_factor_authentication_device_sms, user:, channel:) } let(:strategy) { described_class.new user:, device:, channel: } before do - allow(strategy).to receive(:token).and_return "1234" + allow(strategy).to receive(:token).and_return '1234' end - describe "#build_recipients" do + describe '#build_recipients' do subject do {}.tap do |params| strategy.send(:build_recipients, params) end[:recipients] end - it "strips all spaces and country lead" do - expect(subject).to eq "49123456789" + it 'strips all spaces and country lead' do + expect(subject).to eq '49123456789' end end - describe "#build_localized_message" do + describe '#build_localized_message' do subject do {}.tap do |params| strategy.send(:build_localized_message, params) end end - context "with en" do - let(:locale) { "en" } + context 'with en' do + let(:locale) { 'en' } - it "returns the correct language and message" do - expect(subject[:language]).to eq :"en-us" - expect(subject[:message]).to include "Your OpenProject one-time password is 1234" + it 'returns the correct language and message' do + expect(subject[:language]).to eq :'en-us' + expect(subject[:message]).to include 'Your OpenProject one-time password is 1234' end end - context "with de" do - let(:locale) { "de" } + context 'with de' do + let(:locale) { 'de' } - it "returns the correct language and message" do + it 'returns the correct language and message' do expected_message = I18n.t("two_factor_authentication.text_otp_delivery_message_sms", app_title: Setting.app_title, - locale: "de", - token: "1234") + locale: 'de', + token: '1234') - expect(subject[:language]).to be :"de-de" + expect(subject[:language]).to be :'de-de' expect(subject[:message]).to eql expected_message end end - context "with unsupported locale ar (Arabic is not supported in message bird)" do - let(:locale) { "ar" } + context 'with unsupported locale ar (Arabic is not supported in message bird)' do + let(:locale) { 'ar' } - it "falls back to english" do + it 'falls back to english' do expected_message = I18n.t("two_factor_authentication.text_otp_delivery_message_sms", app_title: Setting.app_title, - locale: "en", - token: "1234") + locale: 'en', + token: '1234') - expect(subject[:language]).to eq :"en-us" + expect(subject[:language]).to eq :'en-us' expect(subject[:message]).to eql expected_message end end diff --git a/modules/two_factor_authentication/spec/lib/token_strategy_manager_spec.rb b/modules/two_factor_authentication/spec/lib/token_strategy_manager_spec.rb index 103e3a365588..4e948f49167f 100644 --- a/modules/two_factor_authentication/spec/lib/token_strategy_manager_spec.rb +++ b/modules/two_factor_authentication/spec/lib/token_strategy_manager_spec.rb @@ -1,4 +1,4 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' RSpec.describe OpenProject::TwoFactorAuthentication::TokenStrategyManager do let(:dev_strategy) { OpenProject::TwoFactorAuthentication::TokenStrategy::Developer } @@ -11,7 +11,7 @@ end let(:enforced) { false } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: configuration @@ -19,52 +19,52 @@ end end - describe "#find_matching_strategy" do + describe '#find_matching_strategy' do subject { described_class.find_matching_strategy(:sms) } - context "when no strategy is set" do + context 'when no strategy is set' do let(:active_strategies) { [] } - it "returns nil" do + it 'returns nil' do expect(subject).to be_nil end end - context "when matching strategy exists" do + context 'when matching strategy exists' do let(:active_strategies) { [:developer] } - it "returns the strategy" do + it 'returns the strategy' do expect(subject).to eq(dev_strategy) end end - context "when non-matching strategy exists" do + context 'when non-matching strategy exists' do let(:active_strategies) { [:totp] } - it "returns the strategy" do + it 'returns the strategy' do expect(subject).to be_nil end end end - describe "#active_strategies" do - context "with bogus strategy" do + describe '#active_strategies' do + context 'with bogus strategy' do let(:active_strategies) { [:doesnotexist] } - it "raises when accessing" do + it 'raises when accessing' do expect { described_class.active_strategies }.to raise_error(ArgumentError) end - it "raises when validating" do + it 'raises when validating' do expect { described_class.validate_active_strategies! }.to raise_error(ArgumentError) end end end - describe "#validate_active_strategies!" do + describe '#validate_active_strategies!' do subject { described_class.validate_active_strategies! } - context "when no strategy is set" do + context 'when no strategy is set' do let(:active_strategies) { [] } before do @@ -73,20 +73,20 @@ .and_return false end - context "when enforced is false" do + context 'when enforced is false' do let(:enforced) { false } - it "accepts that" do + it 'accepts that' do expect { subject }.not_to raise_error expect(described_class).not_to be_enabled expect(described_class).not_to be_enforced end end - context "when enforced is true" do + context 'when enforced is true' do let(:enforced) { true } - it "raises and error that a strategy is needed" do + it 'raises and error that a strategy is needed' do expect { subject }.to raise_error(ArgumentError) expect(described_class).not_to be_enabled expect(described_class).to be_enforced @@ -94,11 +94,11 @@ end end - context "when a strategy is set" do + context 'when a strategy is set' do let(:active_strategies) { [:developer] } - context "when it is valid" do - it "returns that" do + context 'when it is valid' do + it 'returns that' do expect { subject }.not_to raise_error expect(described_class.active_strategies).to eq([dev_strategy]) expect(described_class).to be_enabled @@ -106,11 +106,11 @@ end end - context "when it is invalid" do - it "raises" do - allow(dev_strategy).to receive(:validate!).and_raise "Error!" + context 'when it is invalid' do + it 'raises' do + allow(dev_strategy).to receive(:validate!).and_raise 'Error!' - expect { subject }.to raise_error "Error!" + expect { subject }.to raise_error 'Error!' expect(described_class).to be_enabled expect(described_class).not_to be_enforced end diff --git a/modules/two_factor_authentication/spec/models/device/default_device_spec.rb b/modules/two_factor_authentication/spec/models/device/default_device_spec.rb index a4735a54070b..14cf614d04c3 100644 --- a/modules/two_factor_authentication/spec/models/device/default_device_spec.rb +++ b/modules/two_factor_authentication/spec/models/device/default_device_spec.rb @@ -1,19 +1,19 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Default device" do +RSpec.describe 'Default device' do let(:user) { create(:user) } let(:other_otp) { build(:two_factor_authentication_device_totp, user:, default: true) } subject { build(:two_factor_authentication_device_totp, user:, default: true) } - it "can be set if nothing else exists" do + it 'can be set if nothing else exists' do expect(subject.save).to be true expect(other_otp).to be_invalid - expect(other_otp.errors[:default]).to include "is already set for another OTP device." + expect(other_otp.errors[:default]).to include 'is already set for another OTP device.' end - context "assuming another default exists" do + context 'assuming another default exists' do let(:other_otp) { create(:two_factor_authentication_device_totp, user:, default: true) } let(:other_sms) { create(:two_factor_authentication_device_sms, user:, default: false) } @@ -25,7 +25,7 @@ subject end - it "can be set through make_default!" do + it 'can be set through make_default!' do expect(user.otp_devices.count).to eq(3) expect(user.otp_devices.get_default).to eq(other_otp) diff --git a/modules/two_factor_authentication/spec/models/device/totp_spec.rb b/modules/two_factor_authentication/spec/models/device/totp_spec.rb index aad1993cdc47..2b7c87ad5d23 100644 --- a/modules/two_factor_authentication/spec/models/device/totp_spec.rb +++ b/modules/two_factor_authentication/spec/models/device/totp_spec.rb @@ -1,50 +1,50 @@ -require "spec_helper" -require "timecop" +require 'spec_helper' +require 'timecop' RSpec.describe TwoFactorAuthentication::Device::Totp do let(:user) { create(:user) } let(:channel) { :totp } - subject { described_class.new identifier: "foo", channel:, user:, active: true } + subject { described_class.new identifier: 'foo', channel:, user:, active: true } - describe "validations" do - context "with invalid channel" do + describe 'validations' do + context 'with invalid channel' do let(:channel) { :whatver } - it "is invalid" do + it 'is invalid' do expect(subject).to be_invalid expect(subject.errors[:channel]).to be_present end end - context "with valid channel" do - it "is valid" do + context 'with valid channel' do + it 'is valid' do expect(subject).to be_valid expect(subject.errors).to be_empty end end end - describe "token validation" do + describe 'token validation' do let(:totp) { subject.send :totp } - context "when setting drift", + context 'when setting drift', with_settings: { plugin_openproject_two_factor_authentication: { - "otp_drift_window" => 30 + 'otp_drift_window' => 30 } } do - it "uses the drift window from configuration" do + it 'uses the drift window from configuration' do expect(subject.allowed_drift).to eq 30 end end - context "when no drift set" do - it "uses the default drift window" do + context 'when no drift set' do + it 'uses the default drift window' do expect(subject.allowed_drift).to eq 60 end - it "uses the drift value for verification" do + it 'uses the drift value for verification' do # Assume never used # rubocop:disable RSpec/SubjectStub allow(subject).to receive(:last_used_at).and_return nil @@ -73,7 +73,7 @@ end end - it "avoids double verification" do + it 'avoids double verification' do subject.save! valid = totp.at(Time.current) diff --git a/modules/two_factor_authentication/spec/models/device/webauthn_spec.rb b/modules/two_factor_authentication/spec/models/device/webauthn_spec.rb index bbe39d927652..8403472c2c46 100644 --- a/modules/two_factor_authentication/spec/models/device/webauthn_spec.rb +++ b/modules/two_factor_authentication/spec/models/device/webauthn_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe TwoFactorAuthentication::Device::Webauthn do let(:user) { create(:user) } diff --git a/modules/two_factor_authentication/spec/models/login_token_spec.rb b/modules/two_factor_authentication/spec/models/login_token_spec.rb index ad5d37d87445..558d85fb31ea 100644 --- a/modules/two_factor_authentication/spec/models/login_token_spec.rb +++ b/modules/two_factor_authentication/spec/models/login_token_spec.rb @@ -1,4 +1,4 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' RSpec.describe TwoFactorAuthentication::LoginToken, :with_2fa_ee do shared_let(:user) { create(:user) } diff --git a/modules/two_factor_authentication/spec/models/user_spec.rb b/modules/two_factor_authentication/spec/models/user_spec.rb index 32ef36ec6eb0..94428d16cfb2 100644 --- a/modules/two_factor_authentication/spec/models/user_spec.rb +++ b/modules/two_factor_authentication/spec/models/user_spec.rb @@ -1,4 +1,4 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' module OpenProject::TwoFactorAuthentication::Patches module UserSpec @@ -32,7 +32,7 @@ def login_with(login, password) create_user end - describe "#try_to_login", "with valid username but invalid pwd" do + describe '#try_to_login', "with valid username but invalid pwd" do it "returns nil" do expect(invalid_login).to be_nil end diff --git a/modules/two_factor_authentication/spec/routing/two_factor_authentication/my/two_factor_devices_spec.rb b/modules/two_factor_authentication/spec/routing/two_factor_authentication/my/two_factor_devices_spec.rb index 810b2793a168..5964cc6d5084 100644 --- a/modules/two_factor_authentication/spec/routing/two_factor_authentication/my/two_factor_devices_spec.rb +++ b/modules/two_factor_authentication/spec/routing/two_factor_authentication/my/two_factor_devices_spec.rb @@ -26,42 +26,42 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "users 2fa devices" do - it "route to index" do - expect(get("/my/two_factor_devices")).to route_to("two_factor_authentication/my/two_factor_devices#index") +RSpec.describe 'users 2fa devices' do + it 'route to index' do + expect(get('/my/two_factor_devices')).to route_to('two_factor_authentication/my/two_factor_devices#index') end - it "route to new" do - expect(get("/my/two_factor_devices/new")).to route_to("two_factor_authentication/my/two_factor_devices#new") + it 'route to new' do + expect(get('/my/two_factor_devices/new')).to route_to('two_factor_authentication/my/two_factor_devices#new') end - it "route to register" do - expect(post("/my/two_factor_devices/register")).to route_to("two_factor_authentication/my/two_factor_devices#register") + it 'route to register' do + expect(post('/my/two_factor_devices/register')).to route_to('two_factor_authentication/my/two_factor_devices#register') end - it "route to confirm" do - expect(get("/my/two_factor_devices/1/confirm")).to route_to(controller: "two_factor_authentication/my/two_factor_devices", - action: "confirm", - device_id: "1") + it 'route to confirm' do + expect(get('/my/two_factor_devices/1/confirm')).to route_to(controller: 'two_factor_authentication/my/two_factor_devices', + action: 'confirm', + device_id: '1') end - it "route to POST confirm" do - expect(post("/my/two_factor_devices/1/confirm")).to route_to(controller: "two_factor_authentication/my/two_factor_devices", - action: "confirm", - device_id: "1") + it 'route to POST confirm' do + expect(post('/my/two_factor_devices/1/confirm')).to route_to(controller: 'two_factor_authentication/my/two_factor_devices', + action: 'confirm', + device_id: '1') end - it "route to POST make_default" do - expect(post("/my/two_factor_devices/1/make_default")).to route_to(controller: "two_factor_authentication/my/two_factor_devices", - action: "make_default", - device_id: "1") + it 'route to POST make_default' do + expect(post('/my/two_factor_devices/1/make_default')).to route_to(controller: 'two_factor_authentication/my/two_factor_devices', + action: 'make_default', + device_id: '1') end - it "route to DELETE destroy" do - expect(delete("/my/two_factor_devices/1")).to route_to(controller: "two_factor_authentication/my/two_factor_devices", - action: "destroy", - device_id: "1") + it 'route to DELETE destroy' do + expect(delete('/my/two_factor_devices/1')).to route_to(controller: 'two_factor_authentication/my/two_factor_devices', + action: 'destroy', + device_id: '1') end end diff --git a/modules/two_factor_authentication/spec/routing/two_factor_authentication/users/two_factor_devices_spec.rb b/modules/two_factor_authentication/spec/routing/two_factor_authentication/users/two_factor_devices_spec.rb index 790511b898e7..f712fe9db11d 100644 --- a/modules/two_factor_authentication/spec/routing/two_factor_authentication/users/two_factor_devices_spec.rb +++ b/modules/two_factor_authentication/spec/routing/two_factor_authentication/users/two_factor_devices_spec.rb @@ -26,38 +26,38 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "users 2fa devices" do - it "route to GET new" do - expect(get("/users/2/two_factor_devices/new")).to route_to(controller: "two_factor_authentication/users/two_factor_devices", - action: "new", - id: "2") +RSpec.describe 'users 2fa devices' do + it 'route to GET new' do + expect(get('/users/2/two_factor_devices/new')).to route_to(controller: 'two_factor_authentication/users/two_factor_devices', + action: 'new', + id: '2') end - it "route to POST register" do - expect(post("/users/2/two_factor_devices/register")).to route_to(controller: "two_factor_authentication/users/two_factor_devices", - action: "register", - id: "2") + it 'route to POST register' do + expect(post('/users/2/two_factor_devices/register')).to route_to(controller: 'two_factor_authentication/users/two_factor_devices', + action: 'register', + id: '2') end - it "route to POST confirm" do - expect(post("/users/2/two_factor_devices/1/make_default")).to route_to(controller: "two_factor_authentication/users/two_factor_devices", - action: "make_default", - id: "2", - device_id: "1") + it 'route to POST confirm' do + expect(post('/users/2/two_factor_devices/1/make_default')).to route_to(controller: 'two_factor_authentication/users/two_factor_devices', + action: 'make_default', + id: '2', + device_id: '1') end - it "route to POST delete_all" do - expect(post("/users/2/two_factor_devices/delete_all")).to route_to(controller: "two_factor_authentication/users/two_factor_devices", - action: "delete_all", - id: "2") + it 'route to POST delete_all' do + expect(post('/users/2/two_factor_devices/delete_all')).to route_to(controller: 'two_factor_authentication/users/two_factor_devices', + action: 'delete_all', + id: '2') end - it "route to DELETE destroy" do - expect(delete("/users/2/two_factor_devices/1")).to route_to(controller: "two_factor_authentication/users/two_factor_devices", - action: "destroy", - id: "2", - device_id: "1") + it 'route to DELETE destroy' do + expect(delete('/users/2/two_factor_devices/1')).to route_to(controller: 'two_factor_authentication/users/two_factor_devices', + action: 'destroy', + id: '2', + device_id: '1') end end diff --git a/modules/two_factor_authentication/spec/services/token_delivery/message_bird_spec.rb b/modules/two_factor_authentication/spec/services/token_delivery/message_bird_spec.rb index 7ef6394e0aa3..6093eae370e4 100644 --- a/modules/two_factor_authentication/spec/services/token_delivery/message_bird_spec.rb +++ b/modules/two_factor_authentication/spec/services/token_delivery/message_bird_spec.rb @@ -1,14 +1,14 @@ -require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") -require "messagebird" +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') +require 'messagebird' RSpec.describe OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird do - describe "sending messages" do + describe 'sending messages' do let!(:user) { create(:user, language: locale) } - let!(:locale) { "en" } + let!(:locale) { 'en' } let!(:device) { create(:two_factor_authentication_device_sms, user:, channel:) } - let(:service_url) { "https://example.org/foobar" } - let(:apikey) { "whatever" } + let(:service_url) { 'https://example.org/foobar' } + let(:apikey) { 'whatever' } let(:params) do { apikey: @@ -19,12 +19,12 @@ subject { TwoFactorAuthentication::TokenService.new user: } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: { - "active_strategies" => [:message_bird], - "message_bird" => params + 'active_strategies' => [:message_bird], + 'message_bird' => params } } end @@ -33,61 +33,61 @@ before do allow_any_instance_of(OpenProject::TwoFactorAuthentication::TokenStrategy::MessageBird) .to receive(:create_mobile_otp) - .and_return("1234") + .and_return('1234') end - describe "#setup" do + describe '#setup' do let(:channel) { :sms } let(:params) { { apikey: nil } } - it "raises an exception for incomplete params" do + it 'raises an exception for incomplete params' do expect { described_class.validate! } .to raise_exception(ArgumentError) end end - describe "calling a mocked test API" do + describe 'calling a mocked test API' do let(:channel) { :sms } before do allow(MessageBird::Client).to receive(:new) end - it "uses the api key defined in the settings" do + it 'uses the api key defined in the settings' do result expect(MessageBird::Client).to have_received(:new).with(apikey) end end - describe "calling the real test API" do - let(:apikey) { ENV.fetch("MESSAGEBIRD_TEST_APIKEY", nil) } + describe 'calling the real test API' do + let(:apikey) { ENV.fetch('MESSAGEBIRD_TEST_APIKEY', nil) } before do - skip "Missing MESSAGEBIRD_TEST_APIKEY environment variable" unless apikey.present? + skip 'Missing MESSAGEBIRD_TEST_APIKEY environment variable' unless apikey.present? end - context "with SMS" do + context 'with SMS' do let(:channel) { :sms } - it "returns success in the service" do + it 'returns success in the service' do expect(result).to be_success end end - context "with VOICE" do + context 'with VOICE' do let(:channel) { :voice } - it "returns success in the service" do + it 'returns success in the service' do expect(result).to be_success end end end - describe "calling a mocked API Client" do + describe 'calling a mocked API Client' do let(:messagebird) { instance_double(MessageBird::Client) } let(:failed_count) { 0 } - let(:response) { instance_double(MessageBird::Message, recipients: { "totalDeliveryFailedCount" => failed_count }) } + let(:response) { instance_double(MessageBird::Message, recipients: { 'totalDeliveryFailedCount' => failed_count }) } let(:channel) { :sms } before do @@ -96,34 +96,34 @@ .and_return(messagebird) end - context "with SMS" do + context 'with SMS' do before do allow(messagebird) .to receive(:message_create) .with(Setting.app_title, - "49123456789", - I18n.t("two_factor_authentication.text_otp_delivery_message_sms", app_title: Setting.app_title, token: "1234"), + '49123456789', + I18n.t('two_factor_authentication.text_otp_delivery_message_sms', app_title: Setting.app_title, token: '1234'), validity: 720) .and_return(response) end - it "returns success in the service" do + it 'returns success in the service' do expect(result).to be_success end - context "failure" do + context 'failure' do let(:failed_count) { 1 } - it "returns error in the service" do + it 'returns error in the service' do expect(result).not_to be_success expect(result.errors).to be_present end end end - context "with voice" do + context 'with voice' do let(:channel) { :voice } - let(:expected_language) { :"en-us" } + let(:expected_language) { :'en-us' } before do allow(subject.strategy) @@ -136,35 +136,35 @@ .and_return(response) end - it "returns success in the service" do + it 'returns success in the service' do expect(result).to be_success expect(messagebird) .to have_received(:voice_message_create) - .with("49123456789", - subject.strategy.send(:localized_message, locale, "1234"), + .with('49123456789', + subject.strategy.send(:localized_message, locale, '1234'), ifMachine: :continue, language: expected_language) end - context "failure" do + context 'failure' do let(:failed_count) { 1 } - it "returns error in the service" do + it 'returns error in the service' do expect(result).not_to be_success expect(result.errors).to be_present end end - context "with german locale" do - let(:locale) { "de" } - let(:expected_language) { :"de-de" } + context 'with german locale' do + let(:locale) { 'de' } + let(:expected_language) { :'de-de' } - it "returns success in the service" do + it 'returns success in the service' do expect(result).to be_success expect(messagebird) .to have_received(:voice_message_create) - .with("49123456789", - subject.strategy.send(:localized_message, locale, "1234"), + .with('49123456789', + subject.strategy.send(:localized_message, locale, '1234'), ifMachine: :continue, language: expected_language) end diff --git a/modules/two_factor_authentication/spec/services/token_delivery/sns_spec.rb b/modules/two_factor_authentication/spec/services/token_delivery/sns_spec.rb index 9c2a538555e2..44d0acf3b1ed 100644 --- a/modules/two_factor_authentication/spec/services/token_delivery/sns_spec.rb +++ b/modules/two_factor_authentication/spec/services/token_delivery/sns_spec.rb @@ -1,26 +1,26 @@ -require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') RSpec.describe OpenProject::TwoFactorAuthentication::TokenStrategy::Sns do - describe "sending messages" do - let(:phone) { "+49 123456789" } + describe 'sending messages' do + let(:phone) { '+49 123456789' } let!(:user) { create(:user) } let!(:device) { create(:two_factor_authentication_device_sms, user:, channel:) } let(:channel) { :sms } let(:sns_params) do { - region: "eu-west-1", - access_key_id: "foobar", - secret_access_key: "foobar key" + region: 'eu-west-1', + access_key_id: 'foobar', + secret_access_key: 'foobar key' } end - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: { - "active_strategies" => [:sns], - "sns" => sns_params + 'active_strategies' => [:sns], + 'sns' => sns_params } } end @@ -29,28 +29,28 @@ before do allow_any_instance_of(OpenProject::TwoFactorAuthentication::TokenStrategy::Sns) .to receive(:create_mobile_otp) - .and_return("1234") + .and_return('1234') end - describe "#setup" do - context "for valid params" do - it "validates without errors" do + describe '#setup' do + context 'for valid params' do + it 'validates without errors' do expect { described_class.validate! } .not_to raise_exception end end - context "for incomplete params" do + context 'for incomplete params' do let(:sns_params) { { region: nil } } - it "raises an exception" do + it 'raises an exception' do expect { described_class.validate! } .to raise_exception(ArgumentError) end end end - describe "calling a mocked AWS API" do + describe 'calling a mocked AWS API' do subject { TwoFactorAuthentication::TokenService.new user: } let(:result) { subject.request } @@ -60,21 +60,21 @@ expect(Aws::SNS::Client).to receive(:new).and_return api end - context "assuming invalid credentials" do + context 'assuming invalid credentials' do before do expect(api) .to receive(:set_sms_attributes) .with(any_args) - .and_raise("The security token included in the request is invalid.") + .and_raise('The security token included in the request is invalid.') end - it "does not raise an exception out of delivery" do + it 'does not raise an exception out of delivery' do expect(result).not_to be_success - expect(result.errors.full_messages).to eq([I18n.t("two_factor_authentication.sns.delivery_failed")]) + expect(result.errors.full_messages).to eq([I18n.t('two_factor_authentication.sns.delivery_failed')]) end end - context "assuming valid credential" do + context 'assuming valid credential' do let(:api_result) { double } before do @@ -83,13 +83,13 @@ expect(api).to receive(:set_sms_attributes).and_return(nil) expect(api) .to receive(:publish) - .with({ phone_number: phone.delete(" "), - message: I18n.t("two_factor_authentication.text_otp_delivery_message_sms", + .with({ phone_number: phone.delete(' '), + message: I18n.t('two_factor_authentication.text_otp_delivery_message_sms', app_title: Setting.app_title, token: 1234) }) .and_return(api_result) end - it "returns a successful delivery" do + it 'returns a successful delivery' do expect(result).to be_success end end diff --git a/modules/two_factor_authentication/spec/services/token_delivery/totp_spec.rb b/modules/two_factor_authentication/spec/services/token_delivery/totp_spec.rb index ca6e598524aa..b8718c58f823 100644 --- a/modules/two_factor_authentication/spec/services/token_delivery/totp_spec.rb +++ b/modules/two_factor_authentication/spec/services/token_delivery/totp_spec.rb @@ -1,23 +1,23 @@ -require File.expand_path(File.dirname(__FILE__) + "/../../spec_helper") +require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') RSpec.describe OpenProject::TwoFactorAuthentication::TokenStrategy::Totp do - describe "sending messages" do + describe 'sending messages' do let!(:user) { create(:user) } let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } - describe "#verify" do + describe '#verify' do subject { TwoFactorAuthentication::TokenService.new user: } let(:result) { subject.verify token } - context "with valid current token" do + context 'with valid current token' do let(:token) { device.totp.now } - it "is validated" do + it 'is validated' do expect(result).to be_success end - it "is validated only once" do + it 'is validated only once' do expect(subject.verify(token)).to be_success # Last OTP date is remembered for the device. @@ -25,26 +25,26 @@ end end - context "with invalid token" do - let(:token) { "definitely invalid" } + context 'with invalid token' do + let(:token) { 'definitely invalid' } - it "is not validated" do + it 'is not validated' do expect(result).not_to be_success expect(result.errors[:base]).to include I18n.t(:notice_account_otp_invalid) end end - context "with internal error" do + context 'with internal error' do let(:token) { 1234 } before do allow_any_instance_of(TwoFactorAuthentication::Device::Totp) - .to receive(:verify_token).and_raise "Some internal error!" + .to receive(:verify_token).and_raise 'Some internal error!' end - it "returns a successful delivery" do + it 'returns a successful delivery' do expect(result).not_to be_success - expect(result.errors[:base]).to include "Some internal error!" + expect(result.errors[:base]).to include 'Some internal error!' end end end diff --git a/modules/two_factor_authentication/spec/services/token_service_spec.rb b/modules/two_factor_authentication/spec/services/token_service_spec.rb index f9e0f525c8d2..067f86dcc61e 100644 --- a/modules/two_factor_authentication/spec/services/token_service_spec.rb +++ b/modules/two_factor_authentication/spec/services/token_service_spec.rb @@ -1,13 +1,13 @@ -require_relative "../spec_helper" +require_relative '../spec_helper' RSpec.describe TwoFactorAuthentication::TokenService do - describe "sending messages" do + describe 'sending messages' do let(:user) { create(:user) } let(:dev_strategy) { OpenProject::TwoFactorAuthentication::TokenStrategy::Developer } let(:configuration) do { - "active_strategies" => active_strategies, - "enforced" => enforced + 'active_strategies' => active_strategies, + 'enforced' => enforced } end let(:enforced) { false } @@ -16,7 +16,7 @@ subject { described_class.new user: } - include_context "with settings" do + include_context 'with settings' do let(:settings) do { plugin_openproject_two_factor_authentication: configuration @@ -24,10 +24,10 @@ end end - context "when no strategy is set" do + context 'when no strategy is set' do let(:active_strategies) { [] } - context "when enforced" do + context 'when enforced' do let(:enforced) { true } before do @@ -36,17 +36,17 @@ .and_return false end - it "requires a token" do + it 'requires a token' do expect(subject).to be_requires_token end - it "returns error when requesting" do + it 'returns error when requesting' do expect(result).not_to be_success - expect(result.errors.full_messages).to eq [I18n.t("two_factor_authentication.error_2fa_disabled")] + expect(result.errors.full_messages).to eq [I18n.t('two_factor_authentication.error_2fa_disabled')] end end - context "when not enforced" do + context 'when not enforced' do let(:enforced) { false } before do @@ -55,59 +55,59 @@ .and_return false end - it "requires no token" do + it 'requires no token' do expect(subject).not_to be_requires_token end - it "returns error when requesting" do + it 'returns error when requesting' do expect(result).not_to be_success - expect(result.errors.full_messages).to eq [I18n.t("two_factor_authentication.error_2fa_disabled")] + expect(result.errors.full_messages).to eq [I18n.t('two_factor_authentication.error_2fa_disabled')] end end end - context "when developer strategy is set" do + context 'when developer strategy is set' do let(:active_strategies) { [:developer] } - context "when no device exists" do - it "returns an error" do + context 'when no device exists' do + it 'returns an error' do expect(result).not_to be_success - expect(result.errors.full_messages).to eq [I18n.t("two_factor_authentication.error_no_device")] + expect(result.errors.full_messages).to eq [I18n.t('two_factor_authentication.error_no_device')] end end - context "when matching device exists" do + context 'when matching device exists' do let!(:device) { create(:two_factor_authentication_device_sms, user:, default: true) } - it "submits the request" do + it 'submits the request' do expect(subject).to be_requires_token expect(result).to be_success expect(result.errors).to be_empty end end - context "when non-matching device exists" do + context 'when non-matching device exists' do let!(:device) { create(:two_factor_authentication_device_totp, user:, default: true) } - it "submits the request" do + it 'submits the request' do expect(subject).to be_requires_token expect(result).not_to be_success - expect(result.errors.full_messages).to eq [I18n.t("two_factor_authentication.error_no_matching_strategy")] + expect(result.errors.full_messages).to eq [I18n.t('two_factor_authentication.error_no_matching_strategy')] end end end - context "when developer and totp strategies are set" do + context 'when developer and totp strategies are set' do let(:active_strategies) { %i[developer totp] } let!(:totp_device) { create(:two_factor_authentication_device_totp, user:, default: true) } let!(:sms_device) { create(:two_factor_authentication_device_sms, user:, default: false) } subject { described_class.new user:, use_device: } - context "with default device/channel" do + context 'with default device/channel' do let(:use_device) { nil } - it "uses the totp device" do + it 'uses the totp device' do expect(subject).to be_requires_token expect(result).to be_success expect(result.errors).to be_empty @@ -117,10 +117,10 @@ end end - context "with overridden device" do + context 'with overridden device' do let(:use_device) { sms_device } - it "uses the overridden device" do + it 'uses the overridden device' do expect(subject).to be_requires_token expect(result).to be_success expect(result.errors).to be_empty diff --git a/modules/webhooks/app/components/webhooks/outgoing/deliveries/response_component.rb b/modules/webhooks/app/components/webhooks/outgoing/deliveries/response_component.rb index f5b50f05b78f..36b3b2259a19 100644 --- a/modules/webhooks/app/components/webhooks/outgoing/deliveries/response_component.rb +++ b/modules/webhooks/app/components/webhooks/outgoing/deliveries/response_component.rb @@ -7,7 +7,7 @@ class ResponseComponent < ApplicationComponent property :response_body def title - model.class.human_attribute_name("response_body") + model.class.human_attribute_name('response_body') end end end diff --git a/modules/webhooks/app/components/webhooks/outgoing/deliveries/table_component.rb b/modules/webhooks/app/components/webhooks/outgoing/deliveries/table_component.rb index e85a8cf93498..26a01092973a 100644 --- a/modules/webhooks/app/components/webhooks/outgoing/deliveries/table_component.rb +++ b/modules/webhooks/app/components/webhooks/outgoing/deliveries/table_component.rb @@ -9,16 +9,16 @@ def sortable? end def empty_row_message - I18n.t "webhooks.outgoing.deliveries.no_results_table" + I18n.t 'webhooks.outgoing.deliveries.no_results_table' end def headers [ - ["id", { caption: I18n.t("attributes.id") }], - ["event_name", { caption: ::Webhooks::Log.human_attribute_name("event_name") }], - ["time", { caption: I18n.t("webhooks.outgoing.deliveries.time") }], - ["response_code", { caption: ::Webhooks::Log.human_attribute_name("response_code") }], - ["response_body", { caption: ::Webhooks::Log.human_attribute_name("response_body") }] + ['id', { caption: I18n.t('attributes.id') }], + ['event_name', { caption: ::Webhooks::Log.human_attribute_name('event_name') }], + ['time', { caption: I18n.t('webhooks.outgoing.deliveries.time') }], + ['response_code', { caption: ::Webhooks::Log.human_attribute_name('response_code') }], + ['response_body', { caption: ::Webhooks::Log.human_attribute_name('response_body') }] ] end end diff --git a/modules/webhooks/app/components/webhooks/outgoing/webhooks/row_component.rb b/modules/webhooks/app/components/webhooks/outgoing/webhooks/row_component.rb index 0cf9b561dd2e..1833c9c235f4 100644 --- a/modules/webhooks/app/components/webhooks/outgoing/webhooks/row_component.rb +++ b/modules/webhooks/app/components/webhooks/outgoing/webhooks/row_component.rb @@ -15,7 +15,7 @@ def name def enabled if webhook.enabled? - helpers.op_icon "icon-yes" + helpers.op_icon 'icon-yes' end end @@ -30,9 +30,9 @@ def events count = selected_events.count if count <= 3 - selected_events.join(", ") + selected_events.join(', ') else - content_tag("span", count, class: "badge -border-only") + content_tag('span', count, class: 'badge -border-only') end end @@ -50,17 +50,17 @@ def selected_projects if selected.empty? "(#{I18n.t(:label_all)})" elsif selected.size <= 3 - webhook.projects.pluck(:name).join(", ") + webhook.projects.pluck(:name).join(', ') else - content_tag("span", selected, class: "badge -border-only") + content_tag('span', selected, class: 'badge -border-only') end end def row_css_class [ - "webhooks--outgoing-webhook-row", + 'webhooks--outgoing-webhook-row', "webhooks--outgoing-webhook-row-#{model.id}" - ].join(" ") + ].join(' ') end ### @@ -71,7 +71,7 @@ def button_links def edit_link link_to( - helpers.op_icon("icon icon-edit button--link"), + helpers.op_icon('icon icon-edit button--link'), { controller: table.target_controller, action: :edit, webhook_id: webhook.id }, title: t(:button_edit) ) @@ -79,7 +79,7 @@ def edit_link def delete_link link_to( - helpers.op_icon("icon icon-delete button--link"), + helpers.op_icon('icon icon-delete button--link'), { controller: table.target_controller, action: :destroy, webhook_id: webhook.id }, method: :delete, data: { confirm: I18n.t(:text_are_you_sure) }, diff --git a/modules/webhooks/app/components/webhooks/outgoing/webhooks/table_component.rb b/modules/webhooks/app/components/webhooks/outgoing/webhooks/table_component.rb index b337ed5c4793..b9c2cf52ce6c 100644 --- a/modules/webhooks/app/components/webhooks/outgoing/webhooks/table_component.rb +++ b/modules/webhooks/app/components/webhooks/outgoing/webhooks/table_component.rb @@ -9,7 +9,7 @@ def initial_sort end def target_controller - "webhooks/outgoing/admin" + 'webhooks/outgoing/admin' end def sortable? @@ -18,23 +18,23 @@ def sortable? def inline_create_link link_to({ controller: target_controller, action: :new }, - class: "webhooks--add-row wp-inline-create--add-link", - title: I18n.t("webhooks.outgoing.label_add_new")) do - helpers.op_icon("icon icon-add") + class: 'webhooks--add-row wp-inline-create--add-link', + title: I18n.t('webhooks.outgoing.label_add_new')) do + helpers.op_icon('icon icon-add') end end def empty_row_message - I18n.t "webhooks.outgoing.no_results_table" + I18n.t 'webhooks.outgoing.no_results_table' end def headers [ - ["name", { caption: I18n.t("attributes.name") }], - ["enabled", { caption: I18n.t(:label_active) }], - ["selected_projects", { caption: ::Webhooks::Webhook.human_attribute_name("projects") }], - ["events", { caption: I18n.t("webhooks.outgoing.label_event_resources") }], - ["description", { caption: I18n.t("attributes.description") }] + ['name', { caption: I18n.t('attributes.name') }], + ['enabled', { caption: I18n.t(:label_active) }], + ['selected_projects', { caption: ::Webhooks::Webhook.human_attribute_name('projects') }], + ['events', { caption: I18n.t('webhooks.outgoing.label_event_resources') }], + ['description', { caption: I18n.t('attributes.description') }] ] end end diff --git a/modules/webhooks/app/controllers/webhooks/incoming/hooks_controller.rb b/modules/webhooks/app/controllers/webhooks/incoming/hooks_controller.rb index 208399b7d3fb..acfbceb747f5 100644 --- a/modules/webhooks/app/controllers/webhooks/incoming/hooks_controller.rb +++ b/modules/webhooks/app/controllers/webhooks/incoming/hooks_controller.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "json" +require 'json' module Webhooks module Incoming @@ -50,7 +50,7 @@ def api_request? end def handle_hook - hook = OpenProject::Webhooks.find(params.require("hook_name")) + hook = OpenProject::Webhooks.find(params.require('hook_name')) if hook code = hook.handle(request, params, find_current_user) diff --git a/modules/webhooks/app/controllers/webhooks/outgoing/admin_controller.rb b/modules/webhooks/app/controllers/webhooks/outgoing/admin_controller.rb index 9f673f86b841..7643afaffbf6 100644 --- a/modules/webhooks/app/controllers/webhooks/outgoing/admin_controller.rb +++ b/modules/webhooks/app/controllers/webhooks/outgoing/admin_controller.rb @@ -1,7 +1,7 @@ module Webhooks module Outgoing class AdminController < ::ApplicationController - layout "admin" + layout 'admin' before_action :require_admin before_action :find_webhook, only: %i[show edit update destroy] diff --git a/modules/webhooks/app/models/webhooks.rb b/modules/webhooks/app/models/webhooks.rb index e802584216a2..03e7ca351281 100644 --- a/modules/webhooks/app/models/webhooks.rb +++ b/modules/webhooks/app/models/webhooks.rb @@ -1,5 +1,5 @@ module Webhooks def self.table_name_prefix - "webhooks_" + 'webhooks_' end end diff --git a/modules/webhooks/app/models/webhooks/log.rb b/modules/webhooks/app/models/webhooks/log.rb index ca0829ee60ae..f09b689f2b33 100644 --- a/modules/webhooks/app/models/webhooks/log.rb +++ b/modules/webhooks/app/models/webhooks/log.rb @@ -1,6 +1,6 @@ module Webhooks class Log < ApplicationRecord - belongs_to :webhook, foreign_key: :webhooks_webhook_id, class_name: "::Webhooks::Webhook", dependent: :destroy + belongs_to :webhook, foreign_key: :webhooks_webhook_id, class_name: '::Webhooks::Webhook', dependent: :destroy validates :url, presence: true validates :event_name, presence: true diff --git a/modules/webhooks/app/models/webhooks/project.rb b/modules/webhooks/app/models/webhooks/project.rb index 438986db6ce5..539b6f94cdc5 100644 --- a/modules/webhooks/app/models/webhooks/project.rb +++ b/modules/webhooks/app/models/webhooks/project.rb @@ -1,7 +1,7 @@ module Webhooks class Project < ApplicationRecord belongs_to :webhook - belongs_to :project, class_name: "::Project" + belongs_to :project, class_name: '::Project' validates_presence_of :project end diff --git a/modules/webhooks/app/models/webhooks/webhook.rb b/modules/webhooks/app/models/webhooks/webhook.rb index c8084c301d17..5cc5c9d91eaf 100644 --- a/modules/webhooks/app/models/webhooks/webhook.rb +++ b/modules/webhooks/app/models/webhooks/webhook.rb @@ -8,10 +8,10 @@ class Webhook < ApplicationRecord validates_uniqueness_of :name validates :url, url: true - has_many :events, foreign_key: :webhooks_webhook_id, class_name: "::Webhooks::Event", dependent: :delete_all - has_many :webhook_projects, foreign_key: :webhooks_webhook_id, class_name: "::Webhooks::Project", dependent: :delete_all + has_many :events, foreign_key: :webhooks_webhook_id, class_name: '::Webhooks::Event', dependent: :delete_all + has_many :webhook_projects, foreign_key: :webhooks_webhook_id, class_name: '::Webhooks::Project', dependent: :delete_all has_many :projects, through: :webhook_projects - has_many :deliveries, foreign_key: :webhooks_webhook_id, class_name: "::Webhooks::Log", dependent: :delete_all + has_many :deliveries, foreign_key: :webhooks_webhook_id, class_name: '::Webhooks::Log', dependent: :delete_all def self.enabled where(enabled: true) diff --git a/modules/webhooks/app/services/webhooks/outgoing/update_webhook_service.rb b/modules/webhooks/app/services/webhooks/outgoing/update_webhook_service.rb index 35874386206d..3dbdfc8d0d82 100644 --- a/modules/webhooks/app/services/webhooks/outgoing/update_webhook_service.rb +++ b/modules/webhooks/app/services/webhooks/outgoing/update_webhook_service.rb @@ -35,7 +35,7 @@ def set_selected_projects!(params) option = params.delete :project_ids selected = params.delete :selected_project_ids - if option == "all" + if option == 'all' webhook.all_projects = true else webhook.all_projects = false diff --git a/modules/webhooks/app/views/webhooks/outgoing/admin/edit.html.erb b/modules/webhooks/app/views/webhooks/outgoing/admin/edit.html.erb index 1d97909b1795..181ccaf33589 100644 --- a/modules/webhooks/app/views/webhooks/outgoing/admin/edit.html.erb +++ b/modules/webhooks/app/views/webhooks/outgoing/admin/edit.html.erb @@ -16,7 +16,7 @@ html: { class: 'form', autocomplete: 'off' } do |f| %> <%= render partial: "form", locals: { f: f, webhook: @webhook } %>

    - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_save), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { action: :index }, class: 'button -with-icon icon-cancel' %>

    -<% end %> +<% end %> \ No newline at end of file diff --git a/modules/webhooks/app/views/webhooks/outgoing/admin/index.html.erb b/modules/webhooks/app/views/webhooks/outgoing/admin/index.html.erb index b6773b0c1802..7d3c2e4763f0 100644 --- a/modules/webhooks/app/views/webhooks/outgoing/admin/index.html.erb +++ b/modules/webhooks/app/views/webhooks/outgoing/admin/index.html.erb @@ -4,7 +4,7 @@ <%= toolbar title: t('webhooks.plural') do %>
  • <%= link_to new_admin_outgoing_webhook_path, - { class: 'button -primary', + { class: 'button -alt-highlight', aria: {label: t('webhooks.outgoing.label_add_new')}, title: t('webhooks.outgoing.label_add_new')} do %> <%= op_icon('button--icon icon-add') %> @@ -19,3 +19,4 @@

    <%= render ::Webhooks::Outgoing::Webhooks::TableComponent.new(rows: @webhooks) %> + diff --git a/modules/webhooks/app/views/webhooks/outgoing/admin/new.html.erb b/modules/webhooks/app/views/webhooks/outgoing/admin/new.html.erb index 1df7c94be00d..57602eda0fad 100644 --- a/modules/webhooks/app/views/webhooks/outgoing/admin/new.html.erb +++ b/modules/webhooks/app/views/webhooks/outgoing/admin/new.html.erb @@ -15,7 +15,7 @@ html: { class: 'form', autocomplete: 'off' } do |f| %> <%= render partial: "form", locals: { f: f, webhook: @webhook } %>

    - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> + <%= styled_button_tag t(:button_create), class: '-highlight -with-icon icon-checkmark' %> <%= link_to t(:button_cancel), { action: :index }, class: 'button -with-icon icon-cancel' %>

    -<% end %> +<% end %> \ No newline at end of file diff --git a/modules/webhooks/app/workers/cleanup_webhook_logs_job.rb b/modules/webhooks/app/workers/cleanup_webhook_logs_job.rb index 00fd8f2233ae..4a59ae264cef 100644 --- a/modules/webhooks/app/workers/cleanup_webhook_logs_job.rb +++ b/modules/webhooks/app/workers/cleanup_webhook_logs_job.rb @@ -26,11 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -class CleanupWebhookLogsJob < ApplicationJob +class CleanupWebhookLogsJob < Cron::CronJob + # runs at 5:28 on Sunday + self.cron_expression = '28 5 * * 7' + # Clean any logs older than 7 days def perform ::Webhooks::Log - .where("created_at < ?", 7.days.ago) + .where('created_at < ?', 7.days.ago) .delete_all end end diff --git a/modules/webhooks/app/workers/project_webhook_job.rb b/modules/webhooks/app/workers/project_webhook_job.rb index 1951fa10ea2e..2d04c479cf65 100644 --- a/modules/webhooks/app/workers/project_webhook_job.rb +++ b/modules/webhooks/app/workers/project_webhook_job.rb @@ -32,7 +32,7 @@ def payload_key end def accepted_in_project? - if event_name == "project:created" + if event_name == 'project:created' true else webhook.enabled_for_project?(resource.id) diff --git a/modules/webhooks/app/workers/represented_webhook_job.rb b/modules/webhooks/app/workers/represented_webhook_job.rb index c058938a5237..68fb45bec7cc 100644 --- a/modules/webhooks/app/workers/represented_webhook_job.rb +++ b/modules/webhooks/app/workers/represented_webhook_job.rb @@ -43,7 +43,7 @@ def perform(webhook_id, resource, event_name) response = nil if signature = request_signature(body) - headers["X-OP-Signature"] = signature + headers['X-OP-Signature'] = signature end begin diff --git a/modules/webhooks/config/routes.rb b/modules/webhooks/config/routes.rb index f2bc12676202..fd28b654c70c 100644 --- a/modules/webhooks/config/routes.rb +++ b/modules/webhooks/config/routes.rb @@ -27,16 +27,16 @@ #++ Rails.application.routes.draw do - namespace "webhooks" do - match ":hook_name", to: "incoming/hooks#handle_hook", via: %i(get post) + namespace 'webhooks' do + match ":hook_name", to: 'incoming/hooks#handle_hook', via: %i(get post) end - scope "admin" do + scope 'admin' do scope :settings do resources :webhooks, param: :webhook_id, - controller: "webhooks/outgoing/admin", - as: "admin_outgoing_webhooks" + controller: 'webhooks/outgoing/admin', + as: 'admin_outgoing_webhooks' end end end diff --git a/modules/webhooks/lib/open_project/webhooks/engine.rb b/modules/webhooks/lib/open_project/webhooks/engine.rb index 4b65c8343fa1..5bd5cd54914d 100644 --- a/modules/webhooks/lib/open_project/webhooks/engine.rb +++ b/modules/webhooks/lib/open_project/webhooks/engine.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/plugins" +require 'open_project/plugins' module OpenProject::Webhooks class Engine < ::Rails::Engine @@ -34,30 +34,23 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-webhooks", + register 'openproject-webhooks', bundled: true, - author_url: "https://www.openproject.org" do + author_url: 'https://www.openproject.org' do menu :admin_menu, :plugin_webhooks, - { controller: "webhooks/outgoing/admin", action: :index }, + { controller: 'webhooks/outgoing/admin', action: :index }, if: Proc.new { User.current.admin? }, parent: :api_and_webhooks, - caption: :"webhooks.plural" + caption: :'webhooks.plural' end - initializer "webhooks.subscribe_to_notifications" do |app| + initializer 'webhooks.subscribe_to_notifications' do |app| app.config.after_initialize do ::OpenProject::Webhooks::EventResources.subscribe! end end - add_cron_jobs do - { - CleanupWebhookLogsJob: { - cron: "28 5 * * 7", # runs at 5:28 on Sunday - class: ::CleanupWebhookLogsJob.name - } - } - end + add_cron_jobs { CleanupWebhookLogsJob } end end diff --git a/modules/webhooks/lib/open_project/webhooks/event_resources/attachment.rb b/modules/webhooks/lib/open_project/webhooks/event_resources/attachment.rb index 2d2f21ffd1a9..cde2ea91e38e 100644 --- a/modules/webhooks/lib/open_project/webhooks/event_resources/attachment.rb +++ b/modules/webhooks/lib/open_project/webhooks/event_resources/attachment.rb @@ -1,4 +1,4 @@ -require_relative "base" +require_relative 'base' module OpenProject::Webhooks::EventResources class Attachment < Base @@ -14,13 +14,13 @@ def available_actions end def resource_name - I18n.t :"attributes.attachments" + I18n.t :'attributes.attachments' end protected def handle_notification(payload, event_name) - action = event_name.split("_").last + action = event_name.split('_').last event_name = prefixed_event_name(action) active_webhooks.with_event_name(event_name).pluck(:id).each do |id| diff --git a/modules/webhooks/lib/open_project/webhooks/event_resources/base.rb b/modules/webhooks/lib/open_project/webhooks/event_resources/base.rb index 501c2a1f29c4..172cfaf1f211 100644 --- a/modules/webhooks/lib/open_project/webhooks/event_resources/base.rb +++ b/modules/webhooks/lib/open_project/webhooks/event_resources/base.rb @@ -40,7 +40,7 @@ def available_actions ## # Localize the given event name def localize_event_name(key) - I18n.t(key, scope: "webhooks.outgoing.events") + I18n.t(key, scope: 'webhooks.outgoing.events') end ## diff --git a/modules/webhooks/lib/open_project/webhooks/event_resources/project.rb b/modules/webhooks/lib/open_project/webhooks/event_resources/project.rb index 93d67692550d..5b357acf2b8b 100644 --- a/modules/webhooks/lib/open_project/webhooks/event_resources/project.rb +++ b/modules/webhooks/lib/open_project/webhooks/event_resources/project.rb @@ -1,4 +1,4 @@ -require_relative "base" +require_relative 'base' module OpenProject::Webhooks::EventResources class Project < Base @@ -21,7 +21,7 @@ def resource_name protected def handle_notification(payload, event_name) - action = event_name.split("_").last + action = event_name.split('_').last event_name = prefixed_event_name(action) active_webhooks.with_event_name(event_name).pluck(:id).each do |id| diff --git a/modules/webhooks/lib/open_project/webhooks/event_resources/time_entry.rb b/modules/webhooks/lib/open_project/webhooks/event_resources/time_entry.rb index 5c0bc713241a..1f9b4ae63230 100644 --- a/modules/webhooks/lib/open_project/webhooks/event_resources/time_entry.rb +++ b/modules/webhooks/lib/open_project/webhooks/event_resources/time_entry.rb @@ -1,4 +1,4 @@ -require_relative "base" +require_relative 'base' module OpenProject::Webhooks::EventResources class TimeEntry < Base @@ -14,7 +14,7 @@ def available_actions end def resource_name - I18n.t "webhooks.resources.time_entry.name" + I18n.t 'webhooks.resources.time_entry.name' end protected diff --git a/modules/webhooks/lib/open_project/webhooks/event_resources/work_package.rb b/modules/webhooks/lib/open_project/webhooks/event_resources/work_package.rb index 41e380c1007d..3e9100f770c3 100644 --- a/modules/webhooks/lib/open_project/webhooks/event_resources/work_package.rb +++ b/modules/webhooks/lib/open_project/webhooks/event_resources/work_package.rb @@ -1,4 +1,4 @@ -require_relative "base" +require_relative 'base' module OpenProject::Webhooks::EventResources class WorkPackage < Base diff --git a/modules/webhooks/lib/openproject-webhooks.rb b/modules/webhooks/lib/openproject-webhooks.rb index 0d1b5c7c464c..d804ed38fafb 100644 --- a/modules/webhooks/lib/openproject-webhooks.rb +++ b/modules/webhooks/lib/openproject-webhooks.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "open_project/webhooks" +require 'open_project/webhooks' diff --git a/modules/webhooks/openproject-webhooks.gemspec b/modules/webhooks/openproject-webhooks.gemspec index 2e5272dc381b..ebe5a382904c 100644 --- a/modules/webhooks/openproject-webhooks.gemspec +++ b/modules/webhooks/openproject-webhooks.gemspec @@ -1,13 +1,13 @@ Gem::Specification.new do |s| s.name = "openproject-webhooks" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" s.homepage = "https://github.com/opf/openproject-webhooks" - s.summary = "OpenProject Webhooks" - s.description = "Provides a plug-in API to support OpenProject webhooks for better 3rd party integration" - s.license = "GPLv3" + s.summary = 'OpenProject Webhooks' + s.description = 'Provides a plug-in API to support OpenProject webhooks for better 3rd party integration' + s.license = 'GPLv3' s.files = Dir["{app,config,db,doc,lib}/**/*"] + %w(README.md) - s.metadata["rubygems_mfa_required"] = "true" + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/webhooks/spec/components/webhooks/outgoing/deliveries/table_component_spec.rb b/modules/webhooks/spec/components/webhooks/outgoing/deliveries/table_component_spec.rb index 920d70b4e1cd..d463d231b712 100644 --- a/modules/webhooks/spec/components/webhooks/outgoing/deliveries/table_component_spec.rb +++ b/modules/webhooks/spec/components/webhooks/outgoing/deliveries/table_component_spec.rb @@ -25,25 +25,25 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Webhooks::Outgoing::Deliveries::TableComponent, type: :component do - it "escapes response body html" do - delivery = create(:webhook_log, response_body: "Hello world!") + it 'escapes response body html' do + delivery = create(:webhook_log, response_body: 'Hello world!') render_inline described_class.new(rows: [delivery]) expect(page).to have_css("pre.webhooks--response-body", text: delivery.response_body) end - it "escapes response headers html" do + it 'escapes response headers html' do header_name = "x_header_evil_name" header_value = "header evil value" delivery = create(:webhook_log, response_headers: { header_name => header_value }) render_inline described_class.new(rows: [delivery]) - response_headers_node = page.find("pre.webhooks--response-headers") + response_headers_node = page.find('pre.webhooks--response-headers') aggregate_failures do - expect(response_headers_node).to have_no_css("b", text: "evil") + expect(response_headers_node).to have_no_css('b', text: 'evil') expect(response_headers_node.text).to include(header_name) expect(response_headers_node.text).to include(header_value) end diff --git a/modules/webhooks/spec/controllers/outgoing/admin_controller_spec.rb b/modules/webhooks/spec/controllers/outgoing/admin_controller_spec.rb index 449c04b3c769..fd8b011a9655 100644 --- a/modules/webhooks/spec/controllers/outgoing/admin_controller_spec.rb +++ b/modules/webhooks/spec/controllers/outgoing/admin_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Webhooks::Outgoing::AdminController do let(:user) { build_stubbed(:admin) } @@ -35,58 +35,58 @@ login_as user end - context "when not admin" do + context 'when not admin' do let(:user) { build_stubbed(:user) } - it "renders 403" do + it 'renders 403' do get :index expect(response.status).to eq 403 end end - context "when not logged in" do + context 'when not logged in' do let(:user) { User.anonymous } - it "renders 403" do + it 'renders 403' do get :index expect(response.status).to redirect_to(signin_url(back_url: admin_outgoing_webhooks_url)) end end - describe "#index" do - it "renders the index page" do + describe '#index' do + it 'renders the index page' do get :index expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end end - describe "#new" do - it "renders the new page" do + describe '#new' do + it 'renders the new page' do get :new expect(response).to be_successful expect(assigns[:webhook]).to be_new_record - expect(response).to render_template "new" + expect(response).to render_template 'new' end end - describe "#create" do + describe '#create' do let(:service) { double(Webhooks::Outgoing::UpdateWebhookService) } let(:webhook_params) do { - name: "foo", + name: 'foo', enabled: true } end - describe "with invalid params" do - it "renders an error" do - post :create, params: { foo: "bar" } + describe 'with invalid params' do + it 'renders an error' do + post :create, params: { foo: 'bar' } expect(response).not_to be_successful end end - describe "Calling the service" do + describe 'Calling the service' do before do expect(Webhooks::Outgoing::UpdateWebhookService) .to receive(:new) @@ -99,69 +99,69 @@ post :create, params: { webhook: webhook_params } end - context "when success" do + context 'when success' do let(:success) { true } - it "renders success" do + it 'renders success' do expect(flash[:notice]).to be_present expect(response).to redirect_to(action: :index) end end - context "when not success" do + context 'when not success' do let(:success) { false } - it "renders the form again" do + it 'renders the form again' do expect(flash[:notice]).not_to be_present - expect(response).to render_template "new" + expect(response).to render_template 'new' end end end end - describe "#edit" do - context "when found" do + describe '#edit' do + context 'when found' do before do expect(Webhooks::Webhook) .to receive(:find) .and_return(double(Webhooks::Webhook)) end - it "renders the edit page" do - get :edit, params: { webhook_id: "mocked" } + it 'renders the edit page' do + get :edit, params: { webhook_id: 'mocked' } expect(response).to be_successful expect(assigns[:webhook]).to be_present - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end end - context "when not found" do - it "renders 404" do - get :edit, params: { webhook_id: "1234" } + context 'when not found' do + it 'renders 404' do + get :edit, params: { webhook_id: '1234' } expect(response).not_to be_successful expect(response.status).to eq 404 end end end - describe "#update" do + describe '#update' do let(:service) { double(Webhooks::Outgoing::UpdateWebhookService) } let(:webhook_params) do { - name: "foo", + name: 'foo', enabled: true } end - describe "when not found" do - it "renders an error" do - put :update, params: { webhook_id: "bar" } + describe 'when not found' do + it 'renders an error' do + put :update, params: { webhook_id: 'bar' } expect(response).not_to be_successful expect(response.status).to eq 404 end end - describe "Calling the service" do + describe 'Calling the service' do let(:webhook) { double(Webhooks::Webhook) } before do @@ -177,33 +177,33 @@ .to receive(:call) .and_return(ServiceResult.new(success:)) - put :update, params: { webhook_id: "1234", webhook: webhook_params } + put :update, params: { webhook_id: '1234', webhook: webhook_params } end - context "when success" do + context 'when success' do let(:success) { true } - it "renders success" do + it 'renders success' do expect(flash[:notice]).to be_present expect(response).to redirect_to(action: :index) end end - context "when not success" do + context 'when not success' do let(:success) { false } - it "renders the form again" do + it 'renders the form again' do expect(flash[:notice]).not_to be_present - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end end end end - describe "#destroy" do + describe '#destroy' do let(:webhook) { double(Webhooks::Webhook) } - context "when found" do + context 'when found' do before do expect(Webhooks::Webhook) .to receive(:find) @@ -214,22 +214,22 @@ .and_return(success) end - context "when delete failed" do + context 'when delete failed' do let(:success) { false } - it "redirects to index" do - delete :destroy, params: { webhook_id: "mocked" } + it 'redirects to index' do + delete :destroy, params: { webhook_id: 'mocked' } expect(response).to be_redirect expect(flash[:notice]).not_to be_present expect(flash[:error]).to be_present end end - context "when delete success" do + context 'when delete success' do let(:success) { true } - it "destroys the object" do - delete :destroy, params: { webhook_id: "mocked" } + it 'destroys the object' do + delete :destroy, params: { webhook_id: 'mocked' } expect(response).to be_redirect expect(flash[:notice]).to be_present end diff --git a/modules/webhooks/spec/controllers/webhooks_controller_spec.rb b/modules/webhooks/spec/controllers/webhooks_controller_spec.rb index 0f802cc9f582..5fcb518ba248 100644 --- a/modules/webhooks/spec/controllers/webhooks_controller_spec.rb +++ b/modules/webhooks/spec/controllers/webhooks_controller_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../spec_helper", __dir__) +require File.expand_path('../spec_helper', __dir__) RSpec.describe Webhooks::Incoming::HooksController do let(:hook) { double(OpenProject::Webhooks::Hook) } let(:user) { double(User).as_null_object } - describe "#handle_hook" do + describe '#handle_hook' do before do - expect(OpenProject::Webhooks).to receive(:find).with("testhook").and_return(hook) + expect(OpenProject::Webhooks).to receive(:find).with('testhook').and_return(hook) allow(controller).to receive(:find_current_user).and_return(user) end @@ -43,20 +43,20 @@ User.current = nil end - it "is successful" do + it 'is successful' do expect(hook).to receive(:handle) - post :handle_hook, params: { hook_name: "testhook" } + post :handle_hook, params: { hook_name: 'testhook' } expect(response).to be_successful end - it "calls the hook with a user" do + it 'calls the hook with a user' do expect(hook).to receive(:handle) { |_env, _params, user| expect(user).to equal(user) } - post :handle_hook, params: { hook_name: "testhook" } + post :handle_hook, params: { hook_name: 'testhook' } end end end diff --git a/modules/webhooks/spec/factories/webhook_factory.rb b/modules/webhooks/spec/factories/webhook_factory.rb index 190584c69fde..ee1484c3c016 100644 --- a/modules/webhooks/spec/factories/webhook_factory.rb +++ b/modules/webhooks/spec/factories/webhook_factory.rb @@ -27,7 +27,7 @@ #++ FactoryBot.define do - factory :webhook, class: "Webhooks::Webhook" do + factory :webhook, class: 'Webhooks::Webhook' do name { "Example Webhook" } url { "http://example.net/webhook_receiver/42" } description { "This is an example webhook" } diff --git a/modules/webhooks/spec/factories/webhook_log_factory.rb b/modules/webhooks/spec/factories/webhook_log_factory.rb index 7d3f7e10b676..00cda0310a63 100644 --- a/modules/webhooks/spec/factories/webhook_log_factory.rb +++ b/modules/webhooks/spec/factories/webhook_log_factory.rb @@ -27,14 +27,14 @@ #++ FactoryBot.define do - factory :webhook_log, class: "Webhooks::Log" do + factory :webhook_log, class: 'Webhooks::Log' do webhook factory: :webhook url { "http://example.net/webhook_receiver/42" } - event_name { "foobar" } - response_code { "200" } + event_name { 'foobar' } + response_code { '200' } request_headers { { foo: :bar } } - request_body { "Request body" } + request_body { 'Request body' } response_headers { { response: :foo } } - response_body { "Response body" } + response_body { 'Response body' } end end diff --git a/modules/webhooks/spec/features/manage_webhooks_spec.rb b/modules/webhooks/spec/features/manage_webhooks_spec.rb index dad6fbf95bfc..4fe0679c5b5f 100644 --- a/modules/webhooks/spec/features/manage_webhooks_spec.rb +++ b/modules/webhooks/spec/features/manage_webhooks_spec.rb @@ -1,55 +1,55 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Manage webhooks through UI", :js do +RSpec.describe 'Manage webhooks through UI', :js do before do login_as user end - context "as regular user" do + context 'as regular user' do let(:user) { create(:user) } - it "forbids accessing the webhooks management view" do + it 'forbids accessing the webhooks management view' do visit admin_outgoing_webhooks_path - expect(page).to have_text "[Error 403]" + expect(page).to have_text '[Error 403]' end end - context "as admin" do + context 'as admin' do let(:user) { create(:admin) } let!(:project) { create(:project) } - it "allows the management flow" do + it 'allows the management flow' do visit admin_outgoing_webhooks_path - expect(page).to have_css(".generic-table--empty-row") + expect(page).to have_css('.generic-table--empty-row') # Visit inline create - find(".wp-inline-create--add-link").click + find('.wp-inline-create--add-link').click SeleniumHubWaiter.wait # Fill in elements - fill_in "webhook_name", with: "My webhook" - fill_in "webhook_url", with: "http://example.org" + fill_in 'webhook_name', with: 'My webhook' + fill_in 'webhook_url', with: 'http://example.org' # Check one event find('.form--check-box[value="work_package:created"]').set true # Create - click_on "Create" + click_on 'Create' # # 1st webhook created # - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_create)) - expect(page).to have_css(".webhooks--outgoing-webhook-row .name", text: "My webhook") + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_successful_create)) + expect(page).to have_css('.webhooks--outgoing-webhook-row .name', text: 'My webhook') webhook = Webhooks::Webhook.last expect(webhook.event_names).to eq %w(work_package:created) expect(webhook.all_projects).to be_truthy - expect(page).to have_css(".webhooks--outgoing-webhook-row .enabled .icon-yes") - expect(page).to have_css(".webhooks--outgoing-webhook-row .selected_projects", text: "(all)") - expect(page).to have_css(".webhooks--outgoing-webhook-row .events", text: "Work packages") - expect(page).to have_css(".webhooks--outgoing-webhook-row .description", text: webhook.description) + expect(page).to have_css('.webhooks--outgoing-webhook-row .enabled .icon-yes') + expect(page).to have_css('.webhooks--outgoing-webhook-row .selected_projects', text: '(all)') + expect(page).to have_css('.webhooks--outgoing-webhook-row .events', text: 'Work packages') + expect(page).to have_css('.webhooks--outgoing-webhook-row .description', text: webhook.description) SeleniumHubWaiter.wait # Edit this webhook @@ -61,12 +61,12 @@ find('.form--check-box[value="work_package:updated"]').set true # Check a subset of projects - choose "webhook_project_ids_selection" + choose 'webhook_project_ids_selection' find(".webhooks--selected-project-ids[value='#{project.id}']").set true - click_on "Save" - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update)) - expect(page).to have_css(".webhooks--outgoing-webhook-row .name", text: "My webhook") + click_on 'Save' + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_successful_update)) + expect(page).to have_css('.webhooks--outgoing-webhook-row .name', text: 'My webhook') webhook = Webhooks::Webhook.last expect(webhook.event_names).to eq %w(work_package:updated) expect(webhook.projects.all).to eq [project] @@ -77,54 +77,54 @@ find(".webhooks--outgoing-webhook-row-#{webhook.id} .icon-delete").click page.driver.browser.switch_to.alert.accept - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_delete)) - expect(page).to have_css(".generic-table--empty-row") + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_successful_delete)) + expect(page).to have_css('.generic-table--empty-row') end - context "with existing webhook" do - let!(:webhook) { create(:webhook, name: "testing") } + context 'with existing webhook' do + let!(:webhook) { create(:webhook, name: 'testing') } let!(:log) { create(:webhook_log, response_headers: { test: :foo }, webhook:) } - it "shows the delivery" do + it 'shows the delivery' do visit admin_outgoing_webhooks_path SeleniumHubWaiter.wait - find(".webhooks--outgoing-webhook-row .name a", text: "testing").click + find('.webhooks--outgoing-webhook-row .name a', text: 'testing').click - expect(page).to have_css(".on-off-status.-enabled") - expect(page).to have_css("td.event_name", text: "foo") - expect(page).to have_css("td.response_code", text: "200") + expect(page).to have_css('.on-off-status.-enabled') + expect(page).to have_css('td.event_name', text: 'foo') + expect(page).to have_css('td.response_code', text: '200') # Open modal SeleniumHubWaiter.wait - find("td.response_body a", text: "Show").click + find('td.response_body a', text: 'Show').click - page.within(".spot-modal") do - expect(page).to have_css(".webhooks--response-headers strong", text: "test") - expect(page).to have_css(".webhooks--response-body", text: log.response_body) + page.within('.spot-modal') do + expect(page).to have_css('.webhooks--response-headers strong', text: 'test') + expect(page).to have_css('.webhooks--response-body', text: log.response_body) end end - context "with multiple logs" do - let!(:log2) { create(:webhook_log, response_body: "This is the second log", webhook:) } - let!(:log3) { create(:webhook_log, response_body: "This is the third log", webhook:) } + context 'with multiple logs' do + let!(:log2) { create(:webhook_log, response_body: 'This is the second log', webhook:) } + let!(:log3) { create(:webhook_log, response_body: 'This is the third log', webhook:) } - it "shows the response of the log being clicked" do + it 'shows the response of the log being clicked' do visit admin_outgoing_webhook_path(webhook) # Open modal SeleniumHubWaiter.wait - all("tbody tr").each do |row_element| + all('tbody tr').each do |row_element| matching_log = nil within(row_element) do - id = find("td.id").text.to_i + id = find('td.id').text.to_i matching_log = [log, log2, log3].find { |l| l.id == id } - find("td.response_body a", text: "Show").click + find('td.response_body a', text: 'Show').click end - page.within(".spot-modal") do - expect(page).to have_css(".webhooks--response-body", text: matching_log.response_body) - click_button("Close") + page.within('.spot-modal') do + expect(page).to have_css('.webhooks--response-body', text: matching_log.response_body) + click_button('Close') end end end diff --git a/modules/webhooks/spec/lib/hook_spec.rb b/modules/webhooks/spec/lib/hook_spec.rb index 4fed053dc768..84c789fe5822 100644 --- a/modules/webhooks/spec/lib/hook_spec.rb +++ b/modules/webhooks/spec/lib/hook_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../spec_helper", __dir__) +require File.expand_path('../spec_helper', __dir__) RSpec.describe OpenProject::Webhooks::Hook do - describe "#relative_url" do - let(:hook) { OpenProject::Webhooks::Hook.new("myhook") } + describe '#relative_url' do + let(:hook) { OpenProject::Webhooks::Hook.new('myhook') } it "returns the correct URL" do - expect(hook.relative_url).to eql("webhooks/myhook") + expect(hook.relative_url).to eql('webhooks/myhook') end end - describe "#handle" do + describe '#handle' do let(:probe) { lambda {} } - let(:hook) { OpenProject::Webhooks::Hook.new("myhook", &probe) } + let(:hook) { OpenProject::Webhooks::Hook.new('myhook', &probe) } before do expect(probe).to receive(:call).with(hook, 1, 2, 3) end - it "executes the callback with the correct parameters" do + it 'executes the callback with the correct parameters' do hook.handle(1, 2, 3) end end diff --git a/modules/webhooks/spec/lib/webhooks_spec.rb b/modules/webhooks/spec/lib/webhooks_spec.rb index 869ffeaa8b41..bbfeac19eb29 100644 --- a/modules/webhooks/spec/lib/webhooks_spec.rb +++ b/modules/webhooks/spec/lib/webhooks_spec.rb @@ -26,41 +26,41 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("../spec_helper", __dir__) +require File.expand_path('../spec_helper', __dir__) RSpec.describe OpenProject::Webhooks do - describe ".register_hook" do + describe '.register_hook' do after do - OpenProject::Webhooks.unregister_hook("testhook1") + OpenProject::Webhooks.unregister_hook('testhook1') end - it "succeeds" do - OpenProject::Webhooks.register_hook("testhook1") {} + it 'succeeds' do + OpenProject::Webhooks.register_hook('testhook1') {} end end - describe ".find" do - let!(:hook) { OpenProject::Webhooks.register_hook("testhook3") {} } + describe '.find' do + let!(:hook) { OpenProject::Webhooks.register_hook('testhook3') {} } after do - OpenProject::Webhooks.unregister_hook("testhook3") + OpenProject::Webhooks.unregister_hook('testhook3') end - it "succeeds" do - expect(OpenProject::Webhooks.find("testhook3")).to equal(hook) + it 'succeeds' do + expect(OpenProject::Webhooks.find('testhook3')).to equal(hook) end end - describe ".unregister_hook" do + describe '.unregister_hook' do let(:probe) { lambda {} } before do - OpenProject::Webhooks.register_hook("testhook2", &probe) + OpenProject::Webhooks.register_hook('testhook2', &probe) end - it "results in the hook no longer being found" do - OpenProject::Webhooks.unregister_hook("testhook2") - expect(OpenProject::Webhooks.find("testhook2")).to be_nil + it 'results in the hook no longer being found' do + OpenProject::Webhooks.unregister_hook('testhook2') + expect(OpenProject::Webhooks.find('testhook2')).to be_nil end end end diff --git a/modules/webhooks/spec/models/webhook_spec.rb b/modules/webhooks/spec/models/webhook_spec.rb index b85a87c574be..04e95c8f090f 100644 --- a/modules/webhooks/spec/models/webhook_spec.rb +++ b/modules/webhooks/spec/models/webhook_spec.rb @@ -1,29 +1,29 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Webhooks::Webhook do subject { build(:webhook) } - describe "attributes" do - describe "#url" do - it "accepts http" do - subject.url = "http://foo.example.org" + describe 'attributes' do + describe '#url' do + it 'accepts http' do + subject.url = 'http://foo.example.org' expect(subject).to be_valid end - it "accepts http" do - subject.url = "https://foo.example.org" + it 'accepts http' do + subject.url = 'https://foo.example.org' expect(subject).to be_valid end - it "accepts other schemas" do - subject.url = "ftp://foo.example.org" + it 'accepts other schemas' do + subject.url = 'ftp://foo.example.org' expect(subject).not_to be_valid expect(subject.errors).to have_key(:url) end end end - describe "#events" do + describe '#events' do let(:events) { %w(work_package:updated work_package:created) } before do @@ -31,18 +31,18 @@ subject.save! end - it "has an event association" do + it 'has an event association' do expect(subject.events.count).to eq 2 expect(subject.event_names).to eq events end - it "finds the webhook with the saved events" do + it 'finds the webhook with the saved events' do expect(described_class.with_event_name(events[0]).first).to eq(subject) expect(described_class.with_event_name(events[1]).first).to eq(subject) end end - describe "#projects" do + describe '#projects' do let(:project1) { create(:project) } before do @@ -51,7 +51,7 @@ subject.save! end - it "has an event association" do + it 'has an event association' do expect(subject.projects.count).to eq 1 expect(subject.project_ids).to eq([project1.id]) diff --git a/modules/webhooks/spec/routing/webhooks/outgoing/admin_controller_spec.rb b/modules/webhooks/spec/routing/webhooks/outgoing/admin_controller_spec.rb index 4beaefcdc52c..ea5a64fe84bd 100644 --- a/modules/webhooks/spec/routing/webhooks/outgoing/admin_controller_spec.rb +++ b/modules/webhooks/spec/routing/webhooks/outgoing/admin_controller_spec.rb @@ -26,38 +26,38 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Outgoing webhooks administration" do - it "route to index" do - expect(get("/admin/settings/webhooks")).to route_to("webhooks/outgoing/admin#index") +RSpec.describe 'Outgoing webhooks administration' do + it 'route to index' do + expect(get('/admin/settings/webhooks')).to route_to('webhooks/outgoing/admin#index') end - it "route to new" do - expect(get("/admin/settings/webhooks/new")).to route_to("webhooks/outgoing/admin#new") + it 'route to new' do + expect(get('/admin/settings/webhooks/new')).to route_to('webhooks/outgoing/admin#new') end - it "route to show" do - expect(get("/admin/settings/webhooks/1")).to route_to(controller: "webhooks/outgoing/admin", - action: "show", - webhook_id: "1") + it 'route to show' do + expect(get('/admin/settings/webhooks/1')).to route_to(controller: 'webhooks/outgoing/admin', + action: 'show', + webhook_id: '1') end - it "route to edit" do - expect(get("/admin/settings/webhooks/1/edit")).to route_to(controller: "webhooks/outgoing/admin", - action: "edit", - webhook_id: "1") + it 'route to edit' do + expect(get('/admin/settings/webhooks/1/edit')).to route_to(controller: 'webhooks/outgoing/admin', + action: 'edit', + webhook_id: '1') end - it "route to PUT update" do - expect(put("/admin/settings/webhooks/1")).to route_to(controller: "webhooks/outgoing/admin", - action: "update", - webhook_id: "1") + it 'route to PUT update' do + expect(put('/admin/settings/webhooks/1')).to route_to(controller: 'webhooks/outgoing/admin', + action: 'update', + webhook_id: '1') end - it "route to DELETE destroy" do - expect(delete("/admin/settings/webhooks/1")).to route_to(controller: "webhooks/outgoing/admin", - action: "destroy", - webhook_id: "1") + it 'route to DELETE destroy' do + expect(delete('/admin/settings/webhooks/1')).to route_to(controller: 'webhooks/outgoing/admin', + action: 'destroy', + webhook_id: '1') end end diff --git a/modules/webhooks/spec/spec_helper.rb b/modules/webhooks/spec/spec_helper.rb index e9b86f472dd9..5974eaa856cf 100644 --- a/modules/webhooks/spec/spec_helper.rb +++ b/modules/webhooks/spec/spec_helper.rb @@ -26,4 +26,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' diff --git a/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb b/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb index dcf1a38ef0b4..5ab63be0d1b8 100644 --- a/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/attachment_webhook_job_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AttachmentWebhookJob, :webmock, type: :job do shared_let(:user) { create(:admin) } shared_let(:request_url) { "http://example.net/test/42" } - shared_let(:project) { create(:project, name: "Foo Bar") } + shared_let(:project) { create(:project, name: 'Foo Bar') } shared_let(:container) { create(:work_package, project:) } shared_let(:attachment) { create(:attachment, container:) } shared_let(:webhook) { create(:webhook, all_projects: true, url: request_url, secret: nil) } @@ -56,7 +56,7 @@ "action" => event, "attachment" => hash_including( "_type" => "Attachment", - "id" => attachment.id + 'id' => attachment.id ) ), headers: request_headers @@ -82,7 +82,7 @@ end describe "attachment webhook call" do - it "requests with all projects" do + it 'requests with all projects' do allow(webhook) .to receive(:enabled_for_project?).with(project.id) .and_call_original @@ -91,7 +91,7 @@ expect(stub).to have_been_requested end - it "does not request when project does not match unless create case" do + it 'does not request when project does not match unless create case' do allow(webhook) .to receive(:enabled_for_project?).with(project.id) .and_return(false) @@ -100,10 +100,10 @@ expect(stub).not_to have_been_requested end - context "with uncontainered" do + context 'with uncontainered' do shared_let(:attachment) { create(:attachment, container: nil) } - it "does requests even if project nil" do + it 'does requests even if project nil' do allow(webhook) .to receive(:enabled_for_project?).with(project.id) .and_return(false) @@ -113,7 +113,7 @@ end end - describe "successful flow" do + describe 'successful flow' do before do subject end diff --git a/modules/webhooks/spec/workers/project_webhook_job_spec.rb b/modules/webhooks/spec/workers/project_webhook_job_spec.rb index 02be1c5e54d6..1b1c8eada27c 100644 --- a/modules/webhooks/spec/workers/project_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/project_webhook_job_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ProjectWebhookJob, :webmock, type: :job do shared_let(:user) { create(:admin) } shared_let(:request_url) { "http://example.net/test/42" } - shared_let(:project) { create(:project, name: "Foo Bar") } + shared_let(:project) { create(:project, name: 'Foo Bar') } shared_let(:webhook) { create(:webhook, all_projects: true, url: request_url, secret: nil) } shared_examples "a project webhook call" do @@ -57,7 +57,7 @@ "action" => event, "project" => hash_including( "_type" => "Project", - "name" => "Foo Bar" + "name" => 'Foo Bar' ) ), headers: request_headers @@ -82,7 +82,7 @@ stub end - it "requests with all projects" do + it 'requests with all projects' do allow(webhook) .to receive(:enabled_for_project?).with(project.id) .and_call_original @@ -91,20 +91,20 @@ expect(stub).to have_been_requested end - it "does not request when project does not match unless create case" do + it 'does not request when project does not match unless create case' do allow(webhook) .to receive(:enabled_for_project?).with(project.id) .and_return(false) subject - if event == "project:created" + if event == 'project:created' expect(stub).to have_been_requested else expect(stub).not_to have_been_requested end end - describe "successful flow" do + describe 'successful flow' do before do subject end diff --git a/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb b/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb index f6ac9eb0be60..6f82a98e39af 100644 --- a/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/time_entry_webhook_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TimeEntryWebhookJob, :webmock, type: :job do shared_let(:user) { create(:admin) } @@ -57,7 +57,7 @@ "action" => event, "time_entry" => hash_including( "_type" => "TimeEntry", - "hours" => "PT10H" + "hours" => 'PT10H' ) ), headers: request_headers @@ -82,7 +82,7 @@ stub end - it "requests with all projects" do + it 'requests with all projects' do expect(webhook) .to receive(:enabled_for_project?).with(time_entry.project_id) .and_call_original @@ -91,7 +91,7 @@ expect(stub).to have_been_requested end - it "does not request when project does not match" do + it 'does not request when project does not match' do expect(webhook) .to receive(:enabled_for_project?).with(time_entry.project_id) .and_return(false) @@ -100,7 +100,7 @@ expect(stub).not_to have_been_requested end - describe "successful flow" do + describe 'successful flow' do before do subject end diff --git a/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb b/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb index 39856faa9953..260bd650950c 100644 --- a/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb +++ b/modules/webhooks/spec/workers/work_package_webhook_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackageWebhookJob, :webmock, type: :model do shared_let(:user) { create(:admin) } @@ -78,7 +78,7 @@ stub end - it "requests with all projects" do + it 'requests with all projects' do expect(webhook) .to receive(:enabled_for_project?).with(work_package.project_id) .and_call_original @@ -87,7 +87,7 @@ expect(stub).to have_been_requested end - it "does not request when project does not match" do + it 'does not request when project does not match' do expect(webhook) .to receive(:enabled_for_project?).with(work_package.project_id) .and_return(false) @@ -96,7 +96,7 @@ expect(stub).not_to have_been_requested end - describe "successful flow" do + describe 'successful flow' do before do subject end diff --git a/modules/xls_export/app/models/xls_export/concerns/spreadsheet_builder.rb b/modules/xls_export/app/models/xls_export/concerns/spreadsheet_builder.rb index 60780f76ddb1..10db849c3e4a 100644 --- a/modules/xls_export/app/models/xls_export/concerns/spreadsheet_builder.rb +++ b/modules/xls_export/app/models/xls_export/concerns/spreadsheet_builder.rb @@ -18,7 +18,7 @@ def success(content) .new format: :xls, content:, title: xls_export_filename, - mime_type: "application/vnd.ms-excel" + mime_type: 'application/vnd.ms-excel' end def spreadsheet diff --git a/modules/xls_export/app/models/xls_export/work_package/exporter/xls.rb b/modules/xls_export/app/models/xls_export/work_package/exporter/xls.rb index d9b4f9cf4463..abd2e9fb110b 100644 --- a/modules/xls_export/app/models/xls_export/work_package/exporter/xls.rb +++ b/modules/xls_export/app/models/xls_export/work_package/exporter/xls.rb @@ -140,9 +140,9 @@ def relation_type(work_package, other, relation) normalized = relation.relation_type_for(work_package) I18n.t("js.relation_labels.#{normalized}", default: normalized) elsif work_package.parent_id == other.id - I18n.t "xls_export.child_of" + I18n.t 'xls_export.child_of' elsif work_package.children.where(id: other.id).exists? - I18n.t "xls_export.parent_of" + I18n.t 'xls_export.parent_of' end end diff --git a/modules/xls_export/config/locales/crowdin/zh-CN.yml b/modules/xls_export/config/locales/crowdin/zh-CN.yml index 31c8d3cdd710..59230e603ecf 100644 --- a/modules/xls_export/config/locales/crowdin/zh-CN.yml +++ b/modules/xls_export/config/locales/crowdin/zh-CN.yml @@ -13,4 +13,4 @@ zh-CN: xls_with_relations: "带关系的 XLS" xls_export: child_of: 此项的子项 - parent_of: 此项的父项 + parent_of: 此项的父级 diff --git a/modules/xls_export/lib/open_project/xls_export/engine.rb b/modules/xls_export/lib/open_project/xls_export/engine.rb index 51c0405fc5b5..884d18c94076 100644 --- a/modules/xls_export/lib/open_project/xls_export/engine.rb +++ b/modules/xls_export/lib/open_project/xls_export/engine.rb @@ -4,23 +4,23 @@ class Engine < ::Rails::Engine include OpenProject::Plugins::ActsAsOpEngine - register "openproject-xls_export", - author_url: "https://www.openproject.org", + register 'openproject-xls_export', + author_url: 'https://www.openproject.org', bundled: true config.to_prepare do OpenProject::XlsExport::Hooks::WorkPackageHook end - initializer "xls_export.register_mimetypes" do + initializer 'xls_export.register_mimetypes' do next if defined? Mime::XLS - Mime::Type.register("application/vnd.ms-excel", + Mime::Type.register('application/vnd.ms-excel', :xls, %w(application/vnd.ms-excel)) end - class_inflection_override("xls" => "XLS") + class_inflection_override('xls' => 'XLS') config.to_prepare do ::Exports::Register.register do diff --git a/modules/xls_export/lib/open_project/xls_export/spreadsheet_builder.rb b/modules/xls_export/lib/open_project/xls_export/spreadsheet_builder.rb index ddf0e0c5b337..1247efb187a4 100644 --- a/modules/xls_export/lib/open_project/xls_export/spreadsheet_builder.rb +++ b/modules/xls_export/lib/open_project/xls_export/spreadsheet_builder.rb @@ -1,4 +1,4 @@ -require "spreadsheet" +require 'spreadsheet' # A simple convenience class that wraps some of the spreadsheet # gem's functionality. It's designed to build spreadsheets incrementally @@ -17,7 +17,7 @@ class SpreadsheetBuilder Worksheet = Struct.new(:sheet, :column_widths) unless defined? Worksheet def initialize(name = nil) - Spreadsheet.client_encoding = "UTF-8" + Spreadsheet.client_encoding = 'UTF-8' @xls = Spreadsheet::Workbook.new @worksheets = [] worksheet(0, name) @@ -53,7 +53,7 @@ def update_sheet_widths # Get the approximate width of a value as seen in the excel sheet def get_value_width(value) - if ["Time", "Date"].include?(value.class.name) && !(value.to_s.length < 18) + if ['Time', 'Date'].include?(value.class.name) && !(value.to_s.length < 18) return 18 end @@ -61,11 +61,11 @@ def get_value_width(value) idx = 0 value.to_s.each_char do |c| case c - when "0".."9" + when '0'..'9' tot_w[idx] += 1.2 - when ".", ";", ":", ",", " ", "i", "I", "j", "J", "(", ")", "[", "]", "!", "-", "t", "l" + when '.', ';', ':', ',', ' ', 'i', 'I', 'j', 'J', '(', ')', '[', ']', '!', '-', 't', 'l' tot_w[idx] += 0.7 - when "W", "M", "D" + when 'W', 'M', 'D' tot_w[idx] += 1.2 when "\n" idx = idx + 1 @@ -215,11 +215,11 @@ def raw_sheet end def currency_sign - Setting.plugin_costs["costs_currency"] + Setting.plugin_costs['costs_currency'] end def escaped_worksheet_name(name) - name.gsub!(/[\/\\*\[\]:?]/, "#") + name.gsub!(/[\/\\*\[\]:?]/, '#') name = name[0, [name.length, 27].min] + "..." if name.length > 31 name diff --git a/modules/xls_export/lib/open_project/xls_export/xls_views.rb b/modules/xls_export/lib/open_project/xls_export/xls_views.rb index e2f597647d5f..d4aac6ff4208 100644 --- a/modules/xls_export/lib/open_project/xls_export/xls_views.rb +++ b/modules/xls_export/lib/open_project/xls_export/xls_views.rb @@ -12,7 +12,7 @@ def field_representation_map(key, value) case key.to_sym when :units then value.to_i when :spent_on then value - when :activity_id then mapped value, Enumeration, I18n.t("placeholders.default") + when :activity_id then mapped value, Enumeration, I18n.t('placeholders.default') when :project_id then project_representation(value) when :user_id, :assigned_to_id then user_representation(value) when :work_package_id then work_package_representation(value) @@ -32,7 +32,7 @@ def show_result(row, unit_id = @unit_id, as_text = false) def cost_type_unit_label(cost_type_id, cost_type_inst = nil, plural = true) case cost_type_id when -1 then l_hours(2).split[1..-1].join(" ") # get the plural for hours - when 0 then Setting.plugin_costs["costs_currency"] + when 0 then Setting.plugin_costs['costs_currency'] else cost_type_label(cost_type_id, cost_type_inst, plural) end end diff --git a/modules/xls_export/lib/openproject-xls_export.rb b/modules/xls_export/lib/openproject-xls_export.rb index 8f27e50d500c..912133ee042c 100644 --- a/modules/xls_export/lib/openproject-xls_export.rb +++ b/modules/xls_export/lib/openproject-xls_export.rb @@ -1 +1 @@ -require "open_project/xls_export" +require 'open_project/xls_export' diff --git a/modules/xls_export/openproject-xls_export.gemspec b/modules/xls_export/openproject-xls_export.gemspec index 524990abc299..bdd739ea5e0a 100644 --- a/modules/xls_export/openproject-xls_export.gemspec +++ b/modules/xls_export/openproject-xls_export.gemspec @@ -1,14 +1,14 @@ Gem::Specification.new do |s| s.name = "openproject-xls_export" - s.version = "1.0.0" + s.version = '1.0.0' s.authors = "OpenProject GmbH" s.email = "info@openproject.com" - s.summary = "OpenProject XLS Export" - s.description = "Export issue lists as Excel spreadsheets (.xls)" + s.summary = 'OpenProject XLS Export' + s.description = 'Export issue lists as Excel spreadsheets (.xls)' s.license = "GPLv3" s.files = Dir["{app,config,db,lib}/**/*"] + %w(CHANGELOG.md README.md) s.add_dependency "spreadsheet", "~>1.3.0" - s.metadata["rubygems_mfa_required"] = "true" + s.metadata['rubygems_mfa_required'] = 'true' end diff --git a/modules/xls_export/spec/lib/custom_field_xls_export_spec.rb b/modules/xls_export/spec/lib/custom_field_xls_export_spec.rb index 6254c91b8070..495f3da7b087 100644 --- a/modules/xls_export/spec/lib/custom_field_xls_export_spec.rb +++ b/modules/xls_export/spec/lib/custom_field_xls_export_spec.rb @@ -1,5 +1,5 @@ -require "spec_helper" -require "spreadsheet" +require 'spec_helper' +require 'spreadsheet' RSpec.describe "WorkPackageXlsExport Custom Fields" do let(:type) { create(:type) } @@ -19,7 +19,7 @@ let(:work_package1) do wp = create(:work_package, project:, type:) wp.custom_field_values = { - custom_field.id => custom_values_for("ham", "onions") + custom_field.id => custom_values_for('ham', 'onions') } wp.save wp @@ -28,7 +28,7 @@ let(:work_package2) do wp = create(:work_package, project:, type:) wp.custom_field_values = { - custom_field.id => custom_values_for("pineapple") + custom_field.id => custom_values_for('pineapple') } wp.save wp @@ -40,7 +40,7 @@ let!(:query) do query = build(:query, user: current_user, project:) - query.column_names = ["subject", custom_field.column_name] + query.column_names = ['subject', custom_field.column_name] query.sort_criteria = [%w[id asc]] query.save! @@ -66,9 +66,9 @@ def custom_values_for(*values) end end - it "produces the valid XLS result" do + it 'produces the valid XLS result' do expect(query.columns.map(&:name)).to eq [:subject, custom_field.column_name.to_sym] - expect(sheet.rows.first.take(2)).to eq ["Subject", "Ingredients"] + expect(sheet.rows.first.take(2)).to eq ['Subject', 'Ingredients'] # Subjects expect(sheet.row(1)[0]).to eq(work_package1.subject) @@ -76,8 +76,8 @@ def custom_values_for(*values) expect(sheet.row(3)[0]).to eq(work_package3.subject) # CF values - expect(sheet.row(1)[1]).to eq("ham, onions") - expect(sheet.row(2)[1]).to eq("pineapple") + expect(sheet.row(1)[1]).to eq('ham, onions') + expect(sheet.row(2)[1]).to eq('pineapple') expect(sheet.row(3)[1]).to be_nil end end diff --git a/modules/xls_export/spec/lib/spreadsheet_builder_spec.rb b/modules/xls_export/spec/lib/spreadsheet_builder_spec.rb index 4cad7059fa8c..fce9c2122b78 100644 --- a/modules/xls_export/spec/lib/spreadsheet_builder_spec.rb +++ b/modules/xls_export/spec/lib/spreadsheet_builder_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe "SpreadsheetBuilder" do before do diff --git a/modules/xls_export/spec/models/xls_export/work_package/exporter/xls_integration_spec.rb b/modules/xls_export/spec/models/xls_export/work_package/exporter/xls_integration_spec.rb index 97cdaa0659f9..912122cb4b83 100644 --- a/modules/xls_export/spec/models/xls_export/work_package/exporter/xls_integration_spec.rb +++ b/modules/xls_export/spec/models/xls_export/work_package/exporter/xls_integration_spec.rb @@ -1,5 +1,5 @@ -require "spec_helper" -require "spreadsheet" +require 'spec_helper' +require 'spreadsheet' RSpec.describe XlsExport::WorkPackage::Exporter::XLS do let(:project) { create(:project) } @@ -12,7 +12,7 @@ query.filters.clear query.column_names = column_names - query.sort_criteria = [["id", "asc"]] + query.sort_criteria = [['id', 'asc']] query end @@ -36,26 +36,26 @@ ) end - context "with relations" do + context 'with relations' do let(:options) { { show_relations: true } } - let(:parent) { create(:work_package, project:, subject: "Parent") } + let(:parent) { create(:work_package, project:, subject: 'Parent') } let(:child_1) do - create(:work_package, parent:, project:, subject: "Child 1") + create(:work_package, parent:, project:, subject: 'Child 1') end let(:child_2) do - create(:work_package, parent:, project:, subject: "Child 2") + create(:work_package, parent:, project:, subject: 'Child 2') end - let(:single) { create(:work_package, project:, subject: "Single") } - let(:followed) { create(:work_package, project:, subject: "Followed") } + let(:single) { create(:work_package, project:, subject: 'Single') } + let(:followed) { create(:work_package, project:, subject: 'Followed') } let(:child_2_child) do create(:work_package, parent: child_2, project:, subject: "Child 2's child") end let(:relation) do - create(:follows_relation, from: child_2, to: followed, description: "description foobar") + create(:follows_relation, from: child_2, to: followed, description: 'description foobar') end let(:relations) { [relation] } @@ -77,18 +77,18 @@ RELATION_DESCRIPTION = 10 RELATED_SUBJECT = 13 - it "produces the correct result" do + it 'produces the correct result' do expect(query.columns.map(&:name)).to eq %i[type id subject status assigned_to priority] # the first header row divides the sheet into work packages and relation columns - expect(sheet.rows.first.take(8)).to eq ["Work packages", nil, nil, nil, nil, nil, nil, "Relations"] + expect(sheet.rows.first.take(8)).to eq ['Work packages', nil, nil, nil, nil, nil, nil, 'Relations'] # the second header row includes the column names for work packages and relations and the related work package expect(sheet.rows[1]) .to eq [ - nil, "Type", "ID", "Subject", "Status", "Assignee", "Priority", - nil, "Relation type", "Delay", "Description", - "Type", "ID", "Subject", "Status", "Assignee", "Priority", + nil, 'Type', 'ID', 'Subject', 'Status', 'Assignee', 'Priority', + nil, 'Relation type', 'Delay', 'Description', + 'Type', 'ID', 'Subject', 'Status', 'Assignee', 'Priority', nil ] @@ -98,41 +98,41 @@ .to eq [parent.id, parent.id, child_1.id, c2id, c2id, c2id, single.id, followed.id, child_2_child.id].map(&:to_s) # marks Parent as parent of Child 1 and 2 - expect(sheet.row(PARENT)[RELATION]).to eq "parent of" - expect(sheet.row(PARENT)[RELATED_SUBJECT]).to eq "Child 1" + expect(sheet.row(PARENT)[RELATION]).to eq 'parent of' + expect(sheet.row(PARENT)[RELATED_SUBJECT]).to eq 'Child 1' - expect(sheet.row(PARENT + 1)[RELATION]).to eq "parent of" - expect(sheet.row(PARENT + 1)[RELATED_SUBJECT]).to eq "Child 2" + expect(sheet.row(PARENT + 1)[RELATION]).to eq 'parent of' + expect(sheet.row(PARENT + 1)[RELATED_SUBJECT]).to eq 'Child 2' # shows Child 1 as child of Parent - expect(sheet.row(CHILD_1)[RELATION]).to eq "child of" - expect(sheet.row(CHILD_1)[RELATED_SUBJECT]).to eq "Parent" + expect(sheet.row(CHILD_1)[RELATION]).to eq 'child of' + expect(sheet.row(CHILD_1)[RELATED_SUBJECT]).to eq 'Parent' # shows Child 2 as child of Parent - expect(sheet.row(CHILD_2)[RELATION]).to eq "child of" - expect(sheet.row(CHILD_2)[RELATED_SUBJECT]).to eq "Parent" + expect(sheet.row(CHILD_2)[RELATION]).to eq 'child of' + expect(sheet.row(CHILD_2)[RELATED_SUBJECT]).to eq 'Parent' # shows Child 2 as parent of Child 2's child - expect(sheet.row(CHILD_2 + 1)[RELATION]).to eq "parent of" + expect(sheet.row(CHILD_2 + 1)[RELATION]).to eq 'parent of' expect(sheet.row(CHILD_2 + 1)[RELATED_SUBJECT]).to eq "Child 2's child" # shows Child 2 as following Followed - expect(sheet.row(CHILD_2 + 2)[RELATION]).to eq "Follows" - expect(sheet.row(CHILD_2 + 2)[RELATED_SUBJECT]).to eq "Followed" + expect(sheet.row(CHILD_2 + 2)[RELATION]).to eq 'Follows' + expect(sheet.row(CHILD_2 + 2)[RELATED_SUBJECT]).to eq 'Followed' # shows no relation information for Single expect(sheet.row(SINGLE).drop(7).compact).to eq [] # shows Followed as preceding Child 2' - expect(sheet.row(FOLLOWED)[RELATION]).to eq "Precedes" - expect(sheet.row(FOLLOWED)[RELATION_DESCRIPTION]).to eq "description foobar" - expect(sheet.row(FOLLOWED)[RELATED_SUBJECT]).to eq "Child 2" + expect(sheet.row(FOLLOWED)[RELATION]).to eq 'Precedes' + expect(sheet.row(FOLLOWED)[RELATION_DESCRIPTION]).to eq 'description foobar' + expect(sheet.row(FOLLOWED)[RELATED_SUBJECT]).to eq 'Child 2' # exports the correct data (examples) expect(sheet.row(PARENT)) .to eq [ nil, parent.type.name, parent.id.to_s, parent.subject, parent.status.name, parent.assigned_to, parent.priority.name, - nil, "parent of", nil, nil, + nil, 'parent of', nil, nil, child_1.type.name, child_1.id.to_s, child_1.subject, child_1.status.name, child_1.assigned_to, child_1.priority.name ] # delay nil as this is a parent-child relation not represented by an actual Relation record @@ -145,28 +145,28 @@ .to eq [ nil, followed.type.name, followed.id.to_s, followed.subject, followed.status.name, followed.assigned_to, followed.priority.name, - nil, "Precedes", 0, relation.description, + nil, 'Precedes', 0, relation.description, child_2.type.name, child_2.id.to_s, child_2.subject, child_2.status.name, child_2.assigned_to, child_2.priority.name ] end - context "with someone who may not see related work packages" do + context 'with someone who may not see related work packages' do let(:current_user) { create(:user) } - it "exports no information without visibility" do + it 'exports no information without visibility' do expect(sheet.rows.length).to eq(2) expect(sheet.column(1).drop(2)).to be_empty end end end - describe "with cost and time entries" do + describe 'with cost and time entries' do # Since this test has to work without the actual costs plugin we'll just add # a custom field called 'costs' to emulate it. let(:custom_field) do create(:float_wp_custom_field, - name: "unit costs") + name: 'unit costs') end let(:custom_value) do create(:custom_value, @@ -195,15 +195,15 @@ wps[3].save! wps end - let(:column_names) { ["subject", "status", "estimated_hours", custom_field.column_name] } + let(:column_names) { ['subject', 'status', 'estimated_hours', custom_field.column_name] } before do allow(Setting) .to receive(:plugin_costs) - .and_return("costs_currency" => "EUR", "costs_currency_format" => "%n %u") + .and_return('costs_currency' => 'EUR', 'costs_currency_format' => '%n %u') end - it "successfullies export the work packages with a cost column" do + it 'successfullies export the work packages with a cost column' do expect(sheet.rows.size).to eq(4 + 1) cost_column = sheet.columns.last.to_a @@ -212,10 +212,10 @@ end end - context "with german locale" do + context 'with german locale' do let(:current_user) { create(:admin, language: :de) } - it "successfullies export the work packages with a cost column localized" do + it 'successfullies export the work packages with a cost column localized' do I18n.with_locale :de do sheet end @@ -228,7 +228,7 @@ end end - it "includes estimated hours" do + it 'includes estimated hours' do expect(sheet.rows.size).to eq(4 + 1) # Check row after header row @@ -237,7 +237,7 @@ end end - context "with descriptions" do + context 'with descriptions' do let(:options) { { show_descriptions: true } } let(:work_package) do @@ -249,7 +249,7 @@ let(:work_packages) { [work_package] } let(:column_names) { %w[id] } - it "includes the HTML sanitized description" do + it 'includes the HTML sanitized description' do expect(sheet.rows.size).to eq(1 + 1) expect(sheet.rows[1][1]) @@ -257,17 +257,17 @@ end end - context "with underscore in subject" do + context 'with underscore in subject' do let(:work_package) do create(:work_package, - subject: "underscore_is included", + subject: 'underscore_is included', project:, type: project.types.first) end let(:work_packages) { [work_package] } let(:column_names) { %w[id subject] } - it "includes the underscore" do + it 'includes the underscore' do expect(sheet.rows.size).to eq(1 + 1) expect(sheet.rows[1][1]) @@ -275,15 +275,15 @@ end end - describe "empty result" do + describe 'empty result' do let(:work_packages) { [] } - it "yields an empty XLS file" do + it 'yields an empty XLS file' do expect(sheet.rows.size).to eq(1) # just the headers end end - describe "with user time zone" do + describe 'with user time zone' do let(:zone) { +2 } let(:work_package) do create(:work_package, @@ -304,14 +304,14 @@ allow(current_user).to receive(:time_zone).and_return(zone) end - it "adapts the datetime fields to the user time zone" do + it 'adapts the datetime fields to the user time zone' do work_package.reload updated_at_cell = sheet.rows.last.to_a.last expect(updated_at_cell).to eq(i18n_helper.format_time(work_package.updated_at).to_s) end end - describe "with derived estimated hours" do + describe 'with derived estimated hours' do let(:work_package) do create(:work_package, project:, @@ -322,14 +322,14 @@ let(:column_names) { %w[subject status updated_at estimated_hours] } - it "adapts the datetime fields to the user time zone" do + it 'adapts the datetime fields to the user time zone' do work_package.reload estimated_cell = sheet.rows.last.to_a.last - expect(estimated_cell).to eq "(15.0 h)" + expect(estimated_cell).to eq '(15.0 h)' end end - describe "with derived estimated hours and estimated_hours set to zero" do + describe 'with derived estimated hours and estimated_hours set to zero' do let(:work_package) do create(:work_package, project:, @@ -341,10 +341,10 @@ let(:column_names) { %w[subject status updated_at estimated_hours] } - it "outputs both values" do + it 'outputs both values' do work_package.reload estimated_cell = sheet.rows.last.to_a.last - expect(estimated_cell).to eq "0.0 h (15.0 h)" + expect(estimated_cell).to eq '0.0 h (15.0 h)' end end end diff --git a/modules/xls_export/spec/patches/work_packages_controller_patch_spec.rb b/modules/xls_export/spec/patches/work_packages_controller_patch_spec.rb index 0b0c2b90270b..431a6667d3b2 100644 --- a/modules/xls_export/spec/patches/work_packages_controller_patch_spec.rb +++ b/modules/xls_export/spec/patches/work_packages_controller_patch_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackagesController, type: :controller do before do login_as current_user end - let(:project) { create(:project, identifier: "test_project", public: false) } - let(:stub_project) { build_stubbed(:project, identifier: "test_project", public: false) } + let(:project) { create(:project, identifier: 'test_project', public: false) } + let(:stub_project) { build_stubbed(:project, identifier: 'test_project', public: false) } let(:type) { build_stubbed(:type) } let(:stub_work_package) do build_stubbed(:work_package, @@ -72,7 +72,7 @@ def self.requires_export_permission(&) instance_eval(&) end - describe "w/o the export permission" do + describe 'w/o the export permission' do let(:project) { nil } before do @@ -81,16 +81,16 @@ def self.requires_export_permission(&) call_action end - it "renders a 403" do + it 'renders a 403' do expect(response.response_code).to eq(403) end end end - describe "index" do + describe 'index' do let(:query) { build_stubbed(:query).tap(&:add_default_filter) } - let(:work_packages) { double("work packages").as_null_object } - let(:results) { double("results").as_null_object } + let(:work_packages) { double('work packages').as_null_object } + let(:results) { double('results').as_null_object } before do mock_permissions_for(User.current) do |mock| @@ -98,20 +98,20 @@ def self.requires_export_permission(&) end end - describe "with valid query" do + describe 'with valid query' do before do allow(controller).to receive(:retrieve_query).and_return(query) end - describe "xls" do + describe 'xls' do let(:params) { {} } - let(:call_action) { get("index", params: params.merge(format: mime_type)) } - let(:mime_type) { "xls" } - let(:export_result) { "uuid of the job" } + let(:call_action) { get('index', params: params.merge(format: mime_type)) } + let(:mime_type) { 'xls' } + let(:export_result) { 'uuid of the job' } requires_export_permission do before do - service_instance = double("service_instance") + service_instance = double('service_instance') allow(WorkPackages::Exports::ScheduleService) .to receive(:new) @@ -124,17 +124,17 @@ def self.requires_export_permission(&) .and_return(ServiceResult.failure(result: export_result)) end - it "fulfills the defined should_receives" do + it 'fulfills the defined should_receives' do call_action - expect(response).to redirect_to job_status_path("uuid of the job") + expect(response).to redirect_to job_status_path('uuid of the job') end - context "with json accept" do - it "fulfills the defined should_receives" do - request.headers["Accept"] = "application/json" + context 'with json accept' do + it 'fulfills the defined should_receives' do + request.headers['Accept'] = 'application/json' call_action - expect(response.body).to eq({ job_id: "uuid of the job" }.to_json) + expect(response.body).to eq({ job_id: 'uuid of the job' }.to_json) end end end diff --git a/packaging/addons/openproject/bin/postinstall b/packaging/addons/openproject/bin/postinstall index 403f26a16ac2..c6c7cfab7c17 100755 --- a/packaging/addons/openproject/bin/postinstall +++ b/packaging/addons/openproject/bin/postinstall @@ -62,6 +62,8 @@ fi # And we can use it for backend precompilation ${CLI} config:set EXECJS_RUNTIME="Node" +rake_commands="db:migrate db:seed" + # set rails_cache_store memcached_servers="$(${CLI} config:get MEMCACHED_SERVERS || echo "")" if [ -z "$memcached_servers" ]; then @@ -102,9 +104,8 @@ fi # Allow other tasks to run before the environment is loaded ${CLI} run rake "packager:before_postinstall" -# Use the OpenProject internal setup -${CLI} run rake "db:migrate" -${CLI} run rake "db:seed packager:postinstall" +# Use the OpenProject internal setup in one environment task +${CLI} run rake "${rake_commands} packager:postinstall" # For some reason RHEL8 creates files with chmod 0600 find "${APP_HOME}/public" -type f -exec chmod 0644 {} \; diff --git a/packaging/scripts/check b/packaging/scripts/check index 5c3ae2647711..bd98c43d9bd2 100755 --- a/packaging/scripts/check +++ b/packaging/scripts/check @@ -29,7 +29,7 @@ else log_ko "openproject server is NOT running" fi -if ps -u "$APP_USER" -f | grep -q "good_job start" ; then +if ps -u "$APP_USER" -f | grep -q "rake jobs:work" ; then log_ok "openproject background job worker is running" else log_ko "openproject background job worker is NOT running" diff --git a/packaging/scripts/worker b/packaging/scripts/worker index cb29dbeace3b..ea691e755397 100755 --- a/packaging/scripts/worker +++ b/packaging/scripts/worker @@ -1,3 +1,3 @@ #!/bin/bash -e -QUIET=true bundle exec good_job start +QUIET=true bundle exec rake jobs:work diff --git a/script/api/spec b/script/api/spec index 934d6f3dd5dc..a56167823ee1 100755 --- a/script/api/spec +++ b/script/api/spec @@ -7,11 +7,11 @@ if /((-h)|(--help))/.match?(ARGV.join(" ")) return end -require "pathname" -require "yaml" -require "json" +require 'pathname' +require 'yaml' +require 'json' -require_relative "../../lib/api/open_api" +require_relative '../../lib/api/open_api' path = Pathname(__dir__).join("../../docs/api/apiv3/openapi-spec.yml") spec = API::OpenAPI.assemble_spec path diff --git a/script/api/validate_spec b/script/api/validate_spec index 470604d092a9..bf6f89d4af12 100755 --- a/script/api/validate_spec +++ b/script/api/validate_spec @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -require "pathname" -require "tempfile" +require 'pathname' +require 'tempfile' -openapi_yaml_spec_path = Pathname(__dir__).join("../../tmp/oas-generated.yml") -full_spec = `#{Pathname(__dir__).join("spec")} --format yaml` +openapi_yaml_spec_path = Pathname(__dir__).join('../../tmp/oas-generated.yml') +full_spec = `#{Pathname(__dir__).join('spec')} --format yaml` status = $?.exitstatus if status != 0 warn "failed to bundle the openapi spec yaml file" diff --git a/script/bulk_run_rspec b/script/bulk_run_rspec index fa4ce930a922..05e8ddedfaef 100755 --- a/script/bulk_run_rspec +++ b/script/bulk_run_rspec @@ -5,18 +5,18 @@ # Run with --help for more information # rubocop:disable Rails -require "fileutils" -require "optparse" -require "ostruct" -require "pathname" +require 'fileutils' +require 'optparse' +require 'ostruct' +require 'pathname' -RAILS_ROOT = Pathname.new File.expand_path("../", __dir__) -RSPEC_EXAMPLE_STATUS_PERSISTENCE_FILE_PATH = RAILS_ROOT.join("tmp/spec_examples.txt") -PATTERN = ENV["BULK_RUN_PATTERN"] ? Regexp.new(ENV["BULK_RUN_PATTERN"]) : /features/ +RAILS_ROOT = Pathname.new File.expand_path('../', __dir__) +RSPEC_EXAMPLE_STATUS_PERSISTENCE_FILE_PATH = RAILS_ROOT.join('tmp/spec_examples.txt') +PATTERN = ENV['BULK_RUN_PATTERN'] ? Regexp.new(ENV['BULK_RUN_PATTERN']) : /features/ class Options DEFAULTS = { - run_count: ENV["BULK_RUN_COUNT"] ? ENV["BULK_RUN_COUNT"].to_i : 5 + run_count: ENV['BULK_RUN_COUNT'] ? ENV['BULK_RUN_COUNT'].to_i : 5 }.freeze BANNER = <<~BANNER.freeze @@ -89,7 +89,7 @@ class Options end def normalized(path) - path.sub(/^\.\//, "").tr("/", "__").tr("[]:", "_") + path.sub(/^\.\//, '').tr('/', '__').tr('[]:', '_') end class String @@ -112,7 +112,7 @@ class Test end def to_line - [path, normalized_name, runs.count, runs.count(&:passed?), runs.count(&:failed?)].join(" | ") + [path, normalized_name, runs.count, runs.count(&:passed?), runs.count(&:failed?)].join(' | ') end def normalized_name @@ -162,7 +162,7 @@ class BulkRunner else lines = File.readlines(RSPEC_EXAMPLE_STATUS_PERSISTENCE_FILE_PATH) lines = lines.grep(PATTERN) - lines.map { |line| line.split("|").first.strip } + lines.map { |line| line.split('|').first.strip } end end @@ -172,23 +172,23 @@ class BulkRunner # rubocop:disable Metrics/AbcSize def run - FileUtils.rm_rf(bulk_run_dir("logs")) if bulk_run_dir("logs").exist? - `mkdir -p #{bulk_run_dir("logs")}` + FileUtils.rm_rf(bulk_run_dir('logs')) if bulk_run_dir('logs').exist? + `mkdir -p #{bulk_run_dir('logs')}` puts "#{tests.count} tests to run" puts "logs: #{bulk_run_dir('logs')}" tests.each do |test| - puts "=" * 80 + puts '=' * 80 puts "Running #{test.path} #{Options.run_count} times" - puts "=" * 80 + puts '=' * 80 Options.run_count.times do |i| - puts " Run #{i} ".center(80, "-") + puts " Run #{i} ".center(80, '-') run = Run.new(test.path) run.output = `DISABLE_PRY=1 CI=true bundle exec rspec '#{run.path}' 2>&1` if $?.success? - puts "ok".green + puts 'ok'.green run.passed! else - puts "ko".red + puts 'ko'.red run.failed! end File.write(bulk_run_dir("logs/#{test.normalized_name}.#{run.result}.#{i}.log"), run.output) @@ -196,22 +196,22 @@ class BulkRunner end if test.runs.all?(&:passed?) - puts "PASSED".green + puts 'PASSED'.green else - puts "FAILED".red + puts 'FAILED'.red end end end # rubocop:enable Metrics/AbcSize def bulk_run_dir(path) - RAILS_ROOT.join("tmp/bulk_run").join(path) + RAILS_ROOT.join('tmp/bulk_run').join(path) end def save puts "Saving" - File.open(bulk_run_dir("results.txt"), "w") do |results| - results.puts("test_path | log_prefix | count | passed | failed") + File.open(bulk_run_dir('results.txt'), 'w') do |results| + results.puts('test_path | log_prefix | count | passed | failed') tests.each do |test| results.puts(test.to_line) end diff --git a/script/docs/check_links b/script/docs/check_links index 7bc27e1cb208..42ccd28b8886 100755 --- a/script/docs/check_links +++ b/script/docs/check_links @@ -1,10 +1,10 @@ #!/usr/bin/env ruby -require "pathname" -require "yaml" -require "markly" -require "uri" -require "active_support/inflector" +require 'pathname' +require 'yaml' +require 'markly' +require 'uri' +require 'active_support/inflector' def parse_markdown(content) id_gen = IdGenerator.new @@ -15,7 +15,7 @@ def parse_markdown(content) if node.type == :link || node.type == :image links.push({ url: node.url, pos: node.source_position, type: node.type }) elsif node.type == :header - text = node.to_plaintext.delete("\n").tr(" ", " ") + text = node.to_plaintext.delete("\n").tr(' ', ' ') id = id_gen.generate_id(text) anchors.push(id) end @@ -26,8 +26,8 @@ end class IdGenerator def generate_markdown_header_id(text) id = text.downcase - id.gsub!(/[^\p{Word}\- ]/u, "") # remove punctuation - id.tr!(" ", "-") # replace spaces with dash + id.gsub!(/[^\p{Word}\- ]/u, '') # remove punctuation + id.tr!(' ', '-') # replace spaces with dash id = "section" if id.empty? id end @@ -57,8 +57,8 @@ class APIChecker filename = Pathname(@root_path).join("api/apiv3/openapi-spec.yml") spec = YAML.load_file(filename) @operations = collect_operations_from_spec(spec) - spec["tags"] - .map { |ref| api_page_by_tag(ref["$ref"]) } + spec['tags'] + .map { |ref| api_page_by_tag(ref['$ref']) } .push( introduction_page(spec, filename), markdown_page("api/README.md", "api"), @@ -70,7 +70,7 @@ class APIChecker private def introduction_page(spec, filename) - anchors, links = parse_markdown(spec["info"]["description"]) + anchors, links = parse_markdown(spec['info']['description']) { path: "#{@root_path}/api/introduction", anchors:, links:, filename: } end @@ -81,8 +81,8 @@ class APIChecker end def collect_operations_from_spec(spec) - spec["paths"].map do |p| - path_obj_path = Pathname(@root_path).join("api/apiv3/", p[1]["$ref"]) + spec['paths'].map do |p| + path_obj_path = Pathname(@root_path).join("api/apiv3/", p[1]['$ref']) path_obj = YAML.load_file(path_obj_path) path_obj.keys.map { |key| path_obj[key] } end.flatten @@ -90,16 +90,16 @@ class APIChecker def operation_ids_by_tag(tag, id_gen) @operations - .select { |operation| operation["tags"]&.include?(tag["name"]) } - .map { |operation| id_gen.generate_id(operation["summary"]) } + .select { |operation| operation['tags']&.include?(tag['name']) } + .map { |operation| id_gen.generate_id(operation['summary']) } end def api_page_by_tag(ref) tag_source = Pathname(@root_path).join("api/apiv3", ref) tag = YAML.load_file(tag_source) - anchors, links, id_gen = parse_markdown(tag["description"]) + anchors, links, id_gen = parse_markdown(tag['description']) anchors.concat(operation_ids_by_tag(tag, id_gen)) - tag_path = ActiveSupport::Inflector.parameterize(tag["name"]) + tag_path = ActiveSupport::Inflector.parameterize(tag['name']) tag_path = "endpoints/#{tag_path}" unless PULLED_UP_TAG_PAGES.include?(tag_path) { path: "#{@root_path}/api/#{tag_path}", anchors:, links:, filename: tag_source } end @@ -128,7 +128,7 @@ class DocsChecker def scan @docs = Dir.glob("#{@root_path}/**/README.md") - .reject { |filename| filename.include?("/api/") } + .reject { |filename| filename.include?('/api/') } .map { |filename| build_doc(filename) } end @@ -148,7 +148,7 @@ class DocsChecker def check_link(uri, link, doc) full_url = File.expand_path(uri.to_s, doc[:path]) - target_doc_path = URI(full_url).path.chomp("/") + target_doc_path = URI(full_url).path.chomp('/') target_doc = @docs.find { |d| d[:path] == target_doc_path } if target_doc.nil? return if File.exist?(target_doc_path) # linked files in doc e.g. "./restore.sql" @@ -156,16 +156,16 @@ class DocsChecker full_url = File.expand_path(uri.to_s, File.dirname(doc[:filename])) return if File.exist?(full_url) # linked images in doc e.g. "api/bcf/BCFicon128.png" (but target is api/bcf-rest-api/BCFicon128.png) - return { error: (link[:type] || "Page").capitalize, link:, doc: } + return { error: (link[:type] || 'Page').capitalize, link:, doc: } end unless uri.fragment.nil? || target_doc[:anchors].include?(uri.fragment) - { error: "Anchor", link:, doc: } + { error: 'Anchor', link:, doc: } end end def strip_external_link_to_doc(url, path) uri = URI(url) - full_path = File.expand_path(uri.path.sub("/docs", "."), @root_path) + full_path = File.expand_path(uri.path.sub('/docs', '.'), @root_path) relative_url = Pathname.new(full_path).relative_path_from("#{path}/").to_s "#{relative_url}/##{uri.fragment}" unless uri.fragment.nil? @@ -174,7 +174,7 @@ class DocsChecker def parse_uri(link, doc) uri = URI(link[:url]) - if uri.hostname == "www.openproject.org" && uri.path&.start_with?("/docs") + if uri.hostname == 'www.openproject.org' && uri.path&.start_with?('/docs') uri = URI(strip_external_link_to_doc(link[:url], doc[:path])) end uri unless %w[mailto https http].include?(uri.scheme) @@ -199,17 +199,17 @@ class DocsChecker @errors.each do |error| pos = error[:link][:pos] report_item( - "error", + 'error', error[:doc][:filename], pos[:start_line], pos[:start_column], pos[:end_line], pos[:end_column], "#{error[:error]} not found for link address `#{error[:link][:url]}`" ) end - puts "Done. No broken references found." if @errors.empty? + puts 'Done. No broken references found.' if @errors.empty? end def github_escape(str) - str.gsub(/[%:\n\r]/, { "%" => "%25", "\n" => "%0A", "\r" => "%0D", ":" => "%3A" }).squeeze(" ") + str.gsub(/[%:\n\r]/, { "%" => "%25", "\n" => "%0A", "\r" => "%0D", ':' => '%3A' }).squeeze(' ') end def report_item(*) @@ -241,5 +241,5 @@ class DocsChecker end exit 1 unless DocsChecker.new( - File.expand_path("../../docs/", __dir__) + File.expand_path('../../docs/', __dir__) ).run diff --git a/script/github_pr_errors b/script/github_pr_errors index f71b34f0e5be..3eb86c0f04ad 100755 --- a/script/github_pr_errors +++ b/script/github_pr_errors @@ -1,26 +1,26 @@ #!/usr/bin/env ruby -require "rubygems" -require "bundler" +require 'rubygems' +require 'bundler' Bundler.setup(:default, :development) -require "colored2" -require "json" -require "optparse" -require "base64" -require "pathname" -require "pry" -require "yaml" -require "httpx" - -GITHUB_API_OPENPROJECT_PREFIX = "https://api.github.com/repos/opf/openproject".freeze -GITHUB_HTML_OPENPROJECT_PREFIX = "https://github.com/opf/openproject".freeze +require 'colored2' +require 'json' +require 'optparse' +require 'base64' +require 'pathname' +require 'pry' +require 'yaml' +require 'httpx' + +GITHUB_API_OPENPROJECT_PREFIX = 'https://api.github.com/repos/opf/openproject'.freeze +GITHUB_HTML_OPENPROJECT_PREFIX = 'https://github.com/opf/openproject'.freeze RAILS_ROOT = Pathname.new(__dir__).dirname EXCLUDED_JOB_NAMES = %w[eslint rubocop].freeze -if !ENV["GITHUB_USERNAME"] +if !ENV['GITHUB_USERNAME'] raise "Missing GITHUB_USERNAME env" -elsif !ENV["GITHUB_TOKEN"] +elsif !ENV['GITHUB_TOKEN'] raise "Missing GITHUB_TOKEN env, go to https://github.com/settings/tokens and create one with 'repo' access" end @@ -152,7 +152,7 @@ def current_branch_name end def github_url(path) - if path.start_with?("http") + if path.start_with?('http') path else "#{GITHUB_API_OPENPROJECT_PREFIX}/#{path}" @@ -163,7 +163,7 @@ def http HTTPX .plugin(:follow_redirects) .plugin(:basic_auth) - .basic_auth(ENV.fetch("GITHUB_USERNAME"), ENV.fetch("GITHUB_TOKEN")) + .basic_auth(ENV.fetch('GITHUB_USERNAME'), ENV.fetch('GITHUB_TOKEN')) end def get_http(path) @@ -201,18 +201,18 @@ end def path_to_cache_key(path) path - .gsub(/\?.*$/, "") # remove query parameter - .gsub(/^#{GITHUB_API_OPENPROJECT_PREFIX}\/?/o, "") # remove https://.../ - .gsub(/\W/, "_") # transform non alphanum chars + .gsub(/\?.*$/, '') # remove query parameter + .gsub(/^#{GITHUB_API_OPENPROJECT_PREFIX}\/?/o, '') # remove https://.../ + .gsub(/\W/, '_') # transform non alphanum chars end def get_jobs(workflow_run) - workflow_run["jobs_url"] + workflow_run['jobs_url'] cache_key = [ - path_to_cache_key(workflow_run["jobs_url"]), - workflow_run["updated_at"].delete(":") - ].join("_") - cached(cache_key) { get_json(workflow_run["jobs_url"]) } + path_to_cache_key(workflow_run['jobs_url']), + workflow_run['updated_at'].delete(':') + ].join('_') + cached(cache_key) { get_json(workflow_run['jobs_url']) } end def get_log(job) @@ -242,18 +242,18 @@ end def last_with_status(workflow_runs, status) workflow_runs - .select { |entry| entry["status"] == status } - .max_by { |entry| entry["run_number"] } + .select { |entry| entry['status'] == status } + .max_by { |entry| entry['run_number'] } end def get_last_workflow_run(branch_name) test_workflow_runs = get_json("actions/runs?branch=#{CGI.escape(branch_name)}") - .then { |response| response["workflow_runs"] } - .select { |entry| entry["name"] == "Test suite" } + .then { |response| response['workflow_runs'] } + .select { |entry| entry['name'] == 'Test suite' } - last_completed = last_with_status(test_workflow_runs, "completed") - last_in_progress = last_with_status(test_workflow_runs, "in_progress") + last_completed = last_with_status(test_workflow_runs, 'completed') + last_in_progress = last_with_status(test_workflow_runs, 'in_progress') last_completed || last_in_progress or raise "No workflow run found for branch #{branch_name}" end @@ -511,7 +511,7 @@ class Formatter return end begin - Open3.popen2e("imgcat", "--width", "50%", "--url", screenshot_url) do |stdin, stdout_and_stderr, _thread| + Open3.popen2e('imgcat', '--width', '50%', '--url', screenshot_url) do |stdin, stdout_and_stderr, _thread| stdin.close warn stdout_and_stderr.read end @@ -528,7 +528,7 @@ class Formatter warn [ " ", - "↳".blue.bold, + '↳'.blue.bold, " ", name.blue, ": ", @@ -551,9 +551,9 @@ class Formatter end def display_pull_request_info(workflow_run) - return unless workflow_run["event"] == "pull_request" + return unless workflow_run['event'] == 'pull_request' - if pr = workflow_run["pull_requests"].first + if pr = workflow_run['pull_requests'].first pr_number = "##{pr['number']}" pr_html_url = "#{GITHUB_HTML_OPENPROJECT_PREFIX}/pull/#{pr['number']}" pr_display_title = "#{workflow_run['display_title']} #{pr_number.white.dark} #{pr_html_url.white.dark}" @@ -564,17 +564,17 @@ class Formatter end def commit_message(workflow_run) - workflow_run["head_commit"] + workflow_run['head_commit'] .then { |commit| commit["message"] } .then { |message| message.split("\n", 2).first } end def status_icon(job) - case job["status"] + case job['status'] when "queued", "in_progress" "●".yellow else - case job["conclusion"] + case job['conclusion'] when "success" "✓".green when "failure" @@ -586,9 +586,9 @@ class Formatter end def status_url(job) - return if job["conclusion"] == "success" + return if job['conclusion'] == "success" - job["html_url"].white.dark + job['html_url'].white.dark end def status_line(job) @@ -610,11 +610,11 @@ def get_failed_jobs_logs_from_github(formatter) formatter.display_workflow_status(workflow_run) get_jobs(workflow_run) - .then { |jobs_response| jobs_response["jobs"] } - .sort_by { _1["name"] } + .then { |jobs_response| jobs_response['jobs'] } + .sort_by { _1['name'] } .each { |job| formatter.display_job_status(job) } - .select { _1["conclusion"] == "failure" } - .reject { EXCLUDED_JOB_NAMES.include?(_1["name"]) } + .select { _1['conclusion'] == 'failure' } + .reject { EXCLUDED_JOB_NAMES.include?(_1['name']) } .map { |job| get_log(job) } end diff --git a/script/i18n/generate_languages_translations b/script/i18n/generate_languages_translations index 33b60ad38dfc..d1e91aab0bb4 100755 --- a/script/i18n/generate_languages_translations +++ b/script/i18n/generate_languages_translations @@ -1,7 +1,7 @@ #!/usr/bin/env ruby begin - require "cldr" + require 'cldr' rescue LoadError warn <<~MSG Error: the ruby-cldr gem is not installed @@ -9,15 +9,15 @@ rescue LoadError MSG exit 1 end -require "pathname" -require "yaml" +require 'pathname' +require 'yaml' class App class << self def locales - @locales ||= rails_root.glob("config/locales/**/*.yml") - .map { |f| f.basename.to_s.split(".", 2).first } - .reject! { |l| l.start_with?("js-") || l == "lol" } + @locales ||= rails_root.glob('config/locales/**/*.yml') + .map { |f| f.basename.to_s.split('.', 2).first } + .reject! { |l| l.start_with?('js-') || l == 'lol' } .uniq .map(&:to_sym) end @@ -26,7 +26,7 @@ class App @rails_root ||= Pathname.new(__dir__) .ascend - .find { |dir| dir.join("Gemfile").exist? } + .find { |dir| dir.join('Gemfile').exist? } .tap { |dir| raise "Unable to find Rails root directory (looking up from #{__dir__})" if dir.nil? } end end @@ -37,7 +37,7 @@ class CldrTranslations def initialize ensure_cldr_database_is_downloaded - Cldr::Export::Data.dir = cldr_db_location.join("common").to_s + Cldr::Export::Data.dir = cldr_db_location.join('common').to_s end def language_name(locale) @@ -72,8 +72,8 @@ class CldrTranslations # zh-TW <=> zh-Hant (zh-Hant or zh-Hant-TW (Taiwan) is preferred zh-TW) def cldr_supported(locale) case locale - when :"zh-CN" then :"zh-Hans-CN" - when :"zh-TW" then :"zh-Hant-TW" + when :'zh-CN' then :'zh-Hans-CN' + when :'zh-TW' then :'zh-Hant-TW' else locale end end @@ -85,8 +85,8 @@ class CldrTranslations # From :'pt-PT', returns [:'pt-PT', :pt] def variations(locale) locale.to_s - .split("-") - .reduce([]) { |variations, part| variations.unshift([variations.first, part].compact.join("-")) } + .split('-') + .reduce([]) { |variations, part| variations.unshift([variations.first, part].compact.join('-')) } .then { |variations| insert_self_variation(variations) } .select { |variation| available_locale?(variation) } .map(&:to_sym) @@ -106,13 +106,13 @@ class CldrTranslations end def available_locales - @available_locales ||= Set.new(Cldr::Export::Data.locales.map { _1.tr("_", "-") }) + @available_locales ||= Set.new(Cldr::Export::Data.locales.map { _1.tr('_', '-') }) end def ensure_cldr_database_is_downloaded return if cldr_db_location.exist? - require "cldr/download" + require 'cldr/download' target = cldr_db_location.to_s source = "https://unicode.org/Public/cldr/#{CLDR_VERSION}/core.zip" puts <<~MSG @@ -153,7 +153,7 @@ class GenerateTranslationFiles end def create_translation_file(locale) - translations_directory.join("#{locale}.yml").open("w") do |f| + translations_directory.join("#{locale}.yml").open('w') do |f| f.puts COMMENT YAML.dump(yaml_content(locale), f) end @@ -162,8 +162,8 @@ class GenerateTranslationFiles def yaml_content(locale) { locale.to_s => { - "cldr" => { - "language_name" => cldr_translations.language_name(locale) + 'cldr' => { + 'language_name' => cldr_translations.language_name(locale) } } } @@ -174,7 +174,7 @@ class GenerateTranslationFiles end def translations_directory - @translations_directory ||= App.rails_root.join("config/locales/generated").tap do |dir| + @translations_directory ||= App.rails_root.join('config/locales/generated').tap do |dir| dir.mkdir unless dir.exist? end end diff --git a/script/i18n/generate_seeders_i18n_source_file b/script/i18n/generate_seeders_i18n_source_file index ee008ac502fc..9939d6fbb2e6 100755 --- a/script/i18n/generate_seeders_i18n_source_file +++ b/script/i18n/generate_seeders_i18n_source_file @@ -29,19 +29,19 @@ #++ if !defined? Rails - puts "Loading necessary files to run without loading Rails" + puts 'Loading necessary files to run without loading Rails' puts "(Alternatively, you can try running bundle exec rails runner #{$0})" puts - require "pathname" - require "yaml" - require "active_support/core_ext/hash/deep_merge" - require "active_support/core_ext/hash/keys" - require "active_support/core_ext/object/blank" + require 'pathname' + require 'yaml' + require 'active_support/core_ext/hash/deep_merge' + require 'active_support/core_ext/hash/keys' + require 'active_support/core_ext/object/blank' class Rails def self.root - Pathname.new File.expand_path("../../", __dir__) + Pathname.new File.expand_path('../../', __dir__) end end @@ -71,7 +71,7 @@ class GenerateSeederSourceTranslationFiles source_data = translatable_data(seed_files) return if source_data.blank? - source_file_path(dir).open("w") do |f| + source_file_path(dir).open('w') do |f| puts "Generate crowdin source file #{relative_path(f.path)}" f.puts comment @@ -80,7 +80,7 @@ class GenerateSeederSourceTranslationFiles end def create_additional_dummy_crowdin_source_file - dummy_file = Rails.root.join("modules/boards/config/locales/en.seeders.yml") + dummy_file = Rails.root.join('modules/boards/config/locales/en.seeders.yml') content = <<~CONTENT #{comment} # @@ -101,9 +101,9 @@ class GenerateSeederSourceTranslationFiles base_path = seed_file_path loop do base_path, dir = base_path.split - break if dir.to_s == "app" + break if dir.to_s == 'app' end - base_path.join("config/locales/en.seeders.yml") + base_path.join('config/locales/en.seeders.yml') end def comment @@ -125,14 +125,14 @@ class GenerateSeederSourceTranslationFiles return if merged_translatables.blank? { - "en" => { + 'en' => { Source::Translate::I18N_PREFIX => merged_translatables } } end def relative_path(path) - return path unless path.start_with?("/") + return path unless path.start_with?('/') Pathname.new(path).relative_path_from(Rails.root).to_s end diff --git a/script/i18n/print_packager_languages_choices b/script/i18n/print_packager_languages_choices index 89cc574cdc9e..41a77fdd8466 100755 --- a/script/i18n/print_packager_languages_choices +++ b/script/i18n/print_packager_languages_choices @@ -5,8 +5,8 @@ # # The template is located at packaging/addons/openproject/templates -require "pathname" -require "yaml" +require 'pathname' +require 'yaml' class App class << self @@ -14,7 +14,7 @@ class App @rails_root ||= Pathname.new(__dir__) .ascend - .find { |dir| dir.join("Gemfile").exist? } + .find { |dir| dir.join('Gemfile').exist? } .tap { |dir| raise "Unable to find Rails root directory (looking up from #{__dir__})" if dir.nil? } end end @@ -38,12 +38,12 @@ class PrintPackagerLanguagesChoices end def translations_files - App.rails_root.glob("config/locales/generated/*.yml") + App.rails_root.glob('config/locales/generated/*.yml') end def language_code_and_name_from(translation_file) YAML.load_file(translation_file.to_s) - .map { |(lang, data)| [lang, data.dig("cldr", "language_name")] } + .map { |(lang, data)| [lang, data.dig('cldr', 'language_name')] } end end end diff --git a/script/pdf_export/generate_styles_doc b/script/pdf_export/generate_styles_doc index 9e154c190ae5..db61d65032aa 100755 --- a/script/pdf_export/generate_styles_doc +++ b/script/pdf_export/generate_styles_doc @@ -2,17 +2,17 @@ # Generates the PDF export styling yaml documentation. -require "md_to_pdf/style/schema_doc" +require 'md_to_pdf/style/schema_doc' require "yaml" require "json" root = File.expand_path("../../", __dir__) -schema_file = File.join(root, "app", "models", "work_package", "pdf_export", "schema.json") +schema_file = File.join(root, 'app', 'models', 'work_package', 'pdf_export', 'schema.json') schema = JSON::load_file(schema_file) generator = MarkdownToPDF::StyleSchemaDocsGenerator.new(schema) markdown = generator.generate_markdown -styles_doc_folder = File.join(root, "docs", "system-admin-guide", "design", "pdf-export-styles") +styles_doc_folder = File.join(root, 'docs', 'system-admin-guide', 'design', 'pdf-export-styles') FileUtils.mkdir_p(styles_doc_folder) -styles_doc_file = File.join(styles_doc_folder, "README.md") +styles_doc_file = File.join(styles_doc_folder, 'README.md') File.write(styles_doc_file, markdown) puts "Doc written: #{styles_doc_file}" diff --git a/script/pdf_export/validate_styles b/script/pdf_export/validate_styles index 2f9d2af3a28a..37f931c02c03 100755 --- a/script/pdf_export/validate_styles +++ b/script/pdf_export/validate_styles @@ -1,17 +1,17 @@ #!/usr/bin/env ruby -require "md_to_pdf/style/validation" -require "md_to_pdf/core" -require "yaml" -require "json" +require 'md_to_pdf/style/validation' +require 'md_to_pdf/core' +require 'yaml' +require 'json' class SchemaValidator include MarkdownToPDF::StyleValidation def validate root = File.expand_path("../../", __dir__) - schema = JSON::load_file(File.join(root, "app", "models", "work_package", "pdf_export", "schema.json")) - styles_file = File.join(root, "app", "models", "work_package", "pdf_export", "standard.yml") + schema = JSON::load_file(File.join(root, 'app', 'models', 'work_package', 'pdf_export', 'schema.json')) + styles_file = File.join(root, 'app', 'models', 'work_package', 'pdf_export', 'standard.yml') styles = YAML.load_file(styles_file) validate_schema!(styles, schema) puts "Valid: #{styles_file}" diff --git a/spec/components/activities/item_component_spec.rb b/spec/components/activities/item_component_spec.rb index 2959b13345d6..140b31cdf6f9 100644 --- a/spec/components/activities/item_component_spec.rb +++ b/spec/components/activities/item_component_spec.rb @@ -42,87 +42,87 @@ journal: ) end - let(:project) { build_stubbed(:project, name: "My project") } + let(:project) { build_stubbed(:project, name: 'My project') } let(:journal) { build_stubbed(:work_package_journal) } - it "renders the activity title" do + it 'renders the activity title' do render_inline(described_class.new(event:)) - expect(page).to have_css(".op-activity-list--item-title", text: "Event Title") + expect(page).to have_css('.op-activity-list--item-title', text: 'Event Title') end it 'adds "(Project: ...)" suffix after the activity title' do render_inline(described_class.new(event:)) - expect(page).to have_css(".op-activity-list--item-title", text: /Event Title\s+\(Project: My project\)/) + expect(page).to have_css('.op-activity-list--item-title', text: /Event Title\s+\(Project: My project\)/) end - it "escapes HTML in the activity title and the project suffix" do - event.event_title = "Hello World!" - event.project.name = "Project name with HTML" + it 'escapes HTML in the activity title and the project suffix' do + event.event_title = 'Hello World!' + event.project.name = 'Project name with HTML' render_inline(described_class.new(event:)) - expect(page).to have_css(".op-activity-list--item-title", text: "Hello World!") - expect(page).to have_css(".op-activity-list--item-title", text: "Project: Project name with HTML)") + expect(page).to have_css('.op-activity-list--item-title', text: 'Hello World!') + expect(page).to have_css('.op-activity-list--item-title', text: 'Project: Project name with HTML)') end - it "does not truncate the title" do - event.event_title = "Hello, World!" * 20 + it 'does not truncate the title' do + event.event_title = 'Hello, World!' * 20 render_inline(described_class.new(event:)) - expect(page).to have_css(".op-activity-list--item-title", text: event.event_title) + expect(page).to have_css('.op-activity-list--item-title', text: event.event_title) end - it "removes line breaks and tabs from the title and replaces them with spaces" do + it 'removes line breaks and tabs from the title and replaces them with spaces' do event.event_title = "This \t should\n\rbe\n all\ncleaned" render_inline(described_class.new(event:)) - expect(page).to have_css(".op-activity-list--item-title", text: "This should be all cleaned") + expect(page).to have_css('.op-activity-list--item-title', text: 'This should be all cleaned') end - context "for Project activities" do + context 'for Project activities' do let(:journal) { build_stubbed(:project_journal) } - it "does not add the project suffix" do + it 'does not add the project suffix' do component = described_class.new(event:) render_inline(component) expect(component.project_suffix).to be_nil - expect(page).to have_css(".op-activity-list--item-title", text: /\A\s*Event Title\s*\z/) + expect(page).to have_css('.op-activity-list--item-title', text: /\A\s*Event Title\s*\z/) end end - context "when :current_project is set" do - it "does not display the project suffix for activities of the current project" do - event.project.name = "My project" + context 'when :current_project is set' do + it 'does not display the project suffix for activities of the current project' do + event.project.name = 'My project' component = described_class.new(event:, current_project: project) render_inline(component) expect(component.project_suffix).to be_nil - expect(page).to have_no_css(".op-activity-list--item-title", text: "(Project: My project)") + expect(page).to have_no_css('.op-activity-list--item-title', text: '(Project: My project)') end it 'adds "(Subproject: ...)" suffix for activities of subprojects of the current project' do parent_project = build_stubbed(:project) event.project.parent = parent_project - event.project.name = "My subproject" + event.project.name = 'My subproject' render_inline(described_class.new(event:, current_project: parent_project)) - expect(page).to have_css(".op-activity-list--item-title", text: "(Subproject: My subproject)") + expect(page).to have_css('.op-activity-list--item-title', text: '(Subproject: My subproject)') end end - context "when a journal change does not have a formatter associated" do - it "does not display the change information" do - event.event_description = "" - allow(event.journal).to receive(:details).and_return(i_do_not_have_a_formatter_associated: ["old", "new"]) + context 'when a journal change does not have a formatter associated' do + it 'does not display the change information' do + event.event_description = '' + allow(event.journal).to receive(:details).and_return(i_do_not_have_a_formatter_associated: ['old', 'new']) render_inline(described_class.new(event:)) - expect(page).to have_no_css(".op-activity-list--item-detail") + expect(page).to have_no_css('.op-activity-list--item-detail') end end - context "for TimeEntry activities" do + context 'for TimeEntry activities' do let(:journal) { build_stubbed(:time_entry_journal) } let(:event) do Activities::Event.new( @@ -134,10 +134,10 @@ ) end - it "displays the title correctly" do + it 'displays the title correctly' do component = described_class.new(event:) render_inline(component) - expect(page).to have_css(".op-activity-list--item-title", text: /Event Title\s+\(Project: My project\)/) + expect(page).to have_css('.op-activity-list--item-title', text: /Event Title\s+\(Project: My project\)/) end end end diff --git a/spec/components/application_component_spec.rb b/spec/components/application_component_spec.rb index 9ab464741688..1b8722e4a3e1 100644 --- a/spec/components/application_component_spec.rb +++ b/spec/components/application_component_spec.rb @@ -31,29 +31,29 @@ require "rails_helper" RSpec.describe ApplicationComponent, type: :component do - describe ".options" do + describe '.options' do let(:component_class) do Class.new(described_class) do - options title: "Hello World!", subtitle: "How are you today?" + options title: 'Hello World!', subtitle: 'How are you today?' options enabled: true options :x, :y end end - it "defines options with default values as constructor attributes" do + it 'defines options with default values as constructor attributes' do component = component_class.new - expect(component.title).to eq("Hello World!") - expect(component.subtitle).to eq("How are you today?") + expect(component.title).to eq('Hello World!') + expect(component.subtitle).to eq('How are you today?') expect(component.enabled).to be(true) expect(component.x).to be_nil expect(component.y).to be_nil end - it "returns value used in constructor if present" do - component = component_class.new(title: "My title", subtitle: nil, enabled: false, x: 13, y: 37) + it 'returns value used in constructor if present' do + component = component_class.new(title: 'My title', subtitle: nil, enabled: false, x: 13, y: 37) - expect(component.title).to eq("My title") + expect(component.title).to eq('My title') expect(component.subtitle).to be_nil expect(component.enabled).to be(false) expect(component.x).to eq(13) diff --git a/spec/components/attribute_groups/attribute_group_component_spec.rb b/spec/components/attribute_groups/attribute_group_component_spec.rb index 9798f0dce21f..80e40e3aa6b7 100644 --- a/spec/components/attribute_groups/attribute_group_component_spec.rb +++ b/spec/components/attribute_groups/attribute_group_component_spec.rb @@ -31,7 +31,7 @@ require "rails_helper" RSpec.describe AttributeGroups::AttributeGroupComponent, type: :component do - it "renders the title" do + it 'renders the title' do render_inline(described_class.new) do |component| component.with_header(title: "A Title") @@ -41,32 +41,32 @@ ) end - aggregate_failures "group header" do - expect(page).to have_css(".attributes-group") - expect(page).to have_css("h3.attributes-group--header-text", text: "A Title") + aggregate_failures 'group header' do + expect(page).to have_css('.attributes-group') + expect(page).to have_css('h3.attributes-group--header-text', text: 'A Title') end - aggregate_failures "attribute key value" do - expect(page).to have_css(".attributes-key-value") - expect(page).to have_css(".attributes-key-value--key", text: "Attribute Key 1") & - have_css(".attributes-key-value--value.-text", text: "Attribute Value 1") - expect(page).to have_css(".attributes-key-value--key", text: "Attribute Key 2") & - have_css(".attributes-key-value--value.-text", text: "Attribute Value 2") + aggregate_failures 'attribute key value' do + expect(page).to have_css('.attributes-key-value') + expect(page).to have_css('.attributes-key-value--key', text: 'Attribute Key 1') & + have_css('.attributes-key-value--value.-text', text: 'Attribute Value 1') + expect(page).to have_css('.attributes-key-value--key', text: 'Attribute Key 2') & + have_css('.attributes-key-value--value.-text', text: 'Attribute Value 2') end end - it "renders content when provided" do + it 'renders content when provided' do render_inline(described_class.new) do |component| component.with_header(title: "A Title") "Raw Content" end - expect(page).to have_css(".attributes-group--content", text: "Raw Content") + expect(page).to have_css('.attributes-group--content', text: 'Raw Content') - aggregate_failures "group header" do - expect(page).to have_css(".attributes-group") - expect(page).to have_css("h3.attributes-group--header-text", text: "A Title") + aggregate_failures 'group header' do + expect(page).to have_css('.attributes-group') + expect(page).to have_css('h3.attributes-group--header-text', text: 'A Title') end end end diff --git a/spec/components/attribute_groups/attribute_group_header_component_spec.rb b/spec/components/attribute_groups/attribute_group_header_component_spec.rb index e81c1e73515c..acf67ba5f857 100644 --- a/spec/components/attribute_groups/attribute_group_header_component_spec.rb +++ b/spec/components/attribute_groups/attribute_group_header_component_spec.rb @@ -31,9 +31,9 @@ require "rails_helper" RSpec.describe AttributeGroups::AttributeGroupHeaderComponent, type: :component do - it "renders the title" do - render_inline(described_class.new(title: "A Title")) + it 'renders the title' do + render_inline(described_class.new(title: 'A Title')) - expect(page).to have_css("h3.attributes-group--header-text", text: "A Title") + expect(page).to have_css('h3.attributes-group--header-text', text: 'A Title') end end diff --git a/spec/components/attribute_groups/attribute_key_value_component_spec.rb b/spec/components/attribute_groups/attribute_key_value_component_spec.rb index 70ab3b63c009..dfa482ee538e 100644 --- a/spec/components/attribute_groups/attribute_key_value_component_spec.rb +++ b/spec/components/attribute_groups/attribute_key_value_component_spec.rb @@ -31,40 +31,40 @@ require "rails_helper" RSpec.describe AttributeGroups::AttributeKeyValueComponent, type: :component do - it "renders the attribute key and value" do - render_inline(described_class.new(key: "Attribute Key", value: "Attribute Value")) + it 'renders the attribute key and value' do + render_inline(described_class.new(key: 'Attribute Key', value: 'Attribute Value')) - expect(page).to have_css(".attributes-key-value--key", text: "Attribute Key") & - have_css(".attributes-key-value--value.-text", text: "Attribute Value") + expect(page).to have_css('.attributes-key-value--key', text: 'Attribute Key') & + have_css('.attributes-key-value--value.-text', text: 'Attribute Value') end it "preserve html in the value if it's a safe string" do - render_inline(described_class.new(key: "Attribute Key", value: "
    Some value
    ".html_safe)) + render_inline(described_class.new(key: 'Attribute Key', value: '
    Some value
    '.html_safe)) - expect(page).to have_no_css(".attributes-key-value--value.-text", text: "
    Some value
    ") - expect(page).to have_css(".attributes-key-value--value.-text", text: "Some value") + expect(page).to have_no_css('.attributes-key-value--value.-text', text: "
    Some value
    ") + expect(page).to have_css('.attributes-key-value--value.-text', text: "Some value") end - context "with value and content" do - it "renders the content" do - render_inline(described_class.new(key: "Attribute Key", value: "Attribute Value")) do + context 'with value and content' do + it 'renders the content' do + render_inline(described_class.new(key: 'Attribute Key', value: 'Attribute Value')) do "

    Content Value

    " end - expect(page).to have_css(".attributes-key-value--key", text: "Attribute Key") & - have_css(".attributes-key-value--value.-text", text: "Attribute Value") & - have_css(".attributes-key-value--value.-text", text: "

    Content Value

    ") + expect(page).to have_css('.attributes-key-value--key', text: 'Attribute Key') & + have_css('.attributes-key-value--value.-text', text: 'Attribute Value') & + have_css('.attributes-key-value--value.-text', text: "

    Content Value

    ") end end - context "with content, no value" do - it "renders the content" do - render_inline(described_class.new(key: "Attribute Key")) do + context 'with content, no value' do + it 'renders the content' do + render_inline(described_class.new(key: 'Attribute Key')) do "

    Content Value

    " end - expect(page).to have_css(".attributes-key-value--key", text: "Attribute Key") & - have_css(".attributes-key-value--value.-text", text: "

    Content Value

    ") + expect(page).to have_css('.attributes-key-value--key', text: 'Attribute Key') & + have_css('.attributes-key-value--value.-text', text: "

    Content Value

    ") end end end diff --git a/spec/components/op_turbo/frame_component_spec.rb b/spec/components/op_turbo/frame_component_spec.rb index cbb460b207e5..0f5bb5126ad9 100644 --- a/spec/components/op_turbo/frame_component_spec.rb +++ b/spec/components/op_turbo/frame_component_spec.rb @@ -26,41 +26,41 @@ # See COPYRIGHT and LICENSE files for more details. #++ # -require "spec_helper" +require 'spec_helper' RSpec.describe OpTurbo::FrameComponent, type: :component do - describe "#turbo_frame_id" do - context "with `context:` option" do - it "returns the turbo frame id" do + describe '#turbo_frame_id' do + context 'with `context:` option' do + it 'returns the turbo frame id' do storage = build_stubbed(:nextcloud_storage, id: 1) component = described_class.new(storage, context: :general_info) - expect(component.turbo_frame_id).to eq("general_info_storages_nextcloud_storage_1") + expect(component.turbo_frame_id).to eq('general_info_storages_nextcloud_storage_1') end end - context "without `context:` option" do - it "returns just the model dom id" do + context 'without `context:` option' do + it 'returns just the model dom id' do storage = build_stubbed(:nextcloud_storage, id: 1) component = described_class.new(storage) - expect(component.turbo_frame_id).to eq("storages_nextcloud_storage_1") + expect(component.turbo_frame_id).to eq('storages_nextcloud_storage_1') end end - context "with `id:` option" do - it "returns the turbo frame id" do - component = described_class.new(id: "test_id") + context 'with `id:` option' do + it 'returns the turbo frame id' do + component = described_class.new(id: 'test_id') - expect(component.turbo_frame_id).to eq("test_id") + expect(component.turbo_frame_id).to eq('test_id') end end - context "with `id:` and `context:` option" do - it "returns the turbo frame id" do - component = described_class.new(id: "test_id", context: :general_info) + context 'with `id:` and `context:` option' do + it 'returns the turbo frame id' do + component = described_class.new(id: 'test_id', context: :general_info) - expect(component.turbo_frame_id).to eq("general_info_test_id") + expect(component.turbo_frame_id).to eq('general_info_test_id') end end end diff --git a/spec/components/open_project/common/duration_component_spec.rb b/spec/components/open_project/common/duration_component_spec.rb index 761186f953d9..7442b65a4789 100644 --- a/spec/components/open_project/common/duration_component_spec.rb +++ b/spec/components/open_project/common/duration_component_spec.rb @@ -9,7 +9,7 @@ subject { described_class.new(duration, type, **args) } - shared_examples "renders a duration" do |duration, type, **args| + shared_examples 'renders a duration' do |duration, type, **args| let(:duration) { duration } let(:type) { type } let(:args) { args } @@ -19,54 +19,54 @@ end end - context "with numeric duration" do - it_behaves_like "renders a duration", 1, :minutes do - let(:expected) { "1 minute" } + context 'with numeric duration' do + it_behaves_like 'renders a duration', 1, :minutes do + let(:expected) { '1 minute' } end - it_behaves_like "renders a duration", 20, :minutes do - let(:expected) { "20 minutes" } + it_behaves_like 'renders a duration', 20, :minutes do + let(:expected) { '20 minutes' } end - it_behaves_like "renders a duration", 63, :minutes do - let(:expected) { "1 hour, 3 minutes" } + it_behaves_like 'renders a duration', 63, :minutes do + let(:expected) { '1 hour, 3 minutes' } end - it_behaves_like "renders a duration", 125, :minutes, abbreviated: true do - let(:expected) { "2 hrs, 5 mins" } + it_behaves_like 'renders a duration', 125, :minutes, abbreviated: true do + let(:expected) { '2 hrs, 5 mins' } end end - context "with ISO8601 duration" do - it_behaves_like "renders a duration", "P3DT12H25M" do - let(:expected) { "3 days, 12 hours, 25 minutes" } + context 'with ISO8601 duration' do + it_behaves_like 'renders a duration', 'P3DT12H25M' do + let(:expected) { '3 days, 12 hours, 25 minutes' } end end - context "with AS::Duration" do - it_behaves_like "renders a duration", 3612.seconds do - let(:expected) { "1 hour, 12 seconds" } + context 'with AS::Duration' do + it_behaves_like 'renders a duration', 3612.seconds do + let(:expected) { '1 hour, 12 seconds' } end - it_behaves_like "renders a duration", 3680.seconds do - let(:expected) { "1 hour, 1 minute, 20 seconds" } + it_behaves_like 'renders a duration', 3680.seconds do + let(:expected) { '1 hour, 1 minute, 20 seconds' } end end - context "when providing an invalid type" do + context 'when providing an invalid type' do let(:duration) { 1234 } let(:type) { :bogus } - it "raises an error" do - expected = "Provide known type (seconds, minutes, hours, days, weeks, months, years) " \ - "when providing a number to this component." + it 'raises an error' do + expected = 'Provide known type (seconds, minutes, hours, days, weeks, months, years) ' \ + 'when providing a number to this component.' expect { subject }.to raise_error(ArgumentError, expected) end end - context "when providing an invalid duration" do + context 'when providing an invalid duration' do let(:duration) { %w[what's this] } let(:type) { :minutes } - it "raises an error" do - expect { subject }.to raise_error(ArgumentError, "Invalid duration type Array.") + it 'raises an error' do + expect { subject }.to raise_error(ArgumentError, 'Invalid duration type Array.') end end end diff --git a/spec/components/work_packages/share/user_details_component_spec.rb b/spec/components/work_packages/share/user_details_component_spec.rb index aeb385aa6ca1..b1337756d103 100644 --- a/spec/components/work_packages/share/user_details_component_spec.rb +++ b/spec/components/work_packages/share/user_details_component_spec.rb @@ -27,7 +27,7 @@ # # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::Share::UserDetailsComponent, type: :component do subject { render_inline(described_class.new(share:, manager_mode:, invite_resent:)) } @@ -35,11 +35,11 @@ shared_let(:project) { create(:project) } shared_let(:work_package) { create(:work_package, project:) } shared_let(:work_package_role) { create(:view_work_package_role) } - shared_let(:project_role) { create(:project_role, name: "Cool role") } + shared_let(:project_role) { create(:project_role, name: 'Cool role') } - shared_let(:user_firstname) { "Richard" } - shared_let(:user_lastname) { "Hendricks" } - shared_let(:group_name) { "Cool group" } + shared_let(:user_firstname) { 'Richard' } + shared_let(:user_lastname) { 'Hendricks' } + shared_let(:group_name) { 'Cool group' } let(:invite_resent) { false } @@ -50,11 +50,11 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p inherited_from: group_membership.member_roles.first.id) end - describe "when not in manager mode" do + describe 'when not in manager mode' do let(:manager_mode) { false } - describe "rendering for a user in a non-active state" do - context "when the user is locked" do + describe 'rendering for a user in a non-active state' do + context 'when the user is locked' do let!(:principal) { create(:user, firstname: user_firstname, lastname: user_lastname, status: :locked) } let!(:share) do create(:work_package_member, @@ -71,7 +71,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "when the user is invited" do + context 'when the user is invited' do let!(:principal) { create(:user, firstname: user_firstname, lastname: user_lastname, status: :invited) } let!(:share) do create(:work_package_member, @@ -80,7 +80,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p roles: [work_package_role]) end - context "and the invite has not been resent" do + context 'and the invite has not been resent' do it do subject @@ -89,7 +89,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the invite has been resent" do + context 'and the invite has been resent' do let(:invite_resent) { true } it do @@ -102,7 +102,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - describe "rendering for a group" do + describe 'rendering for a group' do shared_let(:principal) { create(:group, name: group_name) } shared_let(:share) do create(:work_package_member, @@ -111,7 +111,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p roles: [work_package_role]) end - context "when it is a member in the project" do + context 'when it is a member in the project' do before do create(:member, project:, principal:, roles: [project_role]) end @@ -124,7 +124,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "when it is not a member in the project" do + context 'when it is not a member in the project' do it do subject @@ -134,7 +134,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - describe "rendering for a user" do + describe 'rendering for a user' do shared_let(:principal) { create(:user, firstname: user_firstname, lastname: user_lastname) } shared_let(:share) do create(:work_package_member, @@ -143,8 +143,8 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p roles: [work_package_role]) end - context "when the user is not part of a shared with group" do - context "and the user is not a project member" do + context 'when the user is not part of a shared with group' do + context 'and the user is not a project member' do it do subject @@ -153,7 +153,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the user is a project member" do + context 'and the user is a project member' do before do create(:member, project:, principal:, roles: [project_role]) end @@ -167,7 +167,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "when the user is part of a shared with group" do + context 'when the user is part of a shared with group' do shared_let(:group) { create(:group, name: group_name, members: [principal]) } before do @@ -179,7 +179,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p build_inherited_membership(group_membership: group_share, user_membership: share) end - context "and the user is not a project member" do + context 'and the user is not a project member' do it do subject @@ -188,7 +188,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the user is a project member" do + context 'and the user is a project member' do before do create(:member, project:, principal:, roles: [project_role]) end @@ -204,11 +204,11 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - describe "when in manager mode" do + describe 'when in manager mode' do let(:manager_mode) { true } - describe "rendering for a user in a non-active state" do - context "when the user is locked" do + describe 'rendering for a user in a non-active state' do + context 'when the user is locked' do let!(:principal) { create(:user, firstname: user_firstname, lastname: user_lastname, status: :locked) } let!(:share) do create(:work_package_member, @@ -227,7 +227,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "when the user is invited" do + context 'when the user is invited' do let!(:principal) { create(:user, firstname: user_firstname, lastname: user_lastname, status: :invited) } let!(:share) do create(:work_package_member, @@ -236,7 +236,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p roles: [work_package_role]) end - context "and the invite has not been resent" do + context 'and the invite has not been resent' do it do subject @@ -245,7 +245,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the invite has been resent" do + context 'and the invite has been resent' do let(:invite_resent) { true } it do @@ -258,7 +258,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - describe "rendering for a group" do + describe 'rendering for a group' do shared_let(:principal) { create(:group, name: group_name) } shared_let(:share) do create(:work_package_member, @@ -267,7 +267,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p roles: [work_package_role]) end - context "when it is a member in the project" do + context 'when it is a member in the project' do before do create(:member, project:, principal:, roles: [project_role]) end @@ -280,7 +280,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "when it is not a member in the project" do + context 'when it is not a member in the project' do it do subject @@ -290,7 +290,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - describe "rendering for a user" do + describe 'rendering for a user' do shared_let(:principal) { create(:user, firstname: user_firstname, lastname: user_lastname) } shared_let(:share) do create(:work_package_member, @@ -299,10 +299,10 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p roles: [work_package_role]) end - context "when the user is a project member" do + context 'when the user is a project member' do shared_let(:user_membership) { create(:member, project:, principal:, roles: [project_role]) } - context "and the user is not part of any group" do + context 'and the user is not part of any group' do it do subject @@ -311,10 +311,10 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the user is part of a group" do + context 'and the user is part of a group' do shared_let(:group) { create(:group, name: group_name, members: [principal]) } - context "and the group is a project member itself" do + context 'and the group is a project member itself' do before do group_membership = create(:member, project:, @@ -324,7 +324,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p build_inherited_membership(group_membership:, user_membership:, role: project_role) end - context "and the group is shared with" do + context 'and the group is shared with' do before do group_share = create(:work_package_member, principal: group, @@ -343,7 +343,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the group is not shared with" do + context 'and the group is not shared with' do it do subject @@ -354,8 +354,8 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the group is not a project member itself" do - context "and the group is shared with" do + context 'and the group is not a project member itself' do + context 'and the group is shared with' do before do group_share = create(:work_package_member, principal: group, @@ -374,7 +374,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the group is not shared with" do + context 'and the group is not shared with' do it do subject @@ -387,8 +387,8 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "when the user is not a project member" do - context "and the user is not part of any group" do + context 'when the user is not a project member' do + context 'and the user is not part of any group' do it do subject @@ -397,10 +397,10 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the user is part of a group" do + context 'and the user is part of a group' do shared_let(:group) { create(:group, name: group_name, members: [principal]) } - context "and the group is a project member itself" do + context 'and the group is a project member itself' do before do group_membership = create(:member, project:, principal: group, roles: [project_role]) user_membership = create(:member, project:, principal:, roles: [project_role]) @@ -408,7 +408,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p build_inherited_membership(group_membership:, user_membership:, role: project_role) end - context "and the group is shared with" do + context 'and the group is shared with' do before do group_share = create(:work_package_member, principal: group, @@ -427,7 +427,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the group is not shared with" do + context 'and the group is not shared with' do it do subject @@ -438,8 +438,8 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the group is not a project member itself" do - context "and the group is shared with" do + context 'and the group is not a project member itself' do + context 'and the group is shared with' do before do group_share = create(:work_package_member, principal: group, @@ -458,7 +458,7 @@ def build_inherited_membership(group_membership:, user_membership:, role: work_p end end - context "and the group is not shared with" do + context 'and the group is not shared with' do it do subject diff --git a/spec/constants/settings/definition_spec.rb b/spec/constants/settings/definition_spec.rb index c0e15fb79f06..e66d4b0fd13d 100644 --- a/spec/constants/settings/definition_spec.rb +++ b/spec/constants/settings/definition_spec.rb @@ -26,11 +26,11 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Settings::Definition, :settings_reset do - describe ".add_all" do - it "adds all core setting definitions if they are not loaded" do + describe '.add_all' do + it 'adds all core setting definitions if they are not loaded' do described_class.instance_variable_set(:@all, nil) expect(described_class.all).to eq({}) @@ -39,7 +39,7 @@ expect(described_class.all.keys).to eq(described_class::DEFINITIONS.keys) end - it "does not add any plugin/feature settings if they were removed for some reason" do + it 'does not add any plugin/feature settings if they were removed for some reason' do not_core_settings = described_class.all.keys - described_class::DEFINITIONS.keys expect(not_core_settings).not_to be_empty described_class.instance_variable_set(:@all, nil) @@ -50,7 +50,7 @@ end end - describe ".all" do + describe '.all' do subject(:all) { described_class.all } it "is a hash map of setting definitions" do @@ -58,65 +58,65 @@ expect(all.values).to(be_all { |d| d.is_a?(described_class) }) end - it "contains a definition from settings" do + it 'contains a definition from settings' do expect(all[:smtp_address]).to be_present end - it "contains a definition from configuration" do + it 'contains a definition from configuration' do expect(all[:edition]).to be_present end - it "contains a definition from settings.yml" do + it 'contains a definition from settings.yml' do expect(all[:sendmail_location]).to be_present end - it "casts the value from settings.yml" do + it 'casts the value from settings.yml' do expect(all[:brute_force_block_after_failed_logins].value).to eq(20) end - context "when overriding from ENV", + context 'when overriding from ENV', with_env: { - "OPENPROJECT_EDITION" => "bim", - "OPENPROJECT_DEFAULT__LANGUAGE" => "de" + 'OPENPROJECT_EDITION' => 'bim', + 'OPENPROJECT_DEFAULT__LANGUAGE' => 'de' } do - it "allows overriding configuration from ENV with OPENPROJECT_ prefix with double underscore case (legacy)" do + it 'allows overriding configuration from ENV with OPENPROJECT_ prefix with double underscore case (legacy)' do reset(:edition) reset(:default_language) - expect(all[:edition].value).to eql "bim" - expect(all[:default_language].value).to eql "de" + expect(all[:edition].value).to eql 'bim' + expect(all[:default_language].value).to eql 'de' end - it "allows overriding configuration from ENV with OPENPROJECT_ prefix with single underscore case", - with_env: { "OPENPROJECT_DEFAULT_LANGUAGE" => "de" } do + it 'allows overriding configuration from ENV with OPENPROJECT_ prefix with single underscore case', + with_env: { 'OPENPROJECT_DEFAULT_LANGUAGE' => 'de' } do reset(:default_language) - expect(all[:default_language].value).to eql "de" + expect(all[:default_language].value).to eql 'de' end - it "allows overriding configuration from ENV without OPENPROJECT_ prefix", - with_env: { "EDITION" => "bim" } do + it 'allows overriding configuration from ENV without OPENPROJECT_ prefix', + with_env: { 'EDITION' => 'bim' } do reset(:edition) - expect(all[:edition].value).to eql "bim" + expect(all[:edition].value).to eql 'bim' end - it "does not allows overriding configuration from ENV without OPENPROJECT_ prefix if setting is writable", - with_env: { "DEFAULT_LANGUAGE" => "de" } do + it 'does not allows overriding configuration from ENV without OPENPROJECT_ prefix if setting is writable', + with_env: { 'DEFAULT_LANGUAGE' => 'de' } do reset(:default_language) - expect(all[:default_language].value).to eql "en" + expect(all[:default_language].value).to eql 'en' end - it "allows overriding email/smtp configuration from ENV without OPENPROJECT_ prefix even though setting is writable", + it 'allows overriding email/smtp configuration from ENV without OPENPROJECT_ prefix even though setting is writable', with_env: { - "EMAIL_DELIVERY_CONFIGURATION" => "legacy", - "EMAIL_DELIVERY_METHOD" => "smtp", - "SMTP_ADDRESS" => "smtp.somedomain.org", - "SMTP_AUTHENTICATION" => "something", - "SMTP_DOMAIN" => "email.bogus.abc", - "SMTP_ENABLE_STARTTLS_AUTO" => "true", - "SMTP_PASSWORD" => "password", - "SMTP_PORT" => "987", - "SMTP_USER_NAME" => "user", - "SMTP_SSL" => "true" + 'EMAIL_DELIVERY_CONFIGURATION' => 'legacy', + 'EMAIL_DELIVERY_METHOD' => 'smtp', + 'SMTP_ADDRESS' => 'smtp.somedomain.org', + 'SMTP_AUTHENTICATION' => 'something', + 'SMTP_DOMAIN' => 'email.bogus.abc', + 'SMTP_ENABLE_STARTTLS_AUTO' => 'true', + 'SMTP_PASSWORD' => 'password', + 'SMTP_PORT' => '987', + 'SMTP_USER_NAME' => 'user', + 'SMTP_SSL' => 'true' } do reset(:email_delivery_configuration) reset(:email_delivery_method) @@ -129,143 +129,143 @@ reset(:smtp_user_name) reset(:smtp_ssl) - expect(all[:email_delivery_configuration].value).to eql "legacy" + expect(all[:email_delivery_configuration].value).to eql 'legacy' expect(all[:email_delivery_method].value).to eq :smtp - expect(all[:smtp_address].value).to eql "smtp.somedomain.org" - expect(all[:smtp_authentication].value).to eql "something" - expect(all[:smtp_domain].value).to eql "email.bogus.abc" + expect(all[:smtp_address].value).to eql 'smtp.somedomain.org' + expect(all[:smtp_authentication].value).to eql 'something' + expect(all[:smtp_domain].value).to eql 'email.bogus.abc' expect(all[:smtp_enable_starttls_auto].value).to be true - expect(all[:smtp_password].value).to eql "password" + expect(all[:smtp_password].value).to eql 'password' expect(all[:smtp_port].value).to eq 987 - expect(all[:smtp_user_name].value).to eq "user" + expect(all[:smtp_user_name].value).to eq 'user' expect(all[:smtp_ssl].value).to be true end - it "logs a deprecation warning when overriding configuration from ENV without OPENPROJECT_ prefix", - with_env: { "EDITION" => "bim" } do + it 'logs a deprecation warning when overriding configuration from ENV without OPENPROJECT_ prefix', + with_env: { 'EDITION' => 'bim' } do allow(Rails.logger).to receive(:warn) reset(:edition) - expect(all[:edition].value).to eql "bim" + expect(all[:edition].value).to eql 'bim' expect(Rails.logger).to have_received(:warn) .with(a_string_including("use OPENPROJECT_EDITION instead of EDITION")) end - it "overriding boolean configuration from ENV will cast the value", - with_env: { "OPENPROJECT_REST__API__ENABLED" => "0" } do + it 'overriding boolean configuration from ENV will cast the value', + with_env: { 'OPENPROJECT_REST__API__ENABLED' => '0' } do reset(:rest_api_enabled) expect(all[:rest_api_enabled].value).to be false end - it "overriding symbol configuration having allowed values from ENV will cast the value before validation check", - with_env: { "OPENPROJECT_RAILS__CACHE__STORE" => "memcache" } do + it 'overriding symbol configuration having allowed values from ENV will cast the value before validation check', + with_env: { 'OPENPROJECT_RAILS__CACHE__STORE' => 'memcache' } do reset(:rails_cache_store) expect(all[:rails_cache_store].value).to eq :memcache end - it "overriding datetime configuration from ENV will cast the value", - with_env: { "OPENPROJECT_CONSENT__TIME" => "2222-01-01" } do + it 'overriding datetime configuration from ENV will cast the value', + with_env: { 'OPENPROJECT_CONSENT__TIME' => '2222-01-01' } do reset(:consent_time) - expect(all[:consent_time].value).to eql DateTime.parse("2222-01-01") + expect(all[:consent_time].value).to eql DateTime.parse('2222-01-01') end - it "overriding timezone configuration from ENV will cast the value", - with_env: { "OPENPROJECT_USER__DEFAULT__TIMEZONE" => "Europe/Berlin" } do + it 'overriding timezone configuration from ENV will cast the value', + with_env: { 'OPENPROJECT_USER__DEFAULT__TIMEZONE' => 'Europe/Berlin' } do reset(:user_default_timezone) - expect(all[:user_default_timezone].value).to eq "Europe/Berlin" + expect(all[:user_default_timezone].value).to eq 'Europe/Berlin' end - it "overriding timezone configuration from ENV with a bogus value", - with_env: { "OPENPROJECT_USER__DEFAULT__TIMEZONE" => "foobar" } do + it 'overriding timezone configuration from ENV with a bogus value', + with_env: { 'OPENPROJECT_USER__DEFAULT__TIMEZONE' => 'foobar' } do expect { reset(:user_default_timezone) }.to raise_error(ArgumentError) end - it "overriding configuration from ENV will set it to non writable", - with_env: { "OPENPROJECT_EDITION" => "bim" } do + it 'overriding configuration from ENV will set it to non writable', + with_env: { 'OPENPROJECT_EDITION' => 'bim' } do reset(:edition) expect(all[:edition]).not_to be_writable end - it "allows overriding settings array from ENV", - with_env: { "OPENPROJECT_PASSWORD__ACTIVE__RULES" => YAML.dump(["lowercase"]) } do + it 'allows overriding settings array from ENV', + with_env: { 'OPENPROJECT_PASSWORD__ACTIVE__RULES' => YAML.dump(['lowercase']) } do reset(:password_active_rules) - expect(all[:password_active_rules].value).to eql ["lowercase"] + expect(all[:password_active_rules].value).to eql ['lowercase'] end - it "overriding settings from ENV will set it to non writable", - with_env: { "OPENPROJECT_WELCOME__TITLE" => "Some title" } do + it 'overriding settings from ENV will set it to non writable', + with_env: { 'OPENPROJECT_WELCOME__TITLE' => 'Some title' } do reset(:welcome_title) expect(all[:welcome_title]).not_to be_writable end - it "allows overriding settings hash partially from ENV", - with_env: { "OPENPROJECT_REPOSITORY__CHECKOUT__DATA_GIT_ENABLED" => "1" } do + it 'allows overriding settings hash partially from ENV', + with_env: { 'OPENPROJECT_REPOSITORY__CHECKOUT__DATA_GIT_ENABLED' => '1' } do reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "git" => { "enabled" => 1 }, - "subversion" => { "enabled" => 0 } + 'git' => { 'enabled' => 1 }, + 'subversion' => { 'enabled' => 0 } }) end - it "allows overriding settings hash partially from ENV with single underscore name", - with_env: { "OPENPROJECT_REPOSITORY_CHECKOUT_DATA_GIT_ENABLED" => "1" } do + it 'allows overriding settings hash partially from ENV with single underscore name', + with_env: { 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA_GIT_ENABLED' => '1' } do reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "git" => { "enabled" => 1 }, - "subversion" => { "enabled" => 0 } + 'git' => { 'enabled' => 1 }, + 'subversion' => { 'enabled' => 0 } }) end - it "allows overriding settings hash partially from ENV with yaml data", - with_env: { "OPENPROJECT_REPOSITORY_CHECKOUT_DATA" => "{git: {enabled: 1}}" } do + it 'allows overriding settings hash partially from ENV with yaml data', + with_env: { 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA' => '{git: {enabled: 1}}' } do reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "git" => { "enabled" => 1 }, - "subversion" => { "enabled" => 0 } + 'git' => { 'enabled' => 1 }, + 'subversion' => { 'enabled' => 0 } }) end - it "allows overriding settings hash fully from repeated ENV values" do + it 'allows overriding settings hash fully from repeated ENV values' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_REPOSITORY__CHECKOUT__DATA" => "{hg: {enabled: 0}}", - "OPENPROJECT_REPOSITORY__CHECKOUT__DATA_CVS_ENABLED" => "0", - "OPENPROJECT_REPOSITORY_CHECKOUT_DATA_GIT_ENABLED" => "1", - "OPENPROJECT_REPOSITORY_CHECKOUT_DATA_GIT_MINIMUM__VERSION" => "42", - "OPENPROJECT_REPOSITORY_CHECKOUT_DATA_SUBVERSION_ENABLED" => "1" + 'OPENPROJECT_REPOSITORY__CHECKOUT__DATA' => '{hg: {enabled: 0}}', + 'OPENPROJECT_REPOSITORY__CHECKOUT__DATA_CVS_ENABLED' => '0', + 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA_GIT_ENABLED' => '1', + 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA_GIT_MINIMUM__VERSION' => '42', + 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA_SUBVERSION_ENABLED' => '1' } ) reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "cvs" => { "enabled" => 0 }, - "git" => { "enabled" => 1, "minimum_version" => 42 }, - "hg" => { "enabled" => 0 }, - "subversion" => { "enabled" => 1 } + 'cvs' => { 'enabled' => 0 }, + 'git' => { 'enabled' => 1, 'minimum_version' => 42 }, + 'hg' => { 'enabled' => 0 }, + 'subversion' => { 'enabled' => 1 } }) end - it "allows overriding settings hash fully from ENV with yaml data" do + it 'allows overriding settings hash fully from ENV with yaml data' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_REPOSITORY_CHECKOUT_DATA" => '{git: {enabled: 1, key: "42"}, cvs: {enabled: 0}}' + 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA' => '{git: {enabled: 1, key: "42"}, cvs: {enabled: 0}}' } ) reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "git" => { "enabled" => 1, "key" => "42" }, - "cvs" => { "enabled" => 0 }, - "subversion" => { "enabled" => 0 } + 'git' => { 'enabled' => 1, 'key' => '42' }, + 'cvs' => { 'enabled' => 0 }, + 'subversion' => { 'enabled' => 0 } }) end - it "allows overriding settings hash fully from ENV with yaml data multiline" do + it 'allows overriding settings hash fully from ENV with yaml data multiline' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_REPOSITORY_CHECKOUT_DATA" => <<~YML + 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA' => <<~YML --- git: enabled: 1 @@ -277,113 +277,113 @@ ) reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "git" => { "enabled" => 1, "key" => "42" }, - "cvs" => { "enabled" => 0 }, - "subversion" => { "enabled" => 0 } + 'git' => { 'enabled' => 1, 'key' => '42' }, + 'cvs' => { 'enabled' => 0 }, + 'subversion' => { 'enabled' => 0 } }) end - it "allows overriding settings hash fully from ENV with json data" do + it 'allows overriding settings hash fully from ENV with json data' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_REPOSITORY_CHECKOUT_DATA" => '{"git": {"enabled": 1, "key": "42"}, "cvs": {"enabled": 0}}' + 'OPENPROJECT_REPOSITORY_CHECKOUT_DATA' => '{"git": {"enabled": 1, "key": "42"}, "cvs": {"enabled": 0}}' } ) reset(:repository_checkout_data) expect(all[:repository_checkout_data].value).to eql({ - "git" => { "enabled" => 1, "key" => "42" }, - "cvs" => { "enabled" => 0 }, - "subversion" => { "enabled" => 0 } + 'git' => { 'enabled' => 1, 'key' => '42' }, + 'cvs' => { 'enabled' => 0 }, + 'subversion' => { 'enabled' => 0 } }) end - it "allows overriding configuration array from ENV with yaml/json data" do + it 'allows overriding configuration array from ENV with yaml/json data' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_BLACKLISTED_ROUTES" => '["admin/info", "admin/plugins"]' + 'OPENPROJECT_BLACKLISTED_ROUTES' => '["admin/info", "admin/plugins"]' } ) reset(:blacklisted_routes) - expect(all[:blacklisted_routes].value).to eq(["admin/info", "admin/plugins"]) + expect(all[:blacklisted_routes].value).to eq(['admin/info', 'admin/plugins']) end - it "allows overriding configuration array from ENV with space separated string" do + it 'allows overriding configuration array from ENV with space separated string' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_BLACKLISTED_ROUTES" => "admin/info admin/plugins" + 'OPENPROJECT_BLACKLISTED_ROUTES' => 'admin/info admin/plugins' } ) reset(:blacklisted_routes) expect(OpenProject::Configuration.blacklisted_routes) - .to eq(["admin/info", "admin/plugins"]) + .to eq(['admin/info', 'admin/plugins']) expect(Setting.blacklisted_routes) - .to eq(["admin/info", "admin/plugins"]) + .to eq(['admin/info', 'admin/plugins']) end - it "allows overriding configuration array from ENV with single string" do + it 'allows overriding configuration array from ENV with single string' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_DISABLED__MODULES" => "repository" + 'OPENPROJECT_DISABLED__MODULES' => 'repository' } ) reset(:disabled_modules) expect(OpenProject::Configuration.disabled_modules) - .to eq(["repository"]) + .to eq(['repository']) expect(Setting.disabled_modules) - .to eq(["repository"]) + .to eq(['repository']) end - context "with definitions from plugins" do - it "allows overriding settings hash partially from ENV with aliased env name" do + context 'with definitions from plugins' do + it 'allows overriding settings hash partially from ENV with aliased env name' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_2FA_ENFORCED" => "true", - "OPENPROJECT_2FA_ALLOW__REMEMBER__FOR__DAYS" => "15" + 'OPENPROJECT_2FA_ENFORCED' => 'true', + 'OPENPROJECT_2FA_ALLOW__REMEMBER__FOR__DAYS' => '15' } ) # override from env manually because these settings are added by plugin itself described_class.send(:override_value, all[:plugin_openproject_two_factor_authentication]) expect(all[:plugin_openproject_two_factor_authentication].value).to eq( - "active_strategies" => %i[totp webauthn], - "enforced" => true, - "allow_remember_for_days" => 15 + 'active_strategies' => %i[totp webauthn], + 'enforced' => true, + 'allow_remember_for_days' => 15 ) end - it "allows overriding settings hash from ENV with aliased env name" do + it 'allows overriding settings hash from ENV with aliased env name' do stub_const( - "ENV", + 'ENV', { - "OPENPROJECT_2FA" => '{"enforced": true, "allow_remember_for_days": 15}' + 'OPENPROJECT_2FA' => '{"enforced": true, "allow_remember_for_days": 15}' } ) # override from env manually because these settings are added by plugin itself described_class.send(:override_value, all[:plugin_openproject_two_factor_authentication]) expect(all[:plugin_openproject_two_factor_authentication].value) - .to eq({ "active_strategies" => %i[totp webauthn], "enforced" => true, "allow_remember_for_days" => 15 }) + .to eq({ 'active_strategies' => %i[totp webauthn], 'enforced' => true, 'allow_remember_for_days' => 15 }) end end - it "does not handle ENV vars for which no definition exists", - with_env: { "OPENPROJECT_BOGUS" => "1234" } do + it 'does not handle ENV vars for which no definition exists', + with_env: { 'OPENPROJECT_BOGUS' => '1234' } do expect(all[:bogus]).to be_nil end - it "handles ENV vars for definitions added after #all was called (e.g. in a module)", - with_env: { "OPENPROJECT_BOGUS" => "1" } do + it 'handles ENV vars for definitions added after #all was called (e.g. in a module)', + with_env: { 'OPENPROJECT_BOGUS' => '1' } do described_class.add(:bogus, default: 0) expect(all[:bogus].value).to eq 1 end end - context "when overriding from file" do + context 'when overriding from file' do let(:configuration_yml) do <<~YAML --- @@ -403,74 +403,74 @@ before { stub_configuration_yml } - it "overrides from file default" do + it 'overrides from file default' do reset(:edition) - expect(all[:edition].value).to eql "bim" + expect(all[:edition].value).to eql 'bim' end - it "marks the value overwritten from file default unwritable" do + it 'marks the value overwritten from file default unwritable' do reset(:edition) expect(all[:edition]).not_to be_writable end - it "overrides from file default path but once again from current env" do + it 'overrides from file default path but once again from current env' do reset(:sendmail_location) - expect(all[:sendmail_location].value).to eql "test location" + expect(all[:sendmail_location].value).to eql 'test location' end - it "marks the value overwritten from file default and again from current unwritable" do + it 'marks the value overwritten from file default and again from current unwritable' do reset(:sendmail_location) expect(all[:sendmail_location]).not_to be_writable end - it "overrides from file current env" do + it 'overrides from file current env' do reset(:smtp_address) - expect(all[:smtp_address].value).to eql "test address" + expect(all[:smtp_address].value).to eql 'test address' end - it "marks the value overwritten from file current unwritable" do + it 'marks the value overwritten from file current unwritable' do reset(:smtp_address) expect(all[:smtp_address]).not_to be_writable end - it "does not accept undefined settings" do + it 'does not accept undefined settings' do expect(all[:bogus]).to be_nil end - it "correctly parses date objects" do + it 'correctly parses date objects' do reset(:consent_time) expect(all[:consent_time].value).to eql DateTime.parse("2222-01-01") end - it "correctly converts a space separated string into array for array format" do + it 'correctly converts a space separated string into array for array format' do reset(:disabled_modules) - expect(all[:disabled_modules].value).to eq ["repository"] + expect(all[:disabled_modules].value).to eq ['repository'] reset(:blacklisted_routes) - expect(all[:blacklisted_routes].value).to eq ["admin/info", "admin/plugins"] + expect(all[:blacklisted_routes].value).to eq ['admin/info', 'admin/plugins'] end - it "correctly overrides a default by a false value" do + it 'correctly overrides a default by a false value' do reset(:direct_uploads) expect(all[:direct_uploads].value).to be false end - context "when Rails environment is test" do + context 'when Rails environment is test' do before do allow(Rails.env).to receive(:test?).and_return(true) end - it "does not override from file default" do + it 'does not override from file default' do reset(:edition) - expect(all[:edition].value).not_to eql "bim" + expect(all[:edition].value).not_to eql 'bim' end - it "overrides from file current env" do + it 'overrides from file current env' do reset(:smtp_address) - expect(all[:smtp_address].value).to eql "test address" + expect(all[:smtp_address].value).to eql 'test address' end end - context "when having invalid values in the file" do + context 'when having invalid values in the file' do let(:configuration_yml) do <<~YAML --- @@ -479,30 +479,30 @@ YAML end - it "is invalid" do + it 'is invalid' do expect do reset(:smtp_openssl_verify_mode) end.to raise_error ArgumentError end end - context "when overwritten from ENV", - with_env: { "OPENPROJECT_SENDMAIL__LOCATION" => "env location" } do - it "overrides from ENV" do + context 'when overwritten from ENV', + with_env: { 'OPENPROJECT_SENDMAIL__LOCATION' => 'env location' } do + it 'overrides from ENV' do reset(:sendmail_location) - expect(all[:sendmail_location].value).to eql "env location" + expect(all[:sendmail_location].value).to eql 'env location' end - it "marks the overwritten value unwritable" do + it 'marks the overwritten value unwritable' do reset(:sendmail_location) expect(all[:sendmail_location]).not_to be_writable end end end - context "when adding an additional setting" do - it "includes the setting" do - described_class.add("bogus", default: 1, format: :integer) + context 'when adding an additional setting' do + it 'includes the setting' do + described_class.add('bogus', default: 1, format: :integer) expect(all[:bogus].value).to eq(1) end end @@ -511,84 +511,84 @@ describe ".[name]" do subject(:definition) { described_class[key] } - context "with a string" do - let(:key) { "smtp_address" } + context 'with a string' do + let(:key) { 'smtp_address' } - it "returns the definition matching the name" do + it 'returns the definition matching the name' do expect(definition.name) .to eql key end end - context "with a symbol" do + context 'with a symbol' do let(:key) { :smtp_address } - it "returns the definition matching the name" do + it 'returns the definition matching the name' do expect(definition.name) .to eql key.to_s end end - context "with a non existing key" do - let(:key) { "bogus" } + context 'with a non existing key' do + let(:key) { 'bogus' } - it "returns nil" do + it 'returns nil' do expect(definition) .to be_nil end end - context "when adding a setting late", :settings_reset do - let(:key) { "bogus" } + context 'when adding a setting late', :settings_reset do + let(:key) { 'bogus' } before do described_class[key] - described_class.add "bogus", + described_class.add 'bogus', default: 1, format: :integer end - it "has the setting" do + it 'has the setting' do expect(definition.name) .to eql key.to_s end end end - describe "#override_value" do + describe '#override_value' do let(:format) { :string } - let(:default) { "abc" } + let(:default) { 'abc' } let(:instance) do described_class - .new "bogus", + .new 'bogus', format:, default: end - context "with string format" do + context 'with string format' do before do - instance.override_value("xyz") + instance.override_value('xyz') end - it "overwrites the value" do + it 'overwrites the value' do expect(instance.value) - .to eql "xyz" + .to eql 'xyz' end - it "does not overwrite the default" do + it 'does not overwrite the default' do expect(instance.default) - .to eql "abc" + .to eql 'abc' end - it "turns the definition unwritable" do + it 'turns the definition unwritable' do expect(instance) .not_to be_writable end end - context "with hash format" do + context 'with hash format' do let(:format) { :hash } let(:default) do { @@ -601,39 +601,39 @@ end before do - instance.override_value({ abc: { "a" => 5 }, xyz: 2 }) + instance.override_value({ abc: { 'a' => 5 }, xyz: 2 }) end - it "deep merges and transforms keys to string" do + it 'deep merges and transforms keys to string' do expect(instance.value) .to eql({ - "abc" => { - "a" => 5, - "b" => 2 + 'abc' => { + 'a' => 5, + 'b' => 2 }, - "cde" => 1, - "xyz" => 2 + 'cde' => 1, + 'xyz' => 2 }) end - it "does not overwrite the default" do + it 'does not overwrite the default' do expect(instance.default) .to eql({ - "abc" => { - "a" => 1, - "b" => 2 + 'abc' => { + 'a' => 1, + 'b' => 2 }, - "cde" => 1 + 'cde' => 1 }) end - it "turns the definition unwritable" do + it 'turns the definition unwritable' do expect(instance) .not_to be_writable end end - context "with array format" do + context 'with array format' do let(:format) { :array } let(:default) { [1, 2, 3] } @@ -641,323 +641,323 @@ instance.override_value([4, 5, 6]) end - it "overwrites the value" do + it 'overwrites the value' do expect(instance.value) .to eql [4, 5, 6] end - it "does not overwrite the default" do + it 'does not overwrite the default' do expect(instance.default) .to eql [1, 2, 3] end - it "turns the definition unwritable" do + it 'turns the definition unwritable' do expect(instance) .not_to be_writable end end - context "with an invalid value" do + context 'with an invalid value' do let(:instance) do described_class - .new "bogus", + .new 'bogus', format:, - default: "foo", + default: 'foo', allowed: %w[foo bar] end - it "raises an error" do - expect { instance.override_value("invalid") } + it 'raises an error' do + expect { instance.override_value('invalid') } .to raise_error ArgumentError end end end - describe ".exists?" do - context "with an existing setting" do - it "is truthy" do + describe '.exists?' do + context 'with an existing setting' do + it 'is truthy' do expect(described_class) - .to exist("smtp_address") + .to exist('smtp_address') end end - context "with a non existing setting" do - it "is truthy" do + context 'with a non existing setting' do + it 'is truthy' do expect(described_class) - .not_to exist("foobar") + .not_to exist('foobar') end end end - describe ".new" do - context "with all the attributes" do + describe '.new' do + context 'with all the attributes' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', format: :integer, default: 1, writable: false, allowed: [1, 2, 3] end - it "has the name" do + it 'has the name' do expect(instance.name) - .to eql "bogus" + .to eql 'bogus' end - it "has the format (in symbol)" do + it 'has the format (in symbol)' do expect(instance.format) .to eq :integer end - it "has the default" do + it 'has the default' do expect(instance.default) .to eq 1 end - it "has the value" do + it 'has the value' do expect(instance.value) .to eq 1 end - it "is not serialized" do + it 'is not serialized' do expect(instance) .not_to be_serialized end - it "has the writable value" do + it 'has the writable value' do expect(instance) .not_to be_writable end - it "has the allowed value" do + it 'has the allowed value' do expect(instance.allowed) .to eql [1, 2, 3] end end - context "with the minimal attributes (integer value)" do + context 'with the minimal attributes (integer value)' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', default: 1 end - it "has the name" do + it 'has the name' do expect(instance.name) - .to eql "bogus" + .to eql 'bogus' end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :integer end - it "has the default" do + it 'has the default' do expect(instance.default) .to eq 1 end - it "has the default frozen" do + it 'has the default frozen' do expect(instance.default) .to be_frozen end - it "has the value" do + it 'has the value' do expect(instance.value) .to eq 1 end - it "is not serialized" do + it 'is not serialized' do expect(instance) .not_to be_serialized end - it "has the writable value" do + it 'has the writable value' do expect(instance) .to be_writable end end - context "with the minimal attributes (hash value)" do + context 'with the minimal attributes (hash value)' do let(:instance) do - described_class.new "bogus", - default: { a: "b", c: { d: "e" } } + described_class.new 'bogus', + default: { a: 'b', c: { d: 'e' } } end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :hash end - it "is serialized" do + it 'is serialized' do expect(instance) .to be_serialized end - it "has the default frozen" do + it 'has the default frozen' do expect(instance.default) .to be_frozen end - it "transforms keys to string" do + it 'transforms keys to string' do expect(instance.value) .to eq({ - "a" => "b", - "c" => { "d" => "e" } + 'a' => 'b', + 'c' => { 'd' => 'e' } }) end end - context "with the minimal attributes (array value)" do + context 'with the minimal attributes (array value)' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', default: %i[a b] end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :array end - it "is serialized" do + it 'is serialized' do expect(instance) .to be_serialized end end - context "with the minimal attributes (true value)" do + context 'with the minimal attributes (true value)' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', default: true end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :boolean end end - context "with the minimal attributes (false value)" do + context 'with the minimal attributes (false value)' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', default: false end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :boolean end end - context "with the minimal attributes (date value)" do + context 'with the minimal attributes (date value)' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', default: Time.zone.today end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :date end end - context "with the minimal attributes (datetime value)" do + context 'with the minimal attributes (datetime value)' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', default: DateTime.now end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :date_time end end - context "with the minimal attributes (string value)" do + context 'with the minimal attributes (string value)' do let(:instance) do - described_class.new "bogus", - default: "abc" + described_class.new 'bogus', + default: 'abc' end - it "has the format (in symbol) deduced" do + it 'has the format (in symbol) deduced' do expect(instance.format) .to eq :string end end - context "with procs for value, writable and allowed" do + context 'with procs for value, writable and allowed' do let(:instance) do - described_class.new "bogus", - format: "string", - default: -> { "some value" }, + described_class.new 'bogus', + format: 'string', + default: -> { 'some value' }, writable: -> { false }, allowed: -> { %w[a b c] } end - it "returns the procs return value for default" do + it 'returns the procs return value for default' do expect(instance.default) - .to eql "some value" + .to eql 'some value' end - it "returns the procs return value for value" do + it 'returns the procs return value for value' do expect(instance.value) - .to eql "some value" + .to eql 'some value' end - it "returns the procs return value for writable" do + it 'returns the procs return value for writable' do expect(instance) .not_to be_writable end - it "returns the procs return value for allowed" do + it 'returns the procs return value for allowed' do expect(instance.allowed) .to eql %w[a b c] end end - context "with an integer provided as a string" do + context 'with an integer provided as a string' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', format: :integer, - default: "5" + default: '5' end - it "returns default as an int" do + it 'returns default as an int' do expect(instance.default) .to eq 5 end - it "returns value as an int" do + it 'returns value as an int' do expect(instance.value) .to eq 5 end end - context "with a float provided as a string" do + context 'with a float provided as a string' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', format: :float, - default: "0.5" + default: '0.5' end - it "returns default as a float" do + it 'returns default as a float' do expect(instance.default) .to eq 0.5 end - it "returns value as a float" do + it 'returns value as a float' do expect(instance.value) .to eq 0.5 end end - context "with a boolean provided with a proc default" do + context 'with a boolean provided with a proc default' do let(:instance) do - described_class.new "bogus", + described_class.new 'bogus', format: :boolean, default: -> { false } end - it "calls the proc as a default" do + it 'calls the proc as a default' do expect(instance.default) .to be false end diff --git a/spec/contracts/attachments/create_contract_integration_spec.rb b/spec/contracts/attachments/create_contract_integration_spec.rb index 5fe9d1563b41..93ffad7eed5c 100644 --- a/spec/contracts/attachments/create_contract_integration_spec.rb +++ b/spec/contracts/attachments/create_contract_integration_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.describe Attachments::CreateContract, "integration" do - include_context "ModelContract shared context" +RSpec.describe Attachments::CreateContract, 'integration' do + include_context 'ModelContract shared context' let(:model) do build(:attachment, @@ -48,36 +48,36 @@ let(:file) do Rack::Test::UploadedFile.new( Rails.root.join("spec/fixtures/files/image.png"), - "image/png", + 'image/png', true ) end - let(:content_type) { "image/png" } - let(:filename) { "image.png" } + let(:content_type) { 'image/png' } + let(:filename) { 'image.png' } - context "with anonymous user that can view the project" do + context 'with anonymous user that can view the project' do current_user do create(:anonymous_role, permissions: %i[view_project]) User.anonymous end - describe "uncontainered" do - it_behaves_like "contract is invalid", base: :error_unauthorized + describe 'uncontainered' do + it_behaves_like 'contract is invalid', base: :error_unauthorized end - describe "invalid container" do + describe 'invalid container' do let(:container) { build_stubbed(:work_package) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - describe "valid container" do + describe 'valid container' do # create a project so that the anonymous permission has something to attach to let!(:project) { create(:project, public: true) } let(:container) { build_stubbed(:project_export) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end end diff --git a/spec/contracts/attachments/create_contract_spec.rb b/spec/contracts/attachments/create_contract_spec.rb index 26dc11f1fb4f..1c9443e56723 100644 --- a/spec/contracts/attachments/create_contract_spec.rb +++ b/spec/contracts/attachments/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Attachments::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:model) do @@ -49,12 +49,12 @@ let(:file) do Rack::Test::UploadedFile.new( Rails.root.join("spec/fixtures/files/image.png"), - "image/png", + 'image/png', true ) end - let(:content_type) { "image/png" } - let(:filename) { "image.png" } + let(:content_type) { 'image/png' } + let(:filename) { 'image.png' } let(:can_attach_global) { true } @@ -63,23 +63,23 @@ .to receive(:none?).and_return(!can_attach_global) end - context "with user who has no permissions" do + context 'with user who has no permissions' do let(:can_attach_global) { false } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "with a user that is not the author" do + context 'with a user that is not the author' do let(:user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", author: :invalid + it_behaves_like 'contract is invalid', author: :invalid end - context "with user who has permissions to add" do - it_behaves_like "contract is valid" + context 'with user who has permissions to add' do + it_behaves_like 'contract is valid' end - context "with a container" do + context 'with a container' do let(:container) { build_stubbed(:work_package) } before do @@ -89,54 +89,54 @@ .and_return(can_attach) end - context "with user who has no permissions" do + context 'with user who has no permissions' do let(:can_attach) { false } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "with user who has permissions to add" do + context 'with user who has permissions to add' do let(:can_attach) { true } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - context "with an empty whitelist", + context 'with an empty whitelist', with_settings: { attachment_whitelist: %w[] } do - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a matching mime whitelist", + context 'with a matching mime whitelist', with_settings: { attachment_whitelist: %w[image/png] } do - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a matching extension whitelist", + context 'with a matching extension whitelist', with_settings: { attachment_whitelist: %w[*.png] } do - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a non-matching whitelist", + context 'with a non-matching whitelist', with_settings: { attachment_whitelist: %w[*.jpg image/jpeg] } do - it_behaves_like "contract is invalid", content_type: :not_whitelisted + it_behaves_like 'contract is invalid', content_type: :not_whitelisted - context "when disabling the whitelist check" do + context 'when disabling the whitelist check' do let(:contract_options) do { whitelist: [] } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when overriding the whitelist" do + context 'when overriding the whitelist' do let(:contract_options) do { whitelist: %w[*.png] } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/attribute_help_texts/base_contract_spec.rb b/spec/contracts/attribute_help_texts/base_contract_spec.rb index 662c9dad3e0a..22db06452055 100644 --- a/spec/contracts/attribute_help_texts/base_contract_spec.rb +++ b/spec/contracts/attribute_help_texts/base_contract_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe AttributeHelpTexts::BaseContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:model) { build_stubbed(:work_package_help_text) } let(:contract) { described_class.new(model, current_user) } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' end diff --git a/spec/contracts/authentication/omniauth_auth_hash_contract_spec.rb b/spec/contracts/authentication/omniauth_auth_hash_contract_spec.rb index 048dc193e02c..d2fb12e7302a 100644 --- a/spec/contracts/authentication/omniauth_auth_hash_contract_spec.rb +++ b/spec/contracts/authentication/omniauth_auth_hash_contract_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authentication::OmniauthAuthHashContract do let(:auth_hash) do OmniAuth::AuthHash.new( - provider: "google", - uid: "123545", - info: { name: "foo", - email: "foo@bar.com", - first_name: "foo", - last_name: "bar" } + provider: 'google', + uid: '123545', + info: { name: 'foo', + email: 'foo@bar.com', + first_name: 'foo', + last_name: 'bar' } ) end @@ -47,57 +47,57 @@ instance end - shared_examples_for "has error on" do |property, message| + shared_examples_for 'has error on' do |property, message| it property do expect(subject.errors[property]).to include message end end - shared_examples_for "is valid" do - it "is valid" do + shared_examples_for 'is valid' do + it 'is valid' do expect(subject).to be_valid expect(subject.errors).to be_empty end end - describe "#validate_auth_hash" do - context "if valid" do - it_behaves_like "is valid" + describe '#validate_auth_hash' do + context 'if valid' do + it_behaves_like 'is valid' end - context "if invalid" do + context 'if invalid' do before do allow(auth_hash).to receive(:valid?).and_return false end - it_behaves_like "has error on", :base, I18n.t(:error_omniauth_invalid_auth) + it_behaves_like 'has error on', :base, I18n.t(:error_omniauth_invalid_auth) end end - describe "#validate_auth_hash_not_expired" do - context "hash contains valid timestamp" do + describe '#validate_auth_hash_not_expired' do + context 'hash contains valid timestamp' do before do auth_hash[:timestamp] = Time.now end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "hash contains invalid timestamp" do + context 'hash contains invalid timestamp' do before do auth_hash[:timestamp] = Time.now - 1.hour end - it_behaves_like "has error on", :base, I18n.t(:error_omniauth_registration_timed_out) + it_behaves_like 'has error on', :base, I18n.t(:error_omniauth_registration_timed_out) end - context "hash contains no timestamp" do - it_behaves_like "is valid" + context 'hash contains no timestamp' do + it_behaves_like 'is valid' end end - describe "#validate_authorization_callback" do - let(:auth_double) { double("Authorization", approve?: authorized, message:) } + describe '#validate_authorization_callback' do + let(:auth_double) { double('Authorization', approve?: authorized, message:) } before do allow(OpenProject::OmniAuth::Authorization) @@ -106,18 +106,18 @@ .and_return(auth_double) end - context "if authorized" do + context 'if authorized' do let(:authorized) { true } let(:message) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if invalid" do + context 'if invalid' do let(:authorized) { false } - let(:message) { "ERROR!" } + let(:message) { 'ERROR!' } - it_behaves_like "has error on", :base, "ERROR!" + it_behaves_like 'has error on', :base, 'ERROR!' end end end diff --git a/spec/contracts/custom_actions/cu_contract_spec.rb b/spec/contracts/custom_actions/cu_contract_spec.rb index 3f171d377802..5e7ef1dffc94 100644 --- a/spec/contracts/custom_actions/cu_contract_spec.rb +++ b/spec/contracts/custom_actions/cu_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe CustomActions::CuContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:user) { build_stubbed(:user) } let(:action) do @@ -39,30 +39,30 @@ end let(:contract) { described_class.new(action) } - describe "name" do - it "is writable" do - action.name = "blubs" + describe 'name' do + it 'is writable' do + action.name = 'blubs' expect_contract_valid end - it "needs to be set" do + it 'needs to be set' do action.name = nil expect_contract_invalid end end - describe "description" do - it "is writable" do - action.description = "blubs" + describe 'description' do + it 'is writable' do + action.description = 'blubs' expect_contract_valid end end - describe "actions" do - it "is writable" do + describe 'actions' do + it 'is writable' do responsible_action = CustomActions::Actions::Responsible.new action.actions = [responsible_action] @@ -70,63 +70,63 @@ expect_contract_valid end - it "needs to have one" do + it 'needs to have one' do action.actions = [] expect_contract_invalid actions: :empty end - it "requires a value if the action requires one" do + it 'requires a value if the action requires one' do action.actions = [CustomActions::Actions::Status.new([])] expect_contract_invalid actions: :empty end - it "allows only the allowed values" do + it 'allows only the allowed values' do status_action = CustomActions::Actions::Status.new([0]) allow(status_action) .to receive(:allowed_values) - .and_return([{ value: nil, label: "-" }, - { value: 1, label: "some status" }]) + .and_return([{ value: nil, label: '-' }, + { value: 1, label: 'some status' }]) action.actions = [status_action] expect_contract_invalid actions: :inclusion end - it "is not allowed to have an inexistent action" do + it 'is not allowed to have an inexistent action' do action.actions = [CustomActions::Actions::Inexistent.new] expect_contract_invalid actions: :does_not_exist end end - describe "conditions" do - it "is writable" do - action.conditions = [double("some bogus condition", key: "some", values: "bogus", validate: true)] + describe 'conditions' do + it 'is writable' do + action.conditions = [double('some bogus condition', key: 'some', values: 'bogus', validate: true)] expect(contract.validate) .to be_truthy end - it "allows only the allowed values" do + it 'allows only the allowed values' do status_condition = CustomActions::Conditions::Status.new([0]) allow(status_condition) .to receive(:allowed_values) - .and_return([{ value: nil, label: "-" }, - { value: 1, label: "some status" }]) + .and_return([{ value: nil, label: '-' }, + { value: 1, label: 'some status' }]) action.conditions = [status_condition] expect_contract_invalid conditions: :inclusion end - it "is not allowed to have an inexistent condition" do + it 'is not allowed to have an inexistent condition' do action.conditions = [CustomActions::Conditions::Inexistent.new] expect_contract_invalid conditions: :does_not_exist end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/custom_fields/create_contract_spec.rb b/spec/contracts/custom_fields/create_contract_spec.rb index 3717ea3058a0..61702e115ad1 100644 --- a/spec/contracts/custom_fields/create_contract_spec.rb +++ b/spec/contracts/custom_fields/create_contract_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe CustomFields::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:cf) { build(:project_custom_field) } let(:contract) do described_class.new(cf, current_user, options: {}) end - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' end diff --git a/spec/contracts/custom_fields/update_contract_spec.rb b/spec/contracts/custom_fields/update_contract_spec.rb index 66764dfa422f..9ff30cdb5718 100644 --- a/spec/contracts/custom_fields/update_contract_spec.rb +++ b/spec/contracts/custom_fields/update_contract_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe CustomFields::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:cf) { build(:project_custom_field) } let(:contract) do described_class.new(cf, current_user) end - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' end diff --git a/spec/contracts/groups/create_contract_spec.rb b/spec/contracts/groups/create_contract_spec.rb index dab836d27ba3..89b6f6e380d7 100644 --- a/spec/contracts/groups/create_contract_spec.rb +++ b/spec/contracts/groups/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Groups::CreateContract do - it_behaves_like "group contract" do + it_behaves_like 'group contract' do let(:group) do Group.new(name: group_name, group_users:) @@ -38,16 +38,16 @@ let(:contract) { described_class.new(group, current_user) } - describe "validations" do + describe 'validations' do let(:current_user) { build_stubbed(:admin) } - describe "type" do - context "type and class mismatch" do + describe 'type' do + context 'type and class mismatch' do before do group.type = User.name end - it_behaves_like "contract is invalid", type: "Type and class mismatch" + it_behaves_like 'contract is invalid', type: 'Type and class mismatch' end end end diff --git a/spec/contracts/groups/shared_contract_examples.rb b/spec/contracts/groups/shared_contract_examples.rb index a52fa642e280..e40046ca314e 100644 --- a/spec/contracts/groups/shared_contract_examples.rb +++ b/spec/contracts/groups/shared_contract_examples.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "group contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'group contract' do + include_context 'ModelContract shared context' - let(:group_name) { "The group" } + let(:group_name) { 'The group' } let(:group_users_user_ids) { [42, 43] } let(:group_users) do group_users_user_ids.map { |id| build_stubbed(:group_user, user_id: id) } end - shared_context "with real group users" do + shared_context 'with real group users' do # make sure users actually exist (not just stubbed) in this case # so GroupUser validations checking for the existence of group and user don't fail before do @@ -48,52 +48,52 @@ end end - it_behaves_like "contract is valid for active admins and invalid for regular users" do - include_context "with real group users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' do + include_context 'with real group users' end - describe "validations" do + describe 'validations' do let(:current_user) { build_stubbed(:admin) } - context "name" do - context "is valid" do - include_context "with real group users" + context 'name' do + context 'is valid' do + include_context 'with real group users' - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "is too long" do - let(:group_name) { "X" * 257 } + context 'is too long' do + let(:group_name) { 'X' * 257 } - it_behaves_like "contract is invalid", name: :too_long + it_behaves_like 'contract is invalid', name: :too_long end - context "is not empty" do - let(:group_name) { "" } + context 'is not empty' do + let(:group_name) { '' } - it_behaves_like "contract is invalid", name: :blank + it_behaves_like 'contract is invalid', name: :blank end - context "is unique" do + context 'is unique' do before do Group.create(name: group_name) end - it_behaves_like "contract is invalid", name: :taken + it_behaves_like 'contract is invalid', name: :taken end end - context "groups_users" do + context 'groups_users' do let(:group_users) do [build_stubbed(:group_user, user_id: 1), build_stubbed(:group_user, user_id: 1)] end - it_behaves_like "contract is invalid", group_users: :taken + it_behaves_like 'contract is invalid', group_users: :taken end end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:current_user) { build_stubbed(:user) } end end diff --git a/spec/contracts/groups/update_contract_spec.rb b/spec/contracts/groups/update_contract_spec.rb index 298fbf213101..1caee73d5a71 100644 --- a/spec/contracts/groups/update_contract_spec.rb +++ b/spec/contracts/groups/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Groups::UpdateContract do - it_behaves_like "group contract" do + it_behaves_like 'group contract' do let(:group) do build_stubbed(:group, name: group_name, @@ -39,15 +39,15 @@ let(:contract) { described_class.new(group, current_user) } - describe "validations" do + describe 'validations' do let(:current_user) { build_stubbed(:admin) } - describe "type" do + describe 'type' do before do - group.type = "A new type" + group.type = 'A new type' end - it_behaves_like "contract is invalid", type: :error_readonly + it_behaves_like 'contract is invalid', type: :error_readonly end end end diff --git a/spec/contracts/members/create_contract_spec.rb b/spec/contracts/members/create_contract_spec.rb index 9782d67e8ccb..b0fd87d925c6 100644 --- a/spec/contracts/members/create_contract_spec.rb +++ b/spec/contracts/members/create_contract_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Members::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' - it_behaves_like "member contract" do + it_behaves_like 'member contract' do let(:member) do Member.new(project: member_project, roles: member_roles, @@ -41,36 +41,36 @@ let(:contract) { described_class.new(member, current_user) } - describe "#validation" do - context "if the principal is nil" do + describe '#validation' do + context 'if the principal is nil' do let(:member_principal) { nil } - it_behaves_like "contract is invalid", principal: :blank + it_behaves_like 'contract is invalid', principal: :blank end - context "if the principal is a builtin user" do + context 'if the principal is a builtin user' do let(:member_principal) { build_stubbed(:anonymous) } - it_behaves_like "contract is invalid", principal: :unassignable + it_behaves_like 'contract is invalid', principal: :unassignable end - context "if the principal is a locked user" do + context 'if the principal is a locked user' do let(:member_principal) { build_stubbed(:locked_user) } - it_behaves_like "contract is invalid", principal: :unassignable + it_behaves_like 'contract is invalid', principal: :unassignable end end - describe "#assignable_projects" do - context "as a user without permission" do + describe '#assignable_projects' do + context 'as a user without permission' do let(:current_user) { build_stubbed(:user) } - it "is empty" do + it 'is empty' do expect(contract.assignable_projects).to be_empty end end - context "as a user with permission in one project" do + context 'as a user with permission in one project' do let!(:project1) { create(:project) } let!(:project2) { create(:project) } let(:current_user) do @@ -78,7 +78,7 @@ member_with_permissions: { project1 => %i[manage_members] }) end - it "returns the one project" do + it 'returns the one project' do expect(contract.assignable_projects.to_a).to eq [project1] end end diff --git a/spec/contracts/members/shared_contract_examples.rb b/spec/contracts/members/shared_contract_examples.rb index cfaf6363d57f..a24f5747f259 100644 --- a/spec/contracts/members/shared_contract_examples.rb +++ b/spec/contracts/members/shared_contract_examples.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "member contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'member contract' do + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user, admin: current_user_admin) } @@ -63,93 +63,93 @@ def expect_valid(valid, symbols = {}) end end - describe "validation" do - shared_examples "is valid" do - it "is valid" do + describe 'validation' do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' - context "if the roles are nil" do + context 'if the roles are nil' do let(:member_roles) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, roles: %i(role_blank)) end end - context "if any role is not assignable (e.g. builtin)" do + context 'if any role is not assignable (e.g. builtin)' do let(:member_roles) do [build_stubbed(:project_role), build_stubbed(:anonymous_role)] end - it "is invalid" do + it 'is invalid' do expect_valid(false, roles: %i(ungrantable)) end end - context "if the user lacks :manage_members permission in the project" do + context 'if the user lacks :manage_members permission in the project' do let(:permissions) { [:view_members] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if the project is nil (global membership)" do + context 'if the project is nil (global membership)' do let(:member_project) { nil } let(:role) do build_stubbed(:global_role) end - context "if the user is no admin" do - it "is invalid" do + context 'if the user is no admin' do + it 'is invalid' do expect_valid(false, project: %i(blank)) end end - context "if the user is admin and the role is global" do + context 'if the user is admin and the role is global' do let(:current_user_admin) { true } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the role is not a global role" do + context 'if the role is not a global role' do let(:current_user_admin) { true } let(:role) do build_stubbed(:project_role) end - it "is invalid" do + it 'is invalid' do expect_valid(false, roles: %i(ungrantable)) end end end - context "if the project is set to one not being manageable by the user" do + context 'if the project is set to one not being manageable by the user' do let(:permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, project: %i(invalid)) end end end - describe "principal" do - it "returns the member's principal" do + describe 'principal' do + it 'returns the member\'s principal' do expect(contract.principal) .to eql(member.principal) end end - describe "project" do - it "returns the member's project" do + describe 'project' do + it 'returns the member\'s project' do expect(contract.project) .to eql(member.project) end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/members/update_contract_spec.rb b/spec/contracts/members/update_contract_spec.rb index 1b2a40cd10e8..e35f97950dc7 100644 --- a/spec/contracts/members/update_contract_spec.rb +++ b/spec/contracts/members/update_contract_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Members::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' - it_behaves_like "member contract" do + it_behaves_like 'member contract' do let(:member) do build_stubbed(:member, project: member_project, @@ -42,27 +42,27 @@ let(:contract) { described_class.new(member, current_user) } - describe "validation" do - context "if the principal is changed" do + describe 'validation' do + context 'if the principal is changed' do before do member.principal = build_stubbed(:user) end - it_behaves_like "contract is invalid", user_id: :error_readonly + it_behaves_like 'contract is invalid', user_id: :error_readonly end - context "if the project is changed" do + context 'if the project is changed' do before do member.project = build_stubbed(:project) end - it_behaves_like "contract is invalid", project_id: :error_readonly + it_behaves_like 'contract is invalid', project_id: :error_readonly end - context "if the principal is a locked user" do + context 'if the principal is a locked user' do let(:member_principal) { build_stubbed(:locked_user) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end end diff --git a/spec/contracts/messages/create_contract_spec.rb b/spec/contracts/messages/create_contract_spec.rb index cbd38a0f069a..77cce4ab669b 100644 --- a/spec/contracts/messages/create_contract_spec.rb +++ b/spec/contracts/messages/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Messages::CreateContract do - it_behaves_like "message contract" do + it_behaves_like 'message contract' do let(:message) do Message.new(forum: message_forum, parent: message_parent, diff --git a/spec/contracts/messages/shared_contract_examples.rb b/spec/contracts/messages/shared_contract_examples.rb index b1e31740e203..fe5c6b6d577f 100644 --- a/spec/contracts/messages/shared_contract_examples.rb +++ b/spec/contracts/messages/shared_contract_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "message contract" do +RSpec.shared_examples_for 'message contract' do let(:current_user) { build_stubbed(:user) } before do @@ -60,11 +60,11 @@ def expect_valid(valid, symbols = {}) end end - shared_examples "is valid" do - it "is valid" do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' end diff --git a/spec/contracts/messages/update_contract_spec.rb b/spec/contracts/messages/update_contract_spec.rb index b8bcff8cd7eb..1cb7557c3b2c 100644 --- a/spec/contracts/messages/update_contract_spec.rb +++ b/spec/contracts/messages/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Messages::UpdateContract do - it_behaves_like "message contract" do + it_behaves_like 'message contract' do let(:message) do build_stubbed(:message).tap do |message| message.forum = message_forum @@ -44,8 +44,8 @@ end subject(:contract) { described_class.new(message, current_user) } - context "if the author is changed" do - it "is invalid" do + context 'if the author is changed' do + it 'is invalid' do message.author = other_user expect_valid(false, author_id: %i(error_readonly)) end diff --git a/spec/contracts/notifications/create_contract_spec.rb b/spec/contracts/notifications/create_contract_spec.rb index 3a3c6d79e610..19ffbd01d339 100644 --- a/spec/contracts/notifications/create_contract_spec.rb +++ b/spec/contracts/notifications/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Notifications::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) do build_stubbed(:user) do |user| @@ -40,7 +40,7 @@ let(:notification_context) { build_stubbed(:project) } let(:notification_resource) { build_stubbed(:journal) } let(:notification_recipient) { build_stubbed(:user) } - let(:notification_subject) { "Some text" } + let(:notification_subject) { 'Some text' } let(:notification_reason) { :mentioned } let(:notification_read_ian) { false } let(:notification_mail_reminder_sent) { false } @@ -57,45 +57,45 @@ let(:contract) { described_class.new(notification, current_user) } - describe "#validation" do - it_behaves_like "contract is valid" + describe '#validation' do + it_behaves_like 'contract is valid' - context "without a recipient" do + context 'without a recipient' do let(:notification_recipient) { nil } - it_behaves_like "contract is invalid", recipient: :blank + it_behaves_like 'contract is invalid', recipient: :blank end - context "without a reason" do + context 'without a reason' do let(:notification_reason) { nil } - it_behaves_like "contract is invalid", reason: :no_notification_reason + it_behaves_like 'contract is invalid', reason: :no_notification_reason end - context "without a subject" do + context 'without a subject' do let(:notification_subject) { nil } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with an empty subject" do - let(:notification_subject) { "" } + context 'with an empty subject' do + let(:notification_subject) { '' } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with read_ian true" do + context 'with read_ian true' do let(:notification_read_ian) { true } - it_behaves_like "contract is invalid", read_ian: :read_on_creation + it_behaves_like 'contract is invalid', read_ian: :read_on_creation end - context "with mail_reminder_sent true" do + context 'with mail_reminder_sent true' do let(:notification_mail_reminder_sent) { true } - it_behaves_like "contract is invalid", mail_reminder_sent: :set_on_creation + it_behaves_like 'contract is invalid', mail_reminder_sent: :set_on_creation end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/oauth_clients/create_contract_spec.rb b/spec/contracts/oauth_clients/create_contract_spec.rb index 69999601333e..02a44a899f10 100644 --- a/spec/contracts/oauth_clients/create_contract_spec.rb +++ b/spec/contracts/oauth_clients/create_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' RSpec.describe OAuthClients::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { create(:admin) } let(:client_id) { "1234567889" } @@ -43,57 +43,57 @@ let(:contract) { described_class.new(oauth_client, current_user) } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - describe "validations" do - context "when all attributes are valid" do - include_examples "contract is valid" + describe 'validations' do + context 'when all attributes are valid' do + include_examples 'contract is valid' end %i[client_id client_secret].each do |attribute_name| - context "when client_id is invalid" do - context "as it is too long" do - let(attribute_name) { "X" * 257 } + context 'when client_id is invalid' do + context 'as it is too long' do + let(attribute_name) { 'X' * 257 } - include_examples "contract is invalid", attribute_name => :too_long + include_examples 'contract is invalid', attribute_name => :too_long end - context "as it is empty" do - let(attribute_name) { "" } + context 'as it is empty' do + let(attribute_name) { '' } - include_examples "contract is invalid", attribute_name => :blank + include_examples 'contract is invalid', attribute_name => :blank end - context "as it is nil" do + context 'as it is nil' do let(attribute_name) { nil } - include_examples "contract is invalid", attribute_name => :blank + include_examples 'contract is invalid', attribute_name => :blank end end end - context "with blank client ID" do - let(:client_id) { "" } + context 'with blank client ID' do + let(:client_id) { '' } - it "is invalid" do + it 'is invalid' do expect(contract).not_to be_valid expect(contract.errors[:client_id]).to eq(["can't be blank."]) end end - context "with integration (polymorphic attribute) linked" do + context 'with integration (polymorphic attribute) linked' do let(:integration) { create(:nextcloud_storage) } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "without integration (polymorphic attribute)" do + context 'without integration (polymorphic attribute)' do let(:integration) { nil } - include_examples "contract is invalid", { integration_id: :blank, integration_type: :blank } + include_examples 'contract is invalid', { integration_id: :blank, integration_type: :blank } end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/oauth_clients/delete_contract_spec.rb b/spec/contracts/oauth_clients/delete_contract_spec.rb index 7f2f0666dfda..bc3e0e423c35 100644 --- a/spec/contracts/oauth_clients/delete_contract_spec.rb +++ b/spec/contracts/oauth_clients/delete_contract_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' # This DeleteContract spec just tests if the user is _allowed_ # to execute the operation. RSpec.describe OAuthClients::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:oauth_client) { create(:oauth_client) } let(:contract) { described_class.new(oauth_client, current_user) } # Generic checks that the contract is valid for valid admin, but invalid otherwise - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:current_user) { build_stubbed(:admin) } end end diff --git a/spec/contracts/placeholder_users/create_contract_spec.rb b/spec/contracts/placeholder_users/create_contract_spec.rb index 76c4e4d1611e..5c97854159be 100644 --- a/spec/contracts/placeholder_users/create_contract_spec.rb +++ b/spec/contracts/placeholder_users/create_contract_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe PlaceholderUsers::CreateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' - context "without enterprise" do - let(:placeholder_user) { PlaceholderUser.new(name: "foo") } + context 'without enterprise' do + let(:placeholder_user) { PlaceholderUser.new(name: 'foo') } let(:contract) { described_class.new(placeholder_user, current_user) } - context "when user with global permission" do + context 'when user with global permission' do let(:current_user) { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "contract is invalid", base: :error_enterprise_only + it_behaves_like 'contract is invalid', base: :error_enterprise_only end - context "when user with admin permission" do + context 'when user with admin permission' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "contract is invalid", base: :error_enterprise_only + it_behaves_like 'contract is invalid', base: :error_enterprise_only end end - context "with enterprise", with_ee: %i[placeholder_users] do - it_behaves_like "placeholder user contract" do + context 'with enterprise', with_ee: %i[placeholder_users] do + it_behaves_like 'placeholder user contract' do let(:placeholder_user) { PlaceholderUser.new(name: placeholder_user_name) } let(:contract) { described_class.new(placeholder_user, current_user) } end diff --git a/spec/contracts/placeholder_users/delete_contract_spec.rb b/spec/contracts/placeholder_users/delete_contract_spec.rb index 2d67edfe69e5..5f48d5c5186f 100644 --- a/spec/contracts/placeholder_users/delete_contract_spec.rb +++ b/spec/contracts/placeholder_users/delete_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe PlaceholderUsers::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:placeholder_user) { create(:placeholder_user) } let(:role) { create(:existing_project_role, permissions: [:manage_members]) } @@ -38,29 +38,29 @@ let(:not_shared_project) { create(:project, members: { placeholder_user => role }) } let(:contract) { described_class.new(placeholder_user, current_user) } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - context "when user with global permission to manage_placeholders" do + context 'when user with global permission to manage_placeholders' do let(:current_user) { create(:user, global_permissions: %i[manage_placeholder_user]) } before do shared_project end - context "when user is allowed to manage members in all projects of the placeholder user" do - it_behaves_like "contract is valid" + context 'when user is allowed to manage members in all projects of the placeholder user' do + it_behaves_like 'contract is valid' end - context "when user is not allowed to manage members in all projects of the placeholder user" do + context 'when user is not allowed to manage members in all projects of the placeholder user' do before do not_shared_project end - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:current_user) { build_stubbed(:admin) } end end diff --git a/spec/contracts/placeholder_users/shared_contract_examples.rb b/spec/contracts/placeholder_users/shared_contract_examples.rb index 15507f1911c1..86bf396358e4 100644 --- a/spec/contracts/placeholder_users/shared_contract_examples.rb +++ b/spec/contracts/placeholder_users/shared_contract_examples.rb @@ -26,61 +26,61 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "placeholder user contract" do - let(:placeholder_user_name) { "UX Designer" } +RSpec.shared_examples_for 'placeholder user contract' do + let(:placeholder_user_name) { 'UX Designer' } - context "when user with global permission" do + context 'when user with global permission' do let(:current_user) { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - describe "validations" do + describe 'validations' do let(:current_user) { build_stubbed(:admin) } - context "name" do - context "is valid" do - it_behaves_like "contract is valid" + context 'name' do + context 'is valid' do + it_behaves_like 'contract is valid' end - context "is not too long" do - let(:placeholder_user) { PlaceholderUser.new(name: "X" * 257) } + context 'is not too long' do + let(:placeholder_user) { PlaceholderUser.new(name: 'X' * 257) } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end - context "is not empty" do - let(:placeholder_user) { PlaceholderUser.new(name: "") } + context 'is not empty' do + let(:placeholder_user) { PlaceholderUser.new(name: '') } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end - context "is unique" do + context 'is unique' do before do PlaceholderUser.create(name: placeholder_user_name) end - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end end - describe "type" do - context "type and class mismatch" do + describe 'type' do + context 'type and class mismatch' do before do placeholder_user.type = User.name end - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end end end - include_examples "contract reuses the model errors" do + include_examples 'contract reuses the model errors' do let(:current_user) { build_stubbed(:admin) } end end diff --git a/spec/contracts/placeholder_users/update_contract_spec.rb b/spec/contracts/placeholder_users/update_contract_spec.rb index 6c078df4d534..7a6cd7d25c47 100644 --- a/spec/contracts/placeholder_users/update_contract_spec.rb +++ b/spec/contracts/placeholder_users/update_contract_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe PlaceholderUsers::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' - it_behaves_like "placeholder user contract" do + it_behaves_like 'placeholder user contract' do let(:placeholder_user) { build_stubbed(:placeholder_user, name: placeholder_user_name) } let(:contract) { described_class.new(placeholder_user, current_user) } end diff --git a/spec/contracts/projects/archive_contract_spec.rb b/spec/contracts/projects/archive_contract_spec.rb index bf9f765d7c79..1c5052d70e99 100644 --- a/spec/contracts/projects/archive_contract_spec.rb +++ b/spec/contracts/projects/archive_contract_spec.rb @@ -26,82 +26,82 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Projects::ArchiveContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' shared_let(:archivist_role) { create(:project_role, permissions: %i[archive_project]) } let(:project) { build_stubbed(:project) } let(:contract) { described_class.new(project, current_user) } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - context "when user has archive_project permission" do + context 'when user has archive_project permission' do let(:project) { create(:project) } let(:current_user) { create(:user, member_with_roles: { project => archivist_role }) } - include_examples "contract is valid" + include_examples 'contract is valid' end - context "with subprojects" do + context 'with subprojects' do shared_let(:subproject1) { create(:project) } shared_let(:subproject2) { create(:project) } shared_let(:project) { create(:project, children: [subproject1, subproject2]) } shared_let(:current_user) { create(:user, member_with_roles: { project => archivist_role }) } - shared_examples "with archive_project permission on all/some/none of subprojects" do - context "when user does not have archive_project permission on any subprojects" do - include_examples "contract is invalid", base: :archive_permission_missing_on_subprojects + shared_examples 'with archive_project permission on all/some/none of subprojects' do + context 'when user does not have archive_project permission on any subprojects' do + include_examples 'contract is invalid', base: :archive_permission_missing_on_subprojects end - context "when user has archive_project permission on some subprojects but not all" do + context 'when user has archive_project permission on some subprojects but not all' do before do create(:member, user: current_user, project: subproject1, roles: [archivist_role]) end - include_examples "contract is invalid", base: :archive_permission_missing_on_subprojects + include_examples 'contract is invalid', base: :archive_permission_missing_on_subprojects end - context "when user has archive_project permission on all subprojects" do + context 'when user has archive_project permission on all subprojects' do before do create(:member, user: current_user, project: subproject1, roles: [archivist_role]) create(:member, user: current_user, project: subproject2, roles: [archivist_role]) end - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when some of subprojects are archived but not all" do + context 'when some of subprojects are archived but not all' do before do subproject1.update_column(:active, false) create(:member, user: current_user, project: subproject2, roles: [archivist_role]) end - include_examples "contract is valid" + include_examples 'contract is valid' end - context "when all of subprojects are archived" do + context 'when all of subprojects are archived' do before do subproject1.update_column(:active, false) subproject2.update_column(:active, false) end - include_examples "contract is valid" + include_examples 'contract is valid' end end - include_examples "contract is valid for active admins and invalid for regular users" - include_examples "with archive_project permission on all/some/none of subprojects" + include_examples 'contract is valid for active admins and invalid for regular users' + include_examples 'with archive_project permission on all/some/none of subprojects' - context "with deep nesting" do + context 'with deep nesting' do before do subproject2.update(parent: subproject1) end - include_examples "contract is valid for active admins and invalid for regular users" - include_examples "with archive_project permission on all/some/none of subprojects" + include_examples 'contract is valid for active admins and invalid for regular users' + include_examples 'with archive_project permission on all/some/none of subprojects' end end end diff --git a/spec/contracts/projects/base_contract_spec.rb b/spec/contracts/projects/base_contract_spec.rb index 679e42bc31e0..6febab49348f 100644 --- a/spec/contracts/projects/base_contract_spec.rb +++ b/spec/contracts/projects/base_contract_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Projects::BaseContract do - let(:project) { Project.new(name: "Foo", identifier: "foo", templated: false) } + let(:project) { Project.new(name: 'Foo', identifier: 'foo', templated: false) } let(:contract) { described_class.new(project, current_user) } subject { contract.validate } - describe "templated attribute" do + describe 'templated attribute' do before do # Assume the user may manage the project allow(contract) @@ -47,18 +47,18 @@ expect(project.templated_changed?).to be true end - context "as admin" do + context 'as admin' do let(:current_user) { build_stubbed(:admin) } - it "validates the contract" do + it 'validates the contract' do expect(subject).to be true end end - context "as regular user" do + context 'as regular user' do let(:current_user) { build_stubbed(:user) } - it "returns an error on validation" do + it 'returns an error on validation' do expect(subject).to be false expect(contract.errors.symbols_for(:templated)) .to contain_exactly(:error_unauthorized) diff --git a/spec/contracts/projects/create_contract_spec.rb b/spec/contracts/projects/create_contract_spec.rb index dc31da93c078..c152356c7134 100644 --- a/spec/contracts/projects/create_contract_spec.rb +++ b/spec/contracts/projects/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Projects::CreateContract do - it_behaves_like "project contract" do + it_behaves_like 'project contract' do let(:project) do Project.new(name: project_name, identifier: project_identifier, @@ -42,60 +42,15 @@ status_explanation: project_status_explanation) end let(:global_permissions) { [:add_project] } - let(:validated_contract) do - contract.tap(&:validate) - end subject(:contract) { described_class.new(project, current_user) } - context "if the identifier is nil" do + context 'if the identifier is nil' do let(:project_identifier) { nil } - it "is replaced for new project" do + it 'is replaced for new project' do expect_valid(true) end end - - describe "writing read-only attributes" do - shared_examples "can not write" do |attribute, value| - it "can not write #{attribute}", :aggregate_failures do - expect(contract.writable_attributes).not_to include(attribute.to_s) - - project.send(:"#{attribute}=", value) - expect(validated_contract).not_to be_valid - expect(validated_contract.errors[attribute]).to include "was attempted to be written but is not writable." - end - - context "when enabled for admin", with_settings: { apiv3_write_readonly_attributes: true } do - let(:current_user) { build_stubbed(:admin) } - - it_behaves_like "can not write", :updated_at, 1.day.ago - - it "can write created_at", :aggregate_failures do - expect(contract.writable_attributes).to include("created_at") - - project.created_at = 10.days.ago - expect(validated_contract.errors[attribute]).to be_empty - end - end - - context "when disabled for admin", with_settings: { apiv3_write_readonly_attributes: false } do - let(:current_user) { build_stubbed(:admin) } - - it_behaves_like "can not write", :created_at, 1.day.ago - it_behaves_like "can not write", :updated_at, 1.day.ago - end - - context "when enabled for regular user", with_settings: { apiv3_write_readonly_attributes: true } do - it_behaves_like "can not write", :created_at, 1.day.ago - it_behaves_like "can not write", :updated_at, 1.day.ago - end - - context "when disabled for regular user", with_settings: { apiv3_write_readonly_attributes: false } do - it_behaves_like "can not write", :created_at, 1.day.ago - it_behaves_like "can not write", :updated_at, 1.day.ago - end - end - end end end diff --git a/spec/contracts/projects/delete_contract_spec.rb b/spec/contracts/projects/delete_contract_spec.rb index a33d84e90716..a60a786c3cec 100644 --- a/spec/contracts/projects/delete_contract_spec.rb +++ b/spec/contracts/projects/delete_contract_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Projects::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:project) { build_stubbed(:project) } let(:contract) { described_class.new(project, current_user) } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' end diff --git a/spec/contracts/projects/enabled_modules_contract_spec.rb b/spec/contracts/projects/enabled_modules_contract_spec.rb index 35a8de068259..a525d67476b0 100644 --- a/spec/contracts/projects/enabled_modules_contract_spec.rb +++ b/spec/contracts/projects/enabled_modules_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Projects::EnabledModulesContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:project) { build_stubbed(:project, enabled_module_names: enabled_modules) } let(:enabled_modules) { %i[a_module b_module] } @@ -50,19 +50,19 @@ allow(I18n).to receive(:t).with("project_module_b_module").and_return("B Module") end - describe "#valid?" do - it_behaves_like "contract is valid" + describe '#valid?' do + it_behaves_like 'contract is valid' - context "when the dependencies are not met" do + context 'when the dependencies are not met' do let(:enabled_modules) { %i[a_module] } - it_behaves_like "contract is invalid", enabled_modules: :dependency_missing + it_behaves_like 'contract is invalid', enabled_modules: :dependency_missing end - context "when the user lacks the select_project_modules permission" do + context 'when the user lacks the select_project_modules permission' do let(:permissions) { %i[] } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end end end diff --git a/spec/contracts/projects/shared_contract_examples.rb b/spec/contracts/projects/shared_contract_examples.rb index be680d01a77b..bc18c9904749 100644 --- a/spec/contracts/projects/shared_contract_examples.rb +++ b/spec/contracts/projects/shared_contract_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "project contract" do +RSpec.shared_examples_for 'project contract' do let(:current_user) { build_stubbed(:user) } before do @@ -40,20 +40,20 @@ let(:project_permissions) { [] } let(:global_permissions) { [] } - let(:project_name) { "Project name" } - let(:project_identifier) { "project_identifier" } - let(:project_description) { "Project description" } + let(:project_name) { 'Project name' } + let(:project_identifier) { 'project_identifier' } + let(:project_description) { 'Project description' } let(:project_active) { true } let(:project_public) { true } - let(:project_status_code) { "on_track" } - let(:project_status_explanation) { "some explanation" } + let(:project_status_code) { 'on_track' } + let(:project_status_explanation) { 'some explanation' } let(:project_parent) do build_stubbed(:project) end let(:parent_assignable) { true } let!(:assignable_parents) do - assignable_parents_scope = double("assignable parents scope") - assignable_parents = double("assignable parents") + assignable_parents_scope = double('assignable parents scope') + assignable_parents = double('assignable parents') allow(Project) .to receive(:allowed_to) @@ -91,165 +91,165 @@ def expect_valid(valid, symbols = {}) end end - shared_examples "is valid" do - it "is valid" do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' - context "if the name is nil" do + context 'if the name is nil' do let(:project_name) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, name: %i(blank)) end end - context "if the description is nil" do + context 'if the description is nil' do let(:project_description) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the parent is nil" do + context 'if the parent is nil' do let(:project_parent) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the parent is not in the set of assignable_parents" do + context 'if the parent is not in the set of assignable_parents' do let(:parent_assignable) { false } - it "is invalid" do + it 'is invalid' do expect_valid(false, parent: %i(does_not_exist)) end end - context "if active is nil" do + context 'if active is nil' do let(:project_active) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, active: %i(blank)) end end - context "if status code is nil" do + context 'if status code is nil' do let(:project_status_code) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if status explanation is nil" do + context 'if status explanation is nil' do let(:project_status_explanation) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if status code is invalid" do + context 'if status code is invalid' do before do # Hack in order to handle setting an Enum value without raising an # ArgumentError and letting the Contract perform the validation. # # This is the behavior that would be expected to be performed by # the SetAttributesService at that layer of the flow. - bogus_project_status_code = "bogus" - code_attributes = project.instance_variable_get(:@attributes)["status_code"] + bogus_project_status_code = 'bogus' + code_attributes = project.instance_variable_get(:@attributes)['status_code'] code_attributes.instance_variable_set(:@value_before_type_cast, bogus_project_status_code) code_attributes.instance_variable_set(:@value, bogus_project_status_code) end - it "is invalid" do + it 'is invalid' do expect_valid(false, status: %i(inclusion)) end end - context "when the identifier consists of only letters" do - let(:project_identifier) { "abc" } + context 'when the identifier consists of only letters' do + let(:project_identifier) { 'abc' } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the identifier consists of letters followed by numbers" do - let(:project_identifier) { "abc12" } + context 'when the identifier consists of letters followed by numbers' do + let(:project_identifier) { 'abc12' } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the identifier consists of letters followed by numbers with a hyphen in between" do - let(:project_identifier) { "abc-12" } + context 'when the identifier consists of letters followed by numbers with a hyphen in between' do + let(:project_identifier) { 'abc-12' } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the identifier consists of letters followed by numbers with an underscore in between" do - let(:project_identifier) { "abc_12" } + context 'when the identifier consists of letters followed by numbers with an underscore in between' do + let(:project_identifier) { 'abc_12' } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the identifier consists of numbers followed by letters with a hyphen in between" do - let(:project_identifier) { "12-abc" } + context 'when the identifier consists of numbers followed by letters with a hyphen in between' do + let(:project_identifier) { '12-abc' } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the identifier consists of numbers followed by letters with an underscore in between" do - let(:project_identifier) { "12_abc" } + context 'when the identifier consists of numbers followed by letters with an underscore in between' do + let(:project_identifier) { '12_abc' } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "when the identifier consists of only numbers" do - let(:project_identifier) { "12" } + context 'when the identifier consists of only numbers' do + let(:project_identifier) { '12' } - it "is invalid" do + it 'is invalid' do expect_valid(false, identifier: %i(invalid)) end end - context "when the identifier consists of a reserved word" do - let(:project_identifier) { "new" } + context 'when the identifier consists of a reserved word' do + let(:project_identifier) { 'new' } - it "is invalid" do + it 'is invalid' do expect_valid(false, identifier: %i(exclusion)) end end - context "if the user lacks permission" do + context 'if the user lacks permission' do let(:global_permissions) { [] } let(:project_permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - describe "assignable_values" do - context "for project" do + describe 'assignable_values' do + context 'for project' do before do assignable_parents end - it "returns all projects the user has the add_subprojects permissions for" do + it 'returns all projects the user has the add_subprojects permissions for' do expect(contract.assignable_parents) .to eql assignable_parents end end - context "for a list custom field" do + context 'for a list custom field' do let(:custom_field) { build_stubbed(:list_project_custom_field) } - it "is the list of custom field values" do + it 'is the list of custom field values' do expect(subject.assignable_custom_field_values(custom_field)) .to eql custom_field.possible_values end end - context "for a version custom field" do + context 'for a version custom field' do let(:custom_field) { build_stubbed(:version_project_custom_field) } - let(:versions) { double("versions") } + let(:versions) { double('versions') } before do allow(project) @@ -257,14 +257,14 @@ def expect_valid(valid, symbols = {}) .and_return(versions) end - it "is the list of versions for the project" do + it 'is the list of versions for the project' do expect(subject.assignable_custom_field_values(custom_field)) .to eql versions end end end - describe "available_custom_fields" do + describe 'available_custom_fields' do let(:visible_custom_field) { build_stubbed(:integer_project_custom_field, visible: true) } let(:invisible_custom_field) { build_stubbed(:integer_project_custom_field, visible: false) } @@ -274,21 +274,21 @@ def expect_valid(valid, symbols = {}) .and_return([visible_custom_field, invisible_custom_field]) end - context "if the user is admin" do + context 'if the user is admin' do before do allow(current_user) .to receive(:admin?) .and_return(true) end - it "returns all available_custom_fields of the project" do + it 'returns all available_custom_fields of the project' do expect(subject.available_custom_fields) .to contain_exactly(visible_custom_field, invisible_custom_field) end end - context "if the user is no admin" do - it "returns all visible and available_custom_fields of the project" do + context 'if the user is no admin' do + it 'returns all visible and available_custom_fields of the project' do expect(subject.available_custom_fields) .to contain_exactly(visible_custom_field) end diff --git a/spec/contracts/projects/unarchive_contract_spec.rb b/spec/contracts/projects/unarchive_contract_spec.rb index 6cb59bdf68c8..82661cd1341c 100644 --- a/spec/contracts/projects/unarchive_contract_spec.rb +++ b/spec/contracts/projects/unarchive_contract_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Projects::UnarchiveContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:project) { build_stubbed(:project) } let(:contract) { described_class.new(project, current_user) } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' end diff --git a/spec/contracts/projects/update_contract_spec.rb b/spec/contracts/projects/update_contract_spec.rb index 6259841b68c8..5e427df6e41e 100644 --- a/spec/contracts/projects/update_contract_spec.rb +++ b/spec/contracts/projects/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Projects::UpdateContract do - it_behaves_like "project contract" do + it_behaves_like 'project contract' do let(:project) do build_stubbed(:project, active: project_active, @@ -47,10 +47,10 @@ subject(:contract) { described_class.new(project, current_user) } - context "if the identifier is nil" do + context 'if the identifier is nil' do let(:project_identifier) { nil } - it "is replaced for new project" do + it 'is replaced for new project' do expect_valid(false, identifier: %i(blank)) end end diff --git a/spec/contracts/queries/base_contract_spec.rb b/spec/contracts/queries/base_contract_spec.rb index 9b1b6c0ab7a8..c950011e502c 100644 --- a/spec/contracts/queries/base_contract_spec.rb +++ b/spec/contracts/queries/base_contract_spec.rb @@ -26,85 +26,85 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Queries::BaseContract do - include_context "with queries contract" + include_context 'with queries contract' - describe "timestamps" do + describe 'timestamps' do let(:query) { build_stubbed(:query, timestamps:) } - context "with EE", with_ee: %i[baseline_comparison] do + context 'with EE', with_ee: %i[baseline_comparison] do Timestamp::ALLOWED_DATE_KEYWORDS.each do |timestamp_date_keyword| context "when the '#{timestamp_date_keyword}' value is provided" do let(:timestamps) { ["#{timestamp_date_keyword}@12:00+00:00"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end context "when the shortcut value 'now' is provided" do let(:timestamps) { ["now"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when a duration value is provided" do let(:timestamps) { ["P-2D"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when an iso8601 datetime value is provided" do let(:timestamps) { [1.week.ago.iso8601] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - context "without EE", with_ee: false do + context 'without EE', with_ee: false do context "when the 'oneDayAgo' value is provided" do let(:timestamps) { ["oneDayAgo@12:00+00:00"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when the shortcut value 'now' is provided" do let(:timestamps) { ["now"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when the 'PT0S' duration value is provided" do let(:timestamps) { ["PT0S"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when the 'P-1D' duration value is provided" do let(:timestamps) { ["P-1D"] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when an iso8601 datetime value from yesterday is provided" do let(:timestamps) { [1.day.ago.beginning_of_day.iso8601] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end context "when the 'lastWorkingDay' value is provided and it's yesterday" do let(:timestamps) { "lastWorkingDay@00:00+00:00" } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end Timestamp::ALLOWED_DATE_KEYWORDS[2..].each do |timestamp_date_keyword| context "when the '#{timestamp_date_keyword}' value is provided" do let(:timestamps) { ["#{timestamp_date_keyword}@12:00+00:00"] } - it_behaves_like "contract is invalid", timestamps: :forbidden + it_behaves_like 'contract is invalid', timestamps: :forbidden end end @@ -115,19 +115,19 @@ allow(Day).to receive(:last_working) { Day.new(date: 7.days.ago) } end - it_behaves_like "contract is invalid", timestamps: :forbidden + it_behaves_like 'contract is invalid', timestamps: :forbidden end context "when a duration value older than yesterday is provided" do let(:timestamps) { ["P-2D"] } - it_behaves_like "contract is invalid", timestamps: :forbidden + it_behaves_like 'contract is invalid', timestamps: :forbidden end context "when an iso8601 datetime value older than yesterday is provided" do let(:timestamps) { [2.days.ago.end_of_day.iso8601] } - it_behaves_like "contract is invalid", timestamps: :forbidden + it_behaves_like 'contract is invalid', timestamps: :forbidden end end end diff --git a/spec/contracts/queries/create_contract_spec.rb b/spec/contracts/queries/create_contract_spec.rb index 09ca9bafb2d5..36b80d8e6d17 100644 --- a/spec/contracts/queries/create_contract_spec.rb +++ b/spec/contracts/queries/create_contract_spec.rb @@ -26,35 +26,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Queries::CreateContract do - include_context "with queries contract" + include_context 'with queries contract' - describe "include subprojects" do + describe 'include subprojects' do let(:query) do - Query.new name: "foo", + Query.new name: 'foo', include_subprojects:, project: end - context "when true" do + context 'when true' do let(:include_subprojects) { true } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when false" do + context 'when false' do let(:include_subprojects) { false } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when nil" do + context 'when nil' do let(:include_subprojects) { nil } - it_behaves_like "contract is invalid", include_subprojects: %i[inclusion] + it_behaves_like 'contract is invalid', include_subprojects: %i[inclusion] end end end diff --git a/spec/contracts/queries/global_create_contract_spec.rb b/spec/contracts/queries/global_create_contract_spec.rb index eff721e69a53..0036af9f8b01 100644 --- a/spec/contracts/queries/global_create_contract_spec.rb +++ b/spec/contracts/queries/global_create_contract_spec.rb @@ -28,17 +28,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/queries/shared_contract_examples" +require 'spec_helper' +require 'contracts/queries/shared_contract_examples' RSpec.describe Queries::GlobalCreateContract do - include_context "with queries contract" + include_context 'with queries contract' - describe "validation" do - context "if the project_id is nil" do + describe 'validation' do + context 'if the project_id is nil' do let(:project) { nil } - it_behaves_like "contract is invalid", project_id: :blank + it_behaves_like 'contract is invalid', project_id: :blank end end end diff --git a/spec/contracts/queries/ical_sharing_contract_spec.rb b/spec/contracts/queries/ical_sharing_contract_spec.rb index 4e58fa7356ea..0637f6d42803 100644 --- a/spec/contracts/queries/ical_sharing_contract_spec.rb +++ b/spec/contracts/queries/ical_sharing_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Queries::ICalSharingContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' # using `create` approach here as many underlying checks base on # real database checks which should not be mocked @@ -50,96 +50,96 @@ # override as this contract additionally needs the ical_token let(:contract) { described_class.new(query, current_user, options: { ical_token: }) } - describe "private query" do + describe 'private query' do let(:public) { false } - context "when user is author", with_settings: { ical_enabled: true } do + context 'when user is author', with_settings: { ical_enabled: true } do let(:user) { current_user } - context "when user has no permission to share via ical" do + context 'when user has no permission to share via ical' do let(:permissions) { %i(view_work_packages view_calendar manage_calendars) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "when user has permission to share via" do + context 'when user has permission to share via' do let(:permissions) { %i(view_work_packages share_calendars) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when iCalendar subscriptions are globally disabled", with_settings: { ical_enabled: false } do - it_behaves_like "contract user is unauthorized" + context 'when iCalendar subscriptions are globally disabled', with_settings: { ical_enabled: false } do + it_behaves_like 'contract user is unauthorized' end end - context "when ical_token is not scoped to query" do + context 'when ical_token is not scoped to query' do let(:other_query) do create(:query, project:, public:, user:) end let(:ical_token) { create(:ical_token, query: other_query, user: current_user, name: "Some Token") } - context "when user has no permission to share via ical" do + context 'when user has no permission to share via ical' do let(:permissions) { %i(view_work_packages view_calendar manage_calendars) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "when user has permission to share via ical" do + context 'when user has permission to share via ical' do let(:permissions) { %i(view_work_packages share_calendars) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end end - context "when author is someone else", with_settings: { ical_enabled: true } do + context 'when author is someone else', with_settings: { ical_enabled: true } do let(:user) { create(:user) } # other user as owner of query let(:permissions) { %i(view_work_packages share_calendars) } # all necessary permissions - it_behaves_like "contract user is unauthorized" # unauthorized as user is not author + it_behaves_like 'contract user is unauthorized' # unauthorized as user is not author end end - describe "public query" do + describe 'public query' do let(:public) { true } let(:user) { current_user } - context "when user has no permission to share via ical", with_settings: { ical_enabled: true } do + context 'when user has no permission to share via ical', with_settings: { ical_enabled: true } do let(:permissions) { %i(view_work_packages view_calendar manage_calendars) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' - context "when author is someone else" do + context 'when author is someone else' do let(:user) { create(:user) } # other user as owner of query - it_behaves_like "contract user is unauthorized" # authorized as query is public + it_behaves_like 'contract user is unauthorized' # authorized as query is public end end - context "when user has permission to share via ical", with_settings: { ical_enabled: true } do + context 'when user has permission to share via ical', with_settings: { ical_enabled: true } do let(:permissions) { %i(view_work_packages share_calendars) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when author is someone else" do + context 'when author is someone else' do let(:user) { create(:user) } # other user as owner of query - it_behaves_like "contract is valid" # authorized as query is public + it_behaves_like 'contract is valid' # authorized as query is public end - context "when iCalendar subscriptions are globally disabled", with_settings: { ical_enabled: false } do - it_behaves_like "contract user is unauthorized" + context 'when iCalendar subscriptions are globally disabled', with_settings: { ical_enabled: false } do + it_behaves_like 'contract user is unauthorized' - context "when author is someone else" do + context 'when author is someone else' do let(:user) { create(:user) } # other user as owner of query - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end end end - describe "project membership" do + describe 'project membership' do let(:public) { false } let(:other_project) { create(:project) } let(:current_user) do @@ -147,16 +147,16 @@ member_with_permissions: { other_project => permissions }) end - context "when user is author but not member of project (anymore)", with_settings: { ical_enabled: true } do + context 'when user is author but not member of project (anymore)', with_settings: { ical_enabled: true } do let(:user) { current_user } - context "when user has no permission to share via ical" do + context 'when user has no permission to share via ical' do let(:permissions) { %i(view_work_packages view_calendar manage_calendars) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/queries/projects/project_queries/create_contract_spec.rb b/spec/contracts/queries/projects/project_queries/create_contract_spec.rb index ec9466424cfd..6b56f3cfe076 100644 --- a/spec/contracts/queries/projects/project_queries/create_contract_spec.rb +++ b/spec/contracts/queries/projects/project_queries/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Queries::Projects::ProjectQueries::CreateContract do - it_behaves_like "project queries contract" do + it_behaves_like 'project queries contract' do let(:query) do Queries::Projects::ProjectQuery.new(name: query_name).tap do |query| query.extend(OpenProject::ChangedBySystem) diff --git a/spec/contracts/queries/projects/project_queries/delete_contract_spec.rb b/spec/contracts/queries/projects/project_queries/delete_contract_spec.rb index 2b7047e0a78c..7195d530aa9f 100644 --- a/spec/contracts/queries/projects/project_queries/delete_contract_spec.rb +++ b/spec/contracts/queries/projects/project_queries/delete_contract_spec.rb @@ -28,22 +28,22 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Queries::Projects::ProjectQueries::DeleteContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:query_user) { current_user } let(:query) { build_stubbed(:project_query, user: query_user) } let(:contract) { described_class.new(query, current_user) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "if the current user is not the query user" do + context 'if the current user is not the query user' do let(:query_user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end end diff --git a/spec/contracts/queries/projects/project_queries/loading_contract_spec.rb b/spec/contracts/queries/projects/project_queries/loading_contract_spec.rb index 7afe890ed826..fc469506d000 100644 --- a/spec/contracts/queries/projects/project_queries/loading_contract_spec.rb +++ b/spec/contracts/queries/projects/project_queries/loading_contract_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Queries::Projects::ProjectQueries::LoadingContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:query_user) { current_user } - let(:query_filters) { [[:active, "=", "t"]] } + let(:query_filters) { [[:active, '=', 't']] } let(:query_orders) { [%w[name asc]] } - let(:query_columns) { ["name", "public"] } + let(:query_columns) { ['name', 'public'] } let(:query) do Queries::Projects::ProjectQuery.new do |query| query_filters.each do |key, operator, values| @@ -49,7 +49,7 @@ end let(:contract) { described_class.new(query, current_user) } - describe "validation" do - it_behaves_like "contract is valid" + describe 'validation' do + it_behaves_like 'contract is valid' end end diff --git a/spec/contracts/queries/projects/project_queries/shared_contract_examples.rb b/spec/contracts/queries/projects/project_queries/shared_contract_examples.rb index 6a3315276f10..854316f71def 100644 --- a/spec/contracts/queries/projects/project_queries/shared_contract_examples.rb +++ b/spec/contracts/queries/projects/project_queries/shared_contract_examples.rb @@ -26,54 +26,54 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "project queries contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'project queries contract' do + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:query_name) { "Query name" } let(:query_user) { current_user } let(:query_selects) { %i[name project_status] } - describe "validation" do - it_behaves_like "contract is valid" + describe 'validation' do + it_behaves_like 'contract is valid' - context "if the name is nil" do + context 'if the name is nil' do let(:query_name) { nil } - it_behaves_like "contract is invalid", name: :blank + it_behaves_like 'contract is invalid', name: :blank end - context "if the name is too long" do - let(:query_name) { "A" * 256 } + context 'if the name is too long' do + let(:query_name) { 'A' * 256 } - it_behaves_like "contract is invalid", name: :too_long + it_behaves_like 'contract is invalid', name: :too_long end - context "if the user is not the current user" do + context 'if the user is not the current user' do let(:query_user) { build_stubbed(:user) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "if the user and the current user is anonymous" do + context 'if the user and the current user is anonymous' do let(:current_user) { build_stubbed(:anonymous) } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "if the selects do not include the name column" do + context 'if the selects do not include the name column' do let(:query_selects) { %i[project_status] } - it_behaves_like "contract is invalid", selects: :name_not_included + it_behaves_like 'contract is invalid', selects: :name_not_included end - context "if the selects include a non existing one" do + context 'if the selects include a non existing one' do let(:query_selects) { %i[project_status name foo_bar] } - it_behaves_like "contract is invalid", selects: :nonexistent + it_behaves_like 'contract is invalid', selects: :nonexistent end end end diff --git a/spec/contracts/queries/shared_contract_examples.rb b/spec/contracts/queries/shared_contract_examples.rb index 0c57c4d2a686..cd4590700388 100644 --- a/spec/contracts/queries/shared_contract_examples.rb +++ b/spec/contracts/queries/shared_contract_examples.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_context "with queries contract" do - include_context "ModelContract shared context" +RSpec.shared_context 'with queries contract' do + include_context 'ModelContract shared context' let(:project) { build_stubbed(:project) } - let(:name) { "Some query name" } + let(:name) { 'Some query name' } let(:public) { false } let(:user) { current_user } let(:permissions) { %i[save_queries] } @@ -56,21 +56,21 @@ allow(contract).to receive(:project_visible?).and_return true end - describe "validation" do - it_behaves_like "contract is valid" + describe 'validation' do + it_behaves_like 'contract is valid' - context "if the name is nil" do + context 'if the name is nil' do let(:name) { nil } - it_behaves_like "contract is invalid", name: :blank + it_behaves_like 'contract is invalid', name: :blank end - context "if the name is empty" do - let(:name) { "" } + context 'if the name is empty' do + let(:name) { '' } - it_behaves_like "contract is invalid", name: :blank + it_behaves_like 'contract is invalid', name: :blank end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/queries/update_contract_spec.rb b/spec/contracts/queries/update_contract_spec.rb index 1c65b1fd87dc..4e657c17d502 100644 --- a/spec/contracts/queries/update_contract_spec.rb +++ b/spec/contracts/queries/update_contract_spec.rb @@ -26,59 +26,59 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Queries::UpdateContract do - include_context "with queries contract" + include_context 'with queries contract' - describe "private query" do + describe 'private query' do let(:public) { false } - context "when user is author" do + context 'when user is author' do let(:user) { current_user } - context "when user has no permission to save" do + context 'when user has no permission to save' do let(:permissions) { %i(edit_work_packages) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "when user has permission to save" do + context 'when user has permission to save' do let(:permissions) { %i(save_queries) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - context "when user is someone else" do + context 'when user is someone else' do let(:user) { build_stubbed(:user) } let(:permissions) { %i(save_queries) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end - describe "public query" do + describe 'public query' do let(:public) { true } let(:user) { nil } - context "when user has no permission to save" do + context 'when user has no permission to save' do let(:permissions) { %i() } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "when user has no permission to manage public" do + context 'when user has no permission to manage public' do let(:permissions) { %i(manage_public_queries) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when user has permission to save only own" do + context 'when user has permission to save only own' do let(:permissions) { %i(save_queries) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end end diff --git a/spec/contracts/relations/create_contract_spec.rb b/spec/contracts/relations/create_contract_spec.rb index 47cd3de84b0c..4e3f5f150367 100644 --- a/spec/contracts/relations/create_contract_spec.rb +++ b/spec/contracts/relations/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Relations::CreateContract do - it_behaves_like "relation contract" do + it_behaves_like 'relation contract' do let(:relation) do Relation.new from: relation_from, to: relation_to, diff --git a/spec/contracts/relations/shared_contract_examples.rb b/spec/contracts/relations/shared_contract_examples.rb index 175801fd373f..d81355229d95 100644 --- a/spec/contracts/relations/shared_contract_examples.rb +++ b/spec/contracts/relations/shared_contract_examples.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "contracts/shared/model_contract_shared_context" +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "relation contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'relation contract' do + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:relation_from) do - build_stubbed(:work_package, subject: "From WP") do |wp| + build_stubbed(:work_package, subject: 'From WP') do |wp| allow(wp_visible_scope) .to receive(:exists?) .with(wp.id) @@ -41,7 +41,7 @@ end end let(:relation_to) do - build_stubbed(:work_package, subject: "To WP") do |wp| + build_stubbed(:work_package, subject: 'To WP') do |wp| allow(wp_visible_scope) .to receive(:exists?) .with(wp.id) @@ -100,41 +100,41 @@ end end - describe "validation" do - it_behaves_like "contract is valid" + describe 'validation' do + it_behaves_like 'contract is valid' - context "when lacking the necessary permission" do + context 'when lacking the necessary permission' do let(:permissions) { [] } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "when the work package for from is not visible" do + context 'when the work package for from is not visible' do let(:relation_from_visible) { false } - it_behaves_like "contract is invalid", from: :error_not_found + it_behaves_like 'contract is invalid', from: :error_not_found end - context "when the work package for to is not visible" do + context 'when the work package for to is not visible' do let(:relation_to_visible) { false } - it_behaves_like "contract is invalid", to: :error_not_found + it_behaves_like 'contract is invalid', to: :error_not_found end Relation::TYPES.each_key do |available_type| context "when having the type '#{available_type}'" do let(:relation_type) { available_type } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - context "when the work package type is unknown" do - let(:relation_type) { "some_bogus" } + context 'when the work package type is unknown' do + let(:relation_type) { 'some_bogus' } - it_behaves_like "contract is invalid", relation_type: :inclusion + it_behaves_like 'contract is invalid', relation_type: :inclusion end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/relations/update_contract_spec.rb b/spec/contracts/relations/update_contract_spec.rb index d8c925dd0959..e7f770ff3d7c 100644 --- a/spec/contracts/relations/update_contract_spec.rb +++ b/spec/contracts/relations/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Relations::UpdateContract do - it_behaves_like "relation contract" do + it_behaves_like 'relation contract' do let(:relation) do build_stubbed(:relation, from: relation_from, @@ -40,12 +40,12 @@ end end - describe "valid?" do + describe 'valid?' do create_shared_association_defaults_for_work_package_factory let(:current_user) { build_stubbed(:admin) } let(:contract) { described_class.new(relation, current_user) } - context "when an isolated relation is reversed" do + context 'when an isolated relation is reversed' do let(:relation) do create(:relation, relation_type: Relation::TYPE_BLOCKS) end @@ -54,12 +54,12 @@ relation.relation_type = Relation::TYPE_BLOCKED end - it "is valid" do + it 'is valid' do expect(contract).to be_valid end end - context "when a relation that cannot be reversed is reversed" do + context 'when a relation that cannot be reversed is reversed' do let(:relation_from_wp) { create(:work_package) } let(:relation_to_wp) { create(:work_package) } let(:intermediary_wp) { create(:work_package) } @@ -88,7 +88,7 @@ relation.relation_type = Relation::TYPE_PRECEDES end - it "is invalid" do + it 'is invalid' do expect(contract).not_to be_valid end end diff --git a/spec/contracts/roles/create_contract_spec.rb b/spec/contracts/roles/create_contract_spec.rb index 776d8d94399a..72d78d0f5d39 100644 --- a/spec/contracts/roles/create_contract_spec.rb +++ b/spec/contracts/roles/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Roles::CreateContract do - it_behaves_like "roles contract" do + it_behaves_like 'roles contract' do let(:work_package_role) do build(:work_package_role) do |r| r.name = role_name @@ -54,21 +54,21 @@ subject(:contract) { described_class.new(role, current_user) } - describe "validation" do - context "with the type set manually" do + describe 'validation' do + context 'with the type set manually' do before do - role.type = "GlobalRole" + role.type = 'GlobalRole' end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "with the type set manually to something other than Role or GlobalRole" do + context 'with the type set manually to something other than Role or GlobalRole' do before do - role.type = "MyRole" + role.type = 'MyRole' end - it "is invalid" do + it 'is invalid' do # The inclusion is in here twice because: # * The contract validates the type (to check that only GlobalRole and ProjectRole are created) # * The model validates the type (to check that only Role subclasses are created) diff --git a/spec/contracts/roles/shared_contract_examples.rb b/spec/contracts/roles/shared_contract_examples.rb index 04cee35ae438..61a2943ed833 100644 --- a/spec/contracts/roles/shared_contract_examples.rb +++ b/spec/contracts/roles/shared_contract_examples.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "roles contract" do +RSpec.shared_examples_for 'roles contract' do let(:current_user) do build_stubbed(:admin) end let(:role_instance) { Role.new } - let(:role_name) { "A role name" } + let(:role_name) { 'A role name' } let(:role_permissions) { [:view_work_packages] } def expect_valid(valid, symbols = {}) @@ -44,33 +44,33 @@ def expect_valid(valid, symbols = {}) end end - shared_examples "is valid" do - it "is valid" do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - describe "validation" do - it_behaves_like "is valid" + describe 'validation' do + it_behaves_like 'is valid' - context "if the name is nil" do + context 'if the name is nil' do let(:role_name) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, name: %i(blank)) end end - context "if the permissions do not include their dependency" do + context 'if the permissions do not include their dependency' do let(:role_permissions) { [:manage_members] } - it "is invalid" do + it 'is invalid' do expect_valid(false, permissions: %i(dependency_missing)) end end end - describe "#assignable_permissions" do + describe '#assignable_permissions' do let(:permission1) { instance_double(OpenProject::AccessControl::Permission, name: :perm1, public?: false) } let(:permission2) { instance_double(OpenProject::AccessControl::Permission, name: :perm2, public?: true) } let(:permission3) { instance_double(OpenProject::AccessControl::Permission, name: :perm3, public?: false) } @@ -78,36 +78,36 @@ def expect_valid(valid, symbols = {}) let(:all_permissions) { [permission1, permission2, permission3] } let(:public_permissions) { [permission2] } - context "for a project role" do + context 'for a project role' do before do allow(OpenProject::AccessControl).to receive_messages(project_permissions: all_permissions, public_permissions:) end - it "is all project permissions" do + it 'is all project permissions' do expect(contract.assignable_permissions).to match_array(all_permissions - public_permissions) end end - context "for a work package role" do + context 'for a work package role' do let(:role) { work_package_role } before do allow(OpenProject::AccessControl).to receive(:work_package_permissions).and_return(all_permissions) end - it "is all work package permissions" do + it 'is all work package permissions' do expect(contract.assignable_permissions).to match_array(all_permissions - public_permissions) end end - context "for a global role" do + context 'for a global role' do let(:role) { global_role } before do allow(OpenProject::AccessControl).to receive(:global_permissions).and_return(all_permissions) end - it "is all the global permissions" do + it 'is all the global permissions' do expect(contract.assignable_permissions).to match_array(all_permissions - public_permissions) end end diff --git a/spec/contracts/roles/update_contract_spec.rb b/spec/contracts/roles/update_contract_spec.rb index 0888b09bf1ec..792ad15bcf98 100644 --- a/spec/contracts/roles/update_contract_spec.rb +++ b/spec/contracts/roles/update_contract_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Roles::UpdateContract do - it_behaves_like "roles contract" do + it_behaves_like 'roles contract' do let(:work_package_role) do build_stubbed(:work_package_role, - name: "Some name") do |r| + name: 'Some name') do |r| r.name = role_name r.permissions = role_permissions end @@ -41,7 +41,7 @@ let(:role) do build_stubbed(:project_role, - name: "Some name") do |r| + name: 'Some name') do |r| r.name = role_name r.permissions = role_permissions end @@ -49,7 +49,7 @@ let(:global_role) do build_stubbed(:global_role, - name: "Some name") do |r| + name: 'Some name') do |r| r.name = role_name r.permissions = role_permissions end @@ -57,13 +57,13 @@ subject(:contract) { described_class.new(role, current_user) } - describe "validation" do - context "with the type set manually" do + describe 'validation' do + context 'with the type set manually' do before do - role.type = "GlobalRole" + role.type = 'GlobalRole' end - it "is invalid" do + it 'is invalid' do expect_valid(false, type: %i(error_readonly)) end end diff --git a/spec/contracts/settings/update_contract_spec.rb b/spec/contracts/settings/update_contract_spec.rb index 71f1f807adca..81b52742b9dc 100644 --- a/spec/contracts/settings/update_contract_spec.rb +++ b/spec/contracts/settings/update_contract_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe Settings::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:contract) do described_class.new(nil, current_user) end - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' end diff --git a/spec/contracts/settings/working_days_params_contract_spec.rb b/spec/contracts/settings/working_days_params_contract_spec.rb index 31f2e46ec8bd..79b995423c68 100644 --- a/spec/contracts/settings/working_days_params_contract_spec.rb +++ b/spec/contracts/settings/working_days_params_contract_spec.rb @@ -31,12 +31,19 @@ RSpec.describe Settings::WorkingDaysParamsContract do include_context 'ModelContract shared context' - shared_let(:current_user) { create(:admin) } let(:setting) { Setting } + let(:current_user) { build_stubbed(:admin) } let(:params) { { working_days: [1] } } let(:contract) do described_class.new(setting, current_user, params:) end + let(:apply_job_scheduled) { false } + + before do + allow(WorkPackages::ApplyWorkingDaysChangeJob) + .to receive(:scheduled?) + .and_return(apply_job_scheduled) + end it_behaves_like 'contract is valid for active admins and invalid for regular users' @@ -46,17 +53,9 @@ include_examples 'contract is invalid', base: :working_days_are_missing end - context 'with an ApplyWorkingDaysChangeJob already existing', - with_good_job: WorkPackages::ApplyWorkingDaysChangeJob do + context 'with an ApplyWorkingDaysChangeJob already existing' do let(:params) { { working_days: [1, 2, 3] } } - - before do - WorkPackages::ApplyWorkingDaysChangeJob - .set(wait: 10.minutes) # GoodJob executes inline job without wait immediately - .perform_later(user_id: current_user.id, - previous_non_working_days: [], - previous_working_days: [1, 2, 3, 4]) - end + let(:apply_job_scheduled) { true } include_examples 'contract is invalid', base: :previous_working_day_changes_unprocessed end diff --git a/spec/contracts/shared/model_contract_shared_context.rb b/spec/contracts/shared/model_contract_shared_context.rb index 6fa875de44fc..47de6311421b 100644 --- a/spec/contracts/shared/model_contract_shared_context.rb +++ b/spec/contracts/shared/model_contract_shared_context.rb @@ -1,4 +1,4 @@ -RSpec.shared_context "ModelContract shared context" do # rubocop:disable RSpec/ContextWording +RSpec.shared_context 'ModelContract shared context' do # rubocop:disable RSpec/ContextWording def expect_contract_valid expect(contract.validate) .to be(true), @@ -15,14 +15,14 @@ def expect_contract_invalid(errors = {}) end end - shared_examples "contract is valid" do - it "contract is valid" do + shared_examples 'contract is valid' do + it 'contract is valid' do expect_contract_valid end end - shared_examples "contract is invalid" do |error_symbols = {}| - example_title = "contract is invalid" + shared_examples 'contract is invalid' do |error_symbols = {}| + example_title = 'contract is invalid' example_title << " with #{error_symbols.inspect}" if error_symbols.any? it example_title do @@ -30,34 +30,34 @@ def expect_contract_invalid(errors = {}) end end - shared_examples "contract user is unauthorized" do - include_examples "contract is invalid", base: :error_unauthorized + shared_examples 'contract user is unauthorized' do + include_examples 'contract is invalid', base: :error_unauthorized end - shared_examples "contract is valid for active admins and invalid for regular users" do - context "when admin" do + shared_examples 'contract is valid for active admins and invalid for regular users' do + context 'when admin' do let(:current_user) { build_stubbed(:admin) } - context "when active" do - include_examples "contract is valid" + context 'when active' do + include_examples 'contract is valid' end - context "when not active" do + context 'when not active' do let(:current_user) { build_stubbed(:admin, status: User.statuses[:locked]) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end - context "when not admin" do + context 'when not admin' do let(:current_user) { build_stubbed(:user) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end end - shared_examples "contract reuses the model errors" do - it "reuses the model`s errors object" do + shared_examples 'contract reuses the model errors' do + it 'reuses the model`s errors object' do expect(contract.errors.object_id).to be(contract.model.errors.object_id) end end diff --git a/spec/contracts/user_preferences/params_contract_spec.rb b/spec/contracts/user_preferences/params_contract_spec.rb index 937c2fcf70b5..e436195d0724 100644 --- a/spec/contracts/user_preferences/params_contract_spec.rb +++ b/spec/contracts/user_preferences/params_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe UserPreferences::ParamsContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:preference_user) { current_user } @@ -47,20 +47,20 @@ { hide_mail: true, auto_hide_popups: true, - comments_sorting: "desc", + comments_sorting: 'desc', daily_reminders: { enabled: true, times: %w[08:00:00+00:00 12:00:00+00:00] }, - time_zone: "Brasilia", + time_zone: 'Brasilia', warn_on_leaving_unsaved: true, notification_settings: } end let(:contract) { described_class.new(user_preference, current_user, params:) } - describe "notification settings" do - context "when multiple global settings" do + describe 'notification settings' do + context 'when multiple global settings' do let(:notification_settings) do [ { project_id: nil, mentioned: true }, @@ -68,39 +68,39 @@ ] end - it_behaves_like "contract is invalid", notification_settings: :only_one_global_setting + it_behaves_like 'contract is invalid', notification_settings: :only_one_global_setting end - context "when project settings with an email alert set" do + context 'when project settings with an email alert set' do let(:notification_settings) do [ { project_id: 1234, news_added: true } ] end - it_behaves_like "contract is invalid", notification_settings: :email_alerts_global + it_behaves_like 'contract is invalid', notification_settings: :email_alerts_global end - context "when global settings with an email alert set" do + context 'when global settings with an email alert set' do let(:notification_settings) do [ { project_id: nil, news_added: true } ] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "without enterprise" do - context "when global setting with start_date, due_date and overdue set" do + context 'without enterprise' do + context 'when global setting with start_date, due_date and overdue set' do let(:notification_settings) do [ { start_date: 1, due_date: 1, overdue: 1 } ] end - it_behaves_like "contract is invalid", base: :error_enterprise_only do - it "displays the error message containing the feature name" do + it_behaves_like 'contract is invalid', base: :error_enterprise_only do + it 'displays the error message containing the feature name' do contract.validate expect(contract.errors.full_messages) .to eq(["Date Alerts is only available in the OpenProject Enterprise edition"]) @@ -108,117 +108,117 @@ end end - context "when project setting with start_date, due_date and overdue set" do + context 'when project setting with start_date, due_date and overdue set' do let(:notification_settings) do [ { project_id: 1234, start_date: 1, due_date: 1, overdue: 1 } ] end - it_behaves_like "contract is invalid", base: :error_enterprise_only + it_behaves_like 'contract is invalid', base: :error_enterprise_only end end - context "with enterprise", with_ee: %i[date_alerts] do - context "when project setting with start_date, due_date and overdue set" do + context 'with enterprise', with_ee: %i[date_alerts] do + context 'when project setting with start_date, due_date and overdue set' do let(:notification_settings) do [ { project_id: 1234, start_date: 1, due_date: 1, overdue: 1 } ] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when global setting with start_date, due_date and overdue set" do + context 'when global setting with start_date, due_date and overdue set' do let(:notification_settings) do [ { start_date: 1, due_date: 1, overdue: 1 } ] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when project setting with valid start_date, valid due_date and invalid overdue" do + context 'when project setting with valid start_date, valid due_date and invalid overdue' do let(:notification_settings) do [ { project_id: 1234, start_date: 1, due_date: 1, overdue: 0 } ] end - it_behaves_like "contract is invalid", notification_settings: :wrong_date + it_behaves_like 'contract is invalid', notification_settings: :wrong_date end - context "when global setting with invalid start_date, valid due_date and valid overdue" do + context 'when global setting with invalid start_date, valid due_date and valid overdue' do let(:notification_settings) do [ { start_date: -1, due_date: 1, overdue: 1 } ] end - it_behaves_like "contract is invalid", notification_settings: :wrong_date + it_behaves_like 'contract is invalid', notification_settings: :wrong_date end - context "when project setting with start_date, due_date and overdue missing" do + context 'when project setting with start_date, due_date and overdue missing' do let(:notification_settings) do [ { project_id: 1234, start_date: 1, due_date: 1 } ] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when global setting with start_date, due_date and overdue missing" do + context 'when global setting with start_date, due_date and overdue missing' do let(:notification_settings) do [ { start_date: 1, due_date: 1 } ] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when project setting with valid start_date, invalid due_date and overdue missing" do + context 'when project setting with valid start_date, invalid due_date and overdue missing' do let(:notification_settings) do [ { project_id: 1234, start_date: 1, due_date: 24 } ] end - it_behaves_like "contract is invalid", notification_settings: :wrong_date + it_behaves_like 'contract is invalid', notification_settings: :wrong_date end - context "when global setting with invalid start_date, valid due_date and overdue missing" do + context 'when global setting with invalid start_date, valid due_date and overdue missing' do let(:notification_settings) do [ { start_date: 24, due_date: 1 } ] end - it_behaves_like "contract is invalid", notification_settings: :wrong_date + it_behaves_like 'contract is invalid', notification_settings: :wrong_date end end - context "when notification_settings empty" do + context 'when notification_settings empty' do let(:params) do { hide_mail: true, auto_hide_popups: true, - comments_sorting: "desc", + comments_sorting: 'desc', daily_reminders: { enabled: true, times: %w[08:00:00+00:00 12:00:00+00:00] }, - time_zone: "Brasilia", + time_zone: 'Brasilia', warn_on_leaving_unsaved: true } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/user_preferences/update_contract_spec.rb b/spec/contracts/user_preferences/update_contract_spec.rb index b5e17029ff89..582dda716bb3 100644 --- a/spec/contracts/user_preferences/update_contract_spec.rb +++ b/spec/contracts/user_preferences/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' RSpec.describe UserPreferences::UpdateContract do - include_context "ModelContract shared context" + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } let(:preference_user) { current_user } @@ -43,27 +43,27 @@ { hide_mail: true, auto_hide_popups: true, - comments_sorting: "desc", + comments_sorting: 'desc', daily_reminders: { enabled: true, times: %w[08:00:00+00:00 12:00:00+00:00] }, - time_zone: "America/Sao_Paulo", + time_zone: 'America/Sao_Paulo', warn_on_leaving_unsaved: true, workdays: [1, 2, 4, 6] } end let(:contract) { described_class.new(user_preference, current_user) } - describe "validation" do - context "when current_user is admin" do + describe 'validation' do + context 'when current_user is admin' do let(:current_user) { build_stubbed(:admin) } let(:preference_user) { build_stubbed(:user) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when current_user has manage_user permission" do + context 'when current_user has manage_user permission' do let(:preference_user) { build_stubbed(:user) } before do @@ -72,65 +72,65 @@ end end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "when current_user is the own user" do - it_behaves_like "contract is valid" + context 'when current_user is the own user' do + it_behaves_like 'contract is valid' end - context "when current_user is the own user but not active" do + context 'when current_user is the own user but not active' do before do allow(current_user).to receive(:active?).and_return false end - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "when current_user is anonymous" do + context 'when current_user is anonymous' do let(:current_user) { User.anonymous } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "when current_user is a regular user" do + context 'when current_user is a regular user' do let(:preference_user) { build_stubbed(:user) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' end - context "with empty settings" do + context 'with empty settings' do let(:settings) do {} end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a string for hide_mail" do + context 'with a string for hide_mail' do let(:settings) do { - hide_mail: "yes please" + hide_mail: 'yes please' } end - it_behaves_like "contract is invalid", hide_mail: :type_mismatch + it_behaves_like 'contract is invalid', hide_mail: :type_mismatch end - context "with a field within the daily_reminders having the wrong type" do + context 'with a field within the daily_reminders having the wrong type' do let(:settings) do { daily_reminders: { - enabled: "sure", + enabled: 'sure', times: %w[08:00:00+00:00 12:00:00+00:00] } } end - it_behaves_like "contract is invalid", daily_reminders: :type_mismatch_nested + it_behaves_like 'contract is invalid', daily_reminders: :type_mismatch_nested end - context "with a field within the daily_reminders missing" do + context 'with a field within the daily_reminders missing' do let(:settings) do { daily_reminders: { @@ -139,20 +139,20 @@ } end - it_behaves_like "contract is invalid", daily_reminders: :blank_nested + it_behaves_like 'contract is invalid', daily_reminders: :blank_nested end - context "with an extra property" do + context 'with an extra property' do let(:settings) do { foo: true } end - it_behaves_like "contract is invalid", foo: :unknown_property + it_behaves_like 'contract is invalid', foo: :unknown_property end - context "with an extra property within the daily_reminders" do + context 'with an extra property within the daily_reminders' do let(:settings) do { daily_reminders: { @@ -163,10 +163,10 @@ } end - it_behaves_like "contract is invalid", daily_reminders: :unknown_property_nested + it_behaves_like 'contract is invalid', daily_reminders: :unknown_property_nested end - context "with an invalid time for the daily_reminders" do + context 'with an invalid time for the daily_reminders' do let(:settings) do { daily_reminders: { @@ -176,10 +176,10 @@ } end - it_behaves_like "contract is invalid", daily_reminders: %i[format_nested full_hour] + it_behaves_like 'contract is invalid', daily_reminders: %i[format_nested full_hour] end - context "with a sub hour time for the daily_reminders" do + context 'with a sub hour time for the daily_reminders' do let(:settings) do { daily_reminders: { @@ -189,25 +189,25 @@ } end - it_behaves_like "contract is invalid", daily_reminders: :full_hour + it_behaves_like 'contract is invalid', daily_reminders: :full_hour end - context "with an invalid order for comments_sorting" do + context 'with an invalid order for comments_sorting' do let(:settings) do { - comments_sorting: "up" + comments_sorting: 'up' } end - it_behaves_like "contract is invalid", comments_sorting: :inclusion + it_behaves_like 'contract is invalid', comments_sorting: :inclusion end - context "without a time_zone" do + context 'without a time_zone' do let(:settings) do { hide_mail: true, auto_hide_popups: true, - comments_sorting: "desc", + comments_sorting: 'desc', daily_reminders: { enabled: true, times: %w[08:00:00+00:00 12:00:00+00:00] @@ -216,165 +216,165 @@ } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a full time_zone" do + context 'with a full time_zone' do let(:settings) do { - time_zone: "Europe/Paris" + time_zone: 'Europe/Paris' } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a non ActiveSupport::Timezone timezone" do + context 'with a non ActiveSupport::Timezone timezone' do let(:settings) do { - time_zone: "America/Adak" + time_zone: 'America/Adak' } end - it_behaves_like "contract is invalid", time_zone: :inclusion + it_behaves_like 'contract is invalid', time_zone: :inclusion end - context "with a malformed time_zone" do + context 'with a malformed time_zone' do let(:settings) do { - time_zone: "123Brasilia" + time_zone: '123Brasilia' } end - it_behaves_like "contract is invalid", time_zone: :inclusion + it_behaves_like 'contract is invalid', time_zone: :inclusion end - context "with a non tzinfo time_zone" do + context 'with a non tzinfo time_zone' do let(:settings) do { - time_zone: "Brasilia" + time_zone: 'Brasilia' } end - it_behaves_like "contract is invalid", time_zone: :inclusion + it_behaves_like 'contract is invalid', time_zone: :inclusion end - context "with duplicate workday entries" do + context 'with duplicate workday entries' do let(:settings) do { workdays: [1, 1] } end - it_behaves_like "contract is invalid", workdays: :no_duplicates + it_behaves_like 'contract is invalid', workdays: :no_duplicates end - context "with non-iso workday entries" do + context 'with non-iso workday entries' do let(:settings) do { - workdays: [nil, "foo", :bar, 21345, 2.0] + workdays: [nil, 'foo', :bar, 21345, 2.0] } end - it_behaves_like "contract is invalid", workdays: %i[invalid type_mismatch_nested + it_behaves_like 'contract is invalid', workdays: %i[invalid type_mismatch_nested type_mismatch_nested type_mismatch_nested] end end - describe "#assignable_time_zones" do + describe '#assignable_time_zones' do subject(:time_zones) { contract.assignable_time_zones } - it "returns a list of AS::TimeZones" do + it 'returns a list of AS::TimeZones' do expect(time_zones) .to(be_all { |tz| tz.is_a?(ActiveSupport::TimeZone) }) end - it "includes only the namesake zone if multiple AS::Timezone map to the same TZInfo" do + it 'includes only the namesake zone if multiple AS::Timezone map to the same TZInfo' do # In this case 'Edinburgh' and 'Bern' are not included expect(time_zones.select { |tz| %w[Europe/London Europe/Zurich].include? tz.tzinfo.canonical_zone.name }) - .to contain_exactly(ActiveSupport::TimeZone["London"], ActiveSupport::TimeZone["Zurich"]) + .to contain_exactly(ActiveSupport::TimeZone['London'], ActiveSupport::TimeZone['Zurich']) end end - describe "pause_reminders" do - context "with enabled false" do + describe 'pause_reminders' do + context 'with enabled false' do let(:settings) do { pause_reminders: { enabled: false } } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with enabled true but and valid range" do + context 'with enabled true but and valid range' do let(:settings) do { pause_reminders: { enabled: true, - first_day: "2021-10-05", - last_day: "2021-10-10" + first_day: '2021-10-05', + last_day: '2021-10-10' } } end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with empty object" do + context 'with empty object' do let(:settings) do { pause_reminders: {} } end - it_behaves_like "contract is invalid", pause_reminders: :blank_nested + it_behaves_like 'contract is invalid', pause_reminders: :blank_nested end - context "with enabled true but no days" do + context 'with enabled true but no days' do let(:settings) do { pause_reminders: { enabled: true } } end - it_behaves_like "contract is invalid", pause_reminders: :blank + it_behaves_like 'contract is invalid', pause_reminders: :blank end - context "with enabled true but invalid dates" do + context 'with enabled true but invalid dates' do let(:settings) do { pause_reminders: { enabled: true, - first_day: "2021-10-05T08:21:35Z", - last_day: "2021-10-05T08:21:35Z" + first_day: '2021-10-05T08:21:35Z', + last_day: '2021-10-05T08:21:35Z' } } end - it_behaves_like "contract is invalid", pause_reminders: %i[format_nested format_nested] + it_behaves_like 'contract is invalid', pause_reminders: %i[format_nested format_nested] end - context "with enabled true but only first day" do + context 'with enabled true but only first day' do let(:settings) do { - pause_reminders: { enabled: true, first_day: "2021-10-05" } + pause_reminders: { enabled: true, first_day: '2021-10-05' } } end - it_behaves_like "contract is invalid", pause_reminders: :blank + it_behaves_like 'contract is invalid', pause_reminders: :blank end - context "with enabled true but only last day" do + context 'with enabled true but only last day' do let(:settings) do { - pause_reminders: { enabled: true, last_day: "2021-10-05" } + pause_reminders: { enabled: true, last_day: '2021-10-05' } } end - it_behaves_like "contract is invalid", pause_reminders: :blank + it_behaves_like 'contract is invalid', pause_reminders: :blank end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/users/create_contract_spec.rb b/spec/contracts/users/create_contract_spec.rb index f145a076731f..6bb0bf6ac3fc 100644 --- a/spec/contracts/users/create_contract_spec.rb +++ b/spec/contracts/users/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Users::CreateContract do - it_behaves_like "user contract" do + it_behaves_like 'user contract' do let(:user) { User.new(attributes) } let(:contract) { described_class.new(user, current_user) } let(:attributes) do @@ -45,35 +45,35 @@ } end - context "when admin" do + context 'when admin' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - describe "requires a password set when active" do + describe 'requires a password set when active' do before do user.password = nil user.password_confirmation = nil user.activate end - it_behaves_like "contract is invalid", password: :blank + it_behaves_like 'contract is invalid', password: :blank - context "when password is set" do + context 'when password is set' do before do - user.password = user.password_confirmation = "password!password!" + user.password = user.password_confirmation = 'password!password!' end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end - context "when user limit reached" do + context 'when user limit reached' do before do allow(OpenProject::Enterprise).to receive(:user_limit_reached?).and_return(true) end - it_behaves_like "contract is invalid", base: :user_limit_reached + it_behaves_like 'contract is invalid', base: :user_limit_reached end end end diff --git a/spec/contracts/users/shared_contract_examples.rb b/spec/contracts/users/shared_contract_examples.rb index b49c82e8b613..fcc447a150e4 100644 --- a/spec/contracts/users/shared_contract_examples.rb +++ b/spec/contracts/users/shared_contract_examples.rb @@ -26,50 +26,50 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "user contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'user contract' do + include_context 'ModelContract shared context' - let(:user_firstname) { "Bob" } - let(:user_lastname) { "Bobbit" } - let(:user_login) { "bob" } - let(:user_mail) { "bobbit@bob.com" } - let(:user_password) { "adminADMIN!" } - let(:user_password_confirmation) { "adminADMIN!" } + let(:user_firstname) { 'Bob' } + let(:user_lastname) { 'Bobbit' } + let(:user_login) { 'bob' } + let(:user_mail) { 'bobbit@bob.com' } + let(:user_password) { 'adminADMIN!' } + let(:user_password_confirmation) { 'adminADMIN!' } - it_behaves_like "contract is valid for active admins and invalid for regular users" + it_behaves_like 'contract is valid for active admins and invalid for regular users' - context "when admin" do + context 'when admin' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end - context "when global user" do + context 'when global user' do let(:current_user) { create(:user, global_permissions: %i[create_user manage_user]) } - describe "cannot set the password" do + describe 'cannot set the password' do before do - user.password = user.password_confirmation = "password!password!" + user.password = user.password_confirmation = 'password!password!' end - it_behaves_like "contract is invalid", password: :error_readonly + it_behaves_like 'contract is invalid', password: :error_readonly end - describe "can set the status" do + describe 'can set the status' do before do user.password = user.password_confirmation = nil user.status = Principal.statuses[:invited] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - describe "can set the auth_source" do + describe 'can set the auth_source' do let!(:auth_source) { create(:ldap_auth_source) } before do @@ -77,25 +77,25 @@ user.ldap_auth_source = auth_source end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - describe "cannot set the identity url" do + describe 'cannot set the identity url' do before do - user.identity_url = "saml:123412foo" + user.identity_url = 'saml:123412foo' end - it_behaves_like "contract is invalid", identity_url: :error_readonly + it_behaves_like 'contract is invalid', identity_url: :error_readonly end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end - context "when unauthorized user" do + context 'when unauthorized user' do let(:current_user) { build_stubbed(:user) } - it_behaves_like "contract user is unauthorized" + it_behaves_like 'contract user is unauthorized' - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end end diff --git a/spec/contracts/users/update_contract_spec.rb b/spec/contracts/users/update_contract_spec.rb index 033514260c48..a9bc4963268e 100644 --- a/spec/contracts/users/update_contract_spec.rb +++ b/spec/contracts/users/update_contract_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Users::UpdateContract do let!(:default_admin) { create(:admin) } - it_behaves_like "user contract" do + it_behaves_like 'user contract' do let(:current_user) { create(:admin) } let(:user) { build_stubbed(:user, attributes) } let(:contract) { described_class.new(user, current_user) } @@ -47,54 +47,54 @@ } end - context "with a system user" do + context 'with a system user' do let(:current_user) { create(:system) } let(:user) { create(:admin, attributes) } - context "when admin flag is removed" do + context 'when admin flag is removed' do before do user.admin = false end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when no admins left" do + context 'when no admins left' do let(:default_admin) { nil } - it_behaves_like "contract is invalid", base: :one_must_be_active + it_behaves_like 'contract is invalid', base: :one_must_be_active end end - context "when status is locked on an admin user" do + context 'when status is locked on an admin user' do before do user.status = :locked end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when no admins left" do + context 'when no admins left' do let(:default_admin) { nil } - it_behaves_like "contract is invalid", base: :one_must_be_active + it_behaves_like 'contract is invalid', base: :one_must_be_active end end end - context "when global user" do + context 'when global user' do let(:current_user) { create(:user, global_permissions: :manage_user) } - describe "can lock the user" do + describe 'can lock the user' do before do user.status = Principal.statuses[:locked] end - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - describe "cannot update an administrator" do + describe 'cannot update an administrator' do let(:user) { build_stubbed(:admin, attributes) } - it_behaves_like "contract is invalid" + it_behaves_like 'contract is invalid' end end @@ -102,14 +102,14 @@ # That scenario is the only that is not covered by the shared examples let(:current_user) { user } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' - context "when setting status" do + context 'when setting status' do before do user.status = Principal.statuses[:locked] end - it_behaves_like "contract is invalid", status: :error_readonly + it_behaves_like 'contract is invalid', status: :error_readonly end end end diff --git a/spec/contracts/versions/create_contract_spec.rb b/spec/contracts/versions/create_contract_spec.rb index 1304fa278019..b06af3050952 100644 --- a/spec/contracts/versions/create_contract_spec.rb +++ b/spec/contracts/versions/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Versions::CreateContract do - it_behaves_like "version contract" do + it_behaves_like 'version contract' do let(:version) do Version.new(name: version_name, project: version_project, @@ -44,9 +44,9 @@ subject(:contract) { described_class.new(version, current_user) } - describe "assignable_values" do - context "for project" do - let(:assignable_projects) { double("assignable projects") } + describe 'assignable_values' do + context 'for project' do + let(:assignable_projects) { double('assignable projects') } before do allow(Project) @@ -55,37 +55,37 @@ .and_return(assignable_projects) end - it "is all projects the user has :manage_versions permission in" do + it 'is all projects the user has :manage_versions permission in' do expect(subject.assignable_values(:project, current_user)) .to eql assignable_projects end end - context "for status" do - it "is a list of all available status" do + context 'for status' do + it 'is a list of all available status' do expect(subject.assignable_values(:status, current_user)) .to eql %w(open locked closed) end end - context "for sharing" do - it "is a list of values" do + context 'for sharing' do + it 'is a list of values' do expect(subject.assignable_values(:sharing, current_user)) .to match_array %w(none descendants hierarchy tree) end - context "if the user is admin" do + context 'if the user is admin' do let(:current_user) { build_stubbed(:admin) } - it "is a list of values" do + it 'is a list of values' do expect(subject.assignable_values(:sharing, current_user)) .to match_array %w(none descendants system hierarchy tree) end end end - context "for something else" do - it "is nil" do + context 'for something else' do + it 'is nil' do expect(subject.assignable_values(:start_date, current_user)) .to be_nil end diff --git a/spec/contracts/versions/shared_contract_examples.rb b/spec/contracts/versions/shared_contract_examples.rb index 5cde71bd8f11..b2adb3bee2d1 100644 --- a/spec/contracts/versions/shared_contract_examples.rb +++ b/spec/contracts/versions/shared_contract_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "version contract" do +RSpec.shared_examples_for 'version contract' do let(:current_user) { build_stubbed(:user) } before do @@ -55,23 +55,23 @@ end end let(:find_page_result) do - double("page found") + double('page found') end let(:wiki_pages) do [build_stubbed(:wiki_page), build_stubbed(:wiki_page)] end - let(:version_name) { "Version name" } - let(:version_description) { "Version description" } + let(:version_name) { 'Version name' } + let(:version_description) { 'Version description' } let(:version_start_date) { Date.current - 5.days } let(:version_due_date) { Date.current + 5.days } - let(:version_status) { "open" } - let(:version_sharing) { "none" } - let(:version_wiki_page_title) { "some page" } + let(:version_status) { 'open' } + let(:version_sharing) { 'none' } + let(:version_wiki_page_title) { 'some page' } let(:permissions) { [:manage_versions] } let(:root_permissions) { [:manage_versions] } - context "validations" do + context 'validations' do def expect_valid(valid, symbols = {}) expect(contract.validate).to eq(valid) @@ -80,211 +80,211 @@ def expect_valid(valid, symbols = {}) end end - shared_examples "is valid" do - it "is valid" do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' - context "if the project is nil" do + context 'if the project is nil' do let(:version_project) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, project_id: %i(blank)) end end - context "if the name is nil" do + context 'if the name is nil' do let(:version_name) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, name: %i(blank)) end end - context "if the description is nil" do + context 'if the description is nil' do let(:version_description) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the start_date is nil" do + context 'if the start_date is nil' do let(:version_start_date) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the end_date is nil" do + context 'if the end_date is nil' do let(:version_due_date) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the status is nil" do + context 'if the status is nil' do let(:version_status) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, status: %i(inclusion)) end end - context "if the status is something other than the allowed values" do - let(:version_status) { "other_status" } + context 'if the status is something other than the allowed values' do + let(:version_status) { 'other_status' } - it "is invalid" do + it 'is invalid' do expect_valid(false, status: %i(inclusion)) end end - context "if sharing is nil" do + context 'if sharing is nil' do before do - version.sharing = "nil" + version.sharing = 'nil' end - it "is invalid" do + it 'is invalid' do expect_valid(false, sharing: %i(inclusion)) end end - context "if sharing is bogus" do + context 'if sharing is bogus' do before do - version.sharing = "bogus" + version.sharing = 'bogus' end - it "is invalid" do + it 'is invalid' do expect_valid(false, sharing: %i(inclusion)) end end - context "if sharing is system and the user an admin" do + context 'if sharing is system and the user an admin' do let(:current_user) { build_stubbed(:admin) } before do - version.sharing = "system" + version.sharing = 'system' end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if sharing is system and the user no admin" do + context 'if sharing is system and the user no admin' do before do - version.sharing = "system" + version.sharing = 'system' end - it "is invalid" do + it 'is invalid' do expect_valid(false, sharing: %i(inclusion)) end end - context "if sharing is descendants" do + context 'if sharing is descendants' do before do - version.sharing = "descendants" + version.sharing = 'descendants' end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if sharing is tree and the user has manage permission on the root project" do + context 'if sharing is tree and the user has manage permission on the root project' do before do - version.sharing = "tree" + version.sharing = 'tree' end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if sharing is tree and the user has no manage permission on the root project" do + context 'if sharing is tree and the user has no manage permission on the root project' do let(:root_permissions) { [] } before do - version.sharing = "tree" + version.sharing = 'tree' end - it "is invalid" do + it 'is invalid' do expect_valid(false, sharing: %i(inclusion)) end end - context "if sharing is hierarchy and the user has manage permission on the root project" do + context 'if sharing is hierarchy and the user has manage permission on the root project' do before do - version.sharing = "hierarchy" + version.sharing = 'hierarchy' end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if sharing is hierarchy and the user has no manage permission on the root project" do + context 'if sharing is hierarchy and the user has no manage permission on the root project' do let(:root_permissions) { [] } before do - version.sharing = "hierarchy" + version.sharing = 'hierarchy' end - it "is invalid" do + it 'is invalid' do expect_valid(false, sharing: %i(inclusion)) end end - context "if the user lacks the manage_versions permission" do + context 'if the user lacks the manage_versions permission' do let(:permissions) { [] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: %i(error_unauthorized)) end end - context "if the start date is after the effective date" do + context 'if the start date is after the effective date' do let(:version_start_date) { version_due_date + 1.day } - it "is invalid" do + it 'is invalid' do expect_valid(false, effective_date: %i(greater_than_start_date)) end end - context "if wiki_page_title is nil" do + context 'if wiki_page_title is nil' do let(:version_wiki_page_title) { nil } let(:find_page_result) do nil end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if wiki_page_title is blank" do - let(:version_wiki_page_title) { "" } + context 'if wiki_page_title is blank' do + let(:version_wiki_page_title) { '' } let(:find_page_result) do nil end - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if wiki_page_title contains a non existing page" do - let(:version_wiki_page_title) { "http://some/url/i/made/up" } + context 'if wiki_page_title contains a non existing page' do + let(:version_wiki_page_title) { 'http://some/url/i/made/up' } let(:find_page_result) do nil end - it "is invalid" do + it 'is invalid' do expect_valid(false, wiki_page_title: %i(inclusion)) end end end - describe "assignable values" do - describe "assignable_wiki_pages" do - context "with a wiki assigned" do - it "returns the pages of the project`s wiki" do + describe 'assignable values' do + describe 'assignable_wiki_pages' do + context 'with a wiki assigned' do + it 'returns the pages of the project`s wiki' do expect(contract.assignable_wiki_pages) .to match_array(wiki_pages) end end - context "without a wiki assigned" do + context 'without a wiki assigned' do let(:project_wiki) { nil } - it "is empty" do + it 'is empty' do expect(contract.assignable_wiki_pages) .to be_empty end diff --git a/spec/contracts/versions/update_contract_spec.rb b/spec/contracts/versions/update_contract_spec.rb index b4ae8b5f1797..a80ab2a32fea 100644 --- a/spec/contracts/versions/update_contract_spec.rb +++ b/spec/contracts/versions/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Versions::UpdateContract do - it_behaves_like "version contract" do + it_behaves_like 'version contract' do let(:version) do build_stubbed(:version, project: version_project, @@ -47,39 +47,39 @@ subject(:contract) { described_class.new(version, current_user) } - describe "assignable_values" do - context "for project" do - it "is empty" do + describe 'assignable_values' do + context 'for project' do + it 'is empty' do expect(subject.assignable_values(:project, current_user)) .to be_empty end end - context "for status" do - it "is a list of all available status" do + context 'for status' do + it 'is a list of all available status' do expect(subject.assignable_values(:status, current_user)) .to eql %w(open locked closed) end end - context "for sharing" do - it "is a list of values" do + context 'for sharing' do + it 'is a list of values' do expect(subject.assignable_values(:sharing, current_user)) .to match_array %w(none descendants hierarchy tree) end - context "if the user is admin" do + context 'if the user is admin' do let(:current_user) { build_stubbed(:admin) } - it "is a list of values" do + it 'is a list of values' do expect(subject.assignable_values(:sharing, current_user)) .to match_array %w(none descendants system hierarchy tree) end end end - context "for something else" do - it "is nil" do + context 'for something else' do + it 'is nil' do expect(subject.assignable_values(:start_date, current_user)) .to be_nil end diff --git a/spec/contracts/views/create_contract_work_packages_table_spec.rb b/spec/contracts/views/create_contract_work_packages_table_spec.rb index f3b749170c8c..05167c53fb17 100644 --- a/spec/contracts/views/create_contract_work_packages_table_spec.rb +++ b/spec/contracts/views/create_contract_work_packages_table_spec.rb @@ -26,48 +26,48 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Views::CreateContract do - it_behaves_like "view contract" do + it_behaves_like 'view contract' do let(:view) do View.new(query: view_query, type: view_type) end let(:view_type) do - "work_packages_table" + 'work_packages_table' end subject(:contract) do described_class.new(view, current_user) end - describe "validation" do - context "with the type being nil" do + describe 'validation' do + context 'with the type being nil' do let(:view_type) { nil } - it_behaves_like "contract is invalid", type: :inclusion + it_behaves_like 'contract is invalid', type: :inclusion end - context "with the type not being one of the configured" do - let(:view_type) { "blubs" } + context 'with the type not being one of the configured' do + let(:view_type) { 'blubs' } - it_behaves_like "contract is invalid", type: :inclusion + it_behaves_like 'contract is invalid', type: :inclusion end - context "with a work_packages_calendar view with the user having the permission to view_calendar" do + context 'with a work_packages_calendar view with the user having the permission to view_calendar' do let(:permissions) { %i[view_work_packages save_queries view_calendar] } - let(:view_type) { "work_packages_calendar" } + let(:view_type) { 'work_packages_calendar' } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end - context "with a work_packages_calendar view with the user not having the permission to view_calendar" do + context 'with a work_packages_calendar view with the user not having the permission to view_calendar' do let(:permissions) { %i[view_work_packages save_queries] } - let(:view_type) { "work_packages_calendar" } + let(:view_type) { 'work_packages_calendar' } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end end end diff --git a/spec/contracts/views/shared_contract_examples.rb b/spec/contracts/views/shared_contract_examples.rb index 9431d711f74b..90ebb53260e9 100644 --- a/spec/contracts/views/shared_contract_examples.rb +++ b/spec/contracts/views/shared_contract_examples.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "view contract" do |disabled_permission_checks| - include_context "ModelContract shared context" +RSpec.shared_examples_for 'view contract' do |disabled_permission_checks| + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user) } @@ -68,46 +68,46 @@ .and_return(query_visible) end - describe "validation" do - it_behaves_like "contract is valid" + describe 'validation' do + it_behaves_like 'contract is valid' - context "with the query being nil" do + context 'with the query being nil' do let(:view_query) { nil } - it_behaves_like "contract is invalid", query: :blank + it_behaves_like 'contract is invalid', query: :blank end - context "with the query being invisible to the user" do + context 'with the query being invisible to the user' do let(:query_visible) { false } - it_behaves_like "contract is invalid", query: :does_not_exist + it_behaves_like 'contract is invalid', query: :does_not_exist end - context "with the query being private, the user being the query user and having the :save_queries permission" do - it_behaves_like "contract is valid" + context 'with the query being private, the user being the query user and having the :save_queries permission' do + it_behaves_like 'contract is valid' end unless disabled_permission_checks - context "with the query being private, the user being the query user and not having the :save_queries permission" do + context 'with the query being private, the user being the query user and not having the :save_queries permission' do let(:permissions) { %i[view_work_packages] } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "with the query being public, the user being the query user but only having the :save_queries permission" do + context 'with the query being public, the user being the query user but only having the :save_queries permission' do let(:query_public) { true } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "with the query being public, the user not being the query user but having the :manage_public_queries permission" do + context 'with the query being public, the user not being the query user but having the :manage_public_queries permission' do let(:query_public) { true } let(:permissions) { %i[view_work_packages manage_public_queries] } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/views/update_contract_spec.rb b/spec/contracts/views/update_contract_spec.rb index c0ea4e071261..613203a5e233 100644 --- a/spec/contracts/views/update_contract_spec.rb +++ b/spec/contracts/views/update_contract_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe Views::UpdateContract do # TODO: this is just a stub to ensure that the type is not altered - it_behaves_like "view contract" do + it_behaves_like 'view contract' do let(:view) do build_stubbed(:view_work_packages_table).tap do |view| view.type = view_type if defined?(view_type) @@ -43,11 +43,11 @@ described_class.new(view, current_user) end - describe "validation" do - context "with the type being changed" do - let(:view_type) { "team_planner" } + describe 'validation' do + context 'with the type being changed' do + let(:view_type) { 'team_planner' } - it_behaves_like "contract is invalid", type: %i[error_readonly] + it_behaves_like 'contract is invalid', type: %i[error_readonly] end end end diff --git a/spec/contracts/wiki_pages/create_contract_spec.rb b/spec/contracts/wiki_pages/create_contract_spec.rb index fc8a18f47720..a24d078eae42 100644 --- a/spec/contracts/wiki_pages/create_contract_spec.rb +++ b/spec/contracts/wiki_pages/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe WikiPages::CreateContract do - it_behaves_like "wiki page contract" do + it_behaves_like 'wiki page contract' do subject(:contract) { described_class.new(page, current_user, options: {}) } let(:page) do @@ -58,19 +58,19 @@ end end - describe "#validation" do - context "if the author is different from the current user" do + describe '#validation' do + context 'if the author is different from the current user' do let(:page_author) { build_stubbed(:user) } - it "is invalid" do + it 'is invalid' do expect_valid(false, author: :not_current_user) end end - context "if the author was not set by system" do + context 'if the author was not set by system' do let(:changed_by_system) { {} } - it "is invalid" do + it 'is invalid' do expect_valid(false, author_id: %i(error_readonly)) end end diff --git a/spec/contracts/wiki_pages/shared_contract_examples.rb b/spec/contracts/wiki_pages/shared_contract_examples.rb index 83648b9fc651..3eb5bf8ee70d 100644 --- a/spec/contracts/wiki_pages/shared_contract_examples.rb +++ b/spec/contracts/wiki_pages/shared_contract_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "wiki page contract" do +RSpec.shared_examples_for 'wiki page contract' do let(:current_user) { build_stubbed(:user) } before do @@ -39,11 +39,11 @@ let(:page_wiki) { build_stubbed(:wiki) } let(:page_author) { current_user } - let(:page_title) { "Wiki title" } - let(:page_slug) { "wiki slug" } + let(:page_title) { 'Wiki title' } + let(:page_slug) { 'wiki slug' } let(:page_protected) { false } let(:page_parent) { nil } - let(:page_text) { "Wiki text" } + let(:page_text) { 'Wiki text' } let(:permissions) { %i[view_wiki_pages edit_wiki_pages] } def expect_valid(valid, symbols = {}) @@ -54,53 +54,53 @@ def expect_valid(valid, symbols = {}) end end - describe "validation" do - shared_examples "is valid" do - it "is valid" do + describe 'validation' do + shared_examples 'is valid' do + it 'is valid' do expect_valid(true) end end - it_behaves_like "is valid" + it_behaves_like 'is valid' - context "if the title is nil" do + context 'if the title is nil' do let(:page_title) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, title: :blank) end end - context "if the slug is nil" do + context 'if the slug is nil' do let(:page_slug) { nil } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the wiki is nil" do + context 'if the wiki is nil' do let(:page_wiki) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, wiki: :blank) end end - context "if the parent is in the same wiki" do + context 'if the parent is in the same wiki' do let(:page_parent) { build_stubbed(:wiki_page, wiki: page_wiki) } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the parent is in a different wiki" do + context 'if the parent is in a different wiki' do let(:page_parent) { build_stubbed(:wiki_page) } - it "is invalid" do + it 'is invalid' do expect_valid(false, parent_title: :not_same_project) end end - context "if the parent is a child of the page (circular dependency)" do - it "is invalid" do + context 'if the parent is a child of the page (circular dependency)' do + it 'is invalid' do page.parent = build_stubbed(:wiki_page, wiki: page_wiki).tap do |parent| # Using stubbing here to avoid infinite loops allow(parent) @@ -112,41 +112,41 @@ def expect_valid(valid, symbols = {}) end end - context "if the parent the page itself (circular dependency" do - it "is invalid" do + context 'if the parent the page itself (circular dependency' do + it 'is invalid' do page.parent = page expect_valid(false, parent_title: :circular_dependency) end end - context "if the author is nil" do + context 'if the author is nil' do let(:page_author) { nil } - it "is invalid" do + it 'is invalid' do expect_valid(false, author: %i[blank not_current_user]) end end - context "if the user lacks permission" do + context 'if the user lacks permission' do let(:permissions) { %i[view_wiki_pages] } - it "is invalid" do + it 'is invalid' do expect_valid(false, base: :error_unauthorized) end end - context "if the page is protected and the user has permission to protect pages" do + context 'if the page is protected and the user has permission to protect pages' do let(:permissions) { %i[view_wiki_pages edit_wiki_pages protect_wiki_pages] } let(:page_protected) { true } - it_behaves_like "is valid" + it_behaves_like 'is valid' end - context "if the page is protected and the user lacks permission to protect pages" do + context 'if the page is protected and the user lacks permission to protect pages' do let(:page_protected) { true } - it "is invalid" do + it 'is invalid' do expect_valid(false, protected: :error_unauthorized) end end diff --git a/spec/contracts/work_package_members/create_contract_spec.rb b/spec/contracts/work_package_members/create_contract_spec.rb index 291380cb657f..a48c3734ed00 100644 --- a/spec/contracts/work_package_members/create_contract_spec.rb +++ b/spec/contracts/work_package_members/create_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe WorkPackageMembers::CreateContract do - it_behaves_like "work package member contract" do + it_behaves_like 'work package member contract' do let(:member) do Member.new(roles: member_roles, principal: member_principal, @@ -46,52 +46,52 @@ let(:contract) { described_class.new(member, current_user) } - describe "validation" do - context "if the principal is nil" do + describe 'validation' do + context 'if the principal is nil' do let(:member_principal) { nil } - it_behaves_like "contract is invalid", principal: :blank + it_behaves_like 'contract is invalid', principal: :blank end - context "if the principal is a locked user" do + context 'if the principal is a locked user' do let(:member_principal) { build_stubbed(:locked_user) } - it_behaves_like "contract is invalid", principal: :unassignable + it_behaves_like 'contract is invalid', principal: :unassignable end - context "if the principal is a builtin user" do + context 'if the principal is a builtin user' do let(:member_principal) { build_stubbed(:anonymous) } - it_behaves_like "contract is invalid", principal: :unassignable + it_behaves_like 'contract is invalid', principal: :unassignable end - context "if the project is nil" do + context 'if the project is nil' do let(:member_project) { nil } - it_behaves_like "contract is invalid", project: :blank + it_behaves_like 'contract is invalid', project: :blank end - context "if the project is not set by the system" do + context 'if the project is not set by the system' do before do member.project = build_stubbed(:project) end - it_behaves_like "contract is invalid", project_id: :error_readonly + it_behaves_like 'contract is invalid', project_id: :error_readonly end - context "if the entity is nil" do + context 'if the entity is nil' do let(:member_entity) { nil } let(:member_project) { build_stubbed(:project) } - it_behaves_like "contract is invalid", entity: :blank + it_behaves_like 'contract is invalid', entity: :blank end - context "if the entity is something else" do + context 'if the entity is something else' do before do - member.entity_type = "Meeting" + member.entity_type = 'Meeting' end - it_behaves_like "contract is invalid", entity_type: :inclusion + it_behaves_like 'contract is invalid', entity_type: :inclusion end end end diff --git a/spec/contracts/work_package_members/shared_contract_examples.rb b/spec/contracts/work_package_members/shared_contract_examples.rb index fe14e69d2afe..ecf5a3f8e83b 100644 --- a/spec/contracts/work_package_members/shared_contract_examples.rb +++ b/spec/contracts/work_package_members/shared_contract_examples.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "contracts/shared/model_contract_shared_context" +require 'spec_helper' +require 'contracts/shared/model_contract_shared_context' -RSpec.shared_examples_for "work package member contract" do - include_context "ModelContract shared context" +RSpec.shared_examples_for 'work package member contract' do + include_context 'ModelContract shared context' let(:current_user) { build_stubbed(:user, admin: current_user_admin) } before do @@ -57,44 +57,44 @@ let(:permissions) { [:share_work_packages] } let(:current_user_admin) { false } - describe "validation" do - it_behaves_like "contract is valid" + describe 'validation' do + it_behaves_like 'contract is valid' - context "if the roles are nil" do + context 'if the roles are nil' do let(:member_roles) { [] } - it_behaves_like "contract is invalid", roles: :role_blank + it_behaves_like 'contract is invalid', roles: :role_blank end - context "if any role is not assignable (e.g. builtin)" do + context 'if any role is not assignable (e.g. builtin)' do let(:member_roles) do [build_stubbed(:project_role)] end - it_behaves_like "contract is invalid", roles: :ungrantable + it_behaves_like 'contract is invalid', roles: :ungrantable end - context "if the principal is the current user" do + context 'if the principal is the current user' do let(:member_principal) { current_user } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end - context "if more than one non-inherited role is assigned" do + context 'if more than one non-inherited role is assigned' do let(:member_roles) do [build_stubbed(:view_work_package_role), build_stubbed(:comment_work_package_role)] end - it_behaves_like "contract is invalid", roles: :more_than_one + it_behaves_like 'contract is invalid', roles: :more_than_one end - context "if the user lacks :share_work_packages permission in the project" do + context 'if the user lacks :share_work_packages permission in the project' do # This permission would work for a project member. let(:permissions) { [:manage_members] } - it_behaves_like "contract is invalid", base: :error_unauthorized + it_behaves_like 'contract is invalid', base: :error_unauthorized end end - include_examples "contract reuses the model errors" + include_examples 'contract reuses the model errors' end diff --git a/spec/contracts/work_package_members/update_contract_spec.rb b/spec/contracts/work_package_members/update_contract_spec.rb index 707e3b021b11..970970e2e509 100644 --- a/spec/contracts/work_package_members/update_contract_spec.rb +++ b/spec/contracts/work_package_members/update_contract_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require_relative "shared_contract_examples" +require 'spec_helper' +require_relative 'shared_contract_examples' RSpec.describe WorkPackageMembers::UpdateContract do - it_behaves_like "work package member contract" do + it_behaves_like 'work package member contract' do let(:member) do build_stubbed(:work_package_member, project: member_project, @@ -41,35 +41,35 @@ let(:contract) { described_class.new(member, current_user) } - describe "validation" do - context "if the principal is changed" do + describe 'validation' do + context 'if the principal is changed' do before do member.principal = build_stubbed(:user) end - it_behaves_like "contract is invalid", principal: :error_readonly + it_behaves_like 'contract is invalid', principal: :error_readonly end - context "if the project is changed" do + context 'if the project is changed' do before do member.project = build_stubbed(:project) end - it_behaves_like "contract is invalid", project_id: :error_readonly + it_behaves_like 'contract is invalid', project_id: :error_readonly end - context "if the entity is changed" do + context 'if the entity is changed' do before do member.entity = build_stubbed(:work_package) end - it_behaves_like "contract is invalid", entity_id: :error_readonly + it_behaves_like 'contract is invalid', entity_id: :error_readonly end - context "if the principal is a locked user" do + context 'if the principal is a locked user' do let(:member_principal) { build_stubbed(:locked_user) } - it_behaves_like "contract is valid" + it_behaves_like 'contract is valid' end end end diff --git a/spec/contracts/work_packages/create_contract_spec.rb b/spec/contracts/work_packages/create_contract_spec.rb index 810bca17a333..1c382797245a 100644 --- a/spec/contracts/work_packages/create_contract_spec.rb +++ b/spec/contracts/work_packages/create_contract_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "contracts/work_packages/shared_base_contract" +require 'spec_helper' +require 'contracts/work_packages/shared_base_contract' RSpec.describe WorkPackages::CreateContract do let(:work_package) do @@ -47,10 +47,10 @@ subject(:contract) { described_class.new(work_package, user) } - it_behaves_like "work package contract" + it_behaves_like 'work package contract' - describe "authorization" do - context "when user allowed in project and project specified" do + describe 'authorization' do + context 'when user allowed in project and project specified' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_packages, project: @@ -59,12 +59,12 @@ work_package.project = project end - it "has no authorization error" do + it 'has no authorization error' do expect(validated_contract.errors[:base]).to be_empty end end - context "when user not allowed in project and project specified" do + context 'when user not allowed in project and project specified' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_packages, project: other_project @@ -73,116 +73,96 @@ work_package.project = project end - it "is not authorized" do + it 'is not authorized' do expect(validated_contract.errors.symbols_for(:base)) .to contain_exactly(:error_unauthorized) end end - context "when user allowed in a project and no project specified" do + context 'when user allowed in a project and no project specified' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_packages, project: end end - it "has no authorization error" do + it 'has no authorization error' do expect(validated_contract.errors[:base]).to be_empty end end - context "when user not allowed in any projects and no project specified" do + context 'when user not allowed in any projects and no project specified' do before do mock_permissions_for(user, &:forbid_everything) end - it "is not authorized" do + it 'is not authorized' do expect(validated_contract.errors.symbols_for(:base)) .to contain_exactly(:error_unauthorized) end end - context "when user not allowed in any projects and project specified" do + context 'when user not allowed in any projects and project specified' do before do mock_permissions_for(user, &:forbid_everything) work_package.project = project end - it "is not authorized" do + it 'is not authorized' do expect(validated_contract.errors.symbols_for(:base)) .to contain_exactly(:error_unauthorized) end end end - describe "remaining hours" do + describe 'author_id' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_packages, project: end - work_package.project = project - end - - context "when not changed" do - it("is valid") { expect(validated_contract.errors[:remaining_hours]).to be_empty } end - context "when changed" do - before do - work_package.remaining_hours = 10 - end + context 'if the user is set by the system and the user is the user the contract is evaluated for' do + subject(:contract) { described_class.new(work_package, user) } - it("is valid") { expect(validated_contract.errors[:remaining_hours]).to be_empty } - end - end - - describe "writing read-only attributes" do - shared_examples "can write" do |attribute, value| - it "can write #{attribute}", :aggregate_failures do - expect(contract.writable_attributes).to include(attribute.to_s) + it 'is valid' do + work_package.change_by_system do + work_package.author = user + end - work_package.send(:"#{attribute}=", value) - expect(validated_contract.errors[attribute]).to be_empty + expect(validated_contract.errors[:author_id]).to be_empty end end - shared_examples "can not write" do |attribute, value| - it "can not write #{attribute}", :aggregate_failures do - expect(contract.writable_attributes).not_to include(attribute.to_s) + context 'if the user is different from the user the contract is evaluated for' do + it 'is invalid' do + work_package.author = build_stubbed(:user) - work_package.send(:"#{attribute}=", value) - expect(validated_contract).not_to be_valid - expect(validated_contract.errors[attribute]).to include "was attempted to be written but is not writable." + expect(validated_contract.errors.symbols_for(:author_id)) + .to match_array %i[invalid error_readonly] end end + end - context "when enabled for admin", with_settings: { apiv3_write_readonly_attributes: true } do - let(:user) { build_stubbed(:admin) } - - it_behaves_like "can write", :created_at, 1.day.ago - it_behaves_like "can write", :updated_at, 1.day.ago - it_behaves_like "can write", :author_id, 1234 + describe 'remaining hours' do + before do + mock_permissions_for(user) do |mock| + mock.allow_in_project :add_work_packages, project: + end + work_package.project = project end - context "when disabled for admin", with_settings: { apiv3_write_readonly_attributes: false } do - let(:user) { build_stubbed(:admin) } - - it_behaves_like "can not write", :created_at, 1.day.ago - it_behaves_like "can not write", :updated_at, 1.day.ago - it_behaves_like "can not write", :author_id, 1234 + context 'when not changed' do + it('is valid') { expect(validated_contract.errors[:remaining_hours]).to be_empty } end - context "when enabled for regular user", with_settings: { apiv3_write_readonly_attributes: true } do - it_behaves_like "can not write", :created_at, 1.day.ago - it_behaves_like "can not write", :updated_at, 1.day.ago - it_behaves_like "can not write", :author_id, 1234 - end + context 'when changed' do + before do + work_package.remaining_hours = 10 + end - context "when disabled for regular user", with_settings: { apiv3_write_readonly_attributes: false } do - it_behaves_like "can not write", :created_at, 1.day.ago - it_behaves_like "can not write", :updated_at, 1.day.ago - it_behaves_like "can not write", :author_id, 1234 + it('is valid') { expect(validated_contract.errors[:remaining_hours]).to be_empty } end end end diff --git a/spec/contracts/work_packages/create_note_contract_spec.rb b/spec/contracts/work_packages/create_note_contract_spec.rb index fc8c55797d2e..67270182fe88 100644 --- a/spec/contracts/work_packages/create_note_contract_spec.rb +++ b/spec/contracts/work_packages/create_note_contract_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::CreateNoteContract do let(:work_package) do @@ -39,55 +39,55 @@ wp end let(:user) { build_stubbed(:user) } - let(:policy_instance) { double("WorkPackagePolicyInstance") } + let(:policy_instance) { double('WorkPackagePolicyInstance') } subject(:contract) do contract = described_class.new(work_package, user) - contract.send(:"policy=", policy_instance) + contract.send(:'policy=', policy_instance) contract end - describe "note" do + describe 'note' do before do - work_package.journal_notes = "blubs" + work_package.journal_notes = 'blubs' end - context "if the user has the permissions" do + context 'if the user has the permissions' do before do allow(policy_instance).to receive(:allowed?).with(work_package, :comment).and_return true contract.validate end - it("is valid") { expect(contract.errors).to be_empty } + it('is valid') { expect(contract.errors).to be_empty } end - context "if the user lacks the permissions" do + context 'if the user lacks the permissions' do before do allow(policy_instance).to receive(:allowed?).with(work_package, :comment).and_return false contract.validate end - it "is invalid" do + it 'is invalid' do expect(contract.errors.symbols_for(:journal_notes)) .to contain_exactly(:error_unauthorized) end end end - describe "subject" do + describe 'subject' do before do - work_package.subject = "blubs" + work_package.subject = 'blubs' allow(policy_instance).to receive(:allowed?).and_return true contract.validate end - it "is invalid" do + it 'is invalid' do expect(contract.errors.symbols_for(:subject)) .to contain_exactly(:error_readonly) end diff --git a/spec/contracts/work_packages/shared_base_contract.rb b/spec/contracts/work_packages/shared_base_contract.rb index 163865dfc4c1..791531b2f87d 100644 --- a/spec/contracts/work_packages/shared_base_contract.rb +++ b/spec/contracts/work_packages/shared_base_contract.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "work package contract" do +RSpec.shared_examples_for 'work package contract' do let(:user) { build_stubbed(:user) } let(:other_user) { build_stubbed(:user) } let(:policy) { double(WorkPackagePolicy, allowed?: true) } @@ -47,7 +47,7 @@ let(:possible_assignees) { [] } let!(:assignable_assignees_scope) do - scope = double "assignable assignees scope" + scope = double 'assignable assignees scope' if work_package.persisted? allow(Principal) @@ -69,73 +69,73 @@ scope end - shared_examples_for "has no error on" do |property| + shared_examples_for 'has no error on' do |property| it property do expect(validated_contract.errors[property]).to be_empty end end - describe "assigned_to_id" do + describe 'assigned_to_id' do before do work_package.assigned_to_id = other_user.id end - context "if the assigned user is a possible assignee" do + context 'if the assigned user is a possible assignee' do let(:possible_assignees) { [other_user] } - it_behaves_like "has no error on", :assigned_to + it_behaves_like 'has no error on', :assigned_to end - context "if the assigned user is not a possible assignee" do - it "is not a valid assignee" do - error = I18n.t("api_v3.errors.validation.invalid_user_assigned_to_work_package", - property: I18n.t("attributes.assignee")) + context 'if the assigned user is not a possible assignee' do + it 'is not a valid assignee' do + error = I18n.t('api_v3.errors.validation.invalid_user_assigned_to_work_package', + property: I18n.t('attributes.assignee')) expect(validated_contract.errors[:assigned_to]).to contain_exactly(error) end end - context "if the project is not set" do + context 'if the project is not set' do let(:work_package_project) { nil } - it_behaves_like "has no error on", :assigned_to + it_behaves_like 'has no error on', :assigned_to end end - describe "responsible_id" do + describe 'responsible_id' do before do work_package.responsible_id = other_user.id end - context "if the responsible user is a possible responsible" do + context 'if the responsible user is a possible responsible' do let(:possible_assignees) { [other_user] } - it_behaves_like "has no error on", :responsible + it_behaves_like 'has no error on', :responsible end - context "if the assigned user is not a possible responsible" do - it "is not a valid responsible" do - error = I18n.t("api_v3.errors.validation.invalid_user_assigned_to_work_package", - property: I18n.t("attributes.responsible")) + context 'if the assigned user is not a possible responsible' do + it 'is not a valid responsible' do + error = I18n.t('api_v3.errors.validation.invalid_user_assigned_to_work_package', + property: I18n.t('attributes.responsible')) expect(validated_contract.errors[:responsible]).to contain_exactly(error) end end - context "if the project is not set" do + context 'if the project is not set' do let(:work_package_project) { nil } - it_behaves_like "has no error on", :responsible + it_behaves_like 'has no error on', :responsible end end - describe "#assignable_assignees" do - it "returns the Principal`s possible_assignee scope" do + describe '#assignable_assignees' do + it 'returns the Principal`s possible_assignee scope' do expect(subject.assignable_assignees) .to eql assignable_assignees_scope end end - describe "#assignable_responsibles" do - it "returns the Principal`s possible_assignee scope" do + describe '#assignable_responsibles' do + it 'returns the Principal`s possible_assignee scope' do expect(subject.assignable_responsibles) .to eql assignable_assignees_scope end diff --git a/spec/contracts/work_packages/update_contract_spec.rb b/spec/contracts/work_packages/update_contract_spec.rb index 888bca9959e9..d98772abd06c 100644 --- a/spec/contracts/work_packages/update_contract_spec.rb +++ b/spec/contracts/work_packages/update_contract_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "contracts/work_packages/shared_base_contract" +require 'spec_helper' +require 'contracts/work_packages/shared_base_contract' RSpec.describe WorkPackages::UpdateContract do shared_let(:persistent_project) { create(:project, public: false) } @@ -37,7 +37,7 @@ project: work_package_project, type:, status:) do |wp| - wp_scope = double("wp scope") + wp_scope = double('wp scope') allow(WorkPackage) .to receive(:visible) @@ -62,15 +62,15 @@ subject(:contract) { described_class.new(work_package, user) } - it_behaves_like "work package contract" do + it_behaves_like 'work package contract' do let(:work_package) do build_stubbed(:work_package, project: work_package_project) end end - describe "lock_version" do - context "no lock_version present" do + describe 'lock_version' do + context 'no lock_version present' do before do work_package.lock_version = nil contract.validate @@ -79,7 +79,7 @@ it { expect(contract.errors.symbols_for(:base)).to include(:error_conflict) } end - context "lock_version changed" do + context 'lock_version changed' do before do work_package.lock_version += 1 contract.validate @@ -88,7 +88,7 @@ it { expect(contract.errors.symbols_for(:base)).to include(:error_conflict) } end - context "lock_version present and unchanged" do + context 'lock_version present and unchanged' do before do contract.validate end @@ -97,7 +97,7 @@ end end - describe "authorization" do + describe 'authorization' do let(:attributes) { {} } before do @@ -105,54 +105,54 @@ contract.validate end - context "full access" do - it "is valid" do + context 'full access' do + it 'is valid' do expect(contract.errors).to be_empty end end - context "no read access" do + context 'no read access' do let(:permissions) { [:edit_work_packages] } it { expect(contract.errors.symbols_for(:base)).to include(:error_not_found) } end - context "no write access" do + context 'no write access' do let(:permissions) { [:view_work_packages] } it { expect(contract.errors.symbols_for(:base)).to include(:error_unauthorized) } end - context "only comment permission" do + context 'only comment permission' do let(:permissions) { %i[view_work_packages add_work_package_notes] } - context "when only adding a journal" do - let(:attributes) { { journal_notes: "some notes" } } + context 'when only adding a journal' do + let(:attributes) { { journal_notes: 'some notes' } } - it "is valid" do + it 'is valid' do expect(contract.errors).to be_empty end end - context "when changing more than a journal" do - let(:attributes) { { journal_notes: "some notes", subject: "blubs" } } + context 'when changing more than a journal' do + let(:attributes) { { journal_notes: 'some notes', subject: 'blubs' } } - it "is invalid" do + it 'is invalid' do expect(contract.errors.symbols_for(:base)).to include(:error_unauthorized) end end end - context "only assign_versions permission" do + context 'only assign_versions permission' do let(:permissions) { %i[view_work_packages assign_versions] } - it "is valid" do + it 'is valid' do expect(contract.errors).to be_empty end end end - describe "project_id" do + describe 'project_id' do let(:target_project) { create(:project, types: [type]) } let(:target_permissions) { [:move_work_packages] } @@ -175,20 +175,20 @@ contract.validate end - context "if the user has the permissions" do - it("is valid") { expect(contract.errors).to be_empty } + context 'if the user has the permissions' do + it('is valid') { expect(contract.errors).to be_empty } end - context "if the user lacks the permissions" do + context 'if the user lacks the permissions' do let(:target_permissions) { [] } - it "is invalid" do + it 'is invalid' do expect(contract.errors.symbols_for(:project_id)).to contain_exactly(:error_readonly) end end end - describe "version" do + describe 'version' do let(:version) { build_stubbed(:version) } before do @@ -201,32 +201,32 @@ contract.validate end - context "having full access" do - context "with an assignable_version" do + context 'having full access' do + context 'with an assignable_version' do let(:attributes) { { version_id: version.id } } - it "is valid" do + it 'is valid' do expect(contract.errors).to be_empty end end - context "with an unassignable_version" do + context 'with an unassignable_version' do let(:attributes) { { version_id: version.id + 1 } } - it "adds an error" do + it 'adds an error' do expect(contract.errors.symbols_for(:version_id)) .to include(:inclusion) end end end - context "write access" do + context 'write access' do let(:permissions) { %i[view_work_packages edit_work_packages] } - context "if assigning a version" do + context 'if assigning a version' do let(:attributes) { { version_id: version.id } } - it "adds an error" do + it 'adds an error' do expect(contract.errors.symbols_for(:version_id)) .to include(:error_readonly) end @@ -234,8 +234,8 @@ end end - describe "ignore_non_working_days" do - context "when having children and not being scheduled manually" do + describe 'ignore_non_working_days' do + context 'when having children and not being scheduled manually' do before do allow(work_package) .to receive(:leaf?) @@ -247,13 +247,13 @@ contract.validate end - it "is invalid" do + it 'is invalid' do expect(contract.errors.symbols_for(:ignore_non_working_days)) .to contain_exactly(:error_readonly) end end - context "when having children and being scheduled manually" do + context 'when having children and being scheduled manually' do before do allow(work_package) .to receive(:leaf?) @@ -265,14 +265,14 @@ contract.validate end - it "is valid" do + it 'is valid' do expect(contract.errors).to be_empty end end end - describe "with children" do - context "changing to milestone" do + describe 'with children' do + context 'changing to milestone' do let(:milestone) { build_stubbed(:type, is_milestone: true) } let(:children) { [build_stubbed(:work_package)] } @@ -282,13 +282,13 @@ contract.validate end - it "adds an error because cannot change to milestone with children" do + it 'adds an error because cannot change to milestone with children' do expect(contract.errors.symbols_for(:type)).to include(:cannot_be_milestone_due_to_children) end end end - describe "parent_id" do + describe 'parent_id' do shared_let(:parent) { create(:work_package) } let(:parent_visible) { true } @@ -299,18 +299,18 @@ contract.validate end - context "if the user has only edit permissions" do + context 'if the user has only edit permissions' do it { expect(contract.errors.symbols_for(:parent_id)).to include(:error_readonly) } end - context "if the user has edit and subtasks permissions" do + context 'if the user has edit and subtasks permissions' do let(:permissions) { %i[edit_work_packages view_work_packages manage_subtasks] } - it("is valid") do + it('is valid') do expect(contract.errors).to be_empty end - describe "invalid lock version" do + describe 'invalid lock version' do before do work_package.lock_version = 9999 contract.validate @@ -320,22 +320,22 @@ end end - context "no write access" do + context 'no write access' do let(:permissions) { [:view_work_packages] } it { expect(contract.errors.symbols_for(:parent_id)).to include(:error_readonly) } end - context "with manage_subtasks permission" do + context 'with manage_subtasks permission' do let(:permissions) { %i[view_work_packages manage_subtasks] } - it("is valid") do + it('is valid') do expect(contract.errors).to be_empty end - describe "changing more than the parent_id" do + describe 'changing more than the parent_id' do before do - work_package.subject = "Foobar!" + work_package.subject = 'Foobar!' contract.validate end @@ -343,46 +343,46 @@ end end - context "when the user does not have access to the parent" do + context 'when the user does not have access to the parent' do let(:parent_visible) { false } it { expect(contract.errors.symbols_for(:parent_id)).to include(:error_unauthorized) } end end - describe "#writable_attributes" do + describe '#writable_attributes' do subject { contract.writable_attributes } - context "for a user having only the edit_work_packages permission" do + context 'for a user having only the edit_work_packages permission' do let(:permissions) { %i[edit_work_packages] } - it "includes all attributes except version_id" do + it 'includes all attributes except version_id' do expect(subject) - .to include("subject", "start_date", "description") + .to include('subject', 'start_date', 'description') expect(subject) - .not_to include("version_id", "version") + .not_to include('version_id', 'version') end end - context "for a user having only the assign_versions permission" do + context 'for a user having only the assign_versions permission' do let(:permissions) { %i[assign_versions] } - it "includes all attributes except version_id" do + it 'includes all attributes except version_id' do expect(subject) - .to include("version_id", "version") + .to include('version_id', 'version') expect(subject) - .not_to include("subject", "start_date", "description") + .not_to include('subject', 'start_date', 'description') end end end - describe "readonly status" do - context "with the status being readonly", with_ee: %i[readonly_work_packages] do + describe 'readonly status' do + context 'with the status being readonly', with_ee: %i[readonly_work_packages] do let(:status) { build_stubbed(:status, is_readonly: true) } - describe "updating the priority" do + describe 'updating the priority' do let(:new_priority) { build_stubbed(:priority) } before do @@ -391,79 +391,79 @@ contract.validate end - it "is invalid" do + it 'is invalid' do expect(contract) .not_to be_valid end - it "adds an error to the written to attribute" do + it 'adds an error to the written to attribute' do expect(contract.errors.symbols_for(:priority_id)) .to include(:error_readonly) end - it "adds an error to base to better explain" do + it 'adds an error to base to better explain' do expect(contract.errors.symbols_for(:base)) .to include(:readonly_status) end end - describe "updating the custom field values" do + describe 'updating the custom field values' do let(:cf1) { create(:string_wp_custom_field) } before do work_package_project.work_package_custom_fields << cf1 type.custom_fields << cf1 - work_package.custom_field_values = { cf1.id => "test" } + work_package.custom_field_values = { cf1.id => 'test' } contract.validate end - shared_examples_for "custom_field readonly errors" do - it "adds an error to the written custom field attribute" do + shared_examples_for 'custom_field readonly errors' do + it 'adds an error to the written custom field attribute' do expect(contract.errors.symbols_for(cf1.attribute_name.to_sym)) .to include(:error_readonly) end - it "adds an error to base to better explain" do + it 'adds an error to base to better explain' do expect(contract.errors.symbols_for(:base)) .to include(:readonly_status) end end - context "when the subject does not extends OpenProject::ChangedBySystem" do - include_examples "custom_field readonly errors" + context 'when the subject does not extends OpenProject::ChangedBySystem' do + include_examples 'custom_field readonly errors' end - context "when the subject extends OpenProject::ChangedBySystem" do + context 'when the subject extends OpenProject::ChangedBySystem' do before do work_package.extend(OpenProject::ChangedBySystem) end - include_examples "custom_field readonly errors" + include_examples 'custom_field readonly errors' end end end end - describe "remaining hours" do - context "when is not a parent" do + describe 'remaining hours' do + context 'when is not a parent' do before do contract.validate end - context "when has not changed" do - it("is valid") { expect(contract.errors.empty?).to be true } + context 'when has not changed' do + it('is valid') { expect(contract.errors.empty?).to be true } end - context "when has changed" do + context 'when has changed' do before do work_package.remaining_hours = 10 end - it("is valid") { expect(contract.errors.empty?).to be true } + it('is valid') { expect(contract.errors.empty?).to be true } end end - context "when is a parent" do + context 'when is a parent' do let(:work_package) do build_stubbed(:work_package, project: work_package_project, @@ -488,16 +488,16 @@ contract.validate end - context "when has not changed" do - it("is valid") { expect(contract.errors.empty?).to be true } + context 'when has not changed' do + it('is valid') { expect(contract.errors.empty?).to be true } end - context "when has changed" do + context 'when has changed' do before do work_package.remaining_hours = 10 end - it("is valid") { expect(contract.errors.empty?).to be true } + it('is valid') { expect(contract.errors.empty?).to be true } end end end diff --git a/spec/controllers/account_controller_spec.rb b/spec/controllers/account_controller_spec.rb index 00f6d528e6bf..0b106959222b 100644 --- a/spec/controllers/account_controller_spec.rb +++ b/spec/controllers/account_controller_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AccountController, :skip_2fa_stage do let(:user_hook_class) do @@ -57,69 +57,69 @@ def reset! hook.reset! end - describe "GET #login" do + describe 'GET #login' do let(:params) { {} } - context "when the user is not already logged in" do + context 'when the user is not already logged in' do before do get :login, params: end - it "renders the view" do - expect(response).to render_template "login" + it 'renders the view' do + expect(response).to render_template 'login' expect(response).to be_successful end end - context "when the user is already logged in" do + context 'when the user is already logged in' do before do login_as user get :login, params: end - it "redirects to home" do + it 'redirects to home' do expect(response) .to redirect_to my_page_path end - context "and a valid back url is present" do + context 'and a valid back url is present' do let(:params) { { back_url: "/projects" } } - it "redirects to back_url value" do + it 'redirects to back_url value' do expect(response) .to redirect_to projects_path end end - context "and an invalid back url present" do - let(:params) { { back_url: "http://test.foo/work_packages/show/1" } } + context 'and an invalid back url present' do + let(:params) { { back_url: 'http://test.foo/work_packages/show/1' } } - it "redirects to home" do + it 'redirects to home' do expect(response).to redirect_to my_page_path end end end end - describe "GET #internal_login" do + describe 'GET #internal_login' do shared_let(:admin) { create(:admin) } - context "when direct login enabled", with_config: { omniauth_direct_login_provider: "some_provider" } do - it "allows to login internally using a special route" do + context 'when direct login enabled', with_config: { omniauth_direct_login_provider: 'some_provider' } do + it 'allows to login internally using a special route' do get :internal_login - expect(response).to render_template "account/login" + expect(response).to render_template 'account/login' end - it "allows to post to login" do - post :login, params: { username: admin.login, password: "adminADMIN!" } - expect(response).to redirect_to "/my/page" + it 'allows to post to login' do + post :login, params: { username: admin.login, password: 'adminADMIN!' } + expect(response).to redirect_to '/my/page' end end - context "when direct login disabled" do - it "the internal login route is inactive" do + context 'when direct login disabled' do + it 'the internal login route is inactive' do get :internal_login expect(response).to have_http_status(:not_found) @@ -128,171 +128,171 @@ def reset! end end - describe "POST #login" do + describe 'POST #login' do shared_let(:admin) { create(:admin) } - describe "wrong password" do - it "redirects back to login" do - post :login, params: { username: "admin", password: "bad" } + describe 'wrong password' do + it 'redirects back to login' do + post :login, params: { username: 'admin', password: 'bad' } expect(response).to be_successful - expect(response).to render_template "login" - expect(flash[:error]).to include "Invalid user or password" + expect(response).to render_template 'login' + expect(flash[:error]).to include 'Invalid user or password' end end - context "with first login" do + context 'with first login' do before do admin.update first_login: true - post :login, params: { username: admin.login, password: "adminADMIN!" } + post :login, params: { username: admin.login, password: 'adminADMIN!' } end - it "redirect to default path with ?first_time_user=true" do + it 'redirect to default path with ?first_time_user=true' do expect(response).to redirect_to "/?first_time_user=true" end - it "calls the user_first_login hook" do + it 'calls the user_first_login hook' do expect(hook.first_login_user).to eq admin end end - context "without first login" do + context 'without first login' do before do - post :login, params: { username: admin.login, password: "adminADMIN!" } + post :login, params: { username: admin.login, password: 'adminADMIN!' } end - it "redirect to the my page" do + it 'redirect to the my page' do expect(response).to redirect_to "/my/page" end - it "does not call the user_first_login hook" do + it 'does not call the user_first_login hook' do expect(hook.first_login_user).to be_nil end end - describe "User logging in with back_url" do - it "redirects to a relative path" do + describe 'User logging in with back_url' do + it 'redirects to a relative path' do post :login, - params: { username: admin.login, password: "adminADMIN!", back_url: "/" } + params: { username: admin.login, password: 'adminADMIN!', back_url: '/' } expect(response).to redirect_to root_path end - it "redirects to an absolute path given the same host" do + it 'redirects to an absolute path given the same host' do # note: test.host is the hostname during tests post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "http://test.host/work_packages/show/1" + password: 'adminADMIN!', + back_url: 'http://test.host/work_packages/show/1' } - expect(response).to redirect_to "/work_packages/show/1" + expect(response).to redirect_to '/work_packages/show/1' end - it "does not redirect to another host" do + it 'does not redirect to another host' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "http://test.foo/work_packages/show/1" + password: 'adminADMIN!', + back_url: 'http://test.foo/work_packages/show/1' } expect(response).to redirect_to my_page_path end - it "does not redirect to another host with a protocol relative url" do + it 'does not redirect to another host with a protocol relative url' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "//test.foo/fake" + password: 'adminADMIN!', + back_url: '//test.foo/fake' } expect(response).to redirect_to my_page_path end - it "does not redirect to logout" do + it 'does not redirect to logout' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "/logout" + password: 'adminADMIN!', + back_url: '/logout' } expect(response).to redirect_to my_page_path end - context "with a relative url root" do + context 'with a relative url root' do around do |example| - old_relative_url_root = OpenProject::Configuration["rails_relative_url_root"] - OpenProject::Configuration["rails_relative_url_root"] = "/openproject" + old_relative_url_root = OpenProject::Configuration['rails_relative_url_root'] + OpenProject::Configuration['rails_relative_url_root'] = '/openproject' example.run ensure - OpenProject::Configuration["rails_relative_url_root"] = old_relative_url_root + OpenProject::Configuration['rails_relative_url_root'] = old_relative_url_root end - it "redirects to the same subdirectory with an absolute path" do + it 'redirects to the same subdirectory with an absolute path' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "http://test.host/openproject/work_packages/show/1" + password: 'adminADMIN!', + back_url: 'http://test.host/openproject/work_packages/show/1' } - expect(response).to redirect_to "/openproject/work_packages/show/1" + expect(response).to redirect_to '/openproject/work_packages/show/1' end - it "redirects to the same subdirectory with a relative path" do + it 'redirects to the same subdirectory with a relative path' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "/openproject/work_packages/show/1" + password: 'adminADMIN!', + back_url: '/openproject/work_packages/show/1' } - expect(response).to redirect_to "/openproject/work_packages/show/1" + expect(response).to redirect_to '/openproject/work_packages/show/1' end - it "does not redirect to another subdirectory with an absolute path" do + it 'does not redirect to another subdirectory with an absolute path' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "http://test.host/foo/work_packages/show/1" + password: 'adminADMIN!', + back_url: 'http://test.host/foo/work_packages/show/1' } expect(response).to redirect_to my_page_path end - it "does not redirect to another subdirectory with a relative path" do + it 'does not redirect to another subdirectory with a relative path' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "/foo/work_packages/show/1" + password: 'adminADMIN!', + back_url: '/foo/work_packages/show/1' } expect(response).to redirect_to my_page_path end - it "does not redirect to another subdirectory by going up the path hierarchy" do + it 'does not redirect to another subdirectory by going up the path hierarchy' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "http://test.host/openproject/../foo/work_packages/show/1" + password: 'adminADMIN!', + back_url: 'http://test.host/openproject/../foo/work_packages/show/1' } expect(response).to redirect_to my_page_path end - it "does not redirect to another subdirectory with a protocol relative path" do + it 'does not redirect to another subdirectory with a protocol relative path' do post :login, params: { username: admin.login, - password: "adminADMIN!", - back_url: "//test.host/foo/work_packages/show/1" + password: 'adminADMIN!', + back_url: '//test.host/foo/work_packages/show/1' } expect(response).to redirect_to my_page_path end end end - describe "GET #logout" do + describe 'GET #logout' do shared_let(:admin) { create(:admin) } - it "calls reset_session" do + it 'calls reset_session' do allow(controller).to receive(:reset_session) login_as admin @@ -302,11 +302,11 @@ def reset! expect(response).to be_redirect end - context "with a user with an SSO provider attached" do - let(:user) { build_stubbed(:user, login: "bob", identity_url: "saml:foo") } + context 'with a user with an SSO provider attached' do + let(:user) { build_stubbed(:user, login: 'bob', identity_url: 'saml:foo') } let(:slo_callback) { nil } let(:sso_provider) do - { name: "saml", single_sign_out_callback: slo_callback } + { name: 'saml', single_sign_out_callback: slo_callback } end before do @@ -316,50 +316,50 @@ def reset! login_as user end - context "with no provider" do - it "redirects to default" do + context 'with no provider' do + it 'redirects to default' do get :logout expect(response).to redirect_to home_path end end - context "with a redirecting callback" do + context 'with a redirecting callback' do let(:slo_callback) do Proc.new do |prev_session, prev_user| - if prev_session[:foo] && prev_user[:login] = "bob" - redirect_to "/login" + if prev_session[:foo] && prev_user[:login] = 'bob' + redirect_to '/login' end end end - context "with direct login and redirecting callback", - with_config: { omniauth_direct_login_provider: "foo" }, with_settings: { login_required?: true } do - it "stills call the callback" do + context 'with direct login and redirecting callback', + with_config: { omniauth_direct_login_provider: 'foo' }, with_settings: { login_required?: true } do + it 'stills call the callback' do # Set the previous session - session[:foo] = "bar" + session[:foo] = 'bar' get :logout - expect(response).to redirect_to "/login" + expect(response).to redirect_to '/login' # Expect session to be cleared expect(session[:foo]).to be_nil end end - it "calls the callback" do + it 'calls the callback' do # Set the previous session - session[:foo] = "bar" + session[:foo] = 'bar' get :logout - expect(response).to redirect_to "/login" + expect(response).to redirect_to '/login' # Expect session to be cleared expect(session[:foo]).to be_nil end end - context "with a no-op callback" do - it "redirects to default if the callback does nothing" do + context 'with a no-op callback' do + it 'redirects to default if the callback does nothing' do was_called = false sso_provider[:single_sign_out_callback] = Proc.new do was_called = true @@ -371,10 +371,10 @@ def reset! end end - context "with a provider that does not have slo_callback" do + context 'with a provider that does not have slo_callback' do let(:slo_callback) { nil } - it "redirects to default if the callback does nothing" do + it 'redirects to default if the callback does nothing' do get :logout expect(response).to redirect_to home_path end @@ -382,59 +382,59 @@ def reset! end end - describe "for a user trying to log in via an API request" do + describe 'for a user trying to log in via an API request' do before do post :login, params: { username: admin.login, - password: "adminADMIN!" + password: 'adminADMIN!' }, format: :json end - it "returns a 410" do - expect(response.code.to_s).to eql("410") + it 'returns a 410' do + expect(response.code.to_s).to eql('410') end - it "does not login the user" do + it 'does not login the user' do expect(controller.send(:current_user)).to be_anonymous end end - context "with disabled password login" do + context 'with disabled password login' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) post :login end - it "is not found" do + it 'is not found' do expect(response).to have_http_status :not_found end end end - describe "#login with omniauth_direct_login enabled", - with_config: { omniauth_direct_login_provider: "some_provider" } do - describe "GET" do - it "redirects to some_provider" do + describe '#login with omniauth_direct_login enabled', + with_config: { omniauth_direct_login_provider: 'some_provider' } do + describe 'GET' do + it 'redirects to some_provider' do get :login - expect(response).to redirect_to "/auth/some_provider" + expect(response).to redirect_to '/auth/some_provider' end end - describe "POST" do + describe 'POST' do shared_let(:admin) { create(:admin) } - it "allows to login internally still" do - post :login, params: { username: admin.login, password: "adminADMIN!" } + it 'allows to login internally still' do + post :login, params: { username: admin.login, password: 'adminADMIN!' } expect(response).to redirect_to "/my/page" end end end - describe "Login for user with forced password change" do + describe 'Login for user with forced password change' do let(:admin) { create(:admin, force_password_change: true) } before do @@ -443,106 +443,106 @@ def reset! describe "Missing flash data for user initiated password change" do before do - post "change_password", + post 'change_password', flash: { _password_change_user_id: nil }, params: { username: admin.login, - password: "whatever", - new_password: "whatever", - new_password_confirmation: "whatever2" + password: 'whatever', + new_password: 'whatever', + new_password_confirmation: 'whatever2' } end - it "renders 404" do + it 'renders 404' do expect(response).to have_http_status :not_found end end describe "User who is not allowed to change password can't login" do before do - post "change_password", + post 'change_password', params: { password_change_user_id: admin.id, username: admin.login, - password: "adminADMIN!", - new_password: "adminADMIN!New", - new_password_confirmation: "adminADMIN!New" + password: 'adminADMIN!', + new_password: 'adminADMIN!New', + new_password_confirmation: 'adminADMIN!New' } end - it "redirects to the login page" do - expect(response).to redirect_to "/login" + it 'redirects to the login page' do + expect(response).to redirect_to '/login' end end - describe "User who is not allowed to change password, is not redirected to the login page" do + describe 'User who is not allowed to change password, is not redirected to the login page' do before do - post "login", params: { username: admin.login, password: "adminADMIN!" } + post 'login', params: { username: admin.login, password: 'adminADMIN!' } end - it "redirects to the login page" do - expect(response).to redirect_to "/login" + it 'redirects to the login page' do + expect(response).to redirect_to '/login' end end end - describe "POST #change_password" do - context "with disabled password login" do + describe 'POST #change_password' do + context 'with disabled password login' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) post :change_password end - it "is not found" do + it 'is not found' do expect(response).to have_http_status :not_found end end end - describe "POST #lost_password" do - context "when the user has been invited but not yet activated" do + describe 'POST #lost_password' do + context 'when the user has been invited but not yet activated' do shared_let(:admin) { create(:admin, status: :invited) } shared_let(:token) { create(:recovery_token, user: admin) } - context "with a valid token" do + context 'with a valid token' do before do allow(controller).to receive(:allow_lost_password_recovery).and_return(true) post :lost_password, params: { token: token.value } end - it "redirects to the login page" do - expect(response).to redirect_to "/login" + it 'redirects to the login page' do + expect(response).to redirect_to '/login' end end end end - shared_examples "registration disabled" do - it "redirects to back the login page" do + shared_examples 'registration disabled' do + it 'redirects to back the login page' do expect(response).to redirect_to signin_path end - it "informs the user that registration is disabled" do - expect(flash[:error]).to eq(I18n.t("account.error_self_registration_disabled")) + it 'informs the user that registration is disabled' do + expect(flash[:error]).to eq(I18n.t('account.error_self_registration_disabled')) end - it "does not call the user_registered callback" do + it 'does not call the user_registered callback' do expect(hook.registered_user).to be_nil end end - describe "GET #register" do - context "with self registration on", + describe 'GET #register' do + context 'with self registration on', with_settings: { self_registration: Setting::SelfRegistration.automatic } do - context "and password login enabled" do + context 'and password login enabled' do before do get :register end - it "is successful" do + it 'is successful' do expect(subject).to respond_with :success expect(response).to render_template :register expect(assigns[:user]).not_to be_nil @@ -550,27 +550,27 @@ def reset! end end - context "and password login disabled" do + context 'and password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) get :register end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end end - context "with self registration off", + context 'with self registration off', with_settings: { self_registration: Setting::SelfRegistration.disabled } do before do get :register end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end - context "with self registration off but an ongoing invitation activation", + context 'with self registration off but an ongoing invitation activation', with_settings: { self_registration: Setting::SelfRegistration.disabled } do let(:token) { create(:invitation_token) } @@ -580,7 +580,7 @@ def reset! get :register end - it "is successful" do + it 'is successful' do expect(subject).to respond_with :success expect(response).to render_template :register expect(assigns[:user]).not_to be_nil @@ -589,44 +589,44 @@ def reset! end # See integration/account_test.rb for the full test - describe "POST #register" do - context "with self registration on automatic", + describe 'POST #register' do + context 'with self registration on automatic', with_settings: { self_registration: Setting::SelfRegistration.automatic } do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(false) end - context "with password login enabled" do + context 'with password login enabled' do # expects `redirect_to_path` - shared_examples "automatic self registration succeeds" do + shared_examples 'automatic self registration succeeds' do before do post :register, params: { user: { - login: "register", - password: "adminADMIN!", - password_confirmation: "adminADMIN!", - firstname: "John", - lastname: "Doe", - mail: "register@example.com" + login: 'register', + password: 'adminADMIN!', + password_confirmation: 'adminADMIN!', + firstname: 'John', + lastname: 'Doe', + mail: 'register@example.com' } } end - it "redirects to the expected path" do + it 'redirects to the expected path' do expect(subject).to respond_with :redirect expect(assigns[:user]).not_to be_nil expect(subject).to redirect_to(redirect_to_path) - expect(User.where(login: "register").last).not_to be_nil + expect(User.where(login: 'register').last).not_to be_nil end - it "set the user status to active" do - user = User.where(login: "register").last + it 'set the user status to active' do + user = User.where(login: 'register').last expect(user).not_to be_nil expect(user).to be_active end - it "calls the user_registered callback" do + it 'calls the user_registered callback' do user = hook.registered_user expect(user.mail).to eq "register@example.com" @@ -634,7 +634,7 @@ def reset! end end - it_behaves_like "automatic self registration succeeds" do + it_behaves_like 'automatic self registration succeeds' do let(:redirect_to_path) { "/?first_time_user=true" } it "calls the user_first_login callback" do @@ -650,12 +650,12 @@ def reset! let(:params) do { user: { - login: "register", - password: "adminADMIN!", - password_confirmation: "adminADMIN!", - firstname: "John", - lastname: "Doe", - mail: "register@example.com" + login: 'register', + password: 'adminADMIN!', + password_confirmation: 'adminADMIN!', + firstname: 'John', + lastname: 'Doe', + mail: 'register@example.com' } } end @@ -681,53 +681,53 @@ def reset! expect(mail.body.parts.first.to_s).to match /new user \(#{params[:user][:mail]}\)/ end - it "does not call the user_registered callback" do + it 'does not call the user_registered callback' do expect(hook.registered_user).to be_nil end end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) post :register end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end end - context "with self registration by email", + context 'with self registration by email', with_settings: { self_registration: Setting::SelfRegistration.by_email } do - context "with password login enabled" do + context 'with password login enabled' do before do Token::Invitation.delete_all post :register, params: { user: { - login: "register", - password: "adminADMIN!", - password_confirmation: "adminADMIN!", - firstname: "John", - lastname: "Doe", - mail: "register@example.com" + login: 'register', + password: 'adminADMIN!', + password_confirmation: 'adminADMIN!', + firstname: 'John', + lastname: 'Doe', + mail: 'register@example.com' } } end - it "redirects to the login page" do - expect(subject).to redirect_to "/login" + it 'redirects to the login page' do + expect(subject).to redirect_to '/login' end it "doesn't activate the user but sends out a token instead" do - expect(User.find_by_login("register")).not_to be_active # rubocop:disable Rails/DynamicFindBy + expect(User.find_by_login('register')).not_to be_active # rubocop:disable Rails/DynamicFindBy token = Token::Invitation.last - expect(token.user.mail).to eq("register@example.com") + expect(token.user.mail).to eq('register@example.com') expect(token).not_to be_expired end - it "calls the user_registered callback" do + it 'calls the user_registered callback' do user = hook.registered_user expect(user.mail).to eq "register@example.com" @@ -735,42 +735,42 @@ def reset! end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) post :register end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end end - context "with manual activation", + context 'with manual activation', with_settings: { self_registration: Setting::SelfRegistration.manual } do let(:user_hash) do - { login: "register", - password: "adminADMIN!", - password_confirmation: "adminADMIN!", - firstname: "John", - lastname: "Doe", - mail: "register@example.com" } + { login: 'register', + password: 'adminADMIN!', + password_confirmation: 'adminADMIN!', + firstname: 'John', + lastname: 'Doe', + mail: 'register@example.com' } end - context "without back_url" do + context 'without back_url' do before do post :register, params: { user: user_hash } end - it "redirects to the login page" do - expect(response).to redirect_to "/login" + it 'redirects to the login page' do + expect(response).to redirect_to '/login' end it "doesn't activate the user" do - expect(User.find_by_login("register")).not_to be_active # rubocop:disable Rails/DynamicFindBy + expect(User.find_by_login('register')).not_to be_active # rubocop:disable Rails/DynamicFindBy end - it "calls the user_registered callback" do + it 'calls the user_registered callback' do user = hook.registered_user expect(user.mail).to eq "register@example.com" @@ -778,16 +778,16 @@ def reset! end end - context "with back_url" do + context 'with back_url' do before do - post :register, params: { user: user_hash, back_url: "https://example.net/some_back_url" } + post :register, params: { user: user_hash, back_url: 'https://example.net/some_back_url' } end - it "preserves the back url" do - expect(response).to redirect_to("/login?back_url=https%3A%2F%2Fexample.net%2Fsome_back_url") + it 'preserves the back url' do + expect(response).to redirect_to('/login?back_url=https%3A%2F%2Fexample.net%2Fsome_back_url') end - it "calls the user_registered callback" do + it 'calls the user_registered callback' do user = hook.registered_user expect(user.mail).to eq "register@example.com" @@ -795,68 +795,68 @@ def reset! end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) post :register end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end end - context "with self registration off", + context 'with self registration off', with_settings: { self_registration: Setting::SelfRegistration.disabled } do before do post :register, params: { user: { - login: "register", - password: "adminADMIN!", - password_confirmation: "adminADMIN!", - firstname: "John", - lastname: "Doe", - mail: "register@example.com" + login: 'register', + password: 'adminADMIN!', + password_confirmation: 'adminADMIN!', + firstname: 'John', + lastname: 'Doe', + mail: 'register@example.com' } } end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end - context "with on-the-fly registration", + context 'with on-the-fly registration', with_settings: { self_registration: Setting::SelfRegistration.disabled } do before do allow_any_instance_of(User).to receive(:change_password_allowed?).and_return(false) # rubocop:disable RSpec/AnyInstance end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) end - describe "registration" do + describe 'registration' do before do post :register, params: { user: { - firstname: "Foo", - lastname: "Smith", - mail: "foo@bar.com" + firstname: 'Foo', + lastname: 'Smith', + mail: 'foo@bar.com' } } end - it_behaves_like "registration disabled" + it_behaves_like 'registration disabled' end end end end - describe "POST #activate" do - describe "account activation" do - shared_examples "account activation" do + describe 'POST #activate' do + describe 'account activation' do + shared_examples 'account activation' do let(:token) { Token::Invitation.create user: } let(:activation_params) do @@ -865,19 +865,19 @@ def reset! } end - context "with an expired token" do + context 'with an expired token' do before do token.update_column :expires_on, 1.day.ago post :activate, params: activation_params end - it "fails and shows an expiration warning" do - expect(subject).to redirect_to("/") - expect(flash[:warning]).to include "expired" + it 'fails and shows an expiration warning' do + expect(subject).to redirect_to('/') + expect(flash[:warning]).to include 'expired' end - it "deletes the old token and generates a new one" do + it 'deletes the old token and generates a new one' do old_token = Token::Invitation.find_by(id: token.id) new_token = Token::Invitation.find_by(user_id: token.user.id) @@ -887,7 +887,7 @@ def reset! expect(new_token).not_to be_expired end - it "sends out a new activation email" do + it 'sends out a new activation email' do new_token = Token::Invitation.find_by(user_id: token.user.id) perform_enqueued_jobs @@ -898,20 +898,20 @@ def reset! end end - context "with an invited user" do - it_behaves_like "account activation" do + context 'with an invited user' do + it_behaves_like 'account activation' do let(:user) { create(:user, status: 4) } end end - context "with a registered user" do - it_behaves_like "account activation" do + context 'with a registered user' do + it_behaves_like 'account activation' do let(:user) { create(:user, status: 2) } end end end - describe "user limit" do + describe 'user limit' do let!(:admin) { create(:admin) } let(:user) { create(:user, status:) } let(:status) { -1 } @@ -943,13 +943,13 @@ def reset! end end - context "with an invited user" do + context 'with an invited user' do let(:status) { User.statuses[:invited] } it_behaves_like "activation is blocked due to user limit" end - context "with a registered user" do + context 'with a registered user' do let(:status) { User.statuses[:registered] } it_behaves_like "activation is blocked due to user limit" @@ -957,13 +957,13 @@ def reset! end end - describe "GET #auth_source_sso_failed (/sso)" do + describe 'GET #auth_source_sso_failed (/sso)' do render_views let(:failure) do { login:, - back_url: "/my/account", + back_url: '/my/account', ttl: 1 } end @@ -991,9 +991,9 @@ def reset! context "with an invalid user" do let!(:duplicate) { create(:user, mail: "login@DerpLAP.net") } - let(:login) { "foo" } + let(:login) { 'foo' } let(:attrs) do - { mail: duplicate.mail, login:, firstname: "bla", lastname: "bar" } + { mail: duplicate.mail, login:, firstname: 'bla', lastname: 'bar' } end before do @@ -1012,9 +1012,9 @@ def reset! context "with a missing email" do let!(:duplicate) { create(:user, mail: "login@DerpLAP.net") } - let(:login) { "foo" } + let(:login) { 'foo' } let(:attrs) do - { login:, firstname: "bla", lastname: "bar" } + { login:, firstname: 'bla', lastname: 'bar' } end before do diff --git a/spec/controllers/activities_controller_spec.rb b/spec/controllers/activities_controller_spec.rb index 4c657ca01535..b62983dce603 100644 --- a/spec/controllers/activities_controller_spec.rb +++ b/spec/controllers/activities_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ActivitiesController do shared_let(:admin) { create(:admin) } @@ -38,103 +38,103 @@ @params = {} end - describe "for GET index" do - shared_examples_for "valid index response" do + describe 'for GET index' do + shared_examples_for 'valid index response' do it { expect(response).to be_successful } - it { expect(response).to render_template "index" } + it { expect(response).to render_template 'index' } end - describe "global" do + describe 'global' do let!(:work_package) { create(:work_package, :created_in_past, created_at: 3.days.ago) } - before { get "index" } + before { get 'index' } - it_behaves_like "valid index response" + it_behaves_like 'valid index response' it { expect(assigns(:events)).not_to be_empty } - describe "view" do + describe 'view' do render_views it do - assert_select "h3", + assert_select 'h3', content: /#{3.days.ago.to_date.day}/, - sibling: { tag: "dl", - child: { tag: "dt", + sibling: { tag: 'dl', + child: { tag: 'dt', attributes: { class: /work_package/ }, - child: { tag: "a", + child: { tag: 'a', content: /#{ERB::Util.html_escape(work_package.subject)}/ } } } end end - describe "empty filter selection" do + describe 'empty filter selection' do before do - get "index", params: { event_types: [""] } + get 'index', params: { event_types: [''] } end - it_behaves_like "valid index response" + it_behaves_like 'valid index response' it { expect(assigns(:events)).to be_empty } end end - describe "with activated activity module" do + describe 'with activated activity module' do let(:project) do create(:project, enabled_module_names: %w[activity wiki]) end - it "renders activity" do - get "index", params: { project_id: project.id } + it 'renders activity' do + get 'index', params: { project_id: project.id } expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end end - describe "without activated activity module" do + describe 'without activated activity module' do let(:project) do create(:project, enabled_module_names: %w[wiki]) end - it "renders 403" do - get "index", params: { project_id: project.id } + it 'renders 403' do + get 'index', params: { project_id: project.id } expect(response).to have_http_status(:forbidden) - expect(response).to render_template "common/error" + expect(response).to render_template 'common/error' end end - shared_context "for GET index with params" do + shared_context 'for GET index with params' do let(:session_values) { defined?(session_hash) ? session_hash : {} } before { get :index, params:, session: session_values } end - describe "#atom_feed" do + describe '#atom_feed' do let(:user) { create(:user) } let(:project) { create(:project) } - context "with work packages" do + context 'with work packages' do let!(:wp1) do create(:work_package, project:, author: user) end - describe "global" do + describe 'global' do render_views - before { get "index", format: "atom" } + before { get 'index', format: 'atom' } - it "contains a link to the work package" do - assert_select "entry", - child: { tag: "link", + it 'contains a link to the work package' do + assert_select 'entry', + child: { tag: 'link', attributes: { href: Regexp.new("/work_packages/#{wp1.id}#") } } end end - describe "list" do + describe 'list' do let!(:wp2) do create(:work_package, project:, @@ -147,15 +147,15 @@ format: :atom } end - include_context "for GET index with params" + include_context 'for GET index with params' it { expect(assigns(:items).pluck(:event_type)).to match_array(%w[work_package-edit work_package-edit]) } - it { expect(response).to render_template("common/feed") } + it { expect(response).to render_template('common/feed') } end end - context "with forums" do + context 'with forums' do let(:forum) do create(:forum, project:) @@ -174,20 +174,20 @@ format: :atom } end - include_context "for GET index with params" + include_context 'for GET index with params' it { expect(assigns(:items).pluck(:event_type)).to match_array(%w[message message]) } - it { expect(response).to render_template("common/feed") } + it { expect(response).to render_template('common/feed') } end end - describe "user selection" do - describe "first activity request" do - let(:default_scope) { ["work_packages", "changesets"] } + describe 'user selection' do + describe 'first activity request' do + let(:default_scope) { ['work_packages', 'changesets'] } let(:params) { {} } - include_context "for GET index with params" + include_context 'for GET index with params' it { expect(assigns(:activity).scope).to match_array(default_scope) } @@ -196,12 +196,12 @@ it { expect(session[:activity][:with_subprojects]).to be(true) } end - describe "subsequent activity requests" do + describe 'subsequent activity requests' do let(:scope) { [] } let(:params) { {} } let(:session_hash) { { activity: { scope: [], with_subprojects: true } } } - include_context "for GET index with params" + include_context 'for GET index with params' it { expect(assigns(:activity).scope).to match_array(scope) } @@ -210,11 +210,11 @@ it { expect(session[:activity][:with_subprojects]).to be(true) } end - describe "selection with apply" do + describe 'selection with apply' do let(:scope) { [] } - let(:params) { { event_types: [""], with_subprojects: 0 } } + let(:params) { { event_types: [''], with_subprojects: 0 } } - include_context "for GET index with params" + include_context 'for GET index with params' it { expect(assigns(:activity).scope).to match_array(scope) } diff --git a/spec/controllers/admin/settings/aggregation_settings_controller_spec.rb b/spec/controllers/admin/settings/aggregation_settings_controller_spec.rb index 6fb616571b9c..226e68413297 100644 --- a/spec/controllers/admin/settings/aggregation_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/aggregation_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::AggregationSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("aggregation_settings") + require_admin_and_render_template('aggregation_settings') end diff --git a/spec/controllers/admin/settings/api_settings_controller_spec.rb b/spec/controllers/admin/settings/api_settings_controller_spec.rb index cdb51c270559..b5e7b94141dd 100644 --- a/spec/controllers/admin/settings/api_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/api_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::APISettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("api_settings") + require_admin_and_render_template('api_settings') end diff --git a/spec/controllers/admin/settings/attachments_settings_controller_spec.rb b/spec/controllers/admin/settings/attachments_settings_controller_spec.rb index f579676aedf7..fd8c04fc1738 100644 --- a/spec/controllers/admin/settings/attachments_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/attachments_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::AttachmentsSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("attachments_settings") + require_admin_and_render_template('attachments_settings') end diff --git a/spec/controllers/admin/settings/authentication_settings_controller_spec.rb b/spec/controllers/admin/settings/authentication_settings_controller_spec.rb index c10ea68dd230..e8483b137ed2 100644 --- a/spec/controllers/admin/settings/authentication_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/authentication_settings_controller_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::AuthenticationSettingsController do shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("authentication_settings") + require_admin_and_render_template('authentication_settings') - describe "PATCH #update" do - describe "registration_footer" do + describe 'PATCH #update' do + describe 'registration_footer' do let(:old_settings) do { registration_footer: { - "de" => "Old German registration footer", - "en" => "Old English registration footer" + 'de' => 'Old German registration footer', + 'en' => 'Old English registration footer' } } end @@ -49,8 +49,8 @@ let(:new_settings) do { registration_footer: { - "de" => "New German registration footer", - "en" => "New English registration footer" + 'de' => 'New German registration footer', + 'en' => 'New English registration footer' } } end @@ -61,31 +61,31 @@ end end - describe "when writable" do + describe 'when writable' do before do - patch "update", params: { settings: new_settings } + patch 'update', params: { settings: new_settings } end - it "is successful" do + it 'is successful' do expect(response).to redirect_to(admin_settings_authentication_path) end - it "changes the registration_footer" do + it 'changes the registration_footer' do expect(Setting.registration_footer).to eq new_settings[:registration_footer] end end - describe "when non-writable (set via env var)" do + describe 'when non-writable (set via env var)' do before do allow(Setting).to receive(:registration_footer_writable?).and_return(false) - patch "update", params: { settings: new_settings } + patch 'update', params: { settings: new_settings } end - it "is successful" do + it 'is successful' do expect(response).to redirect_to(admin_settings_authentication_path) end - it "does not change the registration_footer" do + it 'does not change the registration_footer' do expect(Setting.registration_footer).to eq old_settings[:registration_footer] end end diff --git a/spec/controllers/admin/settings/date_format_settings_controller_spec.rb b/spec/controllers/admin/settings/date_format_settings_controller_spec.rb index da10096690e5..350457c50720 100644 --- a/spec/controllers/admin/settings/date_format_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/date_format_settings_controller_spec.rb @@ -29,16 +29,16 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::DateFormatSettingsController do shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("date_format_settings") + require_admin_and_render_template('date_format_settings') - describe "PATCH #update" do - subject { patch "update", params: } + describe 'PATCH #update' do + subject { patch 'update', params: } let(:start_of_week) { 1 } let(:first_week_of_year) { 1 } @@ -49,25 +49,25 @@ end let(:params) { { settings: } } - shared_examples "invalid combination of start_of_week and first_week_of_year" do |missing_param:| + shared_examples 'invalid combination of start_of_week and first_week_of_year' do |missing_param:| provided_param = (%i[start_of_week first_week_of_year] - [missing_param]).first context "when setting only #{provided_param} but not #{missing_param}" do let(:settings) { base_settings.except(missing_param) } - it "redirects and sets the flash error" do + it 'redirects and sets the flash error' do subject expect(response).to redirect_to action: :show expect(flash[:error]) - .to eq(I18n.t("settings.date_format.first_date_of_week_and_year_set", + .to eq(I18n.t('settings.date_format.first_date_of_week_and_year_set', first_week_setting_name: I18n.t(:setting_first_week_of_year), day_of_week_setting_name: I18n.t(:setting_start_of_week))) end end end - include_examples "invalid combination of start_of_week and first_week_of_year", missing_param: :first_week_of_year - include_examples "invalid combination of start_of_week and first_week_of_year", missing_param: :start_of_week + include_examples 'invalid combination of start_of_week and first_week_of_year', missing_param: :first_week_of_year + include_examples 'invalid combination of start_of_week and first_week_of_year', missing_param: :start_of_week end end diff --git a/spec/controllers/admin/settings/general_settings_controller_spec.rb b/spec/controllers/admin/settings/general_settings_controller_spec.rb index 849f80be42b1..d7421267a999 100644 --- a/spec/controllers/admin/settings/general_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/general_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::GeneralSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("general_settings") + require_admin_and_render_template('general_settings') end diff --git a/spec/controllers/admin/settings/icalendar_settings_controller_spec.rb b/spec/controllers/admin/settings/icalendar_settings_controller_spec.rb index 92ff27937995..8dfa9d7bf5a5 100644 --- a/spec/controllers/admin/settings/icalendar_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/icalendar_settings_controller_spec.rb @@ -29,27 +29,27 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::IcalendarSettingsController do shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("icalendar_settings") + require_admin_and_render_template('icalendar_settings') - describe "PATCH #update" do - subject { patch "update", params: } + describe 'PATCH #update' do + subject { patch 'update', params: } let(:base_settings) do { ical_enabled: true } end let(:params) { { settings: } } - context "with valid params" do + context 'with valid params' do let(:settings) { base_settings } - it "succeeds" do + it 'succeeds' do subject expect(response).to redirect_to action: :show diff --git a/spec/controllers/admin/settings/incoming_mails_settings_controller_spec.rb b/spec/controllers/admin/settings/incoming_mails_settings_controller_spec.rb index bdf7577974e8..45a779273c9c 100644 --- a/spec/controllers/admin/settings/incoming_mails_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/incoming_mails_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::IncomingMailsSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("incoming_mails_settings") + require_admin_and_render_template('incoming_mails_settings') end diff --git a/spec/controllers/admin/settings/languages_settings_controller_spec.rb b/spec/controllers/admin/settings/languages_settings_controller_spec.rb index c07c48713de1..931f00d430ad 100644 --- a/spec/controllers/admin/settings/languages_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/languages_settings_controller_spec.rb @@ -29,17 +29,17 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::LanguagesSettingsController do shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("languages_settings") + require_admin_and_render_template('languages_settings') - describe "PATCH #update" do - subject { patch "update", params: } + describe 'PATCH #update' do + subject { patch 'update', params: } let(:available_languages) { %w[en fr de] } let(:base_settings) do @@ -47,31 +47,31 @@ end let(:params) { { settings: } } - context "with valid params" do + context 'with valid params' do let(:settings) { base_settings } - it "succeeds" do + it 'succeeds' do subject expect(response).to redirect_to action: :show expect(flash[:notice]).to eq I18n.t(:notice_successful_update) end - it "sets language of users having a non-available language to the default language", - with_settings: { available_languages: %w[en de ja], default_language: "de" } do - user_de = create(:user, language: "de") - user_en = create(:user, language: "en") - user_foo = create(:user, language: "foo") - user_fr = create(:user, language: "fr") - user_ja = create(:user, language: "ja") + it 'sets language of users having a non-available language to the default language', + with_settings: { available_languages: %w[en de ja], default_language: 'de' } do + user_de = create(:user, language: 'de') + user_en = create(:user, language: 'en') + user_foo = create(:user, language: 'foo') + user_fr = create(:user, language: 'fr') + user_ja = create(:user, language: 'ja') subject - expect(user_de.reload.language).to eq("de") - expect(user_en.reload.language).to eq("en") - expect(user_foo.reload.language).to eq("de") - expect(user_fr.reload.language).to eq("de") - expect(user_ja.reload.language).to eq("ja") + expect(user_de.reload.language).to eq('de') + expect(user_en.reload.language).to eq('en') + expect(user_foo.reload.language).to eq('de') + expect(user_fr.reload.language).to eq('de') + expect(user_ja.reload.language).to eq('ja') end end end diff --git a/spec/controllers/admin/settings/mail_notifications_settings_controller_spec.rb b/spec/controllers/admin/settings/mail_notifications_settings_controller_spec.rb index 163f6f974e66..74e65b4a546d 100644 --- a/spec/controllers/admin/settings/mail_notifications_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/mail_notifications_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::MailNotificationsSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("mail_notifications_settings") + require_admin_and_render_template('mail_notifications_settings') end diff --git a/spec/controllers/admin/settings/projects_settings_controller_spec.rb b/spec/controllers/admin/settings/projects_settings_controller_spec.rb index d4c6250c0225..3149f313b693 100644 --- a/spec/controllers/admin/settings/projects_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/projects_settings_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::ProjectsSettingsController do shared_let(:user) { create(:admin) } @@ -36,43 +36,43 @@ allow(controller).to receive(:set_localization) end - describe "GET #show" do + describe 'GET #show' do render_views - describe "default project modules" do - it "contains a check box for the activity module on the projects tab" do - get "show", params: { tab: "projects" } + describe 'default project modules' do + it 'contains a check box for the activity module on the projects tab' do + get 'show', params: { tab: 'projects' } expect(response).to be_successful - expect(response).to render_template "admin/settings/projects_settings/show" + expect(response).to render_template 'admin/settings/projects_settings/show' expect(response.body).to have_css "input[@name='settings[default_projects_modules][]'][@value='activity']" end - context "without activated activity module" do + context 'without activated activity module' do before do Setting.default_projects_modules = %w[wiki] end - it "contains an unchecked checkbox for activity" do - get "show", params: { tab: "projects" } + it 'contains an unchecked checkbox for activity' do + get 'show', params: { tab: 'projects' } expect(response).to be_successful - expect(response).to render_template "admin/settings/projects_settings/show" + expect(response).to render_template 'admin/settings/projects_settings/show' expect(response.body).to have_no_css "input[@name='settings[default_projects_modules][]'][@value='activity'][@checked='checked']" end end - context "with activity in Setting.default_projects_modules" do + context 'with activity in Setting.default_projects_modules' do before do Setting.default_projects_modules = %w[activity] end - it "contains a checked checkbox for activity" do - get "show", params: { tab: "projects" } + it 'contains a checked checkbox for activity' do + get 'show', params: { tab: 'projects' } expect(response).to be_successful - expect(response).to render_template "admin/settings/projects_settings/show" + expect(response).to render_template 'admin/settings/projects_settings/show' expect(response.body).to have_css "input[@name='settings[default_projects_modules][]'][@value='activity'][@checked='checked']" end @@ -80,42 +80,42 @@ end end - describe "PATCH #update" do + describe 'PATCH #update' do render_views - describe "default project modules" do - it "does not store the activity in the default_projects_modules if unchecked" do - patch "update", + describe 'default project modules' do + it 'does not store the activity in the default_projects_modules if unchecked' do + patch 'update', params: { - tab: "projects", + tab: 'projects', settings: { - default_projects_modules: ["wiki"] + default_projects_modules: ['wiki'] } } expect(response).to be_redirect - expect(response).to redirect_to action: "show", tab: "projects" + expect(response).to redirect_to action: 'show', tab: 'projects' - expect(Setting.default_projects_modules).to eq(["wiki"]) + expect(Setting.default_projects_modules).to eq(['wiki']) end - it "stores the activity in the default_projects_modules if checked" do - patch "update", + it 'stores the activity in the default_projects_modules if checked' do + patch 'update', params: { - tab: "projects", + tab: 'projects', settings: { - default_projects_modules: ["activity", "wiki"] + default_projects_modules: ['activity', 'wiki'] } } expect(response).to be_redirect - expect(response).to redirect_to action: "show", tab: "projects" + expect(response).to redirect_to action: 'show', tab: 'projects' - expect(Setting.default_projects_modules).to eq(["activity", "wiki"]) + expect(Setting.default_projects_modules).to eq(['activity', 'wiki']) end end - describe "password settings" do + describe 'password settings' do let(:new_settings) do { password_min_length: 42, @@ -142,74 +142,74 @@ end end - context "with password login enabled" do + context 'with password login enabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(false) - patch "update", params: { tab: "authentication", settings: new_settings } + patch 'update', params: { tab: 'authentication', settings: new_settings } end - it "is successful" do + it 'is successful' do expect(response).to be_redirect # to auth tab end - it "sets the minimum password length to 42" do + it 'sets the minimum password length to 42' do expect(Setting[:password_min_length]).to eq 42 end - it "sets the active character classes to lowercase and uppercase" do + it 'sets the active character classes to lowercase and uppercase' do expect(Setting[:password_active_rules]).to eq %w[uppercase lowercase] end - it "sets the required number of classes to 7" do + it 'sets the required number of classes to 7' do expect(Setting[:password_min_adhered_rules]).to eq 7 end - it "sets passwords to expire after 13 days" do + it 'sets passwords to expire after 13 days' do expect(Setting[:password_days_valid]).to eq 13 end - it "bans the last 80 passwords" do + it 'bans the last 80 passwords' do expect(Setting[:password_count_former_banned]).to eq 80 end - it "sets the lost password option to false" do + it 'sets the lost password option to false' do expect(Setting[:lost_password]).to be false end end - describe "with password login disabled" do + describe 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) - patch "update", params: { tab: "authentication", settings: new_settings } + patch 'update', params: { tab: 'authentication', settings: new_settings } end - it "is successful" do + it 'is successful' do expect(response).to be_redirect # to auth tab end - it "does not set the minimum password length to 42" do + it 'does not set the minimum password length to 42' do expect(Setting[:password_min_length]).to eq 10 end - it "does not set the active character classes to lowercase and uppercase" do + it 'does not set the active character classes to lowercase and uppercase' do expect(Setting[:password_active_rules]).to eq [] end - it "does not set the required number of classes to 7" do + it 'does not set the required number of classes to 7' do expect(Setting[:password_min_adhered_rules]).to eq 0 end - it "does not set passwords to expire after 13 days" do + it 'does not set passwords to expire after 13 days' do expect(Setting[:password_days_valid]).to eq 365 end - it "does not ban the last 80 passwords" do + it 'does not ban the last 80 passwords' do expect(Setting[:password_count_former_banned]).to eq 2 end - it "keeps the lost password option" do + it 'keeps the lost password option' do expect(Setting[:lost_password]).to be true end end diff --git a/spec/controllers/admin/settings/repositories_settings_controller_spec.rb b/spec/controllers/admin/settings/repositories_settings_controller_spec.rb index c7ee75bcec88..24679ec12642 100644 --- a/spec/controllers/admin/settings/repositories_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/repositories_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::RepositoriesSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("repositories_settings") + require_admin_and_render_template('repositories_settings') end diff --git a/spec/controllers/admin/settings/users_settings_controller_spec.rb b/spec/controllers/admin/settings/users_settings_controller_spec.rb index cf98d178b61f..3a48b7b2f8a3 100644 --- a/spec/controllers/admin/settings/users_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/users_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::UsersSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("users_settings") + require_admin_and_render_template('users_settings') end diff --git a/spec/controllers/admin/settings/work_packages_settings_controller_spec.rb b/spec/controllers/admin/settings/work_packages_settings_controller_spec.rb index 03a3f0c98489..b0dae291c33a 100644 --- a/spec/controllers/admin/settings/work_packages_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/work_packages_settings_controller_spec.rb @@ -29,12 +29,12 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::WorkPackagesSettingsController do # rubocop:disable RSpec/EmptyExampleGroup shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("work_packages_settings") + require_admin_and_render_template('work_packages_settings') end diff --git a/spec/controllers/admin/settings/working_days_settings_controller_spec.rb b/spec/controllers/admin/settings/working_days_settings_controller_spec.rb index 8063cf1fd809..f4b695e9a12d 100644 --- a/spec/controllers/admin/settings/working_days_settings_controller_spec.rb +++ b/spec/controllers/admin/settings/working_days_settings_controller_spec.rb @@ -26,76 +26,76 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Admin::Settings::WorkingDaysSettingsController do shared_let(:user) { create(:admin) } current_user { user } - require_admin_and_render_template("working_days_settings") + require_admin_and_render_template('working_days_settings') - describe "update" do - let(:working_days) { [*"1".."7"] } + describe 'update' do + let(:working_days) { [*'1'..'7'] } let(:non_working_days_attributes) { {} } let(:params) do { settings: { working_days:, non_working_days_attributes: } } end - subject { patch "update", params: } + subject { patch 'update', params: } - it "succeeds" do + it 'succeeds' do subject - expect(response).to redirect_to action: "show" + expect(response).to redirect_to action: 'show' expect(flash[:notice]).to eq I18n.t(:notice_successful_update) end - context "with non_working_days" do + context 'with non_working_days' do let(:non_working_days_attributes) do - { "0" => { "name" => "Christmas Eve", "date" => "2022-12-24" } } + { '0' => { 'name' => 'Christmas Eve', 'date' => '2022-12-24' } } end - it "succeeds" do + it 'succeeds' do subject - expect(response).to redirect_to action: "show" + expect(response).to redirect_to action: 'show' expect(flash[:notice]).to eq I18n.t(:notice_successful_update) end - it "creates the non_working_days" do + it 'creates the non_working_days' do expect { subject }.to change(NonWorkingDay, :count).by(1) - expect(NonWorkingDay.first).to have_attributes(name: "Christmas Eve", date: Date.parse("2022-12-24")) + expect(NonWorkingDay.first).to have_attributes(name: 'Christmas Eve', date: Date.parse('2022-12-24')) end end - context "when fails with a duplicate entry" do - let(:nwd_to_delete) { create(:non_working_day, name: "NWD to delete") } + context 'when fails with a duplicate entry' do + let(:nwd_to_delete) { create(:non_working_day, name: 'NWD to delete') } let(:non_working_days_attributes) do { - "0" => { "name" => "Christmas Eve", "date" => "2022-12-24" }, - "1" => { "name" => "Christmas Eve2", "date" => "2022-12-24" }, - "2" => { "id" => nwd_to_delete.id, "_destroy" => true } + '0' => { 'name' => 'Christmas Eve', 'date' => '2022-12-24' }, + '1' => { 'name' => 'Christmas Eve2', 'date' => '2022-12-24' }, + '2' => { 'id' => nwd_to_delete.id, '_destroy' => true } } end - it "displays the error message" do + it 'displays the error message' do subject expect(response).to render_template :show - expect(flash[:error]).to eq "A non-working day already exists for 2022-12-24." + expect(flash[:error]).to eq 'A non-working day already exists for 2022-12-24.' end - it "sets the @modified_non_working_days variable" do + it 'sets the @modified_non_working_days variable' do subject expect(assigns(:modified_non_working_days)).to contain_exactly( - hash_including("name" => "Christmas Eve", "date" => "2022-12-24"), - hash_including("name" => "Christmas Eve2", "date" => "2022-12-24"), - hash_including(nwd_to_delete.as_json(only: %i[id name date]).merge("_destroy" => true)) + hash_including('name' => 'Christmas Eve', 'date' => '2022-12-24'), + hash_including('name' => 'Christmas Eve2', 'date' => '2022-12-24'), + hash_including(nwd_to_delete.as_json(only: %i[id name date]).merge('_destroy' => true)) ) end - it "does not destroys other records" do + it 'does not destroys other records' do subject expect { nwd_to_delete.reload }.not_to raise_error end diff --git a/spec/controllers/admin_controller_spec.rb b/spec/controllers/admin_controller_spec.rb index 275e764b6795..05807d28a85f 100644 --- a/spec/controllers/admin_controller_spec.rb +++ b/spec/controllers/admin_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AdminController do let(:user) { build(:admin) } @@ -35,12 +35,12 @@ allow(User).to receive(:current).and_return user end - describe "#index" do - it "renders index" do + describe '#index' do + it 'renders index' do get :index expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end describe "with a plugin adding a menu item" do @@ -56,9 +56,9 @@ Redmine::Plugin.register name.to_sym do menu :admin_menu, :"#{name}_settings", - { controller: "/admin/settings", action: :show_plugin, id: :"openproject_#{name}" }, + { controller: '/admin/settings', action: :show_plugin, id: :"openproject_#{name}" }, caption: name.capitalize, - icon: "arrow", + icon: 'arrow', if: ->(*) { show } end @@ -70,7 +70,7 @@ let(:visible) { true } it "shows the plugin in the overview" do - expect(response.body).to have_css("a.menu-block", text: plugin_name.capitalize) + expect(response.body).to have_css('a.menu-block', text: plugin_name.capitalize) end end @@ -79,16 +79,16 @@ let(:visible) { false } it "does not show the plugin in the overview" do - expect(response.body).to have_no_css("a.menu-block", text: plugin_name.capitalize) + expect(response.body).to have_no_css('a.menu-block', text: plugin_name.capitalize) end end end end - describe "#plugins" do + describe '#plugins' do render_views - context "with plugins" do + context 'with plugins' do before do Redmine::Plugin.register :foo do end @@ -96,36 +96,36 @@ end end - it "renders the plugins" do + it 'renders the plugins' do get :plugins expect(response).to be_successful - expect(response).to render_template "plugins" + expect(response).to render_template 'plugins' - expect(response.body).to have_css("td span", text: "Foo") - expect(response.body).to have_css("td span", text: "Bar") + expect(response.body).to have_css('td span', text: 'Foo') + expect(response.body).to have_css('td span', text: 'Bar') end end - context "without plugins" do + context 'without plugins' do before do Redmine::Plugin.clear end - it "renders even without plugins" do + it 'renders even without plugins' do get :plugins expect(response).to be_successful - expect(response).to render_template "plugins" + expect(response).to render_template 'plugins' end end end - describe "#info" do - it "renders info" do + describe '#info' do + it 'renders info' do get :info expect(response).to be_successful - expect(response).to render_template "info" + expect(response).to render_template 'info' end end end diff --git a/spec/controllers/announcements_controller_spec.rb b/spec/controllers/announcements_controller_spec.rb index 51b27f8c430f..2a28c91619ed 100644 --- a/spec/controllers/announcements_controller_spec.rb +++ b/spec/controllers/announcements_controller_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe AnnouncementsController do let(:announcement) { build(:announcement) } @@ -10,7 +10,7 @@ allow(Announcement).to receive(:only_one).and_return(announcement) end - describe "#edit" do + describe '#edit' do before do get :edit end @@ -22,20 +22,20 @@ it { expect(response).to be_successful } end - describe "#update" do + describe '#update' do before do expect(announcement).to receive(:save).and_call_original put :update, params: { announcement: { - until_date: "2011-01-11", - text: "announcement!!!", + until_date: '2011-01-11', + text: 'announcement!!!', active: 1 } } end - it "edits the announcement" do + it 'edits the announcement' do expect(response).to redirect_to action: :edit expect(controller).to set_flash[:notice].to I18n.t(:notice_successful_update) end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 1445e4aa56d6..244968946d0a 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ApplicationController do let(:user) { create(:user, lastname: "Crazy name") } @@ -39,20 +39,20 @@ def index end end - describe "logging requesting users", with_settings: { login_required: false } do + describe 'logging requesting users', with_settings: { login_required: false } do let(:user_message) do "OpenProject User: #{user.firstname} Crazy name (#{user.login} ID: #{user.id} <#{user.mail}>)" end - let(:anonymous_message) { "OpenProject User: Anonymous" } + let(:anonymous_message) { 'OpenProject User: Anonymous' } - describe "with log_requesting_user enabled" do + describe 'with log_requesting_user enabled' do before do allow(Rails.logger).to receive(:info) allow(Setting).to receive(:log_requesting_user?).and_return(true) end - it "logs the current user" do + it 'logs the current user' do expect(Rails.logger).to receive(:info).once.with(user_message) as_logged_in_user(user) do @@ -60,7 +60,7 @@ def index end end - it "logs an anonymous user" do + it 'logs an anonymous user' do expect(Rails.logger).to receive(:info).once.with(anonymous_message) # no login, so this is done as Anonymous @@ -68,12 +68,12 @@ def index end end - describe "with log_requesting_user disabled" do + describe 'with log_requesting_user disabled' do before do allow(Setting).to receive(:log_requesting_user?).and_return(false) end - it "does not log the current user" do + it 'does not log the current user' do expect(Rails.logger).not_to receive(:info).with(user_message) as_logged_in_user(user) do @@ -83,8 +83,8 @@ def index end end - describe "unverified request", with_settings: { login_required: false } do - shared_examples "handle_unverified_request resets session" do + describe 'unverified request', with_settings: { login_required: false } do + shared_examples 'handle_unverified_request resets session' do before do ActionController::Base.allow_forgery_protection = true end @@ -93,8 +93,8 @@ def index ActionController::Base.allow_forgery_protection = false end - it "deletes the autologin cookie" do - cookies_double = double("cookies").as_null_object + it 'deletes the autologin cookie' do + cookies_double = double('cookies').as_null_object allow(controller) .to receive(:cookies) @@ -102,12 +102,12 @@ def index expect(cookies_double) .to receive(:delete) - .with(OpenProject::Configuration["autologin_cookie_name"]) + .with(OpenProject::Configuration['autologin_cookie_name']) post :index end - it "logs out the user" do + it 'logs out the user' do @controller.send(:logged_user=, create(:user)) allow(@controller).to receive(:render_error) @@ -117,14 +117,14 @@ def index end end - context "for non-API resources" do + context 'for non-API resources' do before do allow(@controller).to receive(:api_request?).and_return(false) end - it_behaves_like "handle_unverified_request resets session" + it_behaves_like 'handle_unverified_request resets session' - it "gives 422" do + it 'gives 422' do expect(@controller).to receive(:render_error) do |options| expect(options[:status]).to be(422) end @@ -133,14 +133,14 @@ def index end end - context "for API resources" do + context 'for API resources' do before do allow(@controller).to receive(:api_request?).and_return(true) end - it_behaves_like "handle_unverified_request resets session" + it_behaves_like 'handle_unverified_request resets session' - it "does not render an error" do + it 'does not render an error' do expect(@controller).not_to receive(:render_error) @controller.send :handle_unverified_request @@ -148,7 +148,7 @@ def index end end - describe "rack timeout duplicate error suppression", with_settings: { login_required: false } do + describe 'rack timeout duplicate error suppression', with_settings: { login_required: false } do controller do include OpenProjectErrorHelper diff --git a/spec/controllers/attribute_help_texts_controller_spec.rb b/spec/controllers/attribute_help_texts_controller_spec.rb index 061db98398fa..399437dabdc1 100644 --- a/spec/controllers/attribute_help_texts_controller_spec.rb +++ b/spec/controllers/attribute_help_texts_controller_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe AttributeHelpTextsController do let(:user) { build_stubbed(:user) } @@ -19,34 +19,34 @@ end end - describe "#index" do + describe '#index' do before do allow(AttributeHelpText).to receive(:all).and_return [model] get :index end - it "is successful" do + it 'is successful' do expect(response).to be_successful - expect(assigns(:texts_by_type)).to eql("WorkPackage" => [model]) + expect(assigns(:texts_by_type)).to eql('WorkPackage' => [model]) end end - describe "#edit" do + describe '#edit' do before do find_expectation get :edit, params: { id: 1234 } end - context "when found" do - it "is successful" do + context 'when found' do + it 'is successful' do expect(response).to be_successful expect(assigns(:attribute_help_text)).to eql model end end - context "when not found" do + context 'when not found' do let(:find_expectation) do allow(AttributeHelpText) .to receive(:find) @@ -54,19 +54,19 @@ .and_raise(ActiveRecord::RecordNotFound) end - it "returns 404" do + it 'returns 404' do expect(response).to have_http_status :not_found end end end - describe "#update" do + describe '#update' do let(:call) do put :update, params: { id: 1234, attribute_help_text: { - help_text: "my new help text" + help_text: 'my new help text' } } end @@ -75,35 +75,35 @@ find_expectation end - context "when save is success" do + context 'when save is success' do before do expect(model).to receive(:save).and_return(true) call end - it "edits the announcement" do - expect(response).to redirect_to action: :index, tab: "WorkPackage" + it 'edits the announcement' do + expect(response).to redirect_to action: :index, tab: 'WorkPackage' expect(controller).to set_flash[:notice].to I18n.t(:notice_successful_update) - expect(model.help_text).to eq("my new help text") + expect(model.help_text).to eq('my new help text') end end - context "when save is failure" do + context 'when save is failure' do before do expect(model).to receive(:save).and_return(false) call end - it "fails to update the announcement" do + it 'fails to update the announcement' do expect(response).to be_successful - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end end - context "when not found" do + context 'when not found' do let(:find_expectation) do allow(AttributeHelpText) .to receive(:find) @@ -115,7 +115,7 @@ call end - it "returns 404" do + it 'returns 404' do expect(response).to have_http_status :not_found end end diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb index 859bc1cbf06c..4653a1bfa0ba 100644 --- a/spec/controllers/categories_controller_spec.rb +++ b/spec/controllers/categories_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CategoriesController do let(:user) { create(:user) } @@ -48,7 +48,7 @@ allow(User).to receive(:current).and_return user end - shared_examples_for "redirect" do + shared_examples_for 'redirect' do subject { response } it { is_expected.to be_redirect } @@ -56,7 +56,7 @@ it { is_expected.to redirect_to("/projects/#{project.identifier}/settings/categories") } end - describe "#new" do + describe '#new' do before do get :new, params: { project_id: project.id } end @@ -65,11 +65,11 @@ it { is_expected.to be_successful } - it { is_expected.to render_template("new") } + it { is_expected.to render_template('new') } end - describe "#create" do - let(:category_name) { "New category" } + describe '#create' do + let(:category_name) { 'New category' } before do post :create, @@ -80,7 +80,7 @@ } end - describe "#categories" do + describe '#categories' do subject { Category.find_by(name: category_name) } it { expect(subject.project_id).to eq(project.id) } @@ -88,10 +88,10 @@ it { expect(subject.assigned_to_id).to eq(user.id) } end - it_behaves_like "redirect" + it_behaves_like 'redirect' end - describe "#edit" do + describe '#edit' do let(:category) do create(:category, project:) @@ -103,24 +103,24 @@ get :edit, params: { id: category_id } end - context "valid category" do + context 'valid category' do let(:category_id) { category.id } it { is_expected.to be_successful } - it { is_expected.to render_template("edit") } + it { is_expected.to render_template('edit') } end - context "invalid category" do + context 'invalid category' do let(:category_id) { 404 } it { is_expected.to be_not_found } end end - describe "#update" do - let(:name) { "Testing" } + describe '#update' do + let(:name) { 'Testing' } - context "valid category" do + context 'valid category' do let(:category) do create(:category, project:) @@ -138,16 +138,16 @@ it { is_expected.to eq(name) } - describe "#category_count" do + describe '#category_count' do subject { Category.count } it { is_expected.to eq(1) } end - it_behaves_like "redirect" + it_behaves_like 'redirect' end - context "invalid category" do + context 'invalid category' do before do post :update, params: { @@ -162,7 +162,7 @@ end end - describe "#destroy" do + describe '#destroy' do let(:category) do create(:category, project:) @@ -175,23 +175,23 @@ before { category } - shared_examples_for "delete" do + shared_examples_for 'delete' do subject { Category.find_by(id: category.id) } it { is_expected.to be_nil } end - context "unused" do + context 'unused' do before do delete :destroy, params: { id: category.id } end - it_behaves_like "redirect" + it_behaves_like 'redirect' - it_behaves_like "delete" + it_behaves_like 'delete' end - context "in use" do + context 'in use' do before do work_package @@ -202,16 +202,16 @@ it { is_expected.not_to be_nil } - describe "#response" do + describe '#response' do subject { response } it { is_expected.to be_successful } - it { is_expected.to render_template("destroy") } + it { is_expected.to render_template('destroy') } end end - describe "#reassign" do + describe '#reassign' do let(:target) do create(:category, project:) @@ -223,7 +223,7 @@ delete :destroy, params: { id: category.id, - todo: "reassign", + todo: 'reassign', reassign_to_id: target.id } end @@ -232,19 +232,19 @@ it { is_expected.to eq(target.id) } - it_behaves_like "delete" + it_behaves_like 'delete' - it_behaves_like "redirect" + it_behaves_like 'redirect' end - describe "#nullify" do + describe '#nullify' do before do work_package delete :destroy, params: { id: category.id, - todo: "nullify" + todo: 'nullify' } end @@ -252,9 +252,9 @@ it { is_expected.to be_nil } - it_behaves_like "delete" + it_behaves_like 'delete' - it_behaves_like "redirect" + it_behaves_like 'redirect' end end end diff --git a/spec/controllers/colors_controller_spec.rb b/spec/controllers/colors_controller_spec.rb index 36c74d34bffe..ee82de965387 100644 --- a/spec/controllers/colors_controller_spec.rb +++ b/spec/controllers/colors_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ColorsController do let(:current_user) { create(:admin) } @@ -35,68 +35,68 @@ allow(User).to receive(:current).and_return current_user end - describe "index.html" do + describe 'index.html' do def fetch - get "index" + get 'index' end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - describe "new.html" do + describe 'new.html' do def fetch - get "new" + get 'new' end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - describe "create.html" do + describe 'create.html' do def fetch - post "create", params: { color: build(:color).attributes } + post 'create', params: { color: build(:color).attributes } end def expect_redirect_to Regexp.new(colors_path) end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - describe "edit.html" do + describe 'edit.html' do def fetch - @available_color = create(:color, id: "1337") - get "edit", params: { id: "1337" } + @available_color = create(:color, id: '1337') + get 'edit', params: { id: '1337' } end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - describe "update.html" do + describe 'update.html' do def fetch - @available_color = create(:color, id: "1337") - put "update", params: { id: "1337", color: { "name" => "blubs" } } + @available_color = create(:color, id: '1337') + put 'update', params: { id: '1337', color: { 'name' => 'blubs' } } end def expect_redirect_to colors_path end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - describe "confirm_destroy.html" do + describe 'confirm_destroy.html' do def fetch - @available_color = create(:color, id: "1337") - get "confirm_destroy", params: { id: "1337" } + @available_color = create(:color, id: '1337') + get 'confirm_destroy', params: { id: '1337' } end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - describe "destroy.html" do + describe 'destroy.html' do def fetch - @available_color = create(:color, id: "1337") - post "destroy", params: { id: "1337" } + @available_color = create(:color, id: '1337') + post 'destroy', params: { id: '1337' } end def expect_redirect_to colors_path end - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end end diff --git a/spec/controllers/concerns/auth_source_slo_spec.rb b/spec/controllers/concerns/auth_source_slo_spec.rb index fe320d74fa9f..6e68a4f82cce 100644 --- a/spec/controllers/concerns/auth_source_slo_spec.rb +++ b/spec/controllers/concerns/auth_source_slo_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' ## -RSpec.describe AccountController, "Auth header logout" do +RSpec.describe AccountController, 'Auth header logout' do render_views let!(:auth_source) { create(:ldap_auth_source, name: "Dummy LDAP") } @@ -44,34 +44,34 @@ end end - describe "logout" do - context "when a logout URL is present" do + describe 'logout' do + context 'when a logout URL is present' do let(:sso_config) do { - logout_url: "https://example.org/foo?logout=true" + logout_url: 'https://example.org/foo?logout=true' } end - context "and the user came from auth source" do + context 'and the user came from auth source' do before do login_as user session[:user_from_auth_header] = true get :logout end - it "is redirected to the logout URL" do - expect(response).to redirect_to "https://example.org/foo?logout=true" + it 'is redirected to the logout URL' do + expect(response).to redirect_to 'https://example.org/foo?logout=true' end end - context "and the user did not come from auth source" do + context 'and the user did not come from auth source' do before do login_as user session[:user_from_auth_header] = nil get :logout end - it "is redirected to the home URL" do + it 'is redirected to the home URL' do expect(response).to redirect_to home_url end end diff --git a/spec/controllers/concerns/auth_source_sso_spec.rb b/spec/controllers/concerns/auth_source_sso_spec.rb index edd5322155a0..bfea1e110231 100644 --- a/spec/controllers/concerns/auth_source_sso_spec.rb +++ b/spec/controllers/concerns/auth_source_sso_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MyController, :skip_2fa_stage do render_views @@ -48,7 +48,7 @@ let(:header_value) { "#{header_login_value}#{secret ? ':' : ''}#{secret}" } let(:find_user_result) { user } - shared_examples "should log in the user" do + shared_examples 'should log in the user' do it "logs in given user" do expect(response).to redirect_to my_account_path expect(user.reload.last_login_on).to be_within(10.seconds).of(Time.current) @@ -68,7 +68,7 @@ expect(failure[:ttl]).to eq 1 end - context "when the config is marked optional" do + context 'when the config is marked optional' do let(:sso_config) do { header:, @@ -77,7 +77,7 @@ } end - context "when no header is present" do + context 'when no header is present' do let(:header_value) { nil } it "redirects to login" do @@ -85,7 +85,7 @@ end end - context "when the header is present" do + context 'when the header is present' do it "shows an error" do expect(response).to redirect_to("/sso") expect(session).to have_key(:auth_source_sso_failure) @@ -108,32 +108,32 @@ request.headers[header] = header_value end - describe "login" do + describe 'login' do before do get :account end - it_behaves_like "should log in the user" + it_behaves_like 'should log in the user' - context "when the secret being null" do + context 'when the secret being null' do let(:secret) { nil } - it_behaves_like "should log in the user" + it_behaves_like 'should log in the user' end - context "when the secret is a number" do + context 'when the secret is a number' do let(:secret) { 42 } - it_behaves_like "should log in the user" + it_behaves_like 'should log in the user' end - context "when the header values does not match the case" do - let(:header_login_value) { "H.wUrSt" } + context 'when the header values does not match the case' do + let(:header_login_value) { 'H.wUrSt' } - it_behaves_like "should log in the user" + it_behaves_like 'should log in the user' end - context "when the user is invited" do + context 'when the user is invited' do let!(:user) do create(:user, login:, status: Principal.statuses[:invited], ldap_auth_source:) end @@ -173,8 +173,8 @@ end end - context "when the logged-in user differs in case" do - let(:header_login_value) { "h.WURST" } + context 'when the logged-in user differs in case' do + let(:header_login_value) { 'h.WURST' } let(:session_update_time) { 1.minute.ago } let(:last_login) { 1.minute.ago } @@ -185,7 +185,7 @@ session[:should_be_kept] = true end - it "logs in the user" do + it 'logs in the user' do get :account expect(response).not_to be_redirect @@ -201,8 +201,8 @@ end end - context "when the logged-in user differs from the header" do - let(:other_user) { create(:user, login: "other_user") } + context 'when the logged-in user differs from the header' do + let(:other_user) { create(:user, login: 'other_user') } let(:session_update_time) { 1.minute.ago } let(:service) { Users::LogoutService.new(controller:) } @@ -211,7 +211,7 @@ session[:updated_at] = session_update_time end - it "logs out the user and logs it in again" do + it 'logs out the user and logs it in again' do allow(Users::LogoutService).to receive(:new).and_return(service) allow(service).to receive(:call!).with(other_user).and_call_original diff --git a/spec/controllers/concerns/omniauth_login_spec.rb b/spec/controllers/concerns/omniauth_login_spec.rb index 5c78e08132dd..9037116d4a7b 100644 --- a/spec/controllers/concerns/omniauth_login_spec.rb +++ b/spec/controllers/concerns/omniauth_login_spec.rb @@ -26,100 +26,100 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' # Concern is included into AccountController and depends on methods available there RSpec.describe AccountController, :skip_2fa_stage do - let(:omniauth_strategy) { double("Google Strategy", name: "google") } + let(:omniauth_strategy) { double('Google Strategy', name: 'google') } let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", + provider: 'google', strategy: omniauth_strategy, - uid: "123545", - info: { name: "foo", - email: "foo@bar.com", - first_name: "foo", - last_name: "bar" } + uid: '123545', + info: { name: 'foo', + email: 'foo@bar.com', + first_name: 'foo', + last_name: 'bar' } ) end before do - request.env["omniauth.auth"] = omniauth_hash - request.env["omniauth.strategy"] = omniauth_strategy + request.env['omniauth.auth'] = omniauth_hash + request.env['omniauth.strategy'] = omniauth_strategy end after do User.current = nil end - context "GET #omniauth_login", with_settings: { self_registration: Setting::SelfRegistration.automatic } do - describe "with on-the-fly registration" do - context "providing all required fields" do + context 'GET #omniauth_login', with_settings: { self_registration: Setting::SelfRegistration.automatic } do + describe 'with on-the-fly registration' do + context 'providing all required fields' do before do - request.env["omniauth.origin"] = "https://example.net/some_back_url" + request.env['omniauth.origin'] = 'https://example.net/some_back_url' post :omniauth_login, params: { provider: :google } end - it "registers the user on-the-fly" do - user = User.find_by_login("foo@bar.com") + it 'registers the user on-the-fly' do + user = User.find_by_login('foo@bar.com') expect(user).to be_an_instance_of(User) expect(user.ldap_auth_source_id).to be_nil expect(user.current_password).to be_nil - expect(user.identity_url).to eql("google:123545") - expect(user.login).to eql("foo@bar.com") - expect(user.firstname).to eql("foo") - expect(user.lastname).to eql("bar") - expect(user.mail).to eql("foo@bar.com") + expect(user.identity_url).to eql('google:123545') + expect(user.login).to eql('foo@bar.com') + expect(user.firstname).to eql('foo') + expect(user.lastname).to eql('bar') + expect(user.mail).to eql('foo@bar.com') end - it "redirects to the first login page with a back_url" do + it 'redirects to the first login page with a back_url' do expect(response).to redirect_to(home_url(first_time_user: true)) end end - describe "strategy uid mapping override" do + describe 'strategy uid mapping override' do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", + provider: 'google', strategy: omniauth_strategy, - uid: "foo", + uid: 'foo', info: { - uid: "internal", - email: "whattheheck@example.com", - first_name: "what", - last_name: "theheck" + uid: 'internal', + email: 'whattheheck@example.com', + first_name: 'what', + last_name: 'theheck' } ) end - it "takes the uid from the mapped attributes" do + it 'takes the uid from the mapped attributes' do post :omniauth_login, params: { provider: :google } - user = User.find_by_login("whattheheck@example.com") + user = User.find_by_login('whattheheck@example.com') expect(user).to be_an_instance_of(User) - expect(user.identity_url).to eq "google:internal" + expect(user.identity_url).to eq 'google:internal' end end - describe "strategy attribute mapping override" do + describe 'strategy attribute mapping override' do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", + provider: 'google', strategy: omniauth_strategy, - uid: "foo", - info: { email: "whattheheck@example.com", - first_name: "what", - last_name: "theheck" }, + uid: 'foo', + info: { email: 'whattheheck@example.com', + first_name: 'what', + last_name: 'theheck' }, extra: { raw_info: { - real_uid: "bar@example.org", - first_name: "foo", - last_name: "bar" + real_uid: 'bar@example.org', + first_name: 'foo', + last_name: 'bar' } } ) end - context "available" do - it "merges the strategy mapping" do + context 'available' do + it 'merges the strategy mapping' do allow(omniauth_strategy).to receive(:omniauth_hash_to_user_attributes) do |auth| raw_info = auth[:extra][:raw_info] { @@ -133,44 +133,44 @@ post :omniauth_login, params: { provider: :google } - user = User.find_by_login("bar@example.org") + user = User.find_by_login('bar@example.org') expect(user).to be_an_instance_of(User) - expect(user.firstname).to eql("foo") - expect(user.lastname).to eql("bar") + expect(user.firstname).to eql('foo') + expect(user.lastname).to eql('bar') end end - context "unavailable" do - it "keeps the default mapping" do + context 'unavailable' do + it 'keeps the default mapping' do post :omniauth_login, params: { provider: :google } - user = User.find_by_login("whattheheck@example.com") + user = User.find_by_login('whattheheck@example.com') expect(user).to be_an_instance_of(User) - expect(user.firstname).to eql("what") - expect(user.lastname).to eql("theheck") + expect(user.firstname).to eql('what') + expect(user.lastname).to eql('theheck') end end end - context "not providing all required fields" do + context 'not providing all required fields' do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", - uid: "123545", - info: { name: "foo", email: "foo@bar.com" } + provider: 'google', + uid: '123545', + info: { name: 'foo', email: 'foo@bar.com' } # first_name and last_name not set ) end - it "renders user form" do + it 'renders user form' do post :omniauth_login, params: { provider: :google } expect(response).to render_template :register - expect(assigns(:user).mail).to eql("foo@bar.com") + expect(assigns(:user).mail).to eql('foo@bar.com') end - it "registers user via post" do + it 'registers user via post' do expect(OpenProject::OmniAuth::Authorization).to receive(:after_login!) do |user, auth_hash| - new_user = User.find_by_login("login@bar.com") + new_user = User.find_by_login('login@bar.com') expect(user).to eq new_user expect(auth_hash).to include(omniauth_hash) end @@ -183,22 +183,22 @@ post :register, params: { user: { - login: "login@bar.com", - firstname: "Foo", - lastname: "Smith", - mail: "foo@bar.com" + login: 'login@bar.com', + firstname: 'Foo', + lastname: 'Smith', + mail: 'foo@bar.com' } } expect(response).to redirect_to home_url(first_time_user: true) - user = User.find_by_login("login@bar.com") + user = User.find_by_login('login@bar.com') expect(user).to be_an_instance_of(User) expect(user.ldap_auth_source_id).to be_nil expect(user.current_password).to be_nil - expect(user.identity_url).to eql("google:123545") + expect(user.identity_url).to eql('google:123545') end - context "after a timeout expired" do + context 'after a timeout expired' do before do session[:auth_source_registration] = omniauth_hash.merge( omniauth: true, @@ -206,97 +206,97 @@ ) end - it "does not register the user when providing all the missing fields" do + it 'does not register the user when providing all the missing fields' do post :register, params: { user: { - firstname: "Foo", - lastname: "Smith", - mail: "foo@bar.com" + firstname: 'Foo', + lastname: 'Smith', + mail: 'foo@bar.com' } } expect(response).to redirect_to signin_path expect(flash[:error]).to eq(I18n.t(:error_omniauth_registration_timed_out)) - expect(User.find_by_login("foo@bar.com")).to be_nil + expect(User.find_by_login('foo@bar.com')).to be_nil end - it "does not register the user when providing all the missing fields" do + it 'does not register the user when providing all the missing fields' do post :register, params: { user: { - firstname: "Foo", + firstname: 'Foo', # lastname intentionally not provided - mail: "foo@bar.com" + mail: 'foo@bar.com' } } expect(response).to redirect_to signin_path expect(flash[:error]).to eq(I18n.t(:error_omniauth_registration_timed_out)) - expect(User.find_by_login("foo@bar.com")).to be_nil + expect(User.find_by_login('foo@bar.com')).to be_nil end end end - context "with self-registration disabled", + context 'with self-registration disabled', with_settings: { self_registration: Setting::SelfRegistration.disabled } do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", - uid: "123", - info: { name: "foo", - email: "foo@bar.com", - first_name: "foo", - last_name: "bar" } + provider: 'google', + uid: '123', + info: { name: 'foo', + email: 'foo@bar.com', + first_name: 'foo', + last_name: 'bar' } ) end before do - request.env["omniauth.origin"] = "https://example.net/some_back_url" + request.env['omniauth.origin'] = 'https://example.net/some_back_url' post :omniauth_login, params: { provider: :google } end - it "shows a notice about the activated account", :aggregate_failures do - expect(flash[:notice]).to eq(I18n.t("notice_account_registered_and_logged_in")) + it 'shows a notice about the activated account', :aggregate_failures do + expect(flash[:notice]).to eq(I18n.t('notice_account_registered_and_logged_in')) user = User.last - expect(user.firstname).to eq "foo" - expect(user.lastname).to eq "bar" - expect(user.mail).to eq "foo@bar.com" + expect(user.firstname).to eq 'foo' + expect(user.lastname).to eq 'bar' + expect(user.mail).to eq 'foo@bar.com' expect(user).to be_active end end end - describe "login" do + describe 'login' do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", - uid: "123545", - info: { name: "foo", - last_name: "bar", - email: "foo@bar.com" } + provider: 'google', + uid: '123545', + info: { name: 'foo', + last_name: 'bar', + email: 'foo@bar.com' } ) end let(:user) do build(:user, force_password_change: false, - identity_url: "google:123545") + identity_url: 'google:123545') end - context "with an active account" do + context 'with an active account' do before do user.save! end - it "signs in the user after successful external authentication" do + it 'signs in the user after successful external authentication' do post :omniauth_login, params: { provider: :google } expect(response).to redirect_to my_page_path end - it "logs a successful login" do + it 'logs a successful login' do post_at = Time.now.utc post :omniauth_login, params: { provider: :google } @@ -304,53 +304,53 @@ expect(user.last_login_on.utc.to_i).to be >= post_at.utc.to_i end - context "with a back_url present" do + context 'with a back_url present' do before do - request.env["omniauth.origin"] = "http://test.host/projects" + request.env['omniauth.origin'] = 'http://test.host/projects' post :omniauth_login, params: { provider: :google } end - it "redirects to that url", :aggregate_failures do - expect(response).to redirect_to "/projects" + it 'redirects to that url', :aggregate_failures do + expect(response).to redirect_to '/projects' end end - context "with a back_url from a login path" do + context 'with a back_url from a login path' do before do - request.env["omniauth.origin"] = "http://test.host/login" + request.env['omniauth.origin'] = 'http://test.host/login' post :omniauth_login, params: { provider: :google } end - it "redirects to that url", :aggregate_failures do - expect(response).to redirect_to "/my/page" + it 'redirects to that url', :aggregate_failures do + expect(response).to redirect_to '/my/page' end end - context "with a partially blank auth_hash" do + context 'with a partially blank auth_hash' do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", - uid: "123545", - info: { name: "foo", - first_name: "", - last_name: "newLastname", - email: "foo@bar.com" } + provider: 'google', + uid: '123545', + info: { name: 'foo', + first_name: '', + last_name: 'newLastname', + email: 'foo@bar.com' } ) end - it "signs in the user after successful external authentication" do + it 'signs in the user after successful external authentication' do expect { post :omniauth_login, params: { provider: :google } } .not_to change { user.reload.firstname } expect(response).to redirect_to my_page_path - expect(user.lastname).to eq "newLastname" + expect(user.lastname).to eq 'newLastname' end end - describe "authorization" do + describe 'authorization' do let(:config) do - Struct.new(:google_name, :global_email).new "foo", "foo@bar.com" + Struct.new(:google_name, :global_email).new 'foo', 'foo@bar.com' end before do @@ -377,7 +377,7 @@ # ineffective callback OpenProject::OmniAuth::Authorization.authorize_user provider: :foobar do |dec, _| - dec.reject "Though shalt not pass!" + dec.reject 'Though shalt not pass!' end # free for all callback @@ -390,7 +390,7 @@ OpenProject::OmniAuth::Authorization.callbacks.clear end - it "works" do + it 'works' do expect(OpenProject::OmniAuth::Authorization).to receive(:after_login!) do |u, auth| expect(u).to eq user expect(auth).to eq omniauth_hash @@ -401,55 +401,55 @@ expect(response).to redirect_to my_page_path end - context "with wrong email address" do + context 'with wrong email address' do before do - config.global_email = "other@mail.com" + config.global_email = 'other@mail.com' end - it "is rejected against google" do + it 'is rejected against google' do expect(OpenProject::OmniAuth::Authorization).not_to receive(:after_login!).with(user) post :omniauth_login, params: { provider: :google } expect(response).to redirect_to signin_path - expect(flash[:error]).to eq "I only want to see other@mail.com here." + expect(flash[:error]).to eq 'I only want to see other@mail.com here.' end - it "is rejected against any other provider too" do + it 'is rejected against any other provider too' do expect(OpenProject::OmniAuth::Authorization).not_to receive(:after_login!).with(user) - omniauth_hash.provider = "any other" + omniauth_hash.provider = 'any other' post :omniauth_login, params: { provider: :google } expect(response).to redirect_to signin_path - expect(flash[:error]).to eq "I only want to see other@mail.com here." + expect(flash[:error]).to eq 'I only want to see other@mail.com here.' end end - context "with the wrong name" do + context 'with the wrong name' do render_views before do - config.google_name = "hans" + config.google_name = 'hans' end - it "is rejected against google" do + it 'is rejected against google' do expect(OpenProject::OmniAuth::Authorization).not_to receive(:after_login!).with(user) post :omniauth_login, params: { provider: :google } expect(response).to redirect_to signin_path - expect(flash[:error]).to eq "Go away foo!" + expect(flash[:error]).to eq 'Go away foo!' end - it "is approved against any other provider" do + it 'is approved against any other provider' do expect(OpenProject::OmniAuth::Authorization).to receive(:after_login!) do |u| - new_user = User.find_by identity_url: "some other:123545" + new_user = User.find_by identity_url: 'some other:123545' expect(u).to eq new_user end - omniauth_hash.provider = "some other" + omniauth_hash.provider = 'some other' post :omniauth_login, params: { provider: :google } @@ -460,22 +460,22 @@ end # ... and to confirm that, here's what happens when the authorization fails - it "is rejected against any other provider with the wrong email" do + it 'is rejected against any other provider with the wrong email' do expect(OpenProject::OmniAuth::Authorization).not_to receive(:after_login!).with(user) - omniauth_hash.provider = "yet another" - config.global_email = "yarrrr@joro.es" + omniauth_hash.provider = 'yet another' + config.global_email = 'yarrrr@joro.es' post :omniauth_login, params: { provider: :google } expect(response).to redirect_to signin_path - expect(flash[:error]).to eq "I only want to see yarrrr@joro.es here." + expect(flash[:error]).to eq 'I only want to see yarrrr@joro.es here.' end end end end - context "with a registered and not activated accout", + context 'with a registered and not activated accout', with_settings: { self_registration: Setting::SelfRegistration.by_email } do before do user.register @@ -484,13 +484,13 @@ post :omniauth_login, params: { provider: :google } end - it "shows a notice about the activated account", :aggregate_failures do - expect(flash[:notice]).to eq(I18n.t("notice_account_registered_and_logged_in")) + it 'shows a notice about the activated account', :aggregate_failures do + expect(flash[:notice]).to eq(I18n.t('notice_account_registered_and_logged_in')) expect(user.reload).to be_active end end - context "with an invited user and self registration disabled", + context 'with an invited user and self registration disabled', with_settings: { self_registration: Setting::SelfRegistration.disabled } do before do user.invite @@ -499,13 +499,13 @@ post :omniauth_login, params: { provider: :google } end - it "shows a notice about the activated account", :aggregate_failures do - expect(flash[:notice]).to eq(I18n.t("notice_account_registered_and_logged_in")) + it 'shows a notice about the activated account', :aggregate_failures do + expect(flash[:notice]).to eq(I18n.t('notice_account_registered_and_logged_in')) expect(user.reload).to be_active end end - context "with a locked account", + context 'with a locked account', with_settings: { brute_force_block_after_failed_logins: 0 } do before do user.lock @@ -514,20 +514,20 @@ post :omniauth_login, params: { provider: :google } end - it "shows an error indicating a failed login", :aggregate_failures do + it 'shows an error indicating a failed login', :aggregate_failures do expect(flash[:error]).to eql(I18n.t(:notice_account_invalid_credentials)) expect(response).to redirect_to signin_path end end end - describe "with an invalid auth_hash" do + describe 'with an invalid auth_hash' do let(:omniauth_hash) do OmniAuth::AuthHash.new( - provider: "google", + provider: 'google', # id is deliberately missing here to make the auth_hash invalid - info: { name: "foo", - email: "foo@bar.com" } + info: { name: 'foo', + email: 'foo@bar.com' } ) end @@ -535,29 +535,29 @@ post :omniauth_login, params: { provider: :google } end - it "responds with an error" do - expect(flash[:error]).to include "The authentication information returned from the identity provider was invalid." + it 'responds with an error' do + expect(flash[:error]).to include 'The authentication information returned from the identity provider was invalid.' expect(response).to redirect_to signin_path end - it "does not sign in the user" do + it 'does not sign in the user' do expect(controller.send(:current_user).logged?).to be_falsey end - it "does not set registration information in the session" do + it 'does not set registration information in the session' do expect(session[:auth_source_registration]).to be_nil end end - describe "Error occurs during authentication" do - it "redirects to login page" do + describe 'Error occurs during authentication' do + it 'redirects to login page' do post :omniauth_failure expect(response).to redirect_to signin_path end - it "logs a warn message" do - expect(Rails.logger).to receive(:warn).with("invalid_credentials") - post :omniauth_failure, params: { message: "invalid_credentials" } + it 'logs a warn message' do + expect(Rails.logger).to receive(:warn).with('invalid_credentials') + post :omniauth_failure, params: { message: 'invalid_credentials' } end end end diff --git a/spec/controllers/concerns/user_invitation_spec.rb b/spec/controllers/concerns/user_invitation_spec.rb index a4bd7eaae779..6e9ea09f8fdc 100644 --- a/spec/controllers/concerns/user_invitation_spec.rb +++ b/spec/controllers/concerns/user_invitation_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UserInvitation do - describe ".reinvite_user" do + describe '.reinvite_user' do let(:user) { create(:invited_user) } let!(:token) { create(:invitation_token, user:) } - it "notifies listeners of the re-invite" do + it 'notifies listeners of the re-invite' do expect(OpenProject::Notifications).to receive(:send) do |event, _new_token| - expect(event).to eq "user_reinvited" + expect(event).to eq 'user_reinvited' end UserInvitation.reinvite_user user.id end - it "creates a new token" do + it 'creates a new token' do new_token = UserInvitation.reinvite_user user.id expect(new_token.value).not_to eq token.value diff --git a/spec/controllers/custom_actions_controller_spec.rb b/spec/controllers/custom_actions_controller_spec.rb index f13fd01a8202..0fc07f5376c3 100644 --- a/spec/controllers/custom_actions_controller_spec.rb +++ b/spec/controllers/custom_actions_controller_spec.rb @@ -26,63 +26,63 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomActionsController, with_ee: %i[custom_actions] do let(:admin) { build(:admin) } let(:non_admin) { build(:user) } let(:action) { build_stubbed(:custom_action) } let(:params) do - { custom_action: { name: "blubs", + { custom_action: { name: 'blubs', actions: { assigned_to: 1 } } } end - shared_examples_for "read requires enterprise token" do - context "without an enterprise token", with_ee: false do + shared_examples_for 'read requires enterprise token' do + context 'without an enterprise token', with_ee: false do before do login_as(admin) call end - it "renders enterprise_token" do + it 'renders enterprise_token' do expect(response) - .to render_template "common/upsale" + .to render_template 'common/upsale' end end end - shared_examples_for "write requires enterprise token" do - context "without an enterprise token", with_ee: false do + shared_examples_for 'write requires enterprise token' do + context 'without an enterprise token', with_ee: false do before do login_as(admin) call end - it "renders enterprise_token" do + it 'renders enterprise_token' do expect(response.response_code) .to be 403 end end end - shared_examples_for "403 for non admins" do - context "for non admins" do + shared_examples_for '403 for non admins' do + context 'for non admins' do before do login_as(non_admin) call end - it "returns 403" do + it 'returns 403' do expect(response.response_code) .to be 403 end end end - describe "#index" do + describe '#index' do let(:call) { get :index } before do @@ -91,37 +91,37 @@ .and_return([action]) end - context "for admins" do + context 'for admins' do before do login_as(admin) call end - it "returns 200" do + it 'returns 200' do expect(response.response_code) .to be 200 end - it "renders index template" do + it 'renders index template' do expect(response) - .to render_template("index") + .to render_template('index') end - it "assigns the custom actions" do + it 'assigns the custom actions' do expect(assigns(:custom_actions)) .to contain_exactly(action) end end - it_behaves_like "403 for non admins" - it_behaves_like "read requires enterprise token" + it_behaves_like '403 for non admins' + it_behaves_like 'read requires enterprise token' end - describe "#new" do + describe '#new' do let(:call) { get(:new) } - context "for admins" do + context 'for admins' do before do login_as(admin) @@ -132,27 +132,27 @@ call end - it "returns 200" do + it 'returns 200' do expect(response.response_code) .to be 200 end - it "renders new template" do + it 'renders new template' do expect(response) - .to render_template("new") + .to render_template('new') end - it "assigns custom_action" do + it 'assigns custom_action' do expect(assigns(:custom_action)) .to eql action end end - it_behaves_like "403 for non admins" - it_behaves_like "read requires enterprise token" + it_behaves_like '403 for non admins' + it_behaves_like 'read requires enterprise token' end - describe "#create" do + describe '#create' do let(:call) { post :create, params: } let(:current_user) { admin } let(:service_success) { true } @@ -164,7 +164,7 @@ .merge(ActionController::Parameters.new(actions: { assigned_to: "1" }).permit!) end let!(:service) do - service = double("create service") + service = double('create service') allow(CustomActions::CreateService) .to receive(:new) @@ -183,40 +183,40 @@ result: action) end - context "for admins" do + context 'for admins' do before do login_as(current_user) call end - context "on success" do - it "redirects to index" do + context 'on success' do + it 'redirects to index' do expect(response) .to redirect_to(custom_actions_path) end end - context "on failure" do + context 'on failure' do let(:service_success) { false } - it "renders new" do + it 'renders new' do expect(response) .to render_template(:new) end - it "assigns custom action" do + it 'assigns custom action' do expect(assigns[:custom_action]) .to eql action end end end - it_behaves_like "403 for non admins" - it_behaves_like "write requires enterprise token" + it_behaves_like '403 for non admins' + it_behaves_like 'write requires enterprise token' end - describe "#edit" do + describe '#edit' do let(:params) do { id: "42" } end @@ -231,30 +231,30 @@ .and_return(action) end - context "for admins" do + context 'for admins' do before do login_as(admin) call end - it "returns 200" do + it 'returns 200' do expect(response.response_code) .to be 200 end - it "renders edit template" do + it 'renders edit template' do expect(response) - .to render_template("edit") + .to render_template('edit') end - it "assigns custom_action" do + it 'assigns custom_action' do expect(assigns(:custom_action)) .to eql action end end - context "for admins on invalid id" do + context 'for admins on invalid id' do before do allow(CustomAction) .to receive(:find) @@ -266,17 +266,17 @@ call end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(response.response_code) .to be 404 end end - it_behaves_like "403 for non admins" - it_behaves_like "read requires enterprise token" + it_behaves_like '403 for non admins' + it_behaves_like 'read requires enterprise token' end - describe "#update" do + describe '#update' do let(:call) { patch :update, params: } let(:current_user) { admin } let(:service_success) { true } @@ -288,12 +288,12 @@ .merge(ActionController::Parameters.new(actions: { assigned_to: "1" }).permit!) end let(:params) do - { custom_action: { name: "blubs", + { custom_action: { name: 'blubs', actions: { assigned_to: 1 } }, id: "42" } end let!(:service) do - service = double("update service") + service = double('update service') allow(CustomActions::UpdateService) .to receive(:new) @@ -319,36 +319,36 @@ .and_return(action) end - context "for admins" do + context 'for admins' do before do login_as(current_user) call end - context "on success" do - it "redirects to index" do + context 'on success' do + it 'redirects to index' do expect(response) .to redirect_to(custom_actions_path) end end - context "on failure" do + context 'on failure' do let(:service_success) { false } - it "rerenders edit action" do + it 'rerenders edit action' do expect(response) .to render_template(:edit) end - it "assigns the action" do + it 'assigns the action' do expect(assigns[:custom_action]) .to eql(action) end end end - context "for admins on invalid id" do + context 'for admins on invalid id' do before do allow(CustomAction) .to receive(:find) @@ -360,17 +360,17 @@ call end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(response.response_code) .to be 404 end end - it_behaves_like "403 for non admins" - it_behaves_like "write requires enterprise token" + it_behaves_like '403 for non admins' + it_behaves_like 'write requires enterprise token' end - describe "#destroy" do + describe '#destroy' do let(:call) { delete :destroy, params: } let(:current_user) { admin } let(:params) do @@ -384,7 +384,7 @@ .and_return(action) end - context "for admins" do + context 'for admins' do before do expect(action) .to receive(:destroy) @@ -395,13 +395,13 @@ call end - it "redirects to index" do + it 'redirects to index' do expect(response) .to redirect_to(custom_actions_path) end end - context "for admins on invalid id" do + context 'for admins on invalid id' do before do allow(CustomAction) .to receive(:find) @@ -413,13 +413,13 @@ call end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(response.response_code) .to be 404 end end - it_behaves_like "403 for non admins" - it_behaves_like "write requires enterprise token" + it_behaves_like '403 for non admins' + it_behaves_like 'write requires enterprise token' end end diff --git a/spec/controllers/custom_fields_controller_spec.rb b/spec/controllers/custom_fields_controller_spec.rb index 793459ffb53e..a8705c01d000 100644 --- a/spec/controllers/custom_fields_controller_spec.rb +++ b/spec/controllers/custom_fields_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomFieldsController do shared_let(:admin) { create(:admin) } @@ -37,16 +37,16 @@ login_as admin end - describe "POST edit" do + describe 'POST edit' do before do allow(CustomField).to receive(:find).and_return(custom_field) allow(custom_field).to receive(:save).and_return(true) end - describe "WITH all ok params" do + describe 'WITH all ok params' do let(:params) do { - "custom_field" => { "name" => "Issue Field" } + 'custom_field' => { 'name' => 'Issue Field' } } end @@ -54,21 +54,21 @@ put :update, params: params.merge(id: custom_field.id) end - it "works" do + it 'works' do expect(response).to be_redirect - expect(custom_field.name).to eq("Issue Field") + expect(custom_field.name).to eq('Issue Field') end end end - describe "POST new" do - describe "WITH empty name param" do + describe 'POST new' do + describe 'WITH empty name param' do let(:params) do { - "type" => "WorkPackageCustomField", - "custom_field" => { - "name" => "", - "field_format" => "string" + 'type' => 'WorkPackageCustomField', + 'custom_field' => { + 'name' => '', + 'field_format' => 'string' } } end @@ -77,19 +77,19 @@ post :create, params: end - it "responds with error" do - expect(response).to render_template "new" + it 'responds with error' do + expect(response).to render_template 'new' expect(assigns(:custom_field).errors.messages[:name].first).to eq("can't be blank.") end end - describe "WITH all ok params" do + describe 'WITH all ok params' do let(:params) do { - "type" => "WorkPackageCustomField", - "custom_field" => { - "name" => "field", - "field_format" => "string" + 'type' => 'WorkPackageCustomField', + 'custom_field' => { + 'name' => 'field', + 'field_format' => 'string' } } end @@ -98,9 +98,9 @@ post :create, params: end - it "responds ok" do + it 'responds ok' do expect(response).to be_redirect - expect(CustomField.last.name).to eq "field" + expect(CustomField.last.name).to eq 'field' end end end diff --git a/spec/controllers/custom_styles_controller_spec.rb b/spec/controllers/custom_styles_controller_spec.rb index 3577715bc3e7..fec0579a1b89 100644 --- a/spec/controllers/custom_styles_controller_spec.rb +++ b/spec/controllers/custom_styles_controller_spec.rb @@ -26,32 +26,32 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomStylesController do before do login_as user end - context "with admin" do + context 'with admin' do let(:user) { build(:admin) } - describe "#show" do + describe '#show' do subject { get :show } - context "when active token exists", with_ee: %i[define_custom_style] do - it "renders show" do + context 'when active token exists', with_ee: %i[define_custom_style] do + it 'renders show' do expect(subject).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' end end - context "when no active token exists" do + context 'when no active token exists' do before do allow(EnterpriseToken).to receive(:current).and_return(nil) end - it "redirects to #upsale" do + it 'redirects to #upsale' do expect(subject).to redirect_to action: :upsale end end @@ -60,9 +60,9 @@ describe "#upsale" do subject { get :upsale } - it "renders upsale" do + it 'renders upsale' do expect(subject).to be_successful - expect(subject).to render_template "upsale" + expect(subject).to render_template 'upsale' end end @@ -70,7 +70,7 @@ let(:custom_style) { CustomStyle.new } let(:params) do { - custom_style: { logo: "foo", favicon: "bar", icon_touch: "yay" } + custom_style: { logo: 'foo', favicon: 'bar', icon_touch: 'yay' } } end @@ -81,20 +81,20 @@ post :create, params: end - context "with valid custom_style input" do + context 'with valid custom_style input' do let(:valid) { true } - it "redirects to show" do + it 'redirects to show' do expect(response).to redirect_to action: :show end end - context "with invalid custom_style input" do + context 'with invalid custom_style input' do let(:valid) { false } - it "renders with error" do + it 'renders with error' do expect(response).not_to be_redirect - expect(response).to render_template "custom_styles/show" + expect(response).to render_template 'custom_styles/show' end end end @@ -103,11 +103,11 @@ let(:custom_style) { build(:custom_style_with_logo) } let(:params) do { - custom_style: { logo: "foo", favicon: "bar", icon_touch: "yay" } + custom_style: { logo: 'foo', favicon: 'bar', icon_touch: 'yay' } } end - context "with an existing CustomStyle" do + context 'with an existing CustomStyle' do before do allow(CustomStyle).to receive(:current).and_return(custom_style) allow(custom_style).to receive(:update).and_return(valid) @@ -115,25 +115,25 @@ post :update, params: end - context "with valid custom_style input" do + context 'with valid custom_style input' do let(:valid) { true } - it "redirects to show" do + it 'redirects to show' do expect(response).to redirect_to action: :show end end - context "with invalid custom_style input" do + context 'with invalid custom_style input' do let(:valid) { false } - it "renders with error" do + it 'renders with error' do expect(response).not_to be_redirect - expect(response).to render_template "custom_styles/show" + expect(response).to render_template 'custom_styles/show' end end end - context "without an existing CustomStyle" do + context 'without an existing CustomStyle' do before do allow(CustomStyle).to receive(:create!).and_return(custom_style) allow(custom_style).to receive(:update).and_return(valid) @@ -141,20 +141,20 @@ post :update, params: end - context "with valid custom_style input" do + context 'with valid custom_style input' do let(:valid) { true } - it "redirects to show" do + it 'redirects to show' do expect(response).to redirect_to action: :show end end - context "with invalid custom_style input" do + context 'with invalid custom_style input' do let(:valid) { false } - it "renders with error" do + it 'renders with error' do expect(response).not_to be_redirect - expect(response).to render_template "custom_styles/show" + expect(response).to render_template 'custom_styles/show' end end end @@ -170,7 +170,7 @@ context "when logo is present" do let(:custom_style) { build(:custom_style_with_logo) } - it "sends a file" do + it 'sends a file' do expect(response).to have_http_status(:ok) end end @@ -178,7 +178,7 @@ context "when no custom style is present" do let(:custom_style) { nil } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -187,7 +187,7 @@ context "when no logo is present" do let(:custom_style) { build_stubbed(:custom_style) } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -197,25 +197,25 @@ describe "#logo_delete", with_ee: %i[define_custom_style] do let(:custom_style) { create(:custom_style_with_logo) } - context "if it exists" do + context 'if it exists' do before do allow(CustomStyle).to receive(:current).and_return(custom_style) allow(custom_style).to receive(:remove_logo).and_call_original delete :logo_delete end - it "removes the logo from custom_style" do + it 'removes the logo from custom_style' do expect(response).to redirect_to action: :show end end - context "if it does not exist" do + context 'if it does not exist' do before do allow(CustomStyle).to receive(:current).and_return(nil) delete :logo_delete end - it "renders 404" do + it 'renders 404' do expect(response).to have_http_status :not_found end end @@ -231,7 +231,7 @@ context "when export logo is present" do let(:custom_style) { build(:custom_style_with_export_logo) } - it "sends a file" do + it 'sends a file' do expect(response).to have_http_status(:ok) end end @@ -239,7 +239,7 @@ context "when no custom style is present" do let(:custom_style) { nil } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -248,7 +248,7 @@ context "when no export logo is present" do let(:custom_style) { build_stubbed(:custom_style) } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -258,25 +258,25 @@ describe "#export_logo_delete", with_ee: %i[define_custom_style] do let(:custom_style) { create(:custom_style_with_export_logo) } - context "if it exists" do + context 'if it exists' do before do allow(CustomStyle).to receive(:current).and_return(custom_style) allow(custom_style).to receive(:remove_export_logo).and_call_original delete :export_logo_delete end - it "removes the export logo from custom_style" do + it 'removes the export logo from custom_style' do expect(response).to redirect_to action: :show end end - context "if it does not exist" do + context 'if it does not exist' do before do allow(CustomStyle).to receive(:current).and_return(nil) delete :export_logo_delete end - it "renders 404" do + it 'renders 404' do expect(response).to have_http_status :not_found end end @@ -292,7 +292,7 @@ context "when export cover is present" do let(:custom_style) { build(:custom_style_with_export_cover) } - it "sends a file" do + it 'sends a file' do expect(response).to have_http_status(:ok) end end @@ -300,7 +300,7 @@ context "when no custom style is present" do let(:custom_style) { nil } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -309,7 +309,7 @@ context "when no export cover is present" do let(:custom_style) { build_stubbed(:custom_style) } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -319,25 +319,25 @@ describe "#export_cover_delete", with_ee: %i[define_custom_style] do let(:custom_style) { create(:custom_style_with_export_cover) } - context "if it exists" do + context 'if it exists' do before do allow(CustomStyle).to receive(:current).and_return(custom_style) allow(custom_style).to receive(:remove_cover).and_call_original delete :export_cover_delete end - it "removes the export cover from custom_style" do + it 'removes the export cover from custom_style' do expect(response).to redirect_to action: :show end end - context "if it does not exist" do + context 'if it does not exist' do before do allow(CustomStyle).to receive(:current).and_return(nil) delete :export_cover_delete end - it "renders 404" do + it 'renders 404' do expect(response).to have_http_status :not_found end end @@ -353,7 +353,7 @@ context "when favicon is present" do let(:custom_style) { build(:custom_style_with_favicon) } - it "sends a file" do + it 'sends a file' do expect(response).to have_http_status(:ok) end end @@ -361,7 +361,7 @@ context "when no custom style is present" do let(:custom_style) { nil } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -370,7 +370,7 @@ context "when no favicon is present" do let(:custom_style) { build(:custom_style) } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -380,25 +380,25 @@ describe "#favicon_delete", with_ee: %i[define_custom_style] do let(:custom_style) { create(:custom_style_with_favicon) } - context "if it exists" do + context 'if it exists' do before do allow(CustomStyle).to receive(:current).and_return(custom_style) allow(custom_style).to receive(:remove_favicon).and_call_original delete :favicon_delete end - it "removes the favicon from custom_style" do + it 'removes the favicon from custom_style' do expect(response).to redirect_to action: :show end end - context "if it does not exist" do + context 'if it does not exist' do before do allow(CustomStyle).to receive(:current).and_return(nil) delete :favicon_delete end - it "renders 404" do + it 'renders 404' do expect(response).to have_http_status :not_found end end @@ -414,7 +414,7 @@ context "when touch icon is present" do let(:custom_style) { build(:custom_style_with_touch_icon) } - it "sends a file" do + it 'sends a file' do expect(response).to have_http_status(:ok) end end @@ -422,7 +422,7 @@ context "when no custom style is present" do let(:custom_style) { nil } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -431,7 +431,7 @@ context "when no touch icon is present" do let(:custom_style) { build(:custom_style) } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end @@ -441,25 +441,25 @@ describe "#touch_icon_delete", with_ee: %i[define_custom_style] do let(:custom_style) { create(:custom_style_with_touch_icon) } - context "if it exists" do + context 'if it exists' do before do allow(CustomStyle).to receive(:current).and_return(custom_style) allow(custom_style).to receive(:remove_touch_icon).and_call_original delete :touch_icon_delete end - it "removes the touch icon from custom_style" do + it 'removes the touch icon from custom_style' do expect(response).to redirect_to action: :show end end - context "if it does not exist" do + context 'if it does not exist' do before do allow(CustomStyle).to receive(:current).and_return(nil) delete :touch_icon_delete end - it "renders 404" do + it 'renders 404' do expect(response).to have_http_status :not_found end end @@ -470,7 +470,7 @@ { export_cover_text_color: "#990000" } end - context "if CustomStyle exists" do + context 'if CustomStyle exists' do let(:custom_style) { CustomStyle.new } before do @@ -478,7 +478,7 @@ allow(custom_style).to receive(:export_cover_text_color).and_call_original end - context "with valid parameter" do + context 'with valid parameter' do before do post :update_export_cover_text_color, params: end @@ -489,9 +489,9 @@ end end - context "with valid empty parameter" do + context 'with valid empty parameter' do let(:params) do - { export_cover_text_color: "" } + { export_cover_text_color: '' } end before do @@ -506,7 +506,7 @@ end end - context "with invalid parameter" do + context 'with invalid parameter' do let(:params) do { export_cover_text_color: "red" } # we only accept hexcodes end @@ -522,13 +522,13 @@ end end - context "if CustomStyle does not exist" do + context 'if CustomStyle does not exist' do before do allow(CustomStyle).to receive(:current).and_return(nil) post :update_export_cover_text_color, params: end - it "is created" do + it 'is created' do expect(response).to redirect_to action: :show end end @@ -537,7 +537,7 @@ describe "#update_colors", with_ee: %i[define_custom_style] do let(:params) do { - design_colors: [{ "primary-button-color" => "#990000" }] + design_colors: [{ "primary-color" => "#990000" }] } end @@ -553,7 +553,7 @@ end it "updates DesignColor instances" do - post :update_colors, params: { design_colors: [{ "primary-button-color" => "#110000" }] } + post :update_colors, params: { design_colors: [{ "primary-color" => "#110000" }] } design_colors = DesignColor.all expect(design_colors.size).to eq(1) expect(design_colors.first.hexcode).to eq("#110000") @@ -562,28 +562,28 @@ it "deletes DesignColor instances for each param" do expect(DesignColor.count).to eq(1) - post :update_colors, params: { design_colors: [{ "primary-button-color" => "" }] } + post :update_colors, params: { design_colors: [{ "primary-color" => "" }] } expect(DesignColor.count).to eq(0) expect(response).to redirect_to action: :show end end end - context "for a regular user" do + context 'for a regular user' do let(:user) { build(:user) } - describe "#get" do + describe '#get' do before do get :show end - it "requires admin" do + it 'requires admin' do expect(response).to have_http_status :forbidden end end end - context "for an anonymous user" do + context 'for an anonymous user' do let(:user) { User.anonymous } describe "#logo_download" do @@ -596,7 +596,7 @@ context "when logo is present" do let(:custom_style) { build(:custom_style_with_logo) } - it "sends a file" do + it 'sends a file' do expect(response).to have_http_status(:ok) end end @@ -604,7 +604,7 @@ context "when no logo is present" do let(:custom_style) { nil } - it "renders with error" do + it 'renders with error' do expect(controller).not_to have_received(:send_file) expect(response).to have_http_status(:not_found) end diff --git a/spec/controllers/enterprises_controller_spec.rb b/spec/controllers/enterprises_controller_spec.rb index d836668e2c83..9abf16a2bed7 100644 --- a/spec/controllers/enterprises_controller_spec.rb +++ b/spec/controllers/enterprises_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe EnterprisesController do let(:a_token) { EnterpriseToken.new } @@ -49,46 +49,46 @@ allow(a_token).to receive(:token_object).and_return(token_object) end - context "with admin" do + context 'with admin' do let(:user) { build(:admin) } - describe "#show" do + describe '#show' do render_views - context "when token exists" do + context 'when token exists' do before do allow(EnterpriseToken).to receive(:current).and_return(a_token) get :show end - shared_examples "it renders the EE overview" do - it "renders the overview" do + shared_examples 'it renders the EE overview' do + it 'renders the overview' do expect(response).to be_successful - expect(response).to render_template "show" - expect(response).to render_template partial: "enterprises/_current" - expect(response).to render_template partial: "enterprises/_form" + expect(response).to render_template 'show' + expect(response).to render_template partial: 'enterprises/_current' + expect(response).to render_template partial: 'enterprises/_form' end end - it_behaves_like "it renders the EE overview" + it_behaves_like 'it renders the EE overview' - context "with version >= 2.0" do + context 'with version >= 2.0' do let(:token_attributes) { super().merge version: "2.0" } - context "with correct domain", with_settings: { host_name: "community.openproject.com" } do - let(:token_attributes) { super().merge domain: "community.openproject.com" } + context 'with correct domain', with_settings: { host_name: 'community.openproject.com' } do + let(:token_attributes) { super().merge domain: 'community.openproject.com' } - it_behaves_like "it renders the EE overview" + it_behaves_like 'it renders the EE overview' it "doesn't show any warnings or errors" do expect(controller).not_to set_flash.now end end - context "with wrong domain", with_settings: { host_name: "community.openproject.com" } do - let(:token_attributes) { super().merge domain: "localhost" } + context 'with wrong domain', with_settings: { host_name: 'community.openproject.com' } do + let(:token_attributes) { super().merge domain: 'localhost' } - it_behaves_like "it renders the EE overview" + it_behaves_like 'it renders the EE overview' it "shows an invalid domain error" do expect(controller).to set_flash.now[:error].to(/.*localhost.*does not match.*community.openproject.com/) @@ -96,13 +96,13 @@ end end - context "with version < 2.0" do + context 'with version < 2.0' do let(:token_attributes) { super().merge version: "1.0.3" } - context "with wrong domain", with_settings: { host_name: "community.openproject.com" } do - let(:token_attributes) { super().merge domain: "localhost" } + context 'with wrong domain', with_settings: { host_name: 'community.openproject.com' } do + let(:token_attributes) { super().merge domain: 'localhost' } - it_behaves_like "it renders the EE overview" + it_behaves_like 'it renders the EE overview' it "doesn't show any warnings or errors" do expect(controller).not_to set_flash.now @@ -111,56 +111,56 @@ end end - context "when no token exists" do + context 'when no token exists' do before do allow(EnterpriseToken).to receive(:current).and_return(nil) get :show end - it "still renders #show with form" do - expect(response).not_to render_template partial: "enterprises/_current" - expect(response.body).to have_css ".upsale-benefits" + it 'still renders #show with form' do + expect(response).not_to render_template partial: 'enterprises/_current' + expect(response.body).to have_css '.upsale-benefits' end end end - describe "#create" do + describe '#create' do let(:params) do { - enterprise_token: { encoded_token: "foo" } + enterprise_token: { encoded_token: 'foo' } } end before do allow(EnterpriseToken).to receive(:current).and_return(nil) allow(EnterpriseToken).to receive(:new).and_return(a_token) - expect(a_token).to receive(:encoded_token=).with("foo") + expect(a_token).to receive(:encoded_token=).with('foo') expect(a_token).to receive(:save).and_return(valid) post :create, params: end - context "valid token input" do + context 'valid token input' do let(:valid) { true } - it "redirects to index" do + it 'redirects to index' do expect(controller).to set_flash[:notice].to I18n.t(:notice_successful_update) expect(response).to redirect_to action: :show end end - context "invalid token input" do + context 'invalid token input' do let(:valid) { false } - it "renders with error" do + it 'renders with error' do expect(response).not_to be_redirect - expect(response).to render_template "enterprises/show" + expect(response).to render_template 'enterprises/show' end end end - describe "#destroy" do - context "when a token exists" do + describe '#destroy' do + context 'when a token exists' do before do expect(EnterpriseToken).to receive(:current).and_return(a_token) expect(a_token).to receive(:destroy) @@ -168,33 +168,33 @@ delete :destroy end - it "redirects to show" do + it 'redirects to show' do expect(controller).to set_flash[:notice].to I18n.t(:notice_successful_delete) expect(response).to redirect_to action: :show end end - context "when no token exists" do + context 'when no token exists' do before do expect(EnterpriseToken).to receive(:current).and_return(nil) delete :destroy end - it "renders 404" do + it 'renders 404' do expect(response.status).to eq(404) end end end end - context "regular user" do + context 'regular user' do let(:user) { build(:user) } before do get :show end - it "is forbidden" do + it 'is forbidden' do expect(response.status).to eq 403 end end diff --git a/spec/controllers/enumerations_controller_spec.rb b/spec/controllers/enumerations_controller_spec.rb index 4a9c187c22a7..27a5b80b1e5d 100644 --- a/spec/controllers/enumerations_controller_spec.rb +++ b/spec/controllers/enumerations_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe EnumerationsController do shared_let(:admin) { create(:admin) } @@ -35,23 +35,23 @@ admin end - describe "#index" do + describe '#index' do before do get :index end - it "is successful" do + it 'is successful' do expect(response) .to have_http_status(:ok) end - it "renders the index template" do + it 'renders the index template' do expect(response) - .to render_template "index" + .to render_template 'index' end end - describe "#destroy" do + describe '#destroy' do let(:enum) { create(:priority) } let(:params) { { id: enum.id } } let(:work_packages) { [] } @@ -62,46 +62,46 @@ delete :destroy, params: end - it "redirects" do + it 'redirects' do expect(response) .to redirect_to enumerations_path end - it "destroys the enum" do + it 'destroys the enum' do expect(Enumeration.where(id: enum.id)) .not_to exist end - context "when in use" do + context 'when in use' do let(:work_packages) { [create(:work_package, priority: enum)] } - it "keeps the enum (as it needs to be reassigned)" do + it 'keeps the enum (as it needs to be reassigned)' do expect(Enumeration.where(id: enum.id)) .to exist end - it "keeps the usage" do + it 'keeps the usage' do expect(work_packages.first.reload.priority) .to eql enum end - it "renders destroy template" do + it 'renders destroy template' do expect(response) .to render_template :destroy end end - context "when in use and reassigning" do + context 'when in use and reassigning' do let(:work_packages) { [create(:work_package, priority: enum)] } let!(:other_enum) { create(:priority) } let(:params) { { id: enum.id, reassign_to_id: other_enum.id } } - it "destroys the enum" do + it 'destroys the enum' do expect(Enumeration.where(id: enum.id)) .not_to exist end - it "reassigns the usage" do + it 'reassigns the usage' do expect(work_packages.first.reload.priority) .to eql other_enum end diff --git a/spec/controllers/forums_controller_spec.rb b/spec/controllers/forums_controller_spec.rb index b2df0e6b6847..ee6ffff79be9 100644 --- a/spec/controllers/forums_controller_spec.rb +++ b/spec/controllers/forums_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ForumsController do shared_let(:user) { create(:user) } @@ -37,25 +37,25 @@ disable_flash_sweep end - describe "#index" do - context "public project" do + describe '#index' do + context 'public project' do let(:project) { create(:public_project) } let!(:role) { create(:non_member) } - it "renders the index template" do + it 'renders the index template' do as_logged_in_user(user) do get :index, params: { project_id: project.id } end expect(response).to be_successful - expect(response).to render_template "forums/index" + expect(response).to render_template 'forums/index' expect(assigns(:forums)).to be_present expect(assigns(:project)).to be_present end end - context "assuming authorized" do - it "renders the index template" do + context 'assuming authorized' do + it 'renders the index template' do as_logged_in_user(user) do allow(@controller).to receive(:authorize).and_return(true) get :index, params: { project_id: project.id } @@ -64,22 +64,22 @@ end end - context "when login_required", with_settings: { login_required: true } do - it "redirects to login" do - get :index, params: { project_id: "not found" } - expect(response).to redirect_to signin_path(back_url: project_forums_url("not found")) + context 'when login_required', with_settings: { login_required: true } do + it 'redirects to login' do + get :index, params: { project_id: 'not found' } + expect(response).to redirect_to signin_path(back_url: project_forums_url('not found')) end end - context "when not login_required", with_settings: { login_required: false } do - it "renders 404 for not found" do - get :index, params: { project_id: "not found" } + context 'when not login_required', with_settings: { login_required: false } do + it 'renders 404 for not found' do + get :index, params: { project_id: 'not found' } expect(response.status).to eq 404 end end end - describe "#show" do + describe '#show' do before do allow(project).to receive_message_chain(:forums, :find).and_return(forum) allow(@controller).to receive(:authorize) @@ -88,25 +88,25 @@ end end - context "when login_required", with_settings: { login_required: true } do - it "redirects to login" do + context 'when login_required', with_settings: { login_required: true } do + it 'redirects to login' do get :show, params: { project_id: project.id, id: 1 } expect(response).to redirect_to signin_path(back_url: project_forum_url(project.id, 1)) end end - context "when not login_required", with_settings: { login_required: false } do - it "renders the show template" do + context 'when not login_required', with_settings: { login_required: false } do + it 'renders the show template' do get :show, params: { project_id: project.id, id: 1 } expect(response).to be_successful - expect(response).to render_template "forums/show" + expect(response).to render_template 'forums/show' end end end - describe "#create" do + describe '#create' do let(:params) { { project_id: project.id, forum: forum_params } } - let(:forum_params) { { name: "my forum", description: "awesome forum" } } + let(:forum_params) { { name: 'my forum', description: 'awesome forum' } } before do expect(@controller).to receive(:authorize) @@ -121,7 +121,7 @@ .and_return(forum) end - describe "w/ the params being valid" do + describe 'w/ the params being valid' do before do expect(forum).to receive(:save).and_return(true) @@ -130,19 +130,19 @@ end end - it "redirects to the index page if successful" do + it 'redirects to the index page if successful' do expect(response) - .to redirect_to controller: "/forums", - action: "index", + .to redirect_to controller: '/forums', + action: 'index', project_id: project.id end - it "have a successful creation flash" do + it 'have a successful creation flash' do expect(flash[:notice]).to eq(I18n.t(:notice_successful_create)) end end - describe "w/ the params being invalid" do + describe 'w/ the params being invalid' do before do expect(forum).to receive(:save).and_return(false) @@ -151,14 +151,14 @@ end end - it "renders the new template" do - expect(response).to render_template("new") + it 'renders the new template' do + expect(response).to render_template('new') end end end - describe "#destroy", with_settings: { login_required: false } do - let(:forum_params) { { name: "my forum", description: "awesome forum" } } + describe '#destroy', with_settings: { login_required: false } do + let(:forum_params) { { name: 'my forum', description: 'awesome forum' } } before do expect(@controller).to receive(:authorize) @@ -168,14 +168,14 @@ end end - it "requests destruction and redirect" do + it 'requests destruction and redirect' do expect(forum).to receive(:destroy) delete :destroy, params: { project_id: project.id, id: 1 } expect(response).to be_redirect end end - describe "#move" do + describe '#move' do let(:project) { create(:project) } let!(:forum_1) do create(:forum, @@ -192,11 +192,11 @@ allow(@controller).to receive(:authorize).and_return(true) end - describe "#higher", with_settings: { login_required: false } do - let(:move_to) { "higher" } + describe '#higher', with_settings: { login_required: false } do + let(:move_to) { 'higher' } before do - post "move", params: { id: forum_2.id, + post 'move', params: { id: forum_2.id, project_id: forum_2.project_id, forum: { move_to: } } end @@ -211,124 +211,124 @@ it do expect(response) - .to redirect_to controller: "/forums", - action: "index", + .to redirect_to controller: '/forums', + action: 'index', project_id: project.id end end end - describe "#update" do + describe '#update' do let!(:forum) do - create(:forum, name: "Forum name", - description: "Forum description") + create(:forum, name: 'Forum name', + description: 'Forum description') end before do expect(@controller).to receive(:authorize) end - describe "w/ the params being valid" do + describe 'w/ the params being valid' do before do as_logged_in_user user do put :update, params: { id: forum.id, project_id: forum.project_id, - forum: { name: "New name", description: "New description" } } + forum: { name: 'New name', description: 'New description' } } end end - it "redirects to the index page if successful" do - expect(response).to redirect_to controller: "/forums", - action: "index", + it 'redirects to the index page if successful' do + expect(response).to redirect_to controller: '/forums', + action: 'index', project_id: forum.project_id end - it "have a successful update flash" do + it 'have a successful update flash' do expect(flash[:notice]).to eq(I18n.t(:notice_successful_update)) end - it "changes the database entry" do + it 'changes the database entry' do forum.reload - expect(forum.name).to eq("New name") - expect(forum.description).to eq("New description") + expect(forum.name).to eq('New name') + expect(forum.description).to eq('New description') end end - describe "w/ the params being invalid" do + describe 'w/ the params being invalid' do before do as_logged_in_user user do post :update, params: { id: forum.id, project_id: forum.project_id, - forum: { name: "", description: "New description" } } + forum: { name: '', description: 'New description' } } end end - it "renders the edit template" do - expect(response).to render_template("edit") + it 'renders the edit template' do + expect(response).to render_template('edit') end - it "does not change the database entry" do + it 'does not change the database entry' do forum.reload - expect(forum.name).to eq("Forum name") - expect(forum.description).to eq("Forum description") + expect(forum.name).to eq('Forum name') + expect(forum.description).to eq('Forum description') end end end - describe "#sticky", with_settings: { login_required: false } do + describe '#sticky', with_settings: { login_required: false } do let!(:message1) { create(:message, forum:) } let!(:message2) { create(:message, forum:) } let!(:sticked_message1) do create(:message, forum_id: forum.id, - subject: "How to", - content: "How to install this cool app", - sticky: "1", + subject: 'How to', + content: 'How to install this cool app', + sticky: '1', sticked_on: Time.now - 2.minutes) end let!(:sticked_message2) do create(:message, forum_id: forum.id, - subject: "FAQ", - content: "Frequestly asked question", - sticky: "1", + subject: 'FAQ', + content: 'Frequestly asked question', + sticky: '1', sticked_on: Time.now - 1.minute) end - describe "all sticky messages" do + describe 'all sticky messages' do before do expect(@controller).to receive(:authorize) get :show, params: { project_id: project.id, id: forum.id } end - it "renders show" do - expect(response).to render_template "show" + it 'renders show' do + expect(response).to render_template 'show' end - it "is displayed on top" do + it 'is displayed on top' do expect(assigns[:topics][0].id).to eq(sticked_message1.id) end end - describe "edit a sticky message" do + describe 'edit a sticky message' do before do sticked_message1.sticky = 0 sticked_message1.save! end - describe "when sticky is unset from message" do + describe 'when sticky is unset from message' do before do expect(@controller).to receive(:authorize) get :show, params: { project_id: project.id, id: forum.id } end - it "is not displayed as sticky message" do + it 'is not displayed as sticky message' do expect(sticked_message1.sticked_on).to be_nil expect(assigns[:topics][0].id).not_to eq(sticked_message1.id) end end - describe "when sticky is set back to message" do + describe 'when sticky is set back to message' do before do sticked_message1.sticky = 1 sticked_message1.save! @@ -337,7 +337,7 @@ get :show, params: { project_id: project.id, id: forum.id } end - it "is not displayed on first position" do + it 'is not displayed on first position' do expect(assigns[:topics][0].id).to eq(sticked_message2.id) end end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 12857c576280..711800383679 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe GroupsController do let(:group) { create(:group, members: group_members) } @@ -35,51 +35,51 @@ login_as current_user end - context "as admin" do + context 'as admin' do shared_let(:admin) { create(:admin) } let(:current_user) { admin } - it "indexes" do + it 'indexes' do get :index expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' end - it "shows" do + it 'shows' do get :show, params: { id: group.id } expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' end - it "shows new" do + it 'shows new' do get :new expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end - it "creates" do + it 'creates' do expect do - post :create, params: { group: { lastname: "New group" } } + post :create, params: { group: { lastname: 'New group' } } end.to change(Group, :count).by(1) expect(response).to redirect_to groups_path end - it "edits" do + it 'edits' do get :edit, params: { id: group.id } expect(response).to be_successful - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end - it "updates" do + it 'updates' do expect do - put :update, params: { id: group.id, group: { lastname: "new name" } } - end.to change { group.reload.name }.to("new name") + put :update, params: { id: group.id, group: { lastname: 'new name' } } + end.to change { group.reload.name }.to('new name') expect(response).to redirect_to groups_path end - it "destroys" do + it 'destroys' do perform_enqueued_jobs do delete :destroy, params: { id: group.id } end @@ -89,28 +89,28 @@ expect(response).to redirect_to groups_path end - context "with two existing users" do + context 'with two existing users' do let(:user1) { create(:user) } let(:user2) { create(:user) } - it "adds users" do + it 'adds users' do post :add_users, params: { id: group.id, user_ids: [user1.id, user2.id] } expect(group.reload.users.count).to eq 2 end end - context "with a group member" do + context 'with a group member' do let(:user1) { create(:user) } let(:user2) { create(:user) } let(:group_members) { [user1] } - it "adds users" do + it 'adds users' do post :add_users, params: { id: group.id, user_ids: [user2.id] } expect(group.reload.users.count).to eq 2 end end - context "with a global role membership" do + context 'with a global role membership' do render_views let!(:member_group) do @@ -119,20 +119,20 @@ roles: [create(:global_role)]) end - it "displays edit memberships" do - get :edit, params: { id: group.id, tab: "memberships" } + it 'displays edit memberships' do + get :edit, params: { id: group.id, tab: 'memberships' } expect(response).to be_successful - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end end - context "with project and role" do + context 'with project and role' do let(:project) { create(:project) } let(:role1) { create(:project_role) } let(:role2) { create(:project_role) } - it "creates membership" do + it 'creates membership' do post :create_memberships, params: { id: group.id, membership: { project_id: project.id, role_ids: [role1.id, role2.id] } } @@ -140,7 +140,7 @@ expect(group.members.first.roles.count).to eq 2 end - context "with an existing membership" do + context 'with an existing membership' do let!(:member_group) do create(:member, project:, @@ -148,7 +148,7 @@ roles: [role1]) end - it "edits a membership" do + it 'edits a membership' do expect(group.members.count).to eq 1 expect(group.members.first.roles.count).to eq 1 @@ -164,7 +164,7 @@ expect(group.members.first.roles.count).to eq 2 end - it "can destroy the membership" do + it 'can destroy the membership' do delete :destroy_membership, params: { id: group.id, membership_id: group.members.first.id } expect(group.reload.members.count).to eq 0 end @@ -172,38 +172,38 @@ end end - context "as regular user" do + context 'as regular user' do let(:user) { create(:user) } let(:current_user) { user } - it "forbids index" do + it 'forbids index' do get :index expect(response).not_to be_successful expect(response.status).to eq 403 end - it "shows" do + it 'shows' do get :show, params: { id: group.id } expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' end - it "forbids new" do + it 'forbids new' do get :new expect(response).not_to be_successful expect(response.status).to eq 403 end - it "forbids create" do + it 'forbids create' do expect do - post :create, params: { group: { lastname: "New group" } } + post :create, params: { group: { lastname: 'New group' } } end.not_to(change(Group, :count)) expect(response).not_to be_successful expect(response.status).to eq 403 end - it "forbids edit" do + it 'forbids edit' do get :edit, params: { id: group.id } expect(response).not_to be_successful diff --git a/spec/controllers/homescreen_controller_spec.rb b/spec/controllers/homescreen_controller_spec.rb index 2d1b8eabfad0..10486c02a9f3 100644 --- a/spec/controllers/homescreen_controller_spec.rb +++ b/spec/controllers/homescreen_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe HomescreenController do before do @@ -44,91 +44,91 @@ let(:show_welcome) { false } - shared_examples "renders blocks" do - it "renders a response" do + shared_examples 'renders blocks' do + it 'renders a response' do expect(response.status).to eq(200) end - describe "with rendered views" do + describe 'with rendered views' do render_views - it "renders the given blocks" do + it 'renders the given blocks' do shown.each do |block| expect(response).to render_template(partial: "homescreen/blocks/_#{block}") end end - it "does not render the other blocks" do + it 'does not render the other blocks' do (all_blocks - shown).each do |block| expect(response).not_to render_template(partial: "homescreen/blocks/_#{block}") end end - it "does not render news when empty" do - expect(response).not_to render_template(partial: "homescreen/blocks/_news") + it 'does not render news when empty' do + expect(response).not_to render_template(partial: 'homescreen/blocks/_news') end - it "shows the news when available" do + it 'shows the news when available' do expect(News).to receive(:latest).with(any_args) .and_return(build_stubbed_list(:news, 5, created_at: Time.now)) get :index - expect(response).to render_template(partial: "homescreen/blocks/_news") + expect(response).to render_template(partial: 'homescreen/blocks/_news') end - it "does not render the welcome block" do - expect(response).not_to render_template(partial: "homescreen/blocks/_welcome") + it 'does not render the welcome block' do + expect(response).not_to render_template(partial: 'homescreen/blocks/_welcome') end - context "with enabled announcement" do + context 'with enabled announcement' do let!(:announcement) { create(:active_announcement) } - it "renders the announcement" do - expect(response).to render_template(partial: "announcements/_show") + it 'renders the announcement' do + expect(response).to render_template(partial: 'announcements/_show') end end - context "with enabled welcome block" do + context 'with enabled welcome block' do before do - allow(Setting).to receive(:welcome_text).and_return("h1. foobar") - allow(Setting).to receive(:welcome_title).and_return("Woohoo!") + allow(Setting).to receive(:welcome_text).and_return('h1. foobar') + allow(Setting).to receive(:welcome_title).and_return('Woohoo!') get :index end let(:show_welcome) { true } - it "renders the block" do - expect(response).to render_template(partial: "homescreen/blocks/_welcome") + it 'renders the block' do + expect(response).to render_template(partial: 'homescreen/blocks/_welcome') end - it "renders the text" do + it 'renders the text' do expect(response.body).to have_css('[data-test-selector="op-widget-box--header"]', - text: "Woohoo!") + text: 'Woohoo!') end end end end - context "with admin" do + context 'with admin' do let(:user) { build(:admin) } - it_behaves_like "renders blocks" do + it_behaves_like 'renders blocks' do let(:shown) { all_blocks } end end - context "regular user" do + context 'regular user' do let(:user) { build(:user) } - it_behaves_like "renders blocks" do + it_behaves_like 'renders blocks' do let(:shown) { all_blocks - %w(administration users) } end end - context "anonymous user" do + context 'anonymous user' do let(:user) { User.anonymous } - it_behaves_like "renders blocks" do + it_behaves_like 'renders blocks' do let(:shown) { all_blocks - %w(administration users my_account) } end end diff --git a/spec/controllers/journals_controller_spec.rb b/spec/controllers/journals_controller_spec.rb index 1c9ebf665f94..a2c86a3968fd 100644 --- a/spec/controllers/journals_controller_spec.rb +++ b/spec/controllers/journals_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe JournalsController do shared_let(:project) { create(:project_with_types) } @@ -39,26 +39,26 @@ params: end - describe "GET diff" do + describe 'GET diff' do render_views - context "for work package description" do + context 'for work package description' do shared_let(:work_package) do create(:work_package, type: project.types.first, author: user, project:, - description: "") + description: '') end - let(:params) { { id: work_package.last_journal.id.to_s, field: :description, format: "js" } } + let(:params) { { id: work_package.last_journal.id.to_s, field: :description, format: 'js' } } before do - work_package.update_attribute :description, "description" + work_package.update_attribute :description, 'description' end - describe "with a user having :view_work_package permission" do + describe 'with a user having :view_work_package permission' do it { expect(response).to have_http_status(:ok) } - it "presents the diff correctly" do + it 'presents the diff correctly' do expect(response.body.strip).to eq( "
    " \ "\n " \ @@ -70,7 +70,7 @@ end end - describe "with a user not having the :view_work_package permission" do + describe 'with a user not having the :view_work_package permission' do before do RolePermission.delete_all end @@ -79,17 +79,17 @@ end end - context "for project description" do - let(:params) { { id: project.last_journal.id.to_s, field: :description, format: "js" } } + context 'for project description' do + let(:params) { { id: project.last_journal.id.to_s, field: :description, format: 'js' } } before do - project.update_attribute :description, "description" + project.update_attribute :description, 'description' end - describe "with a user being member of the project" do + describe 'with a user being member of the project' do it { expect(response).to have_http_status(:ok) } - it "presents the diff correctly" do + it 'presents the diff correctly' do expect(response.body.strip).to eq( "
    " \ "\n " \ @@ -101,7 +101,7 @@ end end - describe "with a user not being member of the project" do + describe 'with a user not being member of the project' do before do Member.delete_all end @@ -111,13 +111,13 @@ describe 'when "Work Package Tracking" module is disabled' do before do - project.enabled_module_names -= ["work_package_tracking"] + project.enabled_module_names -= ['work_package_tracking'] end it { expect(response).to have_http_status(:ok) } end - describe "when project is archived" do + describe 'when project is archived' do before do project.update(active: false) end @@ -126,28 +126,28 @@ end end - context "for another field than description" do + context 'for another field than description' do shared_let(:work_package) do create(:work_package, type: project.types.first, author: user, project:) end - let(:params) { { id: work_package.last_journal.id.to_s, field: :another_field, format: "js" } } + let(:params) { { id: work_package.last_journal.id.to_s, field: :another_field, format: 'js' } } it { expect(response).to have_http_status(:not_found) } end - context "for other types, like forum message" do + context 'for other types, like forum message' do shared_let(:forum) { create(:forum, project:) } - shared_let(:message) { create(:message, forum:, content: "initial content") } + shared_let(:message) { create(:message, forum:, content: 'initial content') } - let(:params) { { id: message.last_journal.id.to_s, field: :description, format: "js" } } + let(:params) { { id: message.last_journal.id.to_s, field: :description, format: 'js' } } before do - message.update_attribute :content, "initial content updated" + message.update_attribute :content, 'initial content updated' end - describe "even with a user having all permissions" do + describe 'even with a user having all permissions' do before do user.update(admin: true) end diff --git a/spec/controllers/ldap_auth_sources_controller_spec.rb b/spec/controllers/ldap_auth_sources_controller_spec.rb index 51def5ec42d5..2bf8f9262985 100644 --- a/spec/controllers/ldap_auth_sources_controller_spec.rb +++ b/spec/controllers/ldap_auth_sources_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe LdapAuthSourcesController do let(:current_user) { create(:admin) } @@ -36,7 +36,7 @@ allow(User).to receive(:current).and_return current_user end - describe "new" do + describe 'new' do before do get :new end @@ -45,13 +45,13 @@ it { is_expected.to respond_with :success } it { is_expected.to render_template :new } - it "initializes a new LdapAuthSource" do + it 'initializes a new LdapAuthSource' do expect(assigns(:ldap_auth_source).class).to eq LdapAuthSource expect(assigns(:ldap_auth_source)).to be_new_record end end - describe "index" do + describe 'index' do before do get :index end @@ -60,9 +60,9 @@ it { is_expected.to render_template :index } end - describe "create" do + describe 'create' do before do - post :create, params: { ldap_auth_source: { name: "Test", host: "example.com", attr_login: "foo" } } + post :create, params: { ldap_auth_source: { name: 'Test', host: 'example.com', attr_login: 'foo' } } end it { is_expected.to respond_with :redirect } @@ -70,8 +70,8 @@ it { is_expected.to set_flash.to /success/i } end - describe "edit" do - let(:ldap) { create(:ldap_auth_source, name: "TestEdit") } + describe 'edit' do + let(:ldap) { create(:ldap_auth_source, name: 'TestEdit') } before do get :edit, params: { id: ldap.id } @@ -82,11 +82,11 @@ it { is_expected.to render_template :edit } end - describe "update" do - let(:ldap) { create(:ldap_auth_source, name: "TestEdit") } + describe 'update' do + let(:ldap) { create(:ldap_auth_source, name: 'TestEdit') } before do - post :update, params: { id: ldap.id, ldap_auth_source: { name: "TestUpdate" } } + post :update, params: { id: ldap.id, ldap_auth_source: { name: 'TestUpdate' } } end it { is_expected.to respond_with :redirect } @@ -94,10 +94,10 @@ it { is_expected.to set_flash.to /update/i } end - describe "destroy" do - let(:ldap) { create(:ldap_auth_source, name: "TestEdit") } + describe 'destroy' do + let(:ldap) { create(:ldap_auth_source, name: 'TestEdit') } - context "without users" do + context 'without users' do before do post :destroy, params: { id: ldap.id } end @@ -107,8 +107,8 @@ it { is_expected.to set_flash.to /deletion/i } end - context "with users" do - let!(:ldap) { create(:ldap_auth_source, name: "TestEdit") } + context 'with users' do + let!(:ldap) { create(:ldap_auth_source, name: 'TestEdit') } let!(:user) { create(:user, ldap_auth_source: ldap) } before do @@ -117,48 +117,48 @@ it { is_expected.to respond_with :redirect } - it "does not destroy the LdapAuthSource" do + it 'does not destroy the LdapAuthSource' do expect(LdapAuthSource.find(ldap.id)).not_to be_nil end end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) end - it "cannot find index" do + it 'cannot find index' do get :index expect(response).to have_http_status :not_found end - it "cannot find new" do + it 'cannot find new' do get :new expect(response).to have_http_status :not_found end - it "cannot find create" do - post :create, params: { ldap_auth_source: { name: "Test" } } + it 'cannot find create' do + post :create, params: { ldap_auth_source: { name: 'Test' } } expect(response).to have_http_status :not_found end - it "cannot find edit" do + it 'cannot find edit' do get :edit, params: { id: 42 } expect(response).to have_http_status :not_found end - it "cannot find update" do - post :update, params: { id: 42, ldap_auth_source: { name: "TestUpdate" } } + it 'cannot find update' do + post :update, params: { id: 42, ldap_auth_source: { name: 'TestUpdate' } } expect(response).to have_http_status :not_found end - it "cannot find destroy" do + it 'cannot find destroy' do post :destroy, params: { id: 42 } expect(response).to have_http_status :not_found diff --git a/spec/controllers/messages_controller_spec.rb b/spec/controllers/messages_controller_spec.rb index 7c86587787a6..ed13eef02ec3 100644 --- a/spec/controllers/messages_controller_spec.rb +++ b/spec/controllers/messages_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MessagesController, with_settings: { journal_aggregation_time_minutes: 0 } do let(:user) { create(:user) } @@ -43,30 +43,30 @@ project:) end - let(:filename) { "testfile.txt" } - let(:file) { File.open(Rails.root.join("spec/fixtures/files", filename)) } + let(:filename) { 'testfile.txt' } + let(:file) { File.open(Rails.root.join('spec/fixtures/files', filename)) } before { allow(User).to receive(:current).and_return user } - describe "#show" do - context "with a public project" do + describe '#show' do + context 'with a public project' do let(:user) { User.anonymous } let(:project) { create(:public_project) } let!(:message) { create(:message, forum:) } - context "when login_required", with_settings: { login_required: true } do - it "redirects to login" do + context 'when login_required', with_settings: { login_required: true } do + it 'redirects to login' do get :show, params: { project_id: project.id, id: message.id } expect(response).to redirect_to signin_path(back_url: topic_url(message.id)) end end - context "when not login_required", with_settings: { login_required: false } do - it "renders the show template" do + context 'when not login_required', with_settings: { login_required: false } do + it 'renders the show template' do get :show, params: { project_id: project.id, id: message.id } expect(response).to be_successful - expect(response).to render_template "messages/show" + expect(response).to render_template 'messages/show' expect(assigns(:topic)).to be_present expect(assigns(:forum)).to be_present expect(assigns(:project)).to be_present @@ -75,7 +75,7 @@ end end - describe "#update" do + describe '#update' do let(:message) { create(:message, forum:) } let(:other_forum) { create(:forum, project:) } @@ -85,39 +85,39 @@ message: { forum_id: other_forum } } end - it "allows for changing the board" do + it 'allows for changing the board' do expect(message.reload.forum).to eq(other_forum) end - context "attachment upload" do + context 'attachment upload' do let!(:message) { create(:message) } let(:attachment_id) { "attachments_#{message.attachments.first.id}" } # Attachment is already uploaded let(:attachment) { create(:attachment, container: nil, author: user) } let(:params) do { id: message.id, - attachments: { "0" => { "id" => attachment.id } } } + attachments: { '0' => { 'id' => attachment.id } } } end - describe "add" do + describe 'add' do before do allow_any_instance_of(Message).to receive(:editable_by?).and_return(true) end - context "journal" do + context 'journal' do before do put(:update, params:) message.reload end - describe "#key" do + describe '#key' do subject { message.journals.last.details } it { is_expected.to have_key attachment_id } end - describe "#value" do + describe '#value' do subject { message.journals.last.details[attachment_id].last } it { is_expected.to eq(attachment.filename) } @@ -126,7 +126,7 @@ end end - describe "#remove" do + describe '#remove' do let!(:attachment) do create(:attachment, container: message, @@ -146,16 +146,16 @@ message.reload end - context "journal" do + context 'journal' do let(:attachment_id) { "attachments_#{attachment.id}" } - describe "#key" do + describe '#key' do subject { message.journals.last.details } it { is_expected.to have_key attachment_id } end - describe "#value" do + describe '#value' do subject { message.journals.last.details[attachment_id].first } it { is_expected.to eq(filename) } @@ -164,26 +164,26 @@ end end - describe "quote" do - let(:message) { create(:message, content: "foo", subject: "subject", forum:) } + describe 'quote' do + let(:message) { create(:message, content: 'foo', subject: 'subject', forum:) } - context "when allowed" do + context 'when allowed' do let(:user) { create(:admin) } before do login_as user end - it "renders the content as json" do + it 'renders the content as json' do get :quote, params: { forum_id: forum.id, id: message.id }, format: :json expect(response).to be_successful expect(response.body).to eq '{"subject":"RE: subject","content":" wrote:\n\u003e foo\n\n"}' end - it "escapes HTML in quoted message author" do - user.firstname = "Hello" - user.lastname = "world" + it 'escapes HTML in quoted message author' do + user.firstname = 'Hello' + user.lastname = 'world' user.save! validate: false message.update!(author: user) diff --git a/spec/controllers/my_controller_spec.rb b/spec/controllers/my_controller_spec.rb index c5cfc3781c42..004a5a49a352 100644 --- a/spec/controllers/my_controller_spec.rb +++ b/spec/controllers/my_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MyController do let(:user) { create(:user) } @@ -35,92 +35,92 @@ login_as(user) end - describe "password change" do - describe "#password" do + describe 'password change' do + describe '#password' do before do get :password end - it "renders the password template" do - assert_template "password" + it 'renders the password template' do + assert_template 'password' assert_response :success end end - describe "with disabled password login" do + describe 'with disabled password login' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) post :change_password end - it "is not found" do + it 'is not found' do expect(response.status).to eq 404 end end - describe "with wrong confirmation" do + describe 'with wrong confirmation' do before do post :change_password, params: { - password: "adminADMIN!", - new_password: "adminADMIN!New", - new_password_confirmation: "adminADMIN!Other" + password: 'adminADMIN!', + new_password: 'adminADMIN!New', + new_password_confirmation: 'adminADMIN!Other' } end - it "shows an error message" do + it 'shows an error message' do assert_response :success - assert_template "password" + assert_template 'password' expect(user.errors.attribute_names).to eq([:password_confirmation]) expect(user.errors.map(&:message).flatten) .to contain_exactly("Password confirmation does not match password.") end end - describe "with wrong password" do + describe 'with wrong password' do render_views before do @current_password = user.current_password.id post :change_password, params: { - password: "wrongpassword", - new_password: "adminADMIN!New", - new_password_confirmation: "adminADMIN!New" + password: 'wrongpassword', + new_password: 'adminADMIN!New', + new_password_confirmation: 'adminADMIN!New' } end - it "shows an error message" do + it 'shows an error message' do assert_response :success - assert_template "password" - expect(flash[:error]).to eq("Wrong password") + assert_template 'password' + expect(flash[:error]).to eq('Wrong password') end - it "does not change the password" do + it 'does not change the password' do expect(user.current_password.id).to eq(@current_password) end end - describe "with good password and good confirmation" do + describe 'with good password and good confirmation' do before do post :change_password, params: { - password: "adminADMIN!", - new_password: "adminADMIN!New", - new_password_confirmation: "adminADMIN!New" + password: 'adminADMIN!', + new_password: 'adminADMIN!New', + new_password_confirmation: 'adminADMIN!New' } end - it "redirects to the my password page" do - expect(response).to redirect_to("/my/password") + it 'redirects to the my password page' do + expect(response).to redirect_to('/my/password') end - it "allows the user to login with the new password" do - assert User.try_to_login(user.login, "adminADMIN!New") + it 'allows the user to login with the new password' do + assert User.try_to_login(user.login, 'adminADMIN!New') end end end - describe "account" do + describe 'account' do let(:custom_field) { create(:user_custom_field, :text) } before do @@ -130,69 +130,69 @@ end end - it "responds with success" do + it 'responds with success' do expect(response).to be_successful end - it "renders the account template" do - expect(response).to render_template "account" + it 'renders the account template' do + expect(response).to render_template 'account' end - it "assigns @user" do + it 'assigns @user' do expect(assigns(:user)).to eq(user) end - context "with render_views" do + context 'with render_views' do render_views - it "renders editable custom fields" do + it 'renders editable custom fields' do expect(response.body).to have_content(custom_field.name) end it "renders the 'Change password' menu entry" do - expect(response.body).to have_css("#menu-sidebar li a", text: "Change password") + expect(response.body).to have_css('#menu-sidebar li a', text: 'Change password') end end end - describe "settings" do - describe "PATCH" do - let(:language) { "en" } + describe 'settings' do + describe 'PATCH' do + let(:language) { 'en' } before do as_logged_in_user user do - user.pref.comments_sorting = "desc" + user.pref.comments_sorting = 'desc' user.pref.auto_hide_popups = true patch :update_settings, params: { user: { language: }, pref: { auto_hide_popups: 0 } } end end - it "updates the settings appropriately", :aggregate_failures do + it 'updates the settings appropriately', :aggregate_failures do expect(assigns(:user).language).to eq language - expect(assigns(:user).pref.comments_sorting).to eql "desc" + expect(assigns(:user).pref.comments_sorting).to eql 'desc' expect(assigns(:user).pref.auto_hide_popups?).to be_falsey expect(request.path).to eq(my_settings_path) expect(flash[:notice]).to eql I18n.t(:notice_account_updated) end - context "when user is invalid" do + context 'when user is invalid' do let(:user) do create(:user).tap do |u| - u.update_column(:mail, "something invalid") + u.update_column(:mail, 'something invalid') end end - it "shows a flash error" do - expect(flash[:error]).to include "Email is not a valid email address." + it 'shows a flash error' do + expect(flash[:error]).to include 'Email is not a valid email address.' expect(request.path).to eq(my_settings_path) end end - context "when changing language" do - let(:language) { "de" } + context 'when changing language' do + let(:language) { 'de' } - it "shows a flash message translated in the selected language" do + it 'shows a flash message translated in the selected language' do expect(assigns(:user).language).to eq(language) expect(flash[:notice]).to eq(I18n.t(:notice_account_updated, locale: language)) end @@ -200,8 +200,8 @@ end end - describe "settings:auto_hide_popups" do - context "with render_views" do + describe 'settings:auto_hide_popups' do + context 'with render_views' do before do as_logged_in_user user do get :settings @@ -209,23 +209,23 @@ end render_views - it "renders auto hide popups checkbox" do - expect(response.body).to have_css("#my_account_form #pref_auto_hide_popups") + it 'renders auto hide popups checkbox' do + expect(response.body).to have_css('#my_account_form #pref_auto_hide_popups') end end - context "PATCH" do + context 'PATCH' do before do as_logged_in_user user do user.pref.auto_hide_popups = false - patch :update_settings, params: { user: { language: "en" } } + patch :update_settings, params: { user: { language: 'en' } } end end end end - describe "account with disabled password login" do + describe 'account with disabled password login' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) as_logged_in_user user do @@ -236,13 +236,13 @@ render_views it "does not render 'Change password' menu entry" do - expect(response.body).to have_no_css("#menu-sidebar li a", text: "Change password") + expect(response.body).to have_no_css('#menu-sidebar li a', text: 'Change password') end end - describe "access_tokens" do - describe "rss" do - it "creates a key" do + describe 'access_tokens' do + describe 'rss' do + it 'creates a key' do expect(user.rss_token).to be_nil post :generate_rss_key @@ -253,10 +253,10 @@ expect(response).to redirect_to action: :access_token end - context "with existing key" do + context 'with existing key' do let!(:key) { Token::RSS.create user: } - it "replaces the key" do + it 'replaces the key' do expect(user.rss_token).to eq(key) post :generate_rss_key @@ -272,9 +272,9 @@ end end - describe "api" do - context "with no existing key" do - it "creates a key" do + describe 'api' do + context 'with no existing key' do + it 'creates a key' do expect(user.api_token).to be_nil post :generate_api_key @@ -288,10 +288,10 @@ end end - context "with existing key" do + context 'with existing key' do let!(:key) { Token::API.create user: } - it "replaces the key" do + it 'replaces the key' do expect(user.reload.api_token).to eq(key) post :generate_api_key @@ -307,14 +307,14 @@ end end - describe "ical" do + describe 'ical' do # unlike with the other tokens, creating new ical tokens is not done in this context # ical tokens are generated whenever the user requests a new ical url # a user can have N ical tokens # # in this context a specific ical token of a user should be reverted # this invalidates the previously generated ical url - context "with existing keys" do + context 'with existing keys' do let(:user) { create(:user) } let(:project) { create(:project) } let(:query) { create(:query, project:) } @@ -323,7 +323,7 @@ let!(:another_ical_token_for_query) { create(:ical_token, user:, query:, name: "Some Other Token Name") } let!(:ical_token_for_another_query) { create(:ical_token, user:, query: another_query, name: "Some Token Name") } - it "revoke specific ical tokens" do + it 'revoke specific ical tokens' do expect(user.ical_tokens).to contain_exactly( ical_token_for_query, another_ical_token_for_query, ical_token_for_another_query ) @@ -346,7 +346,7 @@ end end - describe "file storage" do + describe 'file storage' do let(:client) { create(:oauth_client, integration: create(:nextcloud_storage)) } let(:token) { create(:oauth_client_token, oauth_client: client, scope: nil, user:, expires_in: 3_600) } @@ -354,12 +354,12 @@ before { token } - it "list the tokens" do + it 'list the tokens' do get :access_token expect(response.body).to have_css("#storage-oauth-token-#{token.id}") end - it "can remove the token" do + it 'can remove the token' do expect do delete :delete_storage_token, params: { id: token.id } end.to change(OAuthClientToken, :count).by(-1) diff --git a/spec/controllers/news/comments_controller_spec.rb b/spec/controllers/news/comments_controller_spec.rb index 06dcfafc53bc..d3ac2672d6b2 100644 --- a/spec/controllers/news/comments_controller_spec.rb +++ b/spec/controllers/news/comments_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe News::CommentsController do render_views @@ -38,28 +38,28 @@ allow(User).to receive(:current).and_return user end - describe "#create" do - it "assigns a comment to the news item and redirects to the news page" do - post :create, params: { news_id: news.id, comment: { comments: "This is a test comment" } } + describe '#create' do + it 'assigns a comment to the news item and redirects to the news page' do + post :create, params: { news_id: news.id, comment: { comments: 'This is a test comment' } } expect(response).to redirect_to news_path(news) latest_comment = news.comments.reorder(created_at: :desc).first expect(latest_comment).not_to be_nil - expect(latest_comment.comments).to eq "This is a test comment" + expect(latest_comment.comments).to eq 'This is a test comment' expect(latest_comment.author).to eq user end it "doesn't create a comment when it is invalid" do expect do - post :create, params: { news_id: news.id, comment: { comments: "" } } + post :create, params: { news_id: news.id, comment: { comments: '' } } expect(response).to redirect_to news_path(news) end.not_to change { Comment.count } end end - describe "#destroy" do - it "deletes the comment and redirects to the news page" do + describe '#destroy' do + it 'deletes the comment and redirects to the news page' do comment = create(:comment, commented: news) expect do diff --git a/spec/controllers/news_controller_spec.rb b/spec/controllers/news_controller_spec.rb index daebacc36056..f0ea7a49c2f9 100644 --- a/spec/controllers/news_controller_spec.rb +++ b/spec/controllers/news_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe NewsController do render_views @@ -43,80 +43,80 @@ allow(User).to receive(:current).and_return user end - describe "#index" do - it "renders index" do + describe '#index' do + it 'renders index' do get :index expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' expect(assigns(:project)).to be_nil expect(assigns(:newss)).not_to be_nil end - it "renders index with project" do + it 'renders index with project' do get :index, params: { project_id: project.id } expect(response).to be_successful - expect(response).to render_template "index" + expect(response).to render_template 'index' expect(assigns(:newss)).not_to be_nil end end - describe "#show" do - it "renders show" do + describe '#show' do + it 'renders show' do get :show, params: { id: news.id } expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' - expect(response.body).to have_css("h2", text: news.title) + expect(response.body).to have_css('h2', text: news.title) end - it "renders show with slug" do + it 'renders show with slug' do get :show, params: { id: "#{news.id}-some-news-title" } expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' - expect(response.body).to have_css("h2", text: news.title) + expect(response.body).to have_css('h2', text: news.title) end - it "renders error if news item is not found" do + it 'renders error if news item is not found' do get :show, params: { id: -1 } expect(response).to be_not_found end end - describe "#new" do - it "renders new" do + describe '#new' do + it 'renders new' do get :new, params: { project_id: project.id } expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end end - describe "#create" do - context "with news_added notifications" do - it "persists a news item" do + describe '#create' do + context 'with news_added notifications' do + it 'persists a news item' do become_member(project, user) post :create, params: { project_id: project.id, news: { - title: "NewsControllerTest", - description: "This is the description", - summary: "" + title: 'NewsControllerTest', + description: 'This is the description', + summary: '' } } expect(response).to redirect_to project_news_index_path(project) - news = News.find_by!(title: "NewsControllerTest") + news = News.find_by!(title: 'NewsControllerTest') expect(news).not_to be_nil - expect(news.description).to eq "This is the description" + expect(news.description).to eq 'This is the description' expect(news.author).to eq user expect(news.project).to eq project end @@ -127,43 +127,43 @@ params: { project_id: project.id, news: { - title: "", - description: "This is the description", - summary: "" + title: '', + description: 'This is the description', + summary: '' } } expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' expect(assigns(:news)).not_to be_nil expect(assigns(:news)).to be_new_record - expect(response.body).to have_css("div.op-toast.-error", text: /1 error/) + expect(response.body).to have_css('div.op-toast.-error', text: /1 error/) end end - describe "#edit" do - it "renders edit" do + describe '#edit' do + it 'renders edit' do get :edit, params: { id: news.id } expect(response).to be_successful - expect(response).to render_template "edit" + expect(response).to render_template 'edit' end end - describe "#update" do - it "updates the news element" do + describe '#update' do + it 'updates the news element' do put :update, - params: { id: news.id, news: { description: "Description changed by test_post_edit" } } + params: { id: news.id, news: { description: 'Description changed by test_post_edit' } } expect(response).to redirect_to news_path(news) news.reload - expect(news.description).to eq "Description changed by test_post_edit" + expect(news.description).to eq 'Description changed by test_post_edit' end end - describe "#destroy" do - it "deletes the news element and redirects to the news overview page" do + describe '#destroy' do + it 'deletes the news element and redirects to the news overview page' do delete :destroy, params: { id: news.id } expect(response).to redirect_to project_news_index_path(news.project) diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb index 5ab1af33d4a8..6677683cf0c7 100644 --- a/spec/controllers/oauth/applications_controller_spec.rb +++ b/spec/controllers/oauth/applications_controller_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "work_package" +require 'spec_helper' +require 'work_package' RSpec.describe OAuth::ApplicationsController do let(:user) { build_stubbed(:admin) } - let(:application_stub) { build_stubbed(:oauth_application, id: 1, secret: "foo") } + let(:application_stub) { build_stubbed(:oauth_application, id: 1, secret: 'foo') } before do login_as user end - context "not logged as admin" do + context 'not logged as admin' do let(:user) { build_stubbed(:user) } - it "does not grant access" do + it 'does not grant access' do get :index expect(response.response_code).to eq 403 @@ -61,7 +61,7 @@ end end - describe "#new" do + describe '#new' do it do get :new expect(response.status).to be 200 @@ -69,58 +69,58 @@ end end - describe "#edit" do + describe '#edit' do before do allow(Doorkeeper::Application) .to receive(:find) - .with("1") + .with('1') .and_return(application_stub) end it do - get :edit, params: { id: 1, application: { name: "foo" } } + get :edit, params: { id: 1, application: { name: 'foo' } } expect(response.status).to be 200 expect(response).to render_template :edit end end - describe "#create" do + describe '#create' do before do allow(Doorkeeper::Application) .to receive(:new) .and_return(application_stub) expect(application_stub).to receive(:attributes=) expect(application_stub).to receive(:save).and_return(true) - expect(application_stub).to receive(:plaintext_secret).and_return("secret!") + expect(application_stub).to receive(:plaintext_secret).and_return('secret!') end it do - post :create, params: { application: { name: "foo" } } + post :create, params: { application: { name: 'foo' } } expect(response).to redirect_to action: :show, id: application_stub.id end end - describe "#update" do + describe '#update' do before do allow(Doorkeeper::Application) .to receive(:find) - .with("1") + .with('1') .and_return(application_stub) expect(application_stub).to receive(:attributes=) expect(application_stub).to receive(:save).and_return(true) end it do - patch :update, params: { id: 1, application: { name: "foo" } } + patch :update, params: { id: 1, application: { name: 'foo' } } expect(response).to redirect_to action: :index end end - describe "#destroy" do + describe '#destroy' do before do allow(Doorkeeper::Application) .to receive(:find) - .with("1") + .with('1') .and_return(application_stub) expect(application_stub).to receive(:destroy).and_return(true) end diff --git a/spec/controllers/oauth/grants_controller_spec.rb b/spec/controllers/oauth/grants_controller_spec.rb index 2ad78d320223..4a280584febd 100644 --- a/spec/controllers/oauth/grants_controller_spec.rb +++ b/spec/controllers/oauth/grants_controller_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "work_package" +require 'spec_helper' +require 'work_package' RSpec.describe OAuth::GrantsController do let(:user) { build_stubbed(:user) } - let(:application_stub) { instance_double(Doorkeeper::Application, name: "Foo", id: 1) } + let(:application_stub) { instance_double(Doorkeeper::Application, name: 'Foo', id: 1) } before do login_as user end - describe "#revoke_application" do - context "when not found" do - it "renders 404" do + describe '#revoke_application' do + context 'when not found' do + it 'renders 404' do post :revoke_application, params: { application_id: 1234 } expect(flash[:notice]).to be_nil expect(response.response_code).to eq 404 end end - context "when found" do + context 'when found' do before do allow(controller) .to receive(:find_application) @@ -55,8 +55,8 @@ it do post :revoke_application, params: { application_id: 1 } - expect(flash[:notice]).to include "Foo" - expect(response).to redirect_to controller: "/my", action: :access_token + expect(flash[:notice]).to include 'Foo' + expect(response).to redirect_to controller: '/my', action: :access_token end end end diff --git a/spec/controllers/placeholder_users/memberships_controller_spec.rb b/spec/controllers/placeholder_users/memberships_controller_spec.rb index b4bf36edf6e6..05dda05320f4 100644 --- a/spec/controllers/placeholder_users/memberships_controller_spec.rb +++ b/spec/controllers/placeholder_users/memberships_controller_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "work_package" +require 'spec_helper' +require 'work_package' RSpec.describe PlaceholderUsers::MembershipsController do shared_let(:placeholder_user) { create(:placeholder_user) } @@ -35,8 +35,8 @@ shared_let(:project) { create(:project) } shared_let(:role) { create(:project_role) } - shared_examples "update memberships flow" do - it "works" do + shared_examples 'update memberships flow' do + it 'works' do # i.e. it should successfully add a placeholder user to a project's members post :create, params: { @@ -47,10 +47,10 @@ } } - expect(response).to redirect_to(controller: "/placeholder_users", - action: "edit", + expect(response).to redirect_to(controller: '/placeholder_users', + action: 'edit', id: placeholder_user.id, - tab: "memberships") + tab: 'memberships') is_member = placeholder_user.reload.memberships.any? do |m| m.project_id == project.id && m.role_ids.include?(role.id) @@ -59,9 +59,9 @@ end end - shared_examples "update memberships forbidden flow" do - describe "POST create" do - it "returns an error" do + shared_examples 'update memberships forbidden flow' do + describe 'POST create' do + it 'returns an error' do post :create, params: { placeholder_user_id: placeholder_user.id, membership: { @@ -74,8 +74,8 @@ end end - describe "PUT update" do - it "returns an error" do + describe 'PUT update' do + it 'returns an error' do put :update, params: { placeholder_user_id: placeholder_user.id, id: 1234 @@ -85,8 +85,8 @@ end end - describe "DELETE destroy" do - it "returns an error" do + describe 'DELETE destroy' do + it 'returns an error' do delete :destroy, params: { placeholder_user_id: placeholder_user.id, id: 1234 @@ -97,27 +97,27 @@ end end - context "as admin" do + context 'as admin' do current_user { create(:admin) } - it_behaves_like "update memberships flow" + it_behaves_like 'update memberships flow' end - context "as user with global permission and manage_members" do + context 'as user with global permission and manage_members' do current_user do create(:user, member_with_permissions: { project => %i[manage_members] }, global_permissions: %i[manage_placeholder_user]) end - it_behaves_like "update memberships flow" + it_behaves_like 'update memberships flow' end - context "as user with global permission but not project permission" do + context 'as user with global permission but not project permission' do current_user { create(:user, global_permissions: %i[manage_placeholder_user]) } - describe "POST create" do - it "redirects but fails to create" do + describe 'POST create' do + it 'redirects but fails to create' do post :create, params: { placeholder_user_id: placeholder_user.id, membership: { @@ -131,12 +131,12 @@ end end - context "with a membership in another project that is invisible" do + context 'with a membership in another project that is invisible' do shared_let(:project2) { create(:project) } shared_let(:membership) { create(:member, principal: placeholder_user, project: project2, roles: [role]) } - describe "PUT update" do - it "returns an error" do + describe 'PUT update' do + it 'returns an error' do put :update, params: { placeholder_user_id: placeholder_user.id, id: membership.id @@ -146,8 +146,8 @@ end end - describe "DELETE destroy" do - it "returns an error" do + describe 'DELETE destroy' do + it 'returns an error' do delete :destroy, params: { placeholder_user_id: placeholder_user.id, id: membership.id @@ -159,9 +159,9 @@ end end - context "as user without global permission" do + context 'as user without global permission' do current_user { create(:user) } - it_behaves_like "update memberships forbidden flow" + it_behaves_like 'update memberships forbidden flow' end end diff --git a/spec/controllers/placeholder_users_controller_spec.rb b/spec/controllers/placeholder_users_controller_spec.rb index 401464a45a11..43b01dbc41d3 100644 --- a/spec/controllers/placeholder_users_controller_spec.rb +++ b/spec/controllers/placeholder_users_controller_spec.rb @@ -26,58 +26,58 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "work_package" +require 'spec_helper' +require 'work_package' RSpec.describe PlaceholderUsersController do shared_let(:placeholder_user) { create(:placeholder_user) } - shared_examples "do not allow non-admins" do - it "responds with unauthorized status" do + shared_examples 'do not allow non-admins' do + it 'responds with unauthorized status' do expect(response).not_to be_successful expect(response.status).to eq 403 end end - shared_examples "renders the show template" do - it "renders the show template" do + shared_examples 'renders the show template' do + it 'renders the show template' do get :show, params: { id: placeholder_user.id } expect(response).to be_successful - expect(response).to render_template "placeholder_users/show" + expect(response).to render_template 'placeholder_users/show' expect(assigns(:placeholder_user)).to be_present expect(assigns(:memberships)).to be_empty end end - shared_examples "authorized flows" do - describe "GET new" do - it "renders the new template" do + shared_examples 'authorized flows' do + describe 'GET new' do + it 'renders the new template' do get :new expect(response).to be_successful - expect(response).to render_template "placeholder_users/new" + expect(response).to render_template 'placeholder_users/new' expect(assigns(:placeholder_user)).to be_present end end - describe "GET index" do - it "renders the index template" do + describe 'GET index' do + it 'renders the index template' do get :index expect(response).to be_successful - expect(response).to render_template "placeholder_users/index" + expect(response).to render_template 'placeholder_users/index' expect(assigns(:placeholder_users)).to be_present expect(assigns(:groups)).not_to be_present end end - describe "GET show" do - it_behaves_like "renders the show template" + describe 'GET show' do + it_behaves_like 'renders the show template' end - describe "GET edit" do - it "renders the show template" do + describe 'GET edit' do + it 'renders the show template' do get :edit, params: { id: placeholder_user.id } expect(response).to be_successful expect(response).to render_template "placeholder_users/edit" @@ -87,11 +87,11 @@ end end - describe "POST create" do + describe 'POST create' do let(:params) do { placeholder_user: { - name: "UX Developer" + name: 'UX Developer' } } end @@ -100,8 +100,8 @@ post :create, params: end - context "without ee" do - it "returns with an error" do + context 'without ee' do + it 'returns with an error' do expect { post :create, params: }.not_to change { PlaceholderUser.count } expect(response).to be_successful @@ -110,73 +110,73 @@ end end - context "with ee", with_ee: %i[placeholder_users] do - it "is assigned their new values" do + context 'with ee', with_ee: %i[placeholder_users] do + it 'is assigned their new values' do user_from_db = PlaceholderUser.last - expect(user_from_db.name).to eq("UX Developer") + expect(user_from_db.name).to eq('UX Developer') end - it "shows a success notice" do + it 'shows a success notice' do expect(flash[:notice]).to eql(I18n.t(:notice_successful_create)) end - it "does not send an email" do + it 'does not send an email' do expect(ActionMailer::Base.deliveries.empty?).to be_truthy end - context "when user chose to directly create the next placeholder user" do + context 'when user chose to directly create the next placeholder user' do let(:params) do { placeholder_user: { - name: "UX Developer" + name: 'UX Developer' }, continue: true } end - it "redirects to the new page" do + it 'redirects to the new page' do expect(response).to redirect_to(new_placeholder_user_url) end end - context "when user chose to NOT directly create the next placeholder user" do + context 'when user chose to NOT directly create the next placeholder user' do let(:params) do { placeholder_user: { - name: "UX Developer" + name: 'UX Developer' } } end - it "redirects to the edit page" do + it 'redirects to the edit page' do user_from_db = PlaceholderUser.last expect(response).to redirect_to(edit_placeholder_user_url(user_from_db)) end end - context "invalid params" do + context 'invalid params' do let(:params) do { placeholder_user: { - name: "x" * 300 # Name is too long + name: 'x' * 300 # Name is too long } } end - it "renders the edit form with a validation error message" do - expect(assigns(:placeholder_user).errors.messages[:name].first).to include("is too long") - expect(response).to render_template "placeholder_users/new" + it 'renders the edit form with a validation error message' do + expect(assigns(:placeholder_user).errors.messages[:name].first).to include('is too long') + expect(response).to render_template 'placeholder_users/new' end end end end - describe "PUT update" do + describe 'PUT update' do let(:params) do { id: placeholder_user.id, placeholder_user: { - name: "UX Guru" + name: 'UX Guru' } } end @@ -185,53 +185,53 @@ put :update, params: end - it "redirects to the edit page" do + it 'redirects to the edit page' do expect(response).to redirect_to(edit_placeholder_user_url(placeholder_user)) end - it "is assigned their new values" do + it 'is assigned their new values' do user_from_db = PlaceholderUser.find(placeholder_user.id) - expect(user_from_db.name).to eq("UX Guru") + expect(user_from_db.name).to eq('UX Guru') end - it "does not send an email" do + it 'does not send an email' do expect(ActionMailer::Base.deliveries.empty?).to be_truthy end - context "invalid params" do + context 'invalid params' do let(:params) do { id: placeholder_user.id, placeholder_user: { - name: "x" * 300 # Name is too long + name: 'x' * 300 # Name is too long } } end - it "renders the edit form with a validation error message" do - expect(assigns(:placeholder_user).errors.messages[:name].first).to include("is too long") - expect(response).to render_template "placeholder_users/edit" + it 'renders the edit form with a validation error message' do + expect(assigns(:placeholder_user).errors.messages[:name].first).to include('is too long') + expect(response).to render_template 'placeholder_users/edit' end end end - describe "GET deletion_info" do + describe 'GET deletion_info' do before do get :deletion_info, params: { id: placeholder_user.id } end - it "renders the deletion info response" do + it 'renders the deletion info response' do expect(response).to be_successful - expect(response).to render_template "placeholder_users/deletion_info" + expect(response).to render_template 'placeholder_users/deletion_info' end end - describe "POST destroy" do + describe 'POST destroy' do before do delete :destroy, params: { id: placeholder_user.id } end - it "triggers the deletion" do + it 'triggers the deletion' do expect(response).to redirect_to action: :index expect(flash[:info]).to include I18n.t(:notice_deletion_scheduled) @@ -241,53 +241,53 @@ end end - context "as an admin" do + context 'as an admin' do current_user { create(:admin) } - it_behaves_like "authorized flows" + it_behaves_like 'authorized flows' end - context "as a user with global permission" do + context 'as a user with global permission' do current_user { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "authorized flows" + it_behaves_like 'authorized flows' end - context "as an unauthorized user" do + context 'as an unauthorized user' do current_user { create(:user) } - describe "GET new" do + describe 'GET new' do before do get :new end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end - describe "GET index" do + describe 'GET index' do before do get :index end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end - describe "GET show" do - it_behaves_like "renders the show template" + describe 'GET show' do + it_behaves_like 'renders the show template' end - describe "GET edit" do + describe 'GET edit' do before do get :edit, params: { id: placeholder_user.id } end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end - describe "POST create" do + describe 'POST create' do let(:params) do { placeholder_user: { - name: "UX Developer" + name: 'UX Developer' } } end @@ -296,15 +296,15 @@ post :create, params: end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end - describe "PUT update" do + describe 'PUT update' do let(:params) do { id: placeholder_user.id, placeholder_user: { - name: "UX Guru" + name: 'UX Guru' } } end @@ -313,27 +313,27 @@ put :update, params: end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end - describe "GET deletion_info" do + describe 'GET deletion_info' do before do get :deletion_info, params: { id: placeholder_user.id } end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end - describe "POST destroy" do + describe 'POST destroy' do before do delete :destroy, params: { id: placeholder_user.id } end - it_behaves_like "do not allow non-admins" + it_behaves_like 'do not allow non-admins' end end - context "as a user that may not delete the placeholder" do + context 'as a user that may not delete the placeholder' do current_user { create(:user) } before do @@ -341,23 +341,23 @@ .to receive(:deletion_allowed?).and_return false end - describe "GET deletion_info" do + describe 'GET deletion_info' do before do get :deletion_info, params: { id: placeholder_user.id } end - it "responds with unauthorized status" do + it 'responds with unauthorized status' do expect(response).not_to be_successful expect(response.status).to eq 403 end end - describe "POST destroy" do + describe 'POST destroy' do before do delete :destroy, params: { id: placeholder_user.id } end - it "responds with unauthorized status" do + it 'responds with unauthorized status' do expect(response).not_to be_successful expect(response.status).to eq 403 end diff --git a/spec/controllers/projects/identifier_controller_spec.rb b/spec/controllers/projects/identifier_controller_spec.rb index de3fe73828a1..9737d06daa49 100644 --- a/spec/controllers/projects/identifier_controller_spec.rb +++ b/spec/controllers/projects/identifier_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" +require 'rails_helper' RSpec.describe Projects::IdentifierController do let(:project) { create(:project) } @@ -34,22 +34,22 @@ current_user { create(:admin) } render_views - describe "update" do - it "sets the project identifier to the provided value" do - put :update, params: { project_id: project.id, project: { identifier: "new-identifier" } } + describe 'update' do + it 'sets the project identifier to the provided value' do + put :update, params: { project_id: project.id, project: { identifier: 'new-identifier' } } # Upon success, the user is redirected to the general project settings page expect(response).to have_http_status(:redirect) - expect(project.reload.identifier).to eq("new-identifier") + expect(project.reload.identifier).to eq('new-identifier') end - context "with an invalid identifier" do - it "does not change the project identifier and correctly renders the view" do + context 'with an invalid identifier' do + it 'does not change the project identifier and correctly renders the view' do previous_identifier = project.identifier - put :update, params: { project_id: project.id, project: { identifier: "bad identifier" } } + put :update, params: { project_id: project.id, project: { identifier: 'bad identifier' } } expect(response).to have_http_status(:ok) - expect(response.body).to include("Identifier is invalid") + expect(response.body).to include('Identifier is invalid') expect(project.reload.identifier).to eq(previous_identifier) end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index ec6ae981a623..7e8da4e84cd4 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ProjectsController do shared_let(:admin) { create(:admin) } @@ -38,14 +38,14 @@ login_as admin end - describe "#new" do + describe '#new' do it "renders 'new'" do - get "new" + get 'new' expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end - context "by non-admin user with add_project permission" do + context 'by non-admin user with add_project permission' do let(:non_member_user) { create(:user) } before do @@ -53,40 +53,40 @@ login_as non_member_user end - it "accepts get" do + it 'accepts get' do get :new expect(response).to be_successful - expect(response).to render_template "new" + expect(response).to render_template 'new' end end end - describe "index.html" do - shared_let(:project_a) { create(:project, name: "Project A", public: false, active: true) } - shared_let(:project_b) { create(:project, name: "Project B", public: false, active: true) } - shared_let(:project_c) { create(:project, name: "Project C", public: true, active: true) } - shared_let(:project_d) { create(:project, name: "Project D", public: true, active: false) } + describe 'index.html' do + shared_let(:project_a) { create(:project, name: 'Project A', public: false, active: true) } + shared_let(:project_b) { create(:project, name: 'Project B', public: false, active: true) } + shared_let(:project_c) { create(:project, name: 'Project C', public: true, active: true) } + shared_let(:project_d) { create(:project, name: 'Project D', public: true, active: false) } before do ProjectRole.anonymous ProjectRole.non_member login_as(user) - get "index" + get 'index' end - shared_examples_for "successful index" do - it "is success" do + shared_examples_for 'successful index' do + it 'is success' do expect(response).to be_successful end - it "renders the index template" do - expect(response).to render_template "index" + it 'renders the index template' do + expect(response).to render_template 'index' end end end - describe "#destroy" do + describe '#destroy' do render_views let(:project) { build_stubbed(:project) } @@ -105,20 +105,20 @@ .and_return(deletion_service) end - context "when service call succeeds" do + context 'when service call succeeds' do let(:success) { true } - it "prints success" do + it 'prints success' do request expect(response).to be_redirect expect(flash[:notice]).to be_present end end - context "when service call fails" do + context 'when service call fails' do let(:success) { false } - it "prints fail" do + it 'prints fail' do request expect(response).to be_redirect expect(flash[:error]).to be_present @@ -126,28 +126,28 @@ end end - describe "with an existing project" do - let(:project) { create(:project, identifier: "blog") } + describe 'with an existing project' do + let(:project) { create(:project, identifier: 'blog') } - it "gets destroy info" do + it 'gets destroy info' do get :destroy_info, params: { id: project.id } expect(response).to be_successful - expect(response).to render_template "destroy_info" + expect(response).to render_template 'destroy_info' expect { project.reload }.not_to raise_error end end - describe "#copy" do - let(:project) { create(:project, identifier: "blog") } + describe '#copy' do + let(:project) { create(:project, identifier: 'blog') } it "renders 'copy'" do - get "copy", params: { id: project.id } + get 'copy', params: { id: project.id } expect(response).to be_successful - expect(response).to render_template "copy" + expect(response).to render_template 'copy' end - context "as non authorized user" do + context 'as non authorized user' do let(:user) { build_stubbed(:user) } before do @@ -155,7 +155,7 @@ end it "shows an error" do - get "copy", params: { id: project.id } + get 'copy', params: { id: project.id } expect(response.status).to eq 403 end end diff --git a/spec/controllers/projects_settings_menu_controller_spec.rb b/spec/controllers/projects_settings_menu_controller_spec.rb index 9dbc944a742c..380e4acc2e5e 100644 --- a/spec/controllers/projects_settings_menu_controller_spec.rb +++ b/spec/controllers/projects_settings_menu_controller_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::Settings::ModulesController, "menu" do +RSpec.describe Projects::Settings::ModulesController, 'menu' do let(:current_user) { build_stubbed(:user) } let(:project) do @@ -43,84 +43,84 @@ login_as(current_user) end - shared_examples_for "renders the modules show page" do - it "renders show" do - get("show", params:) + shared_examples_for 'renders the modules show page' do + it 'renders show' do + get('show', params:) expect(response).to be_successful - expect(response).to render_template "projects/settings/modules/show" + expect(response).to render_template 'projects/settings/modules/show' end end - shared_examples_for "has selector" do |selector| + shared_examples_for 'has selector' do |selector| render_views it do - get("show", params:) + get('show', params:) expect(response.body).to have_selector selector end end - shared_examples_for "has no selector" do |selector| + shared_examples_for 'has no selector' do |selector| render_views it do - get("show", params:) + get('show', params:) expect(response.body).to have_no_selector selector end end - describe "show" do - describe "without wiki" do + describe 'show' do + describe 'without wiki' do before do project.wiki.destroy project.reload end - it_behaves_like "renders the modules show page" + it_behaves_like 'renders the modules show page' - it_behaves_like "has no selector", "#main-menu a.wiki-wiki-menu-item" + it_behaves_like 'has no selector', '#main-menu a.wiki-wiki-menu-item' end - describe "with wiki" do - describe "without custom wiki menu items" do - it_behaves_like "has selector", "#main-menu a.wiki-wiki-menu-item" + describe 'with wiki' do + describe 'without custom wiki menu items' do + it_behaves_like 'has selector', '#main-menu a.wiki-wiki-menu-item' end - describe "with custom wiki menu item" do + describe 'with custom wiki menu item' do before do main_item = create(:wiki_menu_item, navigatable_id: project.wiki.id, - name: "example", - title: "Example Title") + name: 'example', + title: 'Example Title') create(:wiki_menu_item, navigatable_id: project.wiki.id, - name: "sub", - title: "Sub Title", + name: 'sub', + title: 'Sub Title', parent_id: main_item.id) end - it_behaves_like "renders the modules show page" + it_behaves_like 'renders the modules show page' - it_behaves_like "has selector", "#main-menu a.wiki-example-menu-item" + it_behaves_like 'has selector', '#main-menu a.wiki-example-menu-item' - it_behaves_like "has selector", "#main-menu a.wiki-sub-menu-item" + it_behaves_like 'has selector', '#main-menu a.wiki-sub-menu-item' end end - describe "with activated activity module" do + describe 'with activated activity module' do let(:enabled_modules) { %w[activity] } - it_behaves_like "renders the modules show page" + it_behaves_like 'renders the modules show page' - it_behaves_like "has selector", "#main-menu a.activity-menu-item" + it_behaves_like 'has selector', '#main-menu a.activity-menu-item' end - describe "without activated activity module" do - it_behaves_like "renders the modules show page" + describe 'without activated activity module' do + it_behaves_like 'renders the modules show page' - it_behaves_like "has no selector", "#main-menu a.activity-menu-item" + it_behaves_like 'has no selector', '#main-menu a.activity-menu-item' end end end diff --git a/spec/controllers/queries/params_parser_spec.rb b/spec/controllers/queries/params_parser_spec.rb index 49fb4569d533..a4fcae942e0c 100644 --- a/spec/controllers/queries/params_parser_spec.rb +++ b/spec/controllers/queries/params_parser_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::ParamsParser, type: :model do let(:params) do @@ -37,65 +37,65 @@ subject { described_class.parse(params.with_indifferent_access) } - describe ".parse" do - context "without any params" do - it "returns an empty array" do + describe '.parse' do + context 'without any params' do + it 'returns an empty array' do expect(subject) .to be_empty end end - context "with a single filter with a single value" do + context 'with a single filter with a single value' do let(:params) do { filters: "active = t" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: ["t"] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: ['t'] }) end end - context "with a single filter with multiple values having single quotes" do + context 'with a single filter with multiple values having single quotes' do let(:params) do { filters: "active = ['t', 'f']" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: %w[t f] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: %w[t f] }) end end - context "with a single filter with multiple values having double quotes" do + context 'with a single filter with multiple values having double quotes' do let(:params) do { filters: "active = [\"t\", \"f\"]" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: %w[t f] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: %w[t f] }) end end - context "with a single filter with a single value with , and &" do + context 'with a single filter with a single value with , and &' do let(:params) do { - filters: "active = something, or another thing & something else" + filters: 'active = something, or another thing & something else' } end - it "returns the parsed filter" do + it 'returns the parsed filter' do # This returns invalid filters but they will then be marked as invalid expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: ["something, or another thing "] }, - { attribute: "something", operator: "else", values: [""] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: ["something, or another thing "] }, + { attribute: 'something', operator: 'else', values: [''] }) end end @@ -106,165 +106,165 @@ } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: ["something, or another thing \" something else"] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: ["something, or another thing \" something else"] }) end end - context "with a single filter with a single value with ' (escaped)" do + context 'with a single filter with a single value with \' (escaped)' do let(:params) do { filters: "active = 'something, or another thing \\' something else'" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: ["something, or another thing ' something else"] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: ["something, or another thing ' something else"] }) end end - context "with a single filter with no value" do + context 'with a single filter with no value' do let(:params) do { - filters: "cf_512 !* " + filters: 'cf_512 !* ' } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "cf_512", operator: "!*", values: [""] }) + .to contain_exactly({ attribute: 'cf_512', operator: '!*', values: [''] }) end end - context "with multiple filters with the first having no value" do + context 'with multiple filters with the first having no value' do let(:params) do { filters: "active !* & id = \"1\"" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "!*", values: [] }, - { attribute: "id", operator: "=", values: ["1"] }) + .to contain_exactly({ attribute: 'active', operator: '!*', values: [] }, + { attribute: 'id', operator: '=', values: ["1"] }) end end - context "with multiple filters with ampersand as a filter value" do + context 'with multiple filters with ampersand as a filter value' do let(:params) do { filters: "active = \"t\" & name_and_identifier ~ \"abc & def\"" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: ["t"] }, - { attribute: "name_and_identifier", operator: "~", values: ["abc & def"] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: ["t"] }, + { attribute: 'name_and_identifier', operator: '~', values: ["abc & def"] }) end end - context "with a corrupt filter only having a key" do + context 'with a corrupt filter only having a key' do let(:params) do { filters: "active" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "", values: [""] }) + .to contain_exactly({ attribute: 'active', operator: '', values: [""] }) end end - context "with a corrupt filter having opening braces but no closing ones" do + context 'with a corrupt filter having opening braces but no closing ones' do let(:params) do { filters: "active = [\"t\", \"f\"" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: %w[t f] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: %w[t f] }) end end - context "with a corrupt filter having opening double quotes but no closing ones" do + context 'with a corrupt filter having opening double quotes but no closing ones' do let(:params) do { filters: 'active = "t' } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: %w[t] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: %w[t] }) end end - context "with a corrupt filter having opening single quotes but no closing ones" do + context 'with a corrupt filter having opening single quotes but no closing ones' do let(:params) do { filters: "active = 't" } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:filters]) - .to contain_exactly({ attribute: "active", operator: "=", values: %w[t] }) + .to contain_exactly({ attribute: 'active', operator: '=', values: %w[t] }) end end - context "with sortBy with a single value" do + context 'with sortBy with a single value' do let(:params) do { sortBy: JSON.dump([%w[name asc]]) } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:orders]) - .to eql [{ attribute: "name", direction: "asc" }] + .to eql [{ attribute: 'name', direction: 'asc' }] end end - context "with sortBy with a multiple value" do + context 'with sortBy with a multiple value' do let(:params) do { sortBy: JSON.dump([%w[name asc], %w[created_at desc]]) } end - it "returns the parsed filter" do + it 'returns the parsed filter' do expect(subject[:orders]) - .to eql [{ attribute: "name", direction: "asc" }, { attribute: "created_at", direction: "desc" }] + .to eql [{ attribute: 'name', direction: 'asc' }, { attribute: 'created_at', direction: 'desc' }] end end - context "with an invalid sortBy" do + context 'with an invalid sortBy' do let(:params) do { sortBy: "[sjfkdsjfkd}" } end - it "returns an invalid sort order" do + it 'returns an invalid sort order' do expect(subject[:orders]) - .to eql [{ attribute: "invalid", direction: "asc" }] + .to eql [{ attribute: 'invalid', direction: 'asc' }] end end - context "with multiple columns" do + context 'with multiple columns' do let(:params) do { columns: "name cf_1 project_status" } end - it "returns an invalid sort order" do + it 'returns an invalid sort order' do expect(subject[:selects]) .to eql %w[name cf_1 project_status] end diff --git a/spec/controllers/repositories_controller_spec.rb b/spec/controllers/repositories_controller_spec.rb index 5f05009126f1..2961d05f479a 100644 --- a/spec/controllers/repositories_controller_spec.rb +++ b/spec/controllers/repositories_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe RepositoriesController do let(:project) do @@ -38,16 +38,16 @@ create(:user, member_with_roles: { project => role }) end let(:role) { create(:project_role, permissions: []) } - let (:url) { "file:///tmp/something/does/not/exist.svn" } + let (:url) { 'file:///tmp/something/does/not/exist.svn' } let(:repository) do - allow(Setting).to receive(:enabled_scm).and_return(["subversion"]) + allow(Setting).to receive(:enabled_scm).and_return(['subversion']) repo = build_stubbed(:repository_subversion, - scm_type: "local", + scm_type: 'local', url:, project:) - allow(repo).to receive(:default_branch).and_return("master") - allow(repo).to receive(:branches).and_return(["master"]) + allow(repo).to receive(:default_branch).and_return('master') + allow(repo).to receive(:branches).and_return(['master']) allow(repo).to receive(:save).and_return(true) repo @@ -58,7 +58,7 @@ allow(project).to receive(:repository).and_return(repository) end - describe "manages the repository" do + describe 'manages the repository' do let(:role) { create(:project_role, permissions: [:manage_repository]) } before do @@ -66,45 +66,45 @@ allow(controller).to receive(:authorize).and_return(true) end - context "with #destroy" do + context 'with #destroy' do before do allow(repository).to receive(:destroy).and_return(true) delete :destroy, params: { project_id: project.id }, xhr: true end - it "redirects to settings" do + it 'redirects to settings' do expect(response).to redirect_to project_settings_repository_path(project.identifier) end end - context "with #update" do + context 'with #update' do before do put :update, params: { project_id: project.id }, xhr: true end - it "redirects to settings" do + it 'redirects to settings' do expect(response).to redirect_to project_settings_repository_path(project.identifier) end end - context "with #create" do + context 'with #create' do before do post :create, params: { project_id: project.id, - scm_vendor: "subversion", - scm_type: "local", - url: "file:///tmp/repo.svn/" + scm_vendor: 'subversion', + scm_type: 'local', + url: 'file:///tmp/repo.svn/' } end - it "redirects to settings" do + it 'redirects to settings' do expect(response).to redirect_to project_settings_repository_path(project.identifier) end end end - describe "with empty repository" do + describe 'with empty repository' do let(:role) { create(:project_role, permissions: [:browse_repository]) } before do @@ -113,25 +113,25 @@ .and_raise(OpenProject::SCM::Exceptions::SCMEmpty) end - context "with #show" do + context 'with #show' do before do get :show, params: { project_id: project.identifier } end - it "renders an empty warning view" do - expect(response).to render_template "repositories/empty" - expect(response.code).to eq("200") + it 'renders an empty warning view' do + expect(response).to render_template 'repositories/empty' + expect(response.code).to eq('200') end end - context "with #show and checkout" do + context 'with #show and checkout' do render_views let(:checkout_hash) do { - "subversion" => { "enabled" => "1", - "text" => "foo", - "base_url" => "http://localhost" } + 'subversion' => { 'enabled' => '1', + 'text' => 'foo', + 'base_url' => 'http://localhost' } } end @@ -140,15 +140,15 @@ get :show, params: { project_id: project.identifier } end - it "renders an empty warning view" do - expect(response).to render_template "repositories/empty" - expect(response).to render_template partial: "repositories/_checkout_instructions" - expect(response.code).to eq("200") + it 'renders an empty warning view' do + expect(response).to render_template 'repositories/empty' + expect(response).to render_template partial: 'repositories/_checkout_instructions' + expect(response.code).to eq('200') end end end - describe "with subversion repository" do + describe 'with subversion repository' do with_subversion_repository do |repo_dir| let(:root_url) { repo_dir } let(:url) { "file://#{root_url}" } @@ -157,96 +157,96 @@ create(:repository_subversion, project:, url:, root_url: url) end - describe "commits per author graph" do + describe 'commits per author graph' do before do - get :graph, params: { project_id: project.identifier, graph: "commits_per_author" } + get :graph, params: { project_id: project.identifier, graph: 'commits_per_author' } end - context "requested by an authorized user" do + context 'requested by an authorized user' do let(:role) do create(:project_role, permissions: %i[browse_repository view_commit_author_statistics]) end - it "is successful" do + it 'is successful' do expect(response).to be_successful end - it "has the right content type" do - expect(response.content_type).to eq("image/svg+xml") + it 'has the right content type' do + expect(response.content_type).to eq('image/svg+xml') end end - context "requested by an unauthorized user" do + context 'requested by an unauthorized user' do let(:role) { create(:project_role, permissions: [:browse_repository]) } - it "returns 403" do - expect(response.code).to eq("403") + it 'returns 403' do + expect(response.code).to eq('403') end end end - describe "committers" do + describe 'committers' do let(:role) { create(:project_role, permissions: [:manage_repository]) } - describe "#get" do + describe '#get' do before do get :committers, params: { project_id: project.id } end - it "is successful" do + it 'is successful' do expect(response).to be_successful - expect(response).to render_template "repositories/committers" + expect(response).to render_template 'repositories/committers' end end - describe "#post" do + describe '#post' do before do repository.fetch_changesets - post :committers, params: { project_id: project.id, committers: { "0" => ["oliver", user.id] }, - commit: "Update" } + post :committers, params: { project_id: project.id, committers: { '0' => ['oliver', user.id] }, + commit: 'Update' } end - it "is successful" do + it 'is successful' do expect(response).to redirect_to committers_project_repository_path(project) - expect(repository.committers).to include(["oliver", user.id]) + expect(repository.committers).to include(['oliver', user.id]) end end end - describe "stats" do + describe 'stats' do before do get :stats, params: { project_id: project.identifier } end - describe "requested by a user with view_commit_author_statistics permission" do + describe 'requested by a user with view_commit_author_statistics permission' do let(:role) do create(:project_role, permissions: %i[browse_repository view_commit_author_statistics]) end - it "show the commits per author graph" do + it 'show the commits per author graph' do expect(assigns(:show_commits_per_author)).to be(true) end end - describe "requested by a user without view_commit_author_statistics permission" do + describe 'requested by a user without view_commit_author_statistics permission' do let(:role) { create(:project_role, permissions: [:browse_repository]) } - it "does not show the commits per author graph" do + it 'does not show the commits per author graph' do expect(assigns(:show_commits_per_author)).to be(false) end end end - shared_examples "renders the repository title" do |active_breadcrumb| + shared_examples 'renders the repository title' do |active_breadcrumb| it do expect(response).to be_successful - expect(response.body).to have_css(".repository-breadcrumbs", text: active_breadcrumb) + expect(response.body).to have_css('.repository-breadcrumbs', text: active_breadcrumb) end end - describe "show" do + describe 'show' do render_views let(:role) { create(:project_role, permissions: [:browse_repository]) } @@ -254,20 +254,20 @@ get :show, params: { project_id: project.identifier, repo_path: path } end - context "with brackets" do - let(:path) { "subversion_test/[folder_with_brackets]" } + context 'with brackets' do + let(:path) { 'subversion_test/[folder_with_brackets]' } - it_behaves_like "renders the repository title", "[folder_with_brackets]" + it_behaves_like 'renders the repository title', '[folder_with_brackets]' end - context "with unicode" do - let(:path) { "Föbar/äm/Sägepütz!%5D§" } + context 'with unicode' do + let(:path) { 'Föbar/äm/Sägepütz!%5D§' } - it_behaves_like "renders the repository title", "Sägepütz!%5D§" + it_behaves_like 'renders the repository title', 'Sägepütz!%5D§' end end - describe "changes" do + describe 'changes' do render_views let(:role) { create(:project_role, permissions: [:browse_repository]) } @@ -276,57 +276,57 @@ expect(response).to be_successful end - context "with brackets" do - let(:path) { "subversion_test/[folder_with_brackets]" } + context 'with brackets' do + let(:path) { 'subversion_test/[folder_with_brackets]' } - it_behaves_like "renders the repository title", "[folder_with_brackets]" + it_behaves_like 'renders the repository title', '[folder_with_brackets]' end - context "with unicode" do - let(:path) { "Föbar/äm" } + context 'with unicode' do + let(:path) { 'Föbar/äm' } - it_behaves_like "renders the repository title", "äm" + it_behaves_like 'renders the repository title', 'äm' end end - describe "checkout path" do + describe 'checkout path' do render_views let(:role) { create(:project_role, permissions: [:browse_repository]) } let(:checkout_hash) do { - "subversion" => { "enabled" => "1", - "text" => "foo", - "base_url" => "http://localhost" } + 'subversion' => { 'enabled' => '1', + 'text' => 'foo', + 'base_url' => 'http://localhost' } } end before do allow(Setting).to receive(:repository_checkout_data).and_return(checkout_hash) - get :show, params: { project_id: project.identifier, repo_path: "subversion_test" } + get :show, params: { project_id: project.identifier, repo_path: 'subversion_test' } end - it "renders an empty warning view" do + it 'renders an empty warning view' do expected_path = "http://localhost/#{project.identifier}/subversion_test" - expect(response.code).to eq("200") - expect(response).to render_template partial: "repositories/_checkout_instructions" + expect(response.code).to eq('200') + expect(response).to render_template partial: 'repositories/_checkout_instructions' expect(response.body).to have_css("#repository-checkout-url[value='#{expected_path}']") end end end end - describe "when not being logged in" do + describe 'when not being logged in' do let(:anonymous) { build_stubbed(:anonymous) } before do login_as(anonymous) end - describe "#show" do - it "redirects to login while preserving the path" do - params = { repo_path: "aDir/within/aDir", rev: "42", project_id: project.id } + describe '#show' do + it 'redirects to login while preserving the path' do + params = { repo_path: 'aDir/within/aDir', rev: '42', project_id: project.id } get(:show, params:) expect(response) diff --git a/spec/controllers/roles_controller_spec.rb b/spec/controllers/roles_controller_spec.rb index ef52683f50d2..74cb660e332d 100644 --- a/spec/controllers/roles_controller_spec.rb +++ b/spec/controllers/roles_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe RolesController do let(:user) do @@ -35,28 +35,28 @@ let(:params) do { role: { - name: "A role name", - permissions: ["add_work_packages", "edit_work_packages", "log_own_time", ""], - assignable: "0" + name: 'A role name', + permissions: ['add_work_packages', 'edit_work_packages', 'log_own_time', ''], + assignable: '0' }, - copy_workflow_from: "5" + copy_workflow_from: '5' } end current_user { user } - describe "#create" do - let(:new_role) { double("role double") } + describe '#create' do + let(:new_role) { double('role double') } let(:service_call) { ServiceResult.success(result: new_role) } let(:create_params) do cp = ActionController::Parameters.new(params[:role]) - .merge(global_role: nil, copy_workflow_from: "5") + .merge(global_role: nil, copy_workflow_from: '5') cp.permit! cp end let(:create_service) do - service_double = double("create service") + service_double = double('create service') expect(Roles::CreateService) .to receive(:new) @@ -75,89 +75,89 @@ post :create, params: end - context "success" do - context "for a member role" do - it "redirects to roles#index" do + context 'success' do + context 'for a member role' do + it 'redirects to roles#index' do expect(response) .to redirect_to(roles_path) end - it "has a flash message" do + it 'has a flash message' do expect(flash[:notice]) .to eql I18n.t(:notice_successful_create) end end - context "for a global role" do + context 'for a global role' do let(:params) do { role: { - name: "A role name", - permissions: ["add_work_packages", "edit_work_packages", "log_time", ""], - assignable: "0" + name: 'A role name', + permissions: ['add_work_packages', 'edit_work_packages', 'log_time', ''], + assignable: '0' }, - global_role: "1", - copy_workflow_from: "5" + global_role: '1', + copy_workflow_from: '5' } end let(:create_params) do cp = ActionController::Parameters.new(params[:role]) - .merge(global_role: "1", copy_workflow_from: "5") + .merge(global_role: '1', copy_workflow_from: '5') cp.permit! cp end - it "redirects to roles#index" do + it 'redirects to roles#index' do expect(response) .to redirect_to(roles_path) end - it "has a flash message" do + it 'has a flash message' do expect(flash[:notice]) .to eql I18n.t(:notice_successful_create) end end end - context "failure" do + context 'failure' do let(:service_call) { ServiceResult.failure(result: new_role) } - it "returns a 200 OK" do + it 'returns a 200 OK' do expect(response) .to have_http_status(:ok) end - it "renders the new template" do + it 'renders the new template' do expect(response) - .to render_template("roles/new") + .to render_template('roles/new') end - it "has the service call assigned" do + it 'has the service call assigned' do expect(assigns[:call]) .to eql service_call end - it "has the role assigned" do + it 'has the role assigned' do expect(assigns[:role]) .to eql new_role end end end - describe "#update" do + describe '#update' do let(:params) do { id: role.id, role: { - name: "A role name", - permissions: ["add_work_packages", "edit_work_packages", "log_time", ""], - assignable: "0" + name: 'A role name', + permissions: ['add_work_packages', 'edit_work_packages', 'log_time', ''], + assignable: '0' } } end let(:role) do - double("role double", id: 6).tap do |d| + double('role double', id: 6).tap do |d| allow(Role) .to receive(:find) .with(d.id.to_s) @@ -172,7 +172,7 @@ cp end let(:update_service) do - service_double = double("update service") + service_double = double('update service') expect(Roles::UpdateService) .to receive(:new) @@ -191,60 +191,60 @@ put :update, params: end - context "success" do - it "redirects to roles#index" do + context 'success' do + it 'redirects to roles#index' do expect(response) .to redirect_to(roles_path) end - it "has a flash message" do + it 'has a flash message' do expect(flash[:notice]) .to eql I18n.t(:notice_successful_update) end end - context "failure" do + context 'failure' do let(:service_call) { ServiceResult.failure(result: role) } - it "returns a 200 OK" do + it 'returns a 200 OK' do expect(response) .to have_http_status(:ok) end - it "renders the edit template" do + it 'renders the edit template' do expect(response) - .to render_template("roles/edit") + .to render_template('roles/edit') end - it "has the service call assigned" do + it 'has the service call assigned' do expect(assigns[:call]) .to eql service_call end - it "has the role assigned" do + it 'has the role assigned' do expect(assigns[:role]) .to eql role end end end - describe "#bulk_update" do + describe '#bulk_update' do let(:params) do { - permissions: { "0" => "", "1" => ["edit_work_packages"], "3" => %w(add_work_packages delete_work_packages) } + permissions: { '0' => '', '1' => ['edit_work_packages'], '3' => %w(add_work_packages delete_work_packages) } } end let(:role0) do - double("role double", id: 0) + double('role double', id: 0) end let(:role1) do - double("role double", id: 1) + double('role double', id: 1) end let(:role2) do - double("role double", id: 2) + double('role double', id: 2) end let(:role3) do - double("role double", id: 3) + double('role double', id: 3) end let(:roles) do [role0, role1, role2, role3] @@ -264,7 +264,7 @@ { permissions: [] } end let(:update_service0) do - service_double = double("update service") + service_double = double('update service') expect(Roles::UpdateService) .to receive(:new) @@ -277,10 +277,10 @@ .and_return(service_call0) end let(:update_params1) do - { permissions: params[:permissions]["1"] } + { permissions: params[:permissions]['1'] } end let(:update_service1) do - service_double = double("update service") + service_double = double('update service') expect(Roles::UpdateService) .to receive(:new) @@ -296,7 +296,7 @@ { permissions: [] } end let(:update_service2) do - service_double = double("update service") + service_double = double('update service') expect(Roles::UpdateService) .to receive(:new) @@ -309,10 +309,10 @@ .and_return(service_call2) end let(:update_params3) do - { permissions: params[:permissions]["3"] } + { permissions: params[:permissions]['3'] } end let(:update_service3) do - service_double = double("update service") + service_double = double('update service') expect(Roles::UpdateService) .to receive(:new) @@ -334,51 +334,51 @@ put :bulk_update, params: end - context "success" do - it "redirects to roles#index" do + context 'success' do + it 'redirects to roles#index' do expect(response) .to redirect_to(roles_path) end - it "has a flash message" do + it 'has a flash message' do expect(flash[:notice]) .to eql I18n.t(:notice_successful_update) end end - context "failure" do + context 'failure' do let(:service_call2) { ServiceResult.failure(result: role2) } - it "returns a 200 OK" do + it 'returns a 200 OK' do expect(response) .to have_http_status(:ok) end - it "renders the report template" do + it 'renders the report template' do expect(response) - .to render_template("roles/report") + .to render_template('roles/report') end - it "has the service call assigned" do + it 'has the service call assigned' do expect(assigns[:calls]) .to contain_exactly(service_call0, service_call1, service_call2, service_call3) end - it "has the roles assigned" do + it 'has the roles assigned' do expect(assigns[:roles]) .to match_array roles end end end - describe "#destroy" do + describe '#destroy' do let(:role) { create(:project_role) } let(:params) { { id: role.id } } subject { delete(:destroy, params:) } - context "with the role not in use" do - it "redirects and destroyes the role" do + context 'with the role not in use' do + it 'redirects and destroyes the role' do allow_any_instance_of(Role).to receive(:permissions).and_return([:read_files]) role expect(Role.count).to eq(1) @@ -387,14 +387,14 @@ subject expect(enqueued_jobs.count).to eq(1) - expect(enqueued_jobs[0][:job]).to eq(Storages::ManageNextcloudIntegrationJob) + expect(enqueued_jobs[0][:job]).to eq(Storages::ManageNextcloudIntegrationEventsJob) expect(response).to redirect_to roles_path expect(Role.count).to eq(0) end end - context "with the role in use" do - it "redirects with a flash error" do + context 'with the role in use' do + it 'redirects with a flash error' do allow_any_instance_of(Role).to receive(:deletable?).and_return(false) role expect(Role.count).to eq(1) @@ -410,7 +410,7 @@ end end - describe "#report" do + describe '#report' do let!(:stub_roles_scope) do allow(controller) .to receive(:roles_scope) @@ -424,22 +424,22 @@ delete :report end - it "is successful" do + it 'is successful' do expect(response) .to have_http_status :ok end - it "renders the template" do + it 'renders the template' do expect(response) .to render_template :report end - it "assigns permissions" do + it 'assigns permissions' do expect(assigns(:permissions)) .to match OpenProject::AccessControl.permissions.reject(&:public?) end - it "assigns roles" do + it 'assigns roles' do expect(assigns(:roles)) .to match roles end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index a3623afb008e..84b81c44a538 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SearchController do shared_let(:project) do create(:project, - name: "eCookbook") + name: 'eCookbook') end shared_let(:other_project) do create(:project, - name: "Other project") + name: 'Other project') end shared_let(:subproject) do create(:project, - name: "Child project", + name: 'Child project', parent: project) end @@ -61,69 +61,69 @@ shared_let(:work_package_1) do create(:work_package, - subject: "This is a test issue", + subject: 'This is a test issue', project:) end shared_let(:work_package_2) do create(:work_package, - subject: "Issue test 2", + subject: 'Issue test 2', project:, status: create(:closed_status)) end shared_let(:work_package_3) do create(:work_package, - subject: "Issue test 3", + subject: 'Issue test 3', project: subproject) end shared_let(:work_package_4) do create(:work_package, - subject: "Issue test 4", + subject: 'Issue test 4', project: other_project) end - shared_examples_for "successful search" do + shared_examples_for 'successful search' do it { expect(response).to be_successful } - it { expect(response).to render_template("index") } + it { expect(response).to render_template('index') } end before { allow(User).to receive(:current).and_return user } - describe "project search" do - context "without a search parameter" do + describe 'project search' do + context 'without a search parameter' do before { get :index } - it_behaves_like "successful search" + it_behaves_like 'successful search' end - context "search parameter" do - context "is a search string" do + context 'search parameter' do + context 'is a search string' do before do - get :index, params: { q: "cook" } + get :index, params: { q: 'cook' } end - it_behaves_like "successful search" + it_behaves_like 'successful search' end end end - describe "scoped project search" do + describe 'scoped project search' do before { get :index, params: { project_id: project.id } } - it_behaves_like "successful search" + it_behaves_like 'successful search' it { expect(assigns(:project).id).to be(project.id) } end - describe "searching in all modules" do - context "when searching in all projects" do - before { get :index, params: { q: "issue", scope: "all" } } + describe 'searching in all modules' do + context 'when searching in all projects' do + before { get :index, params: { q: 'issue', scope: 'all' } } - it_behaves_like "successful search" + it_behaves_like 'successful search' - describe "#result" do + describe '#result' do it { expect(assigns(:results).count).to be(4) } it { expect(assigns(:results)).to include(work_package_1) } it { expect(assigns(:results)).to include(work_package_2) } @@ -132,34 +132,34 @@ it { expect(assigns(:results)).not_to include(work_package_4) } end - describe "#results_count" do + describe '#results_count' do it { expect(assigns(:results_count)).to be_a(Hash) } - it { expect(assigns(:results_count)["work_packages"]).to be(3) } + it { expect(assigns(:results_count)['work_packages']).to be(3) } end end - context "when searching in all projects with an untransliterable character" do + context 'when searching in all projects with an untransliterable character' do before do - work_package_1.update_column(:subject, "Something 会议 something") - get :index, params: { q: "会议", scope: "all" } + work_package_1.update_column(:subject, 'Something 会议 something') + get :index, params: { q: '会议', scope: 'all' } end - it_behaves_like "successful search" + it_behaves_like 'successful search' - it "returns the result", :aggregate_failures do + it 'returns the result', :aggregate_failures do expect(assigns(:results).count).to be(1) expect(assigns(:results)).to include(work_package_1) expect(assigns(:results_count)).to be_a(Hash) - expect(assigns(:results_count)["work_packages"]).to be(1) + expect(assigns(:results_count)['work_packages']).to be(1) end end - context "when searching in project and its subprojects" do - before { get :index, params: { q: "issue", project_id: project.id, scope: "subprojects" } } + context 'when searching in project and its subprojects' do + before { get :index, params: { q: 'issue', project_id: project.id, scope: 'subprojects' } } - it_behaves_like "successful search" + it_behaves_like 'successful search' - describe "#result" do + describe '#result' do it { expect(assigns(:results).count).to be(4) } it { expect(assigns(:results)).to include(work_package_1) } it { expect(assigns(:results)).to include(work_package_2) } @@ -169,12 +169,12 @@ end end - context "when searching in project without its subprojects" do - before { get :index, params: { q: "issue", project_id: project.id, scope: "current_project" } } + context 'when searching in project without its subprojects' do + before { get :index, params: { q: 'issue', project_id: project.id, scope: 'current_project' } } - it_behaves_like "successful search" + it_behaves_like 'successful search' - describe "#result" do + describe '#result' do it { expect(assigns(:results).count).to be(3) } it { expect(assigns(:results)).to include(work_package_1) } it { expect(assigns(:results)).to include(work_package_2) } @@ -184,25 +184,25 @@ end end - context "when searching for a note" do + context 'when searching for a note' do let!(:note_1) do create(:work_package_journal, journable_id: work_package_1.id, - notes: "Test note 1", + notes: 'Test note 1', version: 2) end let!(:note_2) do create(:work_package_journal, journable_id: work_package_1.id, - notes: "Special note 2", + notes: 'Special note 2', version: 3) end before do - get :index, params: { q: "note" } + get :index, params: { q: 'note' } end - describe "second note predecessor" do + describe 'second note predecessor' do subject { note_2.send :predecessor } it { is_expected.to eq note_1 } @@ -210,43 +210,43 @@ it { expect(subject.data).not_to be_nil } end - it_behaves_like "successful search" + it_behaves_like 'successful search' - describe "#result" do + describe '#result' do it { expect(assigns(:results).count).to be 1 } it { expect(assigns(:results)).to include work_package_1 } - it { expect(assigns(:tokens)).to include "note" } + it { expect(assigns(:tokens)).to include 'note' } end end end - describe "helper methods" do - describe "#scan_query_tokens" do + describe 'helper methods' do + describe '#scan_query_tokens' do subject { @controller.send(:scan_query_tokens, query) } - context "with one token" do - let(:query) { "word" } + context 'with one token' do + let(:query) { 'word' } it { is_expected.to eq %w(word) } - context "with double quotes" do + context 'with double quotes' do let(:query) { '"hello world"' } - it { is_expected.to eq ["hello world"] } + it { is_expected.to eq ['hello world'] } end end - context "with multiple tokens" do - let(:query) { "hello world something-hyphenated" } + context 'with multiple tokens' do + let(:query) { 'hello world something-hyphenated' } it { is_expected.to eq %w(hello world something-hyphenated) } - context "with double quotes" do + context 'with double quotes' do let(:query) { 'hello "fallen world" something-hyphenated' } - it { is_expected.to eq ["hello", "fallen world", "something-hyphenated"] } + it { is_expected.to eq ['hello', 'fallen world', 'something-hyphenated'] } end end end diff --git a/spec/controllers/statuses_controller_spec.rb b/spec/controllers/statuses_controller_spec.rb index ee13fa27b90e..6b6b6667e424 100644 --- a/spec/controllers/statuses_controller_spec.rb +++ b/spec/controllers/statuses_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe StatusesController do shared_let(:user) { create(:admin) } @@ -34,7 +34,7 @@ before { login_as(user) } - shared_examples_for "response" do + shared_examples_for 'response' do subject { response } it { is_expected.to be_successful } @@ -42,7 +42,7 @@ it { is_expected.to render_template(template) } end - shared_examples_for "redirect" do + shared_examples_for 'redirect' do subject { response } it { is_expected.to be_redirect } @@ -50,45 +50,45 @@ it { is_expected.to redirect_to(action: :index) } end - shared_examples_for "statuses" do + shared_examples_for 'statuses' do subject { Status.find_by(name:) } it { is_expected.not_to be_nil } end - describe "#index" do - let(:template) { "index" } + describe '#index' do + let(:template) { 'index' } before { get :index } - it_behaves_like "response" + it_behaves_like 'response' end - describe "#new" do - let(:template) { "new" } + describe '#new' do + let(:template) { 'new' } before { get :new } - it_behaves_like "response" + it_behaves_like 'response' end - describe "#create" do - let(:name) { "New Status" } + describe '#create' do + let(:name) { 'New Status' } before do post :create, params: { status: { name: } } end - it_behaves_like "statuses" + it_behaves_like 'statuses' - it_behaves_like "redirect" + it_behaves_like 'redirect' end - describe "#edit" do - let(:template) { "edit" } + describe '#edit' do + let(:template) { 'edit' } - context "default" do + context 'default' do let!(:status_default) do create(:status, is_default: true) @@ -99,41 +99,41 @@ params: { id: status_default.id } end - it_behaves_like "response" + it_behaves_like 'response' - describe "#view" do + describe '#view' do render_views it do - assert_select "p", + assert_select 'p', { content: Status.human_attribute_name(:is_default) }, false end end end - context "no_default" do + context 'no_default' do before do status get :edit, params: { id: status.id } end - it_behaves_like "response" + it_behaves_like 'response' - describe "#view" do + describe '#view' do render_views it do - assert_select "div", + assert_select 'div', content: Status.human_attribute_name(:is_default) end end end end - describe "#update" do - let(:name) { "Renamed Status" } + describe '#update' do + let(:name) { 'Renamed Status' } before do status @@ -145,21 +145,21 @@ } end - it_behaves_like "statuses" + it_behaves_like 'statuses' - it_behaves_like "redirect" + it_behaves_like 'redirect' end - describe "#destroy" do + describe '#destroy' do let(:name) { status.name } - shared_examples_for "destroyed" do + shared_examples_for 'destroyed' do subject { Status.find_by(name:) } it { is_expected.to be_nil } end - context "unused" do + context 'unused' do before do delete :destroy, params: { id: status.id } end @@ -168,12 +168,12 @@ Status.delete_all end - it_behaves_like "destroyed" + it_behaves_like 'destroyed' - it_behaves_like "redirect" + it_behaves_like 'redirect' end - context "used" do + context 'used' do let(:work_package) do create(:work_package, status:) @@ -185,12 +185,12 @@ delete :destroy, params: { id: status.id } end - it_behaves_like "statuses" + it_behaves_like 'statuses' - it_behaves_like "redirect" + it_behaves_like 'redirect' end - context "default" do + context 'default' do let!(:status_default) do create(:status, is_default: true) @@ -200,39 +200,39 @@ delete :destroy, params: { id: status_default.id } end - it_behaves_like "statuses" + it_behaves_like 'statuses' - it_behaves_like "redirect" + it_behaves_like 'redirect' - it "shows the right flash message" do - expect(flash[:error]).to eq(I18n.t("error_unable_delete_default_status")) + it 'shows the right flash message' do + expect(flash[:error]).to eq(I18n.t('error_unable_delete_default_status')) end end end - describe "#update_work_package_done_ratio" do + describe '#update_work_package_done_ratio' do context "with 'work_package_done_ratio' using 'field'" do before do - allow(Setting).to receive(:work_package_done_ratio).and_return "field" + allow(Setting).to receive(:work_package_done_ratio).and_return 'field' post :update_work_package_done_ratio end - it { is_expected.to set_flash[:error].to(I18n.t("error_work_package_done_ratios_not_updated")) } + it { is_expected.to set_flash[:error].to(I18n.t('error_work_package_done_ratios_not_updated')) } - it_behaves_like "redirect" + it_behaves_like 'redirect' end context "with 'work_package_done_ratio' using 'status'" do before do - allow(Setting).to receive(:work_package_done_ratio).and_return "status" + allow(Setting).to receive(:work_package_done_ratio).and_return 'status' post :update_work_package_done_ratio end - it { is_expected.to set_flash[:notice].to(I18n.t("notice_work_package_done_ratios_updated")) } + it { is_expected.to set_flash[:notice].to(I18n.t('notice_work_package_done_ratios_updated')) } - it_behaves_like "redirect" + it_behaves_like 'redirect' end end end diff --git a/spec/controllers/sys_controller_spec.rb b/spec/controllers/sys_controller_spec.rb index a9c8aeb003b4..47bbff6619eb 100644 --- a/spec/controllers/sys_controller_spec.rb +++ b/spec/controllers/sys_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SysController, with_settings: { sys_api_enabled: true } do let(:commit_role) do @@ -34,15 +34,15 @@ end let(:browse_role) { create(:project_role, permissions: [:browse_repository]) } let(:guest_role) { create(:project_role, permissions: []) } - let(:valid_user_password) { "Top Secret Password" } + let(:valid_user_password) { 'Top Secret Password' } let(:valid_user) do create(:user, - login: "johndoe", + login: 'johndoe', password: valid_user_password, password_confirmation: valid_user_password) end - let(:api_key) { "12345678" } + let(:api_key) { '12345678' } let(:public) { false } let(:project) { create(:project, public:) } @@ -61,132 +61,132 @@ RequestStore.clear! end - describe "svn" do + describe 'svn' do let!(:repository) { create(:repository_subversion, project:) } - describe "repo_auth" do - context "for valid login, but no access to repo_auth" do + describe 'repo_auth' do + context 'for valid login, but no access to repo_auth' do before do - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: api_key, - repository: "without-access", - method: "GET" } + post 'repo_auth', params: { key: api_key, + repository: 'without-access', + method: 'GET' } end - it "responds 403 not allowed" do - expect(response.code).to eq("403") - expect(response.body).to eq("Not allowed") + it 'responds 403 not allowed' do + expect(response.code).to eq('403') + expect(response.body).to eq('Not allowed') end end - context "for valid login and user has read permission (role reporter) for project" do + context 'for valid login and user has read permission (role reporter) for project' do before do create(:member, user: valid_user, roles: [browse_role], project:) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) end - it "responds 200 okay dokay for GET" do - post "repo_auth", params: { key: api_key, + it 'responds 200 okay dokay for GET' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET" } + method: 'GET' } - expect(response.code).to eq("200") + expect(response.code).to eq('200') end - it "responds 403 not allowed for POST" do - post "repo_auth", params: { key: api_key, + it 'responds 403 not allowed for POST' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "POST" } + method: 'POST' } - expect(response.code).to eq("403") + expect(response.code).to eq('403') end end - context "for valid login and user has rw permission (role developer) for project" do + context 'for valid login and user has rw permission (role developer) for project' do before do create(:member, user: valid_user, roles: [commit_role], project:) valid_user.save - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) end - it "responds 200 okay dokay for GET" do - post "repo_auth", params: { key: api_key, + it 'responds 200 okay dokay for GET' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET" } + method: 'GET' } - expect(response.code).to eq("200") + expect(response.code).to eq('200') end - it "responds 200 okay dokay for POST" do - post "repo_auth", params: { key: api_key, + it 'responds 200 okay dokay for POST' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "POST" } + method: 'POST' } - expect(response.code).to eq("200") + expect(response.code).to eq('200') end end - context "for invalid login and user has role manager for project" do + context 'for invalid login and user has role manager for project' do before do create(:member, user: valid_user, roles: [commit_role], project:) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, - valid_user_password + "made invalid" + valid_user_password + 'made invalid' ) - post "repo_auth", params: { key: api_key, + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET" } + method: 'GET' } end - it "responds 401 auth required" do - expect(response.code).to eq("401") + it 'responds 401 auth required' do + expect(response.code).to eq('401') end end - context "for valid login and user is not member for project" do + context 'for valid login and user is not member for project' do before do - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: api_key, + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET" } + method: 'GET' } end - it "responds 403 not allowed" do - expect(response.code).to eq("403") + it 'responds 403 not allowed' do + expect(response.code).to eq('403') end end - context "for valid login and project is public" do + context 'for valid login and project is public' do let(:public) { true } before do @@ -196,134 +196,134 @@ roles: [browse_role], project: random_project) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: api_key, + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET" } + method: 'GET' } end - it "responds 200 OK" do - expect(response.code).to eq("200") + it 'responds 200 OK' do + expect(response.code).to eq('200') end end - context "for invalid credentials" do + context 'for invalid credentials' do before do - post "repo_auth", params: { key: api_key, - repository: "any-repo", - method: "GET" } + post 'repo_auth', params: { key: api_key, + repository: 'any-repo', + method: 'GET' } end - it "responds 401 auth required" do - expect(response.code).to eq("401") - expect(response.body).to eq("Authorization required") + it 'responds 401 auth required' do + expect(response.code).to eq('401') + expect(response.body).to eq('Authorization required') end end - context "for invalid api key" do - it "responds 403 for valid username/password" do - request.env["HTTP_AUTHORIZATION"] = + context 'for invalid api key' do + it 'responds 403 for valid username/password' do + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: "not_the_api_key", - repository: "any-repo", - method: "GET" } + post 'repo_auth', params: { key: 'not_the_api_key', + repository: 'any-repo', + method: 'GET' } - expect(response.code).to eq("403") + expect(response.code).to eq('403') expect(response.body) - .to eq("Access denied. Repository management WS is disabled or key is invalid.") + .to eq('Access denied. Repository management WS is disabled or key is invalid.') end - it "responds 403 for invalid username/password" do - request.env["HTTP_AUTHORIZATION"] = + it 'responds 403 for invalid username/password' do + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( - "invalid", - "invalid" + 'invalid', + 'invalid' ) - post "repo_auth", params: { key: "not_the_api_key", - repository: "any-repo", - method: "GET" } + post 'repo_auth', params: { key: 'not_the_api_key', + repository: 'any-repo', + method: 'GET' } - expect(response.code).to eq("403") + expect(response.code).to eq('403') expect(response.body) - .to eq("Access denied. Repository management WS is disabled or key is invalid.") + .to eq('Access denied. Repository management WS is disabled or key is invalid.') end end end end - describe "git" do + describe 'git' do let!(:repository) { create(:repository_git, project:) } - describe "repo_auth" do - context "for valid login, but no access to repo_auth" do + describe 'repo_auth' do + context 'for valid login, but no access to repo_auth' do before do - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: api_key, - repository: "without-access", - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + post 'repo_auth', params: { key: api_key, + repository: 'without-access', + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } end - it "responds 403 not allowed" do - expect(response.code).to eq("403") - expect(response.body).to eq("Not allowed") + it 'responds 403 not allowed' do + expect(response.code).to eq('403') + expect(response.body).to eq('Not allowed') end end - context "for valid login and user has read permission (role reporter) for project" do + context 'for valid login and user has read permission (role reporter) for project' do before do create(:member, user: valid_user, roles: [browse_role], project:) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) end - it "responds 200 okay dokay for read-only access" do - post "repo_auth", params: { key: api_key, + it 'responds 200 okay dokay for read-only access' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } - expect(response.code).to eq("200") + expect(response.code).to eq('200') end - it "responds 403 not allowed for write (push)" do - post "repo_auth", params: { key: api_key, + it 'responds 403 not allowed for write (push)' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "POST", - git_smart_http: "1", + method: 'POST', + git_smart_http: '1', uri: "/git/#{project.identifier}/git-receive-pack", - location: "/git" } + location: '/git' } - expect(response.code).to eq("403") + expect(response.code).to eq('403') end end - context "for valid login and user has rw permission (role developer) for project" do + context 'for valid login and user has rw permission (role developer) for project' do before do create(:member, user: valid_user, @@ -331,85 +331,85 @@ project:) valid_user.save - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) end - it "responds 200 okay dokay for GET" do - post "repo_auth", params: { key: api_key, + it 'responds 200 okay dokay for GET' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } - expect(response.code).to eq("200") + expect(response.code).to eq('200') end - it "responds 200 okay dokay for POST" do - post "repo_auth", params: { key: api_key, + it 'responds 200 okay dokay for POST' do + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "POST", - git_smart_http: "1", + method: 'POST', + git_smart_http: '1', uri: "/git/#{project.identifier}/git-receive-pack", - location: "/git" } + location: '/git' } - expect(response.code).to eq("200") + expect(response.code).to eq('200') end end - context "for invalid login and user has role manager for project" do + context 'for invalid login and user has role manager for project' do before do create(:member, user: valid_user, roles: [commit_role], project:) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, - valid_user_password + "made invalid" + valid_user_password + 'made invalid' ) - post "repo_auth", params: { key: api_key, + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } end - it "responds 401 auth required" do - expect(response.code).to eq("401") + it 'responds 401 auth required' do + expect(response.code).to eq('401') end end - context "for valid login and user is not member for project" do + context 'for valid login and user is not member for project' do before do project = create(:project, public: false) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: api_key, + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } end - it "responds 403 not allowed" do - expect(response.code).to eq("403") + it 'responds 403 not allowed' do + expect(response.code).to eq('403') end end - context "for valid login and project is public" do + context 'for valid login and project is public' do let(:public) { true } before do @@ -419,117 +419,117 @@ roles: [browse_role], project: random_project) - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: api_key, + post 'repo_auth', params: { key: api_key, repository: project.identifier, - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } end - it "responds 200 OK" do - expect(response.code).to eq("200") + it 'responds 200 OK' do + expect(response.code).to eq('200') end end - context "for invalid credentials" do + context 'for invalid credentials' do before do - post "repo_auth", params: { key: api_key, - repository: "any-repo", - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + post 'repo_auth', params: { key: api_key, + repository: 'any-repo', + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } end - it "responds 401 auth required" do - expect(response.code).to eq("401") - expect(response.body).to eq("Authorization required") + it 'responds 401 auth required' do + expect(response.code).to eq('401') + expect(response.body).to eq('Authorization required') end end - context "for invalid api key" do - it "responds 403 for valid username/password" do - request.env["HTTP_AUTHORIZATION"] = + context 'for invalid api key' do + it 'responds 403 for valid username/password' do + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - post "repo_auth", params: { key: "not_the_api_key", - repository: "any-repo", - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + post 'repo_auth', params: { key: 'not_the_api_key', + repository: 'any-repo', + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } - expect(response.code).to eq("403") + expect(response.code).to eq('403') expect(response.body) - .to eq("Access denied. Repository management WS is disabled or key is invalid.") + .to eq('Access denied. Repository management WS is disabled or key is invalid.') end - it "responds 403 for invalid username/password" do - request.env["HTTP_AUTHORIZATION"] = + it 'responds 403 for invalid username/password' do + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( - "invalid", - "invalid" + 'invalid', + 'invalid' ) - post "repo_auth", params: { key: "not_the_api_key", - repository: "any-repo", - method: "GET", - git_smart_http: "1", - uri: "/git", - location: "/git" } + post 'repo_auth', params: { key: 'not_the_api_key', + repository: 'any-repo', + method: 'GET', + git_smart_http: '1', + uri: '/git', + location: '/git' } - expect(response.code).to eq("403") + expect(response.code).to eq('403') expect(response.body) - .to eq("Access denied. Repository management WS is disabled or key is invalid.") + .to eq('Access denied. Repository management WS is disabled or key is invalid.') end end end end - describe "#cached_user_login" do + describe '#cached_user_login' do let(:cache_key) do OpenProject::RepositoryAuthentication::CACHE_PREFIX + Digest::SHA1.hexdigest("#{valid_user.login}#{valid_user_password}") end let(:cache_expiry) { OpenProject::RepositoryAuthentication::CACHE_EXPIRES_AFTER } - it "calls user_login only once when called twice" do + it 'calls user_login only once when called twice' do expect(controller).to receive(:user_login).once.and_return(valid_user) 2.times { controller.send(:cached_user_login, valid_user.login, valid_user_password) } end - it "returns the same as user_login for valid creds" do + it 'returns the same as user_login for valid creds' do expect(controller.send(:cached_user_login, valid_user.login, valid_user_password)) .to eq(controller.send(:user_login, valid_user.login, valid_user_password)) end - it "returns the same as user_login for invalid creds" do - expect(controller.send(:cached_user_login, "invalid", "invalid")) - .to eq(controller.send(:user_login, "invalid", "invalid")) + it 'returns the same as user_login for invalid creds' do + expect(controller.send(:cached_user_login, 'invalid', 'invalid')) + .to eq(controller.send(:user_login, 'invalid', 'invalid')) end - it "uses cache" do + it 'uses cache' do allow(Rails.cache).to receive(:fetch).and_call_original expect(Rails.cache).to receive(:fetch).with(cache_key, expires_in: cache_expiry) .and_return(Marshal.dump(valid_user.id.to_s)) controller.send(:cached_user_login, valid_user.login, valid_user_password) end - describe "with caching disabled" do + describe 'with caching disabled' do before do allow(Setting).to receive(:repository_authentication_caching_enabled?).and_return(false) end - it "does not use a cache" do + it 'does not use a cache' do allow(Rails.cache).to receive(:fetch).and_wrap_original do |m, *args, &block| expect(args.first).not_to eq(cache_key) m.call(*args, &block) @@ -539,28 +539,28 @@ end end - describe "update_required_storage" do + describe 'update_required_storage' do let(:force) { nil } let(:apikey) { Setting.sys_api_key } let(:last_updated) { nil } def request_storage - get "update_required_storage", params: { key: apikey, + get 'update_required_storage', params: { key: apikey, id:, force: } end - context "missing project" do + context 'missing project' do let(:id) { 1234 } - it "returns 404" do + it 'returns 404' do request_storage - expect(response.code).to eq("404") - expect(response.body).to include("Could not find project #1234") + expect(response.code).to eq('404') + expect(response.body).to include('Could not find project #1234') end end - context "available project, but missing repository" do + context 'available project, but missing repository' do let(:project) { build_stubbed(:project) } let(:id) { project.id } @@ -569,13 +569,13 @@ def request_storage request_storage end - it "returns 404" do - expect(response.code).to eq("404") + it 'returns 404' do + expect(response.code).to eq('404') expect(response.body).to include("Project ##{project.id} does not have a repository.") end end - context "stubbed repository" do + context 'stubbed repository' do let(:project) { build_stubbed(:project) } let(:id) { project.id } let(:repository) do @@ -590,29 +590,29 @@ def request_storage request_storage end - context "local non-existing repository" do - let(:root_url) { "/tmp/does/not/exist/svn/foo.svn" } + context 'local non-existing repository' do + let(:root_url) { '/tmp/does/not/exist/svn/foo.svn' } let(:url) { "file://#{root_url}" } - it "does not have storage available" do + it 'does not have storage available' do expect(repository.scm.storage_available?).to be false - expect(response.code).to eq("400") + expect(response.code).to eq('400') end end - context "remote stubbed repository" do - let(:root_url) { "" } - let(:url) { "https://foo.example.org/svn/bar" } + context 'remote stubbed repository' do + let(:root_url) { '' } + let(:url) { 'https://foo.example.org/svn/bar' } - it "has no storage available" do + it 'has no storage available' do request_storage expect(repository.scm.storage_available?).to be false - expect(response.code).to eq("400") + expect(response.code).to eq('400') end end end - context "local existing repository" do + context 'local existing repository' do with_subversion_repository do |repo_dir| let(:root_url) { repo_dir } let(:url) { "file://#{root_url}" } @@ -629,17 +629,17 @@ def request_storage allow(repository).to receive(:storage_updated_at).and_return(last_updated) end - it "has storage available" do + it 'has storage available' do expect(repository.scm.storage_available?).to be true end - context "storage never updated before" do - it "updates the storage" do + context 'storage never updated before' do + it 'updates the storage' do expect(repository.required_storage_bytes).to eq 0 request_storage - expect(response.code).to eq("200") - expect(response.body).to include("Updated: true") + expect(response.code).to eq('200') + expect(response.body).to include('Updated: true') perform_enqueued_jobs @@ -648,29 +648,29 @@ def request_storage end end - context "outdated storage" do + context 'outdated storage' do let(:last_updated) { 2.days.ago } - it "updates the storage" do + it 'updates the storage' do expect(SCM::StorageUpdaterJob).to receive(:perform_later) request_storage end end - context "valid storage time" do + context 'valid storage time' do let(:last_updated) { 10.minutes.ago } - it "does not update to storage" do + it 'does not update to storage' do expect(SCM::StorageUpdaterJob).not_to receive(:perform_later) request_storage end end - context "valid storage time and force" do - let(:force) { "1" } + context 'valid storage time and force' do + let(:force) { '1' } let(:last_updated) { 10.minutes.ago } - it "does update to storage" do + it 'does update to storage' do expect(SCM::StorageUpdaterJob).to receive(:perform_later) request_storage end @@ -680,43 +680,43 @@ def request_storage end end - describe "#projects" do + describe '#projects' do before do - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password ) - get "projects", params: { key: api_key } + get 'projects', params: { key: api_key } end - it "is successful" do + it 'is successful' do expect(response) .to have_http_status(:ok) end - it "returns an xml with the projects having a repository" do + it 'returns an xml with the projects having a repository' do expect(response.content_type) - .to eql "application/xml; charset=utf-8" + .to eql 'application/xml; charset=utf-8' - expect(Nokogiri::XML::Document.parse(response.body).xpath("//projects[1]//id").text) + expect(Nokogiri::XML::Document.parse(response.body).xpath('//projects[1]//id').text) .to eql repository_project.id.to_s end - context "when disabled", with_settings: { sys_api_enabled?: false } do - it "is 403 forbidden" do + context 'when disabled', with_settings: { sys_api_enabled?: false } do + it 'is 403 forbidden' do expect(response) .to have_http_status(:forbidden) end end end - describe "#fetch_changesets" do + describe '#fetch_changesets' do let(:params) { { id: repository_project.identifier } } before do - request.env["HTTP_AUTHORIZATION"] = + request.env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials( valid_user.login, valid_user_password @@ -724,36 +724,36 @@ def request_storage allow_any_instance_of(Repository::Subversion).to receive(:fetch_changesets).and_return(true) - get "fetch_changesets", params: params.merge({ key: api_key }) + get 'fetch_changesets', params: params.merge({ key: api_key }) end - context "with a project identifier" do - it "is successful" do + context 'with a project identifier' do + it 'is successful' do expect(response) .to have_http_status(:ok) end end - context "without a project identifier" do + context 'without a project identifier' do let(:params) { {} } - it "is successful" do + it 'is successful' do expect(response) .to have_http_status(:ok) end end - context "for an unknown project" do + context 'for an unknown project' do let(:params) { { id: 0 } } - it "returns 404" do + it 'returns 404' do expect(response) .to have_http_status(:not_found) end end - context "when disabled", with_settings: { sys_api_enabled?: false } do - it "is 403 forbidden" do + context 'when disabled', with_settings: { sys_api_enabled?: false } do + it 'is 403 forbidden' do expect(response) .to have_http_status(:forbidden) end diff --git a/spec/controllers/types_controller_spec.rb b/spec/controllers/types_controller_spec.rb index 88e8a5f7e736..89121aae9f30 100644 --- a/spec/controllers/types_controller_spec.rb +++ b/spec/controllers/types_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TypesController do let(:project) do @@ -35,105 +35,105 @@ end let(:custom_field_1) do create(:work_package_custom_field, - field_format: "string", + field_format: 'string', is_for_all: true) end let(:custom_field_2) { create(:work_package_custom_field) } let(:status_0) { create(:status) } let(:status_1) { create(:status) } - context "with an unauthorized account" do + context 'with an unauthorized account' do let(:current_user) { create(:user) } before do allow(User).to receive(:current).and_return(current_user) end - describe "GET index" do - describe "the access should be restricted" do - before { get "index" } + describe 'GET index' do + describe 'the access should be restricted' do + before { get 'index' } it { expect(response.status).to eq(403) } end end - describe "GET new" do - describe "the access should be restricted" do - before { get "new" } + describe 'GET new' do + describe 'the access should be restricted' do + before { get 'new' } it { expect(response.status).to eq(403) } end end - describe "GET edit" do - describe "the access should be restricted" do - before { get "edit", params: { id: "123" } } + describe 'GET edit' do + describe 'the access should be restricted' do + before { get 'edit', params: { id: '123' } } it { expect(response.status).to eq(403) } end end - describe "POST create" do - describe "the access should be restricted" do - before { post "create" } + describe 'POST create' do + describe 'the access should be restricted' do + before { post 'create' } it { expect(response.status).to eq(403) } end end - describe "DELETE destroy" do - describe "the access should be restricted" do - before { delete "destroy", params: { id: "123" } } + describe 'DELETE destroy' do + describe 'the access should be restricted' do + before { delete 'destroy', params: { id: '123' } } it { expect(response.status).to eq(403) } end end - describe "POST update" do - describe "the access should be restricted" do - before { post "update", params: { id: "123" } } + describe 'POST update' do + describe 'the access should be restricted' do + before { post 'update', params: { id: '123' } } it { expect(response.status).to eq(403) } end end - describe "POST move" do - describe "the access should be restricted" do - before { post "move", params: { id: "123" } } + describe 'POST move' do + describe 'the access should be restricted' do + before { post 'move', params: { id: '123' } } it { expect(response.status).to eq(403) } end end end - context "with an authorized account" do + context 'with an authorized account' do let(:current_user) { create(:admin) } before do allow(User).to receive(:current).and_return(current_user) end - describe "GET index" do - before { get "index" } + describe 'GET index' do + before { get 'index' } it { expect(response).to be_successful } - it { expect(response).to render_template "index" } + it { expect(response).to render_template 'index' } end - describe "GET new" do - before { get "new" } + describe 'GET new' do + before { get 'new' } it { expect(response).to be_successful } - it { expect(response).to render_template "new" } + it { expect(response).to render_template 'new' } end - describe "POST create" do - describe "WITH valid params" do + describe 'POST create' do + describe 'WITH valid params' do let(:params) do - { "type" => { name: "New type", - project_ids: { "1" => project.id }, - custom_field_ids: { "1" => custom_field_1.id, - "2" => custom_field_2.id } } } + { 'type' => { name: 'New type', + project_ids: { '1' => project.id }, + custom_field_ids: { '1' => custom_field_1.id, + '2' => custom_field_2.id } } } end before do @@ -143,18 +143,18 @@ it { expect(response).to be_redirect } it do - type = Type.find_by(name: "New type") - expect(response).to redirect_to(action: "edit", tab: "settings", id: type.id) + type = Type.find_by(name: 'New type') + expect(response).to redirect_to(action: 'edit', tab: 'settings', id: type.id) end end - describe "WITH an empty name" do + describe 'WITH an empty name' do render_views let(:params) do - { "type" => { name: "", - project_ids: { "1" => project.id }, - custom_field_ids: { "1" => custom_field_1.id, - "2" => custom_field_2.id } } } + { 'type' => { name: '', + project_ids: { '1' => project.id }, + custom_field_ids: { '1' => custom_field_1.id, + '2' => custom_field_2.id } } } end before do @@ -163,13 +163,13 @@ it { expect(response.status).to eq(200) } - it "shows an error message" do + it 'shows an error message' do expect(response.body).to have_content("Name can't be blank") end end - describe "WITH workflow copy" do - let!(:existing_type) { create(:type, name: "Existing type") } + describe 'WITH workflow copy' do + let!(:existing_type) { create(:type, name: 'Existing type') } let!(:workflow) do create(:workflow, old_status: status_0, @@ -178,10 +178,10 @@ end let(:params) do - { "type" => { name: "New type", - project_ids: { "1" => project.id }, - custom_field_ids: { "1" => custom_field_1.id, "2" => custom_field_2.id } }, - "copy_workflow_from" => existing_type.id } + { 'type' => { name: 'New type', + project_ids: { '1' => project.id }, + custom_field_ids: { '1' => custom_field_1.id, '2' => custom_field_2.id } }, + 'copy_workflow_from' => existing_type.id } end before do @@ -191,70 +191,70 @@ it { expect(response).to be_redirect } it do - type = Type.find_by(name: "New type") - expect(response).to redirect_to(action: "edit", tab: "settings", id: type.id) + type = Type.find_by(name: 'New type') + expect(response).to redirect_to(action: 'edit', tab: 'settings', id: type.id) end - it "has the copied workflows" do - expect(Type.find_by(name: "New type") + it 'has the copied workflows' do + expect(Type.find_by(name: 'New type') .workflows.count).to eq(existing_type.workflows.count) end end end - describe "GET edit settings" do + describe 'GET edit settings' do render_views let(:type) do - create(:type, name: "My type", + create(:type, name: 'My type', is_milestone: true, projects: [project]) end before do - get "edit", params: { id: type.id, tab: :settings } + get 'edit', params: { id: type.id, tab: :settings } end it { expect(response).to be_successful } - it { expect(response).to render_template "edit" } - it { expect(response).to render_template "types/form/_settings" } + it { expect(response).to render_template 'edit' } + it { expect(response).to render_template 'types/form/_settings' } it { expect(response.body).to have_css "input[@name='type[name]'][@value='My type']" } it { expect(response.body).to have_css "input[@name='type[is_milestone]'][@value='1'][@checked='checked']" } end - describe "GET edit projects" do + describe 'GET edit projects' do render_views let(:type) do - create(:type, name: "My type", + create(:type, name: 'My type', is_milestone: true, projects: [project]) end before do - get "edit", params: { id: type.id, tab: :projects } + get 'edit', params: { id: type.id, tab: :projects } end it { expect(response).to be_successful } - it { expect(response).to render_template "edit" } - it { expect(response).to render_template "types/form/_projects" } + it { expect(response).to render_template 'edit' } + it { expect(response).to render_template 'types/form/_projects' } it { expect(response.body).to have_css "input[@name='type[project_ids][]'][@value='#{project.id}'][@checked='checked']" } end - describe "POST update" do + describe 'POST update' do let(:project2) { create(:project) } let(:type) do - create(:type, name: "My type", + create(:type, name: 'My type', is_milestone: true, projects: [project, project2]) end - describe "WITH type rename" do + describe 'WITH type rename' do let(:params) do - { "id" => type.id, - "type" => { name: "My type renamed" }, - "tab" => "settings" } + { 'id' => type.id, + 'type' => { name: 'My type renamed' }, + 'tab' => "settings" } end before do @@ -269,16 +269,16 @@ ) end - it "is renamed" do - expect(Type.find_by(name: "My type renamed").id).to eq(type.id) + it 'is renamed' do + expect(Type.find_by(name: 'My type renamed').id).to eq(type.id) end end - describe "WITH projects removed" do + describe 'WITH projects removed' do let(:params) do - { "id" => type.id, - "type" => { project_ids: [""] }, - "tab" => "projects" } + { 'id' => type.id, + 'type' => { project_ids: [''] }, + 'tab' => "projects" } end before do @@ -293,17 +293,17 @@ ) end - it "has no projects assigned" do - expect(Type.find_by(name: "My type").projects.count).to eq(0) + it 'has no projects assigned' do + expect(Type.find_by(name: 'My type').projects.count).to eq(0) end end end - describe "POST move" do - context "with a successful update" do - let!(:type) { create(:type, name: "My type", position: "1") } - let!(:type2) { create(:type, name: "My type 2", position: "2") } - let(:params) { { "id" => type.id, "type" => { move_to: "lower" } } } + describe 'POST move' do + context 'with a successful update' do + let!(:type) { create(:type, name: 'My type', position: '1') } + let!(:type2) { create(:type, name: 'My type 2', position: '2') } + let(:params) { { 'id' => type.id, 'type' => { move_to: 'lower' } } } before do post :move, params: @@ -312,15 +312,15 @@ it { expect(response).to be_redirect } it { expect(response).to redirect_to(types_path) } - it "has the position updated" do - expect(Type.find_by(name: "My type").position).to eq(2) + it 'has the position updated' do + expect(Type.find_by(name: 'My type').position).to eq(2) end end - context "with a failed update" do - let!(:type) { create(:type, name: "My type", position: "1") } - let!(:type2) { create(:type, name: "My type 2", position: "2") } - let(:params) { { "id" => type.id, "type" => { move_to: "lower" } } } + context 'with a failed update' do + let!(:type) { create(:type, name: 'My type', position: '1') } + let!(:type2) { create(:type, name: 'My type 2', position: '2') } + let(:params) { { 'id' => type.id, 'type' => { move_to: 'lower' } } } before do allow(Type).to receive(:find).and_return(type) @@ -330,25 +330,25 @@ end it { expect(response).not_to be_redirect } - it { expect(response).to render_template("edit") } + it { expect(response).to render_template('edit') } - it "has an unsuccessful move flash" do + it 'has an unsuccessful move flash' do expect(flash[:error]).to eq(I18n.t(:error_type_could_not_be_saved)) end it "doesn't update the position" do - expect(Type.find_by(name: "My type").position).to eq(1) + expect(Type.find_by(name: 'My type').position).to eq(1) end end end - describe "DELETE destroy" do - let(:type) { create(:type, name: "My type") } - let(:type2) { create(:type, name: "My type 2", projects: [project]) } - let(:type3) { create(:type, name: "My type 3", is_standard: true) } + describe 'DELETE destroy' do + let(:type) { create(:type, name: 'My type') } + let(:type2) { create(:type, name: 'My type 2', projects: [project]) } + let(:type3) { create(:type, name: 'My type 3', is_standard: true) } - describe "successful destroy" do - let(:params) { { "id" => type.id } } + describe 'successful destroy' do + let(:params) { { 'id' => type.id } } before do delete :destroy, params: @@ -357,16 +357,16 @@ it { expect(response).to be_redirect } it { expect(response).to redirect_to(types_path) } - it "has a successful destroy flash" do + it 'has a successful destroy flash' do expect(flash[:notice]).to eq(I18n.t(:notice_successful_delete)) end - it "is not present in the database" do - expect(Type.find_by(name: "My type")).to be_nil + it 'is not present in the database' do + expect(Type.find_by(name: 'My type')).to be_nil end end - describe "destroy type in use should fail" do + describe 'destroy type in use should fail' do let(:archived_project) do create(:project, :archived, @@ -379,14 +379,14 @@ type: type2, project: archived_project) end - let(:params) { { "id" => type2.id } } + let(:params) { { 'id' => type2.id } } let(:error_message) do archived_projects_urls = described_class .helpers .archived_projects_urls_for([archived_project]) [ - I18n.t(:"error_can_not_delete_type.explanation"), + I18n.t(:'error_can_not_delete_type.explanation'), I18n.t(:error_can_not_delete_in_use_archived_work_packages, archived_projects_urls:) ] end @@ -398,17 +398,17 @@ it { expect(response).to be_redirect } it { expect(response).to redirect_to(types_path) } - it "shows an error message" do + it 'shows an error message' do expect(sanitize_string(flash[:error])).to eq(sanitize_string(error_message)) end - it "is present in the database" do - expect(Type.find_by(name: "My type 2").id).to eq(type2.id) + it 'is present in the database' do + expect(Type.find_by(name: 'My type 2').id).to eq(type2.id) end end - describe "destroy standard type should fail" do - let(:params) { { "id" => type3.id } } + describe 'destroy standard type should fail' do + let(:params) { { 'id' => type3.id } } before { delete :destroy, params: } diff --git a/spec/controllers/users/memberships_controller_spec.rb b/spec/controllers/users/memberships_controller_spec.rb index 90e2ec87dd0b..8f43cff22f94 100644 --- a/spec/controllers/users/memberships_controller_spec.rb +++ b/spec/controllers/users/memberships_controller_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "work_package" +require 'spec_helper' +require 'work_package' RSpec.describe Users::MembershipsController do shared_let(:admin) { create(:admin) } @@ -35,11 +35,11 @@ let(:user) { create(:user) } let(:anonymous) { create(:anonymous) } - describe "update memberships" do + describe 'update memberships' do let(:project) { create(:project) } let(:role) { create(:project_role) } - it "works" do + it 'works' do # i.e. it should successfully add a user to a project's members as_logged_in_user admin do post :create, @@ -52,7 +52,7 @@ } end - expect(response).to redirect_to(controller: "/users", action: "edit", id: user.id, tab: "memberships") + expect(response).to redirect_to(controller: '/users', action: 'edit', id: user.id, tab: 'memberships') is_member = user.reload.memberships.any? do |m| m.project_id == project.id && m.role_ids.include?(role.id) diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 9c590f3b7aad..ac603f200b37 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "work_package" +require 'spec_helper' +require 'work_package' RSpec.describe UsersController do shared_let(:admin) { create(:admin) } shared_let(:anonymous) { User.anonymous } - shared_let(:user_password) { "bob!" * 4 } + shared_let(:user_password) { 'bob!' * 4 } shared_let(:user) do create(:user, - login: "bob", + login: 'bob', password: user_password, password_confirmation: user_password) end - describe "GET new" do + describe 'GET new' do context "without user limit reached" do before do as_logged_in_user admin do @@ -49,17 +49,17 @@ end end - it "is success" do + it 'is success' do expect(response) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(response) - .to have_rendered("new") + .to have_rendered('new') end - it "have a user object initialized" do + it 'have a user object initialized' do expect(assigns(:user)) .to be_a(User) end @@ -106,10 +106,10 @@ end end - describe "GET deletion_info" do - let(:params) { { "id" => user.id.to_s } } + describe 'GET deletion_info' do + let(:params) { { 'id' => user.id.to_s } } - context "when the current user is the requested user" do + context 'when the current user is the requested user' do current_user { user } context "when the setting users_deletable_by_self is set to true", @@ -120,11 +120,11 @@ it { expect(response).to have_http_status(:success) } - it "assigns @user to requested user" do + it 'assigns @user to requested user' do expect(assigns(:user)).to eq(user) end - it { expect(response).to render_template("deletion_info") } + it { expect(response).to render_template('deletion_info') } end context "when the setting users_deletable_by_self is set to false", @@ -137,7 +137,7 @@ end end - context "when the current user is the anonymous user" do + context 'when the current user is the anonymous user' do current_user { anonymous } before do @@ -145,10 +145,10 @@ end it { - expect(response).to redirect_to(controller: "account", - action: "login", - back_url: controller.url_for(controller: "users", - action: "deletion_info")) + expect(response).to redirect_to(controller: 'account', + action: 'login', + back_url: controller.url_for(controller: 'users', + action: 'deletion_info')) } end @@ -163,11 +163,11 @@ it { expect(response).to have_http_status(:success) } - it "assigns @user to requested user" do + it 'assigns @user to requested user' do expect(assigns(:user)).to eq(user) end - it { expect(response).to render_template("deletion_info") } + it { expect(response).to render_template('deletion_info') } end context "when the setting users_deletable_by_admins is set to false", @@ -181,10 +181,10 @@ end end - describe "POST resend_invitation" do + describe 'POST resend_invitation' do let(:invited_user) { create(:invited_user) } - context "without admin rights" do + context 'without admin rights' do let(:normal_user) { create(:user) } before do @@ -193,12 +193,12 @@ end end - it "returns 403 forbidden" do + it 'returns 403 forbidden' do expect(response.status).to eq 403 end end - context "with admin rights" do + context 'with admin rights' do before do expect(ActionMailer::Base.deliveries).to be_empty @@ -209,51 +209,51 @@ end end - it "redirects back to the edit user page" do + it 'redirects back to the edit user page' do expect(response).to redirect_to edit_user_path(invited_user) end - it "sends another activation email" do + it 'sends another activation email' do mail = ActionMailer::Base.deliveries.first.body.parts.first.body.to_s token = Token::Invitation.find_by user_id: invited_user.id - expect(mail).to include "activate your account" + expect(mail).to include 'activate your account' expect(mail).to include token.value end end end - describe "GET edit" do + describe 'GET edit' do before do as_logged_in_user admin do get :edit, params: { id: user.id } end end - it "is success" do + it 'is success' do expect(response) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(response) - .to have_rendered("edit") + .to have_rendered('edit') end - it "have a user object initialized" do + it 'have a user object initialized' do expect(assigns(:user)) .to eql user end end - describe "POST destroy" do - let(:base_params) { { "id" => user.id.to_s, back_url: my_account_path } } + describe 'POST destroy' do + let(:base_params) { { 'id' => user.id.to_s, back_url: my_account_path } } before do disable_flash_sweep end - context "when the password confirmation is missing" do + context 'when the password confirmation is missing' do before do allow(Setting).to receive(:users_deletable_by_self?).and_return(true) @@ -263,18 +263,18 @@ end it do - expect(response).to redirect_to(controller: "my", action: "account") + expect(response).to redirect_to(controller: 'my', action: 'account') end it { expect(flash[:error]).to eq(I18n.t(:notice_password_confirmation_failed)) } end - context "when password confirmation is present" do + context 'when password confirmation is present' do let(:params) do base_params.merge(_password_confirmation: user_password) end - context "when the current user is the requested one" do + context 'when the current user is the requested one' do current_user { user } context "when the setting users_deletable_by_self is set to true", @@ -284,13 +284,13 @@ end it do - expect(response).to redirect_to(controller: "account", action: "login") + expect(response).to redirect_to(controller: 'account', action: 'login') end - it { expect(flash[:notice]).to eq(I18n.t("account.deletion_pending")) } + it { expect(flash[:notice]).to eq(I18n.t('account.deletion_pending')) } end - context "when the setting users_deletable_by_self is set to false", + context 'when the setting users_deletable_by_self is set to false', with_settings: { users_deletable_by_self: false } do before do post :destroy, params: @@ -300,10 +300,10 @@ end end - context "when the current user is the anonymous user" do + context 'when the current user is the anonymous user' do current_user { anonymous } - context "even when the setting login_required is set to false and users_deletable_by_self is set to true", + context 'even when the setting login_required is set to false and users_deletable_by_self is set to true', with_settings: { login_required: false, users_deletable_by_self: true } do before do post :destroy, params: params.merge(id: anonymous.id.to_s) @@ -314,7 +314,7 @@ end end - context "when the current user is the admin" do + context 'when the current user is the admin' do current_user { admin } context "when the given password does NOT match and the setting users_deletable_by_admins is set to true", @@ -323,8 +323,8 @@ post :destroy, params: end - it "redirects with error" do - expect(response).to redirect_to(controller: "my", action: "account") + it 'redirects with error' do + expect(response).to redirect_to(controller: 'my', action: 'account') expect(flash[:notice]).to be_nil expect(flash[:error]).to eq(I18n.t(:notice_password_confirmation_failed)) end @@ -333,14 +333,14 @@ context "when the given password does match and the setting users_deletable_by_admins is set to true", with_settings: { users_deletable_by_admins: true } do before do - post :destroy, params: params.merge(_password_confirmation: "adminADMIN!") + post :destroy, params: params.merge(_password_confirmation: 'adminADMIN!') end it do - expect(response).to redirect_to(controller: "users", action: "index") + expect(response).to redirect_to(controller: 'users', action: 'index') end - it { expect(flash[:notice]).to eq(I18n.t("account.deletion_pending")) } + it { expect(flash[:notice]).to eq(I18n.t('account.deletion_pending')) } end context "when the setting users_deletable_by_admins is set to false", @@ -355,7 +355,7 @@ end end - describe "#change_status_info" do + describe '#change_status_info' do let!(:registered_user) do create(:user, status: User.statuses[:registered]) end @@ -370,52 +370,52 @@ end end - shared_examples "valid status info" do - it "renders the status info" do + shared_examples 'valid status info' do + it 'renders the status info' do expect(response).to be_successful - expect(response).to render_template "users/change_status_info" + expect(response).to render_template 'users/change_status_info' expect(assigns(:user)).to eq(registered_user) expect(assigns(:status_change)).to eq(change_action) end end - describe "with valid activate" do + describe 'with valid activate' do let(:change_action) { :activate } - it_behaves_like "valid status info" + it_behaves_like 'valid status info' end - describe "with valid unlock" do + describe 'with valid unlock' do let(:change_action) { :unlock } - it_behaves_like "valid status info" + it_behaves_like 'valid status info' end - describe "with valid lock" do + describe 'with valid lock' do let(:change_action) { :lock } - it_behaves_like "valid status info" + it_behaves_like 'valid status info' end - describe "bogus status" do + describe 'bogus status' do let(:change_action) { :wtf } - it "renders 400" do + it 'renders 400' do expect(response.status).to eq(400) - expect(response).not_to render_template "users/change_status_info" + expect(response).not_to render_template 'users/change_status_info' end end end - describe "#change_status", + describe '#change_status', with_settings: { available_languages: %w[en de], bcc_recipients: 1 } do - describe "WHEN activating a registered user" do + describe 'WHEN activating a registered user' do let!(:registered_user) do create(:user, status: User.statuses[:registered], - language: "de") + language: 'de') end let(:user_limit_reached) { false } @@ -428,22 +428,22 @@ params: { id: registered_user.id, user: { status: User.statuses[:active] }, - activate: "1" + activate: '1' } end end - it "activates the user" do + it 'activates the user' do assert registered_user.reload.active? end - it "sends an email to the correct user in the correct language" do + it 'sends an email to the correct user in the correct language' do perform_enqueued_jobs mail = ActionMailer::Base.deliveries.last expect(mail).not_to be_nil expect([registered_user.mail]).to eq(mail.to) mail.parts.each do |part| - expect(part.body.encoded).to include(I18n.t(:notice_account_activated, locale: "de")) + expect(part.body.encoded).to include(I18n.t(:notice_account_activated, locale: 'de')) end end @@ -461,7 +461,7 @@ end end - describe "GET #index" do + describe 'GET #index' do let(:params) { {} } before do @@ -470,45 +470,45 @@ end end - it "to be success" do + it 'to be success' do expect(response) .to have_http_status(:ok) end - it "renders the index" do + it 'renders the index' do expect(response) - .to have_rendered("index") + .to have_rendered('index') end - it "assigns users" do + it 'assigns users' do expect(assigns(:users)) .to contain_exactly(user, admin) end - context "with a name filter" do + context 'with a name filter' do let(:params) { { name: user.firstname } } - it "assigns users" do + it 'assigns users' do expect(assigns(:users)) .to contain_exactly(user) end end - context "with a group filter" do + context 'with a group filter' do let(:group) { create(:group, members: [user]) } let(:params) do { group_id: group.id } end - it "assigns users" do + it 'assigns users' do expect(assigns(:users)) .to contain_exactly(user) end end end - describe "session lifetime" do + describe 'session lifetime' do # TODO move this section to a proper place because we test a # before_action from the application controller @@ -517,120 +517,120 @@ User.current = nil end - shared_examples_for "index action with disabled session lifetime or inactivity not exceeded" do + shared_examples_for 'index action with disabled session lifetime or inactivity not exceeded' do it "doesn't logout the user and renders the index action" do expect(User.current).to eq(admin) - expect(response).to render_template "index" + expect(response).to render_template 'index' end end - shared_examples_for "index action with enabled session lifetime and inactivity exceeded" do - it "logs out the user and redirects with a warning that he has been locked out" do - expect(response.redirect_url).to eq(signin_url + "?back_url=" + CGI::escape(@controller.url_for(controller: "users", - action: "index"))) + shared_examples_for 'index action with enabled session lifetime and inactivity exceeded' do + it 'logs out the user and redirects with a warning that he has been locked out' do + expect(response.redirect_url).to eq(signin_url + '?back_url=' + CGI::escape(@controller.url_for(controller: 'users', + action: 'index'))) expect(User.current).not_to eq(admin) expect(flash[:warning]).to eq(I18n.t(:notice_forced_logout, ttl_time: Setting.session_ttl)) end end - context "disabled" do + context 'disabled' do before do allow(Setting).to receive(:session_ttl_enabled?).and_return(false) @controller.send(:logged_user=, admin) get :index end - it_behaves_like "index action with disabled session lifetime or inactivity not exceeded" + it_behaves_like 'index action with disabled session lifetime or inactivity not exceeded' end - context "enabled" do + context 'enabled' do before do allow(Setting).to receive(:session_ttl_enabled?).and_return(true) - allow(Setting).to receive(:session_ttl).and_return("120") + allow(Setting).to receive(:session_ttl).and_return('120') @controller.send(:logged_user=, admin) end - context "before 120 min of inactivity" do + context 'before 120 min of inactivity' do before do session[:updated_at] = Time.now - 1.hour get :index end - it_behaves_like "index action with disabled session lifetime or inactivity not exceeded" + it_behaves_like 'index action with disabled session lifetime or inactivity not exceeded' end - context "after 120 min of inactivity" do + context 'after 120 min of inactivity' do before do session[:updated_at] = Time.now - 3.hours get :index end - it_behaves_like "index action with enabled session lifetime and inactivity exceeded" + it_behaves_like 'index action with enabled session lifetime and inactivity exceeded' end - context "without last activity time in the session" do + context 'without last activity time in the session' do before do - allow(Setting).to receive(:session_ttl).and_return("60") + allow(Setting).to receive(:session_ttl).and_return('60') session[:updated_at] = nil get :index end - it_behaves_like "index action with enabled session lifetime and inactivity exceeded" + it_behaves_like 'index action with enabled session lifetime and inactivity exceeded' end - context "with ttl = 0" do + context 'with ttl = 0' do before do - allow(Setting).to receive(:session_ttl).and_return("0") + allow(Setting).to receive(:session_ttl).and_return('0') session[:updated_at] = Time.now - 1.hour get :index end - it_behaves_like "index action with disabled session lifetime or inactivity not exceeded" + it_behaves_like 'index action with disabled session lifetime or inactivity not exceeded' end - context "with ttl < 0" do + context 'with ttl < 0' do before do - allow(Setting).to receive(:session_ttl).and_return("-60") + allow(Setting).to receive(:session_ttl).and_return('-60') session[:updated_at] = Time.now - 1.hour get :index end - it_behaves_like "index action with disabled session lifetime or inactivity not exceeded" + it_behaves_like 'index action with disabled session lifetime or inactivity not exceeded' end - context "with ttl < 5 > 0" do + context 'with ttl < 5 > 0' do before do - allow(Setting).to receive(:session_ttl).and_return("4") + allow(Setting).to receive(:session_ttl).and_return('4') session[:updated_at] = Time.now - 1.hour get :index end - it_behaves_like "index action with disabled session lifetime or inactivity not exceeded" + it_behaves_like 'index action with disabled session lifetime or inactivity not exceeded' end end end - describe "PATCH #update" do + describe 'PATCH #update' do shared_let(:user_with_manage_user_global_permission) do - create(:user, login: "human-resources", global_permissions: [:manage_user]) + create(:user, login: 'human-resources', global_permissions: [:manage_user]) end - shared_let(:some_user) { create(:user, firstname: "User being updated") } - shared_let(:some_admin) { create(:admin, firstname: "Admin being updated") } + shared_let(:some_user) { create(:user, firstname: 'User being updated') } + shared_let(:some_admin) { create(:admin, firstname: 'Admin being updated') } - context "when updating fields as an admin" do + context 'when updating fields as an admin' do current_user { admin } let(:params) do { id: some_user.id, user: { - firstname: "Changed", - login: "changed_login", + firstname: 'Changed', + login: 'changed_login', force_password_change: true }, pref: { - hide_mail: "1", - comments_sorting: "desc" + hide_mail: '1', + comments_sorting: 'desc' } } end @@ -641,69 +641,69 @@ end end - it "redirects to the edit page" do - expect(response).to render_template :edit + it 'redirects to the edit page' do + expect(response).to redirect_to(edit_user_url(some_user)) end - it "is assigned their new values" do + it 'is assigned their new values' do some_user_from_db = User.find(some_user.id) - expect(some_user_from_db.firstname).to eq("Changed") - expect(some_user_from_db.login).to eq("changed_login") + expect(some_user_from_db.firstname).to eq('Changed') + expect(some_user_from_db.login).to eq('changed_login') expect(some_user_from_db.force_password_change).to be(true) expect(some_user_from_db.pref[:hide_mail]).to be_truthy - expect(some_user_from_db.pref[:comments_sorting]).to eq("desc") + expect(some_user_from_db.pref[:comments_sorting]).to eq('desc') end - it "sends no mail" do + it 'sends no mail' do expect(ActionMailer::Base.deliveries).to be_empty end - context "when updating the password" do + context 'when updating the password' do let(:params) do { id: some_user.id, - user: { password: "newpassPASS!", - password_confirmation: "newpassPASS!" }, - send_information: "1" + user: { password: 'newpassPASS!', + password_confirmation: 'newpassPASS!' }, + send_information: '1' } end - it "sends an email to the user with the password in it" do + it 'sends an email to the user with the password in it' do mail = ActionMailer::Base.deliveries.last expect(mail.to) .to contain_exactly(some_user.mail) expect(mail.body.encoded) - .to include("newpassPASS!") + .to include('newpassPASS!') end end - context "with invalid params" do + context 'with invalid params' do let(:params) do { id: some_user.id, user: { - firstname: "" + firstname: '' } } end - it "is success" do + it 'is success' do expect(response) .to have_http_status(:ok) end - it "renders the edit template with errors" do + it 'renders the edit template with errors' do expect(response) - .to have_rendered("edit") + .to have_rendered('edit') expect(assigns(:user).errors.first) .to have_attributes(attribute: :firstname, type: :blank) end end end - shared_examples "it can update field" do |field:, value:, edited_user:, current_user:| + shared_examples 'it can update field' do |field:, value:, edited_user:, current_user:| it "can change field #{field} " \ "of #{edited_user.to_s.humanize(capitalize: false)} " \ "as #{current_user.to_s.humanize(capitalize: false)}" do @@ -720,7 +720,7 @@ end end - shared_examples "it cannot update field" do |field:, value:, edited_user:, current_user:| + shared_examples 'it cannot update field' do |field:, value:, edited_user:, current_user:| it "cannot change field #{field} " \ "of #{edited_user.to_s.humanize(capitalize: false)} " \ "as #{current_user.to_s.humanize(capitalize: false)}" do @@ -738,122 +738,122 @@ end # admin field - include_examples "it can update field", + include_examples 'it can update field', field: :admin, value: true, edited_user: :some_user, current_user: :admin - include_examples "it can update field", + include_examples 'it can update field', field: :admin, value: false, edited_user: :some_admin, current_user: :admin - include_examples "it cannot update field", + include_examples 'it cannot update field', field: :admin, value: true, edited_user: :some_user, current_user: :user - include_examples "it cannot update field", + include_examples 'it cannot update field', field: :admin, value: true, edited_user: :some_user, current_user: :user_with_manage_user_global_permission # email field - include_examples "it can update field", + include_examples 'it can update field', field: :mail, - value: "another_email@example.com", + value: 'another_email@example.com', edited_user: :some_user, current_user: :admin - include_examples "it can update field", + include_examples 'it can update field', field: :mail, - value: "another_email@example.com", + value: 'another_email@example.com', edited_user: :some_admin, current_user: :admin - include_examples "it can update field", + include_examples 'it can update field', field: :mail, - value: "another_email@example.com", + value: 'another_email@example.com', edited_user: :some_user, current_user: :user_with_manage_user_global_permission - include_examples "it cannot update field", + include_examples 'it cannot update field', field: :mail, - value: "another_email@example.com", + value: 'another_email@example.com', edited_user: :some_admin, current_user: :user_with_manage_user_global_permission - include_examples "it cannot update field", + include_examples 'it cannot update field', field: :mail, - value: "another_email@example.com", + value: 'another_email@example.com', edited_user: :some_user, current_user: :user - context "with external authentication" do - let(:some_user) { create(:user, identity_url: "some:identity") } + context 'with external authentication' do + let(:some_user) { create(:user, identity_url: 'some:identity') } before do as_logged_in_user(admin) do - put :update, params: { id: some_user.id, user: { force_password_change: "true" } } + put :update, params: { id: some_user.id, user: { force_password_change: 'true' } } end some_user.reload end - it "ignores setting force_password_change" do + it 'ignores setting force_password_change' do expect(some_user.force_password_change).to be(false) end end - context "with ldap auth source" do + context 'with ldap auth source' do let(:ldap_auth_source) { create(:ldap_auth_source) } - it "switching to internal authentication on a password change" do + it 'switching to internal authentication on a password change' do some_user.ldap_auth_source = ldap_auth_source as_logged_in_user admin do put :update, params: { id: some_user.id, - user: { ldap_auth_source_id: "", password: "newpassPASS!", - password_confirmation: "newpassPASS!" } + user: { ldap_auth_source_id: '', password: 'newpassPASS!', + password_confirmation: 'newpassPASS!' } } end expect(some_user.reload.ldap_auth_source).to be_nil - expect(some_user.check_password?("newpassPASS!")).to be true + expect(some_user.check_password?('newpassPASS!')).to be true end end - context "with disabled_password_choice", + context 'with disabled_password_choice', with_config: { disable_password_choice: true } do - it "ignores password parameters and leaves the password unchanged" do + it 'ignores password parameters and leaves the password unchanged' do as_logged_in_user(admin) do put :update, params: { id: user.id, - user: { password: "changedpass!", password_confirmation: "changedpass!" } + user: { password: 'changedpass!', password_confirmation: 'changedpass!' } } end - expect(user.reload.check_password?("changedpass!")).to be false + expect(user.reload.check_password?('changedpass!')).to be false end end end - describe "Anonymous should not be able to create a user" do - it "redirects to the login page" do + describe 'Anonymous should not be able to create a user' do + it 'redirects to the login page' do post :create, params: { user: { - login: "psmith", - firstname: "Paul", - lastname: "Smith" + login: 'psmith', + firstname: 'Paul', + lastname: 'Smith' }, - password: "psmithPSMITH09", - password_confirmation: "psmithPSMITH09" + password: 'psmithPSMITH09', + password_confirmation: 'psmithPSMITH09' } - expect(response).to redirect_to "/login?back_url=http%3A%2F%2Ftest.host%2Fusers" + expect(response).to redirect_to '/login?back_url=http%3A%2F%2Ftest.host%2Fusers' end end - describe "GET #show" do - describe "general" do + describe 'GET #show' do + describe 'general' do let(:current_user) { user } let(:params) { { id: user.id } } let(:action) { :show } @@ -864,73 +864,73 @@ end end - it "responds with success", :aggregate_failures do + it 'responds with success', :aggregate_failures do expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' expect(assigns(:user)).to eq(user) end context 'when requesting special value "me"' do - let(:params) { { id: "me" } } + let(:params) { { id: 'me' } } - it "responds with success", :aggregate_failures do + it 'responds with success', :aggregate_failures do expect(response).to be_successful - expect(response).to render_template "show" + expect(response).to render_template 'show' expect(assigns(:user)).to eq(user) end end - context "when not being logged in" do + context 'when not being logged in' do let(:current_user) { User.anonymous } - context "when login_required", with_settings: { login_required: true } do - it "redirects to login" do + context 'when login_required', with_settings: { login_required: true } do + it 'redirects to login' do expect(response).to redirect_to signin_path(back_url: user_url(user.id)) end end - context "when not login_required", with_settings: { login_required: false } do - it "responds with 404" do + context 'when not login_required', with_settings: { login_required: false } do + it 'responds with 404' do expect(response) .to have_http_status(:not_found) end end context 'when requesting special value "me"' do - let(:params) { { id: "me" } } + let(:params) { { id: 'me' } } - it "redirects to login", :aggregate_failures do - expect(response).to redirect_to signin_url(back_url: user_url("me")) + it 'redirects to login', :aggregate_failures do + expect(response).to redirect_to signin_url(back_url: user_url('me')) end end end - context "when the user is locked for an admin" do + context 'when the user is locked for an admin' do let(:current_user) do user.locked! admin end - it "responds with 200" do + it 'responds with 200' do expect(response) .to have_http_status(:ok) end end - context "when the user is locked for an non admin" do + context 'when the user is locked for an non admin' do let(:current_user) do user.locked! create(:user) end - it "responds with 200" do + it 'responds with 200' do expect(response) .to have_http_status(:not_found) end end end - describe "for user with Activity" do + describe 'for user with Activity' do render_views let(:work_package) do @@ -974,26 +974,26 @@ get :show, params: { id: user.id } end - it "includes the number of reported work packages" do + it 'includes the number of reported work packages' do label = Regexp.escape(I18n.t(:label_reported_work_packages)) - expect(response.body).to have_css("p", text: /#{label}.*42/) + expect(response.body).to have_css('p', text: /#{label}.*42/) end end end - describe "POST #create" do + describe 'POST #create' do current_user { admin } let(:params) do { user: { - firstname: "John", - lastname: "Doe", - login: "jdoe", - password: "adminADMIN!", - password_confirmation: "adminADMIN!", - mail: "jdoe@gmail.com" + firstname: 'John', + lastname: 'Doe', + login: 'jdoe', + password: 'adminADMIN!', + password_confirmation: 'adminADMIN!', + mail: 'jdoe@gmail.com' }, pref: {} } @@ -1005,17 +1005,17 @@ end end - it "is successful" do + it 'is successful' do expect(response) .to redirect_to edit_user_path(User.newest.first) end - it "creates the user with the provided params" do + it 'creates the user with the provided params' do expect(User.newest.first.attributes.with_indifferent_access.slice(:firstname, :lastname, :login, :mail)) .to eql params[:user].with_indifferent_access.slice(:firstname, :lastname, :login, :mail) end - it "sends an activation mail" do + it 'sends an activation mail' do mail = ActionMailer::Base.deliveries.last expect(mail.to) @@ -1029,12 +1029,12 @@ assert(mail.body.encoded =~ activation_link) end - context "with invalid parameters" do - let(:params) { { user: { login: "jdoe" } } } + context 'with invalid parameters' do + let(:params) { { user: { login: 'jdoe' } } } - it "renders new" do + it 'renders new' do expect(response) - .to render_template "new" + .to render_template 'new' end end end diff --git a/spec/controllers/versions_controller_spec.rb b/spec/controllers/versions_controller_spec.rb index 38ae203668d3..1746c43ea993 100644 --- a/spec/controllers/versions_controller_spec.rb +++ b/spec/controllers/versions_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe VersionsController do let(:user) { create(:admin) } @@ -35,7 +35,7 @@ let(:version2) { create(:version, project:) } let(:version3) { create(:version, project:, effective_date: (Date.today - 14.days)) } - describe "#index" do + describe '#index' do render_views before do @@ -44,31 +44,31 @@ version3 end - context "without additional params" do + context 'without additional params' do before do login_as(user) get :index, params: { project_id: project.id } end it { expect(response).to be_successful } - it { expect(response).to render_template("index") } + it { expect(response).to render_template('index') } subject { assigns(:versions) } - it "shows Version with no date set" do + it 'shows Version with no date set' do expect(subject.include?(version1)).to be_truthy end - it "shows Version with date set" do + it 'shows Version with date set' do expect(subject.include?(version2)).to be_truthy end - it "not shows Completed version" do + it 'not shows Completed version' do expect(subject.include?(version3)).to be_falsey end end - context "with showing selected types" do + context 'with showing selected types' do let(:type_a) { create(:type) } let(:type_b) { create(:type) } @@ -84,13 +84,13 @@ login_as(user) end - describe "with all types" do + describe 'with all types' do before do - get :index, params: { project_id: project, completed: "1" } + get :index, params: { project_id: project, completed: '1' } end it { expect(response).to be_successful } - it { expect(response).to render_template("index") } + it { expect(response).to render_template('index') } it "shows all work packages" do issues_by_version = assigns(:wps_by_version) @@ -101,13 +101,13 @@ end end - describe "with selected types" do + describe 'with selected types' do before do - get :index, params: { project_id: project, completed: "1", type_ids: [type_b.id] } + get :index, params: { project_id: project, completed: '1', type_ids: [type_b.id] } end it { expect(response).to be_successful } - it { expect(response).to render_template("index") } + it { expect(response).to render_template('index') } it "shows only work packages of the selected type" do issues_by_version = assigns(:wps_by_version) @@ -119,31 +119,31 @@ end end - context "with showing completed versions" do + context 'with showing completed versions' do before do login_as(user) - get :index, params: { project_id: project, completed: "1" } + get :index, params: { project_id: project, completed: '1' } end it { expect(response).to be_successful } - it { expect(response).to render_template("index") } + it { expect(response).to render_template('index') } subject { assigns(:versions) } - it "shows Version with no date set" do + it 'shows Version with no date set' do expect(subject.include?(version1)).to be_truthy end - it "shows Version with date set" do + it 'shows Version with date set' do expect(subject.include?(version2)).to be_truthy end - it "not shows Completed version" do + it 'not shows Completed version' do expect(subject.include?(version3)).to be_truthy end end - describe "Sub Project Versions" do + describe 'Sub Project Versions' do let!(:sub_project) { create(:public_project, parent_id: project.id) } let!(:sub_project_version) { create(:version, project: sub_project) } @@ -155,19 +155,19 @@ subject { assigns(:versions) } - shared_examples "is successful" do + shared_examples 'is successful' do it { expect(response).to be_successful } - it { expect(response).to render_template("index") } + it { expect(response).to render_template('index') } end - shared_examples "shows versions with and without a date set" do + shared_examples 'shows versions with and without a date set' do it do expect(subject).to include(version1, version2) end end shared_examples "shows sub project's' version" do - it "sets @with_subprojects to true" do + it 'sets @with_subprojects to true' do expect(assigns(:with_subprojects)).to be_truthy end @@ -177,7 +177,7 @@ end shared_examples "does not show sub project's versions" do - it "sets @with_subprojects to false" do + it 'sets @with_subprojects to false' do expect(assigns(:with_subprojects)).to be_falsey end @@ -186,40 +186,40 @@ end end - context "when with_subprojects param is set to 1" do + context 'when with_subprojects param is set to 1' do let(:params) { { project_id: project.id, with_subprojects: 1 } } - include_examples "is successful" + include_examples 'is successful' include_examples "shows sub project's' version" end - context "when with_subprojects param is set to 0" do + context 'when with_subprojects param is set to 0' do let(:params) { { project_id: project.id, with_subprojects: 0 } } - include_examples "is successful" + include_examples 'is successful' include_examples "does not show sub project's versions" end - context "with sub projects included by default", + context 'with sub projects included by default', with_settings: { display_subprojects_work_packages: true } do - context "and with_subprojects is not a param" do + context 'and with_subprojects is not a param' do let(:params) { { project_id: project.id } } - include_examples "is successful" + include_examples 'is successful' include_examples "shows sub project's' version" end - context "and with_subprojects is set to 0" do + context 'and with_subprojects is set to 0' do let(:params) { { project_id: project.id, with_subprojects: 0 } } - include_examples "is successful" + include_examples 'is successful' include_examples "does not show sub project's versions" end end end end - describe "#show" do + describe '#show' do render_views before do @@ -229,42 +229,42 @@ end it { expect(response).to be_successful } - it { expect(response).to render_template("show") } - it { assert_select "h2", content: version2.name } + it { expect(response).to render_template('show') } + it { assert_select 'h2', content: version2.name } subject { assigns(:version) } it { is_expected.to eq(version2) } end - describe "#new" do + describe '#new' do # This spec is here because at one point the `new` action was requiring # the `version` key in params, so visiting it without one failed. - it "renders correctly" do + it 'renders correctly' do login_as(user) get :new, params: { project_id: project.id } expect(response.status).to eq(200) end end - describe "#create" do - context "with valid attributes" do + describe '#create' do + context 'with valid attributes' do before do login_as(user) - post :create, params: { project_id: project.id, version: { name: "test_add_version" } } + post :create, params: { project_id: project.id, version: { name: 'test_add_version' } } end it { expect(response).to redirect_to(project_settings_versions_path(project)) } - it "generates the new version" do - version = Version.find_by(name: "test_add_version") + it 'generates the new version' do + version = Version.find_by(name: 'test_add_version') expect(version).not_to be_nil expect(version.project).to eq(project) end end end - describe "#edit" do + describe '#edit' do render_views before do @@ -273,33 +273,33 @@ get :edit, params: { id: version2.id } end - context "when resource is found" do + context 'when resource is found' do it { expect(response).to be_successful } - it { expect(response).to render_template("edit") } + it { expect(response).to render_template('edit') } end end - describe "#close_completed" do + describe '#close_completed' do before do login_as(user) - version1.update_attribute :status, "open" - version2.update_attribute :status, "open" - version3.update_attribute :status, "open" + version1.update_attribute :status, 'open' + version2.update_attribute :status, 'open' + version3.update_attribute :status, 'open' put :close_completed, params: { project_id: project.id } end it { expect(response).to redirect_to(project_settings_versions_path(project)) } - it { expect(Version.find_by(status: "closed")).to eq(version3) } + it { expect(Version.find_by(status: 'closed')).to eq(version3) } end - describe "#update" do - context "with valid params" do + describe '#update' do + context 'with valid params' do let(:params) do { id: version1.id, version: { - name: "New version name", - effective_date: Date.today.strftime("%Y-%m-%d") + name: 'New version name', + effective_date: Date.today.strftime('%Y-%m-%d') } } end @@ -310,7 +310,7 @@ end it { expect(response).to redirect_to(project_settings_versions_path(project)) } - it { expect(Version.find_by(name: "New version name")).to eq(version1) } + it { expect(Version.find_by(name: 'New version name')).to eq(version1) } it { expect(version1.reload.effective_date).to eq(Date.today) } end @@ -321,8 +321,8 @@ patch :update, params: { id: version1.id, - version: { name: "New version name", - effective_date: Date.today.strftime("%Y-%m-%d") }, + version: { name: 'New version name', + effective_date: Date.today.strftime('%Y-%m-%d') }, back_url: home_path } end @@ -330,31 +330,31 @@ it { expect(response).to redirect_to(home_path) } end - context "with invalid params" do + context 'with invalid params' do before do login_as(user) patch :update, params: { id: version1.id, - version: { name: "", - effective_date: Date.today.strftime("%Y-%m-%d") } + version: { name: '', + effective_date: Date.today.strftime('%Y-%m-%d') } } end it { expect(response).to be_successful } - it { expect(response).to render_template("edit") } + it { expect(response).to render_template('edit') } it { expect(assigns(:version).errors.symbols_for(:name)).to contain_exactly(:blank) } end end - describe "#destroy" do + describe '#destroy' do before do login_as(user) @deleted = version3.id delete :destroy, params: { id: @deleted } end - it "redirects to projects versions and the version is deleted" do + it 'redirects to projects versions and the version is deleted' do expect(response).to redirect_to(project_settings_versions_path(project)) expect { Version.find(@deleted) }.to raise_error ActiveRecord::RecordNotFound end diff --git a/spec/controllers/wiki_controller_spec.rb b/spec/controllers/wiki_controller_spec.rb index 9adb49497620..43ece7d6c8c7 100644 --- a/spec/controllers/wiki_controller_spec.rb +++ b/spec/controllers/wiki_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiController do shared_let(:admin) { create(:admin) } @@ -37,45 +37,45 @@ shared_let(:wiki) { project.wiki } shared_let(:existing_page) do - create(:wiki_page, wiki_id: project.wiki.id, title: "ExistingPage", author: admin) + create(:wiki_page, wiki_id: project.wiki.id, title: 'ExistingPage', author: admin) end - describe "actions" do + describe 'actions' do before do allow(controller).to receive(:set_localization) end current_user { admin } - describe "index" do + describe 'index' do before do get :index, params: { project_id: project.identifier } end - it "is successful" do + it 'is successful' do expect(response) .to have_http_status(:ok) end - it "renders the index template" do + it 'renders the index template' do expect(response) .to render_template(:index) end - it "assigns pages" do + it 'assigns pages' do expect(assigns[:pages]) .to eq project.wiki.pages end end shared_examples_for "a 'new' action" do - it "assigns @project to the current project" do + it 'assigns @project to the current project' do get_page expect(assigns[:project]).to eq(project) end - it "assigns @page to a newly created wiki page" do + it 'assigns @page to a newly created wiki page' do get_page expect(assigns[:page]).to be_new_record @@ -83,38 +83,38 @@ expect(assigns[:page].wiki).to eq(project.wiki) end - it "renders the new action" do + it 'renders the new action' do get_page - expect(response).to render_template "new" + expect(response).to render_template 'new' end end - describe "new" do - let(:get_page) { get "new", params: { project_id: project } } + describe 'new' do + let(:get_page) { get 'new', params: { project_id: project } } it_behaves_like "a 'new' action" end - describe "new_child" do - let(:get_page) { get "new_child", params: { project_id: project, id: existing_page.title } } + describe 'new_child' do + let(:get_page) { get 'new_child', params: { project_id: project, id: existing_page.title } } it_behaves_like "a 'new' action" - it "sets the parent page for the new page" do + it 'sets the parent page for the new page' do get_page expect(assigns[:page].parent).to eq(existing_page) end - it "renders 404 if used with an unknown page title" do - get "new_child", params: { project_id: project, id: "foobar" } + it 'renders 404 if used with an unknown page title' do + get 'new_child', params: { project_id: project, id: 'foobar' } expect(response.status).to eq(404) # not found end end - describe "show" do + describe 'show' do let(:permissions) { %w[view_wiki_pages] } let(:user) { create(:user, member_with_permissions: { project => permissions }) } @@ -124,40 +124,40 @@ get_page end - context "when querying for an existing page" do + context 'when querying for an existing page' do let(:get_page) { get :show, params: { project_id: project, id: existing_page.title } } - it "is a success" do + it 'is a success' do expect(response) .to have_http_status(:ok) end - it "renders the show template" do + it 'renders the show template' do expect(response) .to render_template(:show) end - it "assigns the page" do + it 'assigns the page' do expect(assigns[:page]) .to eql existing_page end end - context "when querying for the wiki root page with edit permissions" do - let(:get_page) { get :show, params: { project_id: project, id: "wiki" } } + context 'when querying for the wiki root page with edit permissions' do + let(:get_page) { get :show, params: { project_id: project, id: 'wiki' } } let(:permissions) { %w[view_wiki_pages edit_wiki_pages] } - it "is a success" do + it 'is a success' do expect(response) .to have_http_status(:ok) end - it "renders the new template" do + it 'renders the new template' do expect(response) .to render_template(:new) end - it "assigns a new page that is unpersisted" do + it 'assigns a new page that is unpersisted' do expect(assigns[:page]) .to be_a WikiPages::AtVersion @@ -166,21 +166,21 @@ end end - context "when querying for an unexisting page with edit permissions" do - let(:get_page) { get :show, params: { project_id: project, id: "new_page" } } + context 'when querying for an unexisting page with edit permissions' do + let(:get_page) { get :show, params: { project_id: project, id: 'new_page' } } let(:permissions) { %w[view_wiki_pages edit_wiki_pages] } - it "is a success" do + it 'is a success' do expect(response) .to have_http_status(:ok) end - it "renders the new template" do + it 'renders the new template' do expect(response) .to render_template(:new) end - it "assigns a new page that is unpersisted" do + it 'assigns a new page that is unpersisted' do expect(assigns[:page]) .to be_a WikiPages::AtVersion @@ -189,52 +189,52 @@ end end - context "when querying for no specific page" do + context 'when querying for no specific page' do let(:get_page) do project.wiki.update_column(:start_page, existing_page.title) get :show, params: { project_id: project } end - it "is a success" do + it 'is a success' do expect(response) .to have_http_status(:ok) end - it "renders the show template" do + it 'renders the show template' do expect(response) .to render_template(:show) end - it "assigns the wiki start page" do + it 'assigns the wiki start page' do expect(assigns[:page]) .to eql existing_page end end - context "when querying for the wiki root page without edit permissions" do - let(:get_page) { get :show, params: { project_id: project, id: "wiki" } } + context 'when querying for the wiki root page without edit permissions' do + let(:get_page) { get :show, params: { project_id: project, id: 'wiki' } } - it "redirects to index" do + it 'redirects to index' do expect(response).to redirect_to action: :index end - it "shows a flash info" do - expect(flash[:info]).to include I18n.t("wiki.page_not_editable_index") + it 'shows a flash info' do + expect(flash[:info]).to include I18n.t('wiki.page_not_editable_index') end end - context "when querying for a non existing page without edit permissions" do - let(:get_page) { get :show, params: { project_id: project, id: "new_page" } } + context 'when querying for a non existing page without edit permissions' do + let(:get_page) { get :show, params: { project_id: project, id: 'new_page' } } - it "returns 404" do + it 'returns 404' do expect(response) .to have_http_status(:not_found) end end end - describe "edit" do + describe 'edit' do let(:permissions) { %i[view_wiki_pages edit_wiki_pages] } let(:params) do @@ -250,22 +250,22 @@ get :edit, params:, flash: end - context "with an existing wiki page" do + context 'with an existing wiki page' do let(:params) do { project_id: project, id: existing_page.title } end - it "is sucessful" do + it 'is sucessful' do expect(response) .to have_http_status(:ok) end - it "renders the edit template" do + it 'renders the edit template' do expect(response) .to render_template :edit end - it "assigns the page" do + it 'assigns the page' do expect(assigns[:page]) .to eq existing_page @@ -274,36 +274,36 @@ end end - context "with an existing wiki page that is protected" do + context 'with an existing wiki page that is protected' do let(:params) do existing_page.update_column(:protected, true) { project_id: project, id: existing_page.title } end - it "is forbiddend" do + it 'is forbiddend' do expect(response) .to have_http_status(:forbidden) end end - context "with an existing wiki page that is protected and having the necessary permission" do + context 'with an existing wiki page that is protected and having the necessary permission' do let(:permissions) do existing_page.update_column(:protected, true) %i[view_wiki_pages edit_wiki_pages protect_wiki_pages] end - it "is sucessful" do + it 'is sucessful' do expect(response) .to have_http_status(:ok) end - it "renders the edit template" do + it 'renders the edit template' do expect(response) .to render_template :edit end - it "assigns the page" do + it 'assigns the page' do expect(assigns[:page]) .to eq existing_page @@ -312,23 +312,23 @@ end end - context "with a related wiki page in the flash and a non existing wiki page" do + context 'with a related wiki page in the flash and a non existing wiki page' do let(:flash) { { _related_wiki_page_id: 1234 } } let(:params) do - { project_id: project, id: "foobar" } + { project_id: project, id: 'foobar' } end - it "is sucessful" do + it 'is sucessful' do expect(response) .to have_http_status(:ok) end - it "renders the edit template" do + it 'renders the edit template' do expect(response) .to render_template :edit end - it "assigns @page to a new wiki page with the parent id set" do + it 'assigns @page to a new wiki page with the parent id set' do expect(assigns[:page]) .to be_a WikiPages::AtVersion @@ -341,99 +341,99 @@ end end - describe "create" do - describe "successful action" do - it "redirects to the show action" do - post "create", + describe 'create' do + describe 'successful action' do + it 'redirects to the show action' do + post 'create', params: { project_id: project, - page: { text: "h1. abc", title: "abc" } + page: { text: 'h1. abc', title: 'abc' } } - expect(response).to redirect_to action: "show", project_id: project, id: "abc" + expect(response).to redirect_to action: 'show', project_id: project, id: 'abc' end - it "saves a new WikiPage with proper content" do - post "create", + it 'saves a new WikiPage with proper content' do + post 'create', params: { project_id: project, - page: { text: "h1. abc", title: "abc" } + page: { text: 'h1. abc', title: 'abc' } } - page = project.wiki.pages.find_by title: "abc" + page = project.wiki.pages.find_by title: 'abc' expect(page).not_to be_nil - expect(page.text).to eq("h1. abc") + expect(page.text).to eq('h1. abc') end end - describe "unsuccessful action" do + describe 'unsuccessful action' do it 'renders "wiki/new"' do - post "create", + post 'create', params: { project_id: project, - page: { text: "h1. abc", title: "" } + page: { text: 'h1. abc', title: '' } } - expect(response).to render_template("new") + expect(response).to render_template('new') end - it "assigns project to work with new template" do - post "create", + it 'assigns project to work with new template' do + post 'create', params: { project_id: project, - page: { text: "h1. abc", title: "" } + page: { text: 'h1. abc', title: '' } } expect(assigns[:project]).to eq(project) end - it "assigns wiki to work with new template" do - post "create", + it 'assigns wiki to work with new template' do + post 'create', params: { project_id: project, - page: { text: "h1. abc", title: "" } + page: { text: 'h1. abc', title: '' } } expect(assigns[:wiki]).to eq(project.wiki) expect(assigns[:wiki]).not_to be_new_record end - it "assigns page to work with new template" do - post "create", + it 'assigns page to work with new template' do + post 'create', params: { project_id: project, - page: { text: "h1. abc", title: "" } + page: { text: 'h1. abc', title: '' } } expect(assigns[:page]).to be_new_record expect(assigns[:page].wiki.project).to eq(project) - expect(assigns[:page].title).to eq("") - expect(assigns[:page].text).to eq("h1. abc") + expect(assigns[:page].title).to eq('') + expect(assigns[:page].text).to eq('h1. abc') expect(assigns[:page]).not_to be_valid end end end - describe "update" do - context "when the page is locked" do + describe 'update' do + context 'when the page is locked' do before do existing_page.update!(protected: true) end - it "redirects to the show action" do - post "update", + it 'redirects to the show action' do + post 'update', params: { project_id: project, id: existing_page.title, - page: { text: "h1. abc", title: "foobar" } + page: { text: 'h1. abc', title: 'foobar' } } - expect(response).to redirect_to action: "show", project_id: project, id: "foobar" + expect(response).to redirect_to action: 'show', project_id: project, id: 'foobar' end end end - describe "destroy" do + describe 'destroy' do shared_let(:parent_page) { create(:wiki_page, wiki:) } shared_let(:child_page) { create(:wiki_page, wiki:, parent: parent_page) } @@ -449,13 +449,13 @@ response end - context "when it is not the only wiki page" do - it "redirects to wiki#index" do + context 'when it is not the only wiki page' do + it 'redirects to wiki#index' do expect(subject) - .to redirect_to action: "index", project_id: project, id: redirect_page_after_destroy + .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy end - it "destroys the page" do + it 'destroys the page' do expect { subject } .to change { WikiPage.where(id: existing_page.id).count } .from(1) @@ -463,17 +463,17 @@ end end - context "when it is the only wiki page" do + context 'when it is the only wiki page' do before do WikiPage.where.not(id: existing_page.id).delete_all end - it "redirects to projects#show" do + it 'redirects to projects#show' do expect(subject) .to redirect_to project_path(project) end - it "destroys the page" do + it 'destroys the page' do expect { subject } .to change { WikiPage.where(id: existing_page.id).count } .from(1) @@ -481,17 +481,17 @@ end end - context "when destroying a child" do + context 'when destroying a child' do let(:params) do { project_id: project, id: child_page } end - it "redirects to wiki#index" do + it 'redirects to wiki#index' do expect(subject) - .to redirect_to action: "index", project_id: project, id: redirect_page_after_destroy + .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy end - it "destroys the page" do + it 'destroys the page' do expect { subject } .to change { WikiPage.where(id: child_page.id).count } .from(1) @@ -499,40 +499,40 @@ end end - context "when destroying a parent without specifying todo" do + context 'when destroying a parent without specifying todo' do let(:params) do { project_id: project, id: parent_page } end - it "responds with success" do + it 'responds with success' do expect(subject) .to have_http_status(:ok) end - it "destroys the page" do + it 'destroys the page' do expect { subject } .not_to change(WikiPage, :count) end end - context "when destroying a parent with nullify" do + context 'when destroying a parent with nullify' do let(:params) do - { project_id: project, id: parent_page, todo: "nullify" } + { project_id: project, id: parent_page, todo: 'nullify' } end - it "redirects to wiki#index" do + it 'redirects to wiki#index' do expect(subject) - .to redirect_to action: "index", project_id: project, id: redirect_page_after_destroy + .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy end - it "destroys the page" do + it 'destroys the page' do expect { subject } .to change { WikiPage.where(id: parent_page.id).count } .from(1) .to(0) end - it "sets the parent_id of the child to nil" do + it 'sets the parent_id of the child to nil' do subject expect(child_page.parent_id) @@ -540,17 +540,17 @@ end end - context "when destroying a parent with todo = destroy" do + context 'when destroying a parent with todo = destroy' do let(:params) do - { project_id: project, id: parent_page, todo: "destroy" } + { project_id: project, id: parent_page, todo: 'destroy' } end - it "redirects to wiki#index" do + it 'redirects to wiki#index' do expect(subject) - .to redirect_to action: "index", project_id: project, id: redirect_page_after_destroy + .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy end - it "destroys the page" do + it 'destroys the page' do expect { subject } .to change { WikiPage.where(id: [parent_page, child_page]).count } .from(2) @@ -558,24 +558,24 @@ end end - context "when destroying a parent with reassign" do + context 'when destroying a parent with reassign' do let(:params) do - { project_id: project, id: parent_page, todo: "reassign", reassign_to_id: existing_page.id } + { project_id: project, id: parent_page, todo: 'reassign', reassign_to_id: existing_page.id } end - it "redirects to wiki#index" do + it 'redirects to wiki#index' do expect(subject) - .to redirect_to action: "index", project_id: project, id: redirect_page_after_destroy + .to redirect_to action: 'index', project_id: project, id: redirect_page_after_destroy end - it "destroys the page" do + it 'destroys the page' do expect { subject } .to change { WikiPage.where(id: parent_page).count } .from(1) .to(0) end - it "sets the parent_id of the child to the specified page" do + it 'sets the parent_id of the child to the specified page' do subject expect(child_page.parent_id) @@ -584,7 +584,7 @@ end end - describe "rename" do + describe 'rename' do shared_let(:parent_page) { create(:wiki_page, wiki:) } shared_let(:child_page) { create(:wiki_page, wiki:, parent: parent_page) } @@ -606,45 +606,45 @@ response end - context "when getting for a page" do - it "is success" do + context 'when getting for a page' do + it 'is success' do expect(subject) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(subject) .to render_template :rename end end - context "when getting for a child page" do + context 'when getting for a child page' do let(:params) do { project_id: project, id: child_page.title } end - it "is success" do + it 'is success' do expect(subject) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(subject) .to render_template :rename end end - context "when getting for a page without permissions" do + context 'when getting for a page without permissions' do let(:permissions) { %i[view_wiki_pages] } - it "is forbidden" do + it 'is forbidden' do expect(subject) .to have_http_status(:forbidden) end end - context "when patching with redirect" do - let(:new_title) { "The new page title" } + context 'when patching with redirect' do + let(:new_title) { 'The new page title' } let!(:old_title) { existing_page.title } let(:params) do @@ -662,19 +662,19 @@ patch :rename, params: end - it "redirects to the show page with the altered name" do + it 'redirects to the show page with the altered name' do expect(subject) - .to redirect_to action: "show", project_id: project.identifier, id: "the-new-page-title" + .to redirect_to action: 'show', project_id: project.identifier, id: 'the-new-page-title' end - it "renames the page" do + it 'renames the page' do subject expect(existing_page.reload.title) .to eql new_title end - it "finds the page by the old name" do + it 'finds the page by the old name' do subject expect(wiki.find_page(old_title)) @@ -682,8 +682,8 @@ end end - context "when patching without redirect" do - let(:new_title) { "The new page title" } + context 'when patching without redirect' do + let(:new_title) { 'The new page title' } let!(:old_title) { existing_page.title } let(:params) do @@ -692,7 +692,7 @@ id: existing_page.title, page: { title: new_title, - redirect_existing_links: "0" + redirect_existing_links: '0' } } end @@ -701,19 +701,19 @@ patch :rename, params: end - it "redirects to the show page with the altered name" do + it 'redirects to the show page with the altered name' do expect(subject) - .to redirect_to action: "show", project_id: project.identifier, id: "the-new-page-title" + .to redirect_to action: 'show', project_id: project.identifier, id: 'the-new-page-title' end - it "renames the page" do + it 'renames the page' do subject expect(existing_page.reload.title) .to eql new_title end - it "does not find the page by the old name" do + it 'does not find the page by the old name' do subject expect(wiki.find_page(old_title)) @@ -722,10 +722,10 @@ end end - describe "diffs" do + describe 'diffs' do let!(:journal_from) { existing_page.journals.last } let!(:journal_to) do - existing_page.text = "new_text" + existing_page.text = 'new_text' existing_page.save existing_page.journals.reload.last @@ -754,17 +754,17 @@ response end - it "is success" do + it 'is success' do expect(subject) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(subject) .to render_template :diff end - it "assigns html_diff" do + it 'assigns html_diff' do subject expect(assigns[:html_diff]) @@ -772,10 +772,10 @@ end end - describe "annotates" do + describe 'annotates' do let!(:journal_from) { existing_page.journals.last } let!(:journal_to) do - existing_page.text = "new_text" + existing_page.text = 'new_text' existing_page.save existing_page.journals.reload.last @@ -799,18 +799,18 @@ response end - it "is success" do + it 'is success' do expect(subject) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(subject) .to render_template :annotate end end - describe "export" do + describe 'export' do let(:permissions) { %i[view_wiki_pages export_wiki_pages] } current_user { create(:user, member_with_permissions: { project => permissions }) } @@ -819,36 +819,36 @@ get :export, params: { project_id: project.identifier } end - it "is successful" do + it 'is successful' do expect(response) .to have_http_status(:ok) end - it "assigns pages" do + it 'assigns pages' do expect(assigns[:pages]) .to eq project.wiki.pages end - it "is an html response" do + it 'is an html response' do expect(response.content_type) - .to eq "text/html" + .to eq 'text/html' end - context "for an unauthorized user" do + context 'for an unauthorized user' do let(:permissions) { %i[view_wiki_pages] } - it "prevents access" do + it 'prevents access' do expect(response) .to have_http_status(:forbidden) end end end - describe "protect" do + describe 'protect' do let(:permissions) { %i[view_wiki_pages protect_wiki_pages] } let(:params) do - { project_id: project, id: existing_page.title, protected: "1" } + { project_id: project, id: existing_page.title, protected: '1' } end let(:request) do @@ -862,21 +862,21 @@ response end - context "with an existing wiki page" do - it "set the protected property of the page" do + context 'with an existing wiki page' do + it 'set the protected property of the page' do expect { subject } .to change { existing_page.reload.protected? } .from(false) .to(true) end - it "redirects to the show page" do + it 'redirects to the show page' do expect(subject) - .to redirect_to action: "show", project_id: project.identifier, id: existing_page.title.downcase + .to redirect_to action: 'show', project_id: project.identifier, id: existing_page.title.downcase end end - context "with an existing wiki page that is protected" do + context 'with an existing wiki page that is protected' do let(:permissions) do existing_page.update_column :protected, true @@ -884,40 +884,40 @@ end let(:params) do - { project_id: project, id: existing_page.title, protected: "0" } + { project_id: project, id: existing_page.title, protected: '0' } end - it "set the protected property of the page" do + it 'set the protected property of the page' do expect { subject } .to change { existing_page.reload.protected? } .from(true) .to(false) end - it "redirects to the show page" do + it 'redirects to the show page' do expect(subject) - .to redirect_to action: "show", project_id: project.identifier, id: existing_page.title.downcase + .to redirect_to action: 'show', project_id: project.identifier, id: existing_page.title.downcase end end - context "with an existing wiki page but missing permissions" do + context 'with an existing wiki page but missing permissions' do let(:permissions) do %i[view_wiki_pages] end - it "does not change the protected property of the page" do + it 'does not change the protected property of the page' do expect { subject } .not_to change { existing_page.reload.protected? } end - it "return forbidden" do + it 'return forbidden' do expect(subject) .to have_http_status(:forbidden) end end end - describe "history" do + describe 'history' do let(:permissions) { %i[view_wiki_edits] } current_user { create(:user, member_with_permissions: { project => permissions }) } @@ -926,27 +926,27 @@ get :history, params: { project_id: project.identifier, id: existing_page.title } end - it "is successful" do + it 'is successful' do expect(response) .to have_http_status(:ok) end - it "renders the template" do + it 'renders the template' do expect(response) .to render_template :history end - it "assigns versions" do + it 'assigns versions' do expect(assigns[:versions]) .to eq existing_page.journals end - context "for a non existing page" do + context 'for a non existing page' do before do - get :history, params: { project_id: project.identifier, id: "bogus" } + get :history, params: { project_id: project.identifier, id: 'bogus' } end - it "states not found" do + it 'states not found' do expect(response) .to have_http_status(:not_found) end @@ -954,7 +954,7 @@ end end - describe "view related stuff" do + describe 'view related stuff' do render_views shared_let(:project) do @@ -965,19 +965,19 @@ let!(:page_with_content) do create(:wiki_page, wiki_id: project.wiki.id, - title: "PagewithContent", + title: 'PagewithContent', author_id: admin.id) end let!(:page_default) do create(:wiki_page, wiki_id: project.wiki.id, - title: "Wiki", + title: 'Wiki', author_id: admin.id) end let!(:unrelated_page) do create(:wiki_page, wiki_id: project.wiki.id, - title: "UnrelatedPage", + title: 'UnrelatedPage', author_id: admin.id) end @@ -1002,27 +1002,27 @@ current_user { admin } - describe "- main menu links" do + describe '- main menu links' do before do @main_menu_item_for_page_with_content = create(:wiki_menu_item, navigatable_id: project.wiki.id, - title: "Item for Page with Content", + title: 'Item for Page with Content', name: page_with_content.slug) @main_menu_item_for_new_wiki_page = create(:wiki_menu_item, navigatable_id: project.wiki.id, - title: "Item for new WikiPage", - name: "new-wiki-page") + title: 'Item for new WikiPage', + name: 'new-wiki-page') @other_menu_item = create(:wiki_menu_item, navigatable_id: project.wiki.id, - title: "Item for other page", + title: 'Item for other page', name: unrelated_page.slug) end - shared_examples_for "all wiki menu items" do - it "is inactive, when an unrelated page is shown" do - get "show", params: { id: unrelated_page.slug, project_id: project.id } + shared_examples_for 'all wiki menu items' do + it 'is inactive, when an unrelated page is shown' do + get 'show', params: { id: unrelated_page.slug, project_id: project.id } expect(response).to be_successful @@ -1031,17 +1031,17 @@ end it "is inactive, when another wiki menu item's page is shown" do - get "show", params: { id: @other_wiki_menu_item.name, project_id: project.id } + get 'show', params: { id: @other_wiki_menu_item.name, project_id: project.id } expect(response).to be_successful - expect(response.body).to have_css(".main-menu--children a.selected", count: 0) + expect(response.body).to have_css('.main-menu--children a.selected', count: 0) assert_select "#main-menu a.#{@wiki_menu_item.menu_identifier}-menu-item" assert_select "#main-menu a.#{@wiki_menu_item.menu_identifier}-menu-item.selected", false end - it "is active, when the given wiki menu item is shown" do - get "show", params: { id: @wiki_menu_item.name, project_id: project.id } + it 'is active, when the given wiki menu item is shown' do + get 'show', params: { id: @wiki_menu_item.name, project_id: project.id } expect(response).to be_successful @@ -1049,130 +1049,130 @@ end end - shared_examples_for "all existing wiki menu items" do + shared_examples_for 'all existing wiki menu items' do # TODO: Add tests for new and toc options within menu item - it "is active on parents item, when new page is shown" do - get "new_child", params: { id: @wiki_menu_item.name, project_id: project.identifier } + it 'is active on parents item, when new page is shown' do + get 'new_child', params: { id: @wiki_menu_item.name, project_id: project.identifier } expect(response).to be_successful assert_select "#main-menu a.#{@wiki_menu_item.menu_identifier}-menu-item.selected" end - it "is active, when a toc page is shown" do - get "index", params: { id: @wiki_menu_item.name, project_id: project.id } + it 'is active, when a toc page is shown' do + get 'index', params: { id: @wiki_menu_item.name, project_id: project.id } expect(response).to be_successful - assert_select "#content h2", text: "Table of Contents" + assert_select '#content h2', text: 'Table of Contents' assert_select "#main-menu a.#{@wiki_menu_item.menu_identifier}-menu-item.selected" end end - shared_examples_for "all wiki menu items with child pages" do - it "is active, when the given wiki menu item is an ancestor of the shown page" do - get "show", params: { id: child_page.slug, project_id: project.id } + shared_examples_for 'all wiki menu items with child pages' do + it 'is active, when the given wiki menu item is an ancestor of the shown page' do + get 'show', params: { id: child_page.slug, project_id: project.id } expect(response).to be_successful - expect(response.body).to have_css("#main-menu a.selected", count: 1) + expect(response.body).to have_css('#main-menu a.selected', count: 1) assert_select "#main-menu a.#{@wiki_menu_item.menu_identifier}-menu-item.selected" end end - describe "- wiki menu item pointing to a saved wiki page" do + describe '- wiki menu item pointing to a saved wiki page' do before do @wiki_menu_item = @main_menu_item_for_page_with_content @other_wiki_menu_item = @other_menu_item end - it_behaves_like "all wiki menu items" - it_behaves_like "all existing wiki menu items" - it_behaves_like "all wiki menu items with child pages" + it_behaves_like 'all wiki menu items' + it_behaves_like 'all existing wiki menu items' + it_behaves_like 'all wiki menu items with child pages' end - describe "- wiki menu item pointing to a new wiki page" do + describe '- wiki menu item pointing to a new wiki page' do before do @wiki_menu_item = @main_menu_item_for_new_wiki_page @other_wiki_menu_item = @other_menu_item end - it_behaves_like "all wiki menu items" + it_behaves_like 'all wiki menu items' end - describe "- wiki_menu_item containing special chars only" do + describe '- wiki_menu_item containing special chars only' do before do @wiki_menu_item = create(:wiki_menu_item, navigatable_id: project.wiki.id, - title: "?", - name: "help") + title: '?', + name: 'help') @other_wiki_menu_item = @other_menu_item end - it_behaves_like "all wiki menu items" + it_behaves_like 'all wiki menu items' end end - describe "- wiki sidebar" do - describe "configure menu items link" do - describe "on a show page" do - describe "being authorized to configure menu items" do - it "is visible" do - get "show", params: { project_id: project.id } + describe '- wiki sidebar' do + describe 'configure menu items link' do + describe 'on a show page' do + describe 'being authorized to configure menu items' do + it 'is visible' do + get 'show', params: { project_id: project.id } expect(response).to be_successful - assert_select "#content a", "Configure menu item" + assert_select '#content a', 'Configure menu item' end end - describe "being unauthorized to configure menu items" do + describe 'being unauthorized to configure menu items' do before do allow(User).to receive(:current).and_return @anon end - it "is invisible" do - get "show", params: { project_id: project.id } + it 'is invisible' do + get 'show', params: { project_id: project.id } expect(response).to be_successful - assert_select "#content a", text: "Configure menu item", count: 0 + assert_select '#content a', text: 'Configure menu item', count: 0 end end end end - describe "new child page link" do - describe "on an index page" do - describe "being authorized to edit wiki pages" do - it "is invisible" do - get "index", params: { project_id: project.id } + describe 'new child page link' do + describe 'on an index page' do + describe 'being authorized to edit wiki pages' do + it 'is invisible' do + get 'index', params: { project_id: project.id } expect(response).to be_successful - assert_select "#content a", text: "Wiki page", count: 0 + assert_select '#content a', text: 'Wiki page', count: 0 end end - describe "being unauthorized to edit wiki pages" do + describe 'being unauthorized to edit wiki pages' do before do allow(User).to receive(:current).and_return @anon end - it "is invisible" do - get "index", params: { project_id: project.id } + it 'is invisible' do + get 'index', params: { project_id: project.id } expect(response).to be_successful - assert_select "#content a", text: "Wiki page", count: 0 + assert_select '#content a', text: 'Wiki page', count: 0 end end end - describe "on a wiki page" do - describe "being authorized to edit wiki pages" do - describe "with a wiki page present" do - it "is visible" do - get "show", + describe 'on a wiki page' do + describe 'being authorized to edit wiki pages' do + describe 'with a wiki page present' do + it 'is visible' do + get 'show', params: { id: page_with_content.title, project_id: project.identifier } expect(response).to be_successful @@ -1182,62 +1182,62 @@ path = new_child_project_wiki_path(project_id: project, id: page_with_content.slug) - assert_select "#content a[href='#{path}']", "Wiki page" + assert_select "#content a[href='#{path}']", 'Wiki page' end end - describe "with no wiki page present" do - it "is invisible" do - get "show", params: { id: "i-am-a-ghostpage", project_id: project.identifier } + describe 'with no wiki page present' do + it 'is invisible' do + get 'show', params: { id: 'i-am-a-ghostpage', project_id: project.identifier } expect(response).to be_successful assert_select "#content a[href='#{new_child_project_wiki_path(project_id: project, id: 'i-am-a-ghostpage')}']", - text: "Wiki page", count: 0 + text: 'Wiki page', count: 0 end end end - describe "being unauthorized to edit wiki pages" do + describe 'being unauthorized to edit wiki pages' do before do allow(User).to receive(:current).and_return @anon end - it "is invisible" do - get "show", params: { id: page_with_content.title, project_id: project.identifier } + it 'is invisible' do + get 'show', params: { id: page_with_content.title, project_id: project.identifier } expect(response).to be_successful - assert_select "#content a", text: "Wiki page", count: 0 + assert_select '#content a', text: 'Wiki page', count: 0 end end end end - describe "new page link" do - describe "on a show page" do - describe "being authorized to edit wiki pages" do - it "is visible" do - get "show", params: { project_id: project.id } + describe 'new page link' do + describe 'on a show page' do + describe 'being authorized to edit wiki pages' do + it 'is visible' do + get 'show', params: { project_id: project.id } expect(response).to be_successful assert_select ".toolbar-items a[href='#{new_child_project_wiki_path(project_id: project, id: 'wiki')}']", - "Wiki page" + 'Wiki page' end end - describe "being unauthorized to edit wiki pages" do + describe 'being unauthorized to edit wiki pages' do before do allow(User).to receive(:current).and_return @anon end - it "is invisible" do - get "show", params: { project_id: project.id } + it 'is invisible' do + get 'show', params: { project_id: project.id } expect(response).to be_successful - assert_select ".toolbar-items a", text: "Wiki page", count: 0 + assert_select '.toolbar-items a', text: 'Wiki page', count: 0 end end end diff --git a/spec/controllers/wiki_menu_authentication_spec.rb b/spec/controllers/wiki_menu_authentication_spec.rb index f67dc5b33bcc..5d33ff2a7ef9 100644 --- a/spec/controllers/wiki_menu_authentication_spec.rb +++ b/spec/controllers/wiki_menu_authentication_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiMenuItemsController do before do @@ -42,25 +42,25 @@ @params[:id] = page.title end - describe "w/ valid auth" do - it "renders the edit action" do + describe 'w/ valid auth' do + it 'renders the edit action' do admin_user = create(:admin) allow(User).to receive(:current).and_return admin_user - permission_role = create(:project_role, name: "accessgranted", permissions: [:manage_wiki_menu]) + permission_role = create(:project_role, name: 'accessgranted', permissions: [:manage_wiki_menu]) member = create(:member, principal: admin_user, user: admin_user, project: @project, roles: [permission_role]) - get "edit", params: @params + get 'edit', params: @params expect(response).to be_successful end end - describe "w/o valid auth" do - it "be forbidden" do + describe 'w/o valid auth' do + it 'be forbidden' do allow(User).to receive(:current).and_return create(:user) - get "edit", params: @params + get 'edit', params: @params expect(response.status).to eq(403) # forbidden end diff --git a/spec/controllers/wiki_menu_items_controller_spec.rb b/spec/controllers/wiki_menu_items_controller_spec.rb index 507185359dbe..9ebf004b18fb 100644 --- a/spec/controllers/wiki_menu_items_controller_spec.rb +++ b/spec/controllers/wiki_menu_items_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiMenuItemsController do let(:current_user) { create(:admin) } @@ -45,7 +45,7 @@ allow(User).to receive(:current).and_return current_user end - describe "#edit" do + describe '#edit' do # more wiki pages with menu items let(:another_wiki_page) { create(:wiki_page, wiki:) } # second wiki page with two child pages let!(:another_wiki_page_top_level_wiki_menu_item) do @@ -63,19 +63,19 @@ let(:grand_child_page) { create(:wiki_page, parent: child_page, wiki:) } let!(:grand_child_page_wiki_menu_item) { create(:wiki_menu_item, wiki:, name: grand_child_page.slug) } - context "when no parent wiki menu item has been configured yet" do - context "and it is a child page" do + context 'when no parent wiki menu item has been configured yet' do + context 'and it is a child page' do before { get :edit, params: { project_id: project.id, id: child_page.slug } } subject { response } - it "preselects the wiki menu item of the parent page as parent wiki menu item option" do - expect(assigns["selected_parent_menu_item_id"]).to eq(another_wiki_page_top_level_wiki_menu_item.id) + it 'preselects the wiki menu item of the parent page as parent wiki menu item option' do + expect(assigns['selected_parent_menu_item_id']).to eq(another_wiki_page_top_level_wiki_menu_item.id) # see FIXME in menu_helper.rb end end - context "and it is a grand child page the parent of which is not a main item" do + context 'and it is a grand child page the parent of which is not a main item' do before do # ensure the parent page of grand_child_page is not a main item child_page_wiki_menu_item.tap { |page| page.parent = top_level_wiki_menu_item }.save @@ -84,38 +84,38 @@ subject { response } - it "preselects the wiki menu item of the grand parent page as parent wiki menu item option" do - expect(assigns["selected_parent_menu_item_id"]).to eq(another_wiki_page_top_level_wiki_menu_item.id) + it 'preselects the wiki menu item of the grand parent page as parent wiki menu item option' do + expect(assigns['selected_parent_menu_item_id']).to eq(another_wiki_page_top_level_wiki_menu_item.id) end end end - context "when a parent wiki menu item has already been configured" do + context 'when a parent wiki menu item has already been configured' do before { get :edit, params: { project_id: project.id, id: another_child_page.slug } } subject { response } - it "preselects the parent wiki menu item that is already assigned" do - expect(assigns["selected_parent_menu_item_id"]).to eq(top_level_wiki_menu_item.id) + it 'preselects the parent wiki menu item that is already assigned' do + expect(assigns['selected_parent_menu_item_id']).to eq(top_level_wiki_menu_item.id) end end end - shared_context "when there is one more wiki page with a child page" do + shared_context 'when there is one more wiki page with a child page' do let!(:child_page) { create(:wiki_page, parent: wiki_page, wiki:) } let!(:another_wiki_page) { create(:wiki_page, wiki:) } # second wiki page with two child pages let!(:another_child_page) { create(:wiki_page, parent: another_wiki_page, wiki:) } end - describe "#select_main_menu_item" do - include_context "when there is one more wiki page with a child page" + describe '#select_main_menu_item' do + include_context 'when there is one more wiki page with a child page' before { get :select_main_menu_item, params: { project_id: project, id: wiki_page.id } } - subject { assigns["possible_wiki_pages"] } + subject { assigns['possible_wiki_pages'] } - context "when selecting a new wiki page to replace the current main menu item" do + context 'when selecting a new wiki page to replace the current main menu item' do it { is_expected.to include wiki_page } it { is_expected.to include child_page } it { is_expected.to include another_wiki_page } @@ -123,10 +123,10 @@ end end - describe "#replace_main_menu_item" do - include_context "when there is one more wiki page with a child page" + describe '#replace_main_menu_item' do + include_context 'when there is one more wiki page with a child page' - context "when another wiki page is selected for replacement" do + context 'when another wiki page is selected for replacement' do let(:selected_page) { child_page } let(:new_menu_item) { selected_page.menu_item } @@ -139,21 +139,21 @@ } end - it "destroys the current wiki menu item" do + it 'destroys the current wiki menu item' do expect(wiki_page.menu_item).to be_nil end - it "creates a new main menu item for the selected wiki page" do + it 'creates a new main menu item for the selected wiki page' do expect(selected_page.menu_item).to be_present expect(selected_page.menu_item.parent).to be_nil end - it "transfers the menu item options to the selected wiki page" do + it 'transfers the menu item options to the selected wiki page' do expect(new_menu_item.options).to eq(index_page: true, new_wiki_page: true) end end - context "when its own wiki page is selected for replacement" do + context 'when its own wiki page is selected for replacement' do let!(:wiki_menu_item) { wiki_page.menu_item } before do @@ -165,7 +165,7 @@ } end - it "does not destroy the wiki menu item" do + it 'does not destroy the wiki menu item' do expect(wiki_menu_item.reload).to be_present end end diff --git a/spec/controllers/work_packages/auto_completes_controller_spec.rb b/spec/controllers/work_packages/auto_completes_controller_spec.rb index e1eafd6ab8c2..4d6c2b0037ce 100644 --- a/spec/controllers/work_packages/auto_completes_controller_spec.rb +++ b/spec/controllers/work_packages/auto_completes_controller_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::AutoCompletesController do let(:user) { create(:user) } @@ -49,13 +49,13 @@ let(:work_package_2) do create(:work_package, - subject: "Error when updating a recipe", + subject: 'Error when updating a recipe', project:) end let(:work_package_3) do create(:work_package, - subject: "Lorem ipsum", + subject: 'Lorem ipsum', project:) end @@ -69,37 +69,37 @@ work_package_3 end - shared_examples_for "successful response" do + shared_examples_for 'successful response' do subject { response } it { is_expected.to be_successful } end - shared_examples_for "contains expected values" do + shared_examples_for 'contains expected values' do subject { assigns(:work_packages) } it { is_expected.to include(*expected_values) } end - describe "#work_packages" do - describe "search is case insensitive" do + describe '#work_packages' do + describe 'search is case insensitive' do let(:expected_values) { [work_package_1, work_package_2] } before do get :index, params: { project_id: project.id, - q: "ReCiPe" + q: 'ReCiPe' }, format: :json end - it_behaves_like "successful response" + it_behaves_like 'successful response' - it_behaves_like "contains expected values" + it_behaves_like 'contains expected values' end - describe "returns work package for given id" do + describe 'returns work package for given id' do let(:expected_values) { work_package_1 } before do @@ -111,12 +111,12 @@ format: :json end - it_behaves_like "successful response" + it_behaves_like 'successful response' - it_behaves_like "contains expected values" + it_behaves_like 'contains expected values' end - describe "returns work package for given id" do + describe 'returns work package for given id' do # this relies on all expected work packages to have ids that contain the given string # we do not want to have work_package_3 so we take it's id + 1 to create a string # we are sure to not be part of work_package_3's id. @@ -156,11 +156,11 @@ format: :json end - it_behaves_like "successful response" + it_behaves_like 'successful response' - it_behaves_like "contains expected values" + it_behaves_like 'contains expected values' - context "uniq" do + context 'uniq' do let(:assigned) { assigns(:work_packages) } subject { assigned.size } @@ -169,7 +169,7 @@ end end - describe "returns work package for given id" do + describe 'returns work package for given id' do render_views let(:work_package_4) do create(:work_package, @@ -187,15 +187,15 @@ format: :json end - it_behaves_like "successful response" - it_behaves_like "contains expected values" + it_behaves_like 'successful response' + it_behaves_like 'contains expected values' - it "escapes html" do - expect(response.body).not_to include "' ] end @@ -87,25 +87,25 @@ visit project_wiki_path(project, :wiki) # Set value - find(".ck-content").base.send_keys(wiki_body) - click_button "Save" + find('.ck-content').base.send_keys(wiki_body) + click_button 'Save' - expect(page).to have_css(".title-container h2", text: "Wiki") - expect(page).to have_css("a.wiki-page", count: 5) + expect(page).to have_css('.title-container h2', text: 'Wiki') + expect(page).to have_css('a.wiki-page', count: 5) end - it "shows renders correct links" do + it 'shows renders correct links' do expected_titles.each_with_index do |title, i| visit project_wiki_path(project, :wiki) - expect(page).to have_css("div.wiki-content") - target_link = all("div.wiki-content a.wiki-page")[i] + expect(page).to have_css('div.wiki-content') + target_link = all('div.wiki-content a.wiki-page')[i] expect(target_link.text).to eq(title) expect(target_link[:href]).to match("/wiki/#{expected_slugs[i]}") target_link.click - expect(page).to have_css(".title-container h2", text: title) + expect(page).to have_css('.title-container h2', text: title) end end end diff --git a/spec/features/work_package_show_spec.rb b/spec/features/work_package_show_spec.rb index c6bfa27491f5..88336e5d2545 100644 --- a/spec/features/work_package_show_spec.rb +++ b/spec/features/work_package_show_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package show page", :selenium do +RSpec.describe 'Work package show page', :selenium do let(:user) { create(:admin) } let(:project) { create(:project) } let(:work_package) do @@ -43,7 +43,7 @@ work_package.save! end - it "all different angular based work package views", :js do + it 'all different angular based work package views', :js do wp_page = Pages::FullWorkPackage.new(work_package) wp_page.visit! diff --git a/spec/features/work_packages/attachments/attachment_upload_spec.rb b/spec/features/work_packages/attachments/attachment_upload_spec.rb index 274ba35ff1e7..479a0ddbfb44 100644 --- a/spec/features/work_packages/attachments/attachment_upload_spec.rb +++ b/spec/features/work_packages/attachments/attachment_upload_spec.rb @@ -65,7 +65,7 @@ # Activate the edit field field.activate! - editor.expect_button 'Upload image from computer' + editor.expect_button 'Insert image' editor.drag_attachment image_fixture.path, 'Some image caption' @@ -95,7 +95,7 @@ comment_field.activate! # Button should be hidden - editor.expect_no_button 'Upload image from computer' + editor.expect_no_button 'Insert image' editor.click_and_type_slowly 'this is a comment!1' comment_field.submit_by_click @@ -113,7 +113,7 @@ it 'can open the editor and image upload is shown' do comment_field.activate! - editor.expect_button 'Upload image from computer' + editor.expect_button 'Insert image' editor.click_and_type_slowly 'this is a comment!2' editor.drag_attachment image_fixture.path, 'Some image caption' diff --git a/spec/features/work_packages/attribute_help_texts_spec.rb b/spec/features/work_packages/attribute_help_texts_spec.rb index 253082a3dad3..383cdb20719a 100644 --- a/spec/features/work_packages/attribute_help_texts_spec.rb +++ b/spec/features/work_packages/attribute_help_texts_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package attribute help texts", :js do +RSpec.describe 'Work package attribute help texts', :js do let(:project) { create(:project) } let(:work_package) { create(:work_package, project:) } let(:instance) do create(:work_package_help_text, attribute_name: :status, - help_text: "Some **help text** for status.") + help_text: 'Some **help text** for status.') end let(:modal) { Components::AttributeHelpTextModal.new(instance) } @@ -50,30 +50,30 @@ wp_page.ensure_page_loaded end - shared_examples "allows to view help texts" do - it "shows an indicator for whatever help text exists" do + shared_examples 'allows to view help texts' do + it 'shows an indicator for whatever help text exists' do expect(page).to have_css('.work-package--single-view [data-qa-help-text-for="status"]') # Open help text modal modal.open! - expect(modal.modal_container).to have_css("strong", text: "help text") + expect(modal.modal_container).to have_css('strong', text: 'help text') modal.expect_edit(editable: user.allowed_globally?(:edit_attribute_help_texts)) modal.close! end end - describe "as admin" do + describe 'as admin' do let(:user) { create(:admin) } - it_behaves_like "allows to view help texts" + it_behaves_like 'allows to view help texts' end - describe "as regular user" do + describe 'as regular user' do let(:user) do create(:user, member_with_permissions: { project => [:view_work_packages] }) end - it_behaves_like "allows to view help texts" + it_behaves_like 'allows to view help texts' end end diff --git a/spec/features/work_packages/bulk/copy_work_package_spec.rb b/spec/features/work_packages/bulk/copy_work_package_spec.rb index d9ffe06b2f4c..668fe743005e 100644 --- a/spec/features/work_packages/bulk/copy_work_package_spec.rb +++ b/spec/features/work_packages/bulk/copy_work_package_spec.rb @@ -1,26 +1,26 @@ -require "spec_helper" -require "features/page_objects/notification" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'spec_helper' +require 'features/page_objects/notification' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' -RSpec.describe "Copy work packages through Rails view", :js, :with_cuprite do +RSpec.describe 'Copy work packages through Rails view', :js, :with_cuprite do include Components::Autocompleter::NgSelectAutocompleteHelpers - shared_let(:type) { create(:type, name: "Bug") } - shared_let(:type2) { create(:type, name: "Risk") } + shared_let(:type) { create(:type, name: 'Bug') } + shared_let(:type2) { create(:type, name: 'Risk') } - shared_let(:project) { create(:project, name: "Source", types: [type, type2]) } - shared_let(:project2) { create(:project, name: "Target", types: [type, type2]) } + shared_let(:project) { create(:project, name: 'Source', types: [type, type2]) } + shared_let(:project2) { create(:project, name: 'Target', types: [type, type2]) } shared_let(:dev) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_permissions: { project => %i[view_work_packages work_package_assigned] }) end shared_let(:mover) do create(:user, - firstname: "Manager", - lastname: "Guy", + firstname: 'Manager', + lastname: 'Guy', member_with_permissions: { project => %i[view_work_packages copy_work_packages move_work_packages manage_subtasks assign_versions add_work_packages], @@ -54,42 +54,42 @@ wp_table.expect_work_package_listed work_package, work_package2 end - describe "copying work packages" do + describe 'copying work packages' do before do # Select all work packages - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] end - context "with permission" do + context 'with permission' do let(:current_user) { mover } let(:wp_table_target) { Pages::WorkPackagesTable.new(project2) } before do wp_table.expect_work_package_count 2 context_menu.open_for work_package - context_menu.choose "Bulk copy" + context_menu.choose 'Bulk copy' - expect(page).to have_css("#new_project_id") # rubocop:disable RSpec/ExpectInHook + expect(page).to have_css('#new_project_id') # rubocop:disable RSpec/ExpectInHook wait_for_network_idle expect_page_reload do - select_autocomplete page.find_test_selector("new_project_id"), + select_autocomplete page.find_test_selector('new_project_id'), query: project2.name, select_text: project2.name, - results_selector: "body" + results_selector: 'body' end wait_for_network_idle # wait for the change of target project to finish updating the page end - it "sets the version on copy and leaves a note" do - select version.name, from: "version_id" - notes.set_markdown "A note on copy" - click_on "Copy and follow" + it 'sets the version on copy and leaves a note' do + select version.name, from: 'version_id' + notes.set_markdown 'A note on copy' + click_on 'Copy and follow' wp_table_target.expect_current_path wp_table_target.expect_work_package_count 2 - expect(page).to have_css("#projects-menu", text: "Target") + expect(page).to have_css('#projects-menu', text: 'Target') # Should not move the sources work_package2.reload @@ -99,17 +99,17 @@ copied_wps = WorkPackage.last(2) expect(copied_wps.map(&:project_id).uniq).to eq([project2.id]) expect(copied_wps.map(&:version_id).uniq).to eq([version.id]) - expect(copied_wps.map { |wp| wp.journals.last.notes }.uniq).to eq(["A note on copy"]) + expect(copied_wps.map { |wp| wp.journals.last.notes }.uniq).to eq(['A note on copy']) end - context "when the limit to move in the frontend is 1", + context 'when the limit to move in the frontend is 1', with_settings: { work_packages_bulk_request_limit: 1 } do - it "copies them in the background and shows a status page" do - select version.name, from: "version_id" - notes.set_markdown "A note on copy" - click_on "Copy and follow" + it 'copies them in the background and shows a status page' do + select version.name, from: 'version_id' + notes.set_markdown 'A note on copy' + click_on 'Copy and follow' - expect(page).to have_text "The job has been queued and will be processed shortly." + expect(page).to have_text 'The job has been queued and will be processed shortly.' perform_enqueued_jobs @@ -118,7 +118,7 @@ end end - context "with a work package having a child" do + context 'with a work package having a child' do let!(:child) do create(:work_package, author: dev, @@ -138,26 +138,26 @@ wp_table.visit! expect_angular_frontend_initialized wp_table.expect_work_package_listed work_package, work_package2, child - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] wp_table.expect_work_package_count 3 context_menu.open_for work_package - context_menu.choose "Bulk copy" + context_menu.choose 'Bulk copy' - expect(page).to have_css("#new_project_id") # rubocop:disable RSpec/ExpectInHook + expect(page).to have_css('#new_project_id') # rubocop:disable RSpec/ExpectInHook expect_page_reload do - select_autocomplete page.find_test_selector("new_project_id"), + select_autocomplete page.find_test_selector('new_project_id'), query: project2.name, select_text: project2.name, - results_selector: "body" + results_selector: 'body' end sleep(1) # wait for the change of target project to finish updating the page end - it "copies WPs with parent/child hierarchy and relations maintained" do - click_on "Copy and follow" + it 'copies WPs with parent/child hierarchy and relations maintained' do + click_on 'Copy and follow' wp_table_target.expect_current_path - expect(page).to have_css("#projects-menu", text: "Target") + expect(page).to have_css('#projects-menu', text: 'Target') # Should not move the sources expect(work_package.reload.project_id).to eq(project.id) @@ -185,7 +185,7 @@ end end - context "when the target project does not have the type" do + context 'when the target project does not have the type' do let!(:child) do create(:work_package, author: dev, @@ -198,55 +198,55 @@ project2.types = [type2] end - it "fails, informing of the reasons" do - click_on "Copy and follow" + it 'fails, informing of the reasons' do + click_on 'Copy and follow' expect(page) .to have_css( - ".op-toast.-error", - text: I18n.t("work_packages.bulk.none_could_be_saved", total: 3) + '.op-toast.-error', + text: I18n.t('work_packages.bulk.none_could_be_saved', total: 3) ) expect(page) .to have_css( - ".op-toast.-error", - text: I18n.t("work_packages.bulk.selected_because_descendants", total: 3, selected: 2) + '.op-toast.-error', + text: I18n.t('work_packages.bulk.selected_because_descendants', total: 3, selected: 2) ) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: "#{work_package.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}" ) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: "#{work_package2.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}" ) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: "#{child.id} (descendant of selected): Type #{I18n.t('activerecord.errors.messages.inclusion')}" ) end - context "when the limit to move in the frontend is 0", + context 'when the limit to move in the frontend is 0', with_settings: { work_packages_bulk_request_limit: 0 } do - it "shows the errors properly in the frontend" do - click_on "Copy and follow" + it 'shows the errors properly in the frontend' do + click_on 'Copy and follow' - expect(page).to have_text "The job has been queued and will be processed shortly." + expect(page).to have_text 'The job has been queued and will be processed shortly.' perform_enqueued_jobs - expect(page).to have_text "The work packages could not be copied.", wait: 10 + expect(page).to have_text 'The work packages could not be copied.', wait: 10 - expect(page).to have_text I18n.t("work_packages.bulk.none_could_be_saved", total: 3) + expect(page).to have_text I18n.t('work_packages.bulk.none_could_be_saved', total: 3) expect(page) - .to have_text I18n.t("work_packages.bulk.selected_because_descendants", total: 3, selected: 2) + .to have_text I18n.t('work_packages.bulk.selected_because_descendants', total: 3, selected: 2) expect(page) .to have_text "#{work_package.id}: Type #{I18n.t('activerecord.errors.messages.inclusion')}" @@ -261,27 +261,27 @@ end end - context "without permission" do + context 'without permission' do let(:current_user) { dev } - it "does not allow to copy" do + it 'does not allow to copy' do context_menu.open_for work_package - context_menu.expect_no_options "Bulk copy" + context_menu.expect_no_options 'Bulk copy' end end end - describe "copying work package to clipboard" do + describe 'copying work package to clipboard' do let(:current_user) { dev } let(:wp_table_target) { Pages::WorkPackagesTable.new(project2) } before do wp_table.expect_work_package_count 2 context_menu.open_for work_package - context_menu.choose "Copy link to clipboard" + context_menu.choose 'Copy link to clipboard' end - it "successfully copies the short url of the work package" do + it 'successfully copies the short url of the work package' do # We cannot access the navigator.clipboard from a headless browser. # This test makes sure the copy to clipboard logic is working, # regardless of the browser permissions. @@ -289,7 +289,7 @@ end end - describe "unsetting the assignee as the current assignee is not a member in the project" do + describe 'unsetting the assignee as the current assignee is not a member in the project' do let(:work_packages) { [work_package] } let(:current_user) { mover } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -299,30 +299,30 @@ work_package.save end - it "copies the work package" do + it 'copies the work package' do context_menu.open_for work_package - context_menu.choose "Copy to other project" + context_menu.choose 'Copy to other project' # On work packages move page expect_page_reload do - select_autocomplete page.find_test_selector("new_project_id"), + select_autocomplete page.find_test_selector('new_project_id'), query: project2.name, select_text: project2.name, - results_selector: "body" + results_selector: 'body' end wait_for_network_idle # wait for page reload after selecting the target project - select "nobody", from: "Assignee" + select 'nobody', from: 'Assignee' - click_on "Copy and follow" + click_on 'Copy and follow' expect(page) - .to have_css(".op-toast.-success", + .to have_css('.op-toast.-success', text: I18n.t(:notice_successful_create)) wp_page = Pages::FullWorkPackage.new(WorkPackage.last) - wp_page.expect_attributes assignee: "-" + wp_page.expect_attributes assignee: '-' end end end diff --git a/spec/features/work_packages/bulk/move_work_package_spec.rb b/spec/features/work_packages/bulk/move_work_package_spec.rb index 43f3b35bf9d8..21dd70e0ccf2 100644 --- a/spec/features/work_packages/bulk/move_work_package_spec.rb +++ b/spec/features/work_packages/bulk/move_work_package_spec.rb @@ -1,8 +1,8 @@ -require "spec_helper" -require "features/page_objects/notification" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'spec_helper' +require 'features/page_objects/notification' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' -RSpec.describe "Moving a work package through Rails view", :js do +RSpec.describe 'Moving a work package through Rails view', :js do include Components::Autocompleter::NgSelectAutocompleteHelpers let(:dev_role) do @@ -15,22 +15,22 @@ end let(:dev) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_roles: { project => dev_role }) end let(:mover) do create(:admin, - firstname: "Manager", - lastname: "Guy", + firstname: 'Manager', + lastname: 'Guy', member_with_roles: { project => mover_role }) end - let(:type) { create(:type, name: "Bug") } - let(:type2) { create(:type, name: "Risk") } + let(:type) { create(:type, name: 'Bug') } + let(:type2) { create(:type, name: 'Risk') } - let!(:project) { create(:project, name: "Source", types: [type, type2]) } - let!(:project2) { create(:project, name: "Target", types: [type, type2]) } + let!(:project) { create(:project, name: 'Source', types: [type, type2]) } + let!(:project2) { create(:project, name: 'Target', types: [type, type2]) } let(:work_package) do create(:work_package, @@ -62,7 +62,7 @@ expect_angular_frontend_initialized end - describe "moving a work package and its children" do + describe 'moving a work package and its children' do let(:work_packages) { [work_package, child_wp] } let(:child_wp) do create(:work_package, @@ -73,19 +73,19 @@ status:) end - context "with permission" do + context 'with permission' do before do expect(child_wp.project_id).to eq(project.id) context_menu.open_for work_package - context_menu.choose "Change project" + context_menu.choose 'Change project' # On work packages move page - expect(page).to have_css("#new_project_id") - select_autocomplete page.find_test_selector("new_project_id"), - query: "Target", - select_text: "Target", - results_selector: "body" + expect(page).to have_css('#new_project_id') + select_autocomplete page.find_test_selector('new_project_id'), + query: 'Target', + select_text: 'Target', + results_selector: 'body' if using_cuprite? wait_for_network_idle else @@ -93,14 +93,14 @@ end end - context "when the limit to move in the frontend is 1", + context 'when the limit to move in the frontend is 1', with_settings: { work_packages_bulk_request_limit: 1 } do - it "copies them in the background and shows a status page", :with_cuprite do - click_on "Move and follow" + it 'copies them in the background and shows a status page', :with_cuprite do + click_on 'Move and follow' wait_for_reload - page.find_test_selector("job-status--header") + page.find_test_selector('job-status--header') - expect(page).to have_text "The job has been queued and will be processed shortly." + expect(page).to have_text 'The job has been queued and will be processed shortly.' perform_enqueued_jobs @@ -108,29 +108,29 @@ expect(work_package.project_id).to eq(project2.id) expect(page).to have_current_path "/projects/#{project2.identifier}/work_packages/#{work_package.id}/activity" - page.find_by_id("projects-menu", text: "Target") + page.find_by_id('projects-menu', text: 'Target') end end - it "moves parent and child wp to a new project", :with_cuprite do - click_on "Move and follow" + it 'moves parent and child wp to a new project', :with_cuprite do + click_on 'Move and follow' wait_for_reload - page.find(".inline-edit--container.subject", text: work_package.subject) - page.find_by_id("projects-menu", text: "Target") + page.find('.inline-edit--container.subject', text: work_package.subject) + page.find_by_id('projects-menu', text: 'Target') # Should move its children child_wp.reload expect(child_wp.project_id).to eq(project2.id) end - context "when the target project does not have the type" do - let!(:project2) { create(:project, name: "Target", types: [type2]) } + context 'when the target project does not have the type' do + let!(:project2) { create(:project, name: 'Target', types: [type2]) } - it "does moves the work package and changes the type", :with_cuprite do - click_on "Move and follow" + it 'does moves the work package and changes the type', :with_cuprite do + click_on 'Move and follow' wait_for_reload - page.find(".inline-edit--container.subject", text: work_package.subject) - page.find_by_id("projects-menu", text: "Target") + page.find('.inline-edit--container.subject', text: work_package.subject) + page.find_by_id('projects-menu', text: 'Target') # Should NOT have moved child_wp.reload @@ -142,24 +142,24 @@ end end - context "when the target project has a type with a required field" do + context 'when the target project has a type with a required field' do let(:required_cf) { create(:integer_wp_custom_field, is_required: true) } - let(:type2) { create(:type, name: "Risk", custom_fields: [required_cf]) } - let!(:project2) { create(:project, name: "Target", types: [type2], work_package_custom_fields: [required_cf]) } + let(:type2) { create(:type, name: 'Risk', custom_fields: [required_cf]) } + let!(:project2) { create(:project, name: 'Target', types: [type2], work_package_custom_fields: [required_cf]) } - it "does not moves the work package when the required field is missing" do + it 'does not moves the work package when the required field is missing' do select "Risk", from: "Type" expect(page).to have_field(required_cf.name) # Clicking move and follow might be broken due to the location.href # in the refresh-on-form-changes component retry_block do - click_on "Move and follow" + click_on 'Move and follow' end expect(page) - .to have_css(".op-toast.-error", - text: I18n.t(:"work_packages.bulk.none_could_be_saved", + .to have_css('.op-toast.-error', + text: I18n.t(:'work_packages.bulk.none_could_be_saved', total: 1)) child_wp.reload work_package.reload @@ -169,17 +169,17 @@ expect(child_wp.type_id).to eq(type.id) end - it "does moves the work package when the required field is set" do + it 'does moves the work package when the required field is set' do select "Risk", from: "Type" - fill_in required_cf.name, with: "1" + fill_in required_cf.name, with: '1' # Clicking move and follow might be broken due to the location.href # in the refresh-on-form-changes component retry_block do - click_on "Move and follow" + click_on 'Move and follow' end - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') child_wp.reload work_package.reload @@ -191,51 +191,51 @@ end end - context "without permission" do + context 'without permission' do let(:current_user) { dev } - it "does not allow to move" do + it 'does not allow to move' do context_menu.open_for work_package - context_menu.expect_no_options "Change project" + context_menu.expect_no_options 'Change project' end end end - describe "moving an unmovable (e.g. readonly status) and a movable work package", with_ee: %i[readonly_work_packages] do + describe 'moving an unmovable (e.g. readonly status) and a movable work package', with_ee: %i[readonly_work_packages] do let(:work_packages) { [work_package, work_package2] } let(:work_package2_status) { create(:status, is_readonly: true) } before do loading_indicator_saveguard # Select all work packages - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] context_menu.open_for work_package2 - context_menu.choose "Bulk change of project" + context_menu.choose 'Bulk change of project' # On work packages move page - select_autocomplete page.find_test_selector("new_project_id"), + select_autocomplete page.find_test_selector('new_project_id'), query: project2.name, select_text: project2.name, - results_selector: "body" - click_on "Move and follow" + results_selector: 'body' + click_on 'Move and follow' end - it "displays an error message explaining which work package could not be moved and why" do + it 'displays an error message explaining which work package could not be moved and why' do expect(page) - .to have_css(".op-toast.-error", - text: I18n.t("work_packages.bulk.could_not_be_saved"), + .to have_css('.op-toast.-error', + text: I18n.t('work_packages.bulk.could_not_be_saved'), wait: 10) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: "#{work_package2.id}: Project #{I18n.t('activerecord.errors.messages.error_readonly')}" ) expect(page) - .to have_css(".op-toast.-error", - text: I18n.t("work_packages.bulk.x_out_of_y_could_be_saved", + .to have_css('.op-toast.-error', + text: I18n.t('work_packages.bulk.x_out_of_y_could_be_saved', failing: 1, total: 2, success: 1)) diff --git a/spec/features/work_packages/bulk/update_work_package_spec.rb b/spec/features/work_packages/bulk/update_work_package_spec.rb index 6689aff8ae9f..7f07d525b897 100644 --- a/spec/features/work_packages/bulk/update_work_package_spec.rb +++ b/spec/features/work_packages/bulk/update_work_package_spec.rb @@ -1,19 +1,19 @@ -require "spec_helper" -require "features/page_objects/notification" +require 'spec_helper' +require 'features/page_objects/notification' -RSpec.describe "Bulk update work packages through Rails view", :js, :with_cuprite do - shared_let(:type) { create(:type, name: "Bug") } - shared_let(:project) { create(:project, name: "Source", types: [type]) } +RSpec.describe 'Bulk update work packages through Rails view', :js, :with_cuprite do + shared_let(:type) { create(:type, name: 'Bug') } + shared_let(:project) { create(:project, name: 'Source', types: [type]) } shared_let(:status) { create(:status) } shared_let(:custom_field) do create(:string_wp_custom_field, - name: "Text CF", + name: 'Text CF', types: [type], projects: [project]) end shared_let(:custom_field_removed) do create(:string_wp_custom_field, - name: "Text CF Removed", + name: 'Text CF Removed', types: [type], projects: [project]) end @@ -27,14 +27,14 @@ end shared_let(:dev) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_roles: { project => dev_role }) end shared_let(:mover) do create(:admin, - firstname: "Manager", - lastname: "Guy", + firstname: 'Manager', + lastname: 'Guy', member_with_roles: { project => mover_role }) end @@ -75,22 +75,22 @@ wp_table.expect_work_package_listed work_package, work_package2 # Select all work packages - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] end - context "with permission" do + context 'with permission' do let(:current_user) { mover } before do context_menu.open_for work_package - context_menu.choose "Bulk edit" + context_menu.choose 'Bulk edit' - notes.set_markdown("The typed note") + notes.set_markdown('The typed note') end - it "sets status and leaves a note" do - select status2.name, from: "work_package_status_id" - click_on "Submit" + it 'sets status and leaves a note' do + select status2.name, from: 'work_package_status_id' + click_on 'Submit' expect_angular_frontend_initialized wp_table.expect_work_package_count 2 @@ -100,32 +100,32 @@ .to eq([status2.id]) expect([work_package.journals.last.notes, work_package2.journals.last.notes].uniq) - .to eq(["The typed note"]) + .to eq(['The typed note']) end - context "when making an error in the form" do + context 'when making an error in the form' do let(:work_package2_status) { create(:status) } # without creating a workflow - it "does not update the work packages" do - select status2.name, from: "work_package_status_id" - fill_in "Parent", with: "-1" - click_on "Submit" + it 'does not update the work packages' do + select status2.name, from: 'work_package_status_id' + fill_in 'Parent', with: '-1' + click_on 'Submit' expect(page) .to have_css( - ".op-toast.-error", - text: I18n.t("work_packages.bulk.none_could_be_saved", total: 2) + '.op-toast.-error', + text: I18n.t('work_packages.bulk.none_could_be_saved', total: 2) ) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: "#{work_package.id}: Parent #{I18n.t('activerecord.errors.messages.does_not_exist')}" ) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: <<~MSG.squish #{work_package2.id}: Parent #{I18n.t('activerecord.errors.messages.does_not_exist')} @@ -141,27 +141,27 @@ end end - describe "custom fields" do - context "when editing custom field of work packages with a readonly status (regression#44673)" do + describe 'custom fields' do + context 'when editing custom field of work packages with a readonly status (regression#44673)' do let(:work_package2_status) { create(:status, :readonly) } - context "with enterprise", with_ee: %i[readonly_work_packages] do - it "does not update the work packages" do + context 'with enterprise', with_ee: %i[readonly_work_packages] do + it 'does not update the work packages' do expect(work_package.send(custom_field.attribute_getter)).to be_nil expect(work_package2.send(custom_field.attribute_getter)).to be_nil - fill_in custom_field.name, with: "Custom field text" - click_on "Submit" + fill_in custom_field.name, with: 'Custom field text' + click_on 'Submit' expect(page) .to have_css( - ".op-toast.-error", - text: I18n.t("work_packages.bulk.x_out_of_y_could_be_saved", total: 2, failing: 1, success: 1) + '.op-toast.-error', + text: I18n.t('work_packages.bulk.x_out_of_y_could_be_saved', total: 2, failing: 1, success: 1) ) expect(page) .to have_css( - ".op-toast.-error", + '.op-toast.-error', text: <<~MSG.squish #{work_package2.id}: #{custom_field.name} #{I18n.t('activerecord.errors.messages.error_readonly')} @@ -174,60 +174,60 @@ work_package2.reload expect(work_package.send(custom_field.attribute_getter)) - .to eq("Custom field text") + .to eq('Custom field text') expect(work_package2.send(custom_field.attribute_getter)) .to be_nil end end - context "without enterprise", with_ee: false do - it "ignores the readonly status and updates the work packages" do + context 'without enterprise', with_ee: false do + it 'ignores the readonly status and updates the work packages' do expect(work_package.send(custom_field.attribute_getter)).to be_nil expect(work_package2.send(custom_field.attribute_getter)).to be_nil - fill_in custom_field.name, with: "Custom field text" - click_on "Submit" + fill_in custom_field.name, with: 'Custom field text' + click_on 'Submit' - expect(page).to have_css(".op-toast.-success", text: I18n.t(:notice_successful_update)) + expect(page).to have_css('.op-toast.-success', text: I18n.t(:notice_successful_update)) # Should update 2 work package custom fields work_package.reload work_package2.reload expect(work_package.send(custom_field.attribute_getter)) - .to eq("Custom field text") + .to eq('Custom field text') expect(work_package2.send(custom_field.attribute_getter)) - .to eq("Custom field text") + .to eq('Custom field text') end end end - describe "unsetting values for different fields" do + describe 'unsetting values for different fields' do let(:boolean_cf) do create(:boolean_wp_custom_field, - name: "Bool CF", + name: 'Bool CF', types: [type], projects: [project]) end let(:required_boolean_cf) do create(:boolean_wp_custom_field, - name: "Required Bool CF", + name: 'Required Bool CF', types: [type], projects: [project], is_required: true) end let(:list_cf) do create(:list_wp_custom_field, - name: "List CF", + name: 'List CF', types: [type], projects: [project], possible_values: %w[A B C]) end let(:required_list_cf) do create(:list_wp_custom_field, - name: "Required List CF", + name: 'Required List CF', types: [type], projects: [project], possible_values: %w[A B C], @@ -235,20 +235,20 @@ end let(:multi_list_cf) do create(:list_wp_custom_field, :multi_list, - name: "Multi select List CF", + name: 'Multi select List CF', types: [type], projects: [project], possible_values: %w[A B C]) end let(:user_cf) do create(:user_wp_custom_field, - name: "User CF", + name: 'User CF', types: [type], projects: [project]) end let(:multi_user_cf) do create(:user_wp_custom_field, :multi_user, - name: "Multi user CF", + name: 'Multi user CF', types: [type], projects: [project]) end @@ -274,33 +274,33 @@ wait_for_reload end - it "clears the chosen values" do + it 'clears the chosen values' do # Required fields should not have a 'none' option - expect(page).to have_no_select(required_boolean_cf.name, with_options: ["none"]) - expect(page).to have_no_select(required_list_cf.name, with_options: ["none"]) + expect(page).to have_no_select(required_boolean_cf.name, with_options: ['none']) + expect(page).to have_no_select(required_list_cf.name, with_options: ['none']) # Unset any non-required fields - select "none", from: boolean_cf.name - select "none", from: list_cf.name - select "none", from: multi_list_cf.name - select "nobody", from: user_cf.name - select "nobody", from: multi_user_cf.name + select 'none', from: boolean_cf.name + select 'none', from: list_cf.name + select 'none', from: multi_list_cf.name + select 'nobody', from: user_cf.name + select 'nobody', from: multi_user_cf.name - click_on "Submit" + click_on 'Submit' expect_angular_frontend_initialized wp_table.expect_work_package_count 2 # It clears all the values except the required fields expect(work_package.reload.custom_field_values.pluck(:value).compact) - .to eq(["f", required_list_cf.custom_options.find_by(value: "B").id.to_s]) + .to eq(['f', required_list_cf.custom_options.find_by(value: "B").id.to_s]) expect(work_package2.reload.custom_field_values.pluck(:value).compact) - .to eq(["f", required_list_cf.custom_options.find_by(value: "B").id.to_s]) + .to eq(['f', required_list_cf.custom_options.find_by(value: "B").id.to_s]) end end - context "when custom fields are removed from types" do - it "does not display them on the form" do + context 'when custom fields are removed from types' do + it 'does not display them on the form' do expect(page).to have_field custom_field_removed.name custom_field_removed.types = [] @@ -314,12 +314,12 @@ end end - context "without permission" do + context 'without permission' do let(:current_user) { dev } - it "does not allow to copy" do + it 'does not allow to copy' do context_menu.open_for work_package - context_menu.expect_no_options "Bulk edit" + context_menu.expect_no_options 'Bulk edit' end end end diff --git a/spec/features/work_packages/cancel_editing_spec.rb b/spec/features/work_packages/cancel_editing_spec.rb index 8a16f99f4e11..038d1cd36944 100644 --- a/spec/features/work_packages/cancel_editing_spec.rb +++ b/spec/features/work_packages/cancel_editing_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Cancel editing work package", :js do +RSpec.describe 'Cancel editing work package', :js do let(:user) { create(:admin) } let(:project) { create(:project) } let(:work_package) { create(:work_package, project:) } @@ -53,22 +53,22 @@ def expect_active_edit(path) visit path expect_angular_frontend_initialized - expect(page).to have_css("#wp-new-inline-edit--field-subject", wait: 10) + expect(page).to have_css('#wp-new-inline-edit--field-subject', wait: 10) end def expect_subject(val) - subject = page.find_by_id("wp-new-inline-edit--field-subject") + subject = page.find_by_id('wp-new-inline-edit--field-subject') expect(subject.value).to eq(val) end def move_to_home_page(alert: true) - find(".op-logo--link").click + find('.op-logo--link').click page.driver.browser.switch_to.alert.accept if alert - expect(page).to have_css("#projects-menu", text: "Select a project") + expect(page).to have_css('#projects-menu', text: 'Select a project') end - it "does not show an alert when moving to other pages" do + it 'does not show an alert when moving to other pages' do # This used to show an alert until browsers dropped support # for `onbeforeunload`. # @@ -84,7 +84,7 @@ def move_to_home_page(alert: true) end end - it "shows an alert when moving to other states" do + it 'shows an alert when moving to other states' do expect_active_edit(new_split_work_packages_path) loading_indicator_saveguard wp_table.expect_work_package_listed(work_package2) @@ -92,11 +92,11 @@ def move_to_home_page(alert: true) wp_table.open_split_view(work_package2) page.driver.browser.switch_to.alert.dismiss - expect(page).to have_css("#wp-new-inline-edit--field-subject") + expect(page).to have_css('#wp-new-inline-edit--field-subject') expect(wp_page).not_to have_alert_dialog end - it "shows an alert when moving to other states while editing a single attribute (Regression #25135)" do + it 'shows an alert when moving to other states while editing a single attribute (Regression #25135)' do wp_table.visit! wp_table.expect_work_package_listed(work_package, work_package2) @@ -119,45 +119,45 @@ def move_to_home_page(alert: true) version.expect_inactive! end - it "cancels the editing when clicking the button" do + it 'cancels the editing when clicking the button' do paths.each do |path| expect_active_edit(path) - find_by_id("work-packages--edit-actions-cancel").click + find_by_id('work-packages--edit-actions-cancel').click expect(wp_page).not_to have_alert_dialog end end - it "allows to move from split to full screen in edit mode" do + it 'allows to move from split to full screen in edit mode' do # Start creating on split view expect_active_edit(new_split_work_packages_path) - find_by_id("wp-new-inline-edit--field-subject").set "foobar" + find_by_id('wp-new-inline-edit--field-subject').set 'foobar' # Expect editing works when moving to full screen - find(".work-packages-show-view-button").click + find('.work-packages-show-view-button').click expect(wp_page).not_to have_alert_dialog - expect(page).to have_css("#wp-new-inline-edit--field-subject") - expect_subject("foobar") + expect(page).to have_css('#wp-new-inline-edit--field-subject') + expect_subject('foobar') # Moving back also works - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') expect(wp_page).not_to have_alert_dialog - expect(page).to have_css("#wp-new-inline-edit--field-subject") - expect_subject("foobar") + expect(page).to have_css('#wp-new-inline-edit--field-subject') + expect_subject('foobar') # Cancel edition - find_by_id("work-packages--edit-actions-cancel").click + find_by_id('work-packages--edit-actions-cancel').click expect(wp_page).not_to have_alert_dialog # Visiting another page does not create alert - find(".op-logo--link").click + find('.op-logo--link').click expect(wp_page).not_to have_alert_dialog end - it "correctly cancels setting the back route (Regression #30714)" do + it 'correctly cancels setting the back route (Regression #30714)' do wp_page = Pages::FullWorkPackage.new work_package wp_page.visit! wp_page.ensure_page_loaded @@ -165,7 +165,7 @@ def move_to_home_page(alert: true) # Edit description in full view description = wp_page.edit_field :description description.activate! - description.click_and_type_slowly "foobar" + description.click_and_type_slowly 'foobar' # Try to move back to list, expect warning wp_page.go_back @@ -180,12 +180,12 @@ def move_to_home_page(alert: true) wp_table.expect_work_package_listed(work_package, work_package2) end - context "when user does not want to be warned" do + context 'when user does not want to be warned' do before do create(:user_preference, user:, others: { warn_on_leaving_unsaved: false }) end - it "does not alert when moving anywhere" do + it 'does not alert when moving anywhere' do # Moving to angular states expect_active_edit(new_split_work_packages_path) wp_table.expect_work_package_listed(work_package2) @@ -193,8 +193,8 @@ def move_to_home_page(alert: true) wp_table.open_split_view(work_package2) expect(wp_page).not_to have_alert_dialog - expect(page).to have_no_css("#wp-new-inline-edit--field-subject") - expect(page).to have_css(".work-packages--details--subject", text: work_package2.subject) + expect(page).to have_no_css('#wp-new-inline-edit--field-subject') + expect(page).to have_css('.work-packages--details--subject', text: work_package2.subject) # Moving somewhere else expect_active_edit(new_split_work_packages_path) diff --git a/spec/features/work_packages/copy_spec.rb b/spec/features/work_packages/copy_spec.rb index 4073eccc4c73..53ccc792d3ba 100644 --- a/spec/features/work_packages/copy_spec.rb +++ b/spec/features/work_packages/copy_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package copy", :js, :selenium do +RSpec.describe 'Work package copy', :js, :selenium do let(:user) do create(:user, member_with_roles: { project => create_role }) @@ -63,20 +63,20 @@ let(:role) { build(:project_role, permissions: %i[view_work_packages work_package_assigned]) } let(:assignee) do create(:user, - firstname: "An", - lastname: "assignee", + firstname: 'An', + lastname: 'assignee', member_with_roles: { project => role }) end let(:responsible) do create(:user, - firstname: "The", - lastname: "responsible", + firstname: 'The', + lastname: 'responsible', member_with_roles: { project => role }) end let(:author) do create(:user, - firstname: "The", - lastname: "author", + firstname: 'The', + lastname: 'author', member_with_roles: { project => role }) end let(:version) do @@ -90,21 +90,21 @@ work_flow.save! end - it "on fullscreen page" do + it 'on fullscreen page' do original_work_package_page = Pages::FullWorkPackage.new(original_work_package, project) to_copy_work_package_page = original_work_package_page.visit_copy! to_copy_work_package_page.expect_current_path to_copy_work_package_page.expect_fully_loaded - to_copy_work_package_page.update_attributes Description: "Copied WP Description" + to_copy_work_package_page.update_attributes Description: 'Copied WP Description' to_copy_work_package_page.save! - expect(page).to have_css(".op-toast--content", - text: I18n.t("js.notice_successful_create"), + expect(page).to have_css('.op-toast--content', + text: I18n.t('js.notice_successful_create'), wait: 20) - copied_work_package = WorkPackage.order(created_at: "desc").first + copied_work_package = WorkPackage.order(created_at: 'desc').first expect(copied_work_package).not_to eql original_work_package @@ -112,7 +112,7 @@ work_package_page.ensure_page_loaded work_package_page.expect_attributes Subject: original_work_package.subject, - Description: "Copied WP Description", + Description: 'Copied WP Description', Version: original_work_package.version, Priority: original_work_package.priority, Assignee: original_work_package.assigned_to.name, @@ -123,41 +123,41 @@ work_package_page.visit_tab! :relations expect_angular_frontend_initialized - expect(page).to have_css(".relation-group--header", text: "RELATED TO", wait: 20) - expect(page).to have_test_selector("op-relation--row-subject", text: original_work_package.subject) + expect(page).to have_css('.relation-group--header', text: 'RELATED TO', wait: 20) + expect(page).to have_test_selector('op-relation--row-subject', text: original_work_package.subject) end - describe "when source work package has an attachment" do - it "still allows copying through menu (Regression #30518)" do + describe 'when source work package has an attachment' do + it 'still allows copying through menu (Regression #30518)' do wp_page = Pages::FullWorkPackage.new(original_work_package, project) wp_page.visit! wp_page.ensure_page_loaded # Go to add cost entry page - find("#action-show-more-dropdown-menu .button").click - find(".menu-item", text: "Copy", exact_text: true).click + find('#action-show-more-dropdown-menu .button').click + find('.menu-item', text: 'Copy', exact_text: true).click to_copy_work_package_page = Pages::FullWorkPackageCreate.new(original_work_package:) - to_copy_work_package_page.update_attributes Description: "Copied WP Description" + to_copy_work_package_page.update_attributes Description: 'Copied WP Description' to_copy_work_package_page.save! - to_copy_work_package_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_create") + to_copy_work_package_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_create') end end - it "on split screen page" do + it 'on split screen page' do original_work_package_page = Pages::SplitWorkPackage.new(original_work_package, project) to_copy_work_package_page = original_work_package_page.visit_copy! to_copy_work_package_page.expect_current_path to_copy_work_package_page.expect_fully_loaded - to_copy_work_package_page.update_attributes Description: "Copied WP Description" + to_copy_work_package_page.update_attributes Description: 'Copied WP Description' to_copy_work_package_page.save! - find(".op-toast--content", text: I18n.t("js.notice_successful_create"), wait: 20) + find('.op-toast--content', text: I18n.t('js.notice_successful_create'), wait: 20) - copied_work_package = WorkPackage.order(created_at: "desc").first + copied_work_package = WorkPackage.order(created_at: 'desc').first expect(copied_work_package).not_to eql original_work_package @@ -165,7 +165,7 @@ work_package_page.ensure_page_loaded work_package_page.expect_attributes Subject: original_work_package.subject, - Description: "Copied WP Description", + Description: 'Copied WP Description', Version: original_work_package.version, Priority: original_work_package.priority, Assignee: original_work_package.assigned_to, @@ -174,9 +174,9 @@ work_package_page.expect_activity user, number: 1 work_package_page.expect_current_path - work_package_page.visit_tab!("relations") + work_package_page.visit_tab!('relations') expect_angular_frontend_initialized - expect(page).to have_css(".relation-group--header", text: "RELATED TO", wait: 20) - expect(page).to have_test_selector("op-relation--row-subject", text: original_work_package.subject) + expect(page).to have_css('.relation-group--header', text: 'RELATED TO', wait: 20) + expect(page).to have_test_selector('op-relation--row-subject', text: original_work_package.subject) end end diff --git a/spec/features/work_packages/custom_actions/custom_actions_me_value_spec.rb b/spec/features/work_packages/custom_actions/custom_actions_me_value_spec.rb index 6f1938bf9be5..f6dcd7ea364e 100644 --- a/spec/features/work_packages/custom_actions/custom_actions_me_value_spec.rb +++ b/spec/features/work_packages/custom_actions/custom_actions_me_value_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Custom actions me value", :js, :with_cuprite, with_ee: %i[custom_actions] do +RSpec.describe 'Custom actions me value', :js, :with_cuprite, with_ee: %i[custom_actions] do shared_let(:admin) { create(:admin) } let(:permissions) { %i(view_work_packages edit_work_packages) } @@ -37,7 +37,7 @@ create(:user, member_with_roles: { project => role }) end let(:type) { create(:type_task) } - let(:project) { create(:project, types: [type], name: "This project") } + let(:project) { create(:project, types: [type], name: 'This project') } let!(:custom_field) { create(:user_wp_custom_field, types: [type], projects: [project]) } let!(:work_package) do create(:work_package, @@ -47,7 +47,7 @@ let(:wp_page) { Pages::FullWorkPackage.new(work_package) } let(:default_priority) do - create(:default_priority, name: "Normal") + create(:default_priority, name: 'Normal') end let(:index_ca_page) { Pages::Admin::CustomActions::Index.new } @@ -55,26 +55,26 @@ login_as(admin) end - it "can assign user custom field to self" do + it 'can assign user custom field to self' do # create custom action 'Unassign' index_ca_page.visit! new_ca_page = index_ca_page.new - new_ca_page.set_name("Set CF to me") - new_ca_page.add_action(custom_field.name, I18n.t("custom_actions.actions.assigned_to.executing_user_value")) + new_ca_page.set_name('Set CF to me') + new_ca_page.add_action(custom_field.name, I18n.t('custom_actions.actions.assigned_to.executing_user_value')) new_ca_page.create assign = CustomAction.last expect(assign.actions.length).to eq(1) expect(assign.conditions.length).to eq(0) - expect(assign.actions.first.values).to eq(["current_user"]) + expect(assign.actions.first.values).to eq(['current_user']) login_as user wp_page.visit! - wp_page.expect_custom_action("Set CF to me") - wp_page.click_custom_action("Set CF to me") + wp_page.expect_custom_action('Set CF to me') + wp_page.click_custom_action('Set CF to me') wp_page.expect_attributes "customField#{custom_field.id}": user.name end end diff --git a/spec/features/work_packages/custom_actions/custom_actions_spec.rb b/spec/features/work_packages/custom_actions/custom_actions_spec.rb index f3f40b859dab..d2690c01f2b4 100644 --- a/spec/features/work_packages/custom_actions/custom_actions_spec.rb +++ b/spec/features/work_packages/custom_actions/custom_actions_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Custom actions", :js, :with_cuprite, +RSpec.describe 'Custom actions', :js, :with_cuprite, with_ee: %i[custom_actions] do shared_let(:admin) { create(:admin) } shared_let(:permissions) { %i(view_work_packages edit_work_packages move_work_packages work_package_assigned) } shared_let(:role) { create(:project_role, permissions:) } shared_let(:other_role) { create(:project_role, permissions:) } - shared_let(:project) { create(:project, name: "This project") } - shared_let(:other_project) { create(:project, name: "Other project") } + shared_let(:project) { create(:project, name: 'This project') } + shared_let(:other_project) { create(:project, name: 'Other project') } shared_let(:user) do create(:user, - firstname: "A", - lastname: "User", + firstname: 'A', + lastname: 'User', member_with_roles: { project => [role], other_project => [role] }) end shared_let(:other_member_user) do create(:user, - firstname: "Other member", - lastname: "User", + firstname: 'Other member', + lastname: 'User', member_with_roles: { project => role }) end @@ -60,21 +60,21 @@ let(:wp_page) { Pages::FullWorkPackage.new(work_package) } let(:default_priority) do - create(:default_priority, name: "Normal") + create(:default_priority, name: 'Normal') end let!(:immediate_priority) do create(:issue_priority, - name: "At once", + name: 'At once', position: IssuePriority.maximum(:position) + 1) end let(:default_status) do - create(:default_status, name: "Default status") + create(:default_status, name: 'Default status') end let(:closed_status) do - create(:closed_status, name: "Closed") + create(:closed_status, name: 'Closed') end let(:rejected_status) do - create(:closed_status, name: "Rejected") + create(:closed_status, name: 'Rejected') end let(:other_type) do type = create(:type) @@ -134,21 +134,21 @@ login_as admin end - it "viewing workflow buttons" do + it 'viewing workflow buttons' do # create custom action 'Unassign' index_ca_page.visit! new_ca_page = index_ca_page.new - new_ca_page.set_name("Unassign") - new_ca_page.set_description("Removes the assignee") - new_ca_page.add_action("Assignee", "-") - new_ca_page.expect_action("assigned_to", nil) + new_ca_page.set_name('Unassign') + new_ca_page.set_description('Removes the assignee') + new_ca_page.add_action('Assignee', '-') + new_ca_page.expect_action('assigned_to', nil) new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign") + index_ca_page.expect_listed('Unassign') unassign = CustomAction.last expect(unassign.actions.length).to eq(1) @@ -158,22 +158,22 @@ new_ca_page = index_ca_page.new - new_ca_page.set_name("Close") + new_ca_page.set_name('Close') - new_ca_page.add_action("Status", "Close") - new_ca_page.expect_action("status", closed_status.id) + new_ca_page.add_action('Status', 'Close') + new_ca_page.expect_action('status', closed_status.id) - new_ca_page.set_condition("Role", role.name) + new_ca_page.set_condition('Role', role.name) new_ca_page.expect_selected_option role.name - new_ca_page.set_condition("Status", [default_status.name, rejected_status.name]) + new_ca_page.set_condition('Status', [default_status.name, rejected_status.name]) new_ca_page.expect_selected_option default_status.name new_ca_page.expect_selected_option rejected_status.name new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign", "Close") + index_ca_page.expect_listed('Unassign', 'Close') close = CustomAction.last expect(close.actions.length).to eq(1) @@ -182,22 +182,22 @@ # create custom action 'Escalate' new_ca_page = index_ca_page.new - new_ca_page.set_name("Escalate") - new_ca_page.add_action("Priority", immediate_priority.name) - new_ca_page.expect_action("priority", immediate_priority.id) + new_ca_page.set_name('Escalate') + new_ca_page.add_action('Priority', immediate_priority.name) + new_ca_page.expect_action('priority', immediate_priority.id) - new_ca_page.add_action("Notify", other_member_user.name) + new_ca_page.add_action('Notify', other_member_user.name) new_ca_page.expect_selected_option other_member_user.name new_ca_page.add_action(list_custom_field.name, selected_list_custom_field_options.map(&:name)) - new_ca_page.expect_selected_option "A" - new_ca_page.expect_selected_option "G" + new_ca_page.expect_selected_option 'A' + new_ca_page.expect_selected_option 'G' new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign", "Close", "Escalate") + index_ca_page.expect_listed('Unassign', 'Close', 'Escalate') escalate = CustomAction.last expect(escalate.actions.length).to eq(3) @@ -207,28 +207,28 @@ new_ca_page = index_ca_page.new - new_ca_page.set_name("Reset") + new_ca_page.set_name('Reset') - new_ca_page.add_action("Priority", default_priority.name) - new_ca_page.expect_action("priority", default_priority.id) + new_ca_page.add_action('Priority', default_priority.name) + new_ca_page.expect_action('priority', default_priority.id) - new_ca_page.add_action("Status", default_status.name) - new_ca_page.expect_action("status", default_status.id) + new_ca_page.add_action('Status', default_status.name) + new_ca_page.expect_action('status', default_status.id) - new_ca_page.add_action("Assignee", user.name) - new_ca_page.expect_action("assigned_to", user.id) + new_ca_page.add_action('Assignee', user.name) + new_ca_page.expect_action('assigned_to', user.id) # This custom field is not applicable - new_ca_page.add_action(int_custom_field.name, "1") - new_ca_page.expect_action(int_custom_field.attribute_name, "1") + new_ca_page.add_action(int_custom_field.name, '1') + new_ca_page.expect_action(int_custom_field.attribute_name, '1') - new_ca_page.set_condition("Status", closed_status.name) + new_ca_page.set_condition('Status', closed_status.name) new_ca_page.expect_selected_option closed_status.name new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign", "Close", "Escalate", "Reset") + index_ca_page.expect_listed('Unassign', 'Close', 'Escalate', 'Reset') reset = CustomAction.last expect(reset.actions.length).to eq(4) @@ -238,17 +238,17 @@ new_ca_page = index_ca_page.new - new_ca_page.set_name("Other roles action") + new_ca_page.set_name('Other roles action') - new_ca_page.add_action("Status", default_status.name) - new_ca_page.expect_action("status", default_status.id) + new_ca_page.add_action('Status', default_status.name) + new_ca_page.expect_action('status', default_status.id) - new_ca_page.set_condition("Role", other_role.name) + new_ca_page.set_condition('Role', other_role.name) new_ca_page.expect_selected_option other_role.name new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign", "Close", "Escalate", "Reset", "Other roles action") + index_ca_page.expect_listed('Unassign', 'Close', 'Escalate', 'Reset', 'Other roles action') other_roles_action = CustomAction.last expect(other_roles_action.actions.length).to eq(1) @@ -259,36 +259,36 @@ new_ca_page = index_ca_page.new retry_block do - new_ca_page.set_name("Move project") + new_ca_page.set_name('Move project') # Add date custom action which has a different admin layout ignore_ferrum_javascript_error do - select date_custom_field.name, from: "Add action" + select date_custom_field.name, from: 'Add action' end ignore_ferrum_javascript_error do - select "on", from: date_custom_field.name + select 'on', from: date_custom_field.name end date = (Date.current + 5.days) find("#custom_action_actions_custom_field_#{date_custom_field.id}_visible").click - datepicker = Components::Datepicker.new "body" + datepicker = Components::Datepicker.new 'body' datepicker.set_date date - new_ca_page.add_action("Type", other_type.name) - new_ca_page.expect_action("type", other_type.id) + new_ca_page.add_action('Type', other_type.name) + new_ca_page.expect_action('type', other_type.id) - new_ca_page.add_action("Project", other_project.name) - new_ca_page.expect_action("project", other_project.id) + new_ca_page.add_action('Project', other_project.name) + new_ca_page.expect_action('project', other_project.id) - new_ca_page.set_condition("Project", project.name) + new_ca_page.set_condition('Project', project.name) new_ca_page.expect_selected_option project.name end new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign", "Close", "Escalate", "Reset", "Other roles action", "Move project") + index_ca_page.expect_listed('Unassign', 'Close', 'Escalate', 'Reset', 'Other roles action', 'Move project') move_project = CustomAction.last expect(move_project.actions.length).to eq(3) @@ -299,50 +299,50 @@ wp_page.visit! - wp_page.expect_custom_action("Unassign") - wp_page.expect_custom_action("Close") - wp_page.expect_custom_action("Escalate") - wp_page.expect_custom_action("Move project") - wp_page.expect_no_custom_action("Reset") - wp_page.expect_no_custom_action("Other roles action") - wp_page.expect_custom_action_order("Unassign", "Close", "Escalate", "Move project") + wp_page.expect_custom_action('Unassign') + wp_page.expect_custom_action('Close') + wp_page.expect_custom_action('Escalate') + wp_page.expect_custom_action('Move project') + wp_page.expect_no_custom_action('Reset') + wp_page.expect_no_custom_action('Other roles action') + wp_page.expect_custom_action_order('Unassign', 'Close', 'Escalate', 'Move project') - within(".custom-actions") do + within('.custom-actions') do # When hovering over the button, the description is displayed - button = find(".custom-action--button", text: "Unassign") - expect(button["title"]) - .to eql "Removes the assignee" + button = find('.custom-action--button', text: 'Unassign') + expect(button['title']) + .to eql 'Removes the assignee' end - wp_page.click_custom_action("Unassign") - wp_page.expect_attributes assignee: "-" - within ".work-package-details-activities-list" do + wp_page.click_custom_action('Unassign') + wp_page.expect_attributes assignee: '-' + within '.work-package-details-activities-list' do expect(page) - .to have_css(".op-user-activity .op-user-activity--user-name", + .to have_css('.op-user-activity .op-user-activity--user-name', text: user.name, wait: 10) end - wp_page.click_custom_action("Escalate") + wp_page.click_custom_action('Escalate') wp_page.expect_attributes priority: immediate_priority.name, status: default_status.name, - assignee: "-", + assignee: '-', "customField#{list_custom_field.id}" => selected_list_custom_field_options.map(&:name).join("\n") - within ".work-package-details-activities-list" do + within '.work-package-details-activities-list' do expect(page) - .to have_css(".op-user-activity a.user-mention", + .to have_css('.op-user-activity a.user-mention', text: other_member_user.name, wait: 10) end - wp_page.click_custom_action("Close") + wp_page.click_custom_action('Close') wp_page.expect_attributes status: closed_status.name, priority: immediate_priority.name - wp_page.expect_custom_action("Reset") - wp_page.expect_no_custom_action("Close") + wp_page.expect_custom_action('Reset') + wp_page.expect_no_custom_action('Close') - wp_page.click_custom_action("Reset") + wp_page.click_custom_action('Reset') wp_page.expect_attributes priority: default_priority.name, status: default_status.name, @@ -354,130 +354,130 @@ index_ca_page.visit! - edit_ca_page = index_ca_page.edit("Reset") + edit_ca_page = index_ca_page.edit('Reset') retry_block do - edit_ca_page.set_name "Reject" - edit_ca_page.remove_action "Priority" - edit_ca_page.set_action "Assignee", "-" - edit_ca_page.expect_action "assigned_to", nil + edit_ca_page.set_name 'Reject' + edit_ca_page.remove_action 'Priority' + edit_ca_page.set_action 'Assignee', '-' + edit_ca_page.expect_action 'assigned_to', nil - edit_ca_page.set_action "Status", rejected_status.name - edit_ca_page.expect_action "status", rejected_status.id + edit_ca_page.set_action 'Status', rejected_status.name + edit_ca_page.expect_action 'status', rejected_status.id - edit_ca_page.set_condition "Status", default_status.name + edit_ca_page.set_condition 'Status', default_status.name edit_ca_page.expect_selected_option default_status.name end edit_ca_page.save index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign", "Close", "Escalate", "Reject") + index_ca_page.expect_listed('Unassign', 'Close', 'Escalate', 'Reject') - reset = CustomAction.find_by(name: "Reject") + reset = CustomAction.find_by(name: 'Reject') expect(reset.actions.length).to eq(3) expect(reset.conditions.length).to eq(1) - index_ca_page.move_top "Move project" - index_ca_page.move_bottom "Escalate" - index_ca_page.move_up "Close" - index_ca_page.move_down "Unassign" + index_ca_page.move_top 'Move project' + index_ca_page.move_bottom 'Escalate' + index_ca_page.move_up 'Close' + index_ca_page.move_down 'Unassign' # Check the altered button login_as(user) wp_page.visit! - wp_page.expect_custom_action("Unassign") - wp_page.expect_custom_action("Close") - wp_page.expect_custom_action("Escalate") - wp_page.expect_custom_action("Move project") - wp_page.expect_custom_action("Reject") - wp_page.expect_no_custom_action("Reset") - wp_page.expect_custom_action_order("Move project", "Close", "Reject", "Unassign", "Escalate") + wp_page.expect_custom_action('Unassign') + wp_page.expect_custom_action('Close') + wp_page.expect_custom_action('Escalate') + wp_page.expect_custom_action('Move project') + wp_page.expect_custom_action('Reject') + wp_page.expect_no_custom_action('Reset') + wp_page.expect_custom_action_order('Move project', 'Close', 'Reject', 'Unassign', 'Escalate') - wp_page.click_custom_action("Reject") - wp_page.expect_attributes assignee: "-", + wp_page.click_custom_action('Reject') + wp_page.expect_attributes assignee: '-', status: rejected_status.name, priority: default_priority.name - wp_page.expect_custom_action("Close") - wp_page.expect_no_custom_action("Reject") + wp_page.expect_custom_action('Close') + wp_page.expect_no_custom_action('Reject') # Delete 'Reject' from list of actions login_as(admin) index_ca_page.visit! - index_ca_page.delete("Unassign") + index_ca_page.delete('Unassign') index_ca_page.expect_current_path - index_ca_page.expect_listed("Close", "Escalate", "Reject") + index_ca_page.expect_listed('Close', 'Escalate', 'Reject') login_as(user) wp_page.visit! - wp_page.expect_no_custom_action("Unassign") - wp_page.expect_custom_action("Close") - wp_page.expect_custom_action("Escalate") - wp_page.expect_no_custom_action("Reject") + wp_page.expect_no_custom_action('Unassign') + wp_page.expect_custom_action('Close') + wp_page.expect_custom_action('Escalate') + wp_page.expect_no_custom_action('Reject') # Move project - wp_page.click_custom_action("Move project") + wp_page.click_custom_action('Move project') - wp_page.expect_attributes assignee: "-", + wp_page.expect_attributes assignee: '-', status: rejected_status.name, type: other_type.name.upcase, - "customField#{date_custom_field.id}" => (Date.today + 5.days).strftime("%m/%d/%Y") + "customField#{date_custom_field.id}" => (Date.today + 5.days).strftime('%m/%d/%Y') expect(page) - .to have_content(I18n.t("js.project.click_to_switch_to_project", projectname: other_project.name)) + .to have_content(I18n.t('js.project.click_to_switch_to_project', projectname: other_project.name)) ## Bump the lockVersion and by that force a conflict. work_package.reload.touch - wp_page.click_custom_action("Escalate", expect_success: false) + wp_page.click_custom_action('Escalate', expect_success: false) - wp_page.expect_toast type: :error, message: I18n.t("api_v3.errors.code_409") + wp_page.expect_toast type: :error, message: I18n.t('api_v3.errors.code_409') end - it "editing a current date custom action (Regression #30949)" do + it 'editing a current date custom action (Regression #30949)' do # create custom action 'Unassign' index_ca_page.visit! new_ca_page = index_ca_page.new - new_ca_page.set_name("Current date") - new_ca_page.set_description("Sets the current date") - new_ca_page.add_action("Date", "Current date") + new_ca_page.set_name('Current date') + new_ca_page.set_description('Sets the current date') + new_ca_page.add_action('Date', 'Current date') new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Current date") + index_ca_page.expect_listed('Current date') date_action = CustomAction.last expect(date_action.actions.length).to eq(1) expect(date_action.conditions.length).to eq(0) - edit_page = index_ca_page.edit("Current date") - expect(page).to have_select("custom_action_actions_date", selected: "Current date") + edit_page = index_ca_page.edit('Current date') + expect(page).to have_select('custom_action_actions_date', selected: 'Current date') end - it "disables the custom action button and editing other fields when submiting the custom action" do + it 'disables the custom action button and editing other fields when submiting the custom action' do # create custom action 'Unassign' index_ca_page.visit! new_ca_page = index_ca_page.new - new_ca_page.set_name("Unassign") - new_ca_page.set_description("Removes the assignee") - new_ca_page.add_action("Assignee", "-") - new_ca_page.expect_action("assigned_to", nil) + new_ca_page.set_name('Unassign') + new_ca_page.set_description('Removes the assignee') + new_ca_page.add_action('Assignee', '-') + new_ca_page.expect_action('assigned_to', nil) new_ca_page.create index_ca_page.expect_current_path - index_ca_page.expect_listed("Unassign") + index_ca_page.expect_listed('Unassign') unassign = CustomAction.last expect(unassign.actions.length).to eq(1) @@ -491,17 +491,17 @@ # Stop sending ajax requests in order to test disabled fields upon submit wp_page.disable_ajax_requests - wp_page.click_custom_action("Unassign", expect_success: false) - wp_page.expect_custom_action_disabled("Unassign") + wp_page.click_custom_action('Unassign', expect_success: false) + wp_page.expect_custom_action_disabled('Unassign') find('[data-field-name="estimatedTime"]').click expect(page).to have_css("#wp-#{work_package.id}-inline-edit--field-estimatedTime[disabled]") end - context "with baseline enabled" do + context 'with baseline enabled' do let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:query) do create(:query, - name: "Timestamps Query", + name: 'Timestamps Query', project:, user:, timestamps: ["P-1d", "PT0S"]) @@ -510,17 +510,17 @@ before do create(:custom_action, actions: [CustomActions::Actions::AssignedTo.new(value: nil)], - name: "Unassign") + name: 'Unassign') end - it "executes the custom action (Regression#49588)" do + it 'executes the custom action (Regression#49588)' do login_as(user) wp_table.visit_query(query) wp_page = wp_table.open_full_screen_by_link(work_package) wp_page.ensure_page_loaded - wp_page.click_custom_action("Unassign", expect_success: true) + wp_page.click_custom_action('Unassign', expect_success: true) end end end diff --git a/spec/features/work_packages/datepicker/datepicker_follows_relation_spec.rb b/spec/features/work_packages/datepicker/datepicker_follows_relation_spec.rb index 7c9c182c9d08..b8d4a3ceb300 100644 --- a/spec/features/work_packages/datepicker/datepicker_follows_relation_spec.rb +++ b/spec/features/work_packages/datepicker/datepicker_follows_relation_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/edit_fields/edit_field" +require 'spec_helper' +require 'support/edit_fields/edit_field' -RSpec.describe "Datepicker logic on follow relationships", :js, :with_cuprite, - with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'Datepicker logic on follow relationships', :js, :with_cuprite, + with_settings: { date_format: '%Y-%m-%d' } do shared_let(:user) { create(:admin) } shared_let(:type) { create(:type_bug) } @@ -39,15 +39,15 @@ shared_let(:predecessor) do create(:work_package, type:, project:, - start_date: Date.parse("2024-02-01"), - due_date: Date.parse("2024-02-05")) + start_date: Date.parse('2024-02-01'), + due_date: Date.parse('2024-02-05')) end let(:work_packages_page) { Pages::FullWorkPackage.new(follower) } let(:datepicker) { date_field.datepicker } - shared_examples "keeps the minimum date from the predecessor when toggling NWD" do - it "keeps the minimum dates disabled" do + shared_examples 'keeps the minimum date from the predecessor when toggling NWD' do + it 'keeps the minimum dates disabled' do login_as(user) work_packages_page.visit! @@ -61,37 +61,37 @@ datepicker.expect_ignore_non_working_days false datepicker.expect_scheduling_mode false - datepicker.show_date "2024-02-05" - datepicker.expect_disabled Date.parse("2024-02-05") - datepicker.expect_disabled Date.parse("2024-02-04") - datepicker.expect_disabled Date.parse("2024-02-03") - datepicker.expect_disabled Date.parse("2024-02-02") - datepicker.expect_disabled Date.parse("2024-02-01") + datepicker.show_date '2024-02-05' + datepicker.expect_disabled Date.parse('2024-02-05') + datepicker.expect_disabled Date.parse('2024-02-04') + datepicker.expect_disabled Date.parse('2024-02-03') + datepicker.expect_disabled Date.parse('2024-02-02') + datepicker.expect_disabled Date.parse('2024-02-01') datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days true - datepicker.show_date "2024-02-05" - datepicker.expect_disabled Date.parse("2024-02-05") - datepicker.expect_disabled Date.parse("2024-02-04") - datepicker.expect_disabled Date.parse("2024-02-03") - datepicker.expect_disabled Date.parse("2024-02-02") - datepicker.expect_disabled Date.parse("2024-02-01") + datepicker.show_date '2024-02-05' + datepicker.expect_disabled Date.parse('2024-02-05') + datepicker.expect_disabled Date.parse('2024-02-04') + datepicker.expect_disabled Date.parse('2024-02-03') + datepicker.expect_disabled Date.parse('2024-02-02') + datepicker.expect_disabled Date.parse('2024-02-01') end end - context "if the follower is a task" do + context 'if the follower is a task' do let!(:follower) { create(:work_package, type:, project:) } let!(:relation) { create(:follows_relation, from: follower, to: predecessor) } let(:date_field) { work_packages_page.edit_field(:combinedDate) } - it_behaves_like "keeps the minimum date from the predecessor when toggling NWD" + it_behaves_like 'keeps the minimum date from the predecessor when toggling NWD' end - context "if the follower is a milestone" do + context 'if the follower is a milestone' do let!(:follower) { create(:work_package, type: milestone_type, project:) } let!(:relation) { create(:follows_relation, from: follower, to: predecessor) } let(:date_field) { work_packages_page.edit_field(:date) } - it_behaves_like "keeps the minimum date from the predecessor when toggling NWD" + it_behaves_like 'keeps the minimum date from the predecessor when toggling NWD' end end diff --git a/spec/features/work_packages/datepicker/datepicker_logic_spec.rb b/spec/features/work_packages/datepicker/datepicker_logic_spec.rb index e4d4cecbf412..469c3c9ad10f 100644 --- a/spec/features/work_packages/datepicker/datepicker_logic_spec.rb +++ b/spec/features/work_packages/datepicker/datepicker_logic_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/edit_fields/edit_field" +require 'spec_helper' +require 'support/edit_fields/edit_field' -RSpec.describe "Datepicker modal logic test cases (WP #43539)", :js, :with_cuprite, with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'Datepicker modal logic test cases (WP #43539)', :js, :with_cuprite, with_settings: { date_format: '%Y-%m-%d' } do shared_let(:user) { create(:admin) } shared_let(:type_bug) { create(:type_bug) } @@ -55,7 +55,7 @@ def apply_and_expect_saved(attributes) date_field.save! - work_packages_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_update") + work_packages_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_update') work_package.reload @@ -78,33 +78,33 @@ def apply_and_expect_saved(attributes) datepicker.expect_visible end - context "when only start_date set, updating duration (scenario 1)" do + context 'when only start_date set, updating duration (scenario 1)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), + start_date: Date.parse('2021-02-08'), due_date: nil, duration: nil } end - it "sets finish date" do - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'sets finish date' do + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.set_duration 10 - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-19" + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 10 apply_and_expect_saved duration: 10, - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-19") + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-19') end end - describe "when no values set, updating duration (scenario 2)" do + describe 'when no values set, updating duration (scenario 2)' do let(:current_attributes) do { start_date: nil, @@ -113,15 +113,15 @@ def apply_and_expect_saved(attributes) } end - it "sets only the duration" do - datepicker.expect_start_date "" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'sets only the duration' do + datepicker.expect_start_date '' + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.set_duration 10 - datepicker.expect_start_date "" - datepicker.expect_due_date "" + datepicker.expect_start_date '' + datepicker.expect_due_date '' datepicker.expect_duration 10 apply_and_expect_saved duration: 10, @@ -130,238 +130,238 @@ def apply_and_expect_saved(attributes) end end - describe "when only due date set, updating duration (scenario 3)" do + describe 'when only due date set, updating duration (scenario 3)' do let(:current_attributes) do { start_date: nil, - due_date: Date.parse("2021-02-19"), + due_date: Date.parse('2021-02-19'), duration: nil } end - it "sets the start date" do - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-19" - datepicker.expect_duration "" + it 'sets the start date' do + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-19' + datepicker.expect_duration '' datepicker.set_duration 10 - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-19" + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 10 apply_and_expect_saved duration: 10, - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-19") + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-19') end end - describe "when all values set, increasing duration (scenario 4)" do + describe 'when all values set, increasing duration (scenario 4)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-19"), + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-19'), duration: 10 } end - it "updates the finish date to a later date" do - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-19" + it 'updates the finish date to a later date' do + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 10 datepicker.set_duration 11 - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-22" + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-22' datepicker.expect_duration 11 apply_and_expect_saved duration: 11, - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-22") + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-22') end end - describe "when all values set, reducing duration (scenario 5)" do + describe 'when all values set, reducing duration (scenario 5)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-22"), + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-22'), duration: 11 } end - it "updates the finish date to an earlier date" do - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-22" + it 'updates the finish date to an earlier date' do + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-22' datepicker.expect_duration 11 datepicker.set_duration 10 - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-19" + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 10 apply_and_expect_saved duration: 10, - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-19") + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-19') end end - describe "when all values set, removing duration (scenario 6)" do + describe 'when all values set, removing duration (scenario 6)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-09"), - due_date: Date.parse("2021-02-12"), + start_date: Date.parse('2021-02-09'), + due_date: Date.parse('2021-02-12'), duration: 3 } end - it "also unsets the due date" do - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-12" + it 'also unsets the due date' do + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-12' datepicker.expect_duration 3 datepicker.clear_duration - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '' datepicker.expect_duration nil end end - describe "when all values set, removing duration through icon (scenario 6a)" do + describe 'when all values set, removing duration through icon (scenario 6a)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-09"), - due_date: Date.parse("2021-02-12"), + start_date: Date.parse('2021-02-09'), + due_date: Date.parse('2021-02-12'), duration: 3 } end - it "also unsets the due date" do - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-12" + it 'also unsets the due date' do + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-12' datepicker.expect_duration 3 datepicker.clear_duration_with_icon - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '' datepicker.expect_duration nil end end - describe "when all values set, removing duration and setting it again" do + describe 'when all values set, removing duration and setting it again' do let(:current_attributes) do { - start_date: Date.parse("2021-02-09"), - due_date: Date.parse("2021-02-12"), + start_date: Date.parse('2021-02-09'), + due_date: Date.parse('2021-02-12'), duration: 3 } end - it "allows re-deriving duration" do - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-12" + it 'allows re-deriving duration' do + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-12' datepicker.expect_duration 3 datepicker.clear_duration_with_icon - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '' datepicker.expect_duration nil # Now select a date datepicker.select_day 5 - datepicker.expect_start_date "2021-02-05" - datepicker.expect_due_date "2021-02-09" + datepicker.expect_start_date '2021-02-05' + datepicker.expect_due_date '2021-02-09' datepicker.expect_duration 3 datepicker.clear_duration_with_icon - datepicker.expect_start_date "2021-02-05" - datepicker.expect_due_date "" + datepicker.expect_start_date '2021-02-05' + datepicker.expect_due_date '' datepicker.expect_duration nil datepicker.select_day 8 - datepicker.expect_start_date "2021-02-05" - datepicker.expect_due_date "2021-02-08" + datepicker.expect_start_date '2021-02-05' + datepicker.expect_due_date '2021-02-08' datepicker.expect_duration 2 end end - describe "when all values set, changing start date in calendar (scenario 7)" do + describe 'when all values set, changing start date in calendar (scenario 7)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-11"), + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-11'), duration: 4 } end - it "adjusts the duration" do - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-11" + it 'adjusts the duration' do + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 4 - datepicker.set_start_date "2021-02-09" + datepicker.set_start_date '2021-02-09' - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-11" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 3 end end # Same as scenario 7, with error state in the middle - describe "when all values set, setting the start date to invalid value, then to a valid value" do + describe 'when all values set, setting the start date to invalid value, then to a valid value' do let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-11"), + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-11'), duration: 4 } end - it "adjusts the duration" do - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-11" + it 'adjusts the duration' do + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 4 # simulate someone deleting some chars to type a new date - datepicker.set_start_date "2021-02-" - datepicker.set_start_date "2021-02-09" + datepicker.set_start_date '2021-02-' + datepicker.set_start_date '2021-02-09' - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-11" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 3 end end - describe "when all values set, changing due date (scenario 8)" do + describe 'when all values set, changing due date (scenario 8)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-09"), - due_date: Date.parse("2021-02-12"), + start_date: Date.parse('2021-02-09'), + due_date: Date.parse('2021-02-12'), duration: 4 } end - it "adjusts the duration" do - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-12" + it 'adjusts the duration' do + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-12' datepicker.expect_duration 4 - datepicker.set_due_date "2021-02-11" + datepicker.set_due_date '2021-02-11' - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-11" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 3 end end - describe "when only duration set, setting finish date (scenario 9)" do + describe 'when only duration set, setting finish date (scenario 9)' do let(:current_attributes) do { start_date: nil, @@ -370,86 +370,86 @@ def apply_and_expect_saved(attributes) } end - it "derives the start date" do - datepicker.expect_start_date "" - datepicker.expect_due_date "" + it 'derives the start date' do + datepicker.expect_start_date '' + datepicker.expect_due_date '' datepicker.expect_duration 4 - datepicker.set_due_date "2021-02-12" + datepicker.set_due_date '2021-02-12' - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-12" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-12' datepicker.expect_duration 4 end end - describe "when only due date set, setting start date (scenario 10)" do + describe 'when only due date set, setting start date (scenario 10)' do let(:current_attributes) do { start_date: nil, - due_date: Date.parse("2021-02-11"), + due_date: Date.parse('2021-02-11'), duration: nil } end - it "derives the duration" do - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-11" - datepicker.expect_duration "" + it 'derives the duration' do + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-11' + datepicker.expect_duration '' - datepicker.set_start_date "2021-02-09" + datepicker.set_start_date '2021-02-09' - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-11" + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 3 end end - describe "when all values set, changing the start date to the future in the picker (Scenario 13)" do + describe 'when all values set, changing the start date to the future in the picker (Scenario 13)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-09"), - due_date: Date.parse("2021-02-11"), + start_date: Date.parse('2021-02-09'), + due_date: Date.parse('2021-02-11'), duration: 3 } end - it "unsets the other two values" do - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-11" + it 'unsets the other two values' do + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 3 - datepicker.set_start_date "2021-03-03" + datepicker.set_start_date '2021-03-03' - datepicker.expect_start_date "2021-03-03" - datepicker.expect_due_date "" - datepicker.expect_duration "" + datepicker.expect_start_date '2021-03-03' + datepicker.expect_due_date '' + datepicker.expect_duration '' end end - describe "when only finish date set, changing the start date to the future in the picker (Scenario 13 variation)" do + describe 'when only finish date set, changing the start date to the future in the picker (Scenario 13 variation)' do let(:current_attributes) do { start_date: nil, - due_date: Date.parse("2021-02-11"), + due_date: Date.parse('2021-02-11'), duration: nil } end - it "unsets the finish date" do - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-11" - datepicker.expect_duration "" + it 'unsets the finish date' do + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-11' + datepicker.expect_duration '' - datepicker.set_start_date "2021-03-03" + datepicker.set_start_date '2021-03-03' - datepicker.expect_start_date "2021-03-03" - datepicker.expect_due_date "" - datepicker.expect_duration "" + datepicker.expect_start_date '2021-03-03' + datepicker.expect_due_date '' + datepicker.expect_duration '' end end - describe "when only start date set, changing the finish date to the past with today (Scenario 13a)" do + describe 'when only start date set, changing the finish date to the past with today (Scenario 13a)' do let(:current_attributes) do { start_date: 2.days.from_now, @@ -459,19 +459,19 @@ def apply_and_expect_saved(attributes) } end - it "unsets the other two values" do + it 'unsets the other two values' do datepicker.expect_start_date 2.days.from_now.to_date.iso8601 - datepicker.expect_due_date "" + datepicker.expect_due_date '' datepicker.set_today :due - datepicker.expect_start_date "" + datepicker.expect_start_date '' datepicker.expect_due_date Time.zone.today.iso8601 - datepicker.expect_duration "" + datepicker.expect_duration '' end end - describe "when all values set, changing the finish date to the past with today (Scenario 13a)" do + describe 'when all values set, changing the finish date to the past with today (Scenario 13a)' do let(:current_attributes) do { start_date: 2.days.from_now, @@ -480,396 +480,396 @@ def apply_and_expect_saved(attributes) } end - it "unsets the other two values" do + it 'unsets the other two values' do datepicker.expect_start_date 2.days.from_now.to_date.iso8601 datepicker.expect_due_date 3.days.from_now.to_date.iso8601 datepicker.set_today :due - datepicker.expect_start_date "" + datepicker.expect_start_date '' datepicker.expect_due_date Time.zone.today.iso8601 - datepicker.expect_duration "" + datepicker.expect_duration '' end end - describe "when all values set, changing the start date to the past in the picker (Scenario 14)" do + describe 'when all values set, changing the start date to the past in the picker (Scenario 14)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-09"), - due_date: Date.parse("2021-02-11"), + start_date: Date.parse('2021-02-09'), + due_date: Date.parse('2021-02-11'), duration: 3 } end - it "conserves the duration and updates the finish date" do - datepicker.expect_start_date "2021-02-09" - datepicker.expect_due_date "2021-02-11" + it 'conserves the duration and updates the finish date' do + datepicker.expect_start_date '2021-02-09' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 3 - datepicker.set_start_date "2021-02-03" + datepicker.set_start_date '2021-02-03' - datepicker.expect_start_date "2021-02-03" - datepicker.expect_due_date "2021-02-05" + datepicker.expect_start_date '2021-02-03' + datepicker.expect_due_date '2021-02-05' datepicker.expect_duration 3 end end - describe "when all values set, changing include NWD to true (Scenario 15)" do + describe 'when all values set, changing include NWD to true (Scenario 15)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-11"), - due_date: Date.parse("2021-02-16"), + start_date: Date.parse('2021-02-11'), + due_date: Date.parse('2021-02-16'), duration: 4 } end - it "conserves the duration and updates the finish date" do - datepicker.expect_start_date "2021-02-11" - datepicker.expect_due_date "2021-02-16" + it 'conserves the duration and updates the finish date' do + datepicker.expect_start_date '2021-02-11' + datepicker.expect_due_date '2021-02-16' datepicker.expect_duration 4 datepicker.toggle_ignore_non_working_days - datepicker.expect_start_date "2021-02-11" - datepicker.expect_due_date "2021-02-14" + datepicker.expect_start_date '2021-02-11' + datepicker.expect_due_date '2021-02-14' datepicker.expect_duration 4 end end - describe "when all values set and include NWD true, changing include NWD to false (Scenario 16)" do + describe 'when all values set and include NWD true, changing include NWD to false (Scenario 16)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-11"), - due_date: Date.parse("2021-02-14"), + start_date: Date.parse('2021-02-11'), + due_date: Date.parse('2021-02-14'), duration: 4, ignore_non_working_days: true } end - it "conserves the duration and updates the finish date" do - datepicker.expect_start_date "2021-02-11" - datepicker.expect_due_date "2021-02-14" + it 'conserves the duration and updates the finish date' do + datepicker.expect_start_date '2021-02-11' + datepicker.expect_due_date '2021-02-14' datepicker.expect_duration 4 datepicker.expect_ignore_non_working_days true datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days false - datepicker.expect_start_date "2021-02-11" - datepicker.expect_due_date "2021-02-16" + datepicker.expect_start_date '2021-02-11' + datepicker.expect_due_date '2021-02-16' datepicker.expect_duration 4 end end - describe "when all values set and include NWD true, changing include NWD to false (Scenario 17)" do + describe 'when all values set and include NWD true, changing include NWD to false (Scenario 17)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-13"), - due_date: Date.parse("2021-02-14"), + start_date: Date.parse('2021-02-13'), + due_date: Date.parse('2021-02-14'), duration: 2, ignore_non_working_days: true } end - it "shifts the start date to soonest working day, and updates finish date to conserve duration" do - datepicker.expect_start_date "2021-02-13" - datepicker.expect_due_date "2021-02-14" + it 'shifts the start date to soonest working day, and updates finish date to conserve duration' do + datepicker.expect_start_date '2021-02-13' + datepicker.expect_due_date '2021-02-14' datepicker.expect_duration 2 datepicker.expect_ignore_non_working_days true datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days false - datepicker.expect_start_date "2021-02-15" - datepicker.expect_due_date "2021-02-16" + datepicker.expect_start_date '2021-02-15' + datepicker.expect_due_date '2021-02-16' datepicker.expect_duration 2 end end - describe "when all values set and include NWD true, changing include NWD to false (Scenario 18)" do + describe 'when all values set and include NWD true, changing include NWD to false (Scenario 18)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-13"), - due_date: Date.parse("2021-02-23"), + start_date: Date.parse('2021-02-13'), + due_date: Date.parse('2021-02-23'), duration: 11, ignore_non_working_days: true } end - it "shifts the start date to soonest working day, and updates finish date to conserve duration" do - datepicker.expect_start_date "2021-02-13" - datepicker.expect_due_date "2021-02-23" + it 'shifts the start date to soonest working day, and updates finish date to conserve duration' do + datepicker.expect_start_date '2021-02-13' + datepicker.expect_due_date '2021-02-23' datepicker.expect_duration 11 datepicker.expect_ignore_non_working_days true datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days false - datepicker.expect_start_date "2021-02-15" - datepicker.expect_due_date "2021-03-01" + datepicker.expect_start_date '2021-02-15' + datepicker.expect_due_date '2021-03-01' datepicker.expect_duration 11 apply_and_expect_saved duration: 11, - start_date: Date.parse("2021-02-15"), - due_date: Date.parse("2021-03-01"), + start_date: Date.parse('2021-02-15'), + due_date: Date.parse('2021-03-01'), ignore_non_working_days: false end end - describe "when only start date set and include NWD true, changing include NWD to false (Scenario 19)" do + describe 'when only start date set and include NWD true, changing include NWD to false (Scenario 19)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-13"), + start_date: Date.parse('2021-02-13'), due_date: nil, duration: nil, ignore_non_working_days: true } end - it "shifts the start date to soonest working day" do - datepicker.expect_start_date "2021-02-13" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'shifts the start date to soonest working day' do + datepicker.expect_start_date '2021-02-13' + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.expect_ignore_non_working_days true datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days false - datepicker.expect_start_date "2021-02-15" - datepicker.expect_due_date "" - datepicker.expect_duration "" + datepicker.expect_start_date '2021-02-15' + datepicker.expect_due_date '' + datepicker.expect_duration '' apply_and_expect_saved duration: nil, - start_date: Date.parse("2021-02-15"), + start_date: Date.parse('2021-02-15'), due_date: nil, ignore_non_working_days: false end end - describe "when only finish date set and include NWD true, changing include NWD to false (Scenario 20)" do + describe 'when only finish date set and include NWD true, changing include NWD to false (Scenario 20)' do let(:current_attributes) do { start_date: nil, - due_date: Date.parse("2021-02-21"), + due_date: Date.parse('2021-02-21'), duration: nil, ignore_non_working_days: true } end - it "shifts the finish date to soonest working day" do - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-21" - datepicker.expect_duration "" + it 'shifts the finish date to soonest working day' do + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-21' + datepicker.expect_duration '' datepicker.expect_ignore_non_working_days true datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days false - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-22" - datepicker.expect_duration "" + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-22' + datepicker.expect_duration '' apply_and_expect_saved duration: nil, start_date: nil, - due_date: Date.parse("2021-02-22"), + due_date: Date.parse('2021-02-22'), ignore_non_working_days: false end end - describe "When all values set, clear the start date (Scenario 21a)" do + describe 'When all values set, clear the start date (Scenario 21a)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-20"), - due_date: Date.parse("2021-02-21"), + start_date: Date.parse('2021-02-20'), + due_date: Date.parse('2021-02-21'), duration: 1, ignore_non_working_days: true } end - it "also removes duration, but keeps finish date" do - datepicker.expect_start_date "2021-02-20" - datepicker.expect_due_date "2021-02-21" + it 'also removes duration, but keeps finish date' do + datepicker.expect_start_date '2021-02-20' + datepicker.expect_due_date '2021-02-21' datepicker.expect_duration 1 datepicker.expect_ignore_non_working_days true - datepicker.set_start_date "" - datepicker.expect_duration "" - datepicker.expect_due_date "2021-02-21" + datepicker.set_start_date '' + datepicker.expect_duration '' + datepicker.expect_due_date '2021-02-21' apply_and_expect_saved duration: nil, start_date: nil, - due_date: Date.parse("2021-02-21"), + due_date: Date.parse('2021-02-21'), ignore_non_working_days: true end end - describe "When all values set, clear the due date (Scenario 21b)" do + describe 'When all values set, clear the due date (Scenario 21b)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-20"), - due_date: Date.parse("2021-02-21"), + start_date: Date.parse('2021-02-20'), + due_date: Date.parse('2021-02-21'), duration: 1, ignore_non_working_days: true } end - it "also removes duration, but keeps start date" do - datepicker.expect_start_date "2021-02-20" - datepicker.expect_due_date "2021-02-21" + it 'also removes duration, but keeps start date' do + datepicker.expect_start_date '2021-02-20' + datepicker.expect_due_date '2021-02-21' datepicker.expect_duration 1 datepicker.expect_ignore_non_working_days true - datepicker.set_due_date "" - datepicker.expect_duration "" - datepicker.expect_start_date "2021-02-20" + datepicker.set_due_date '' + datepicker.expect_duration '' + datepicker.expect_start_date '2021-02-20' apply_and_expect_saved duration: nil, - start_date: Date.parse("2021-02-20"), + start_date: Date.parse('2021-02-20'), due_date: nil, ignore_non_working_days: true end end - describe "When only start date set, duration in focus, select earlier date (Scenario 22a)" do + describe 'When only start date set, duration in focus, select earlier date (Scenario 22a)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-18"), + start_date: Date.parse('2021-02-18'), due_date: nil, duration: nil, ignore_non_working_days: true } end - it "sets start date to selected value, finish date to start date" do - datepicker.expect_start_date "2021-02-18" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'sets start date to selected value, finish date to start date' do + datepicker.expect_start_date '2021-02-18' + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.focus_duration datepicker.expect_duration_highlighted datepicker.select_day 17 - datepicker.expect_start_date "2021-02-17" - datepicker.expect_due_date "2021-02-18" + datepicker.expect_start_date '2021-02-17' + datepicker.expect_due_date '2021-02-18' datepicker.expect_duration 2 datepicker.expect_start_highlighted apply_and_expect_saved duration: 2, - start_date: Date.parse("2021-02-17"), - due_date: Date.parse("2021-02-18"), + start_date: Date.parse('2021-02-17'), + due_date: Date.parse('2021-02-18'), ignore_non_working_days: true end end - describe "When only start date set, duration in focus, select later date (Scenario 22b)" do + describe 'When only start date set, duration in focus, select later date (Scenario 22b)' do let(:current_attributes) do { - start_date: Date.parse("2021-02-18"), + start_date: Date.parse('2021-02-18'), due_date: nil, duration: nil, ignore_non_working_days: true } end - it "sets finish date to selected date" do - datepicker.expect_start_date "2021-02-18" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'sets finish date to selected date' do + datepicker.expect_start_date '2021-02-18' + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.focus_duration datepicker.expect_duration_highlighted datepicker.select_day 19 - datepicker.expect_start_date "2021-02-18" - datepicker.expect_due_date "2021-02-19" + datepicker.expect_start_date '2021-02-18' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 2 datepicker.expect_start_highlighted apply_and_expect_saved duration: 2, - start_date: Date.parse("2021-02-18"), - due_date: Date.parse("2021-02-19"), + start_date: Date.parse('2021-02-18'), + due_date: Date.parse('2021-02-19'), ignore_non_working_days: true end end - describe "When only due date set, duration in focus, select later date (Scenario 23a)" do + describe 'When only due date set, duration in focus, select later date (Scenario 23a)' do let(:current_attributes) do { start_date: nil, - due_date: Date.parse("2021-02-18"), + due_date: Date.parse('2021-02-18'), duration: nil, ignore_non_working_days: true } end - it "sets due date to selected value, start to finish date, focus on start" do - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-18" - datepicker.expect_duration "" + it 'sets due date to selected value, start to finish date, focus on start' do + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-18' + datepicker.expect_duration '' datepicker.focus_duration datepicker.expect_duration_highlighted datepicker.select_day 19 - datepicker.expect_start_date "2021-02-18" - datepicker.expect_due_date "2021-02-19" + datepicker.expect_start_date '2021-02-18' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 2 datepicker.expect_start_highlighted apply_and_expect_saved duration: 2, - start_date: Date.parse("2021-02-18"), - due_date: Date.parse("2021-02-19"), + start_date: Date.parse('2021-02-18'), + due_date: Date.parse('2021-02-19'), ignore_non_working_days: true end end - describe "When only due date set, duration in focus, select earlier date (Scenario 23b)" do + describe 'When only due date set, duration in focus, select earlier date (Scenario 23b)' do let(:current_attributes) do { start_date: nil, - due_date: Date.parse("2021-02-18"), + due_date: Date.parse('2021-02-18'), duration: nil, ignore_non_working_days: true } end - it "sets start date to selected date" do - datepicker.expect_start_date "" - datepicker.expect_due_date "2021-02-18" - datepicker.expect_duration "" + it 'sets start date to selected date' do + datepicker.expect_start_date '' + datepicker.expect_due_date '2021-02-18' + datepicker.expect_duration '' datepicker.focus_duration datepicker.expect_duration_highlighted datepicker.select_day 17 - datepicker.expect_start_date "2021-02-17" - datepicker.expect_due_date "2021-02-18" + datepicker.expect_start_date '2021-02-17' + datepicker.expect_due_date '2021-02-18' datepicker.expect_duration 2 datepicker.expect_start_highlighted apply_and_expect_saved duration: 2, - start_date: Date.parse("2021-02-17"), - due_date: Date.parse("2021-02-18"), + start_date: Date.parse('2021-02-17'), + due_date: Date.parse('2021-02-18'), ignore_non_working_days: true end end - describe "when all values set and duration highlighted, selecting date in datepicker" do + describe 'when all values set and duration highlighted, selecting date in datepicker' do let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-11"), + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-11'), duration: 4 } end - it "sets start to the selected value, keeps finish date" do - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-11" + it 'sets start to the selected value, keeps finish date' do + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-11' datepicker.expect_duration 4 # Focus duration @@ -879,25 +879,25 @@ def apply_and_expect_saved(attributes) # Select date in datepicker datepicker.select_day 5 - datepicker.expect_start_date "2021-02-05" - datepicker.expect_due_date "2021-02-10" + datepicker.expect_start_date '2021-02-05' + datepicker.expect_due_date '2021-02-10' datepicker.expect_duration 4 # Focus is on start date datepicker.expect_due_highlighted datepicker.select_day 15 - datepicker.expect_start_date "2021-02-05" - datepicker.expect_due_date "2021-02-15" + datepicker.expect_start_date '2021-02-05' + datepicker.expect_due_date '2021-02-15' datepicker.expect_duration 7 apply_and_expect_saved duration: 7, - start_date: Date.parse("2021-02-05"), - due_date: Date.parse("2021-02-15") + start_date: Date.parse('2021-02-05'), + due_date: Date.parse('2021-02-15') end end - describe "when all values set and duration highlighted, selecting dates in datepicker" do + describe 'when all values set and duration highlighted, selecting dates in datepicker' do let(:current_attributes) do { start_date: nil, @@ -906,98 +906,98 @@ def apply_and_expect_saved(attributes) } end - it "sets start to the selected value, moves to finish date" do - datepicker.expect_start_date "" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'sets start to the selected value, moves to finish date' do + datepicker.expect_start_date '' + datepicker.expect_due_date '' + datepicker.expect_duration '' # Focus duration datepicker.duration_field.click datepicker.expect_duration_highlighted # Select date in datepicker - datepicker.set_start_date Date.parse("2021-02-05") + datepicker.set_start_date Date.parse('2021-02-05') - datepicker.expect_start_date "2021-02-05" + datepicker.expect_start_date '2021-02-05' datepicker.expect_due_highlighted - datepicker.expect_due_date "" - datepicker.expect_duration "" + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.select_day 9 - datepicker.expect_start_date "2021-02-05" - datepicker.expect_due_date "2021-02-09" + datepicker.expect_start_date '2021-02-05' + datepicker.expect_due_date '2021-02-09' datepicker.expect_duration 3 apply_and_expect_saved duration: 3, - start_date: Date.parse("2021-02-05"), - due_date: Date.parse("2021-02-09") + start_date: Date.parse('2021-02-05'), + due_date: Date.parse('2021-02-09') end end - context "when setting ignore NWD to true for a milestone" do + context 'when setting ignore NWD to true for a milestone' do let(:date_attribute) { :date } let(:work_package) { milestone_wp } let(:current_attributes) do { - start_date: "2022-06-20", - due_date: "2022-06-20", + start_date: '2022-06-20', + due_date: '2022-06-20', ignore_non_working_days: false } end - it "allows to persist that value (Regression #43932)" do - datepicker.expect_milestone_date "2022-06-20" + it 'allows to persist that value (Regression #43932)' do + datepicker.expect_milestone_date '2022-06-20' datepicker.expect_ignore_non_working_days false datepicker.toggle_ignore_non_working_days datepicker.expect_ignore_non_working_days true - datepicker.expect_milestone_date "2022-06-20" + datepicker.expect_milestone_date '2022-06-20' # Set date to sunday - datepicker.set_milestone_date "2022-06-19" - apply_and_expect_saved start_date: Date.parse("2022-06-19"), - due_date: Date.parse("2022-06-19"), + datepicker.set_milestone_date '2022-06-19' + apply_and_expect_saved start_date: Date.parse('2022-06-19'), + due_date: Date.parse('2022-06-19'), ignore_non_working_days: true end end - context "when setting scheduleManually to true for a milestone" do + context 'when setting scheduleManually to true for a milestone' do let(:date_attribute) { :date } let(:work_package) { milestone_wp } let(:current_attributes) do { - start_date: "2022-06-20", - due_date: "2022-06-20", + start_date: '2022-06-20', + due_date: '2022-06-20', schedule_manually: false } end - it "allows to persist that value (Regression #46721)" do - datepicker.expect_milestone_date "2022-06-20" + it 'allows to persist that value (Regression #46721)' do + datepicker.expect_milestone_date '2022-06-20' datepicker.expect_scheduling_mode false datepicker.toggle_scheduling_mode datepicker.expect_scheduling_mode true - datepicker.expect_milestone_date "2022-06-20" + datepicker.expect_milestone_date '2022-06-20' - apply_and_expect_saved start_date: Date.parse("2022-06-20"), - due_date: Date.parse("2022-06-20"), + apply_and_expect_saved start_date: Date.parse('2022-06-20'), + due_date: Date.parse('2022-06-20'), schedule_manually: true date_field.activate! date_field.expect_active! datepicker.expect_visible - datepicker.expect_milestone_date "2022-06-20" + datepicker.expect_milestone_date '2022-06-20' datepicker.expect_scheduling_mode true end end - context "when setting start and due date through today links" do + context 'when setting start and due date through today links' do let(:current_attributes) do { start_date: nil, @@ -1007,20 +1007,20 @@ def apply_and_expect_saved(attributes) } end - it "allows to persist that value (Regression #44140)" do - datepicker.expect_start_date "" - datepicker.expect_due_date "" - datepicker.expect_duration "" + it 'allows to persist that value (Regression #44140)' do + datepicker.expect_start_date '' + datepicker.expect_due_date '' + datepicker.expect_duration '' today = Time.zone.today today_str = today.iso8601 # Setting start will set active to due - datepicker.set_today "start" + datepicker.set_today 'start' datepicker.expect_start_date today_str datepicker.expect_due_highlighted - datepicker.set_today "due" + datepicker.set_today 'due' datepicker.expect_due_date today_str datepicker.expect_start_highlighted @@ -1032,32 +1032,32 @@ def apply_and_expect_saved(attributes) end end - context "when the user locale has a custom digit map" do + context 'when the user locale has a custom digit map' do let(:current_user) { create(:admin, language: :ar) } let(:current_attributes) do { - start_date: Date.parse("2021-02-08"), + start_date: Date.parse('2021-02-08'), due_date: nil, duration: nil } end - it "still renders the traditional Arabic numbers without errors" do + it 'still renders the traditional Arabic numbers without errors' do work_packages_page.expect_no_toaster(type: :error, message: "is not a valid date.") - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "" - datepicker.expect_duration "" + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '' + datepicker.expect_duration '' datepicker.set_duration 10 - datepicker.expect_start_date "2021-02-08" - datepicker.expect_due_date "2021-02-19" + datepicker.expect_start_date '2021-02-08' + datepicker.expect_due_date '2021-02-19' datepicker.expect_duration 10 apply_and_expect_saved duration: 10, - start_date: Date.parse("2021-02-08"), - due_date: Date.parse("2021-02-19") + start_date: Date.parse('2021-02-08'), + due_date: Date.parse('2021-02-19') end end end diff --git a/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb b/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb index 939287fcba12..a5e34ae11ebe 100644 --- a/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb +++ b/spec/features/work_packages/datepicker/datepicker_non_working_day_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/edit_fields/edit_field" +require 'spec_helper' +require 'support/edit_fields/edit_field' -RSpec.describe "Datepicker modal individual non working days (WP #44453)", :js, - with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'Datepicker modal individual non working days (WP #44453)', :js, + with_settings: { date_format: '%Y-%m-%d' } do shared_let(:user) { create(:admin) } shared_let(:project) { create(:project) } @@ -51,12 +51,12 @@ date: Time.zone.today.end_of_year.next_occurring(:tuesday)) end - shared_examples "shows individual non working days" do + shared_examples 'shows individual non working days' do let(:work_packages_page) { Pages::FullWorkPackage.new(work_package, project) } let(:date_field) { work_packages_page.edit_field(date_attribute) } let(:datepicker) { date_field.datepicker } - it "loads and shows individual non working days when navigating" do + it 'loads and shows individual non working days when navigating' do login_as user work_packages_page.visit! @@ -76,17 +76,17 @@ end end - context "for multi date work package" do + context 'for multi date work package' do let(:work_package) { bug_wp } let(:date_attribute) { :combinedDate } - it_behaves_like "shows individual non working days" + it_behaves_like 'shows individual non working days' end - context "for milestone work package" do + context 'for milestone work package' do let(:work_package) { milestone_wp } let(:date_attribute) { :date } - it_behaves_like "shows individual non working days" + it_behaves_like 'shows individual non working days' end end diff --git a/spec/features/work_packages/datepicker/datepicker_parent_spec.rb b/spec/features/work_packages/datepicker/datepicker_parent_spec.rb index 7d9d9c3494fe..1aa18d14b625 100644 --- a/spec/features/work_packages/datepicker/datepicker_parent_spec.rb +++ b/spec/features/work_packages/datepicker/datepicker_parent_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/edit_fields/edit_field" +require 'spec_helper' +require 'support/edit_fields/edit_field' -RSpec.describe "Datepicker logic on parents", :js, with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'Datepicker logic on parents', :js, with_settings: { date_format: '%Y-%m-%d' } do shared_let(:user) { create(:admin) } # assume sat+sun are non working days @@ -62,16 +62,16 @@ datepicker.expect_visible end - context "with the child having set dates" do + context 'with the child having set dates' do let(:child_attributes) do { - start_date: "2021-02-01", - due_date: "2021-02-02", + start_date: '2021-02-01', + due_date: '2021-02-02', ignore_non_working_days: true } end - it "disables the non working days options" do + it 'disables the non working days options' do datepicker.expect_ignore_non_working_days_disabled datepicker.expect_scheduling_mode false diff --git a/spec/features/work_packages/details/closed_status_and_version_spec.rb b/spec/features/work_packages/details/closed_status_and_version_spec.rb index 6f3bef669265..46293fc9c65e 100644 --- a/spec/features/work_packages/details/closed_status_and_version_spec.rb +++ b/spec/features/work_packages/details/closed_status_and_version_spec.rb @@ -1,12 +1,12 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Closed status and version in full view", :js do +RSpec.describe 'Closed status and version in full view', :js do let(:type) { create(:type) } let(:status) { create(:closed_status) } let(:project) { create(:project, types: [type]) } - let(:version) { create(:version, status: "closed", project:) } + let(:version) { create(:version, status: 'closed', project:) } let(:work_package) { create(:work_package, project:, status:, version:) } let(:wp_page) { Pages::FullWorkPackage.new(work_package, project) } @@ -17,13 +17,13 @@ wp_page.visit! end - it "shows a warning when trying to edit status" do + it 'shows a warning when trying to edit status' do # Should be initially editable (due to non specific schema) status = page.find("#{test_selector('op-wp-status-button')} button:not([disabled])") status.click wp_page.expect_and_dismiss_toaster type: :error, - message: I18n.t("js.work_packages.message_work_package_status_blocked") + message: I18n.t('js.work_packages.message_work_package_status_blocked') expect(page).to have_css("#{test_selector('op-wp-status-button')} button[disabled]") end diff --git a/spec/features/work_packages/details/context_menu_spec.rb b/spec/features/work_packages/details/context_menu_spec.rb index 1620d50c1afc..54cab9a7b520 100644 --- a/spec/features/work_packages/details/context_menu_spec.rb +++ b/spec/features/work_packages/details/context_menu_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package single context menu", :js do +RSpec.describe 'Work package single context menu', :js do let(:user) { create(:admin) } let(:work_package) { create(:work_package) } @@ -9,18 +9,18 @@ before do login_as(user) wp_view.visit! - find("#action-show-more-dropdown-menu .button").click + find('#action-show-more-dropdown-menu .button').click end - it "sets the correct copy project link" do - find(".menu-item", text: "Copy to other project", exact_text: true).click - expect(page).to have_css("h2", text: I18n.t(:button_copy)) - expect(page).to have_css("a.work_package", text: "##{work_package.id}") + it 'sets the correct copy project link' do + find('.menu-item', text: 'Copy to other project', exact_text: true).click + expect(page).to have_css('h2', text: I18n.t(:button_copy)) + expect(page).to have_css('a.work_package', text: "##{work_package.id}") expect(page).to have_current_path /work_packages\/move\/new\?copy=true&ids\[\]=#{work_package.id}/ end - it "successfully copies the short url of the work package" do - find(".menu-item", text: "Copy link to clipboard", exact_text: true).click + it 'successfully copies the short url of the work package' do + find('.menu-item', text: 'Copy link to clipboard', exact_text: true).click # We cannot access the navigator.clipboard from a headless browser. # This test makes sure the copy to clipboard logic is working, diff --git a/spec/features/work_packages/details/custom_fields/custom_field_spec.rb b/spec/features/work_packages/details/custom_fields/custom_field_spec.rb index 7443dc0953b3..5ce3fc766c47 100644 --- a/spec/features/work_packages/details/custom_fields/custom_field_spec.rb +++ b/spec/features/work_packages/details/custom_fields/custom_field_spec.rb @@ -1,8 +1,8 @@ -require "spec_helper" -require "features/work_packages/work_packages_page" -require "features/work_packages/details/inplace_editor/shared_examples" +require 'spec_helper' +require 'features/work_packages/work_packages_page' +require 'features/work_packages/details/inplace_editor/shared_examples' -RSpec.describe "custom field inplace editor", :js do +RSpec.describe 'custom field inplace editor', :js do let(:user) { create(:admin) } let(:type) { create(:type_standard, custom_fields:) } let(:project) do @@ -33,19 +33,19 @@ def expect_update(value, update_args) wp_field = update_args.delete(:field) { field } wp_field.set_value value - wp_field.submit_by_enter if wp_field.field_type == "input" + wp_field.submit_by_enter if wp_field.field_type == 'input' wp_page.expect_toast(**update_args) wp_page.dismiss_toaster! end - describe "long text" do + describe 'long text' do let(:custom_field) do - create(:issue_custom_field, :text, name: "LongText") + create(:issue_custom_field, :text, name: 'LongText') end let(:field) { TextEditorField.new wp_page, property_name } - let(:initial_custom_values) { { custom_field.id => "foo" } } + let(:initial_custom_values) { { custom_field.id => 'foo' } } - it "can cancel through the button only" do + it 'can cancel through the button only' do # Activate the field field.activate! @@ -58,11 +58,11 @@ def expect_update(value, update_args) field.expect_inactive! end - it_behaves_like "a workpackage autocomplete field" - it_behaves_like "not a principal autocomplete field" + it_behaves_like 'a workpackage autocomplete field' + it_behaves_like 'not a principal autocomplete field' end - describe "custom field lists" do + describe 'custom field lists' do let(:custom_field1) do create(:list_wp_custom_field, is_required: false, @@ -77,12 +77,12 @@ def expect_update(value, update_args) let(:custom_fields) { [custom_field1, custom_field2] } let(:field1) do f = wp_page.custom_edit_field(custom_field1) - f.field_type = "create-autocompleter" + f.field_type = 'create-autocompleter' f end let(:field2) do f = wp_page.custom_edit_field(custom_field2) - f.field_type = "create-autocompleter" + f.field_type = 'create-autocompleter' f end let(:initial_custom_values) { {} } @@ -91,98 +91,98 @@ def custom_value(value) CustomOption.find_by(value:).try(:id) end - it "properly updates both values" do + it 'properly updates both values' do field1.activate! - expect_update "bar", - message: I18n.t("js.notice_successful_update"), + expect_update 'bar', + message: I18n.t('js.notice_successful_update'), field: field1 field2.activate! - expect_update "Y", - message: I18n.t("js.notice_successful_update"), + expect_update 'Y', + message: I18n.t('js.notice_successful_update'), field: field2 - wp_page.expect_attributes "customField#{custom_field1.id}": "bar", - "customField#{custom_field2.id}": "Y" + wp_page.expect_attributes "customField#{custom_field1.id}": 'bar', + "customField#{custom_field2.id}": 'Y' field1.activate! - expect(field1.input_element).to have_text "bar" + expect(field1.input_element).to have_text 'bar' field1.cancel_by_escape field2.activate! - expect(field2.input_element).to have_text "Y" + expect(field2.input_element).to have_text 'Y' - expect_update "X", - message: I18n.t("js.notice_successful_update"), + expect_update 'X', + message: I18n.t('js.notice_successful_update'), field: field2 - wp_page.expect_attributes "customField#{custom_field1.id}": "bar", - "customField#{custom_field2.id}": "X" + wp_page.expect_attributes "customField#{custom_field1.id}": 'bar', + "customField#{custom_field2.id}": 'X' end end - describe "integer type" do + describe 'integer type' do let(:custom_field) do - create(:issue_custom_field, :integer, args.merge(name: "MyNumber")) + create(:issue_custom_field, :integer, args.merge(name: 'MyNumber')) end let(:initial_custom_values) { { custom_field.id => 123 } } - context "with length restrictions" do + context 'with length restrictions' do let(:args) do { min_length: 2, max_length: 5 } end - it "renders errors for invalid entries" do + it 'renders errors for invalid entries' do field.activate! # exceeding max length - expect_update "123456", + expect_update '123456', type: :error, - message: "MyNumber is too long (maximum is 5 characters)." + message: 'MyNumber is too long (maximum is 5 characters).' # below min length - expect_update "1", + expect_update '1', type: :error, - message: "MyNumber is too short (minimum is 2 characters)." + message: 'MyNumber is too short (minimum is 2 characters).' # Correct value - expect_update "9999", - message: I18n.t("js.notice_successful_update") - wp_page.expect_attributes property_name => "9999" + expect_update '9999', + message: I18n.t('js.notice_successful_update') + wp_page.expect_attributes property_name => '9999' end end - context "with no restrictions" do + context 'with no restrictions' do let(:args) { {} } - it "renders errors for invalid entries" do + it 'renders errors for invalid entries' do # Valid input field.activate! - expect_update "9999999999", - message: I18n.t("js.notice_successful_update") - wp_page.expect_attributes property_name => "9999999999" + expect_update '9999999999', + message: I18n.t('js.notice_successful_update') + wp_page.expect_attributes property_name => '9999999999' # Remove value field.activate! - expect_update "", - message: I18n.t("js.notice_successful_update") - wp_page.expect_attributes property_name => "-" + expect_update '', + message: I18n.t('js.notice_successful_update') + wp_page.expect_attributes property_name => '-' # Zero value field.activate_edition - expect_update "0", - message: I18n.t("js.notice_successful_update") - wp_page.expect_attributes property_name => "0" + expect_update '0', + message: I18n.t('js.notice_successful_update') + wp_page.expect_attributes property_name => '0' end end - context "when required" do + context 'when required' do let(:args) { { is_required: true } } - it "renders errors for invalid entries" do + it 'renders errors for invalid entries' do # Invalid input (non-digit) field.activate! - field.set_value "" + field.set_value '' field.expect_invalid field.save! @@ -193,43 +193,43 @@ def custom_value(value) end end - describe "float type" do + describe 'float type' do let(:custom_field) do - create(:float_wp_custom_field, args.merge(name: "MyFloat")) + create(:float_wp_custom_field, args.merge(name: 'MyFloat')) end let(:args) { {} } let(:initial_custom_values) { { custom_field.id => 123.50 } } - context "with zero value" do - let(:user) { create(:admin, language: "en") } + context 'with zero value' do + let(:user) { create(:admin, language: 'en') } let(:initial_custom_values) { { custom_field.id => 0 } } - it "displays the zero (Regression #37157)" do - field.expect_state_text "0" + it 'displays the zero (Regression #37157)' do + field.expect_state_text '0' end end - context "with english locale" do - let(:user) { create(:admin, language: "en") } + context 'with english locale' do + let(:user) { create(:admin, language: 'en') } - it "displays the float with english locale and allows editing" do - field.expect_state_text "123.5" - field.update "10000.55" - field.expect_state_text "10,000.55" + it 'displays the float with english locale and allows editing' do + field.expect_state_text '123.5' + field.update '10000.55' + field.expect_state_text '10,000.55' work_package.reload expect(work_package.custom_value_for(custom_field.id).typed_value).to eq 10000.55 end end - context "with german locale", + context 'with german locale', driver: :firefox_de do - let(:user) { create(:admin, language: "de") } + let(:user) { create(:admin, language: 'de') } - it "displays the float with german locale and allows editing" do - field.expect_state_text "123,5" - field.update "10000,55" - field.expect_state_text "10.000,55" + it 'displays the float with german locale and allows editing' do + field.expect_state_text '123,5' + field.update '10000,55' + field.expect_state_text '10.000,55' work_package.reload expect(work_package.custom_value_for(custom_field.id).typed_value).to eq 10000.55 diff --git a/spec/features/work_packages/details/date_editor_spec.rb b/spec/features/work_packages/details/date_editor_spec.rb index fddcd03c5d20..b0556bad4ffc 100644 --- a/spec/features/work_packages/details/date_editor_spec.rb +++ b/spec/features/work_packages/details/date_editor_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" - -RSpec.describe "date inplace editor", :js, :selenium, with_settings: { date_format: "%Y-%m-%d" } do +require 'spec_helper' +require 'features/page_objects/notification' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' + +RSpec.describe 'date inplace editor', :js, :selenium, with_settings: { date_format: '%Y-%m-%d' } do shared_let(:project) { create(:project_with_types, public: true) } shared_let(:user) { create(:admin) } shared_let(:type) { project.types.first } @@ -49,7 +49,7 @@ ) end - let(:work_package) { create(:work_package, project:, start_date: Date.parse("2016-01-02"), duration: nil) } + let(:work_package) { create(:work_package, project:, start_date: Date.parse('2016-01-02'), duration: nil) } let(:work_packages_page) { Pages::FullWorkPackage.new(work_package, project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -66,28 +66,28 @@ work_packages_page.ensure_page_loaded end - it "can directly set the due date when only a start date is set" do + it 'can directly set the due date when only a start date is set' do start_date.activate! start_date.expect_active! - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" - start_date.datepicker.select_day "25" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' + start_date.datepicker.select_day '25' - start_date.datepicker.expect_start_date "2016-01-02" - start_date.datepicker.expect_due_date "2016-01-25" + start_date.datepicker.expect_start_date '2016-01-02' + start_date.datepicker.expect_due_date '2016-01-25' start_date.datepicker.expect_duration 24 start_date.save! start_date.expect_inactive! - start_date.expect_state_text "2016-01-02 - 2016-01-25" + start_date.expect_state_text '2016-01-02 - 2016-01-25' end it 'can set "today" as a date via the provided link' do start_date.activate! start_date.expect_active! - start_date.datepicker.expect_start_date "2016-01-02" + start_date.datepicker.expect_start_date '2016-01-02' start_date.datepicker.expect_year work_package.start_date.year start_date.datepicker.expect_month work_package.start_date.strftime("%B") start_date.datepicker.expect_day work_package.start_date.day @@ -104,84 +104,84 @@ start_date.expect_state_text "#{Time.zone.today.strftime('%Y-%m-%d')} - no finish date" end - context "with start and end date set" do + context 'with start and end date set' do let(:work_package) do create(:work_package, project:, - start_date: Date.parse("2016-01-02"), - due_date: Date.parse("2016-01-25")) + start_date: Date.parse('2016-01-02'), + due_date: Date.parse('2016-01-25')) end - it "selecting a date before the current start date will move the finish date" do + it 'selecting a date before the current start date will move the finish date' do start_date.activate! start_date.expect_active! - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" - start_date.datepicker.select_day "1" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' + start_date.datepicker.select_day '1' - start_date.datepicker.expect_start_date "2016-01-01" - start_date.datepicker.expect_due_date "2016-01-24" + start_date.datepicker.expect_start_date '2016-01-01' + start_date.datepicker.expect_due_date '2016-01-24' start_date.datepicker.expect_duration 24 start_date.save! start_date.expect_inactive! - start_date.expect_state_text "2016-01-01 - 2016-01-24" + start_date.expect_state_text '2016-01-01 - 2016-01-24' end - it "selecting a date in between changes the date that is currently in focus" do + it 'selecting a date in between changes the date that is currently in focus' do start_date.activate! start_date.expect_active! - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" - start_date.datepicker.select_day "3" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' + start_date.datepicker.select_day '3' - start_date.datepicker.expect_start_date "2016-01-03" + start_date.datepicker.expect_start_date '2016-01-03' # Since the focus shifts automatically, we can directly click again to modify the end date - start_date.datepicker.select_day "21" + start_date.datepicker.select_day '21' - start_date.datepicker.expect_due_date "2016-01-21" + start_date.datepicker.expect_due_date '2016-01-21' start_date.datepicker.expect_duration 19 start_date.save! start_date.expect_inactive! - start_date.expect_state_text "2016-01-03 - 2016-01-21" + start_date.expect_state_text '2016-01-03 - 2016-01-21' end - it "selecting a date after the current finish date will change either start or finish depending on the focus" do + it 'selecting a date after the current finish date will change either start or finish depending on the focus' do start_date.activate! start_date.expect_active! - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' # Focus the end date field start_date.activate_due_date_within_modal - start_date.datepicker.set_due_date "2016-03-01" + start_date.datepicker.set_due_date '2016-03-01' # Since the end date is focused, the date will become the new end date start_date.save! start_date.expect_inactive! - start_date.expect_state_text "2016-01-02 - 2016-03-01" + start_date.expect_state_text '2016-01-02 - 2016-03-01' # Activating again and now changing the start date to something after the current end date start_date.activate! start_date.expect_active! - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" - start_date.datepicker.set_start_date "2016-04-01" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' + start_date.datepicker.set_start_date '2016-04-01' # This will set the new start and unset the end date start_date.save! start_date.expect_inactive! - start_date.expect_state_text "2016-04-01 - no finish date" + start_date.expect_state_text '2016-04-01 - no finish date' end end - context "with the start date empty" do + context 'with the start date empty' do let(:work_package) { create(:work_package, project:, start_date: nil, duration: nil) } it 'can set "today" as a date via the provided link' do @@ -203,7 +203,7 @@ end end - it "can set start and due date to the same day" do + it 'can set start and due date to the same day' do start_date.activate! start_date.expect_active! @@ -226,10 +226,10 @@ start_date.save! start_date.expect_inactive! - start_date.expect_state_text Time.zone.today.strftime("%Y-%m-%d") + start_date.expect_state_text Time.zone.today.strftime('%Y-%m-%d') end - it "can set a negative duration which gets transformed (Regression #44219)" do + it 'can set a negative duration which gets transformed (Regression #44219)' do start_date.activate! start_date.expect_active! @@ -240,7 +240,7 @@ start_date.datepicker.expect_duration 128 end - it "saves the date when clearing and then confirming" do + it 'saves the date when clearing and then confirming' do start_date.activate! start_date.input_element.click @@ -250,35 +250,35 @@ sleep 1 start_date.save! - work_packages_page.expect_and_dismiss_toaster message: "Successful update." + work_packages_page.expect_and_dismiss_toaster message: 'Successful update.' start_date.expect_inactive! - start_date.expect_state_text "no start date" + start_date.expect_state_text 'no start date' work_package.reload expect(work_package.start_date).to be_nil end - it "closes the date picker when moving away" do + it 'closes the date picker when moving away' do wp_table.visit! wp_table.open_full_screen_by_doubleclick work_package start_date.activate! start_date.expect_active! - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') work_packages_page.accept_alert_dialog! if work_packages_page.has_alert_dialog? # Ensure no modal survives - expect(page).to have_no_css(".spot-modal") + expect(page).to have_no_css('.spot-modal') end - context "with a date custom field" do + context 'with a date custom field' do let(:cf_field) { EditField.new page, date_cf.attribute_name(:camel_case) } let(:datepicker) { Components::BasicDatepicker.new } let(:create_page) { Pages::FullWorkPackageCreate.new(project:) } - it "can handle creating a CF date" do + it 'can handle creating a CF date' do create_page.visit! type_field = create_page.edit_field(:type) @@ -297,15 +297,15 @@ # Open date picker cf_field.input_element.click datepicker.set_date Time.zone.today - create_page.edit_field(:subject).set_value "My subject!" + create_page.edit_field(:subject).set_value 'My subject!' create_page.save! - create_page.expect_and_dismiss_toaster message: "Successful creation" + create_page.expect_and_dismiss_toaster message: 'Successful creation' wp = WorkPackage.last expect(wp.custom_value_for(date_cf.id).value).to eq Time.zone.today.iso8601 end - it "can set the date via the in-place editing" do + it 'can set the date via the in-place editing' do datepicker.expect_not_visible cf_field.activate! @@ -313,13 +313,13 @@ datepicker.set_date Time.zone.today - create_page.expect_and_dismiss_toaster message: "Successful update." + create_page.expect_and_dismiss_toaster message: 'Successful update.' cf_field.expect_inactive! - cf_field.expect_state_text Time.zone.today.strftime("%Y-%m-%d") + cf_field.expect_state_text Time.zone.today.strftime('%Y-%m-%d') end end - context "with the work package having no relations whatsoever" do + context 'with the work package having no relations whatsoever' do let!(:work_package) { create(:work_package, project:) } before do @@ -327,19 +327,19 @@ start_date.expect_active! end - it "does not show a banner with or without manual scheduling" do - expect(page).not_to have_test_selector("op-modal-banner-warning") - expect(page).not_to have_test_selector("op-modal-banner-info") + it 'does not show a banner with or without manual scheduling' do + expect(page).not_to have_test_selector('op-modal-banner-warning') + expect(page).not_to have_test_selector('op-modal-banner-info') # When toggling manually scheduled start_date.toggle_scheduling_mode - expect(page).not_to have_test_selector("op-modal-banner-warning") - expect(page).not_to have_test_selector("op-modal-banner-info") + expect(page).not_to have_test_selector('op-modal-banner-warning') + expect(page).not_to have_test_selector('op-modal-banner-info') end end - context "with the work package being the last in the hierarchy" do + context 'with the work package being the last in the hierarchy' do let!(:parent) { create(:work_package, project:, schedule_manually:, start_date: 1.day.ago, due_date: 5.days.from_now) } let!(:work_package) { create(:work_package, project:, schedule_manually:, parent:) } @@ -348,12 +348,12 @@ start_date.expect_active! end - context "when work package is manually scheduled" do + context 'when work package is manually scheduled' do let(:schedule_manually) { true } - it "shows a banner that the relations are ignored" do + it 'shows a banner that the relations are ignored' do expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.", + text: 'Manual scheduling enabled, all relations ignored.', wait: 5) # When toggling manually scheduled @@ -362,9 +362,9 @@ # Expect new banner info expect(page) .to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Changing these dates will affect dates of related work packages.") + text: 'Changing these dates will affect dates of related work packages.') - new_window = window_opened_by { click_on "Show relations" } + new_window = window_opened_by { click_on 'Show relations' } switch_to_window new_window wp_table.expect_work_package_listed parent @@ -375,25 +375,25 @@ end end - context "when work package is not manually scheduled" do + context 'when work package is not manually scheduled' do let(:schedule_manually) { false } - it "shows a banner that the start date is limited" do + it 'shows a banner that the start date is limited' do expect(page) .to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Changing these dates will affect dates of related work packages.", + text: 'Changing these dates will affect dates of related work packages.', wait: 5) # When toggling manually scheduled start_date.toggle_scheduling_mode expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') end end end - context "with the work package being a parent" do + context 'with the work package being a parent' do let!(:child) { create(:work_package, project:, start_date: 1.day.ago, due_date: 5.days.from_now) } let!(:work_package) do wp = create(:work_package, project:, schedule_manually:) @@ -406,21 +406,21 @@ start_date.expect_active! end - context "when parent is manually scheduled" do + context 'when parent is manually scheduled' do let(:schedule_manually) { true } - it "shows a banner that the relations are ignored" do + it 'shows a banner that the relations are ignored' do expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') # When toggling manually scheduled start_date.toggle_scheduling_mode # Expect banner to switch expect(page).to have_css("#{test_selector('op-modal-banner-info')} span", - text: "Automatically scheduled. Dates are derived from relations.") + text: 'Automatically scheduled. Dates are derived from relations.') - new_window = window_opened_by { click_on "Show relations" } + new_window = window_opened_by { click_on 'Show relations' } switch_to_window new_window wp_table.expect_work_package_listed child @@ -429,39 +429,39 @@ end end - context "when parent is not manually scheduled" do + context 'when parent is not manually scheduled' do let(:schedule_manually) { false } - it "shows a banner that the dates are not editable" do + it 'shows a banner that the dates are not editable' do expect(page).to have_css("#{test_selector('op-modal-banner-info')} span", - text: "Automatically scheduled. Dates are derived from relations.") + text: 'Automatically scheduled. Dates are derived from relations.') # When toggling manually scheduled start_date.toggle_scheduling_mode expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') - new_window = window_opened_by { click_on "Show relations" } + new_window = window_opened_by { click_on 'Show relations' } switch_to_window new_window wp_table.expect_work_package_listed child wp_timeline.expect_timeline! end - context "when parent is not manually scheduled, child has workdays only set" do + context 'when parent is not manually scheduled, child has workdays only set' do let(:schedule_manually) { false } let!(:child) do create(:work_package, project:, ignore_non_working_days: false, - start_date: Date.parse("2022-09-27"), - due_date: Date.parse("2022-09-29")) + start_date: Date.parse('2022-09-27'), + due_date: Date.parse('2022-09-29')) end - it "allows switching to manual scheduling to set the ignore NWD (Regression #43933)" do + it 'allows switching to manual scheduling to set the ignore NWD (Regression #43933)' do expect(page).to have_css("#{test_selector('op-modal-banner-info')} span", - text: "Automatically scheduled. Dates are derived from relations.") + text: 'Automatically scheduled. Dates are derived from relations.') # Expect "Working days only" to be checked datepicker.expect_ignore_non_working_days_disabled @@ -474,7 +474,7 @@ datepicker.expect_ignore_non_working_days true expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') # Reset when disabled start_date.toggle_scheduling_mode @@ -482,13 +482,13 @@ datepicker.expect_ignore_non_working_days false, disabled: true expect(page).to have_css("#{test_selector('op-modal-banner-info')} span", - text: "Automatically scheduled. Dates are derived from relations.") + text: 'Automatically scheduled. Dates are derived from relations.') end end end end - context "with the work package having a precedes relation" do + context 'with the work package having a precedes relation' do let!(:work_package) { create(:work_package, project:, schedule_manually:) } let!(:preceding) { create(:work_package, project:, start_date: 10.days.ago, due_date: 5.days.ago) } @@ -504,21 +504,21 @@ start_date.expect_active! end - context "when work package is manually scheduled" do + context 'when work package is manually scheduled' do let(:schedule_manually) { true } - it "shows a banner that the relations are ignored" do + it 'shows a banner that the relations are ignored' do expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') # When toggling manually scheduled start_date.toggle_scheduling_mode # Expect new banner info expect(page).to have_css("#{test_selector('op-modal-banner-info')} span", - text: "Available start and finish dates are limited by relations.") + text: 'Available start and finish dates are limited by relations.') - new_window = window_opened_by { click_on "Show relations" } + new_window = window_opened_by { click_on 'Show relations' } switch_to_window new_window wp_table.expect_work_package_listed preceding @@ -527,23 +527,23 @@ end end - context "when work package is not manually scheduled" do + context 'when work package is not manually scheduled' do let(:schedule_manually) { false } - it "shows a banner that the start date is limited" do + it 'shows a banner that the start date is limited' do expect(page).to have_css("#{test_selector('op-modal-banner-info')} span", - text: "Available start and finish dates are limited by relations.") + text: 'Available start and finish dates are limited by relations.') # When toggling manually scheduled start_date.toggle_scheduling_mode expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') end end end - context "with the work package having a follows relation" do + context 'with the work package having a follows relation' do let!(:work_package) { create(:work_package, project:, schedule_manually:) } let!(:following) { create(:work_package, project:, start_date: 5.days.from_now, due_date: 10.days.from_now) } @@ -559,21 +559,21 @@ start_date.expect_active! end - context "when work package is manually scheduled" do + context 'when work package is manually scheduled' do let(:schedule_manually) { true } - it "shows a banner that the relations are ignored" do + it 'shows a banner that the relations are ignored' do expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') # When toggling manually scheduled start_date.toggle_scheduling_mode expect(page) .to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Changing these dates will affect dates of related work packages.") + text: 'Changing these dates will affect dates of related work packages.') - new_window = window_opened_by { click_on "Show relations" } + new_window = window_opened_by { click_on 'Show relations' } switch_to_window new_window wp_table.expect_work_package_listed following @@ -582,41 +582,41 @@ end end - context "when work package is not manually scheduled" do + context 'when work package is not manually scheduled' do let(:schedule_manually) { false } - it "shows a banner that the start date is limited" do + it 'shows a banner that the start date is limited' do expect(page) .to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Changing these dates will affect dates of related work packages.") + text: 'Changing these dates will affect dates of related work packages.') # When toggling manually scheduled start_date.toggle_scheduling_mode expect(page).to have_css("#{test_selector('op-modal-banner-warning')} span", - text: "Manual scheduling enabled, all relations ignored.") + text: 'Manual scheduling enabled, all relations ignored.') end end end - context "with a negative time zone", driver: :chrome_new_york_time_zone do - it "can normally select the dates via datepicker (regression #43562)" do + context 'with a negative time zone', driver: :chrome_new_york_time_zone do + it 'can normally select the dates via datepicker (regression #43562)' do start_date.activate! start_date.expect_active! - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" - start_date.datepicker.select_day "25" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' + start_date.datepicker.select_day '25' sleep 2 - start_date.datepicker.expect_year "2016" - start_date.datepicker.expect_month "January" - start_date.datepicker.expect_day "25" + start_date.datepicker.expect_year '2016' + start_date.datepicker.expect_month 'January' + start_date.datepicker.expect_day '25' start_date.save! start_date.expect_inactive! - start_date.expect_state_text "2016-01-02 - 2016-01-25" + start_date.expect_state_text '2016-01-02 - 2016-01-25' end end end diff --git a/spec/features/work_packages/details/details_refreshing_spec.rb b/spec/features/work_packages/details/details_refreshing_spec.rb index df950bfbcab9..729316f6ffaf 100644 --- a/spec/features/work_packages/details/details_refreshing_spec.rb +++ b/spec/features/work_packages/details/details_refreshing_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Work package table refreshing due to split view", :js, :with_cuprite do +RSpec.describe 'Work package table refreshing due to split view', :js, :with_cuprite do let(:project) { create(:project_with_types) } let!(:work_package) { create(:work_package, project:) } let(:wp_split) { Pages::SplitWorkPackage.new work_package } @@ -41,13 +41,13 @@ wp_split.visit! end - it "toggles the watch state" do + it 'toggles the watch state' do wp_split.ensure_page_loaded wp_split.edit_field(:subject).expect_text work_package.subject wp_table.expect_work_package_listed work_package page.within wp_table.row(work_package) do - expect(page).to have_css(".wp-table--drag-and-drop-handle.icon-drag-handle", visible: :all) + expect(page).to have_css('.wp-table--drag-and-drop-handle.icon-drag-handle', visible: :all) end end end diff --git a/spec/features/work_packages/details/details_toolbar_spec.rb b/spec/features/work_packages/details/details_toolbar_spec.rb index 0c88255ccb2b..48b9ed001fa9 100644 --- a/spec/features/work_packages/details/details_toolbar_spec.rb +++ b/spec/features/work_packages/details/details_toolbar_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Work package details toolbar", :js, :selenium do +RSpec.describe 'Work package details toolbar', :js, :selenium do let(:project) { create(:project_with_types, public: true) } let!(:work_package) { create(:work_package, project:) } let(:work_packages_page) { WorkPackagesPage.new(project) } - describe "toggle watch state" do + describe 'toggle watch state' do let(:user) { create(:admin) } before do @@ -42,17 +42,17 @@ work_packages_page.visit_index(work_package) end - it "toggles the watch state" do + it 'toggles the watch state' do expect(work_package.watcher_users).not_to include(user) - expect(page).to have_css(".work-packages--details-toolbar button", text: "Watch") - within ".work-packages--details-toolbar" do - click_button "Watch" + expect(page).to have_css('.work-packages--details-toolbar button', text: 'Watch') + within '.work-packages--details-toolbar' do + click_button 'Watch' end - expect(page).to have_css(".work-packages--details-toolbar button", text: "Unwatch") + expect(page).to have_css('.work-packages--details-toolbar button', text: 'Unwatch') expect(work_package.reload.watcher_users).to include(user) - expect(page).to have_css(".work-packages--details-toolbar button", text: "Unwatch") + expect(page).to have_css('.work-packages--details-toolbar button', text: 'Unwatch') end end end diff --git a/spec/features/work_packages/details/inplace_editor/shared_examples.rb b/spec/features/work_packages/details/inplace_editor/shared_examples.rb index 510bbf5e22d9..1b7c1a9e7ade 100644 --- a/spec/features/work_packages/details/inplace_editor/shared_examples.rb +++ b/spec/features/work_packages/details/inplace_editor/shared_examples.rb @@ -1,12 +1,12 @@ -RSpec.shared_examples "as an accessible inplace editor" do - it "triggers edit mode on click" do +RSpec.shared_examples 'as an accessible inplace editor' do + it 'triggers edit mode on click' do scroll_to_element(field.display_element) field.activate_edition expect(field).to be_editing field.cancel_by_escape end - it "triggers edit mode on RETURN key" do + it 'triggers edit mode on RETURN key' do scroll_to_element(field.display_element) field.display_element.native.send_keys(:return) @@ -14,43 +14,43 @@ field.cancel_by_escape end - it "is focusable" do + it 'is focusable' do scroll_to_element(field.display_element) - tab_index = field.display_element["tabindex"] + tab_index = field.display_element['tabindex'] expect(tab_index).not_to be_nil - expect(tab_index).not_to eq("-1") + expect(tab_index).not_to eq('-1') end end -RSpec.shared_examples "as an auth aware field" do - context "when is editable" do - it_behaves_like "as an accessible inplace editor" +RSpec.shared_examples 'as an auth aware field' do + context 'when is editable' do + it_behaves_like 'as an accessible inplace editor' end - context "when user is authorized" do - it "is editable" do + context 'when user is authorized' do + it 'is editable' do expect(field).to be_editable end end - context "when user is not authorized" do + context 'when user is not authorized' do let(:user) do create(:user, member_with_permissions: { project => %i(view_work_packages) }) end - it "is not editable" do + it 'is not editable' do expect(field).not_to be_editable end end end -RSpec.shared_context "as a single validation point" do +RSpec.shared_context 'as a single validation point' do let(:other_field) { EditField.new page, :type } before do other_field.activate_edition field.activate_edition - field.input_element.set "" + field.input_element.set '' field.submit_by_enter end @@ -60,10 +60,10 @@ end end -RSpec.shared_context "as a required field" do +RSpec.shared_context 'as a required field' do before do field.activate_edition - field.input_element.set "" + field.input_element.set '' field.submit_by_enter end @@ -72,69 +72,69 @@ end end -RSpec.shared_examples "a cancellable field" do - shared_examples "cancelling properly" do - it "reverts to read state and keeps its focus" do +RSpec.shared_examples 'a cancellable field' do + shared_examples 'cancelling properly' do + it 'reverts to read state and keeps its focus' do expect(field).not_to be_editing field.expect_state_text(work_package.send(property_name)) - active_class_name = page.evaluate_script("document.activeElement.className") + active_class_name = page.evaluate_script('document.activeElement.className') expect(active_class_name).to include(field.display_selector[1..]) end end - context "for escape" do + context 'for escape' do before do field.activate! sleep 1 field.cancel_by_escape end - it_behaves_like "cancelling properly" + it_behaves_like 'cancelling properly' end end -RSpec.shared_examples "a workpackage autocomplete field" do - let!(:wp2) { create(:work_package, project:, subject: "AutoFoo") } +RSpec.shared_examples 'a workpackage autocomplete field' do + let!(:wp2) { create(:work_package, project:, subject: 'AutoFoo') } - it "autocompletes the other work package" do + it 'autocompletes the other work package' do field.activate! field.clear field.type(" ##{wp2.id}") - expect(page).to have_css(".mention-list-item", text: wp2.to_s.strip) + expect(page).to have_css('.mention-list-item', text: wp2.to_s.strip) end end -RSpec.shared_examples "a principal autocomplete field" do +RSpec.shared_examples 'a principal autocomplete field' do let(:role) { create(:project_role, permissions: %i[view_work_packages edit_work_packages]) } let!(:user) do create(:user, member_with_roles: { project => role }, - firstname: "John") + firstname: 'John') end let!(:mentioned_user) do create(:user, member_with_roles: { project => role }, - firstname: "Laura", - lastname: "Foobar") + firstname: 'Laura', + lastname: 'Foobar') end let!(:mentioned_group) do - create(:group, lastname: "Laudators", member_with_roles: { project => role }) + create(:group, lastname: 'Laudators', member_with_roles: { project => role }) end - shared_examples "principal autocomplete on field" do + shared_examples 'principal autocomplete on field' do before do wp_page.visit! wp_page.ensure_page_loaded end - it "autocompletes links to user profiles" do + it 'autocompletes links to user profiles' do field.activate! field.clear with_backspace: true field.input_element.send_keys(" @lau") - expect(page).to have_css(".mention-list-item", text: mentioned_user.name) - expect(page).to have_css(".mention-list-item", text: mentioned_group.name) - expect(page).to have_no_css(".mention-list-item", text: user.name) + expect(page).to have_css('.mention-list-item', text: mentioned_user.name) + expect(page).to have_css('.mention-list-item', text: mentioned_group.name) + expect(page).to have_no_css('.mention-list-item', text: user.name) # Close the autocompleter field.input_element.send_keys :escape @@ -142,67 +142,67 @@ sleep 2 - field.ckeditor.type_slowly "@Laura" - expect(page).to have_css(".mention-list-item", text: mentioned_user.name) - expect(page).to have_no_css(".mention-list-item", text: mentioned_group.name) - expect(page).to have_no_css(".mention-list-item", text: user.name) + field.ckeditor.type_slowly '@Laura' + expect(page).to have_css('.mention-list-item', text: mentioned_user.name) + expect(page).to have_no_css('.mention-list-item', text: mentioned_group.name) + expect(page).to have_no_css('.mention-list-item', text: user.name) end end - context "with the project page" do + context 'with the project page' do let(:wp_page) { Pages::SplitWorkPackage.new(work_package, project) } - it_behaves_like "principal autocomplete on field" + it_behaves_like 'principal autocomplete on field' end - context "without the project page" do + context 'without the project page' do let(:wp_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "principal autocomplete on field" + it_behaves_like 'principal autocomplete on field' end end -RSpec.shared_examples "not a principal autocomplete field" do +RSpec.shared_examples 'not a principal autocomplete field' do let(:role) { create(:project_role, permissions: %i[view_work_packages edit_work_packages]) } let!(:user) do create(:user, member_with_roles: { project => role }, - firstname: "John") + firstname: 'John') end let!(:mentioned_user) do create(:user, member_with_roles: { project => role }, - firstname: "Laura", - lastname: "Foobar") + firstname: 'Laura', + lastname: 'Foobar') end let!(:mentioned_group) do - create(:group, lastname: "Laudators", member_with_roles: { project => role }) + create(:group, lastname: 'Laudators', member_with_roles: { project => role }) end - shared_examples "not principal autocomplete on field" do + shared_examples 'not principal autocomplete on field' do before do wp_page.visit! wp_page.ensure_page_loaded end - it "does not autocompletes links to user profiles" do + it 'does not autocompletes links to user profiles' do field.activate! field.clear with_backspace: true field.input_element.send_keys(" @lau") sleep 2 - expect(page).to have_no_css(".mention-list-item") + expect(page).to have_no_css('.mention-list-item') end end - context "with the project page" do + context 'with the project page' do let(:wp_page) { Pages::SplitWorkPackage.new(work_package, project) } - it_behaves_like "not principal autocomplete on field" + it_behaves_like 'not principal autocomplete on field' end - context "without the project page" do + context 'without the project page' do let(:wp_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "not principal autocomplete on field" + it_behaves_like 'not principal autocomplete on field' end end diff --git a/spec/features/work_packages/details/inplace_editor/subject_editor_spec.rb b/spec/features/work_packages/details/inplace_editor/subject_editor_spec.rb index e3cb1a6d0741..32788c9d7d27 100644 --- a/spec/features/work_packages/details/inplace_editor/subject_editor_spec.rb +++ b/spec/features/work_packages/details/inplace_editor/subject_editor_spec.rb @@ -1,14 +1,14 @@ -require "spec_helper" -require "features/page_objects/notification" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" - -RSpec.describe "subject inplace editor", :js, :selenium do +require 'spec_helper' +require 'features/page_objects/notification' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' + +RSpec.describe 'subject inplace editor', :js, :selenium do let(:project) { create(:project_with_types, public: true) } let(:property_name) { :subject } - let(:property_title) { "Subject" } + let(:property_title) { 'Subject' } let(:work_package) { create(:work_package, project:) } let(:user) { create(:admin) } let(:work_packages_page) { Pages::SplitWorkPackage.new(work_package, project) } @@ -22,33 +22,33 @@ work_packages_page.ensure_page_loaded end - context "as a read state" do - it "has correct content" do + context 'as a read state' do + it 'has correct content' do field.expect_state_text(work_package.send(property_name)) end end - it_behaves_like "as an auth aware field" - it_behaves_like "a cancellable field" - it_behaves_like "as a single validation point" - it_behaves_like "as a required field" + it_behaves_like 'as an auth aware field' + it_behaves_like 'a cancellable field' + it_behaves_like 'as a single validation point' + it_behaves_like 'as a required field' - context "as an edit state" do + context 'as an edit state' do before do field.activate_edition end - it "renders a text input" do + it 'renders a text input' do expect(field.input_element).to be_visible - expect(field.input_element["type"]).to eq "text" + expect(field.input_element['type']).to eq 'text' end - it "has a correct value for the input" do + it 'has a correct value for the input' do expect(field.input_element[:value]).to eq work_package.subject end - it "displays an error when too long" do - too_long = "*" * 256 + it 'displays an error when too long' do + too_long = '*' * 256 field.set_value too_long field.submit_by_enter @@ -56,34 +56,34 @@ field.expect_active! expect(field.input_element.value).to eq(too_long) - notification.expect_error("Subject is too long (maximum is 255 characters)") + notification.expect_error('Subject is too long (maximum is 255 characters)') end - context "when save" do + context 'when save' do before do - field.input_element.set "Aloha" + field.input_element.set 'Aloha' end # safeguard - include_context "ensure wp details pane update done" do + include_context 'ensure wp details pane update done' do let(:update_user) { user } end - it "saves the value on ENTER" do + it 'saves the value on ENTER' do field.submit_by_enter - field.expect_state_text("Aloha") + field.expect_state_text('Aloha') end end end - context "with conflicting modification" do - it "shows a conflict when modified elsewhere" do - work_package.subject = "Some other subject!" + context 'with conflicting modification' do + it 'shows a conflict when modified elsewhere' do + work_package.subject = 'Some other subject!' work_package.save! field.display_element.click - notification.expect_error(I18n.t("api_v3.errors.code_409")) + notification.expect_error(I18n.t('api_v3.errors.code_409')) end end end diff --git a/spec/features/work_packages/details/inplace_editor/version_editor_spec.rb b/spec/features/work_packages/details/inplace_editor/version_editor_spec.rb index 1d3fac2cd741..120d461958fa 100644 --- a/spec/features/work_packages/details/inplace_editor/version_editor_spec.rb +++ b/spec/features/work_packages/details/inplace_editor/version_editor_spec.rb @@ -1,39 +1,39 @@ -require "spec_helper" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' -RSpec.describe "subject inplace editor", :js, :selenium do - let(:project) { create(:project_with_types, name: "Root", public: true) } - let(:subproject1) { create(:project_with_types, name: "Child", parent: project) } - let(:subproject2) { create(:project_with_types, name: "Aunt", parent: project) } +RSpec.describe 'subject inplace editor', :js, :selenium do + let(:project) { create(:project_with_types, name: 'Root', public: true) } + let(:subproject1) { create(:project_with_types, name: 'Child', parent: project) } + let(:subproject2) { create(:project_with_types, name: 'Aunt', parent: project) } let!(:version) do create(:version, - name: "1. First version", - status: "open", - sharing: "tree", - start_date: "2019-02-02", - effective_date: "2019-02-03", + name: '1. First version', + status: 'open', + sharing: 'tree', + start_date: '2019-02-02', + effective_date: '2019-02-03', project:) end let!(:version2) do create(:version, - status: "open", - sharing: "tree", - name: "2. Second version", - start_date: "2020-02-02", - effective_date: "2020-02-03", + status: 'open', + sharing: 'tree', + name: '2. Second version', + start_date: '2020-02-02', + effective_date: '2020-02-03', project: subproject1) end let!(:version3) do create(:version, - status: "open", - sharing: "tree", + status: 'open', + sharing: 'tree', start_date: nil, effective_date: nil, - name: "3. Third version", + name: '3. Third version', project: subproject2) end @@ -50,60 +50,60 @@ let(:permissions) { %i[view_work_packages edit_work_packages assign_versions] } let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } - context "with manage permissions" do + context 'with manage permissions' do before do login_as(user) end - it "renders hierarchical versions" do + it 'renders hierarchical versions' do work_package_page.visit! work_package_page.ensure_page_loaded field = work_package_page.work_package_field(:version) field.activate! - expect(page).to have_css(".ng-option-label", text: "-") - expect(page).to have_css(".ng-option-label", text: version3.name) - expect(page).to have_css(".ng-option-label", text: version2.name) - expect(page).to have_css(".ng-option-label", text: version.name) + expect(page).to have_css('.ng-option-label', text: '-') + expect(page).to have_css('.ng-option-label', text: version3.name) + expect(page).to have_css('.ng-option-label', text: version2.name) + expect(page).to have_css('.ng-option-label', text: version.name) # Expect the order to be descending by version date - labels = page.all(".ng-option-label").map { |el| el.text.strip } - expect(labels).to eq ["-", version.name, version2.name, version3.name] + labels = page.all('.ng-option-label').map { |el| el.text.strip } + expect(labels).to eq ['-', version.name, version2.name, version3.name] - page.find(".ng-option-label", text: version3.name).select_option + page.find('.ng-option-label', text: version3.name).select_option field.expect_state_text(version3.name) end - it "allows creating versions from within the WP view" do + it 'allows creating versions from within the WP view' do work_package_page.visit! work_package_page.ensure_page_loaded field = work_package_page.work_package_field(:version) field.activate! - field.set_new_value "Super cool new release" - field.expect_state_text "Super cool new release" + field.set_new_value 'Super cool new release' + field.expect_state_text 'Super cool new release' visit project_settings_versions_path(project) - expect(page).to have_content "Super cool new release" + expect(page).to have_content 'Super cool new release' end end - context "without the permission to manage versions" do + context 'without the permission to manage versions' do before do login_as(second_user) end - it "does not allow creating versions from within the WP view" do + it 'does not allow creating versions from within the WP view' do work_package_page.visit! work_package_page.ensure_page_loaded field = work_package_page.work_package_field(:version) field.activate! - field.input_element.find("input").set "Version that does not exist" - expect(page).to have_no_css(".ng-option", text: "Create: Version that does not exist") + field.input_element.find('input').set 'Version that does not exist' + expect(page).to have_no_css('.ng-option', text: 'Create: Version that does not exist') end end end diff --git a/spec/features/work_packages/details/markdown/activity_comments_spec.rb b/spec/features/work_packages/details/markdown/activity_comments_spec.rb index 06ba11d9d6ec..64a72b3c82ab 100644 --- a/spec/features/work_packages/details/markdown/activity_comments_spec.rb +++ b/spec/features/work_packages/details/markdown/activity_comments_spec.rb @@ -1,9 +1,9 @@ -require "spec_helper" +require 'spec_helper' -require "features/work_packages/shared_contexts" -require "features/work_packages/details/inplace_editor/shared_examples" +require 'features/work_packages/shared_contexts' +require 'features/work_packages/details/inplace_editor/shared_examples' -RSpec.describe "activity comments", :js do +RSpec.describe 'activity comments', :js do let(:project) { create(:project, public: true) } let!(:work_package) do create(:work_package, @@ -11,20 +11,20 @@ journal_notes: initial_comment) end let(:wp_page) { Pages::SplitWorkPackage.new(work_package, project) } - let(:selector) { ".work-packages--activity--add-comment" } + let(:selector) { '.work-packages--activity--add-comment' } let(:comment_field) do TextEditorField.new wp_page, - "comment", + 'comment', selector: end - let(:initial_comment) { "the first comment in this WP" } + let(:initial_comment) { 'the first comment in this WP' } before do login_as(current_user) allow(current_user.pref).to receive(:warn_on_leaving_unsaved?).and_return(false) end - context "with permission" do + context 'with permission' do let(:current_user) { create(:admin) } before do @@ -32,169 +32,169 @@ wp_page.ensure_page_loaded end - context "in edit state" do + context 'in edit state' do before do comment_field.activate! end - describe "submitting comment" do - it "does not submit with enter" do - comment_field.click_and_type_slowly "this is a comment" + describe 'submitting comment' do + it 'does not submit with enter' do + comment_field.click_and_type_slowly 'this is a comment' comment_field.submit_by_enter - expect(page).to have_no_css(".user-comment .message", text: "this is a comment") + expect(page).to have_no_css('.user-comment .message', text: 'this is a comment') end - it "submits with click" do - comment_field.click_and_type_slowly "this is a comment!1" + it 'submits with click' do + comment_field.click_and_type_slowly 'this is a comment!1' comment_field.submit_by_click - wp_page.expect_comment text: "this is a comment!1" + wp_page.expect_comment text: 'this is a comment!1' end - it "submits comments repeatedly" do - comment_field.click_and_type_slowly "this is my first comment!1" + it 'submits comments repeatedly' do + comment_field.click_and_type_slowly 'this is my first comment!1' comment_field.submit_by_click - expect(page).to have_css(".user-comment > .message", count: 2) - wp_page.expect_comment text: "this is my first comment!1" + expect(page).to have_css('.user-comment > .message', count: 2) + wp_page.expect_comment text: 'this is my first comment!1' expect(comment_field.editing?).to be false comment_field.activate! expect(comment_field.editing?).to be true - comment_field.click_and_type_slowly "this is my second comment!1" + comment_field.click_and_type_slowly 'this is my second comment!1' comment_field.submit_by_click - expect(page).to have_css(".user-comment > .message", count: 3) - wp_page.expect_comment text: "this is my second comment!1" + expect(page).to have_css('.user-comment > .message', count: 3) + wp_page.expect_comment text: 'this is my second comment!1' expect(comment_field.editing?).to be false comment_field.activate! expect(comment_field.editing?).to be true - comment_field.click_and_type_slowly "this is my third comment!1" + comment_field.click_and_type_slowly 'this is my third comment!1' comment_field.submit_by_click # Only shows three most recent - expect(page).to have_css(".user-comment > .message", count: 3) - wp_page.expect_comment text: "this is my third comment!1" + expect(page).to have_css('.user-comment > .message', count: 3) + wp_page.expect_comment text: 'this is my third comment!1' - wp_page.switch_to_tab tab: "Activity" + wp_page.switch_to_tab tab: 'Activity' # Now showing all comments - expect(page).to have_css(".user-comment > .message", count: 4, wait: 10) + expect(page).to have_css('.user-comment > .message', count: 4, wait: 10) expect(comment_field.editing?).to be false comment_field.activate! expect(comment_field.editing?).to be true - comment_field.click_and_type_slowly "this is my fifth comment!1" + comment_field.click_and_type_slowly 'this is my fifth comment!1' comment_field.submit_by_click - expect(page).to have_css(".user-comment > .message", count: 4) - wp_page.expect_comment text: "this is my fifth comment!1" + expect(page).to have_css('.user-comment > .message', count: 4) + wp_page.expect_comment text: 'this is my fifth comment!1' # Expect no activity details - expect(page).to have_no_css(".work-package-details-activities-messages li") + expect(page).to have_no_css('.work-package-details-activities-messages li') end end - describe "cancel comment" do + describe 'cancel comment' do it do expect(comment_field.editing?).to be true - comment_field.input_element.set "this is a comment" + comment_field.input_element.set 'this is a comment' # Escape should NOT cancel the editing comment_field.cancel_by_escape expect(comment_field.editing?).to be true - expect(page).to have_no_css(".user-comment .message", text: "this is a comment") + expect(page).to have_no_css('.user-comment .message', text: 'this is a comment') # Click should cancel the editing comment_field.cancel_by_click expect(comment_field.editing?).to be false - expect(page).to have_no_css(".user-comment .message", text: "this is a comment") + expect(page).to have_no_css('.user-comment .message', text: 'this is a comment') end end - describe "autocomplete" do - describe "work packages" do - let!(:wp2) { create(:work_package, project:, subject: "AutoFoo") } + describe 'autocomplete' do + describe 'work packages' do + let!(:wp2) { create(:work_package, project:, subject: 'AutoFoo') } - it "can move to the work package by click (Regression #30928)" do + it 'can move to the work package by click (Regression #30928)' do comment_field.input_element.send_keys("##{wp2.id}") - expect(page).to have_css(".mention-list-item", text: wp2.to_s.strip) + expect(page).to have_css('.mention-list-item', text: wp2.to_s.strip) comment_field.submit_by_click - page.find("#activity-2 a.issue", text: wp2.id).click + page.find('#activity-2 a.issue', text: wp2.id).click other_wp_page = Pages::FullWorkPackage.new wp2 other_wp_page.ensure_page_loaded - other_wp_page.edit_field(:subject).expect_text "AutoFoo" + other_wp_page.edit_field(:subject).expect_text 'AutoFoo' end end - describe "users" do - it_behaves_like "a principal autocomplete field" do + describe 'users' do + it_behaves_like 'a principal autocomplete field' do let(:field) { comment_field } end end end - describe "with an existing comment" do - it "allows to edit an existing comment" do + describe 'with an existing comment' do + it 'allows to edit an existing comment' do # Insert new text, need to do this separately.'' - ["Comment with", " ", "*", "*", "bold text", "*", "*", " ", "in it"].each do |key| + ['Comment with', ' ', '*', '*', 'bold text', '*', '*', ' ', 'in it'].each do |key| comment_field.input_element.send_keys key end comment_field.submit_by_click - wp_page.expect_comment text: "Comment with bold text in it" - wp_page.expect_comment text: "bold text", subselector: "strong" + wp_page.expect_comment text: 'Comment with bold text in it' + wp_page.expect_comment text: 'bold text', subselector: 'strong' # Hover the new activity - activity = page.find_by_id("activity-2") + activity = page.find_by_id('activity-2') page.driver.browser.action.move_to(activity.native).perform # Check the edit textarea - edit_button = activity.find(".icon-edit") + edit_button = activity.find('.icon-edit') scroll_to_element(edit_button) edit_button.click edit = TextEditorField.new wp_page, - "comment", - selector: ".user-comment--form" + 'comment', + selector: '.user-comment--form' # Insert new text, need to do this separately. edit.input_element.click - [:enter, "Comment with", " ", "_", "italic text", "_", " ", "in it"].each do |key| + [:enter, 'Comment with', ' ', '_', 'italic text', '_', ' ', 'in it'].each do |key| edit.input_element.send_keys key end edit.submit_by_click - wp_page.expect_comment text: "Comment with italic text in it" - wp_page.expect_comment text: "italic text", subselector: "em" + wp_page.expect_comment text: 'Comment with italic text in it' + wp_page.expect_comment text: 'italic text', subselector: 'em' end end end - describe "quoting" do - it "can quote a previous comment" do - expect(page).to have_css(".user-comment .message", + describe 'quoting' do + it 'can quote a previous comment' do + expect(page).to have_css('.user-comment .message', text: initial_comment) # Hover comment - quoted = page.find(".user-comment > .message") + quoted = page.find('.user-comment > .message') scroll_to_element(quoted) quoted.hover # Quote this comment - page.find(".comments-icons .icon-quote").click + page.find('.comments-icons .icon-quote').click expect(comment_field.editing?).to be true # Add our comment - expect(comment_field.input_element).to have_css("blockquote") + expect(comment_field.input_element).to have_css('blockquote') quote = comment_field.input_element[:innerHTML] expect(quote).to eq '

    Anonymous wrote:

    the first comment in this WP

    ' @@ -204,32 +204,32 @@ comment_field.ckeditor.click_and_type_slowly :enter # Insert new text, need to do this separately. - comment_field.ckeditor.click_and_type_slowly :return, "this is ", "*", "*", "a bold", "*", "*", " remark" + comment_field.ckeditor.click_and_type_slowly :return, 'this is ', '*', '*', 'a bold', '*', '*', ' remark' comment_field.submit_by_click # Scroll to the activity - scroll_to_element(page.find_by_id("activity-2")) + scroll_to_element(page.find_by_id('activity-2')) - wp_page.expect_comment text: "this is a bold remark" + wp_page.expect_comment text: 'this is a bold remark' wp_page.expect_comment count: 2 - wp_page.expect_comment subselector: "blockquote" - wp_page.expect_comment subselector: "strong", text: "a bold" + wp_page.expect_comment subselector: 'blockquote' + wp_page.expect_comment subselector: 'strong', text: 'a bold' end end - describe "referencing another work package" do + describe 'referencing another work package' do let!(:work_package2) { create(:work_package, project:, type: create(:type)) } - it "can reference another work package with all methods" do + it 'can reference another work package with all methods' do comment_field.activate! # Insert a new reference using the autocompleter comment_field.input_element.send_keys "Single ##{work_package2.id}" expect(page) - .to have_css(".mention-list-item", text: "#{work_package2.type.name} ##{work_package2.id}:") + .to have_css('.mention-list-item', text: "#{work_package2.type.name} ##{work_package2.id}:") - find(".mention-list-item", text: "#{work_package2.type.name} ##{work_package2.id}:").click + find('.mention-list-item', text: "#{work_package2.type.name} ##{work_package2.id}:").click # Insert new text, need to do this separately. # No autocompleter used this time. @@ -246,17 +246,17 @@ comment_field.submit_by_click wp_page.expect_comment text: "Single ##{work_package2.id}" - expect(page).to have_css(".user-comment opce-macro-wp-quickinfo", count: 2) - expect(page).to have_css(".user-comment .work-package--quickinfo.preview-trigger", count: 2) + expect(page).to have_css('.user-comment opce-macro-wp-quickinfo', count: 2) + expect(page).to have_css('.user-comment .work-package--quickinfo.preview-trigger', count: 2) end end - it "can move away to another tab, keeping the draft comment" do + it 'can move away to another tab, keeping the draft comment' do comment_field.activate! comment_field.input_element.send_keys "I'm typing an important message here ..." wp_page.switch_to_tab tab: :files - expect(page).to have_test_selector("op-tab-content--tab-section") + expect(page).to have_test_selector('op-tab-content--tab-section') wp_page.switch_to_tab tab: :activity @@ -273,7 +273,7 @@ # Has removed the draft now wp_page.switch_to_tab tab: :files - expect(page).to have_test_selector("op-tab-content--tab-section") + expect(page).to have_test_selector('op-tab-content--tab-section') wp_page.switch_to_tab tab: :activity comment_field.expect_inactive! @@ -283,7 +283,7 @@ end end - context "with no permission" do + context 'with no permission' do let(:role) { create(:project_role, permissions: %i(view_work_packages)) } let(:current_user) { create(:user, member_with_roles: { project => role }) } @@ -292,7 +292,7 @@ wp_page.ensure_page_loaded end - it "does not show the field" do + it 'does not show the field' do expect(page).to have_no_selector(selector, visible: true) end end diff --git a/spec/features/work_packages/details/markdown/description_editor_spec.rb b/spec/features/work_packages/details/markdown/description_editor_spec.rb index 087ad71411c6..b05ba27261ad 100644 --- a/spec/features/work_packages/details/markdown/description_editor_spec.rb +++ b/spec/features/work_packages/details/markdown/description_editor_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' -RSpec.describe "description inplace editor", :js, :selenium do +RSpec.describe 'description inplace editor', :js, :selenium do let(:project) { create(:project_with_types, public: true) } let(:property_name) { :description } - let(:property_title) { "Description" } - let(:description_text) { "Ima description" } + let(:property_title) { 'Description' } + let(:description_text) { 'Ima description' } let!(:work_package) do create( :work_package, @@ -45,7 +45,7 @@ ) end let(:user) { create(:admin) } - let(:field) { TextEditorField.new wp_page, "description" } + let(:field) { TextEditorField.new wp_page, 'description' } let(:wp_page) { Pages::SplitWorkPackage.new(work_package, project) } before do @@ -55,8 +55,8 @@ wp_page.ensure_page_loaded end - context "with permission" do - it "allows editing description field" do + context 'with permission' do + it 'allows editing description field' do field.expect_state_text(description_text) # Regression test #24033 @@ -90,49 +90,49 @@ field.set_value "Edit to be saved by keyboard" field.submit_by_enter - wp_page.expect_toast message: I18n.t("js.notice_successful_update") - field.expect_state_text "Edit to be saved by keyboard" + wp_page.expect_toast message: I18n.t('js.notice_successful_update') + field.expect_state_text 'Edit to be saved by keyboard' end end - context "when is empty" do - let(:description_text) { "" } + context 'when is empty' do + let(:description_text) { '' } - it "renders a placeholder" do - field.expect_state_text "Description: Click to edit..." + it 'renders a placeholder' do + field.expect_state_text 'Description: Click to edit...' field.activate! # An empty description is also allowed field.expect_save_button(enabled: true) - field.set_value "A new hope ..." + field.set_value 'A new hope ...' field.expect_save_button(enabled: true) field.submit_by_click - wp_page.expect_toast message: I18n.t("js.notice_successful_update") - field.expect_state_text "A new hope ..." + wp_page.expect_toast message: I18n.t('js.notice_successful_update') + field.expect_state_text 'A new hope ...' end end - context "with no permission" do + context 'with no permission' do let(:role) { create(:project_role, permissions: %i(view_work_packages)) } let(:user) { create(:user, member_with_roles: { project => role }) } - it "does not show the field" do - expect(page).to have_no_css(".inline-edit--display-field.description.-editable") + it 'does not show the field' do + expect(page).to have_no_css('.inline-edit--display-field.description.-editable') field.display_element.click field.expect_inactive! end - context "when is empty" do - let(:description_text) { "" } + context 'when is empty' do + let(:description_text) { '' } - it "renders a placeholder" do - field.expect_state_text "" + it 'renders a placeholder' do + field.expect_state_text '' end end end - it_behaves_like "a workpackage autocomplete field" - it_behaves_like "a principal autocomplete field" + it_behaves_like 'a workpackage autocomplete field' + it_behaves_like 'a principal autocomplete field' end diff --git a/spec/features/work_packages/details/markdown/todolist_spec.rb b/spec/features/work_packages/details/markdown/todolist_spec.rb index c78914665e16..47831b8436c4 100644 --- a/spec/features/work_packages/details/markdown/todolist_spec.rb +++ b/spec/features/work_packages/details/markdown/todolist_spec.rb @@ -68,11 +68,11 @@ # Select first and first nested item ckeditor.in_editor do |_container, editable| - first_item = editable.all('.todo-list li')[0] + first_item = editable.all('.op-uc-list li')[0] first_item.find('input[type=checkbox]', visible: :all).set true # First nested - first_nested_item = editable.all('.todo-list .todo-list li')[0] + first_nested_item = editable.all('.op-uc-list .op-uc-list li')[0] first_nested_item.find('input[type=checkbox]', visible: :all).set true sleep 0.5 @@ -165,7 +165,7 @@ # Update the link text, no idea how to do this differently ckeditor.in_editor do |_container, editable| - link = editable.find('.todo-list .todo-list a') + link = editable.find('.op-uc-list .op-uc-list a') link.set('This is a link') sleep 0.5 @@ -173,7 +173,7 @@ # Select nested item ckeditor.in_editor do |_container, editable| - editable.find('.todo-list .todo-list input[type=checkbox]', visible: :all).set true + editable.find('.op-uc-list .op-uc-list input[type=checkbox]', visible: :all).set true sleep 0.5 end @@ -206,7 +206,7 @@ # Select first item ckeditor.in_editor do |_container, editable| - first_item = editable.all('.todo-list li')[0] + first_item = editable.all('.op-uc-list li')[0] first_item.find('input[type=checkbox]', visible: :all).set true sleep 0.5 @@ -229,13 +229,13 @@ # Expect still the same when editing again field.activate! ckeditor.in_editor do |_container, editable| - expect(editable).to have_css('.todo-list li', count: 2) + expect(editable).to have_css('.op-uc-list li', count: 2) - first_item = editable.all('.todo-list li')[0].find('input[type=checkbox]', visible: :all) + first_item = editable.all('.op-uc-list li')[0].find('input[type=checkbox]', visible: :all) expect(first_item).to be_checked # Check last item - last_item = editable.all('.todo-list li').last + last_item = editable.all('.op-uc-list li').last last_item.find('input[type=checkbox]', visible: :all).set true sleep 0.5 diff --git a/spec/features/work_packages/details/milestones_spec.rb b/spec/features/work_packages/details/milestones_spec.rb index c50de5a0a4ea..4439aa6cd57e 100644 --- a/spec/features/work_packages/details/milestones_spec.rb +++ b/spec/features/work_packages/details/milestones_spec.rb @@ -1,24 +1,24 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Milestones full screen v iew", :js do +RSpec.describe 'Milestones full screen v iew', :js do let(:type) { create(:type, is_milestone: true) } let(:project) { create(:project, types: [type]) } let!(:work_package) do create(:work_package, project:, type:, - subject: "Foobar") + subject: 'Foobar') end let(:wp_page) { Pages::FullWorkPackage.new(work_package, project) } - let(:button) { find(".add-work-package", wait: 5) } + let(:button) { find('.add-work-package', wait: 5) } before do login_as(user) wp_page.visit! end - context "user has :add_work_packages permission" do + context 'user has :add_work_packages permission' do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -27,15 +27,15 @@ %i[view_work_packages add_work_packages] end - it "shows the button as enabled" do + it 'shows the button as enabled' do expect(button).not_to be_disabled button.click - expect(page).to have_css(".menu-item", text: type.name.upcase) + expect(page).to have_css('.menu-item', text: type.name.upcase) end end - context "user has :view_work_packages permission only" do + context 'user has :view_work_packages permission only' do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -44,8 +44,8 @@ %i[view_work_packages] end - it "shows the button as correctly disabled" do - expect(button["disabled"]).to be_truthy + it 'shows the button as correctly disabled' do + expect(button['disabled']).to be_truthy end end end diff --git a/spec/features/work_packages/details/query_groups/relation_query_group_spec.rb b/spec/features/work_packages/details/query_groups/relation_query_group_spec.rb index b41c7c052f28..92d4ec3046ed 100644 --- a/spec/features/work_packages/details/query_groups/relation_query_group_spec.rb +++ b/spec/features/work_packages/details/query_groups/relation_query_group_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package with relation query group", :js, :selenium do - include_context "ng-select-autocomplete helpers" +RSpec.describe 'Work package with relation query group', :js, :selenium do + include_context 'ng-select-autocomplete helpers' let(:user) { create(:admin) } let(:project) { create(:project, types: [type]) } @@ -60,8 +60,8 @@ let(:full_wp) { Pages::FullWorkPackage.new(work_package) } let(:relations) { Components::WorkPackages::Relations.new(work_package) } let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } - let(:relations_tab) { find(".op-tab-row--link", text: "RELATIONS") } - let(:embedded_table) { Pages::EmbeddedWorkPackagesTable.new(first("wp-single-view .work-packages-embedded-view--container")) } + let(:relations_tab) { find('.op-tab-row--link', text: 'RELATIONS') } + let(:embedded_table) { Pages::EmbeddedWorkPackagesTable.new(first('wp-single-view .work-packages-embedded-view--container')) } let(:visit) { true } @@ -80,14 +80,14 @@ end end - context "children table" do - it "creates and removes across all tables" do + context 'children table' do + it 'creates and removes across all tables' do embedded_table.expect_work_package_count 1 relations_tab.click relations.expect_child(related_work_package) # Create new work package within embedded table - embedded_table.table_container.find("button", text: I18n.t("js.relation_buttons.add_new_child")).click + embedded_table.table_container.find("button", text: I18n.t('js.relation_buttons.add_new_child')).click subject_field = embedded_table.edit_field(nil, :subject) subject_field.expect_active! subject_field.set_value("Fresh WP\n") @@ -107,7 +107,7 @@ end end - describe "follower table with project filters" do + describe 'follower table with project filters' do let(:visit) { false } let!(:project2) { create(:project, types: [type]) } let!(:project3) { create(:project, types: [type]) } @@ -123,17 +123,17 @@ let(:type) do create(:type_with_relation_query_group, relation_filter: relation_type) end - let(:query_text) { "Embedded Table for follows".upcase } + let(:query_text) { 'Embedded Table for follows'.upcase } before do query = type.attribute_groups.last.query - query.add_filter("project_id", "=", [project2.id, project3.id]) + query.add_filter('project_id', '=', [project2.id, project3.id]) # User has no permission to save, avoid creating another user to allow it query.save!(validate: false) type.save! end - context "with a user who has permission in one project" do + context 'with a user who has permission in one project' do let(:role) { create(:project_role, permissions:) } let(:permissions) { %i[view_work_packages add_work_packages edit_work_packages manage_work_package_relations] } let(:user) do @@ -146,24 +146,24 @@ member.save! end - it "can load the query and inline create" do + it 'can load the query and inline create' do full_wp.visit! full_wp.ensure_page_loaded - expect(page).to have_css(".attributes-group--header-text", text: query_text, wait: 20) + expect(page).to have_css('.attributes-group--header-text', text: query_text, wait: 20) embedded_table.expect_work_package_listed related_work_package embedded_table.click_inline_create subject_field = embedded_table.edit_field(nil, :subject) subject_field.expect_active! - subject_field.set_value "Another subject" + subject_field.set_value 'Another subject' subject_field.save! - embedded_table.expect_work_package_subject "Another subject" + embedded_table.expect_work_package_subject 'Another subject' end end - context "with a user who has no permission in any project" do + context 'with a user who has no permission in any project' do let(:role) { create(:project_role, permissions:) } let(:permissions) { [:view_work_packages] } let(:user) do @@ -171,18 +171,18 @@ member_with_roles: { project => role }) end - it "hides that group automatically without showing an error" do + it 'hides that group automatically without showing an error' do full_wp.visit! full_wp.ensure_page_loaded # Will first try to load the query, and then hide it. - expect(page).to have_no_css(".attributes-group--header-text", text: query_text, wait: 20) - expect(page).to have_no_css(".work-packages-embedded-view--container .op-toast.-error") + expect(page).to have_no_css('.attributes-group--header-text', text: query_text, wait: 20) + expect(page).to have_no_css('.work-packages-embedded-view--container .op-toast.-error') end end end - context "follower table" do + context 'follower table' do let(:relation_type) { :follows } let(:relation_target) { work_package } let!(:independent_work_package) do @@ -196,23 +196,23 @@ relations.expect_relation(related_work_package) end - it "creates and removes across all tables" do - embedded_table.table_container.find("button", text: I18n.t("js.relation_buttons.create_new")).click + it 'creates and removes across all tables' do + embedded_table.table_container.find('button', text: I18n.t('js.relation_buttons.create_new')).click subject_field = embedded_table.edit_field(nil, :subject) subject_field.expect_active! subject_field.set_value("Fresh WP\n") - expect(embedded_table.table_container).to have_text("Fresh WP", wait: 10) - relations.expect_relation_by_text("Fresh WP") + expect(embedded_table.table_container).to have_text('Fresh WP', wait: 10) + relations.expect_relation_by_text('Fresh WP') end - it "add existing, remove it, add it from relations tab, remove from relations tab" do - embedded_table.table_container.find("button", text: I18n.t("js.relation_buttons.add_existing")).click - embedded_table.table_container.find(".wp-relations-create--form", wait: 10) + it 'add existing, remove it, add it from relations tab, remove from relations tab' do + embedded_table.table_container.find('button', text: I18n.t('js.relation_buttons.add_existing')).click + embedded_table.table_container.find('.wp-relations-create--form', wait: 10) autocomplete = page.find_test_selector("wp-relations-autocomplete") select_autocomplete autocomplete, - results_selector: ".ng-dropdown-panel-items", + results_selector: '.ng-dropdown-panel-items', query: independent_work_package.subject, select_text: independent_work_package.subject @@ -239,9 +239,9 @@ # Check that deletion of relations still work after a page reload full_wp.visit! - relations_tab = find(".op-tab-row--link", text: "RELATIONS") + relations_tab = find('.op-tab-row--link', text: 'RELATIONS') relations = Components::WorkPackages::Relations.new(work_package) - embedded_table = Pages::EmbeddedWorkPackagesTable.new(first("wp-single-view .work-packages-embedded-view--container")) + embedded_table = Pages::EmbeddedWorkPackagesTable.new(first('wp-single-view .work-packages-embedded-view--container')) embedded_table.table_container.find(".wp-row-#{independent_work_package.id}-table").hover embedded_table.table_container.find("#{row} .wp-table-action--unlink").click diff --git a/spec/features/work_packages/details/relations/hierarchy_custom_fields_spec.rb b/spec/features/work_packages/details/relations/hierarchy_custom_fields_spec.rb index 025152922fa7..cae9d3d05c8d 100644 --- a/spec/features/work_packages/details/relations/hierarchy_custom_fields_spec.rb +++ b/spec/features/work_packages/details/relations/hierarchy_custom_fields_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "creating a child directly after the wp itself was created", :js do +RSpec.describe 'creating a child directly after the wp itself was created', :js do let(:user) { create(:admin) } let(:project) { create(:project, types: [type]) } let(:wp_page) { Pages::FullWorkPackageCreate.new } @@ -38,10 +38,10 @@ let(:type) { create(:type, custom_fields: [custom_field]) } let(:custom_field) do create(:work_package_custom_field, - field_format: "int", + field_format: 'int', is_for_all: true) end - let(:relations_tab) { find(".op-tab-row--link", text: "RELATIONS") } + let(:relations_tab) { find('.op-tab-row--link', text: 'RELATIONS') } before do login_as user @@ -50,28 +50,28 @@ loading_indicator_saveguard end - it "keeps its custom field values (regression #29511, #29446)" do + it 'keeps its custom field values (regression #29511, #29446)' do # Set subject subject = wp_page.edit_field :subject - subject.set_value "My subject" + subject.set_value 'My subject' # Set CF cf = wp_page.edit_field custom_field.attribute_name(:camel_case) - cf.set_value "42" + cf.set_value '42' # Save WP wp_page.save! - wp_page.expect_and_dismiss_toaster(message: "Successful creation.") + wp_page.expect_and_dismiss_toaster(message: 'Successful creation.') # Add child scroll_to_and_click relations_tab - find_test_selector("op-wp-inline-create").click - fill_in "wp-new-inline-edit--field-subject", with: "A child WP" - find_by_id("wp-new-inline-edit--field-subject").native.send_keys(:return) + find_test_selector('op-wp-inline-create').click + fill_in 'wp-new-inline-edit--field-subject', with: 'A child WP' + find_by_id('wp-new-inline-edit--field-subject').native.send_keys(:return) # Expect CF value to be still visible - wp_page.expect_and_dismiss_toaster(message: "Successful creation.") - expect(wp_page).to have_test_selector("tab-count", text: "(1)") - wp_page.expect_attributes "customField#{custom_field.id}": "42" + wp_page.expect_and_dismiss_toaster(message: 'Successful creation.') + expect(wp_page).to have_test_selector('tab-count', text: "(1)") + wp_page.expect_attributes "customField#{custom_field.id}": '42' end end diff --git a/spec/features/work_packages/details/relations/hierarchy_milestone_spec.rb b/spec/features/work_packages/details/relations/hierarchy_milestone_spec.rb index 952c7c371ec9..325771c868b5 100644 --- a/spec/features/work_packages/details/relations/hierarchy_milestone_spec.rb +++ b/spec/features/work_packages/details/relations/hierarchy_milestone_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "work package hierarchies for milestones", :js, :selenium do +RSpec.describe 'work package hierarchies for milestones', :js, :selenium do let(:user) { create(:admin) } let(:type) { create(:type, is_milestone: true) } let(:project) { create(:project, types: [type]) } @@ -37,22 +37,22 @@ let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } let(:wp_page) { Pages::FullWorkPackage.new(work_package) } - let(:relations_tab) { find(".op-tab-row--link_selected", text: "RELATIONS") } + let(:relations_tab) { find('.op-tab-row--link_selected', text: 'RELATIONS') } let(:visit) { true } before do login_as user - wp_page.visit_tab!("relations") + wp_page.visit_tab!('relations') expect_angular_frontend_initialized wp_page.expect_subject loading_indicator_saveguard end - it "does not provide links to add children or existing children (Regression #28745)" do - within(".wp-relations--children") do - expect(page).to have_no_text("Add existing child") - expect(page).to have_no_text("Create new child") - expect(page).to have_no_css("wp-inline-create--add-link") + it 'does not provide links to add children or existing children (Regression #28745)' do + within('.wp-relations--children') do + expect(page).to have_no_text('Add existing child') + expect(page).to have_no_text('Create new child') + expect(page).to have_no_css('wp-inline-create--add-link') end end end diff --git a/spec/features/work_packages/details/relations/hierarchy_spec.rb b/spec/features/work_packages/details/relations/hierarchy_spec.rb index d22a198d1875..b4f0ccf80405 100644 --- a/spec/features/work_packages/details/relations/hierarchy_spec.rb +++ b/spec/features/work_packages/details/relations/hierarchy_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "work package relations tab", :js, :selenium do - include_context "ng-select-autocomplete helpers" +RSpec.shared_examples 'work package relations tab', :js, :selenium do + include_context 'ng-select-autocomplete helpers' let(:user) { create(:admin) } @@ -38,7 +38,7 @@ let(:relations) { Components::WorkPackages::Relations.new(work_package) } let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } - let(:relations_tab) { find(".op-tab-row--link_selected", text: "RELATIONS") } + let(:relations_tab) { find('.op-tab-row--link_selected', text: 'RELATIONS') } let(:visit) { true } @@ -51,18 +51,18 @@ end def visit_relations - wp_page.visit_tab!("relations") + wp_page.visit_tab!('relations') expect_angular_frontend_initialized wp_page.expect_subject loading_indicator_saveguard end - describe "as admin" do - let!(:parent) { create(:work_package, project:, subject: "Parent WP") } - let!(:child) { create(:work_package, project:, subject: "Child WP") } - let!(:child2) { create(:work_package, project:, subject: "Another child WP") } + describe 'as admin' do + let!(:parent) { create(:work_package, project:, subject: 'Parent WP') } + let!(:child) { create(:work_package, project:, subject: 'Child WP') } + let!(:child2) { create(:work_package, project:, subject: 'Another child WP') } - it "allows to manage hierarchy" do + it 'allows to manage hierarchy' do # Add parent relations.add_parent(parent.id, parent) relations.expect_parent(parent) @@ -85,11 +85,11 @@ def visit_relations tabs.expect_counter(relations_tab, 2) end - context "when switching to custom field with required CF" do + context 'when switching to custom field with required CF' do let(:custom_field) do create( :work_package_custom_field, - field_format: "string", + field_format: 'string', default_value: nil, is_required: true, is_for_all: true @@ -106,36 +106,36 @@ def visit_relations custom_field end - it "shows the required field when switching" do - relations.inline_create_child "my new child" + it 'shows the required field when switching' do + relations.inline_create_child 'my new child' table = relations.children_table - table.expect_work_package_subject "my new child" - wp = WorkPackage.find_by!(subject: "my new child") + table.expect_work_package_subject 'my new child' + wp = WorkPackage.find_by!(subject: 'my new child') type_field = table.edit_field(wp, :type) type_field.activate! type_field.set_value type2.name wp_page.expect_toast message: "#{custom_field.name} can't be blank.", - type: "error" + type: 'error' cf_field = wp_page.edit_field(custom_field.attribute_name(:camel_case)) cf_field.expect_active! - cf_field.expect_value("") + cf_field.expect_value('') - cf_field.set_value "my value" + cf_field.set_value 'my value' cf_field.save! wp_page.expect_toast message: "Successful update.", - type: "success" + type: 'success' wp.reload - expect(wp.custom_value_for(custom_field).value).to eq "my value" + expect(wp.custom_value_for(custom_field).value).to eq 'my value' end end - describe "inline create" do + describe 'inline create' do let!(:status) { create(:status, is_default: true) } let!(:priority) { create(:priority, is_default: true) } let(:type_bug) { create(:type_bug) } @@ -143,11 +143,11 @@ def visit_relations create(:project, types: [type_bug]) end - it "can inline-create children" do - relations.inline_create_child "my new child" + it 'can inline-create children' do + relations.inline_create_child 'my new child' table = relations.children_table - table.expect_work_package_subject "my new child" + table.expect_work_package_subject 'my new child' work_package.reload expect(work_package.children.count).to eq(1) @@ -157,7 +157,7 @@ def visit_relations end end - describe "relation group-by toggler" do + describe 'relation group-by toggler' do let(:project) { create(:project, types: [type1, type2]) } let(:type1) { create(:type) } let(:type2) { create(:type) } @@ -178,18 +178,18 @@ def visit_relations relation_type: Relation::TYPE_RELATES) end - let(:toggle_btn_selector) { "#wp-relation-group-by-toggle" } + let(:toggle_btn_selector) { '#wp-relation-group-by-toggle' } let(:visit) { false } before do visit_relations - wp_page.visit_tab!("relations") + wp_page.visit_tab!('relations') wp_page.expect_subject loading_indicator_saveguard end - describe "with limited permissions" do + describe 'with limited permissions' do let(:permissions) { %i(view_work_packages) } let(:user_role) do create(:project_role, permissions:) @@ -200,41 +200,41 @@ def visit_relations member_with_roles: { project => user_role }) end - context "as view-only user, with parent set" do - let!(:parent) { create(:work_package, project:, subject: "Parent WP") } - let!(:work_package) { create(:work_package, parent:, project:, subject: "Child WP") } + context 'as view-only user, with parent set' do + let!(:parent) { create(:work_package, project:, subject: 'Parent WP') } + let!(:work_package) { create(:work_package, parent:, project:, subject: 'Child WP') } - it "shows no links to create relations" do + it 'shows no links to create relations' do # No create buttons should exist - expect(page).to have_no_css(".wp-relations-create-button") + expect(page).to have_no_css('.wp-relations-create-button') # Test for add relation - expect(page).to have_no_css("#relation--add-relation") + expect(page).to have_no_css('#relation--add-relation') # Test for add parent - expect(page).to have_no_css(".wp-relation--parent-change") + expect(page).to have_no_css('.wp-relation--parent-change') # Test for add children - expect(page).to have_no_css("#hierarchy--add-existing-child") - expect(page).to have_no_css("#hierarchy--add-new-child") + expect(page).to have_no_css('#hierarchy--add-existing-child') + expect(page).to have_no_css('#hierarchy--add-new-child') # But it should show the linked parent - expect(page).to have_test_selector("op-wp-breadcrumb-parent", text: parent.subject) + expect(page).to have_test_selector('op-wp-breadcrumb-parent', text: parent.subject) # And it should count the two relations tabs.expect_counter(relations_tab, 2) end end - context "with manage_subtasks permissions" do + context 'with manage_subtasks permissions' do let(:permissions) { %i(view_work_packages manage_subtasks) } - let!(:parent) { create(:work_package, project:, subject: "Parent WP") } - let!(:child) { create(:work_package, project:, subject: "Child WP") } + let!(:parent) { create(:work_package, project:, subject: 'Parent WP') } + let!(:child) { create(:work_package, project:, subject: 'Child WP') } - it "is able to link parent and children" do + it 'is able to link parent and children' do # Add parent relations.add_parent(parent.id, parent) - wp_page.expect_and_dismiss_toaster(message: "Successful update.") + wp_page.expect_and_dismiss_toaster(message: 'Successful update.') relations.expect_parent(parent) ## @@ -242,7 +242,7 @@ def visit_relations relations.open_children_autocompleter relations.add_existing_child(child) - wp_page.expect_and_dismiss_toaster(message: "Successful update.") + wp_page.expect_and_dismiss_toaster(message: 'Successful update.') relations.expect_child(child) # Expect counter to add up child to the existing relations @@ -250,7 +250,7 @@ def visit_relations # Remove parent relations.remove_parent - wp_page.expect_and_dismiss_toaster(message: "Successful update.") + wp_page.expect_and_dismiss_toaster(message: 'Successful update.') relations.expect_no_parent # Remove child @@ -266,14 +266,14 @@ def visit_relations end end -RSpec.context "Split screen" do +RSpec.context 'Split screen' do let(:wp_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "work package relations tab" + it_behaves_like 'work package relations tab' end -RSpec.context "Full screen" do +RSpec.context 'Full screen' do let(:wp_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "work package relations tab" + it_behaves_like 'work package relations tab' end diff --git a/spec/features/work_packages/details/relations/relations_spec.rb b/spec/features/work_packages/details/relations/relations_spec.rb index 18456037b309..74e8ec108171 100644 --- a/spec/features/work_packages/details/relations/relations_spec.rb +++ b/spec/features/work_packages/details/relations/relations_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package relations tab", :js, :selenium do - include_context "ng-select-autocomplete helpers" +RSpec.describe 'Work package relations tab', :js, :selenium do + include_context 'ng-select-autocomplete helpers' let(:user) { create(:admin) } @@ -40,7 +40,7 @@ let(:relations) { Components::WorkPackages::Relations.new(work_package) } let(:tabs) { Components::WorkPackages::Tabs.new(work_package) } - let(:relations_tab) { find(".op-tab-row--link_selected", text: "RELATIONS") } + let(:relations_tab) { find('.op-tab-row--link_selected', text: 'RELATIONS') } let(:visit) { true } @@ -53,13 +53,13 @@ end def visit_relations - work_packages_page.visit_tab!("relations") + work_packages_page.visit_tab!('relations') expect_angular_frontend_initialized work_packages_page.expect_subject loading_indicator_saveguard end - describe "relation group-by toggler" do + describe 'relation group-by toggler' do let(:project) { create(:project, types: [type1, type2]) } let(:type1) { create(:type) } let(:type2) { create(:type) } @@ -80,73 +80,73 @@ def visit_relations relation_type: Relation::TYPE_RELATES) end - let(:toggle_btn_selector) { "#wp-relation-group-by-toggle" } + let(:toggle_btn_selector) { '#wp-relation-group-by-toggle' } let(:visit) { false } before do visit_relations - work_packages_page.visit_tab!("relations") + work_packages_page.visit_tab!('relations') work_packages_page.expect_subject loading_indicator_saveguard - scroll_to_element find(".detail-panel--relations") + scroll_to_element find('.detail-panel--relations') end - it "allows to toggle how relations are grouped" do + it 'allows to toggle how relations are grouped' do # Expect to be grouped by relation type by default expect(page).to have_selector(toggle_btn_selector, - text: "Group by work package type", wait: 20) + text: 'Group by work package type', wait: 20) - expect(page).to have_css(".relation-group--header", text: "FOLLOWS") - expect(page).to have_css(".relation-group--header", text: "RELATED TO") + expect(page).to have_css('.relation-group--header', text: 'FOLLOWS') + expect(page).to have_css('.relation-group--header', text: 'RELATED TO') - expect(page).to have_css(".relation-row--type", text: type1.name.upcase) - expect(page).to have_css(".relation-row--type", text: type2.name.upcase) + expect(page).to have_css('.relation-row--type', text: type1.name.upcase) + expect(page).to have_css('.relation-row--type', text: type2.name.upcase) find(toggle_btn_selector).click - expect(page).to have_selector(toggle_btn_selector, text: "Group by relation type", wait: 10) + expect(page).to have_selector(toggle_btn_selector, text: 'Group by relation type', wait: 10) - expect(page).to have_css(".relation-group--header", text: type1.name.upcase) - expect(page).to have_css(".relation-group--header", text: type2.name.upcase) + expect(page).to have_css('.relation-group--header', text: type1.name.upcase) + expect(page).to have_css('.relation-group--header', text: type2.name.upcase) - expect(page).to have_css(".relation-row--type", text: "Follows") - expect(page).to have_css(".relation-row--type", text: "Related To") + expect(page).to have_css('.relation-row--type', text: 'Follows') + expect(page).to have_css('.relation-row--type', text: 'Related To') end - it "allows to edit relation types when toggled" do + it 'allows to edit relation types when toggled' do find(toggle_btn_selector).click - expect(page).to have_selector(toggle_btn_selector, text: "Group by relation type", wait: 20) + expect(page).to have_selector(toggle_btn_selector, text: 'Group by relation type', wait: 20) # Expect current to be follows and other one related - expect(page).to have_css(".relation-row--type", text: "Follows") - expect(page).to have_css(".relation-row--type", text: "Related To") + expect(page).to have_css('.relation-row--type', text: 'Follows') + expect(page).to have_css('.relation-row--type', text: 'Related To') # edit to blocks - relations.edit_relation_type(to1, to_type: "Blocks") + relations.edit_relation_type(to1, to_type: 'Blocks') # the other one should not be altered - expect(page).to have_css(".relation-row--type", text: "Blocks") - expect(page).to have_css(".relation-row--type", text: "Related To") + expect(page).to have_css('.relation-row--type', text: 'Blocks') + expect(page).to have_css('.relation-row--type', text: 'Related To') updated_relation = Relation.find(relation1.id) - expect(updated_relation.relation_type).to eq("blocks") + expect(updated_relation.relation_type).to eq('blocks') expect(updated_relation.from_id).to eq(work_package.id) expect(updated_relation.to_id).to eq(to1.id) - relations.edit_relation_type(to1, to_type: "Blocked by") + relations.edit_relation_type(to1, to_type: 'Blocked by') - expect(page).to have_css(".relation-row--type", text: "Blocked by") - expect(page).to have_css(".relation-row--type", text: "Related To") + expect(page).to have_css('.relation-row--type', text: 'Blocked by') + expect(page).to have_css('.relation-row--type', text: 'Related To') updated_relation = Relation.find(relation1.id) - expect(updated_relation.relation_type).to eq("blocks") + expect(updated_relation.relation_type).to eq('blocks') expect(updated_relation.from_id).to eq(to1.id) expect(updated_relation.to_id).to eq(work_package.id) end end - describe "with limited permissions" do + describe 'with limited permissions' do let(:permissions) { %i(view_work_packages) } let(:user_role) do create(:project_role, permissions:) @@ -157,33 +157,33 @@ def visit_relations member_with_roles: { project => user_role }) end - context "as view-only user, with parent set" do + context 'as view-only user, with parent set' do let(:work_package) { create(:work_package, project:) } - it "shows no links to create relations" do + it 'shows no links to create relations' do # No create buttons should exist - expect(page).to have_no_css(".wp-relations-create-button") + expect(page).to have_no_css('.wp-relations-create-button') # Test for add relation - expect(page).to have_no_css("#relation--add-relation") + expect(page).to have_no_css('#relation--add-relation') end end - context "with relations permissions" do + context 'with relations permissions' do let(:permissions) do %i(view_work_packages add_work_packages manage_subtasks manage_work_package_relations) end let!(:relatable) { create(:work_package, project:) } - it "allows to manage relations" do - relations.add_relation(type: "follows", to: relatable) + it 'allows to manage relations' do + relations.add_relation(type: 'follows', to: relatable) # Relations counter badge should increase number of relations tabs.expect_counter(relations_tab, 1) relations.remove_relation(relatable) - expect(page).to have_no_css(".relation-group--header", text: "FOLLOWS") + expect(page).to have_no_css('.relation-group--header', text: 'FOLLOWS') # If there are no relations, the counter badge should not be displayed tabs.expect_no_counter(relations_tab) @@ -192,30 +192,30 @@ def visit_relations expect(work_package.relations).to be_empty end - it "allows to move between split and full view (Regression #24194)" do - relations.add_relation(type: "follows", to: relatable) + it 'allows to move between split and full view (Regression #24194)' do + relations.add_relation(type: 'follows', to: relatable) # Relations counter should increase tabs.expect_counter(relations_tab, 1) # Switch to full view - find(".work-packages--details-fullscreen-icon").click + find('.work-packages--details-fullscreen-icon').click # Expect to have row relations.hover_action(relatable, :delete) - expect(page).to have_no_css(".relation-group--header", text: "FOLLOWS") - expect(page).to have_no_css(".wp-relations--subject-field", text: relatable.subject) + expect(page).to have_no_css('.relation-group--header', text: 'FOLLOWS') + expect(page).to have_no_css('.wp-relations--subject-field', text: relatable.subject) # Back to split view - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') work_packages_page.expect_subject - expect(page).to have_no_css(".relation-group--header", text: "FOLLOWS") - expect(page).to have_no_css(".wp-relations--subject-field", text: relatable.subject) + expect(page).to have_no_css('.relation-group--header', text: 'FOLLOWS') + expect(page).to have_no_css('.wp-relations--subject-field', text: relatable.subject) end - it "follows the relation links (Regression #26794)" do - relations.add_relation(type: "follows", to: relatable) + it 'follows the relation links (Regression #26794)' do + relations.add_relation(type: 'follows', to: relatable) relations.click_relation(relatable) subject = full_wp.edit_field(:subject) @@ -226,54 +226,54 @@ def visit_relations subject.expect_state_text work_package.subject end - it "allows to change relation descriptions" do - relations.add_relation(type: "follows", to: relatable) + it 'allows to change relation descriptions' do + relations.add_relation(type: 'follows', to: relatable) ## Toggle description relations.hover_action(relatable, :info) # Open textarea created_row = relations.find_row(relatable) - created_row.find(".wp-relation--description-read-value.-placeholder", - text: I18n.t("js.placeholders.relation_description")).click + created_row.find('.wp-relation--description-read-value.-placeholder', + text: I18n.t('js.placeholders.relation_description')).click - expect(page).to have_focus_on(".wp-relation--description-textarea") - textarea = created_row.find(".wp-relation--description-textarea") - textarea.set "my description!" + expect(page).to have_focus_on('.wp-relation--description-textarea') + textarea = created_row.find('.wp-relation--description-textarea') + textarea.set 'my description!' # Save description - created_row.find(".inplace-edit--control--save").click + created_row.find('.inplace-edit--control--save').click loading_indicator_saveguard # Wait for the relations table to be present sleep 2 - expect(page).to have_test_selector("op-relation--row-subject") + expect(page).to have_test_selector('op-relation--row-subject') - scroll_to_element find(".detail-panel--relations") + scroll_to_element find('.detail-panel--relations') ## Toggle description again retry_block do relations.hover_action(relatable, :info) created_row = relations.find_row(relatable) - find ".wp-relation--description-read-value" + find '.wp-relation--description-read-value' end - created_row.find(".wp-relation--description-read-value", - text: "my description!").click + created_row.find('.wp-relation--description-read-value', + text: 'my description!').click # Cancel edition - created_row.find(".inplace-edit--control--cancel").click - created_row.find(".wp-relation--description-read-value", - text: "my description!").click + created_row.find('.inplace-edit--control--cancel').click + created_row.find('.wp-relation--description-read-value', + text: 'my description!').click relation = work_package.relations.first - expect(relation.description).to eq("my description!") + expect(relation.description).to eq('my description!') # Toggle to close relations.hover_action(relatable, :info) - expect(created_row).to have_no_css(".wp-relation--description-read-value") + expect(created_row).to have_no_css('.wp-relation--description-read-value') end end end diff --git a/spec/features/work_packages/details/workdays_spec.rb b/spec/features/work_packages/details/workdays_spec.rb index e6f30bce626b..c736a72345ec 100644 --- a/spec/features/work_packages/details/workdays_spec.rb +++ b/spec/features/work_packages/details/workdays_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/page_objects/notification' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' -RSpec.describe "Work packages datepicker workdays", :js, with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'Work packages datepicker workdays', :js, with_settings: { date_format: '%Y-%m-%d' } do shared_let(:project) { create(:project_with_types, public: true) } - shared_let(:work_package) { create(:work_package, project:, start_date: Date.parse("2022-01-01")) } + shared_let(:work_package) { create(:work_package, project:, start_date: Date.parse('2022-01-01')) } shared_let(:user) { create(:admin) } shared_let(:work_packages_page) { Pages::FullWorkPackage.new(work_package, project) } @@ -51,21 +51,21 @@ combined_date.expect_active! end - context "with default work days" do + context 'with default work days' do shared_let(:working_days) { week_with_saturday_and_sunday_as_weekend } - it "shows them as disabled" do - expect(page).to have_css(".dayContainer", count: 2) + it 'shows them as disabled' do + expect(page).to have_css('.dayContainer', count: 2) weekend_days = %w[1 2 8 9 15 16 22 23 29 30].map(&:to_i) weekend_days.each do |weekend_day| - expect(page).to have_css(".dayContainer:first-of-type .flatpickr-day.flatpickr-non-working-day", + expect(page).to have_css('.dayContainer:first-of-type .flatpickr-day.flatpickr-non-working-day', text: weekend_day, exact_text: true) end ((1..31).to_a - weekend_days).each do |workday| - expect(page).to have_css(".dayContainer:first-of-type .flatpickr-day:not(.flatpickr-non-working-day)", + expect(page).to have_css('.dayContainer:first-of-type .flatpickr-day:not(.flatpickr-non-working-day)', text: workday, exact_text: true) end diff --git a/spec/features/work_packages/display_fields/date_field_display_spec.rb b/spec/features/work_packages/display_fields/date_field_display_spec.rb index 5d08592694f1..3cbcae25ee2b 100644 --- a/spec/features/work_packages/display_fields/date_field_display_spec.rb +++ b/spec/features/work_packages/display_fields/date_field_display_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Show the date of a Work Package", :js do +RSpec.describe 'Show the date of a Work Package', :js do let(:project) { create(:project) } let(:admin) { create(:admin) } let(:work_package) do @@ -52,22 +52,22 @@ new_status: closed_status) end - context "with an overdue date" do + context 'with an overdue date' do before do login_as(admin) wp_page.visit! end - it "is highlighted only if the WP status is open (#33457)" do + it 'is highlighted only if the WP status is open (#33457)' do # Highlighted with an open status - expect(page).to have_css(".inline-edit--display-field.combinedDate .__hl_date_overdue") + expect(page).to have_css('.inline-edit--display-field.combinedDate .__hl_date_overdue') # Change status to closed status_field = WorkPackageStatusField.new(page) status_field.update(closed_status.name) # Not highlighted with a closed status - expect(page).to have_no_css(".inline-edit--display-field.combinedDate .__hl_date_overdue") + expect(page).to have_no_css('.inline-edit--display-field.combinedDate .__hl_date_overdue') end end end diff --git a/spec/features/work_packages/display_fields/estimated_hours_display_spec.rb b/spec/features/work_packages/display_fields/estimated_hours_display_spec.rb index 3b571e999586..c67d9a50703f 100644 --- a/spec/features/work_packages/display_fields/estimated_hours_display_spec.rb +++ b/spec/features/work_packages/display_fields/estimated_hours_display_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Estimated hours display", :js do +RSpec.describe 'Estimated hours display', :js do shared_let(:project) { create(:project) } shared_let(:user) { create(:admin) } shared_let(:wiki_page) { create(:wiki_page, wiki: project.wiki) } @@ -58,8 +58,8 @@ login_as(user) end - shared_examples "estimated time display" do |expected_text:| - it "work package index" do + shared_examples 'estimated time display' do |expected_text:| + it 'work package index' do wp_table.visit_query query wp_table.expect_work_package_listed child @@ -68,19 +68,19 @@ ) end - it "work package details" do + it 'work package details' do visit work_package_path(parent.id) expect(page).to have_content("Work\n#{expected_text}") end - it "wiki page workPackageValue:id:estimatedTime macro" do + it 'wiki page workPackageValue:id:estimatedTime macro' do visit edit_project_wiki_path(project, wiki_page.id) editor.set_markdown("workPackageValue:#{parent.id}:estimatedTime") - click_on "Save" + click_on 'Save' - expect(page).to have_css(".wiki-content", text: expected_text) + expect(page).to have_css('.wiki-content', text: expected_text) end end @@ -91,7 +91,7 @@ child | 3h | TABLE - include_examples "estimated time display", expected_text: "1 h·Σ 4 h" + include_examples 'estimated time display', expected_text: '1 h·Σ 4 h' end context "with just work" do @@ -101,7 +101,7 @@ child | 0h | TABLE - include_examples "estimated time display", expected_text: "1 h" + include_examples 'estimated time display', expected_text: '1 h' end context "with just derived work with (parent work 0 h)" do @@ -111,7 +111,7 @@ child | 3h | TABLE - include_examples "estimated time display", expected_text: "0 h·Σ 3 h" + include_examples 'estimated time display', expected_text: '0 h·Σ 3 h' end context "with just derived work (parent work unset)" do @@ -121,7 +121,7 @@ child | 3h | TABLE - include_examples "estimated time display", expected_text: "-·Σ 3 h" + include_examples 'estimated time display', expected_text: '-·Σ 3 h' end context "with neither work nor derived work (both 0 h)" do @@ -131,7 +131,7 @@ child | 0h | TABLE - include_examples "estimated time display", expected_text: "0 h" + include_examples 'estimated time display', expected_text: '0 h' end context "with neither work nor derived work (both unset)" do @@ -141,10 +141,10 @@ child | | TABLE - include_examples "estimated time display", expected_text: "-" + include_examples 'estimated time display', expected_text: '-' end - describe "link to detailed view" do + describe 'link to detailed view' do let_work_packages(<<~TABLE) hierarchy | work | parent | 5h | @@ -158,7 +158,7 @@ # Run UpdateAncestorsService on the grand child to update the whole hierarchy derived values let(:initiator_work_package) { grand_child21 } - it "displays a link to a detailed view explaining work calculation" do + it 'displays a link to a detailed view explaining work calculation' do wp_table.visit_query query # parent @@ -169,29 +169,29 @@ expect(page).to have_link("Σ 15 h") end - context "when clicking the link of a top parent" do + context 'when clicking the link of a top parent' do before do visit work_package_path(parent) end - it "shows a work package table with a parent filter to list the direct children" do + it 'shows a work package table with a parent filter to list the direct children' do click_on("Σ 20 h") wp_table.expect_work_package_count(4) wp_table.expect_work_package_listed(parent, child1, child2, child3) within(:table) do - expect(page).to have_columnheader("Work") - expect(page).to have_columnheader("Remaining work") + expect(page).to have_columnheader('Work') + expect(page).to have_columnheader('Remaining work') end end end - context "when clicking the link of an intermediate parent" do + context 'when clicking the link of an intermediate parent' do before do visit work_package_path(child2) end - it "shows also all ancestors in the work package table" do + it 'shows also all ancestors in the work package table' do expect(page).to have_content("Work\n3 h·Σ 15 h") click_on("Σ 15 h") diff --git a/spec/features/work_packages/display_fields/spent_time_display_spec.rb b/spec/features/work_packages/display_fields/spent_time_display_spec.rb index ed7da8592b33..06aa0c026b49 100644 --- a/spec/features/work_packages/display_fields/spent_time_display_spec.rb +++ b/spec/features/work_packages/display_fields/spent_time_display_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Logging time within the work package view", :js do +RSpec.describe 'Logging time within the work package view', :js do shared_let(:project) { create(:project) } shared_let(:admin) { create(:admin) } shared_let(:work_package) { create(:work_package, project:) } @@ -36,7 +36,7 @@ let(:user) { admin } - let(:spent_time_field) { SpentTimeEditField.new(page, "spentTime") } + let(:spent_time_field) { SpentTimeEditField.new(page, 'spentTime') } let(:wp_page) { Pages::FullWorkPackage.new(work_package, project) } @@ -46,12 +46,12 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z time_logging_modal.is_visible true # the fields are visible - time_logging_modal.has_field_with_value "spent_on", Time.zone.today.strftime("%Y-%m-%d") - time_logging_modal.shows_field "work_package", false - time_logging_modal.shows_field "user", user_field_visible + time_logging_modal.has_field_with_value 'spent_on', Time.zone.today.strftime("%Y-%m-%d") + time_logging_modal.shows_field 'work_package', false + time_logging_modal.shows_field 'user', user_field_visible # Update the fields - time_logging_modal.update_field "activity", activity.name + time_logging_modal.update_field 'activity', activity.name Components::BasicDatepicker.update_field( "##{time_logging_modal.field_identifier('spent_on')}", @@ -59,17 +59,17 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z ) if log_for_user - time_logging_modal.update_field "user", log_for_user.name + time_logging_modal.update_field 'user', log_for_user.name elsif user_field_visible - expect(page).to have_css(".ng-value-label", text: user.name) + expect(page).to have_css('.ng-value-label', text: user.name) end # a click on save creates a time entry time_logging_modal.perform_action I18n.t(:button_save) - wp_page.expect_and_dismiss_toaster message: I18n.t("js.notice_successful_create") + wp_page.expect_and_dismiss_toaster message: I18n.t('js.notice_successful_create') end - context "as an admin" do + context 'as an admin' do before do login_as(user) wp_page.visit! @@ -77,7 +77,7 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z spent_time_field.time_log_icon_visible true end - it "shows a logging button within the display field and can log time via a modal" do + it 'shows a logging button within the display field and can log time via a modal' do # click on button opens modal spent_time_field.open_time_log_modal expect do @@ -85,7 +85,7 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z end.to change(TimeEntry, :count).by(1) # the value is updated automatically - spent_time_field.expect_display_value "1 h" + spent_time_field.expect_display_value '1 h' TimeEntry.last.tap do |te| expect(te.work_package).to eq(work_package) @@ -97,22 +97,22 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z end end - context "with another user in the project" do + context 'with another user in the project' do let!(:other_user) do create(:user, - firstname: "Loggable", - lastname: "User", + firstname: 'Loggable', + lastname: 'User', member_with_permissions: { project => %i[view_work_packages edit_work_packages work_package_assigned] }) end - it "can log time for that user" do + it 'can log time for that user' do # click on button opens modal spent_time_field.open_time_log_modal log_time_via_modal log_for_user: other_user # the value is updated automatically - spent_time_field.expect_display_value "1 h" + spent_time_field.expect_display_value '1 h' time_entry = TimeEntry.last expect(time_entry.user).to eq other_user @@ -120,37 +120,37 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z end end - it "the context menu entry to log time leads to the modal" do + it 'the context menu entry to log time leads to the modal' do # click on context menu opens the modal - find("#action-show-more-dropdown-menu .button").click - find(".menu-item", text: "Log time").click + find('#action-show-more-dropdown-menu .button').click + find('.menu-item', text: 'Log time').click log_time_via_modal # the value is updated automatically - spent_time_field.expect_display_value "1 h" + spent_time_field.expect_display_value '1 h' end - context "with a user with non-one unit numbers", with_settings: { available_languages: %w[en ja] } do - let(:user) { create(:admin, language: "ja") } + context 'with a user with non-one unit numbers', with_settings: { available_languages: %w[en ja] } do + let(:user) { create(:admin, language: 'ja') } before do - I18n.locale = "ja" + I18n.locale = 'ja' end - it "shows the correct number (Regression #36269)" do + it 'shows the correct number (Regression #36269)' do # click on button opens modal spent_time_field.open_time_log_modal log_time_via_modal # the value is updated automatically - spent_time_field.expect_display_value "1 h" + spent_time_field.expect_display_value '1 h' end end end - context "as a user who cannot log time" do + context 'as a user who cannot log time' do let(:user) do create(:user, member_with_permissions: { project => %i[view_time_entries view_work_packages edit_work_packages] }) @@ -162,13 +162,13 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z loading_indicator_saveguard end - it "shows no logging button within the display field" do + it 'shows no logging button within the display field' do spent_time_field.time_log_icon_visible false - spent_time_field.expect_display_value "0 h" + spent_time_field.expect_display_value '0 h' end end - context "as a user who can only log own time" do + context 'as a user who can only log own time' do let(:user) do create(:user, member_with_permissions: { project => %i[view_time_entries view_work_packages log_own_time] }) @@ -180,7 +180,7 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z loading_indicator_saveguard end - it "can log its own time" do + it 'can log its own time' do spent_time_field.time_log_icon_visible true # click on button opens modal spent_time_field.open_time_log_modal @@ -188,14 +188,14 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z log_time_via_modal user_field_visible: false # the value is updated automatically - spent_time_field.expect_display_value "1 h" + spent_time_field.expect_display_value '1 h' end end - context "when in the table" do + context 'when in the table' do let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:second_work_package) { create(:work_package, project:) } - let(:query) { create(:public_query, project:, column_names: ["subject", "spent_hours"]) } + let(:query) { create(:public_query, project:, column_names: ['subject', 'spent_hours']) } before do work_package @@ -206,15 +206,15 @@ def log_time_via_modal(user_field_visible: true, log_for_user: nil, date: Time.z loading_indicator_saveguard end - it "shows no logging button within the display field" do + it 'shows no logging button within the display field' do wp_table.expect_work_package_listed work_package, second_work_package - find("tr:nth-of-type(1) .wp-table--cell-td.spentTime .icon-time").click + find('tr:nth-of-type(1) .wp-table--cell-td.spentTime .icon-time').click log_time_via_modal - expect(page).to have_css("tr:nth-of-type(1) .wp-table--cell-td.spentTime", text: "1 h") - expect(page).to have_css("tr:nth-of-type(2) .wp-table--cell-td.spentTime", text: "0 h") + expect(page).to have_css('tr:nth-of-type(1) .wp-table--cell-td.spentTime', text: '1 h') + expect(page).to have_css('tr:nth-of-type(2) .wp-table--cell-td.spentTime', text: '0 h') end end end diff --git a/spec/features/work_packages/display_representations/switch_display_representations_on_mobile_spec.rb b/spec/features/work_packages/display_representations/switch_display_representations_on_mobile_spec.rb index caf09abd1c88..12c5fd59a2fb 100644 --- a/spec/features/work_packages/display_representations/switch_display_representations_on_mobile_spec.rb +++ b/spec/features/work_packages/display_representations/switch_display_representations_on_mobile_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Switching work package view on mobile", :js do +RSpec.describe 'Switching work package view on mobile', :js do let(:user) { create(:admin) } let(:project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -53,21 +53,21 @@ wp_table.expect_work_package_listed wp_1, wp_2 end - context "switching to mobile card view" do - include_context "with mobile screen size" + context 'switching to mobile card view' do + include_context 'with mobile screen size' - it "can switch the representation automatically on mobile after a refresh" do + it 'can switch the representation automatically on mobile after a refresh' do # It shows the elements as cards cards.expect_work_package_listed wp_1, wp_2 # A single click leads to the full view cards.select_work_package(wp_1) - expect(page).to have_css(".work-packages--details--subject", + expect(page).to have_css('.work-packages--details--subject', text: wp_1.subject) - page.find(".work-packages-back-button").click + page.find('.work-packages-back-button').click # The query is however unchanged - expect(page).to have_no_css(".editable-toolbar-title--save") + expect(page).to have_no_css('.editable-toolbar-title--save') url = URI.parse(page.current_url).query expect(url).not_to match(/query_props=.+/) diff --git a/spec/features/work_packages/edit_on_assign_version_permission_spec.rb b/spec/features/work_packages/edit_on_assign_version_permission_spec.rb index b02566b81d2b..a4937cd633dd 100644 --- a/spec/features/work_packages/edit_on_assign_version_permission_spec.rb +++ b/spec/features/work_packages/edit_on_assign_version_permission_spec.rb @@ -1,17 +1,17 @@ -require "spec_helper" -require "features/page_objects/notification" +require 'spec_helper' +require 'features/page_objects/notification' -RSpec.describe "edit work package", :js do +RSpec.describe 'edit work package', :js do let(:current_user) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_permissions: { project => permissions }) end let(:permissions) { %i[view_work_packages assign_versions] } let(:cf_all) do - create(:work_package_custom_field, is_for_all: true, field_format: "text") + create(:work_package_custom_field, is_for_all: true, field_format: 'text') end let(:type) { create(:type, custom_fields: [cf_all]) } @@ -39,23 +39,23 @@ def visit! visit! end - context "as a user having only the assign_versions permission" do - it "can only change the version" do + context 'as a user having only the assign_versions permission' do + it 'can only change the version' do wp_page.update_attributes version: version.name - wp_page.expect_toast(message: "Successful update") + wp_page.expect_toast(message: 'Successful update') wp_page.expect_attributes version: version.name - subject_field = wp_page.work_package_field("subject") + subject_field = wp_page.work_package_field('subject') subject_field.expect_read_only end end - context "as a user having only the edit_work_packages permission" do + context 'as a user having only the edit_work_packages permission' do let(:permissions) { %i[view_work_packages edit_work_packages] } - it "can not change the version" do - version_field = wp_page.work_package_field("version") + it 'can not change the version' do + version_field = wp_page.work_package_field('version') version_field.expect_read_only end end diff --git a/spec/features/work_packages/edit_on_change_work_package_status_permission_spec.rb b/spec/features/work_packages/edit_on_change_work_package_status_permission_spec.rb index cd0b86a91857..194f8c9e6b04 100644 --- a/spec/features/work_packages/edit_on_change_work_package_status_permission_spec.rb +++ b/spec/features/work_packages/edit_on_change_work_package_status_permission_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" +require 'spec_helper' +require 'features/page_objects/notification' -RSpec.describe "edit work package", :js do +RSpec.describe 'edit work package', :js do let(:current_user) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_roles: { project => role }) end let(:permissions) { %i[view_work_packages change_work_package_status] } @@ -41,8 +41,8 @@ let(:type) { create(:type) } let(:project) { create(:project, types: [type]) } - let(:status_new) { create(:status, name: "New") } - let(:status_done) { create(:status, name: "Done") } + let(:status_new) { create(:status, name: 'New') } + let(:status_done) { create(:status, name: 'Done') } let(:workflow) do create(:workflow, type_id: type.id, @@ -69,29 +69,29 @@ wp_page.ensure_page_loaded end - context "as a user having only the change_work_package_status permission" do - it "can only change the status" do + context 'as a user having only the change_work_package_status permission' do + it 'can only change the status' do status_field = wp_page.edit_field :status status_field.expect_state_text status_new.name status_field.update status_done.name - wp_page.expect_toast(message: "Successful update") + wp_page.expect_toast(message: 'Successful update') status_field.expect_state_text status_done.name - subject_field = wp_page.work_package_field("subject") + subject_field = wp_page.work_package_field('subject') subject_field.expect_read_only end end - context "as a user having only the edit_work_packages permission" do + context 'as a user having only the edit_work_packages permission' do let(:permissions) { %i[view_work_packages edit_work_packages] } - it "can change the status" do + it 'can change the status' do status_field = wp_page.edit_field :status status_field.expect_state_text status_new.name status_field.update status_done.name - wp_page.expect_toast(message: "Successful update") + wp_page.expect_toast(message: 'Successful update') status_field.expect_state_text status_done.name end end diff --git a/spec/features/work_packages/edit_work_package_spec.rb b/spec/features/work_packages/edit_work_package_spec.rb index 16b6d8fc2176..c8201d945a82 100644 --- a/spec/features/work_packages/edit_work_package_spec.rb +++ b/spec/features/work_packages/edit_work_package_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" -require "features/page_objects/notification" +require 'spec_helper' +require 'features/page_objects/notification' -RSpec.describe "edit work package", :js do +RSpec.describe 'edit work package', :js do let(:dev_role) do create(:project_role, permissions: %i[view_work_packages @@ -9,8 +9,8 @@ end let(:dev) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_roles: { project => dev_role }) end let(:manager_role) do @@ -21,8 +21,8 @@ end let(:manager) do create(:admin, - firstname: "Manager", - lastname: "Guy", + firstname: 'Manager', + lastname: 'Guy', member_with_roles: { project => manager_role }) end let(:placeholder_user) do @@ -31,15 +31,15 @@ end let(:cf_all) do - create(:work_package_custom_field, is_for_all: true, field_format: "text") + create(:work_package_custom_field, is_for_all: true, field_format: 'text') end let(:cf_tp1) do - create(:work_package_custom_field, is_for_all: true, field_format: "text") + create(:work_package_custom_field, is_for_all: true, field_format: 'text') end let(:cf_tp2) do - create(:work_package_custom_field, is_for_all: true, field_format: "text") + create(:work_package_custom_field, is_for_all: true, field_format: 'text') end let(:type) { create(:type, custom_fields: [cf_all, cf_tp1]) } @@ -55,7 +55,7 @@ end let(:status) { work_package.status } - let(:new_subject) { "Some other subject" } + let(:new_subject) { 'Some other subject' } let(:wp_page) { Pages::FullWorkPackage.new(work_package) } let(:priority2) { create(:priority) } let(:status2) { create(:status) } @@ -90,12 +90,12 @@ def visit! end end - context "as an admin without roles" do + context 'as an admin without roles' do let(:visit_before) { false } let(:work_package) { create(:work_package, project:, type: type2) } let(:admin) { create(:admin) } - it "can still use the manager role" do + it 'can still use the manager role' do # A role must still exist workflow login_as admin @@ -108,7 +108,7 @@ def visit! end end - context "with progress" do + context 'with progress' do let(:visit_before) { false } before do @@ -116,36 +116,36 @@ def visit! visit! end - it "does not hide empty % Complete while it is being edited" do + it 'does not hide empty % Complete while it is being edited' do field = wp_page.work_package_field(:percentageDone) - field.update("0", save: false, expect_failure: true) + field.update('0', save: false, expect_failure: true) expect(page).to have_text("% Complete") end end - it "allows updating and seeing the results" do - wp_page.update_attributes subject: "a new subject", + it 'allows updating and seeing the results' do + wp_page.update_attributes subject: 'a new subject', type: type2.name, - combinedDate: ["2013-03-04", "2013-03-20"], + combinedDate: ['2013-03-04', '2013-03-20'], responsible: manager.name, assignee: manager.name, - estimatedTime: "5", + estimatedTime: '5', priority: priority2.name, version: version.name, category: category.name, - percentageDone: "30", + percentageDone: '30', status: status2.name, - description: "a new description" + description: 'a new description' wp_page.expect_attributes type: type2.name.upcase, responsible: manager.name, assignee: manager.name, - combinedDate: "03/04/2013 - 03/20/2013", - estimatedTime: "5", - percentageDone: "30%", - subject: "a new subject", - description: "a new description", + combinedDate: '03/04/2013 - 03/20/2013', + estimatedTime: '5', + percentageDone: '30%', + subject: 'a new subject', + description: 'a new description', priority: priority2.name, status: status2.name, version: version.name, @@ -154,7 +154,7 @@ def visit! wp_page.expect_activity_message("Status changed from #{status.name} to #{status2.name}") end - it "correctly assigns and un-assigns users" do + it 'correctly assigns and un-assigns users' do wp_page.update_attributes assignee: manager.name wp_page.expect_attributes assignee: manager.name wp_page.expect_activity_message("Assignee set to #{manager.name}") @@ -162,23 +162,23 @@ def visit! field = wp_page.edit_field :assignee field.unset_value - wp_page.expect_attributes assignee: "-" + wp_page.expect_attributes assignee: '-' wp_page.visit! # Another (empty) journal should exist now - expect(page).to have_css(".op-user-activity--user-name", + expect(page).to have_css('.op-user-activity--user-name', text: work_package.journals.last.user.name, wait: 10, count: 2) - wp_page.expect_attributes assignee: "-" + wp_page.expect_attributes assignee: '-' work_package.reload expect(work_package.assigned_to).to be_nil end - it "allows selecting placeholder users for assignee and responsible" do + it 'allows selecting placeholder users for assignee and responsible' do wp_page.update_attributes assignee: placeholder_user.name, responsible: placeholder_user.name @@ -189,11 +189,11 @@ def visit! wp_page.expect_activity_message("Accountable set to #{placeholder_user.name}") end - context "switching to custom field with required CF" do + context 'switching to custom field with required CF' do let(:custom_field) do create( :work_package_custom_field, - field_format: "string", + field_format: 'string', default_value: nil, is_required: true, is_for_all: true @@ -201,81 +201,81 @@ def visit! end let!(:type2) { create(:type, custom_fields: [custom_field]) } - it "shows the required field when switching" do + it 'shows the required field when switching' do type_field = wp_page.edit_field(:type) type_field.activate! type_field.set_value type2.name wp_page.expect_toast message: "#{custom_field.name} can't be blank.", - type: "error" + type: 'error' cf_field = wp_page.edit_field(custom_field.attribute_name(:camel_case)) cf_field.expect_active! - cf_field.expect_value("") + cf_field.expect_value('') end end - it "allows the user to add a comment to a work package" do + it 'allows the user to add a comment to a work package' do wp_page.ensure_page_loaded wp_page.trigger_edit_comment - wp_page.update_comment "hallo welt" + wp_page.update_comment 'hallo welt' wp_page.save_comment - wp_page.expect_toast(message: "The comment was successfully added.") - wp_page.expect_comment text: "hallo welt" + wp_page.expect_toast(message: 'The comment was successfully added.') + wp_page.expect_comment text: 'hallo welt' end - it "updates the presented custom fields based on the selected type" do + it 'updates the presented custom fields based on the selected type' do wp_page.ensure_page_loaded - wp_page.expect_attributes "customField#{cf_all.id}" => "", - "customField#{cf_tp1.id}" => "" + wp_page.expect_attributes "customField#{cf_all.id}" => '', + "customField#{cf_tp1.id}" => '' wp_page.expect_attribute_hidden "customField#{cf_tp2.id}" - wp_page.update_attributes "customField#{cf_all.id}" => "bird is the word", - "type" => type2.name + wp_page.update_attributes "customField#{cf_all.id}" => 'bird is the word', + 'type' => type2.name - wp_page.expect_attributes "customField#{cf_all.id}" => "bird is the word", - "customField#{cf_tp2.id}" => "" + wp_page.expect_attributes "customField#{cf_all.id}" => 'bird is the word', + "customField#{cf_tp2.id}" => '' wp_page.expect_attribute_hidden "customField#{cf_tp1.id}" end - it "shows an error if a subject is entered which is too long" do - too_long = ("Too long. Can you feel it? " * 10).strip + it 'shows an error if a subject is entered which is too long' do + too_long = ('Too long. Can you feel it? ' * 10).strip wp_page.ensure_page_loaded field = wp_page.work_package_field(:subject) field.update(too_long, expect_failure: true) - wp_page.expect_toast message: "Subject is too long (maximum is 255 characters)", - type: "error" + wp_page.expect_toast message: 'Subject is too long (maximum is 255 characters)', + type: 'error' end - context "submitting" do + context 'submitting' do let(:subject_field) { wp_page.edit_field(:subject) } before do subject_field.activate! - subject_field.set_value "My new subject!" + subject_field.set_value 'My new subject!' end - it "submits the edit mode when pressing enter" do + it 'submits the edit mode when pressing enter' do subject_field.input_element.send_keys(:return) - wp_page.expect_toast(message: "Successful update") + wp_page.expect_toast(message: 'Successful update') subject_field.expect_inactive! - subject_field.expect_state_text "My new subject!" + subject_field.expect_state_text 'My new subject!' end - it "submits the edit mode when changing the focus" do + it 'submits the edit mode when changing the focus' do page.find("body").click - wp_page.expect_toast(message: "Successful update") + wp_page.expect_toast(message: 'Successful update') subject_field.expect_inactive! - subject_field.expect_state_text "My new subject!" + subject_field.expect_state_text 'My new subject!' end end end diff --git a/spec/features/work_packages/export_spec.rb b/spec/features/work_packages/export_spec.rb index 4644baf1ff5b..4bf509cebc78 100644 --- a/spec/features/work_packages/export_spec.rb +++ b/spec/features/work_packages/export_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "work package export" do +RSpec.describe 'work package export' do let(:project) { create(:project_with_types, types: [type_a, type_b]) } - let(:export_type) { "CSV" } + let(:export_type) { 'CSV' } let(:current_user) { create(:admin) } let(:type_a) { create(:type, name: "Type A") } @@ -65,15 +65,15 @@ def export!(expect_success = true) work_packages_page.ensure_loaded - settings_menu.open_and_choose "Export" + settings_menu.open_and_choose 'Export' click_on export_type # Expect to get a response regarding queuing - expect(page).to have_content I18n.t("js.job_status.generic_messages.in_queue"), + expect(page).to have_content I18n.t('js.job_status.generic_messages.in_queue'), wait: 10 # Expect title - expect(page).to have_test_selector "job-status--header", text: I18n.t("export.your_work_packages_export") + expect(page).to have_test_selector 'job-status--header', text: I18n.t('export.your_work_packages_export') begin perform_enqueued_jobs @@ -90,15 +90,15 @@ def export!(expect_success = true) DownloadList.clear end - context "CSV export" do - context "with default filter" do + context 'CSV export' do + context 'with default filter' do before do work_packages_page.visit_index filters.expect_filter_count 1 filters.open end - it "shows all work packages with the default filters", :js do + it 'shows all work packages with the default filters', :js do export! expect(subject).to have_text(wp1.description) @@ -110,8 +110,8 @@ def export!(expect_success = true) expect(subject.scan(/Type (A|B)/).flatten).to eq %w(A A B A) end - it "shows all work packages grouped by", :js do - group_by.enable_via_menu "Type" + it 'shows all work packages grouped by', :js do + group_by.enable_via_menu 'Type' wp_table.expect_work_package_listed(wp1) wp_table.expect_work_package_listed(wp2) @@ -129,8 +129,8 @@ def export!(expect_success = true) expect(subject.scan(/Type (A|B)/).flatten).to eq %w(A A A B) end - it "shows only the work package with the right progress if filtered this way", :js do - filters.add_filter_by "% Complete", "is", ["25"], "percentageDone" + it 'shows only the work package with the right progress if filtered this way', :js do + filters.add_filter_by '% Complete', 'is', ['25'], 'percentageDone' sleep 1 loading_indicator_saveguard @@ -145,8 +145,8 @@ def export!(expect_success = true) expect(subject).to have_no_text(wp3.description) end - it "shows only work packages of the filtered type", :js do - filters.add_filter_by "Type", "is (OR)", wp3.type.name + it 'shows only work packages of the filtered type', :js do + filters.add_filter_by 'Type', 'is (OR)', wp3.type.name expect(page).to have_no_content(wp2.description) # safeguard @@ -159,17 +159,17 @@ def export!(expect_success = true) expect(subject).to have_text(wp3.description) end - it "exports selected columns", :js do - columns.add "% Complete" + it 'exports selected columns', :js do + columns.add '% Complete' export! - expect(subject).to have_text("% Complete") - expect(subject).to have_text("25") + expect(subject).to have_text('% Complete') + expect(subject).to have_text('25') end end - describe "with a manually sorted query", :js do + describe 'with a manually sorted query', :js do let(:query) do create(:query, user: current_user, @@ -182,20 +182,20 @@ def export!(expect_success = true) OrderedWorkPackage.create(query:, work_package: wp2, position: 2) OrderedWorkPackage.create(query:, work_package: wp3, position: 3) - query.add_filter("manual_sort", "ow", []) - query.sort_criteria = [[:manual_sorting, "asc"]] + query.add_filter('manual_sort', 'ow', []) + query.sort_criteria = [[:manual_sorting, 'asc']] query.save! end - it "returns the correct number of work packages" do + it 'returns the correct number of work packages' do wp_table.visit_query query wp_table.expect_work_package_listed(wp1, wp2, wp3, wp4) wp_table.expect_work_package_order(wp4, wp1, wp2, wp3) export! - expect(page).to have_css(".job-status--modal .icon-checkmark", wait: 10) - expect(page).to have_content("The export has completed successfully.") + expect(page).to have_css('.job-status--modal .icon-checkmark', wait: 10) + expect(page).to have_content('The export has completed successfully.') expect(subject).to have_text(wp1.description) expect(subject).to have_text(wp2.description) @@ -208,17 +208,17 @@ def export!(expect_success = true) end end - context "PDF export", :js do - let(:export_type) { I18n.t("export.format.pdf_overview_table") } + context 'PDF export', :js do + let(:export_type) { I18n.t('export.format.pdf_overview_table') } let(:query) do create(:query, user: current_user, project:) end - context "with many columns" do + context 'with many columns' do before do - query.column_names = query.displayable_columns.map { |c| c.name.to_s } - ["bcf_thumbnail"] + query.column_names = query.displayable_columns.map { |c| c.name.to_s } - ['bcf_thumbnail'] query.save! # Despite attempts to provoke the error by having a lot of columns, the pdf @@ -228,7 +228,7 @@ def export!(expect_success = true) .and_raise(I18n.t(:error_pdf_export_too_many_columns)) end - it "returns the error" do + it 'returns the error' do wp_table.visit_query query export!(false) @@ -241,18 +241,18 @@ def export!(expect_success = true) # Atom exports are not downloaded. In fact, it is not even a download but rather # a feed one can follow. - context "Atom export", :js do - let(:export_type) { "Atom" } + context 'Atom export', :js do + let(:export_type) { 'Atom' } - context "with default filter" do + context 'with default filter' do before do work_packages_page.visit_index filters.expect_filter_count 1 filters.open end - it "shows an xml with work packages" do - settings_menu.open_and_choose "Export" + it 'shows an xml with work packages' do + settings_menu.open_and_choose 'Export' # The feed is opened in a new tab new_window = window_opened_by { click_on export_type } diff --git a/spec/features/work_packages/highlighting_spec.rb b/spec/features/work_packages/highlighting_spec.rb index 67c9af0644df..52702c1a539e 100644 --- a/spec/features/work_packages/highlighting_spec.rb +++ b/spec/features/work_packages/highlighting_spec.rb @@ -1,16 +1,16 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package highlighting fields", :js, +RSpec.describe 'Work Package highlighting fields', :js, with_ee: %i[conditional_highlighting] do let(:user) { create(:admin) } let(:project) { create(:project) } - let(:status1) { create(:status, color: create(:color, hexcode: "#FF0000")) } # rgba(255, 0, 0, 1) - let(:status2) { create(:status, color: create(:color, hexcode: "#F0F0F0")) } # rgba(240, 240, 240, 1) + let(:status1) { create(:status, color: create(:color, hexcode: '#FF0000')) } # rgba(255, 0, 0, 1) + let(:status2) { create(:status, color: create(:color, hexcode: '#F0F0F0')) } # rgba(240, 240, 240, 1) let(:priority1) do - create(:issue_priority, color: create(:color, hexcode: "#123456")) + create(:issue_priority, color: create(:color, hexcode: '#123456')) end let(:priority_no_color) { create(:issue_priority, color: nil) } @@ -18,7 +18,7 @@ create(:work_package, project:, status: status1, - subject: "B", + subject: 'B', due_date: (Date.today - 1.day), priority: priority1) end @@ -27,7 +27,7 @@ create(:work_package, project:, status: status2, - subject: "A", + subject: 'A', due_date: Date.today, priority: priority_no_color) end @@ -57,7 +57,7 @@ wp_table.expect_work_package_listed wp_1, wp_2 end - it "provides highlighting through css classes" do + it 'provides highlighting through css classes' do # Default inline highlight wp1_row = wp_table.row(wp_1) wp2_row = wp_table.row(wp_2) @@ -65,26 +65,26 @@ ## Status expect(SelectorHelpers.get_pseudo_class_property(page, wp1_row.find('[class^="__hl_inline_status_"]'), - ":before", - "background-color")).to eq("rgb(255, 0, 0)") + ':before', + "background-color")).to eq('rgb(255, 0, 0)') expect(SelectorHelpers.get_pseudo_class_property(page, wp2_row.find('[class^="__hl_inline_status_"]'), - ":before", - "background-color")).to eq("rgb(240, 240, 240)") + ':before', + "background-color")).to eq('rgb(240, 240, 240)') ## Priority expect(SelectorHelpers.get_pseudo_class_property(page, wp1_row.find('[class^="__hl_inline_priority_"]'), - ":before", - "background-color")).to eq("rgb(18, 52, 86)") + ':before', + "background-color")).to eq('rgb(18, 52, 86)') expect(SelectorHelpers.get_pseudo_class_property(page, wp2_row.find('[class^="__hl_inline_priority_"]'), - ":before", - "background-color")).to eq("rgba(0, 0, 0, 0)") + ':before', + "background-color")).to eq('rgba(0, 0, 0, 0)') ## Overdue - expect(wp1_row).to have_css(".__hl_date_overdue") - expect(wp2_row).to have_css(".__hl_date_due_today") + expect(wp1_row).to have_css('.__hl_date_overdue') + expect(wp2_row).to have_css('.__hl_date_due_today') # Highlight only one attribute highlighting.switch_inline_attribute_highlight "Priority" @@ -95,12 +95,12 @@ ## Priority should have a dot expect(SelectorHelpers.get_pseudo_class_property(page, wp1_row.find('[class^="__hl_inline_priority_"]'), - ":before", - "background-color")).to eq("rgb(18, 52, 86)") + ':before', + "background-color")).to eq('rgb(18, 52, 86)') expect(SelectorHelpers.get_pseudo_class_property(page, wp2_row.find('[class^="__hl_inline_priority_"]'), - ":before", - "background-color")).to eq("rgba(0, 0, 0, 0)") + ':before', + "background-color")).to eq('rgba(0, 0, 0, 0)') ## Status should not have a dot expect(wp1_row).to have_no_css('.status [class^="__hl_inline_"]') @@ -110,29 +110,29 @@ wp1_row = wp_table.row(wp_1) expect(SelectorHelpers.get_pseudo_class_property(page, wp1_row.find('[class^="__hl_inline_priority_"]'), - ":before", - "background-color")).to eq("rgb(18, 52, 86)") + ':before', + "background-color")).to eq('rgb(18, 52, 86)') expect(SelectorHelpers.get_pseudo_class_property(page, wp1_row.find('[class^="__hl_inline_status_"]'), - ":before", - "background-color")).to eq("rgb(255, 0, 0)") + ':before', + "background-color")).to eq('rgb(255, 0, 0)') # Highlight entire row by status - highlighting.switch_entire_row_highlight "Status" + highlighting.switch_entire_row_highlight 'Status' expect(page).to have_css("#{wp_table.row_selector(wp_1)}.__hl_background_status_#{status1.id}") expect(page).to have_css("#{wp_table.row_selector(wp_2)}.__hl_background_status_#{status2.id}") # Unselect all rows to ensure we get the correct background - find("body").send_keys [:control, "d"] + find('body').send_keys [:control, 'd'] wp1_row = wp_table.row(wp_1) wp2_row = wp_table.row(wp_2) - expect(wp1_row.native.css_value("background-color")).to eq("rgba(255, 0, 0, 1)") - expect(wp2_row.native.css_value("background-color")).to eq("rgba(240, 240, 240, 1)") + expect(wp1_row.native.css_value('background-color')).to eq('rgba(255, 0, 0, 1)') + expect(wp2_row.native.css_value('background-color')).to eq('rgba(240, 240, 240, 1)') # Save query wp_table.save - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' query.reload expect(query.highlighting_mode).to eq(:status) @@ -142,17 +142,17 @@ expect(page).to have_no_css('[class*="__hl_date"]') # Highlight entire row by priority - highlighting.switch_entire_row_highlight "Priority" + highlighting.switch_entire_row_highlight 'Priority' expect(page).to have_css("#{wp_table.row_selector(wp_1)}.__hl_background_priority_#{priority1.id}") expect(page).to have_css("#{wp_table.row_selector(wp_2)}.__hl_background_priority_#{priority_no_color.id}") # Remove selection from table row - find("body").send_keys [:control, "d"] + find('body').send_keys [:control, 'd'] wp1_row = wp_table.row(wp_1) wp2_row = wp_table.row(wp_2) - expect(wp1_row.native.css_value("background-color")).to eq("rgba(18, 52, 86, 1)") - expect(wp2_row.native.css_value("background-color")).to eq("rgba(0, 0, 0, 0)") + expect(wp1_row.native.css_value('background-color')).to eq('rgba(18, 52, 86, 1)') + expect(wp2_row.native.css_value('background-color')).to eq('rgba(0, 0, 0, 0)') # Highlighting is kept even after a hard reload (Regression #30217) page.driver.refresh @@ -164,7 +164,7 @@ # Save query wp_table.save - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' query.reload expect(query.highlighting_mode).to eq(:priority) @@ -174,7 +174,7 @@ expect(page).to have_no_css('[class*="__hl_date"]') # No highlighting - highlighting.switch_highlighting_mode "No highlighting" + highlighting.switch_highlighting_mode 'No highlighting' expect(page).to have_no_css('[class*="__hl_background"]') expect(page).to have_no_css('[class*="__hl_background_status"]') expect(page).to have_no_css('[class*="__hl_background_priority"]') @@ -182,7 +182,7 @@ # Save query wp_table.save - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' query.reload expect(query.highlighting_mode).to eq(:none) @@ -194,25 +194,25 @@ expect(page).to have_css(".__hl_inline_priority_#{priority1.id}") end - it "correctly parses custom selected inline attributes", :with_cuprite do + it 'correctly parses custom selected inline attributes', :with_cuprite do # Highlight only one attribute highlighting.switch_inline_attribute_highlight "Priority" # Regression test, resort table - sort_by.sort_via_header "Subject" + sort_by.sort_via_header 'Subject' wp_table.expect_work_package_order wp_2, wp_1 # Regression test, resort table - sort_by.sort_via_header "Subject", descending: true + sort_by.sort_via_header 'Subject', descending: true wp_table.expect_work_package_order wp_1, wp_2 end - it "does not set query_props when switching in view (Regression #32118)" do + it 'does not set query_props when switching in view (Regression #32118)' do prio_wp1 = wp_table.edit_field(wp_1, :priority) prio_wp1.update priority_no_color.name prio_wp1.expect_state_text priority_no_color.name - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' wp_1.reload expect(wp_1.priority).to eq priority_no_color diff --git a/spec/features/work_packages/index_sums_spec.rb b/spec/features/work_packages/index_sums_spec.rb index 5c894d85da34..ee9097e4027b 100644 --- a/spec/features/work_packages/index_sums_spec.rb +++ b/spec/features/work_packages/index_sums_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package index sums", :js do +RSpec.describe 'Work package index sums', :js do shared_let(:type_bug) { create(:type_bug) } shared_let(:type_task) { create(:type_task) } - shared_let(:status_new) { create(:status, name: "New") } - shared_let(:status_in_progress) { create(:status, name: "In progress") } + shared_let(:status_new) { create(:status, name: 'New') } + shared_let(:status_in_progress) { create(:status, name: 'In progress') } shared_let(:project) { create(:project, types: [type_bug, type_task]) } let(:user) do @@ -96,7 +96,7 @@ end # unit costs let(:cost_type) do - type = create(:cost_type, name: "Translations") + type = create(:cost_type, name: 'Translations') create(:cost_rate, cost_type: type, rate: 3.00) @@ -119,24 +119,24 @@ current_user { user } - it "calculates sums correctly" do + it 'calculates sums correctly' do visit project_work_packages_path(project) wp_table.expect_work_package_listed work_package1, work_package2 # Add work column - columns.add "Work" + columns.add 'Work' # Add remaining work column - columns.add "Remaining work" + columns.add 'Remaining work' # Add int cf column columns.add int_cf.name # Add float cf column columns.add float_cf.name # Add labor costs column - columns.add "Labor costs" + columns.add 'Labor costs' # Add unit costs column - columns.add "Unit costs" + columns.add 'Unit costs' # Add overall costs column - columns.add "Overall costs" + columns.add 'Overall costs' # Trigger action from action menu dropdown modal.set_display_sums enable: true @@ -145,79 +145,79 @@ # Expect the total sums row within(:row, "Total sum") do |row| - expect(row).to have_css(".estimatedTime", text: "25 h") - expect(row).to have_css(".remainingTime", text: "12.5 h") - expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "12") - expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "13.2") - expect(row).to have_css(".laborCosts", text: "15.00 EUR") - expect(row).to have_css(".materialCosts", text: "7.50 EUR") # Unit costs - expect(row).to have_css(".overallCosts", text: "22.50 EUR") + expect(row).to have_css('.estimatedTime', text: '25 h') + expect(row).to have_css('.remainingTime', text: '12.5 h') + expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '12') + expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '13.2') + expect(row).to have_css('.laborCosts', text: '15.00 EUR') + expect(row).to have_css('.materialCosts', text: '7.50 EUR') # Unit costs + expect(row).to have_css('.overallCosts', text: '22.50 EUR') end # Update the sum wp_table.edit_field(work_package1, :estimatedTime) - .update "20" + .update '20' wp_table.edit_field(work_package1, :remainingTime) - .update "12" + .update '12' within(:row, "Total sum") do |row| - expect(row).to have_css(".estimatedTime", text: "35 h") - expect(row).to have_css(".remainingTime", text: "19.5 h") - expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "12") - expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "13.2") - expect(row).to have_css(".laborCosts", text: "15.00 EUR") - expect(row).to have_css(".materialCosts", text: "7.50 EUR") # Unit costs - expect(row).to have_css(".overallCosts", text: "22.50 EUR") + expect(row).to have_css('.estimatedTime', text: '35 h') + expect(row).to have_css('.remainingTime', text: '19.5 h') + expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '12') + expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '13.2') + expect(row).to have_css('.laborCosts', text: '15.00 EUR') + expect(row).to have_css('.materialCosts', text: '7.50 EUR') # Unit costs + expect(row).to have_css('.overallCosts', text: '22.50 EUR') end # Enable groups - group_by.enable_via_menu "Status" + group_by.enable_via_menu 'Status' # Expect to have three sums rows now - expect(page).to have_row("Sum", count: 2) - expect(page).to have_row("Total sum", count: 1) + expect(page).to have_row('Sum', count: 2) + expect(page).to have_row('Total sum', count: 1) - first_sum_row, second_sum_row = *find_all(:row, "Sum") + first_sum_row, second_sum_row = *find_all(:row, 'Sum') # First status row - expect(first_sum_row).to have_css(".estimatedTime", text: "20 h") - expect(first_sum_row).to have_css(".remainingTime", text: "12 h") - expect(first_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "5") - expect(first_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "5.5") - expect(first_sum_row).to have_css(".laborCosts", text: "15.00 EUR") - expect(first_sum_row).to have_css(".materialCosts", text: "7.50 EUR") # Unit costs - expect(first_sum_row).to have_css(".overallCosts", text: "22.50 EUR") + expect(first_sum_row).to have_css('.estimatedTime', text: '20 h') + expect(first_sum_row).to have_css('.remainingTime', text: '12 h') + expect(first_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '5') + expect(first_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '5.5') + expect(first_sum_row).to have_css('.laborCosts', text: '15.00 EUR') + expect(first_sum_row).to have_css('.materialCosts', text: '7.50 EUR') # Unit costs + expect(first_sum_row).to have_css('.overallCosts', text: '22.50 EUR') # Second status row - expect(second_sum_row).to have_css(".estimatedTime", text: "15 h") - expect(second_sum_row).to have_css(".remainingTime", text: "7.5 h") - expect(second_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "7") - expect(second_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "7.7") - expect(second_sum_row).to have_css(".laborCosts", text: "", exact_text: true) - expect(second_sum_row).to have_css(".materialCosts", text: "", exact_text: true) # Unit costs - expect(second_sum_row).to have_css(".overallCosts", text: "", exact_text: true) + expect(second_sum_row).to have_css('.estimatedTime', text: '15 h') + expect(second_sum_row).to have_css('.remainingTime', text: '7.5 h') + expect(second_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '7') + expect(second_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '7.7') + expect(second_sum_row).to have_css('.laborCosts', text: '', exact_text: true) + expect(second_sum_row).to have_css('.materialCosts', text: '', exact_text: true) # Unit costs + expect(second_sum_row).to have_css('.overallCosts', text: '', exact_text: true) # Total sums row is unchanged within(:row, "Total sum") do |row| - expect(row).to have_css(".estimatedTime", text: "35 h") - expect(row).to have_css(".remainingTime", text: "19.5 h") - expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "12") - expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "13.2") - expect(row).to have_css(".laborCosts", text: "15.00 EUR") - expect(row).to have_css(".materialCosts", text: "7.50 EUR") # Unit costs - expect(row).to have_css(".overallCosts", text: "22.50 EUR") + expect(row).to have_css('.estimatedTime', text: '35 h') + expect(row).to have_css('.remainingTime', text: '19.5 h') + expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '12') + expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '13.2') + expect(row).to have_css('.laborCosts', text: '15.00 EUR') + expect(row).to have_css('.materialCosts', text: '7.50 EUR') # Unit costs + expect(row).to have_css('.overallCosts', text: '22.50 EUR') end # Collapsing groups will also hide the sums row - page.find(".expander.icon-minus2", match: :first).click + page.find('.expander.icon-minus2', match: :first).click sleep 1 - page.find(".expander.icon-minus2", match: :first).click + page.find('.expander.icon-minus2', match: :first).click # Expect to have only the final sums - expect(page).not_to have_row("Sum") - expect(page).to have_row("Total sum") + expect(page).not_to have_row('Sum') + expect(page).to have_row('Total sum') end - context "when filtering" do + context 'when filtering' do let!(:work_package3) do create(:work_package, project:, @@ -258,7 +258,7 @@ user:) end - it "calculates sums correctly" do + it 'calculates sums correctly' do query = create(:query, project:, user:, @@ -271,74 +271,74 @@ # Expect the total sums row without filtering within(:row, "Total sum") do |row| - expect(row).to have_css(".estimatedTime", text: "50 h") - expect(row).to have_css(".remainingTime", text: "25 h") - expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "24") - expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "26.4") - expect(row).to have_css(".laborCosts", text: "40.00 EUR") - expect(row).to have_css(".materialCosts", text: "18.00 EUR") # Unit costs - expect(row).to have_css(".overallCosts", text: "58.00 EUR") + expect(row).to have_css('.estimatedTime', text: '50 h') + expect(row).to have_css('.remainingTime', text: '25 h') + expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '24') + expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '26.4') + expect(row).to have_css('.laborCosts', text: '40.00 EUR') + expect(row).to have_css('.materialCosts', text: '18.00 EUR') # Unit costs + expect(row).to have_css('.overallCosts', text: '58.00 EUR') end # Filter filters.open - filters.add_filter_by("Type", "is (OR)", type_task.name) + filters.add_filter_by('Type', 'is (OR)', type_task.name) puts Capybara::Screenshot.screenshot_and_save_page # Expect 2 work packages shown - expect(page).to have_row("WorkPackage", count: 2) # works because the subject name includes "WorkPackage" + expect(page).to have_row('WorkPackage', count: 2) # works because the subject name includes "WorkPackage" # Expect the total sums row to have changed within(:row, "Total sum") do |row| - expect(row).to have_css(".estimatedTime", text: "30 h") - expect(row).to have_css(".remainingTime", text: "15 h") - expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "14") - expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "15.4") - expect(row).to have_css(".laborCosts", text: "", exact_text: true) - expect(row).to have_css(".materialCosts", text: "", exact_text: true) # Unit costs - expect(row).to have_css(".overallCosts", text: "", exact_text: true) + expect(row).to have_css('.estimatedTime', text: '30 h') + expect(row).to have_css('.remainingTime', text: '15 h') + expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '14') + expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '15.4') + expect(row).to have_css('.laborCosts', text: '', exact_text: true) + expect(row).to have_css('.materialCosts', text: '', exact_text: true) # Unit costs + expect(row).to have_css('.overallCosts', text: '', exact_text: true) end # Filter by status open - filters.remove_filter("type") - filters.remove_filter("status") - filters.add_filter_by("Status", "is (OR)", status_new.name) + filters.remove_filter('type') + filters.remove_filter('status') + filters.add_filter_by('Status', 'is (OR)', status_new.name) # Enable groups by type - group_by.enable_via_menu "Type" + group_by.enable_via_menu 'Type' # Expect to have three sums rows now - expect(page).to have_row("Sum", count: 2) - expect(page).to have_row("Total sum", count: 1) + expect(page).to have_row('Sum', count: 2) + expect(page).to have_row('Total sum', count: 1) - first_sum_row, second_sum_row = *find_all(:row, "Sum") + first_sum_row, second_sum_row = *find_all(:row, 'Sum') # First status row - expect(first_sum_row).to have_css(".estimatedTime", text: "10 h") - expect(first_sum_row).to have_css(".remainingTime", text: "5 h") - expect(first_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "5") - expect(first_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "5.5") - expect(first_sum_row).to have_css(".laborCosts", text: "15.00 EUR") - expect(first_sum_row).to have_css(".materialCosts", text: "7.50 EUR") # Unit costs - expect(first_sum_row).to have_css(".overallCosts", text: "22.50 EUR") + expect(first_sum_row).to have_css('.estimatedTime', text: '10 h') + expect(first_sum_row).to have_css('.remainingTime', text: '5 h') + expect(first_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '5') + expect(first_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '5.5') + expect(first_sum_row).to have_css('.laborCosts', text: '15.00 EUR') + expect(first_sum_row).to have_css('.materialCosts', text: '7.50 EUR') # Unit costs + expect(first_sum_row).to have_css('.overallCosts', text: '22.50 EUR') # Second status row - expect(second_sum_row).to have_css(".estimatedTime", text: "15 h") - expect(second_sum_row).to have_css(".remainingTime", text: "7.5 h") - expect(second_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "7") - expect(second_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "7.7") - expect(second_sum_row).to have_css(".laborCosts", text: "", exact_text: true) - expect(second_sum_row).to have_css(".materialCosts", text: "", exact_text: true) # Unit costs - expect(second_sum_row).to have_css(".overallCosts", text: "", exact_text: true) + expect(second_sum_row).to have_css('.estimatedTime', text: '15 h') + expect(second_sum_row).to have_css('.remainingTime', text: '7.5 h') + expect(second_sum_row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '7') + expect(second_sum_row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '7.7') + expect(second_sum_row).to have_css('.laborCosts', text: '', exact_text: true) + expect(second_sum_row).to have_css('.materialCosts', text: '', exact_text: true) # Unit costs + expect(second_sum_row).to have_css('.overallCosts', text: '', exact_text: true) # Total sum within(:row, "Total sum") do |row| - expect(row).to have_css(".estimatedTime", text: "25 h") - expect(row).to have_css(".remainingTime", text: "12.5 h") - expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: "12") - expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: "13.2") - expect(row).to have_css(".laborCosts", text: "15.00 EUR") - expect(row).to have_css(".materialCosts", text: "7.50 EUR") # Unit costs - expect(row).to have_css(".overallCosts", text: "22.50 EUR") + expect(row).to have_css('.estimatedTime', text: '25 h') + expect(row).to have_css('.remainingTime', text: '12.5 h') + expect(row).to have_css(".#{int_cf.attribute_name(:camel_case)}", text: '12') + expect(row).to have_css(".#{float_cf.attribute_name(:camel_case)}", text: '13.2') + expect(row).to have_css('.laborCosts', text: '15.00 EUR') + expect(row).to have_css('.materialCosts', text: '7.50 EUR') # Unit costs + expect(row).to have_css('.overallCosts', text: '22.50 EUR') end end end diff --git a/spec/features/work_packages/navigation_spec.rb b/spec/features/work_packages/navigation_spec.rb index 059d7e3cae51..a5d04cc97547 100644 --- a/spec/features/work_packages/navigation_spec.rb +++ b/spec/features/work_packages/navigation_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package navigation", :js, :selenium do +RSpec.describe 'Work package navigation', :js, :selenium do let(:user) { create(:admin) } - let(:project) { create(:project, name: "Some project", enabled_module_names: [:work_package_tracking]) } + let(:project) { create(:project, name: 'Some project', enabled_module_names: [:work_package_tracking]) } let(:work_package) { build(:work_package, project:) } let(:global_html_title) { Components::HtmlTitle.new } let(:project_html_title) { Components::HtmlTitle.new project } @@ -54,7 +54,7 @@ login_as(user) end - it "all different angular based work package views" do + it 'all different angular based work package views' do work_package.save! # deep link global work package index @@ -62,7 +62,7 @@ global_work_packages.visit! global_work_packages.expect_work_package_listed(work_package) - global_html_title.expect_first_segment "All open" + global_html_title.expect_first_segment 'All open' # open details pane for work package @@ -97,17 +97,17 @@ project_work_packages.visit! project_work_packages.expect_work_package_listed(work_package) - project_html_title.expect_first_segment "All open" + project_html_title.expect_first_segment 'All open' # Visit query with project wp project_work_packages.visit_query query project_work_packages.expect_work_package_listed(work_package) - project_html_title.expect_first_segment "My fancy query" + project_html_title.expect_first_segment 'My fancy query' # Go back to work packages without query - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') project_work_packages.expect_work_package_listed(work_package) - project_html_title.expect_first_segment "All open" + project_html_title.expect_first_segment 'All open' # open project work package details pane @@ -121,12 +121,12 @@ full_work_package = split_project_work_package.switch_to_fullscreen full_work_package.expect_subject - expect(page).to have_current_path project_work_package_path(project, work_package, "activity") + expect(page).to have_current_path project_work_package_path(project, work_package, 'activity') project_html_title.expect_first_segment wp_title_segment # Switch tabs full_work_package.switch_to_tab tab: :relations - expect(page).to have_current_path project_work_package_path(project, work_package, "relations") + expect(page).to have_current_path project_work_package_path(project, work_package, 'relations') project_html_title.expect_first_segment wp_title_segment # Back to split screen using the button @@ -145,66 +145,66 @@ full_work_package.ensure_page_loaded end - it "loading an unknown work package ID" do - visit "/work_packages/999999999" + it 'loading an unknown work package ID' do + visit '/work_packages/999999999' page404 = Pages::Page.new page404.expect_toast type: :error, message: I18n.t(:notice_file_not_found) visit "/projects/#{project.identifier}/work_packages/999999999" - page404.expect_and_dismiss_toaster type: :error, message: I18n.t("api_v3.errors.not_found.work_package") + page404.expect_and_dismiss_toaster type: :error, message: I18n.t('api_v3.errors.not_found.work_package') end # Regression #29994 - it "access the work package views directly from a non-angular view" do + it 'access the work package views directly from a non-angular view' do visit project_path(project) - find("#main-menu-work-packages ~ .toggler").click - expect(page).to have_css(".op-view-select--search-results") - find(".op-sidemenu--item-action", text: query.name).click + find('#main-menu-work-packages ~ .toggler').click + expect(page).to have_css('.op-view-select--search-results') + find('.op-sidemenu--item-action', text: query.name).click - expect(page).to have_no_css(".title-container", text: "Overview") - expect(page).to have_field("editable-toolbar-title", with: query.name) + expect(page).to have_no_css('.title-container', text: 'Overview') + expect(page).to have_field('editable-toolbar-title', with: query.name) end - it "double clicking search result row (Regression #30247)" do - work_package.subject = "Foobar" + it 'double clicking search result row (Regression #30247)' do + work_package.subject = 'Foobar' work_package.save! - visit search_path(q: "Foo", work_packages: 1, scope: :all) + visit search_path(q: 'Foo', work_packages: 1, scope: :all) - table = Pages::EmbeddedWorkPackagesTable.new page.find_by_id("content") + table = Pages::EmbeddedWorkPackagesTable.new page.find_by_id('content') table.expect_work_package_listed work_package full_page = table.open_full_screen_by_doubleclick work_package full_page.ensure_page_loaded end - it "double clicking my page (Regression #30343)" do + it 'double clicking my page (Regression #30343)' do work_package.author = user - work_package.subject = "Foobar" + work_package.subject = 'Foobar' work_package.save! visit my_page_path - page.find(".wp-table--cell-td.id a", text: work_package.id).click + page.find('.wp-table--cell-td.id a', text: work_package.id).click full_page = Pages::FullWorkPackage.new work_package, work_package.project full_page.ensure_page_loaded end - describe "moving back to filtered list after change" do - let!(:work_package) { create(:work_package, project:, subject: "foo") } + describe 'moving back to filtered list after change' do + let!(:work_package) { create(:work_package, project:, subject: 'foo') } let!(:query) do query = build(:query, user:, project:) query.column_names = %w(id subject) query.name = "My fancy query" - query.add_filter("subject", "~", ["foo"]) + query.add_filter('subject', '~', ['foo']) query.save! query end - it "filters out the work package" do + it 'filters out the work package' do wp_table = Pages::WorkPackagesTable.new project wp_table.visit! @@ -213,9 +213,9 @@ full_view.ensure_page_loaded subject = full_view.edit_field :subject - subject.update "bar" + subject.update 'bar' - full_view.expect_and_dismiss_toaster message: "Successful update." + full_view.expect_and_dismiss_toaster message: 'Successful update.' # Go back to list full_view.go_back @@ -224,13 +224,13 @@ end end - context "with work package with an attachment" do - let!(:attachment) { build(:attachment, filename: "attachment-first.pdf") } + context 'with work package with an attachment' do + let!(:attachment) { build(:attachment, filename: 'attachment-first.pdf') } let!(:wp_with_attachment) do - create(:work_package, subject: "WP attachment A", project:, attachments: [attachment]) + create(:work_package, subject: 'WP attachment A', project:, attachments: [attachment]) end - it "shows it when navigating from table to single view" do + it 'shows it when navigating from table to single view' do wp_table = Pages::WorkPackagesTable.new project wp_table.visit! @@ -238,16 +238,16 @@ full_view = wp_table.open_full_screen_by_link wp_with_attachment full_view.ensure_page_loaded - full_view.switch_to_tab(tab: "FILES") + full_view.switch_to_tab(tab: 'FILES') expect(page) - .to have_test_selector("op-files-tab--file-list-item-title", text: "attachment-first.pdf", wait: 10) + .to have_test_selector('op-files-tab--file-list-item-title', text: 'attachment-first.pdf', wait: 10) end end - context "when visiting a query that will lead to a query validation error" do + context 'when visiting a query that will lead to a query validation error' do let(:wp_table) { Pages::WorkPackagesTable.new(project) } - it "outputs a correct error message (Regression #39880)" do + it 'outputs a correct error message (Regression #39880)' do url_query = "query_id=%7B%22%7B%22&query_props=%7B%22c%22%3A%5B%22id%22%2C%22subject" \ "%22%2C%22type%22%2C%22status%22%2C%22assignee%22%2C%22updatedAt%22%5D%2C" \ @@ -258,8 +258,8 @@ visit "/projects/#{project.identifier}/work_packages?#{url_query}" - wp_table.expect_toast message: "Your view is erroneous and could not be processed.", type: :error - expect(page).to have_css "li", text: "Bad request: id is invalid" + wp_table.expect_toast message: 'Your view is erroneous and could not be processed.', type: :error + expect(page).to have_css 'li', text: 'Bad request: id is invalid' end end end diff --git a/spec/features/work_packages/new/attributes_from_filter_spec.rb b/spec/features/work_packages/new/attributes_from_filter_spec.rb index b4b11875d198..cb5de138a92a 100644 --- a/spec/features/work_packages/new/attributes_from_filter_spec.rb +++ b/spec/features/work_packages/new/attributes_from_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package create uses attributes from filters", :js, :selenium do +RSpec.describe 'Work package create uses attributes from filters', :js, :selenium do let(:user) { create(:admin) } let(:type_bug) { create(:type_bug) } let(:type_task) { create(:type_task) } @@ -50,13 +50,13 @@ query.add_filter(*filter) end - query.column_names = ["id", "subject", "type", "assigned_to", "status"] + query.column_names = ['id', 'subject', 'type', 'assigned_to', 'status'] query.save! end end let(:filters) do - [["type_id", "=", [type_task.id]]] + [['type_id', '=', [type_task.id]]] end before do @@ -65,7 +65,7 @@ wp_table.expect_no_work_package_listed end - context "with a multi-value custom field" do + context 'with a multi-value custom field' do let(:type_task) { create(:type_task, custom_fields: [custom_field]) } let!(:project) do create(:project, @@ -86,42 +86,42 @@ end let(:filters) do - [["type_id", "=", [type_task.id]], - [custom_field.column_name, "=", [custom_field.custom_options.detect { |o| o.value == "A" }.id]]] + [['type_id', '=', [type_task.id]], + [custom_field.column_name, '=', [custom_field.custom_options.detect { |o| o.value == 'A' }.id]]] end - it "allows to save with a single value (Regression test #27833)" do + it 'allows to save with a single value (Regression test #27833)' do split_page = wp_table.create_wp_by_button type_task subject = split_page.edit_field(:subject) subject.expect_active! - subject.set_value "Foobar!" + subject.set_value 'Foobar!' split_page.save! wp_table.expect_and_dismiss_toaster( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) wp = WorkPackage.last - expect(wp.subject).to eq "Foobar!" + expect(wp.subject).to eq 'Foobar!' expect(wp.send(custom_field.attribute_getter)).to eq %w(A) expect(wp.type_id).to eq type_task.id end end - context "with assignee filter" do + context 'with assignee filter' do let!(:assignee) do create(:user, - firstname: "An", - lastname: "assignee", + firstname: 'An', + lastname: 'assignee', member_with_roles: { project => role }) end let(:filters) do - [["type_id", "=", [type_task.id]], - ["assigned_to_id", "=", [assignee.id]]] + [['type_id', '=', [type_task.id]], + ['assigned_to_id', '=', [assignee.id]]] end - it "uses the assignee filter in inline-create and split view" do + it 'uses the assignee filter in inline-create and split view' do wp_table.click_inline_create subject_field = wp_table.edit_field(nil, :subject) @@ -136,16 +136,16 @@ assignee_field.expect_state_text type_task.name.upcase # Save the WP - subject_field.set_value "Foobar!" + subject_field.set_value 'Foobar!' subject_field.submit_by_enter wp_table.expect_toast( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) wp_table.dismiss_toaster! wp = WorkPackage.last - expect(wp.subject).to eq "Foobar!" + expect(wp.subject).to eq 'Foobar!' expect(wp.assigned_to_id).to eq assignee.id expect(wp.type_id).to eq type_task.id @@ -155,7 +155,7 @@ # Subject subject_field = split_view_create.edit_field :subject subject_field.expect_active! - subject_field.set_value "Split Foobar!" + subject_field.set_value 'Split Foobar!' # Type field IS NOT synced type_field = split_view_create.edit_field :type @@ -163,28 +163,28 @@ # Assignee is synced assignee_field = split_view_create.edit_field :assignee - expect(assignee_field.input_element.find(".ng-value-label").text).to eql("An assignee") + expect(assignee_field.input_element.find('.ng-value-label').text).to eql('An assignee') - within ".work-packages--edit-actions" do - click_button "Save" + within '.work-packages--edit-actions' do + click_button 'Save' end - wp_table.expect_toast(message: "Successful creation.") + wp_table.expect_toast(message: 'Successful creation.') wp = WorkPackage.last - expect(wp.subject).to eq "Split Foobar!" + expect(wp.subject).to eq 'Split Foobar!' expect(wp.assigned_to_id).to eq assignee.id expect(wp.type_id).to eq type_bug.id end end - context "with status filter" do + context 'with status filter' do let(:closed_status) { create(:closed_status, workflow_for_type: type_bug) } let(:filters) do - [["status_id", "=", [closed_status.id]]] + [['status_id', '=', [closed_status.id]]] end - it "uses the status filter in inline-create and split view" do + it 'uses the status filter in inline-create and split view' do # When the chosen type ( type_task ) does not have a workflow for the status (closed_status) # of the filter, it uses the default status instead (Regression #36719) wp_table.click_inline_create @@ -199,16 +199,16 @@ # Save the WP subject_field = wp_table.edit_field(nil, :subject) - subject_field.set_value "Foobar!" + subject_field.set_value 'Foobar!' subject_field.submit_by_enter wp_table.expect_toast( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) wp_table.dismiss_toaster! wp = WorkPackage.last - expect(wp.subject).to eq "Foobar!" + expect(wp.subject).to eq 'Foobar!' expect(wp.type_id).to eq type_task.id expect(wp.status_id).to eq default_status.id @@ -220,7 +220,7 @@ subject_field = split_view_create.edit_field :subject subject_field.expect_active! - subject_field.set_value "Split Foobar!" + subject_field.set_value 'Split Foobar!' # Type field IS NOT synced type_field = split_view_create.edit_field :type @@ -230,14 +230,14 @@ status_field = split_view_create.edit_field :status status_field.expect_display_value(closed_status.name.humanize) - within ".work-packages--edit-actions" do - click_button "Save" + within '.work-packages--edit-actions' do + click_button 'Save' end - wp_table.expect_toast(message: "Successful creation.") + wp_table.expect_toast(message: 'Successful creation.') wp = WorkPackage.last - expect(wp.subject).to eq "Split Foobar!" + expect(wp.subject).to eq 'Split Foobar!' expect(wp.type_id).to eq type_bug.id expect(wp.status_id).to eq closed_status.id @@ -251,7 +251,7 @@ subject_field = split_view_create.edit_field :subject subject_field.expect_active! - subject_field.set_value "Split Foobar!" + subject_field.set_value 'Split Foobar!' # Type field IS NOT synced type_field = split_view_create.edit_field :type @@ -261,14 +261,14 @@ status_field = split_view_create.edit_field :status status_field.expect_display_value(default_status.name.humanize) - within ".work-packages--edit-actions" do - click_button "Save" + within '.work-packages--edit-actions' do + click_button 'Save' end - wp_table.expect_toast(message: "Successful creation.") + wp_table.expect_toast(message: 'Successful creation.') wp = WorkPackage.last - expect(wp.subject).to eq "Split Foobar!" + expect(wp.subject).to eq 'Split Foobar!' expect(wp.type_id).to eq type_task.id expect(wp.status_id).to eq default_status.id end diff --git a/spec/features/work_packages/new/new_work_package_datepicker_spec.rb b/spec/features/work_packages/new/new_work_package_datepicker_spec.rb index 7cabade98d1f..023798ee13da 100644 --- a/spec/features/work_packages/new/new_work_package_datepicker_spec.rb +++ b/spec/features/work_packages/new/new_work_package_datepicker_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/page_objects/notification' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' -RSpec.describe "New work package datepicker", - :js, :with_cuprite, with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'New work package datepicker', + :js, :with_cuprite, with_settings: { date_format: '%Y-%m-%d' } do let(:project) { create(:project_with_types, public: true) } let(:user) { create(:admin) } @@ -48,7 +48,7 @@ wait_for_reload end - it "can open and select the datepicker" do + it 'can open and select the datepicker' do date_field.input_element.click date_field.toggle_ignore_non_working_days diff --git a/spec/features/work_packages/new/new_work_package_spec.rb b/spec/features/work_packages/new/new_work_package_spec.rb index f3cb6eda8511..2f705a3c2b25 100644 --- a/spec/features/work_packages/new/new_work_package_spec.rb +++ b/spec/features/work_packages/new/new_work_package_spec.rb @@ -1,9 +1,9 @@ -require "spec_helper" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" -require "features/page_objects/notification" +require 'spec_helper' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' +require 'features/page_objects/notification' -RSpec.describe "new work package", :js, :with_cuprite do +RSpec.describe 'new work package', :js, :with_cuprite do shared_let(:status) { create(:status, is_default: true) } shared_let(:priority) { create(:priority, is_default: true) } shared_let(:type_task) { create(:type_task) } @@ -21,8 +21,8 @@ let(:work_packages_page) { WorkPackagesPage.new(project) } - let(:subject) { "My subject" } - let(:description) { "A description of the newly-created work package." } + let(:subject) { 'My subject' } + let(:description) { 'A description of the newly-created work package.' } let(:subject_field) { wp_page.edit_field :subject } let(:description_field) { wp_page.edit_field :description } @@ -36,10 +36,10 @@ def disable_leaving_unsaved_warning end def save_work_package!(expect_success = true) - scroll_to_and_click find_by_id("work-packages--edit-actions-save") + scroll_to_and_click find_by_id('work-packages--edit-actions-save') if expect_success - toaster.expect_success("Successful creation.") + toaster.expect_success('Successful creation.') end end @@ -53,7 +53,7 @@ def click_create_work_package_button(type) def create_work_package(type, *) click_create_work_package_button(type) - expect(page).to have_focus_on("#wp-new-inline-edit--field-subject") + expect(page).to have_focus_on('#wp-new-inline-edit--field-subject') wp_page.subject_field.set(subject) wait_for_network_idle @@ -81,21 +81,21 @@ def create_work_package_globally(type, project_name) login_as(user) end - shared_examples "work package creation workflow" do + shared_examples 'work package creation workflow' do before do create_method.call(type_task, project.name) expect(page).to have_selector(safeguard_selector, wait: 10) end - it "creates a subsequent work package" do + it 'creates a subsequent work package' do wp_page.subject_field.set(subject) save_work_package! # safeguards wp_page.dismiss_toaster! wp_page.expect_no_toaster( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) subject_field.expect_state_text(subject) @@ -107,7 +107,7 @@ def create_work_package_globally(type, project_name) type_field.expect_state_text /#{type_bug.name}/i end - it "saves the work package with enter" do + it 'saves the work package with enter' do subject_field = wp_page.subject_field subject_field.set(subject) subject_field.send_keys(:enter) @@ -115,20 +115,20 @@ def create_work_package_globally(type, project_name) # safeguards wp_page.dismiss_toaster! wp_page.expect_no_toaster( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) wp_page.edit_field(:subject).expect_text(subject) end - context "with missing values" do - it "shows an error when subject is missing" do + context 'with missing values' do + it 'shows an error when subject is missing' do description_field.set_value(description) # Need to send keys to emulate change subject_field = wp_page.subject_field - subject_field.set("") - subject_field.send_keys("a") + subject_field.set('') + subject_field.send_keys('a') subject_field.send_keys(:backspace) save_work_package!(false) @@ -136,20 +136,20 @@ def create_work_package_globally(type, project_name) end end - context "with subject set" do - it "creates a basic work package" do + context 'with subject set' do + it 'creates a basic work package' do description_field = wp_page.edit_field :description description_field.set_value description save_work_package! - expect(page).to have_css(".op-work-package-tabs") + expect(page).to have_css('.op-work-package-tabs') subject_field.expect_state_text(subject) description_field = wp_page.edit_field :description description_field.expect_state_text(description) end - it "can switch types and keep attributes" do + it 'can switch types and keep attributes' do wp_page.subject_field.set(subject) type_field.activate! type_field.openSelectField @@ -161,11 +161,11 @@ def create_work_package_globally(type, project_name) wp_page.expect_attributes type: type_bug.name.upcase end - context "custom fields" do + context 'custom fields' do let(:custom_field1) do create( :work_package_custom_field, - field_format: "string", + field_format: 'string', is_required: true, is_for_all: true ) @@ -173,7 +173,7 @@ def create_work_package_globally(type, project_name) let(:custom_field2) do create( :work_package_custom_field, - field_format: "list", + field_format: 'list', possible_values: %w(foo bar xyz), is_required: false, is_for_all: true @@ -197,25 +197,25 @@ def create_work_package_globally(type, project_name) expect(page).to have_css(".#{custom_fields.last.attribute_name(:camel_case)} ng-select") cf = wp_page.edit_field custom_fields.last.attribute_name(:camel_case) - cf.field_type = "create-autocompleter" + cf.field_type = 'create-autocompleter' cf.openSelectField - cf.set_value "foo" + cf.set_value 'foo' save_work_package!(false) toaster.expect_error("#{custom_field1.name} can't be blank.") - cf1.set "Custom field content" + cf1.set 'Custom field content' save_work_package!(true) - wp_page.expect_attributes "customField#{custom_field1.id}" => "Custom field content", - "customField#{custom_field2.id}" => "foo" + wp_page.expect_attributes "customField#{custom_field1.id}" => 'Custom field content', + "customField#{custom_field2.id}" => 'foo' end end end end - context "project split screen" do - let(:safeguard_selector) { ".work-packages--details-content.-create-mode" } + context 'project split screen' do + let(:safeguard_selector) { '.work-packages--details-content.-create-mode' } let(:wp_page) { Pages::SplitWorkPackage.new(WorkPackage.new) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -223,38 +223,38 @@ def create_work_package_globally(type, project_name) wp_table.visit! end - it_behaves_like "work package creation workflow" do + it_behaves_like 'work package creation workflow' do let(:create_method) { method(:create_work_package) } end - it "allows to go to the full page through the toaster (Regression #37555)" do + it 'allows to go to the full page through the toaster (Regression #37555)' do create_work_package(type_task) save_work_package! - wp_page.expect_toast message: "Successful creation. Click here to open this work package in fullscreen view." - page.find(".op-toast--target-link", text: "Click here to open this work package in fullscreen view.").click + wp_page.expect_toast message: 'Successful creation. Click here to open this work package in fullscreen view.' + page.find('.op-toast--target-link', text: 'Click here to open this work package in fullscreen view.').click full_page = Pages::FullWorkPackage.new(WorkPackage.last) full_page.ensure_page_loaded full_page.expect_subject end - it "reloads the table and selects the new work package" do - expect(page).to have_no_css(".wp--row") + it 'reloads the table and selects the new work package' do + expect(page).to have_no_css('.wp--row') create_work_package(type_task) expect(page).to have_selector(safeguard_selector, wait: 10) - wp_page.subject_field.set("new work package") + wp_page.subject_field.set('new work package') save_work_package! wp_page.dismiss_toaster! - expect(page).to have_css(".wp--row.-checked") + expect(page).to have_css('.wp--row.-checked') # Editing the subject after creation # Fix for WP #23879 new_wp = WorkPackage.last - new_subject = "new subject" + new_subject = 'new subject' table_subject = wp_table.edit_field(new_wp, :subject) table_subject.activate! table_subject.set_value new_subject @@ -262,7 +262,7 @@ def create_work_package_globally(type, project_name) table_subject.expect_state_text new_subject wp_page.expect_toast( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) new_wp.reload @@ -274,8 +274,8 @@ def create_work_package_globally(type, project_name) end end - context "full screen" do - let(:safeguard_selector) { ".work-package--new-state" } + context 'full screen' do + let(:safeguard_selector) { '.work-package--new-state' } let(:existing_wp) { create(:work_package, type: type_bug, project:) } let(:wp_page) { Pages::FullWorkPackage.new(existing_wp) } @@ -284,12 +284,12 @@ def create_work_package_globally(type, project_name) wp_page.ensure_page_loaded end - it "displays chosen date attribute for milestone type (#44701)" do + it 'displays chosen date attribute for milestone type (#44701)' do click_create_work_package_button(type_milestone) date_field = wp_page.edit_field(:date) - date_field.expect_value(I18n.t("js.label_no_date")) + date_field.expect_value(I18n.t('js.label_no_date')) # Set date date_field.click_to_open_datepicker @@ -301,13 +301,13 @@ def create_work_package_globally(type, project_name) date_field.expect_value date end - it_behaves_like "work package creation workflow" do + it_behaves_like 'work package creation workflow' do let(:create_method) { method(:create_work_package) } end end - context "global split screen" do - let(:safeguard_selector) { ".work-packages--details-content.-create-mode" } + context 'global split screen' do + let(:safeguard_selector) { '.work-packages--details-content.-create-mode' } let(:wp_page) { Pages::SplitWorkPackage.new(WorkPackage.new) } let(:wp_table) { Pages::WorkPackagesTable.new(nil) } @@ -315,38 +315,38 @@ def create_work_package_globally(type, project_name) wp_table.visit! end - it_behaves_like "work package creation workflow" do + it_behaves_like 'work package creation workflow' do let(:create_method) { method(:create_work_package_globally) } end - it "can stop and re-create with correct selection (Regression #30216)" do + it 'can stop and re-create with correct selection (Regression #30216)' do create_work_package_globally(type_bug, project.name) - click_on "Cancel" + click_on 'Cancel' wp_page.click_create_wp_button type_bug - expect(page).to have_no_css(".ng-value", text: project.name) + expect(page).to have_no_css('.ng-value', text: project.name) project_field.openSelectField project_field.set_value project.name - click_on "Cancel" + click_on 'Cancel' end - it "sets a default date that is readable (Regression #34291)" do + it 'sets a default date that is readable (Regression #34291)' do create_work_package_globally(type_bug, project.name) date_field = wp_page.edit_field(:combinedDate) date_field.expect_value("no start date - no finish date") - click_on "Cancel" + click_on 'Cancel' end - it "can save the work package with an assignee (Regression #32887)" do + it 'can save the work package with an assignee (Regression #32887)' do create_work_package_globally(type_task, project.name) expect(page).to have_selector(safeguard_selector, wait: 10) - wp_page.subject_field.set("new work package") + wp_page.subject_field.set('new work package') save_work_package! wp_page.dismiss_toaster! @@ -355,7 +355,7 @@ def create_work_package_globally(type, project_name) expect(wp.assigned_to).to eq user end - it "resets the dates when opening the datepicker and cancelling (Regression #44152)" do + it 'resets the dates when opening the datepicker and cancelling (Regression #44152)' do create_work_package_globally(type_task, project.name) expect(page).to have_selector(safeguard_selector, wait: 10) @@ -372,26 +372,26 @@ def create_work_package_globally(type, project_name) # Cancel date_field.cancel_by_click - date_field.expect_value "no start date - no finish date" + date_field.expect_value 'no start date - no finish date' end - context "with a project without type_bug" do + context 'with a project without type_bug' do let!(:project_without_bug) do - create(:project, name: "Unrelated project", types: [type_task]) + create(:project, name: 'Unrelated project', types: [type_task]) end - it "does not show that value in the project drop down" do + it 'does not show that value in the project drop down' do create_work_package_globally(type_bug, project.name) project_field.openSelectField - expect(page).to have_css(".ng-dropdown-panel .ng-option", text: project.name) - expect(page).to have_no_css(".ng-dropdown-panel .ng-option", text: project_without_bug.name) + expect(page).to have_css('.ng-dropdown-panel .ng-option', text: project.name) + expect(page).to have_no_css('.ng-dropdown-panel .ng-option', text: project_without_bug.name) end end end - context "as a user with no permissions" do + context 'as a user with no permissions' do let(:role) { create(:project_role, permissions: %i(view_work_packages)) } let(:user) { create(:user, member_with_roles: { project => role }) } let(:wp_page) { Pages::Page.new } @@ -405,15 +405,15 @@ def create_work_package_globally(type, project_name) ] end - it "shows a 403 error on creation paths" do + it 'shows a 403 error on creation paths' do paths.each do |path| visit path - wp_page.expect_toast(type: :error, message: I18n.t("api_v3.errors.code_403")) + wp_page.expect_toast(type: :error, message: I18n.t('api_v3.errors.code_403')) end end end - context "as a user with add_work_packages permission, but not edit_work_packages permission (Regression 28580)" do + context 'as a user with add_work_packages permission, but not edit_work_packages permission (Regression 28580)' do let(:role) { create(:project_role, permissions: %i(view_work_packages add_work_packages)) } let(:user) { create(:user, member_with_roles: { project => role }) } let(:wp_page) { Pages::FullWorkPackageCreate.new } @@ -422,15 +422,15 @@ def create_work_package_globally(type, project_name) visit new_project_work_packages_path(project) end - it "can create the work package, but not update it after saving" do + it 'can create the work package, but not update it after saving' do type_field.activate! type_field.set_value type_bug.name # wait after the type change sleep(0.2) - subject_field.update("new work package", save: true) + subject_field.update('new work package', save: true) wp_page.expect_and_dismiss_toaster( - message: "Successful creation." + message: 'Successful creation.' ) subject_field.expect_read_only @@ -439,7 +439,7 @@ def create_work_package_globally(type, project_name) end end - context "an anonymous user is prompted to login" do + context 'an anonymous user is prompted to login' do let(:user) { create(:anonymous) } let(:wp_page) { Pages::Page.new } @@ -452,7 +452,7 @@ def create_work_package_globally(type, project_name) ] end - it "shows a 403 error on creation paths" do + it 'shows a 403 error on creation paths' do paths.each do |path| visit path expect(wp_page.current_url).to match /#{signin_path}\?back_url=/ @@ -460,7 +460,7 @@ def create_work_package_globally(type, project_name) end end - context "creating child work packages" do + context 'creating child work packages' do let!(:parent) do create(:work_package, project:, @@ -474,64 +474,64 @@ def create_work_package_globally(type, project_name) let(:wp_page) { Pages::FullWorkPackage.new(parent) } let(:wp_page_create) { Pages::FullWorkPackageCreate.new(project:) } - it "from within the table" do + it 'from within the table' do work_packages_page.visit_index context_menu.open_for(parent) - context_menu.choose("Create new child") + context_menu.choose('Create new child') # The dates are taken over from the parent by default date_field = split_create_page.edit_field(:combinedDate) date_field.expect_value("#{parent.start_date} - #{parent.due_date}") date_field.click_to_open_datepicker - date_field.update ["", parent.due_date] + date_field.update ['', parent.due_date] subject = split_create_page.edit_field(:subject) - subject.set_value "Child" + subject.set_value 'Child' split_create_page.save! - split_create_page.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_create")) + split_create_page.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_create')) split_create_page.expect_attributes(combinedDate: "no start date - #{parent.due_date.strftime('%m/%d/%Y')}") - expect(split_create_page).to have_test_selector("op-wp-breadcrumb", text: "Parent:\n#{parent.subject}") + expect(split_create_page).to have_test_selector('op-wp-breadcrumb', text: "Parent:\n#{parent.subject}") end - it "can navigate to the fullscreen page (Regression #49565)" do + it 'can navigate to the fullscreen page (Regression #49565)' do work_packages_page.visit_index context_menu.open_for(parent) - context_menu.choose("Create new child") + context_menu.choose('Create new child') subject_field = split_create_page.edit_field(:subject) - subject_field.set_value "My subtask" + subject_field.set_value 'My subtask' - find(".work-packages-show-view-button").click + find('.work-packages-show-view-button').click expect(split_create_page).not_to have_alert_dialog subject_field = wp_page_create.edit_field(:subject) - subject_field.expect_value "My subtask" + subject_field.expect_value 'My subtask' end - it "from the relations tab" do - wp_page.visit_tab!("relations") + it 'from the relations tab' do + wp_page.visit_tab!('relations') - click_button("Create new child") + click_button('Create new child') subject = EditField.new wp_page, :subject - subject.set_value "Child" + subject.set_value 'Child' subject.submit_by_enter - wp_page.expect_and_dismiss_toaster(message: I18n.t("js.notice_successful_create")) + wp_page.expect_and_dismiss_toaster(message: I18n.t('js.notice_successful_create')) # Move to the newly created child wp_page.find("wp-children-query tbody.results-tbody tr").double_click wp_page.expect_attributes(combinedDate: "#{parent.start_date.strftime('%m/%d/%Y')} - #{parent.due_date.strftime('%m/%d/%Y')}") - expect(wp_page).to have_test_selector("op-wp-breadcrumb", text: "Parent:\n#{parent.subject}") + expect(wp_page).to have_test_selector('op-wp-breadcrumb', text: "Parent:\n#{parent.subject}") end end end diff --git a/spec/features/work_packages/new/work_package_default_description_spec.rb b/spec/features/work_packages/new/work_package_default_description_spec.rb index d905d29feb8f..3d3305b4098b 100644 --- a/spec/features/work_packages/new/work_package_default_description_spec.rb +++ b/spec/features/work_packages/new/work_package_default_description_spec.rb @@ -1,9 +1,9 @@ -require "spec_helper" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" -require "features/page_objects/notification" +require 'spec_helper' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' +require 'features/page_objects/notification' -RSpec.describe "new work package", :js do +RSpec.describe 'new work package', :js do let(:type_task) { create(:type_task, description: "# New Task template\n\nHello there") } let(:type_feature) { create(:type_feature, description: "", is_default: true) } let(:type_bug) { create(:type_bug, description: "# New Bug template\n\nGeneral Kenobi") } @@ -26,31 +26,31 @@ # Changes in the description shall not be overridden. def change_type_and_expect_description(set_project: false) if !set_project - expect(page).to have_css(".inline-edit--container.type", text: type_feature.name) + expect(page).to have_css('.inline-edit--container.type', text: type_feature.name) end - expect(page).to have_css(".inline-edit--container.description", text: "") + expect(page).to have_css('.inline-edit--container.description', text: '') type_field.openSelectField type_field.set_value type_task - expect(page).to have_css(".inline-edit--container.description h1", text: "New Task template") + expect(page).to have_css('.inline-edit--container.description h1', text: 'New Task template') type_field.openSelectField type_field.set_value type_bug - expect(page).to have_css(".inline-edit--container.description h1", text: "New Bug template") + expect(page).to have_css('.inline-edit--container.description h1', text: 'New Bug template') - description_field.set_value "Something different than the default." + description_field.set_value 'Something different than the default.' sleep 0.1 type_field.openSelectField type_field.set_value type_task - expect(page).to have_css(".inline-edit--container.description", text: "Something different than the default.") + expect(page).to have_css('.inline-edit--container.description', text: 'Something different than the default.') sleep 0.1 type_field.openSelectField type_field.set_value type_bug - expect(page).to have_css(".inline-edit--container.description", text: "Something different than the default.") + expect(page).to have_css('.inline-edit--container.description', text: 'Something different than the default.') if set_project project_field.openSelectField @@ -58,38 +58,38 @@ def change_type_and_expect_description(set_project: false) sleep 1 end - scroll_to_and_click find_by_id("work-packages--edit-actions-save") - wp_page.expect_toast message: "Successful creation." + scroll_to_and_click find_by_id('work-packages--edit-actions-save') + wp_page.expect_toast message: 'Successful creation.' - expect(page).to have_css(".inline-edit--display-field.description", text: "Something different than the default.") + expect(page).to have_css('.inline-edit--display-field.description', text: 'Something different than the default.') end before do login_as(user) end - describe "global work package create" do - it "shows the template after selection of project and type" do - visit "/work_packages/new" + describe 'global work package create' do + it 'shows the template after selection of project and type' do + visit '/work_packages/new' wp_page.expect_fully_loaded - subject_field.set_value "Foobar!" + subject_field.set_value 'Foobar!' change_type_and_expect_description set_project: true end end - describe "project work package create" do + describe 'project work package create' do let(:wp_table) { Pages::WorkPackagesTable.new project } let(:wp_page) { Pages::SplitWorkPackageCreate.new project: } - it "shows the template after selection of project and type" do + it 'shows the template after selection of project and type' do wp_table.visit! wp_table.create_wp_by_button type_feature wp_page.expect_fully_loaded - subject_field.set_value "Foobar!" + subject_field.set_value 'Foobar!' type_field.activate! diff --git a/spec/features/work_packages/pagination_spec.rb b/spec/features/work_packages/pagination_spec.rb index 3d5babd12b21..d326276c4702 100644 --- a/spec/features/work_packages/pagination_spec.rb +++ b/spec/features/work_packages/pagination_spec.rb @@ -26,66 +26,66 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package pagination", :js do +RSpec.describe 'Work package pagination', :js do shared_let(:admin) { create(:admin) } let(:project) do - create(:project, name: "project1", identifier: "project1") + create(:project, name: 'project1', identifier: 'project1') end - shared_examples_for "paginated work package list" do + shared_examples_for 'paginated work package list' do let!(:work_package_1) { create(:work_package, project:) } let!(:work_package_2) { create(:work_package, project:) } before do login_as(admin) - allow(Setting).to receive(:per_page_options).and_return "1, 50, 100" + allow(Setting).to receive(:per_page_options).and_return '1, 50, 100' visit path expect(page).to have_current_path(expected_path, ignore_query: true) end it do - expect(page).to have_content("All open") + expect(page).to have_content('All open') - within(".work-packages-partitioned-query-space--container") do + within('.work-packages-partitioned-query-space--container') do expect(page).to have_content(work_package_1.subject) expect(page).to have_no_content(work_package_2.subject) end - within(".op-pagination--pages") do - find(".op-pagination--item button", text: "2").click + within('.op-pagination--pages') do + find('.op-pagination--item button', text: '2').click end - within(".work-packages-partitioned-query-space--container") do + within('.work-packages-partitioned-query-space--container') do expect(page).to have_content(work_package_2.subject) expect(page).to have_no_content(work_package_1.subject) end - within(".op-pagination--options") do - find(".op-pagination--item button", text: "50").click + within('.op-pagination--options') do + find('.op-pagination--item button', text: '50').click end - within(".work-packages-partitioned-query-space--container") do + within('.work-packages-partitioned-query-space--container') do expect(page).to have_content(work_package_1.subject) expect(page).to have_content(work_package_2.subject) end end end - context "with project scope" do - it_behaves_like "paginated work package list" do + context 'with project scope' do + it_behaves_like 'paginated work package list' do let(:path) { project_work_packages_path(project) } - let(:expected_path) { "/projects/project1/work_packages" } + let(:expected_path) { '/projects/project1/work_packages' } end end - context "globally" do - it_behaves_like "paginated work package list" do + context 'globally' do + it_behaves_like 'paginated work package list' do let(:path) { work_packages_path } - let(:expected_path) { "/work_packages" } + let(:expected_path) { '/work_packages' } end end end diff --git a/spec/features/work_packages/project_include/project_include_shared_examples.rb b/spec/features/work_packages/project_include/project_include_shared_examples.rb index 83086bac17c4..436c8d691759 100644 --- a/spec/features/work_packages/project_include/project_include_shared_examples.rb +++ b/spec/features/work_packages/project_include/project_include_shared_examples.rb @@ -26,43 +26,43 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "has a project include dropdown", :js, type: :feature do +RSpec.shared_examples 'has a project include dropdown', :js, type: :feature do let(:dropdown) { Components::ProjectIncludeComponent.new } shared_let(:project) do - create(:project, name: "Parent", enabled_module_names: enabled_modules) + create(:project, name: 'Parent', enabled_module_names: enabled_modules) end shared_let(:sub_project) do - create(:project, name: "Direct Child", parent: project, enabled_module_names: enabled_modules) + create(:project, name: 'Direct Child', parent: project, enabled_module_names: enabled_modules) end # The user will not receive a membership in this project # which is why it is invisible to the user. shared_let(:sub_sub_project_invisible) do - create(:project, name: "Invisible Grandchild", parent: sub_project, enabled_module_names: enabled_modules) + create(:project, name: 'Invisible Grandchild', parent: sub_project, enabled_module_names: enabled_modules) end shared_let(:sub_sub_sub_project) do - create(:project, name: "Direct grand Grandchild", parent: sub_sub_project_invisible, enabled_module_names: enabled_modules) + create(:project, name: 'Direct grand Grandchild', parent: sub_sub_project_invisible, enabled_module_names: enabled_modules) end shared_let(:other_project) do - create(:project, name: "Other project", enabled_module_names: enabled_modules) + create(:project, name: 'Other project', enabled_module_names: enabled_modules) end shared_let(:other_sub_project) do - create(:project, name: "Other Child", parent: other_project, enabled_module_names: enabled_modules) + create(:project, name: 'Other Child', parent: other_project, enabled_module_names: enabled_modules) end shared_let(:other_sub_sub_project) do - create(:project, name: "First other sub sub child", parent: other_sub_project, enabled_module_names: enabled_modules) + create(:project, name: 'First other sub sub child', parent: other_sub_project, enabled_module_names: enabled_modules) end shared_let(:another_sub_sub_project) do - create(:project, name: "Second other sub sub child", parent: other_sub_project, enabled_module_names: enabled_modules) + create(:project, name: 'Second other sub sub child', parent: other_sub_project, enabled_module_names: enabled_modules) end shared_let(:user) do @@ -80,8 +80,8 @@ shared_let(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_permissions: { project => permissions, sub_project => permissions, @@ -136,7 +136,7 @@ assigned_to: other_user, start_date: Time.zone.today, due_date: Time.zone.today + 2.days, - subject: "A task for the other user") + subject: 'A task for the other user') end shared_let(:other_other_task) do @@ -146,7 +146,7 @@ assigned_to: other_user, start_date: Time.zone.today - 2.days, due_date: Time.zone.today + 4.days, - subject: "A task for the other user in other-project") + subject: 'A task for the other user in other-project') end before do @@ -170,7 +170,7 @@ work_package_view.visit! end - it "can add and remove projects" do + it 'can add and remove projects' do dropdown.expect_count 1 dropdown.toggle! dropdown.expect_open @@ -214,14 +214,14 @@ dropdown.expect_checkbox(sub_project.id) dropdown.expect_checkbox(sub_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 2 dropdown.toggle! dropdown.toggle_checkbox(sub_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 3 @@ -253,12 +253,12 @@ dropdown.toggle_checkbox(sub_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 2 end - it "can clear the selection" do + it 'can clear the selection' do dropdown.expect_count 1 dropdown.toggle! dropdown.expect_open @@ -275,13 +275,13 @@ dropdown.expect_checkbox(sub_project.id, true) dropdown.expect_checkbox(sub_sub_sub_project.id, true) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 2 dropdown.toggle! - dropdown.click_button "Clear selection" + dropdown.click_button 'Clear selection' dropdown.expect_checkbox(other_project.id) dropdown.expect_checkbox(other_sub_project.id) @@ -304,13 +304,13 @@ dropdown.expect_checkbox(sub_project.id) dropdown.expect_checkbox(sub_sub_sub_project.id, true) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 3 dropdown.toggle! - dropdown.click_button "Clear selection" + dropdown.click_button 'Clear selection' dropdown.expect_checkbox(other_project.id) dropdown.expect_checkbox(other_sub_project.id) @@ -320,12 +320,12 @@ dropdown.expect_checkbox(sub_project.id) dropdown.expect_checkbox(sub_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed dropdown.expect_count 1 end - it "filter projects in the list" do + it 'filter projects in the list' do dropdown.expect_count 1 dropdown.toggle! dropdown.expect_open @@ -355,7 +355,7 @@ end retry_block do - dropdown.search "" + dropdown.search '' dropdown.expect_checkbox(other_project.id) dropdown.expect_checkbox(other_sub_project.id) @@ -428,7 +428,7 @@ end retry_block do - dropdown.search "" + dropdown.search '' dropdown.expect_checkbox(other_project.id, true) dropdown.expect_no_checkbox(other_sub_project.id) @@ -452,11 +452,11 @@ end end - it "keeps working even when there are no results (regression #42908)" do + it 'keeps working even when there are no results (regression #42908)' do dropdown.expect_count 1 dropdown.toggle! dropdown.expect_open - dropdown.search "Nonexistent" + dropdown.search 'Nonexistent' expect(page).to have_no_css("[data-test-selector='op-project-include--loading']") end end diff --git a/spec/features/work_packages/remaining_time_spec.rb b/spec/features/work_packages/remaining_time_spec.rb index 2ba7212cfbce..033a030f5ec0 100644 --- a/spec/features/work_packages/remaining_time_spec.rb +++ b/spec/features/work_packages/remaining_time_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work packages remaining time", :js, :with_cuprite do +RSpec.describe 'Work packages remaining time', :js, :with_cuprite do shared_current_user { create(:admin) } shared_let(:project) do create(:project, @@ -40,21 +40,21 @@ author: current_user) end - it "can set and edit the remaining time in hours (Regression #43549)" do + it 'can set and edit the remaining time in hours (Regression #43549)' do wp_page = Pages::FullWorkPackage.new(work_package) wp_page.visit! wp_page.expect_subject - wp_page.expect_attributes remainingTime: "-" + wp_page.expect_attributes remainingTime: '-' - wp_page.update_attributes remainingTime: "125" # rubocop:disable Rails/ActiveRecordAliases - wp_page.expect_attributes remainingTime: "125 h" + wp_page.update_attributes remainingTime: '125' # rubocop:disable Rails/ActiveRecordAliases + wp_page.expect_attributes remainingTime: '125 h' work_package.reload expect(work_package.remaining_hours).to eq 125.0 end - it "displays the remaining time sum properly in hours (Regression #43833)" do + it 'displays the remaining time sum properly in hours (Regression #43833)' do wp_table_page = Pages::WorkPackagesTable.new(project) query_props = JSON.dump({ @@ -63,11 +63,11 @@ }) wp_table_page.visit_with_params("query_props=#{query_props}") - wp_table_page.expect_work_package_with_attributes work_package, remainingTime: "-" + wp_table_page.expect_work_package_with_attributes work_package, remainingTime: '-' - wp_table_page.update_work_package_attributes work_package, remainingTime: "125" - wp_table_page.expect_work_package_with_attributes work_package, remainingTime: "125 h" - wp_table_page.expect_sums_row_with_attributes remainingTime: "125 h" + wp_table_page.update_work_package_attributes work_package, remainingTime: '125' + wp_table_page.expect_work_package_with_attributes work_package, remainingTime: '125 h' + wp_table_page.expect_sums_row_with_attributes remainingTime: '125 h' work_package.reload expect(work_package.remaining_hours).to eq 125.0 diff --git a/spec/features/work_packages/reports_spec.rb b/spec/features/work_packages/reports_spec.rb index 676f3e7b7b70..86c82b9f3ac7 100644 --- a/spec/features/work_packages/reports_spec.rb +++ b/spec/features/work_packages/reports_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "work package reports", :js do +RSpec.describe 'work package reports', :js do let(:project) { create(:project_with_types, types: [type_a]) } let(:user) { create(:user, member_with_permissions: { project => %i(view_work_packages) }) } let(:type_a) do - create(:type_with_workflow, name: "Type A").tap do |t| + create(:type_with_workflow, name: 'Type A').tap do |t| t.statuses.last.update_attribute(:is_closed, true) end end @@ -47,73 +47,73 @@ login_as(user) end - it "allows navigating to the reports page and drilling down" do + it 'allows navigating to the reports page and drilling down' do wp_table_page.visit! - within ".main-menu--children" do - click_on "Summary" + within '.main-menu--children' do + click_on 'Summary' end expect(page) - .to have_content "TYPE" + .to have_content 'TYPE' expect(page) - .to have_content "PRIORITY" + .to have_content 'PRIORITY' expect(page) - .to have_content "ASSIGNEE" + .to have_content 'ASSIGNEE' expect(page) - .to have_content "ACCOUNTABLE" + .to have_content 'ACCOUNTABLE' expect(page) - .to have_css "thead th:nth-of-type(2)", text: type_a.statuses.first.name.upcase + .to have_css 'thead th:nth-of-type(2)', text: type_a.statuses.first.name.upcase expect(page) - .to have_css "thead th:nth-of-type(3)", text: type_a.statuses.last.name.upcase + .to have_css 'thead th:nth-of-type(3)', text: type_a.statuses.last.name.upcase expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(1)", text: type_a.name + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(1)', text: type_a.name expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(2)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(2)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(3)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(3)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(4)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(4)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(5)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(5)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(6)", text: 2 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(6)', text: 2 # Clicking on the further analyze link will lead to a page focusing on type - click_link "Further analyze: Type" + click_link 'Further analyze: Type' expect(page) - .to have_content "TYPE" + .to have_content 'TYPE' expect(page) - .to have_no_content "PRIORITY" + .to have_no_content 'PRIORITY' expect(page) - .to have_no_content "ASSIGNEE" + .to have_no_content 'ASSIGNEE' expect(page) - .to have_no_content "ACCOUNTABLE" + .to have_no_content 'ACCOUNTABLE' expect(page) - .to have_css "thead th:nth-of-type(2)", text: type_a.statuses.first.name.upcase + .to have_css 'thead th:nth-of-type(2)', text: type_a.statuses.first.name.upcase expect(page) - .to have_css "thead th:nth-of-type(3)", text: type_a.statuses.last.name.upcase + .to have_css 'thead th:nth-of-type(3)', text: type_a.statuses.last.name.upcase expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(1)", text: type_a.name + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(1)', text: type_a.name expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(2)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(2)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(3)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(3)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(4)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(4)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(5)", text: 1 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(5)', text: 1 expect(page) - .to have_css "tbody tr:nth-of-type(1) td:nth-of-type(6)", text: 2 + .to have_css 'tbody tr:nth-of-type(1) td:nth-of-type(6)', text: 2 # Clicking on a number in the table will lead to the wp list filtered by the type - within "tbody tr:first-of-type td:nth-of-type(2)" do - click_link "1" + within 'tbody tr:first-of-type td:nth-of-type(2)' do + click_link '1' end wp_table_page.expect_work_package_listed(wp1) diff --git a/spec/features/work_packages/scheduling/scheduling_mode_spec.rb b/spec/features/work_packages/scheduling/scheduling_mode_spec.rb index 55365b76792a..e1712597c00c 100644 --- a/spec/features/work_packages/scheduling/scheduling_mode_spec.rb +++ b/spec/features/work_packages/scheduling/scheduling_mode_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" -require "features/work_packages/details/inplace_editor/shared_examples" -require "features/work_packages/shared_contexts" -require "support/edit_fields/edit_field" -require "features/work_packages/work_packages_page" - -RSpec.describe "scheduling mode", :js do +require 'spec_helper' +require 'features/page_objects/notification' +require 'features/work_packages/details/inplace_editor/shared_examples' +require 'features/work_packages/shared_contexts' +require 'support/edit_fields/edit_field' +require 'features/work_packages/work_packages_page' + +RSpec.describe 'scheduling mode', :js do let(:project) { create(:project_with_types, public: true) } # Constructing a work package graph that looks like this: # @@ -52,36 +52,36 @@ let!(:wp) do create(:work_package, project:, - start_date: Date.parse("2016-01-01"), - due_date: Date.parse("2016-01-05"), + start_date: Date.parse('2016-01-01'), + due_date: Date.parse('2016-01-05'), parent: wp_parent) end let!(:wp_parent) do create(:work_package, project:, - start_date: Date.parse("2016-01-01"), - due_date: Date.parse("2016-01-05")) + start_date: Date.parse('2016-01-01'), + due_date: Date.parse('2016-01-05')) end let!(:wp_child) do create(:work_package, project:, - start_date: Date.parse("2016-01-01"), - due_date: Date.parse("2016-01-05"), + start_date: Date.parse('2016-01-01'), + due_date: Date.parse('2016-01-05'), parent: wp) end let!(:wp_pre) do create(:work_package, project:, - start_date: Date.parse("2015-12-15"), - due_date: Date.parse("2015-12-31")).tap do |pre| + start_date: Date.parse('2015-12-15'), + due_date: Date.parse('2015-12-31')).tap do |pre| create(:follows_relation, from: wp, to: pre) end end let!(:wp_suc) do create(:work_package, project:, - start_date: Date.parse("2016-01-06"), - due_date: Date.parse("2016-01-10"), + start_date: Date.parse('2016-01-06'), + due_date: Date.parse('2016-01-10'), parent: wp_suc_parent).tap do |suc| create(:follows_relation, from: suc, to: wp) end @@ -89,14 +89,14 @@ let!(:wp_suc_parent) do create(:work_package, project:, - start_date: Date.parse("2016-01-06"), - due_date: Date.parse("2016-01-10")) + start_date: Date.parse('2016-01-06'), + due_date: Date.parse('2016-01-10')) end let!(:wp_suc_child) do create(:work_package, project:, - start_date: Date.parse("2016-01-06"), - due_date: Date.parse("2016-01-10"), + start_date: Date.parse('2016-01-06'), + due_date: Date.parse('2016-01-10'), parent: wp_suc) end let(:work_packages_page) { Pages::SplitWorkPackage.new(wp, project) } @@ -116,7 +116,7 @@ def expect_dates(work_package, start_date, due_date) work_packages_page.ensure_page_loaded end - it "can toggle the scheduling mode through the date modal" do + it 'can toggle the scheduling mode through the date modal' do expect(wp.schedule_manually).to be_falsey # Editing the start/due dates of a parent work package is possible if the @@ -128,29 +128,29 @@ def expect_dates(work_package, start_date, due_date) combined_field.expect_duration 6 combined_field.save! - work_packages_page.expect_and_dismiss_toaster message: "Successful update." + work_packages_page.expect_and_dismiss_toaster message: 'Successful update.' # Changing the scheduling mode is journalized work_packages_page.expect_activity_message("Manual scheduling activated") - expect_dates(wp, "2016-01-05", "2016-01-10") + expect_dates(wp, '2016-01-05', '2016-01-10') expect(wp.schedule_manually).to be_truthy # is not moved because it is a child - expect_dates(wp_child, "2016-01-01", "2016-01-05") + expect_dates(wp_child, '2016-01-01', '2016-01-05') # The due date is moved backwards because its child was moved # but the start date remains unchanged as its grandchild stays put. - expect_dates(wp_parent, "2016-01-01", "2016-01-10") + expect_dates(wp_parent, '2016-01-01', '2016-01-10') # is moved forward because of the follows relationship - expect_dates(wp_suc, "2016-01-11", "2016-01-15") + expect_dates(wp_suc, '2016-01-11', '2016-01-15') # is moved forward because it is the parent of the successor - expect_dates(wp_suc_parent, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_parent, '2016-01-11', '2016-01-15') # is moved forward as the whole hierarchy is moved forward - expect_dates(wp_suc_child, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_child, '2016-01-11', '2016-01-15') # Switching back to automatic scheduling will lead to the work package # and all work packages that are dependent to be rescheduled again. @@ -159,27 +159,27 @@ def expect_dates(work_package, start_date, due_date) combined_field.toggle_scheduling_mode combined_field.save! - work_packages_page.expect_and_dismiss_toaster message: "Successful update." + work_packages_page.expect_and_dismiss_toaster message: 'Successful update.' # Moved backward again as the child determines the dates again - expect_dates(wp, "2016-01-01", "2016-01-05") + expect_dates(wp, '2016-01-01', '2016-01-05') expect(wp.schedule_manually).to be_falsey # Had not been moved in the first place - expect_dates(wp_child, "2016-01-01", "2016-01-05") + expect_dates(wp_child, '2016-01-01', '2016-01-05') # As the child now again takes up the same time interval as the grandchild, # the interval is shortened again. - expect_dates(wp_parent, "2016-01-01", "2016-01-05") + expect_dates(wp_parent, '2016-01-01', '2016-01-05') # does not move backwards, as it just increases the gap between wp and wp_suc - expect_dates(wp_suc, "2016-01-11", "2016-01-15") + expect_dates(wp_suc, '2016-01-11', '2016-01-15') # does not move backwards either - expect_dates(wp_suc_parent, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_parent, '2016-01-11', '2016-01-15') # does not move backwards either because its parent did not move - expect_dates(wp_suc_child, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_child, '2016-01-11', '2016-01-15') # Switching back to manual scheduling but this time backward will lead to the work package # and all work packages that are dependent to be rescheduled again. @@ -196,26 +196,26 @@ def expect_dates(work_package, start_date, due_date) combined_field.expect_duration 12 combined_field.save! - work_packages_page.expect_and_dismiss_toaster message: "Successful update." + work_packages_page.expect_and_dismiss_toaster message: 'Successful update.' - expect_dates(wp, "2015-12-20", "2015-12-31") + expect_dates(wp, '2015-12-20', '2015-12-31') expect(wp.schedule_manually).to be_truthy # is not moved because it is a child - expect_dates(wp_child, "2016-01-01", "2016-01-05") + expect_dates(wp_child, '2016-01-01', '2016-01-05') # The start date is moved forward because its child was moved # but the due date remains unchanged as its grandchild stays put. - expect_dates(wp_parent, "2015-12-20", "2016-01-05") + expect_dates(wp_parent, '2015-12-20', '2016-01-05') # does not move backwards, as it just increases the gap between wp and wp_suc - expect_dates(wp_suc, "2016-01-11", "2016-01-15") + expect_dates(wp_suc, '2016-01-11', '2016-01-15') # does not move backwards either - expect_dates(wp_suc_parent, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_parent, '2016-01-11', '2016-01-15') # does not move backwards either because its parent did not move - expect_dates(wp_suc_child, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_child, '2016-01-11', '2016-01-15') # Switching back to automatic scheduling will lead to the work package # and all work packages that are dependent to be rescheduled again to @@ -225,26 +225,26 @@ def expect_dates(work_package, start_date, due_date) combined_field.toggle_scheduling_mode combined_field.save! - work_packages_page.expect_and_dismiss_toaster message: "Successful update." + work_packages_page.expect_and_dismiss_toaster message: 'Successful update.' # Moved backwards again as the child determines the dates again - expect_dates(wp, "2016-01-01", "2016-01-05") + expect_dates(wp, '2016-01-01', '2016-01-05') expect(wp.schedule_manually).to be_falsey # Had not been moved in the first place - expect_dates(wp_child, "2016-01-01", "2016-01-05") + expect_dates(wp_child, '2016-01-01', '2016-01-05') # As the child now again takes up the same time interval as the grandchild, # the interval is shortened again. - expect_dates(wp_parent, "2016-01-01", "2016-01-05") + expect_dates(wp_parent, '2016-01-01', '2016-01-05') # does not move - expect_dates(wp_suc, "2016-01-11", "2016-01-15") + expect_dates(wp_suc, '2016-01-11', '2016-01-15') # does not move either - expect_dates(wp_suc_parent, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_parent, '2016-01-11', '2016-01-15') # does not move either because its parent did not move - expect_dates(wp_suc_child, "2016-01-11", "2016-01-15") + expect_dates(wp_suc_child, '2016-01-11', '2016-01-15') end end diff --git a/spec/features/work_packages/select/select_query_spec.rb b/spec/features/work_packages/select/select_query_spec.rb index 202d1dcaa52f..aacfe9d38943 100644 --- a/spec/features/work_packages/select/select_query_spec.rb +++ b/spec/features/work_packages/select/select_query_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Query selection" do - let(:project) { create(:project, identifier: "test_project", public: false) } +RSpec.describe 'Query selection' do + let(:project) { create(:project, identifier: 'test_project', public: false) } let(:role) { create(:project_role, permissions: [:view_work_packages]) } let(:current_user) do create(:user, member_with_roles: { project => role }) @@ -43,8 +43,8 @@ let(:query) do build(:query, project:, public: true).tap do |query| query.filters.clear - query.add_filter("assigned_to_id", "=", ["me"]) - query.add_filter("done_ratio", ">=", [10]) + query.add_filter('assigned_to_id', '=', ['me']) + query.add_filter('done_ratio', '>=', [10]) query.save! create(:view_work_packages_table, query:) @@ -61,35 +61,35 @@ login_as(current_user) end - context "default view, without a query selected" do + context 'default view, without a query selected' do before do work_packages_page.visit_index filters.open end - it "shows the default (status) filter", :js do + it 'shows the default (status) filter', :js do filters.expect_filter_count 1 - filters.expect_filter_by "Status", "open", nil + filters.expect_filter_by 'Status', 'open', nil end end - context "when a query is selected" do + context 'when a query is selected' do before do query work_packages_page.select_query query end - it "shows the saved filters", :js do + it 'shows the saved filters', :js do filters.open - filters.expect_filter_by "Assignee", "is (OR)", ["me"] - filters.expect_filter_by "Percent Complete", ">=", ["10"], "percentageDone" + filters.expect_filter_by 'Assignee', 'is (OR)', ['me'] + filters.expect_filter_by 'Percent Complete', '>=', ['10'], 'percentageDone' - expect(page).to have_css("#{test_selector('wp-filter-button')} .badge", text: "2") + expect(page).to have_css("#{test_selector('wp-filter-button')} .badge", text: '2') end end - context "when the selected query is changed" do + context 'when the selected query is changed' do let(:query2) do create(:query_with_view_work_packages_table, project:, @@ -103,10 +103,10 @@ work_packages_page.select_query query end - it "updates the page upon query switching", :js do + it 'updates the page upon query switching', :js do wp_page.expect_title query.name, editable: false - find(".op-sidemenu--item-action", text: query2.name).click + find('.op-sidemenu--item-action', text: query2.name).click end end end diff --git a/spec/features/work_packages/select/select_work_package_row_spec.rb b/spec/features/work_packages/select/select_work_package_row_spec.rb index 054bcebac989..1be14e379003 100644 --- a/spec/features/work_packages/select/select_work_package_row_spec.rb +++ b/spec/features/work_packages/select/select_work_package_row_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Select work package row", :js, :selenium do +RSpec.describe 'Select work package row', :js, :selenium do let(:user) { create(:admin) } let(:project) { create(:project) } let(:work_package_1) { create(:work_package, project:) } @@ -36,7 +36,7 @@ let(:work_package_3) { create(:work_package, project:) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } - include_context "work package table helpers" + include_context 'work package table helpers' before do login_as(user) @@ -103,18 +103,18 @@ def check_row_selection_state(row_index, state = true) end def check_all - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] expect_row_checked(1, 2, 3) - expect(page).to have_no_css "#work-package-context-menu" + expect(page).to have_no_css '#work-package-context-menu' end def uncheck_all - find("body").send_keys [:control, "d"] + find('body').send_keys [:control, 'd'] expect_row_unchecked(1, 2, 3) - expect(page).to have_no_css "#work-package-context-menu" + expect(page).to have_no_css '#work-package-context-menu' end - it "handles selection flows" do + it 'handles selection flows' do ### # Keyboard shortcuts ### @@ -198,30 +198,30 @@ def uncheck_all expect_row_unchecked(2) end - describe "opening work package full screen view" do + describe 'opening work package full screen view' do before do wp_table.open_full_screen_by_doubleclick(work_package_1) end it do - expect(page).to have_css(".work-packages--details--subject", + expect(page).to have_css('.work-packages--details--subject', text: work_package_1.subject) end end - describe "opening last selected work package" do + describe 'opening last selected work package' do before do select_work_package_row(2) expect_row_checked(2) end it do - find_by_id("work-packages-details-view-button").click + find_by_id('work-packages-details-view-button').click split_wp = Pages::SplitWorkPackage.new(work_package_2) split_wp.expect_attributes Subject: work_package_2.subject - find_by_id("work-packages-details-view-button").click - expect(page).to have_no_css(".work-packages--details") + find_by_id('work-packages-details-view-button').click + expect(page).to have_no_css('.work-packages--details') end end end diff --git a/spec/features/work_packages/share/access_spec.rb b/spec/features/work_packages/share/access_spec.rb index a93e3c727feb..19ae9b24db20 100644 --- a/spec/features/work_packages/share/access_spec.rb +++ b/spec/features/work_packages/share/access_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Shared Work Package Access", +RSpec.describe 'Shared Work Package Access', :js, :with_cuprite, with_ee: %i[work_package_sharing] do shared_let(:project) { create(:project_with_types) } - shared_let(:work_package) { create(:work_package, project:, journal_notes: "Hello!") } + shared_let(:work_package) { create(:work_package, project:, journal_notes: 'Hello!') } shared_let(:sharer) { create(:admin) } - shared_let(:shared_with_user) { create(:user, firstname: "Mean", lastname: "Turkey") } + shared_let(:shared_with_user) { create(:user, firstname: 'Mean', lastname: 'Turkey') } shared_let(:viewer_role) { create(:view_work_package_role) } shared_let(:commenter_role) { create(:comment_work_package_role) } @@ -47,8 +47,8 @@ let(:work_packages_page) { Pages::WorkPackagesTable.new(project) } let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } let(:share_modal) { Components::WorkPackages::ShareModal.new(work_package) } - let(:add_comment_button_selector) { ".work-packages--activity--add-comment" } - let(:attach_files_button_selector) { "op-attachments--upload-button" } + let(:add_comment_button_selector) { '.work-packages--activity--add-comment' } + let(:attach_files_button_selector) { 'op-attachments--upload-button' } specify "'View' role share access" do using_session "sharer" do @@ -59,17 +59,17 @@ work_package_page.click_share_button share_modal.expect_open - share_modal.invite_user!(shared_with_user, "View") + share_modal.invite_user!(shared_with_user, 'View') share_modal.close # Shared-with users with the "View" role CAN'T become assignees assignee_field = work_package_page.edit_field(:assignee) assignee_field.activate! - results = assignee_field.autocomplete("Mean Turkey", select: false) + results = assignee_field.autocomplete('Mean Turkey', select: false) wait_for_network_idle expect(results) - .to have_no_css(".ng-option", text: "Mean Turkey", wait: 0) + .to have_no_css('.ng-option', text: 'Mean Turkey', wait: 0) assignee_field.cancel_by_escape end @@ -90,7 +90,7 @@ # # Work Package is now visible project_page.within_sidebar do - click_link(I18n.t("label_work_package_plural")) + click_link(I18n.t('label_work_package_plural')) end work_packages_page.expect_work_package_listed(work_package) work_package_page.visit! @@ -113,8 +113,8 @@ end # And so is viewing and uploading attachments - work_package_page.switch_to_tab(tab: "Files") - work_package_page.expect_tab("Files") + work_package_page.switch_to_tab(tab: 'Files') + work_package_page.expect_tab('Files') work_package_page.within_active_tab do expect(page) .not_to have_test_selector(attach_files_button_selector) @@ -131,7 +131,7 @@ work_package_page.click_share_button share_modal.expect_open - share_modal.invite_user!(shared_with_user, "Comment") + share_modal.invite_user!(shared_with_user, 'Comment') share_modal.close # TODO: This is currently expected failing behavior. @@ -164,7 +164,7 @@ # # Work Package is now visible project_page.within_sidebar do - click_link(I18n.t("label_work_package_plural")) + click_link(I18n.t('label_work_package_plural')) end work_packages_page.expect_work_package_listed(work_package) work_package_page.visit! @@ -180,7 +180,7 @@ end # Spent time is visible and loggable - SpentTimeEditField.new(page, "spentTime") + SpentTimeEditField.new(page, 'spentTime') .time_log_icon_visible(true) work_package_page.ensure_page_loaded # waits for activity section to be ready @@ -191,8 +191,8 @@ end # Attachments are uploadable - work_package_page.switch_to_tab(tab: "Files") - work_package_page.expect_tab("Files") + work_package_page.switch_to_tab(tab: 'Files') + work_package_page.expect_tab('Files') work_package_page.within_active_tab do expect(page) .to have_test_selector(attach_files_button_selector) @@ -209,7 +209,7 @@ work_package_page.click_share_button share_modal.expect_open - share_modal.invite_user!(shared_with_user, "Edit") + share_modal.invite_user!(shared_with_user, 'Edit') share_modal.close @@ -243,7 +243,7 @@ # # Work Package is now visible project_page.within_sidebar do - click_link(I18n.t("label_work_package_plural")) + click_link(I18n.t('label_work_package_plural')) end work_packages_page.expect_work_package_listed(work_package) work_package_page.visit! @@ -264,7 +264,7 @@ end # Spent time is visible and loggable - SpentTimeEditField.new(page, "spentTime") + SpentTimeEditField.new(page, 'spentTime') .time_log_icon_visible(true) work_package_page.ensure_page_loaded # waits for activity section to be ready @@ -275,8 +275,8 @@ end # Attachments are uploadable - work_package_page.switch_to_tab(tab: "Files") - work_package_page.expect_tab("Files") + work_package_page.switch_to_tab(tab: 'Files') + work_package_page.expect_tab('Files') work_package_page.within_active_tab do expect(page) .to have_test_selector(attach_files_button_selector) diff --git a/spec/features/work_packages/share/bulk_sharing_spec.rb b/spec/features/work_packages/share/bulk_sharing_spec.rb index d57b066274d8..71e241f4a223 100644 --- a/spec/features/work_packages/share/bulk_sharing_spec.rb +++ b/spec/features/work_packages/share/bulk_sharing_spec.rb @@ -28,9 +28,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Packages", "Bulk Sharing", +RSpec.describe 'Work Packages', 'Bulk Sharing', :js, :with_cuprite, with_ee: %i[work_package_sharing] do shared_let(:view_work_package_role) { create(:view_work_package_role) } @@ -48,16 +48,16 @@ view_shared_work_packages]) end - shared_let(:sharer) { create(:user, firstname: "Sharer", lastname: "User") } - shared_let(:viewer) { create(:user, firstname: "Viewer", lastname: "User") } + shared_let(:sharer) { create(:user, firstname: 'Sharer', lastname: 'User') } + shared_let(:viewer) { create(:user, firstname: 'Viewer', lastname: 'User') } shared_let(:project) do create(:project, members: { sharer => [sharer_role], viewer => [viewer_role] }) end - shared_let(:dinesh) { create(:user, firstname: "Dinesh", lastname: "Chugtai") } - shared_let(:gilfoyle) { create(:user, firstname: "Bertram", lastname: "Gilfoyle") } - shared_let(:richard) { create(:user, firstname: "Richard", lastname: "Hendricks") } + shared_let(:dinesh) { create(:user, firstname: 'Dinesh', lastname: 'Chugtai') } + shared_let(:gilfoyle) { create(:user, firstname: 'Bertram', lastname: 'Gilfoyle') } + shared_let(:richard) { create(:user, firstname: 'Richard', lastname: 'Hendricks') } shared_let(:work_package) do create(:work_package, project:) do |wp| @@ -70,10 +70,10 @@ let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } let(:share_modal) { Components::WorkPackages::ShareModal.new(work_package) } - context "when having share permission" do + context 'when having share permission' do current_user { sharer } - it "allows administrating shares in bulk" do + it 'allows administrating shares in bulk' do work_package_page.visit! work_package_page.click_share_button @@ -92,7 +92,7 @@ share_modal.expect_select_all_untoggled # Available now share_modal.expect_bulk_actions_available - share_modal.expect_bulk_update_label("View") + share_modal.expect_bulk_update_label('View') # Toggling all selects all share_modal.toggle_select_all @@ -100,7 +100,7 @@ share_modal.expect_selected_count_of(3) share_modal.expect_select_all_toggled share_modal.expect_bulk_actions_available - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') # Deselecting one individually share_modal.deselect_shares(richard) @@ -108,7 +108,7 @@ share_modal.expect_selected_count_of(2) share_modal.expect_select_all_untoggled share_modal.expect_bulk_actions_available - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') # Re-selecting the missing share share_modal.select_shares(richard) @@ -116,7 +116,7 @@ share_modal.expect_selected_count_of(3) share_modal.expect_select_all_toggled share_modal.expect_bulk_actions_available - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') # De-selecting all share_modal.toggle_select_all @@ -133,7 +133,7 @@ share_modal.expect_select_all_toggled # Available again share_modal.expect_bulk_actions_available - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') # De-selecting all individually share_modal.deselect_shares(richard, dinesh, gilfoyle) @@ -147,7 +147,7 @@ share_modal.select_shares(richard, dinesh) share_modal.expect_selected_count_of(2) share_modal.expect_select_all_untoggled - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') share_modal.remove_user(gilfoyle) share_modal.expect_not_shared_with(gilfoyle) @@ -155,35 +155,35 @@ share_modal.expect_selected(richard, dinesh) share_modal.expect_selected_count_of(2) share_modal.expect_select_all_toggled - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') - share_modal.invite_user(gilfoyle, "Comment") + share_modal.invite_user(gilfoyle, 'Comment') share_modal.expect_shared_with(gilfoyle) share_modal.expect_selected(richard, dinesh) share_modal.expect_selected_count_of(2) share_modal.expect_select_all_untoggled - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') end aggregate_failures "Preserving selected states when performing individual updates" do - share_modal.change_role(gilfoyle, "View") - share_modal.expect_shared_with(gilfoyle, "View") + share_modal.change_role(gilfoyle, 'View') + share_modal.expect_shared_with(gilfoyle, 'View') share_modal.expect_selected(richard, dinesh) share_modal.expect_selected_count_of(2) share_modal.expect_select_all_untoggled - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') share_modal.toggle_select_all share_modal.expect_selected_count_of(3) share_modal.expect_select_all_toggled - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') - share_modal.change_role(gilfoyle, "Edit") - share_modal.expect_shared_with(gilfoyle, "Edit") + share_modal.change_role(gilfoyle, 'Edit') + share_modal.expect_shared_with(gilfoyle, 'Edit') share_modal.expect_selected_count_of(3) share_modal.expect_select_all_toggled - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') end # Reset @@ -212,37 +212,37 @@ end # Re-populate - share_modal.invite_user(richard, "View") + share_modal.invite_user(richard, 'View') share_modal.expect_shared_with(richard) - share_modal.invite_user(dinesh, "Comment") + share_modal.invite_user(dinesh, 'Comment') share_modal.expect_shared_with(dinesh) - aggregate_failures "Bulk updating" do + aggregate_failures 'Bulk updating' do share_modal.select_shares(richard) share_modal.expect_selected(richard) share_modal.expect_selected_count_of(1) - share_modal.expect_bulk_update_label("View") + share_modal.expect_bulk_update_label('View') - share_modal.bulk_update("Edit") + share_modal.bulk_update('Edit') - share_modal.expect_shared_with(richard, "Edit") - share_modal.expect_shared_with(dinesh, "Comment") + share_modal.expect_shared_with(richard, 'Edit') + share_modal.expect_shared_with(dinesh, 'Comment') share_modal.expect_selected(richard) share_modal.expect_selected_count_of(1) - share_modal.expect_bulk_update_label("Edit") + share_modal.expect_bulk_update_label('Edit') share_modal.select_shares(richard, dinesh) share_modal.expect_selected(richard, dinesh) share_modal.expect_selected_count_of(2) - share_modal.expect_bulk_update_label("Mixed") + share_modal.expect_bulk_update_label('Mixed') - share_modal.bulk_update("View") + share_modal.bulk_update('View') - share_modal.expect_shared_with(richard, "View") - share_modal.expect_shared_with(dinesh, "View") + share_modal.expect_shared_with(richard, 'View') + share_modal.expect_shared_with(dinesh, 'View') share_modal.expect_selected(richard, dinesh) share_modal.expect_selected_count_of(2) - share_modal.expect_bulk_update_label("View") + share_modal.expect_bulk_update_label('View') share_modal.toggle_select_all share_modal.expect_deselected(richard, dinesh) @@ -273,8 +273,8 @@ share_modal.expect_select_all_not_available share_modal.expect_bulk_actions_not_available - share_modal.invite_user(richard, "View") - share_modal.expect_shared_with(richard, "View") + share_modal.invite_user(richard, 'View') + share_modal.expect_shared_with(richard, 'View') share_modal.expect_shared_count_of(2) share_modal.expect_select_all_available @@ -282,10 +282,10 @@ end end - context "without share permission" do + context 'without share permission' do current_user { viewer } - it "does not allow bulk sharing" do + it 'does not allow bulk sharing' do work_package_page.visit! work_package_page.click_share_button diff --git a/spec/features/work_packages/share/enterprise_restriction_spec.rb b/spec/features/work_packages/share/enterprise_restriction_spec.rb index 8bede4e0c1b6..31afb836d9f2 100644 --- a/spec/features/work_packages/share/enterprise_restriction_spec.rb +++ b/spec/features/work_packages/share/enterprise_restriction_spec.rb @@ -28,9 +28,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "rails_helper" +require 'rails_helper' -RSpec.describe "Work Package Sharing Enterprise Restriction", :js, :with_cuprite do +RSpec.describe 'Work Package Sharing Enterprise Restriction', :js, :with_cuprite do shared_let(:view_work_package_role) { create(:view_work_package_role) } shared_let(:comment_work_package_role) { create(:comment_work_package_role) } shared_let(:edit_work_package_role) { create(:edit_work_package_role) } @@ -41,7 +41,7 @@ share_work_packages]) end - shared_let(:sharer) { create(:user, firstname: "Sharer", lastname: "User") } + shared_let(:sharer) { create(:user, firstname: 'Sharer', lastname: 'User') } shared_let(:project) { create(:project, members: { sharer => [sharer_role] }) } shared_let(:work_package) { create(:work_package, project:) } @@ -58,14 +58,14 @@ share_modal.expect_open end - context "without an enterprise token" do - it "renders an upsale banner" do + context 'without an enterprise token' do + it 'renders an upsale banner' do share_modal.expect_upsale_banner end end - context "with an enterprise token", with_ee: %i[work_package_sharing] do - it "renders the share modal" do + context 'with an enterprise token', with_ee: %i[work_package_sharing] do + it 'renders the share modal' do share_modal.expect_blankslate end end diff --git a/spec/features/work_packages/share/filter_spec.rb b/spec/features/work_packages/share/filter_spec.rb index c6e7e81e6a12..4dadacce50c2 100644 --- a/spec/features/work_packages/share/filter_spec.rb +++ b/spec/features/work_packages/share/filter_spec.rb @@ -28,19 +28,19 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package sharing", +RSpec.describe 'Work package sharing', :js, :with_cuprite, with_ee: %i[work_package_sharing] do shared_let(:view_work_package_role) { create(:view_work_package_role) } shared_let(:comment_work_package_role) { create(:comment_work_package_role) } shared_let(:edit_work_package_role) { create(:edit_work_package_role) } - shared_let(:project_user) { create(:user, firstname: "Anton") } - shared_let(:project_user2) { create(:user, firstname: "Bertha") } - shared_let(:inherited_project_user) { create(:user, firstname: "Caesar") } - shared_let(:non_project_user) { create(:user, firstname: "Dora") } + shared_let(:project_user) { create(:user, firstname: 'Anton') } + shared_let(:project_user2) { create(:user, firstname: 'Bertha') } + shared_let(:inherited_project_user) { create(:user, firstname: 'Caesar') } + shared_let(:non_project_user) { create(:user, firstname: 'Dora') } shared_let(:shared_project_group) { create(:group, members: [project_user, inherited_project_user]) } shared_let(:shared_non_project_group) { create(:group, members: [project_user2, non_project_user]) } @@ -73,35 +73,35 @@ let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } let(:share_modal) { Components::WorkPackages::ShareModal.new(work_package) } - current_user { create(:admin, firstname: "Signed in", lastname: "User") } + current_user { create(:admin, firstname: 'Signed in', lastname: 'User') } - context "when having share permission" do + context 'when having share permission' do before do work_package_page.visit! work_package_page.click_share_button end - it "allows to filter for the type" do + it 'allows to filter for the type' do share_modal.expect_open share_modal.expect_shared_count_of(6) # Filter for: project members (users only) - share_modal.filter("type", I18n.t("work_package.sharing.filter.project_member")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.project_member')) share_modal.expect_shared_count_of(3) - share_modal.expect_shared_with(project_user, "View") - share_modal.expect_shared_with(project_user2, "Comment") + share_modal.expect_shared_with(project_user, 'View') + share_modal.expect_shared_with(project_user2, 'Comment') # The non-project user is listed because it is part of the project group and thus the membership is inherited. - share_modal.expect_shared_with(inherited_project_user, "Edit") + share_modal.expect_shared_with(inherited_project_user, 'Edit') share_modal.expect_not_shared_with(non_project_user) share_modal.expect_not_shared_with(shared_project_group) share_modal.expect_not_shared_with(shared_non_project_group) # Filter for: non-project members (users only) - share_modal.filter("type", I18n.t("work_package.sharing.filter.not_project_member")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.not_project_member')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(non_project_user, "Edit") + share_modal.expect_shared_with(non_project_user, 'Edit') share_modal.expect_not_shared_with(inherited_project_user) share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(project_user2) @@ -109,10 +109,10 @@ share_modal.expect_not_shared_with(shared_non_project_group) # Filter for: project members (groups only) - share_modal.filter("type", I18n.t("work_package.sharing.filter.project_group")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.project_group')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(shared_project_group, "Edit") + share_modal.expect_shared_with(shared_project_group, 'Edit') share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) @@ -120,10 +120,10 @@ share_modal.expect_not_shared_with(shared_non_project_group) # Filter for: non-project members (groups only) - share_modal.filter("type", I18n.t("work_package.sharing.filter.not_project_group")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.not_project_group')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(shared_non_project_group, 'View') share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) @@ -131,48 +131,48 @@ share_modal.expect_not_shared_with(shared_project_group) # Clicking again on the filter will reset it - share_modal.filter("type", I18n.t("work_package.sharing.filter.not_project_group")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.not_project_group')) share_modal.expect_shared_count_of(6) - share_modal.expect_shared_with(project_user, "View") - share_modal.expect_shared_with(project_user2, "Comment") - share_modal.expect_shared_with(inherited_project_user, "Edit") - share_modal.expect_shared_with(non_project_user, "Edit") - share_modal.expect_shared_with(shared_project_group, "Edit") - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(project_user, 'View') + share_modal.expect_shared_with(project_user2, 'Comment') + share_modal.expect_shared_with(inherited_project_user, 'Edit') + share_modal.expect_shared_with(non_project_user, 'Edit') + share_modal.expect_shared_with(shared_project_group, 'Edit') + share_modal.expect_shared_with(shared_non_project_group, 'View') end - it "allows to filter for the role" do + it 'allows to filter for the role' do share_modal.expect_open share_modal.expect_shared_count_of(6) # Filter for: all principals with Edit permission - share_modal.filter("role", I18n.t("work_package.sharing.permissions.edit")) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.edit')) share_modal.expect_shared_count_of(3) - share_modal.expect_shared_with(inherited_project_user, "Edit") - share_modal.expect_shared_with(non_project_user, "Edit") - share_modal.expect_shared_with(shared_project_group, "Edit") + share_modal.expect_shared_with(inherited_project_user, 'Edit') + share_modal.expect_shared_with(non_project_user, 'Edit') + share_modal.expect_shared_with(shared_project_group, 'Edit') share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(shared_non_project_group) # Filter for: all principals with View permission - share_modal.filter("role", I18n.t("work_package.sharing.permissions.view")) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.view')) share_modal.expect_shared_count_of(2) - share_modal.expect_shared_with(project_user, "View") - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(project_user, 'View') + share_modal.expect_shared_with(shared_non_project_group, 'View') share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) share_modal.expect_not_shared_with(non_project_user) share_modal.expect_not_shared_with(shared_project_group) # Filter for: all principals with Comment permission - share_modal.filter("role", I18n.t("work_package.sharing.permissions.comment")) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.comment')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(project_user2, "Comment") + share_modal.expect_shared_with(project_user2, 'Comment') share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(inherited_project_user) share_modal.expect_not_shared_with(non_project_user) @@ -180,29 +180,29 @@ share_modal.expect_not_shared_with(shared_non_project_group) # Clicking again on the filter will reset it - share_modal.filter("role", I18n.t("work_package.sharing.permissions.comment")) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.comment')) share_modal.expect_shared_count_of(6) - share_modal.expect_shared_with(project_user, "View") - share_modal.expect_shared_with(project_user2, "Comment") - share_modal.expect_shared_with(inherited_project_user, "Edit") - share_modal.expect_shared_with(non_project_user, "Edit") - share_modal.expect_shared_with(shared_project_group, "Edit") - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(project_user, 'View') + share_modal.expect_shared_with(project_user2, 'Comment') + share_modal.expect_shared_with(inherited_project_user, 'Edit') + share_modal.expect_shared_with(non_project_user, 'Edit') + share_modal.expect_shared_with(shared_project_group, 'Edit') + share_modal.expect_shared_with(shared_non_project_group, 'View') end - it "allows to filter for role and type at the same time" do + it 'allows to filter for role and type at the same time' do share_modal.expect_open share_modal.expect_shared_count_of(6) # Filter for: all principals with View permission # role: view # type: none - share_modal.filter("role", I18n.t("work_package.sharing.permissions.view")) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.view')) share_modal.expect_shared_count_of(2) - share_modal.expect_shared_with(project_user, "View") - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(project_user, 'View') + share_modal.expect_shared_with(shared_non_project_group, 'View') share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) share_modal.expect_not_shared_with(non_project_user) @@ -211,10 +211,10 @@ # Additional filter for: project members (users only) # role: view # type: project members (users only) - share_modal.filter("type", I18n.t("work_package.sharing.filter.project_member")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.project_member')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(project_user, "View") + share_modal.expect_shared_with(project_user, 'View') share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) share_modal.expect_not_shared_with(non_project_user) @@ -224,10 +224,10 @@ # Change type filter to: project members (groups only) # role: view # type: non-project members (groups only) - share_modal.filter("type", I18n.t("work_package.sharing.filter.not_project_group")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.not_project_group')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(shared_non_project_group, 'View') share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) @@ -237,10 +237,10 @@ # Reset role filter # role: none # type: non-project members (groups only) - share_modal.filter("role", I18n.t("work_package.sharing.permissions.view")) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.view')) share_modal.expect_shared_count_of(1) - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(shared_non_project_group, 'View') share_modal.expect_not_shared_with(project_user) share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) @@ -250,22 +250,22 @@ # Reset type filter # role: none # type: none - share_modal.filter("type", I18n.t("work_package.sharing.filter.not_project_group")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.not_project_group')) share_modal.expect_shared_count_of(6) - share_modal.expect_shared_with(project_user, "View") - share_modal.expect_shared_with(project_user2, "Comment") - share_modal.expect_shared_with(inherited_project_user, "Edit") - share_modal.expect_shared_with(non_project_user, "Edit") - share_modal.expect_shared_with(shared_project_group, "Edit") - share_modal.expect_shared_with(shared_non_project_group, "View") + share_modal.expect_shared_with(project_user, 'View') + share_modal.expect_shared_with(project_user2, 'Comment') + share_modal.expect_shared_with(inherited_project_user, 'Edit') + share_modal.expect_shared_with(non_project_user, 'Edit') + share_modal.expect_shared_with(shared_project_group, 'Edit') + share_modal.expect_shared_with(shared_non_project_group, 'View') end - context "and there are no matching results for my filter" do + context 'and there are no matching results for my filter' do it 'does not check the "toggle all" checkbox' do share_modal.expect_open - share_modal.filter("type", I18n.t("work_package.sharing.filter.not_project_member")) - share_modal.filter("role", I18n.t("work_package.sharing.permissions.view")) + share_modal.filter('type', I18n.t('work_package.sharing.filter.not_project_member')) + share_modal.filter('role', I18n.t('work_package.sharing.permissions.view')) share_modal.expect_empty_search_blankslate share_modal.expect_shared_count_of(0) @@ -273,14 +273,14 @@ end end - it "only displays shares that match the current set of applied filters" do + it 'only displays shares that match the current set of applied filters' do share_modal.expect_open share_modal.toggle_select_all share_modal.bulk_update("View") share_modal.toggle_select_all - share_modal.filter("role", "View") + share_modal.filter('role', "View") share_modal.expect_shared_with(project_user) share_modal.expect_shared_with(project_user2) @@ -290,7 +290,7 @@ share_modal.expect_shared_with(shared_non_project_group) share_modal.change_role(project_user, "Comment") - share_modal.filter("role", "Comment") + share_modal.filter('role', "Comment") share_modal.expect_shared_with(project_user, "Comment") share_modal.expect_not_shared_with(project_user2) share_modal.expect_not_shared_with(inherited_project_user) @@ -298,22 +298,22 @@ share_modal.expect_not_shared_with(shared_project_group) share_modal.expect_not_shared_with(shared_non_project_group) - share_modal.filter("role", "Edit") + share_modal.filter('role', "Edit") share_modal.expect_empty_search_blankslate end - context "when filtering for a specific role" do + context 'when filtering for a specific role' do before do share_modal.expect_open - share_modal.filter("role", "View") + share_modal.filter('role', "View") end - context "and a share from the filtered list is subsequently updated" do + context 'and a share from the filtered list is subsequently updated' do before do share_modal.change_role(project_user, "Comment") end - it "removes the updated share from the list" do + it 'removes the updated share from the list' do share_modal.expect_not_shared_with(project_user) end end diff --git a/spec/features/work_packages/share/multi_invite_spec.rb b/spec/features/work_packages/share/multi_invite_spec.rb index 0b6f77f1e687..588a0cd8a88b 100644 --- a/spec/features/work_packages/share/multi_invite_spec.rb +++ b/spec/features/work_packages/share/multi_invite_spec.rb @@ -28,18 +28,18 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package sharing", +RSpec.describe 'Work package sharing', :js, :with_cuprite, with_ee: %i[work_package_sharing] do shared_let(:view_work_package_role) { create(:view_work_package_role) } shared_let(:comment_work_package_role) { create(:comment_work_package_role) } shared_let(:edit_work_package_role) { create(:edit_work_package_role) } - shared_let(:not_shared_yet_with_user) { create(:user, firstname: "Not shared Yet", lastname: "User") } - shared_let(:another_not_shared_yet_with_user) { create(:user, firstname: "Another not yet shared", lastname: "User") } - shared_let(:richard) { create(:user, firstname: "Richard", lastname: "Hendricks") } + shared_let(:not_shared_yet_with_user) { create(:user, firstname: 'Not shared Yet', lastname: 'User') } + shared_let(:another_not_shared_yet_with_user) { create(:user, firstname: 'Another not yet shared', lastname: 'User') } + shared_let(:richard) { create(:user, firstname: 'Richard', lastname: 'Hendricks') } shared_let(:not_shared_yet_with_group) { create(:group, members: [richard]) } shared_let(:empty_group) { create(:group, members: []) } @@ -64,7 +64,7 @@ let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } let(:share_modal) { Components::WorkPackages::ShareModal.new(work_package) } - current_user { create(:user, firstname: "Signed in", lastname: "User") } + current_user { create(:user, firstname: 'Signed in', lastname: 'User') } def shared_principals Principal.where(id: Member.of_work_package(work_package).select(:user_id)) @@ -74,8 +74,8 @@ def inherited_member_roles(group:) MemberRole.where(inherited_from: MemberRole.where(member_id: group.memberships)) end - context "when having share permission" do - it "allows seeing and administrating sharing" do + context 'when having share permission' do + it 'allows seeing and administrating sharing' do work_package_page.visit! # Clicking on the share button opens a modal which lists all of the users a work package @@ -87,12 +87,12 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(1) # Inviting multiple users at once - share_modal.invite_users([not_shared_yet_with_user, another_not_shared_yet_with_user], "Edit") + share_modal.invite_users([not_shared_yet_with_user, another_not_shared_yet_with_user], 'Edit') share_modal.expect_shared_count_of(3) - share_modal.expect_shared_with(not_shared_yet_with_user, "Edit", position: 1) - share_modal.expect_shared_with(another_not_shared_yet_with_user, "Edit", position: 2) + share_modal.expect_shared_with(not_shared_yet_with_user, 'Edit', position: 1) + share_modal.expect_shared_with(another_not_shared_yet_with_user, 'Edit', position: 2) # They can be removed again share_modal.remove_user(not_shared_yet_with_user) @@ -103,12 +103,12 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(1) # Groups can be added simultaneously as well - share_modal.invite_users([not_shared_yet_with_group, empty_group], "Comment") + share_modal.invite_users([not_shared_yet_with_group, empty_group], 'Comment') share_modal.expect_shared_count_of(3) - share_modal.expect_shared_with(not_shared_yet_with_group, "Comment", position: 1) - share_modal.expect_shared_with(empty_group, "Comment", position: 2) + share_modal.expect_shared_with(not_shared_yet_with_group, 'Comment', position: 1) + share_modal.expect_shared_with(empty_group, 'Comment', position: 2) # They can be removed again share_modal.remove_user(not_shared_yet_with_group) @@ -118,12 +118,12 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(1) # We can also mix - share_modal.invite_users([not_shared_yet_with_user, empty_group], "View") + share_modal.invite_users([not_shared_yet_with_user, empty_group], 'View') share_modal.expect_shared_count_of(3) - share_modal.expect_shared_with(not_shared_yet_with_user, "View", position: 1) - share_modal.expect_shared_with(empty_group, "View", position: 2) + share_modal.expect_shared_with(not_shared_yet_with_user, 'View', position: 1) + share_modal.expect_shared_with(empty_group, 'View', position: 2) # They can be removed again share_modal.remove_user(not_shared_yet_with_user) @@ -138,7 +138,7 @@ def inherited_member_roles(group:) aggregate_failures "Re-opening the modal after changes performed" do # This user preserved - share_modal.expect_shared_with(richard, "Edit", position: 1) + share_modal.expect_shared_with(richard, 'Edit', position: 1) # The users have been removed share_modal.expect_not_shared_with(not_shared_yet_with_user) @@ -153,7 +153,7 @@ def inherited_member_roles(group:) end end - context "when starting with no shares yet" do + context 'when starting with no shares yet' do let(:work_package) { create(:work_package, project:) } let(:global_manager_user) { create(:user, global_permissions: %i[manage_user create_user]) } let(:current_user) { global_manager_user } @@ -163,18 +163,18 @@ def inherited_member_roles(group:) work_package_page.click_share_button end - it "allows adding multiple users and updates the modal correctly" do + it 'allows adding multiple users and updates the modal correctly' do share_modal.expect_open share_modal.expect_blankslate - share_modal.invite_users([not_shared_yet_with_user, another_not_shared_yet_with_user], "Edit") + share_modal.invite_users([not_shared_yet_with_user, another_not_shared_yet_with_user], 'Edit') share_modal.expect_shared_count_of(2) # Due to the exception of starting from a blankslate, the whole modal is re-rendered. # Thus the principals are sorted alphabetically, and not by the time there were added - share_modal.expect_shared_with(not_shared_yet_with_user, "Edit", position: 2) - share_modal.expect_shared_with(another_not_shared_yet_with_user, "Edit", position: 1) + share_modal.expect_shared_with(not_shared_yet_with_user, 'Edit', position: 2) + share_modal.expect_shared_with(another_not_shared_yet_with_user, 'Edit', position: 1) # They can be removed again share_modal.remove_user(not_shared_yet_with_user) @@ -186,11 +186,11 @@ def inherited_member_roles(group:) end end - context "when having global invite permission" do + context 'when having global invite permission' do let(:global_manager_user) { create(:user, global_permissions: %i[manage_user create_user]) } let(:current_user) { global_manager_user } - it "allows creating multiple users at once" do + it 'allows creating multiple users at once' do work_package_page.visit! work_package_page.click_share_button @@ -198,7 +198,7 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(1) # Invite two users that does not exist yet - share_modal.invite_users(["hello@world.de", "aloha@world.de"], "Comment") + share_modal.invite_users(['hello@world.de', 'aloha@world.de'], 'Comment') # New user is shown in the list of shares share_modal.expect_shared_count_of(3) @@ -206,20 +206,20 @@ def inherited_member_roles(group:) # New user is created new_users = User.last(2) - share_modal.expect_shared_with(new_users[0], "Comment", position: 1) - share_modal.expect_shared_with(new_users[1], "Comment", position: 2) + share_modal.expect_shared_with(new_users[0], 'Comment', position: 1) + share_modal.expect_shared_with(new_users[1], 'Comment', position: 2) # The new users can be interacted with - share_modal.change_role(new_users[0], "View") - share_modal.expect_shared_with(new_users[0], "View", position: 1) - share_modal.change_role(new_users[1], "View") - share_modal.expect_shared_with(new_users[1], "View", position: 2) + share_modal.change_role(new_users[0], 'View') + share_modal.expect_shared_with(new_users[0], 'View', position: 1) + share_modal.change_role(new_users[1], 'View') + share_modal.expect_shared_with(new_users[1], 'View', position: 2) share_modal.expect_shared_count_of(3) # The new users can be updated simultaneously - share_modal.invite_user(new_users, "Edit") - share_modal.expect_shared_with(new_users[0], "Edit", position: 1) - share_modal.expect_shared_with(new_users[1], "Edit", position: 2) + share_modal.invite_user(new_users, 'Edit') + share_modal.expect_shared_with(new_users[0], 'Edit', position: 1) + share_modal.expect_shared_with(new_users[1], 'Edit', position: 2) share_modal.expect_shared_count_of(3) # The new users can be deleted @@ -230,7 +230,7 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(1) end - it "allows sharing with an existing user and creating a new one at the same time" do + it 'allows sharing with an existing user and creating a new one at the same time' do work_package_page.visit! work_package_page.click_share_button @@ -241,9 +241,9 @@ def inherited_member_roles(group:) share_modal.select_existing_user not_shared_yet_with_user share_modal.select_not_existing_user_option "hello@world.de" - share_modal.select_invite_role("View") + share_modal.select_invite_role('View') within share_modal.modal_element do - click_button "Share" + click_button 'Share' end # Two users are added @@ -252,11 +252,11 @@ def inherited_member_roles(group:) # New user is created new_user = User.last - share_modal.expect_shared_with(not_shared_yet_with_user, "View", position: 1) - share_modal.expect_shared_with(new_user, "View", position: 2) + share_modal.expect_shared_with(not_shared_yet_with_user, 'View', position: 1) + share_modal.expect_shared_with(new_user, 'View', position: 2) end - context "and an instance user limit" do + context 'and an instance user limit' do before do allow(OpenProject::Enterprise).to receive_messages( user_limit: 10, @@ -264,7 +264,7 @@ def inherited_member_roles(group:) ) end - it "shows a warning as soon as you reach the user limit" do + it 'shows a warning as soon as you reach the user limit' do work_package_page.visit! work_package_page.click_share_button diff --git a/spec/features/work_packages/share/notification_spec.rb b/spec/features/work_packages/share/notification_spec.rb index dc5b39342181..adc4fd1ddfc9 100644 --- a/spec/features/work_packages/share/notification_spec.rb +++ b/spec/features/work_packages/share/notification_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe "Notifications sent on shared work packages", :js, @@ -62,7 +62,7 @@ let(:center) { Pages::Notifications::Center.new } let(:side_menu) { Components::Notifications::Sidemenu.new } - describe "notification for being mentioned" do + describe 'notification for being mentioned' do before do # The notifications need to be created as a different user # as they are otherwise swallowed to avoid self notification. @@ -76,7 +76,7 @@ end end - it "mentioned user receives a notification" do + it 'mentioned user receives a notification' do login_as(recipient) visit home_path @@ -88,13 +88,13 @@ center.expect_work_package_item notification_mentioned - side_menu.click_item "Mentioned" + side_menu.click_item 'Mentioned' side_menu.finished_loading center.expect_work_package_item notification_mentioned end end - describe "notification for being shared with" do + describe 'notification for being shared with' do before do # The notifications need to be created as a different user # as they are otherwise swallowed to avoid self notification. @@ -108,7 +108,7 @@ end end - it "shared with user receives notification" do + it 'shared with user receives notification' do login_as(recipient) visit home_path @@ -120,7 +120,7 @@ center.expect_work_package_item notification_shared - side_menu.click_item "Shared" + side_menu.click_item 'Shared' side_menu.finished_loading center.expect_work_package_item notification_shared end diff --git a/spec/features/work_packages/share/share_account_activation_spec.rb b/spec/features/work_packages/share/share_account_activation_spec.rb index abbadf5e2041..16f53666892e 100644 --- a/spec/features/work_packages/share/share_account_activation_spec.rb +++ b/spec/features/work_packages/share/share_account_activation_spec.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package sharing invited users", +RSpec.describe 'Work package sharing invited users', :js, :with_cuprite, with_ee: %i[work_package_sharing] do shared_let(:view_work_package_role) { create(:view_work_package_role) } - shared_let(:editor) { create(:admin, firstname: "Mr.", lastname: "Sharer") } + shared_let(:editor) { create(:admin, firstname: 'Mr.', lastname: 'Sharer') } shared_let(:sharer_role) do create(:project_role, @@ -54,16 +54,16 @@ let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } let(:share_modal) { Components::WorkPackages::ShareModal.new(work_package) } - it "allows to invite and activate the account" do - login_with(editor.login, "adminADMIN!") - expect(page).to have_current_path "/my/page" + it 'allows to invite and activate the account' do + login_with(editor.login, 'adminADMIN!') + expect(page).to have_current_path '/my/page' work_package_page.visit! work_package_page.click_share_button share_modal.expect_open # Invite a user that does not exist yet - share_modal.invite_user("foobar@example.com", "View") + share_modal.invite_user('foobar@example.com', 'View') # New user is shown in the list of shares share_modal.expect_shared_count_of(1) @@ -76,23 +76,23 @@ user = token.user expect(token).to be_present expect(user).to be_invited - expect(user.mail).to eq "foobar@example.com" + expect(user.mail).to eq 'foobar@example.com' expect(link).to include token.value # Can log in and register the first time visit signout_path visit link - expect(page).to have_text "Create a new account" + expect(page).to have_text 'Create a new account' password = SecureRandom.hex(16) - fill_in "Password", with: password - fill_in "Confirmation", with: password + fill_in 'Password', with: password + fill_in 'Confirmation', with: password - click_button "Create" + click_button 'Create' - expect(page).to have_text "Welcome, your account has been activated. You are logged in now." - expect(page).to have_current_path project_work_package_path(project, work_package.id, "activity") + expect(page).to have_text 'Welcome, your account has been activated. You are logged in now.' + expect(page).to have_current_path project_work_package_path(project, work_package.id, 'activity') expect(page).to have_text work_package.subject expect(user.reload).to be_active @@ -101,10 +101,10 @@ visit signout_path visit link - expect(page).to have_text "Sign in" - login_with "foobar@example.com", password, visit_signin_path: false + expect(page).to have_text 'Sign in' + login_with 'foobar@example.com', password, visit_signin_path: false - expect(page).to have_current_path project_work_package_path(project, work_package.id, "activity") + expect(page).to have_current_path project_work_package_path(project, work_package.id, 'activity') expect(page).to have_text work_package.subject end end diff --git a/spec/features/work_packages/share/share_spec.rb b/spec/features/work_packages/share/share_spec.rb index 33d4fbc47b7b..68e6797c63d5 100644 --- a/spec/features/work_packages/share/share_spec.rb +++ b/spec/features/work_packages/share/share_spec.rb @@ -28,25 +28,25 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package sharing", +RSpec.describe 'Work package sharing', :js, :with_cuprite, with_ee: %i[work_package_sharing] do shared_let(:view_work_package_role) { create(:view_work_package_role) } shared_let(:comment_work_package_role) { create(:comment_work_package_role) } shared_let(:edit_work_package_role) { create(:edit_work_package_role) } - shared_let(:view_user) { create(:user, firstname: "View", lastname: "User") } - shared_let(:comment_user) { create(:user, firstname: "Comment", lastname: "User") } - shared_let(:edit_user) { create(:user, firstname: "Edit", lastname: "User") } - shared_let(:non_shared_project_user) { create(:user, firstname: "Non Shared Project", lastname: "User") } - shared_let(:shared_project_user) { create(:user, firstname: "Shared Project", lastname: "User") } - shared_let(:not_shared_yet_with_user) { create(:user, firstname: "Not shared Yet", lastname: "User") } + shared_let(:view_user) { create(:user, firstname: 'View', lastname: 'User') } + shared_let(:comment_user) { create(:user, firstname: 'Comment', lastname: 'User') } + shared_let(:edit_user) { create(:user, firstname: 'Edit', lastname: 'User') } + shared_let(:non_shared_project_user) { create(:user, firstname: 'Non Shared Project', lastname: 'User') } + shared_let(:shared_project_user) { create(:user, firstname: 'Shared Project', lastname: 'User') } + shared_let(:not_shared_yet_with_user) { create(:user, firstname: 'Not shared Yet', lastname: 'User') } - shared_let(:richard) { create(:user, firstname: "Richard", lastname: "Hendricks") } - shared_let(:dinesh) { create(:user, firstname: "Dinesh", lastname: "Chugtai") } - shared_let(:gilfoyle) { create(:user, firstname: "Bertram", lastname: "Gilfoyle") } + shared_let(:richard) { create(:user, firstname: 'Richard', lastname: 'Hendricks') } + shared_let(:dinesh) { create(:user, firstname: 'Dinesh', lastname: 'Chugtai') } + shared_let(:gilfoyle) { create(:user, firstname: 'Bertram', lastname: 'Gilfoyle') } shared_let(:not_shared_yet_with_group) { create(:group, members: [richard, dinesh, gilfoyle]) } let(:project) do @@ -81,7 +81,7 @@ let(:columns) { Components::WorkPackages::Columns.new } let(:wp_modal) { Components::WorkPackages::TableConfigurationModal.new } - current_user { create(:user, firstname: "Signed in", lastname: "User") } + current_user { create(:user, firstname: 'Signed in', lastname: 'User') } def shared_principals Principal.where(id: Member.of_work_package(work_package).select(:user_id)) @@ -91,8 +91,8 @@ def inherited_member_roles(group:) MemberRole.where(inherited_from: MemberRole.where(member_id: group.memberships)) end - context "when having share permission" do - it "allows seeing and administrating sharing" do + context 'when having share permission' do + it 'allows seeing and administrating sharing' do work_package_page.visit! # Clicking on the share button opens a modal which lists all of the users a work package @@ -102,14 +102,14 @@ def inherited_member_roles(group:) work_package_page.click_share_button aggregate_failures "Initial shares list" do - share_modal.expect_title(I18n.t("js.work_packages.sharing.title")) - share_modal.expect_shared_with(comment_user, "Comment", position: 1) - share_modal.expect_shared_with(dinesh, "Edit", position: 2) - share_modal.expect_shared_with(edit_user, "Edit", position: 3) - share_modal.expect_shared_with(shared_project_user, "Edit", position: 4) + share_modal.expect_title(I18n.t('js.work_packages.sharing.title')) + share_modal.expect_shared_with(comment_user, 'Comment', position: 1) + share_modal.expect_shared_with(dinesh, 'Edit', position: 2) + share_modal.expect_shared_with(edit_user, 'Edit', position: 3) + share_modal.expect_shared_with(shared_project_user, 'Edit', position: 4) # The current users share is also displayed but not editable share_modal.expect_shared_with(current_user, position: 5, editable: false) - share_modal.expect_shared_with(view_user, "View", position: 6) + share_modal.expect_shared_with(view_user, 'View', position: 6) share_modal.expect_not_shared_with(non_shared_project_user) share_modal.expect_not_shared_with(not_shared_yet_with_user) @@ -119,9 +119,9 @@ def inherited_member_roles(group:) aggregate_failures "Inviting a user for the first time" do # Inviting a user will lead to that user being prepended to the list together with the rest of the shared with users. - share_modal.invite_user(not_shared_yet_with_user, "View") + share_modal.invite_user(not_shared_yet_with_user, 'View') - share_modal.expect_shared_with(not_shared_yet_with_user, "View", position: 1) + share_modal.expect_shared_with(not_shared_yet_with_user, 'View', position: 1) share_modal.expect_shared_count_of(7) end @@ -134,8 +134,8 @@ def inherited_member_roles(group:) aggregate_failures "Re-inviting a user" do # Adding a user multiple times will lead to the user's role being updated. - share_modal.invite_user(not_shared_yet_with_user, "Edit") - share_modal.expect_shared_with(not_shared_yet_with_user, "Edit", position: 1) + share_modal.invite_user(not_shared_yet_with_user, 'Edit') + share_modal.expect_shared_with(not_shared_yet_with_user, 'Edit', position: 1) share_modal.expect_shared_count_of(6) # Sent out email only on first share and not again when updating. @@ -145,8 +145,8 @@ def inherited_member_roles(group:) aggregate_failures "Updating a share" do # Updating the share - share_modal.change_role(not_shared_yet_with_user, "Comment") - share_modal.expect_shared_with(not_shared_yet_with_user, "Comment", position: 1) + share_modal.change_role(not_shared_yet_with_user, 'Comment') + share_modal.expect_shared_with(not_shared_yet_with_user, 'Comment', position: 1) share_modal.expect_shared_count_of(6) # Sent out email only on first share and not again when updating so the @@ -158,11 +158,11 @@ def inherited_member_roles(group:) aggregate_failures "Inviting a group" do # Inviting a group propagates the membership to the group's users. However, these propagated # memberships are not expected to be visible. - share_modal.invite_group(not_shared_yet_with_group, "View") - share_modal.expect_shared_with(not_shared_yet_with_group, "View", position: 1) + share_modal.invite_group(not_shared_yet_with_group, 'View') + share_modal.expect_shared_with(not_shared_yet_with_group, 'View', position: 1) # This user has a share independent of the group's share. Hence, that Role prevails - share_modal.expect_shared_with(dinesh, "Edit") + share_modal.expect_shared_with(dinesh, 'Edit') share_modal.expect_not_shared_with(richard) share_modal.expect_not_shared_with(gilfoyle) @@ -183,8 +183,8 @@ def inherited_member_roles(group:) aggregate_failures "Inviting a group member with its own independent role" do # Inviting a group user to a Work Package independently of the the group displays # said user in the shares list - share_modal.invite_user(gilfoyle, "Comment") - share_modal.expect_shared_with(gilfoyle, "Comment", position: 1) + share_modal.invite_user(gilfoyle, 'Comment') + share_modal.expect_shared_with(gilfoyle, 'Comment', position: 1) share_modal.expect_shared_count_of(8) perform_enqueued_jobs @@ -196,10 +196,10 @@ def inherited_member_roles(group:) aggregate_failures "Updating a group's share" do # Updating a group's share role also propagates to the inherited member roles of # its users - share_modal.change_role(not_shared_yet_with_group, "Comment") + share_modal.change_role(not_shared_yet_with_group, 'Comment') wait_for_network_idle - share_modal.expect_shared_with(not_shared_yet_with_group, "Comment") + share_modal.expect_shared_with(not_shared_yet_with_group, 'Comment') share_modal.expect_shared_count_of(8) expect(inherited_member_roles(group: not_shared_yet_with_group)) .to all(have_attributes(role: comment_work_package_role)) @@ -217,8 +217,8 @@ def inherited_member_roles(group:) share_modal.expect_not_shared_with(not_shared_yet_with_group) share_modal.expect_not_shared_with(richard) - share_modal.expect_shared_with(dinesh, "Edit") - share_modal.expect_shared_with(gilfoyle, "Comment") + share_modal.expect_shared_with(dinesh, 'Edit') + share_modal.expect_shared_with(gilfoyle, 'Comment') share_modal.expect_shared_count_of(7) expect(inherited_member_roles(group: not_shared_yet_with_group)) .to be_empty @@ -235,16 +235,16 @@ def inherited_member_roles(group:) aggregate_failures "Re-opening the modal after changes performed" do # This user preserved its group independent share - share_modal.expect_shared_with(gilfoyle, "Comment", position: 1) - share_modal.expect_shared_with(comment_user, "Comment", position: 2) + share_modal.expect_shared_with(gilfoyle, 'Comment', position: 1) + share_modal.expect_shared_with(comment_user, 'Comment', position: 2) # This user preserved its group independent share - share_modal.expect_shared_with(dinesh, "Edit", position: 3) + share_modal.expect_shared_with(dinesh, 'Edit', position: 3) # This user's role was updated - share_modal.expect_shared_with(not_shared_yet_with_user, "Comment", position: 4) + share_modal.expect_shared_with(not_shared_yet_with_user, 'Comment', position: 4) # These users were not changed - share_modal.expect_shared_with(shared_project_user, "Edit", position: 5) + share_modal.expect_shared_with(shared_project_user, 'Edit', position: 5) share_modal.expect_shared_with(current_user, position: 6, editable: false) - share_modal.expect_shared_with(view_user, "View", position: 7) + share_modal.expect_shared_with(view_user, 'View', position: 7) # This group's share was revoked share_modal.expect_not_shared_with(not_shared_yet_with_group) @@ -260,54 +260,54 @@ def inherited_member_roles(group:) visit project_members_path(project) - aggregate_failures "Observing the shared members with view permission" do - members_page.click_menu_item "View" + aggregate_failures 'Observing the shared members with view permission' do + members_page.click_menu_item 'View' expect(members_page).to have_user view_user.name members_page.in_user_row(view_user) do - expect(page).to have_text "1 work package" + expect(page).to have_text '1 work package' end expect(members_page).not_to have_user gilfoyle.name expect(members_page).not_to have_user comment_user.name expect(members_page).not_to have_user dinesh.name end - aggregate_failures "Observing the shared members with comment permission" do - members_page.click_menu_item "Comment" + aggregate_failures 'Observing the shared members with comment permission' do + members_page.click_menu_item 'Comment' expect(members_page).to have_user gilfoyle.name members_page.in_user_row(gilfoyle) do - expect(page).to have_text "1 work package" + expect(page).to have_text '1 work package' end expect(members_page).to have_user comment_user.name expect(members_page).not_to have_user view_user.name expect(members_page).not_to have_user dinesh.name end - aggregate_failures "Observing the shared members with edit permission" do - members_page.click_menu_item "Edit" + aggregate_failures 'Observing the shared members with edit permission' do + members_page.click_menu_item 'Edit' expect(members_page).to have_user dinesh.name expect(members_page).not_to have_user gilfoyle.name expect(members_page).not_to have_user comment_user.name expect(members_page).not_to have_user view_user.name end - aggregate_failures "Showing the shared users in the table" do + aggregate_failures 'Showing the shared users in the table' do wp_table.visit! wp_modal.open! - wp_modal.switch_to "Columns" + wp_modal.switch_to 'Columns' columns.assume_opened columns.uncheck_all save_changes: false - columns.add "ID", save_changes: false - columns.add "Subject", save_changes: false - columns.add "Shared with", save_changes: false + columns.add 'ID', save_changes: false + columns.add 'Subject', save_changes: false + columns.add 'Shared with', save_changes: false columns.apply wp_row = wp_table.row(work_package) - expect(wp_row).to have_css(".wp-table--cell-td.sharedWithUsers .badge", text: "7") - wp_row.find(".wp-table--cell-td.sharedWithUsers .badge").click + expect(wp_row).to have_css('.wp-table--cell-td.sharedWithUsers .badge', text: '7') + wp_row.find('.wp-table--cell-td.sharedWithUsers .badge').click - share_modal.expect_title(I18n.t("js.work_packages.sharing.title")) + share_modal.expect_title(I18n.t('js.work_packages.sharing.title')) share_modal.expect_shared_count_of(7) end end @@ -320,20 +320,20 @@ def inherited_member_roles(group:) share_modal.click_share share_modal.expect_select_a_user_hint - share_modal.invite_user(not_shared_yet_with_user, "View") + share_modal.invite_user(not_shared_yet_with_user, 'View') share_modal.expect_shared_with(not_shared_yet_with_user, position: 1) share_modal.expect_no_select_a_user_hint end end - context "when lacking share permission but having the viewing permission" do + context 'when lacking share permission but having the viewing permission' do let(:sharer_role) do create(:project_role, permissions: %i(view_work_packages view_shared_work_packages)) end - it "allows seeing shares but not editing" do + it 'allows seeing shares but not editing' do work_package_page.visit! # Clicking on the share button opens a modal which lists all of the users a work package @@ -383,42 +383,42 @@ def inherited_member_roles(group:) it_behaves_like "'Share' button is not rendered" end - context "when having global invite permission" do + context 'when having global invite permission' do let(:global_manager_user) { create(:user, global_permissions: %i[manage_user create_user]) } let(:current_user) { global_manager_user } - let(:locked_user) { create(:user, mail: "holly@openproject.com", status: :locked) } + let(:locked_user) { create(:user, mail: 'holly@openproject.com', status: :locked) } before do work_package_page.visit! work_package_page.click_share_button end - it "allows inviting and directly sharing with a user who is not part of the instance yet" do + it 'allows inviting and directly sharing with a user who is not part of the instance yet' do share_modal.expect_open share_modal.expect_shared_count_of(6) # Invite a user that does not exist yet - share_modal.invite_user("hello@world.de", "View") + share_modal.invite_user('hello@world.de', 'View') # New user is shown in the list of shares share_modal.expect_shared_count_of(7) # New user is created new_user = User.last - share_modal.expect_shared_with(new_user, "View", position: 1) + share_modal.expect_shared_with(new_user, 'View', position: 1) perform_enqueued_jobs # Only one combined email for create and share should be send out expect(ActionMailer::Base.deliveries.size).to eq(1) # The new user can be interacted with - share_modal.change_role(new_user, "Comment") - share_modal.expect_shared_with(new_user, "Comment", position: 1) + share_modal.change_role(new_user, 'Comment') + share_modal.expect_shared_with(new_user, 'Comment', position: 1) share_modal.expect_shared_count_of(7) # The new user can be updated - share_modal.invite_user(new_user, "Edit") - share_modal.expect_shared_with(new_user, "Edit", position: 1) + share_modal.invite_user(new_user, 'Edit') + share_modal.expect_shared_with(new_user, 'Edit', position: 1) share_modal.expect_shared_count_of(7) # The invite can be resent @@ -434,7 +434,7 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(6) end - it "shows an error message when inviting an existing locked user" do + it 'shows an error message when inviting an existing locked user' do share_modal.expect_open share_modal.expect_shared_count_of(6) @@ -446,7 +446,7 @@ def inherited_member_roles(group:) share_modal.expect_no_ng_option("", locked_user.name, results_selector: "body") # Invite the email address - share_modal.invite_user(locked_user.mail, "View") + share_modal.invite_user(locked_user.mail, 'View') # The number of shared people has not changed, but an error message is shown share_modal.expect_shared_count_of(6) @@ -454,8 +454,8 @@ def inherited_member_roles(group:) end end - context "when lacking global invite permission" do - it "does not allow creating a user who is not part of the instance yet" do + context 'when lacking global invite permission' do + it 'does not allow creating a user who is not part of the instance yet' do work_package_page.visit! work_package_page.click_share_button @@ -463,7 +463,7 @@ def inherited_member_roles(group:) share_modal.expect_shared_count_of(6) # Search for a user that does not exist - share_modal.search_user("hello@world.de") + share_modal.search_user('hello@world.de') # There is no option to directly create and share the WP for the unknown email address share_modal.expect_no_ng_option("", 'Send invite to"hello@world.de"', results_selector: "body") diff --git a/spec/features/work_packages/shared_contexts.rb b/spec/features/work_packages/shared_contexts.rb index 6ebb643a2552..d9e8a4bb2db1 100644 --- a/spec/features/work_packages/shared_contexts.rb +++ b/spec/features/work_packages/shared_contexts.rb @@ -28,7 +28,7 @@ # Ensure the page is completely loaded before the spec is run. # The status filter is loaded very late in the page setup. -RSpec.shared_context "ensure wp details pane update done" do +RSpec.shared_context 'ensure wp details pane update done' do after do unless update_user raise "Expect to have a let called 'update_user' defining which user \ @@ -37,7 +37,7 @@ # safeguard to ensure all backend queries # have been answered before starting a new spec - expect(page).to have_css(".op-user-activity--user-name", + expect(page).to have_css('.op-user-activity--user-name', text: update_user.name) end end diff --git a/spec/features/work_packages/sorting/manual_sorting_spec.rb b/spec/features/work_packages/sorting/manual_sorting_spec.rb index e871dddf1126..385c9c17d6dd 100644 --- a/spec/features/work_packages/sorting/manual_sorting_spec.rb +++ b/spec/features/work_packages/sorting/manual_sorting_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Manual sorting of WP table", :js do +RSpec.describe 'Manual sorting of WP table', :js do let(:user) { create(:admin) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -37,11 +37,11 @@ let(:type_bug) { create(:type_bug) } let(:project) { create(:project, types: [type_task, type_bug], enabled_module_names: %i[work_package_tracking gantt]) } let(:work_package1) do - create(:work_package, subject: "WP1", project:, type: type_task, created_at: Time.zone.now) + create(:work_package, subject: 'WP1', project:, type: type_task, created_at: Time.zone.now) end let(:work_package2) do create(:work_package, - subject: "WP2", + subject: 'WP2', project:, parent: work_package1, type: type_task, @@ -49,7 +49,7 @@ end let(:work_package3) do create(:work_package, - subject: "WP3", + subject: 'WP3', project:, parent: work_package2, type: type_bug, @@ -57,7 +57,7 @@ end let(:work_package4) do create(:work_package, - subject: "WP4", + subject: 'WP4', project:, parent: work_package3, type: type_bug, @@ -89,7 +89,7 @@ def expect_query_order(query, expected) work_package4 end - describe "hierarchy mode" do + describe 'hierarchy mode' do before do wp_table.visit! @@ -99,18 +99,18 @@ def expect_query_order(query, expected) hierarchies.expect_leaf_at(work_package4) end - it "maintains the order and automatically saves the query" do + it 'maintains the order and automatically saves the query' do wp_table.drag_and_drop_work_package from: 3, to: 1 loading_indicator_saveguard hierarchies.expect_hierarchy_at(work_package1, work_package2) hierarchies.expect_leaf_at(work_package4, work_package3) - wp_table.expect_and_dismiss_toaster message: "Successful creation." + wp_table.expect_and_dismiss_toaster message: 'Successful creation.' query = nil retry_block do query = Query.last - raise "Query was not yet saved." unless query.name == "New manually sorted query" + raise "Query was not yet saved." unless query.name == 'New manually sorted query' end # Expect sorted 1 and 2, the rest is not positioned @@ -121,7 +121,7 @@ def expect_query_order(query, expected) pagination.expect_no_per_page_options end - it "can drag an element into a hierarchy" do + it 'can drag an element into a hierarchy' do # Move up the hierarchy wp_table.drag_and_drop_work_package from: 3, to: 1 loading_indicator_saveguard @@ -134,7 +134,7 @@ def expect_query_order(query, expected) hierarchies.expect_leaf_at(work_package3, work_package4) end - it "can drag an element completely out of the hierarchy" do + it 'can drag an element completely out of the hierarchy' do # Move up the hierarchy wp_table.drag_and_drop_work_package from: 3, to: 0 loading_indicator_saveguard @@ -153,12 +153,12 @@ def expect_query_order(query, expected) wp_page.expect_no_parent end - context "when dragging an element partly out of the hierarchy" do + context 'when dragging an element partly out of the hierarchy' do let(:work_package5) do - create(:work_package, subject: "WP5", project:, parent: work_package1) + create(:work_package, subject: 'WP5', project:, parent: work_package1) end let(:work_package6) do - create(:work_package, subject: "WP6", project:, parent: work_package1) + create(:work_package, subject: 'WP6', project:, parent: work_package1) end before do @@ -179,7 +179,7 @@ def expect_query_order(query, expected) hierarchies.expect_leaf_at(work_package3, work_package4, work_package5, work_package6) end - it "move below a sibling of my parent" do + it 'move below a sibling of my parent' do wp_table.drag_and_drop_work_package from: 3, to: 5 loading_indicator_saveguard @@ -195,46 +195,46 @@ def expect_query_order(query, expected) end end - describe "group mode" do - describe "group by type" do + describe 'group mode' do + describe 'group by type' do let(:group_by) { Components::WorkPackages::GroupBy.new } before do wp_table.visit! - group_by.enable_via_menu "Type" + group_by.enable_via_menu 'Type' - wp_table.save_as "Type query" - wp_table.expect_and_dismiss_toaster message: "Successful creation." + wp_table.save_as 'Type query' + wp_table.expect_and_dismiss_toaster message: 'Successful creation.' end - it "updates the work packages appropriately" do - expect(page).to have_css(".group--value", text: "Task (2)") - expect(page).to have_css(".group--value", text: "Bug (2)") + it 'updates the work packages appropriately' do + expect(page).to have_css('.group--value', text: 'Task (2)') + expect(page).to have_css('.group--value', text: 'Bug (2)') wp_table.drag_and_drop_work_package from: 0, to: 3 - expect(page).to have_css(".group--value", text: "Task (1)") - expect(page).to have_css(".group--value", text: "Bug (3)") + expect(page).to have_css('.group--value', text: 'Task (1)') + expect(page).to have_css('.group--value', text: 'Bug (3)') end - it "dragging item with parent does not result in an error (Regression #30832)" do - expect(page).to have_css(".group--value", text: "Task (2)") - expect(page).to have_css(".group--value", text: "Bug (2)") + it 'dragging item with parent does not result in an error (Regression #30832)' do + expect(page).to have_css('.group--value', text: 'Task (2)') + expect(page).to have_css('.group--value', text: 'Bug (2)') wp_table.drag_and_drop_work_package from: 1, to: 3 - expect(page).to have_css(".group--value", text: "Task (1)") - expect(page).to have_css(".group--value", text: "Bug (3)") + expect(page).to have_css('.group--value', text: 'Task (1)') + expect(page).to have_css('.group--value', text: 'Bug (3)') - expect(page).to have_no_css ".op-toast.error" + expect(page).to have_no_css '.op-toast.error' end end end - describe "with a saved query and positions increasing from zero" do + describe 'with a saved query and positions increasing from zero' do let(:query) do create(:query, user:, project:, show_hierarchies: false).tap do |q| - q.sort_criteria = [[:manual_sorting, "asc"]] + q.sort_criteria = [[:manual_sorting, 'asc']] q.save! end end @@ -248,7 +248,7 @@ def expect_query_order(query, expected) OrderedWorkPackage.create(query:, work_package: work_package4, position: 3) end - it "can inline create a work package and it is positioned to the bottom (Regression #31078)" do + it 'can inline create a work package and it is positioned to the bottom (Regression #31078)' do wp_table.visit_query query wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4 @@ -257,17 +257,17 @@ def expect_query_order(query, expected) subject_field.expect_active! # Save the WP - subject_field.set_value "Foobar!" + subject_field.set_value 'Foobar!' subject_field.submit_by_enter wp_table.expect_and_dismiss_toaster( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) - wp_table.expect_work_package_subject "Foobar!" + wp_table.expect_work_package_subject 'Foobar!' inline_created = WorkPackage.last - expect(inline_created.subject).to eq "Foobar!" + expect(inline_created.subject).to eq 'Foobar!' # Wait until the order was saved, this might take a few moments retry_block do @@ -288,15 +288,15 @@ def expect_query_order(query, expected) end end - describe "with a saved query that is NOT manually sorted" do + describe 'with a saved query that is NOT manually sorted' do let(:query) do create(:query, user:, project:, show_hierarchies: false).tap do |q| - q.sort_criteria = [[:id, "asc"]] + q.sort_criteria = [[:id, 'asc']] q.save! end end - it "can drag and drop and will save the query" do + it 'can drag and drop and will save the query' do wp_table.visit_query query wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4 @@ -304,12 +304,12 @@ def expect_query_order(query, expected) wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4 - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' retry_block do query.reload - if query.sort_criteria != [["manual_sorting", "asc"]] + if query.sort_criteria != [['manual_sorting', 'asc']] raise "Expected sort_criteria to be updated to manual_sorting, was #{query.sort_criteria.inspect}" end end @@ -319,22 +319,22 @@ def expect_query_order(query, expected) end end - describe "flat mode" do + describe 'flat mode' do before do wp_table.visit! hierarchies.disable_via_header wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4 end - it "can sort table rows via DragNDrop" do + it 'can sort table rows via DragNDrop' do wp_table.drag_and_drop_work_package from: 1, to: 3 wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4 - wp_table.expect_and_dismiss_toaster message: "Successful creation." + wp_table.expect_and_dismiss_toaster message: 'Successful creation.' query = Query.last - expect(query.name).to eq "New manually sorted query" + expect(query.name).to eq 'New manually sorted query' expect_query_order(query, [work_package1.id, work_package3.id, work_package2.id]) @@ -343,11 +343,11 @@ def expect_query_order(query, expected) expect_query_order(query, [work_package3.id, work_package1.id, work_package2.id]) end - it "saves the changed order in a previously saved query" do - wp_table.save_as "Manual sorted query" + it 'saves the changed order in a previously saved query' do + wp_table.save_as 'Manual sorted query' sort_by.open_modal - sort_by.update_sorting_mode "manual" + sort_by.update_sorting_mode 'manual' sort_by.apply_changes wp_table.drag_and_drop_work_package from: 1, to: 3 @@ -355,34 +355,34 @@ def expect_query_order(query, expected) wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4 query = Query.last - expect(query.name).to eq "Manual sorted query" + expect(query.name).to eq 'Manual sorted query' expect_query_order(query, [work_package1.id, work_package3.id, work_package2.id]) pagination.expect_range(1, 4, 4) pagination.expect_no_per_page_options end - it "does not loose the current order when switching to manual sorting" do + it 'does not loose the current order when switching to manual sorting' do # Sort by creation date - sort_by.update_criteria "Created on" + sort_by.update_criteria 'Created on' wp_table.expect_work_package_order work_package4, work_package3, work_package2, work_package1 # Enable manual sorting sort_by.open_modal - sort_by.update_sorting_mode "manual" + sort_by.update_sorting_mode 'manual' sort_by.apply_changes # Expect same order wp_table.expect_work_package_order work_package4, work_package3, work_package2, work_package1 end - it "shows a warning when switching from manual to automatic sorting" do + it 'shows a warning when switching from manual to automatic sorting' do wp_table.drag_and_drop_work_package from: 1, to: 3 wp_table.expect_work_package_order work_package1, work_package3, work_package2, work_package4 # Try to sort by creation date - sort_by.sort_via_header "Subject" + sort_by.sort_via_header 'Subject' # Shows a warning dialog.expect_open @@ -390,20 +390,20 @@ def expect_query_order(query, expected) wp_table.expect_work_package_order work_package1, work_package2, work_package3, work_package4 end - context "when view is gantt chart" do + context 'when view is gantt chart' do let(:wp_timeline) { Pages::WorkPackagesTimeline.new(project) } let!(:query_tl) do query = build(:query_with_view_gantt, user:, project:) query.filters.clear query.timeline_visible = true - query.name = "Query with Timeline" + query.name = 'Query with Timeline' query.save! query end - it "reloads after drop" do + it 'reloads after drop' do wp_timeline.visit_query(query_tl) wp_timeline.expect_timeline! wp_timeline.expect_row_count(4) diff --git a/spec/features/work_packages/sorting/table_sorting_spec.rb b/spec/features/work_packages/sorting/table_sorting_spec.rb index 811c44c784cb..231ae2130966 100644 --- a/spec/features/work_packages/sorting/table_sorting_spec.rb +++ b/spec/features/work_packages/sorting/table_sorting_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Select work package row", :js do +RSpec.describe 'Select work package row', :js do let(:user) { create(:admin) } let(:project) { create(:project) } let(:work_packages_page) { WorkPackagesPage.new(project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } - describe "sorting by version" do + describe 'sorting by version' do let(:work_package_1) do create(:work_package, project:) end @@ -45,11 +45,11 @@ let(:version_1) do create(:version, project:, - name: "aaa_version") + name: 'aaa_version') end let(:version_2) do create(:version, project:, - name: "zzz_version") + name: 'zzz_version') end let(:columns) { Components::WorkPackages::Columns.new } let(:sort_by) { Components::WorkPackages::SortBy.new } @@ -63,23 +63,23 @@ work_packages_page.visit_index end - include_context "work package table helpers" + include_context 'work package table helpers' - context "sorting by version" do + context 'sorting by version' do before do work_package_1.update_attribute(:version_id, version_2.id) work_package_2.update_attribute(:version_id, version_1.id) end - it "sorts by version although version is not selected as a column" do + it 'sorts by version although version is not selected as a column' do sort_by.open_modal - sort_by.update_nth_criteria(0, "Version") + sort_by.update_nth_criteria(0, 'Version') expect_work_packages_to_be_in_order([work_package_1, work_package_2]) end end end - describe "sorting modal" do + describe 'sorting modal' do let(:sort_by) { Components::WorkPackages::SortBy.new } before do @@ -87,22 +87,22 @@ wp_table.visit! end - it "provides the default sortation and allows using the value at another level (Regression WP#26792)" do + it 'provides the default sortation and allows using the value at another level (Regression WP#26792)' do # Expect current criteria - sort_by.expect_criteria(["-", "asc"]) + sort_by.expect_criteria(['-', 'asc']) # Expect we can change the criteria and reuse that value sort_by.open_modal - sort_by.update_nth_criteria(0, "Type", descending: true) - sort_by.update_nth_criteria(0, "ID", descending: true) - sort_by.update_nth_criteria(1, "Type") + sort_by.update_nth_criteria(0, 'Type', descending: true) + sort_by.update_nth_criteria(0, 'ID', descending: true) + sort_by.update_nth_criteria(1, 'Type') sort_by.apply_changes - sort_by.expect_criteria(["ID", "desc"], ["Type", "asc"]) + sort_by.expect_criteria(['ID', 'desc'], ['Type', 'asc']) end end - describe "parent sorting" do + describe 'parent sorting' do let(:sort_by) { Components::WorkPackages::SortBy.new } let(:parent) do @@ -136,7 +136,7 @@ end before do - allow(Setting).to receive(:per_page_options).and_return "4" + allow(Setting).to receive(:per_page_options).and_return '4' parent child1 @@ -149,7 +149,7 @@ wp_table.visit! end - it "default sortation (id) does not order depth first (Reverted in #29122)" do + it 'default sortation (id) does not order depth first (Reverted in #29122)' do wp_table.expect_work_package_listed parent, child1, grand_child1, child2 wp_table.expect_work_package_order parent.id, child1.id, grand_child1.id, child2 end diff --git a/spec/features/work_packages/switching_to_project_from_work_package_spec.rb b/spec/features/work_packages/switching_to_project_from_work_package_spec.rb index 3d773a97fd2b..55d4f8be5775 100644 --- a/spec/features/work_packages/switching_to_project_from_work_package_spec.rb +++ b/spec/features/work_packages/switching_to_project_from_work_package_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Switching to project from work package", :js do +RSpec.describe 'Switching to project from work package', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -14,7 +14,7 @@ work_package end - it "allows to switch to the project the work package belongs to" do + it 'allows to switch to the project the work package belongs to' do wp_table.visit! wp_table.expect_work_package_listed work_package @@ -22,8 +22,8 @@ wp_table.open_full_screen_by_link work_package # Follow link to project - expect(page).to have_css(".attributes-group.-project-context") - link = find(".attributes-group.-project-context .project-context--switch-link") + expect(page).to have_css('.attributes-group.-project-context') + link = find('.attributes-group.-project-context .project-context--switch-link') expect(link[:href]).to include(project_path(project.id)) link.click diff --git a/spec/features/work_packages/table/baseline/baseline_invisible_project_spec.rb b/spec/features/work_packages/table/baseline/baseline_invisible_project_spec.rb index 8397afa62695..7dc636fa7c26 100644 --- a/spec/features/work_packages/table/baseline/baseline_invisible_project_spec.rb +++ b/spec/features/work_packages/table/baseline/baseline_invisible_project_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "baseline with a work package moved to an invisible project", :js, - with_settings: { date_format: "%Y-%m-%d" } do +RSpec.describe 'baseline with a work package moved to an invisible project', :js, + with_settings: { date_format: '%Y-%m-%d' } do shared_let(:type_bug) { create(:type_bug) } shared_let(:visible_project) { create(:project, types: [type_bug]) } shared_let(:private_project) { create(:project, types: [type_bug]) } shared_let(:user) do create(:user, - firstname: "Itsa", - lastname: "Me", + firstname: 'Itsa', + lastname: 'Me', member_with_permissions: { visible_project => %i[view_work_packages edit_work_packages work_package_assigned assign_versions] }) end @@ -49,16 +49,16 @@ type: type_bug, assigned_to: user, responsible: user, - subject: "WP in public project", - start_date: "2023-05-01", - due_date: "2023-05-02") + subject: 'WP in public project', + start_date: '2023-05-01', + due_date: '2023-05-02') end Timecop.travel(1.hour.ago) do WorkPackages::UpdateService .new(user: User.system, model: wp) .call( - subject: "Moved to private project", + subject: 'Moved to private project', project: private_project ) .on_failure { |result| raise result.message } @@ -68,7 +68,7 @@ shared_let(:query) do query = create(:query, - name: "Global query changes since yesterday", + name: 'Global query changes since yesterday', project: nil, user:) @@ -85,17 +85,17 @@ current_user { user } - describe "with EE active", with_ee: %i[baseline_comparison] do - it "shows the item with all values removed" do + describe 'with EE active', with_ee: %i[baseline_comparison] do + it 'shows the item with all values removed' do wp_table.visit_query(query) baseline.expect_active baseline.expect_removed wp_bug baseline.expect_changed_attributes wp_bug, - subject: ["WP in public project", ""], - startDate: ["2023-05-01", ""], - dueDate: ["2023-05-02", ""] + subject: ['WP in public project', ''], + startDate: ['2023-05-01', ''], + dueDate: ['2023-05-02', ''] end end end diff --git a/spec/features/work_packages/table/baseline/baseline_query_spec.rb b/spec/features/work_packages/table/baseline/baseline_query_spec.rb index f20307e4207d..9a984223e318 100644 --- a/spec/features/work_packages/table/baseline/baseline_query_spec.rb +++ b/spec/features/work_packages/table/baseline/baseline_query_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "baseline query saving", +RSpec.describe 'baseline query saving', :js, :with_cuprite, with_ee: %i[baseline_comparison], - with_settings: { date_format: "%Y-%m-%d" } do + with_settings: { date_format: '%Y-%m-%d' } do shared_let(:project) { create(:project) } shared_let(:work_package) { create(:work_package, project:) } @@ -43,7 +43,7 @@ shared_let(:berlin_user) do create(:user, - preferences: { time_zone: "Europe/Berlin" }, + preferences: { time_zone: 'Europe/Berlin' }, member_with_permissions: { project => %i[view_work_packages save_queries manage_public_queries] }) end @@ -56,7 +56,7 @@ shared_let(:tokyo_user) do create(:user, - preferences: { time_zone: "Asia/Tokyo" }, + preferences: { time_zone: 'Asia/Tokyo' }, member_with_permissions: { project => %i[view_work_packages save_queries manage_public_queries] }) end # always 9 as Japan does not observe daylight saving time @@ -66,7 +66,7 @@ # always "UTC+9" shared_let(:tokyo_utc_offset) { "UTC+#{tokyo_hours_offset}" } - it "shows a warning when an incompatible filter is used" do + it 'shows a warning when an incompatible filter is used' do login_as berlin_user wp_table.visit! @@ -74,30 +74,30 @@ baseline.expect_no_legends baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.expect_selected "-" + baseline_modal.expect_selected '-' - baseline_modal.select_filter "yesterday" - baseline_modal.set_time "09:00" + baseline_modal.select_filter 'yesterday' + baseline_modal.set_time '09:00' baseline_modal.expect_offset berlin_utc_offset baseline_modal.apply loading_indicator_saveguard filters.open - filters.add_filter_by("Watcher", "is (OR)", "me") + filters.add_filter_by('Watcher', 'is (OR)', 'me') loading_indicator_saveguard expect(page).to have_css( - ".op-toast.-warning", - text: "Baseline mode is on but some of your active filters are not included in the comparison." + '.op-toast.-warning', + text: 'Baseline mode is on but some of your active filters are not included in the comparison.' ) - page.within("#filter_watcher") do - expect(page).to have_test_selector("query-filter-baseline-incompatible") + page.within('#filter_watcher') do + expect(page).to have_test_selector('query-filter-baseline-incompatible') end end - it "can configure and save baseline queries" do + it 'can configure and save baseline queries' do login_as berlin_user wp_table.visit! @@ -105,10 +105,10 @@ baseline.expect_no_legends baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.expect_selected "-" + baseline_modal.expect_selected '-' - baseline_modal.select_filter "yesterday" - baseline_modal.set_time "09:00" + baseline_modal.select_filter 'yesterday' + baseline_modal.set_time '09:00' baseline_modal.expect_offset berlin_utc_offset baseline_modal.apply @@ -116,20 +116,20 @@ baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.expect_selected "yesterday" + baseline_modal.expect_selected 'yesterday' baseline_modal.toggle_drop_modal baseline_modal.expect_closed baseline.expect_legends baseline.expect_legend_text "Changes since yesterday (#{Date.yesterday.iso8601} 9:00 AM #{berlin_utc_offset})" - expect(page).to have_css(".op-baseline-legends--details-added", text: "Now meets filter criteria (1)") - expect(page).to have_css(".op-baseline-legends--details-removed", text: "No longer meets filter criteria (0)") - expect(page).to have_css(".op-baseline-legends--details-changed", text: "Maintained with changes (0)") + expect(page).to have_css(".op-baseline-legends--details-added", text: 'Now meets filter criteria (1)') + expect(page).to have_css(".op-baseline-legends--details-removed", text: 'No longer meets filter criteria (0)') + expect(page).to have_css(".op-baseline-legends--details-changed", text: 'Maintained with changes (0)') - wp_table.save_as "Baseline query" - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.save_as 'Baseline query' + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') - query = retry_block { Query.find_by! name: "Baseline query" } - expect(query.timestamps.map(&:to_s)).to eq ["oneDayAgo@09:00#{berlin_time_offset}", "PT0S"] + query = retry_block { Query.find_by! name: 'Baseline query' } + expect(query.timestamps.map(&:to_s)).to eq ["oneDayAgo@09:00#{berlin_time_offset}", 'PT0S'] query.update! public: true login_as tokyo_user @@ -142,41 +142,41 @@ baseline_modal.expect_closed baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.expect_selected "yesterday" - baseline_modal.expect_selected_time "09:00" + baseline_modal.expect_selected 'yesterday' + baseline_modal.expect_selected_time '09:00' baseline_modal.expect_offset berlin_utc_offset - baseline_modal.select_filter "-" + baseline_modal.select_filter '-' - baseline_modal.select_filter "yesterday" + baseline_modal.select_filter 'yesterday' baseline_modal.expect_offset tokyo_utc_offset - baseline_modal.select_filter "-" + baseline_modal.select_filter '-' baseline_modal.apply baseline.expect_no_legends loading_indicator_saveguard wp_table.save - wp_table.expect_and_dismiss_toaster(message: "Successful update.") + wp_table.expect_and_dismiss_toaster(message: 'Successful update.') query.reload - expect(query.timestamps).to eq ["PT0S"] + expect(query.timestamps).to eq ['PT0S'] baseline_modal.expect_closed baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.select_filter "a specific date" + baseline_modal.select_filter 'a specific date' baseline_modal.expect_offset tokyo_utc_offset - baseline_modal.set_time "06:00" - baseline_modal.set_date "2023-05-20" + baseline_modal.set_time '06:00' + baseline_modal.set_date '2023-05-20' baseline_modal.apply loading_indicator_saveguard wp_table.save - wp_table.expect_and_dismiss_toaster(message: "Successful update.") + wp_table.expect_and_dismiss_toaster(message: 'Successful update.') query.reload - expect(query.timestamps.map(&:to_s)).to eq ["2023-05-20T06:00+09:00", "PT0S"] + expect(query.timestamps.map(&:to_s)).to eq ['2023-05-20T06:00+09:00', 'PT0S'] login_as berlin_user wp_table.visit_query query @@ -186,11 +186,11 @@ baseline_modal.expect_closed baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.expect_selected "a specific date" - baseline_modal.expect_selected_time "06:00" - baseline_modal.expect_offset "UTC+9" + baseline_modal.expect_selected 'a specific date' + baseline_modal.expect_selected_time '06:00' + baseline_modal.expect_offset 'UTC+9' baseline_modal.expect_time_help_text "In your local time: 2023-05-19 11:00 PM" - baseline_modal.select_filter "between two specific dates" + baseline_modal.select_filter 'between two specific dates' # TODO: on the 2023-05-19, utc offset is +2 hours. But when current date is # outside of DST (from November to February for instance), then on time @@ -198,17 +198,17 @@ # would be better to change the offset depending on the selected date: here # UTC+2 offset should be used so that 8:00 is really 8:00 in Berlin on this # date, and not 9:00 (because 8:00 UTC+1 is 9:00 UTC+2). - baseline_modal.set_between_dates from: "2023-05-19", - to: "2023-05-25", - from_time: "08:00", - to_time: "20:00" + baseline_modal.set_between_dates from: '2023-05-19', + to: '2023-05-25', + from_time: '08:00', + to_time: '20:00' baseline_modal.apply loading_indicator_saveguard wp_table.save - wp_table.expect_and_dismiss_toaster(message: "Successful update.") + wp_table.expect_and_dismiss_toaster(message: 'Successful update.') query.reload expect(query.timestamps.map(&:to_s)).to eq ["2023-05-19T08:00#{berlin_time_offset}", "2023-05-25T20:00#{berlin_time_offset}"] @@ -224,11 +224,11 @@ baseline_modal.expect_closed baseline_modal.toggle_drop_modal baseline_modal.expect_open - baseline_modal.expect_selected "between two specific dates" - baseline_modal.expect_between_dates from: "2023-05-19", - to: "2023-05-25", - from_time: "08:00", - to_time: "20:00" + baseline_modal.expect_selected 'between two specific dates' + baseline_modal.expect_between_dates from: '2023-05-19', + to: '2023-05-25', + from_time: '08:00', + to_time: '20:00' baseline_modal.expect_offset berlin_utc_offset, count: 2 end diff --git a/spec/features/work_packages/table/baseline/baseline_rendering_spec.rb b/spec/features/work_packages/table/baseline/baseline_rendering_spec.rb index fb851d6bd95d..402fe968728c 100644 --- a/spec/features/work_packages/table/baseline/baseline_rendering_spec.rb +++ b/spec/features/work_packages/table/baseline/baseline_rendering_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "baseline rendering", +RSpec.describe 'baseline rendering', :js, :with_cuprite, - with_settings: { date_format: "%Y-%m-%d" } do + with_settings: { date_format: '%Y-%m-%d' } do shared_let(:list_wp_custom_field) { create(:list_wp_custom_field) } shared_let(:multi_list_wp_custom_field) { create(:list_wp_custom_field, multi_value: true) } shared_let(:version_wp_custom_field) { create(:version_wp_custom_field) } @@ -67,35 +67,35 @@ end shared_let(:user) do create(:admin, - firstname: "Itsa", - lastname: "Me", + firstname: 'Itsa', + lastname: 'Me', member_with_permissions: { project => %i[view_work_packages edit_work_packages work_package_assigned assign_versions] }) end shared_let(:assignee) do create(:user, - firstname: "Assigned", - lastname: "User", + firstname: 'Assigned', + lastname: 'User', member_with_permissions: { project => %i[view_work_packages edit_work_packages work_package_assigned] }) end shared_let(:default_priority) do - create(:issue_priority, name: "Default", is_default: true) + create(:issue_priority, name: 'Default', is_default: true) end shared_let(:high_priority) do - create(:issue_priority, name: "High priority") + create(:issue_priority, name: 'High priority') end - shared_let(:version_a) { create(:version, project:, name: "Version A") } - shared_let(:version_b) { create(:version, project:, name: "Version B") } + shared_let(:version_a) { create(:version, project:, name: 'Version A') } + shared_let(:version_b) { create(:version, project:, name: 'Version B') } shared_let(:wp_bug) do create(:work_package, project:, type: type_bug, - subject: "A bug", + subject: 'A bug', created_at: 5.days.ago, updated_at: 5.days.ago) end @@ -104,7 +104,7 @@ create(:work_package, project:, type: type_task, - subject: "A task", + subject: 'A task', created_at: 5.days.ago, updated_at: 5.days.ago) @@ -119,16 +119,16 @@ responsible: assignee, priority: default_priority, version: version_a, - subject: "Old subject", - start_date: "2023-05-01", - due_date: "2023-05-02") + subject: 'Old subject', + start_date: '2023-05-01', + due_date: '2023-05-02') end Timecop.travel(1.day.ago) do WorkPackages::UpdateService .new(user:, model: wp) .call( - subject: "New subject", + subject: 'New subject', start_date: Time.zone.today - 1.day, due_date: Time.zone.today, assigned_to: user, @@ -160,7 +160,7 @@ shared_let(:wp_task_was_bug) do wp = Timecop.travel(5.days.ago) do - create(:work_package, project:, type: type_bug, subject: "Bug changed to Task") + create(:work_package, project:, type: type_bug, subject: 'Bug changed to Task') end Timecop.travel(1.day.ago) do @@ -174,7 +174,7 @@ shared_let(:wp_bug_was_task) do wp = Timecop.travel(5.days.ago) do - create(:work_package, project:, type: type_task, subject: "Task changed to Bug") + create(:work_package, project:, type: type_task, subject: 'Task changed to Bug') end Timecop.travel(1.day.ago) do @@ -191,7 +191,7 @@ create(:work_package, project:, type: type_milestone, - subject: "Milestone 1", + subject: 'Milestone 1', start_date: Time.zone.today, due_date: Time.zone.today) end @@ -206,7 +206,7 @@ shared_let(:initial_custom_values) do { int_wp_custom_field.id => 1, - string_wp_custom_field.id => "this is a string", + string_wp_custom_field.id => 'this is a string', bool_wp_custom_field.id => true, float_wp_custom_field.id => nil, date_wp_custom_field.id => Date.yesterday, @@ -220,7 +220,7 @@ shared_let(:changed_custom_values) do { "custom_field_#{int_wp_custom_field.id}": nil, - "custom_field_#{string_wp_custom_field.id}": "this is a changed string", + "custom_field_#{string_wp_custom_field.id}": 'this is a changed string', "custom_field_#{bool_wp_custom_field.id}": false, "custom_field_#{float_wp_custom_field.id}": 3.7, "custom_field_#{date_wp_custom_field.id}": Time.zone.today, @@ -241,7 +241,7 @@ :skip_validations, project:, type: type_task, - subject: "A task with CFs", + subject: 'A task with CFs', custom_values: initial_custom_values) end end @@ -255,12 +255,12 @@ shared_let(:query) do query = create(:query, - name: "Timestamps Query", + name: 'Timestamps Query', project:, user:) query.timestamps = ["P-2d", "PT0S"] - query.add_filter("type_id", "=", [type_task.id, type_milestone.id]) + query.add_filter('type_id', '=', [type_task.id, type_milestone.id]) query.column_names = %w[id subject status type start_date due_date version priority assigned_to responsible] + CustomField.all.pluck(:id).map { |id| "cf_#{id}" } @@ -276,8 +276,8 @@ current_user { user } - describe "with EE", with_ee: %i[baseline_comparison] do - it "does show changes" do + describe 'with EE', with_ee: %i[baseline_comparison] do + it 'does show changes' do wp_table.visit_query(query) wp_table.expect_work_package_listed wp_task, wp_task_changed, wp_task_was_bug, wp_bug_was_task, wp_task_assigned, wp_milestone_date_changed @@ -298,16 +298,16 @@ type: %w[TASK BUG] baseline.expect_changed_attributes wp_task_changed, - subject: ["Old subject", "New subject"], - startDate: ["2023-05-01", (today - 2.days).iso8601], - dueDate: ["2023-05-02", (today - 1.day).iso8601], - version: ["Version A", "Version B"], - priority: ["Default", "High priority"], - assignee: ["Assigned User", "Itsa Me"], - responsible: ["Assigned User", "Itsa Me"] + subject: ['Old subject', 'New subject'], + startDate: ['2023-05-01', (today - 2.days).iso8601], + dueDate: ['2023-05-02', (today - 1.day).iso8601], + version: ['Version A', 'Version B'], + priority: ['Default', 'High priority'], + assignee: ['Assigned User', 'Itsa Me'], + responsible: ['Assigned User', 'Itsa Me'] baseline.expect_changed_attributes wp_task_assigned, - assignee: ["-", "Itsa Me"] + assignee: ['-', 'Itsa Me'] baseline.expect_changed_attributes wp_milestone_date_changed, startDate: [ @@ -326,20 +326,20 @@ baseline.expect_changed_attributes wp_task_cf, "customField#{int_wp_custom_field.id}": [ - "1", - "-" + '1', + '-' ], "customField#{string_wp_custom_field.id}": [ - "this is a string", - "this is a changed string" + 'this is a string', + 'this is a changed string' ], "customField#{bool_wp_custom_field.id}": [ - "yes", - "no" + 'yes', + 'no' ], "customField#{float_wp_custom_field.id}": [ - "-", - "3.7" + '-', + '3.7' ], "customField#{date_wp_custom_field.id}": [ Date.yesterday.iso8601, @@ -354,12 +354,12 @@ "A, B" ], "customField#{user_wp_custom_field.id}": [ - "Assigned User", - "-" + 'Assigned User', + '-' ], "customField#{version_wp_custom_field.id}": [ - "Version A", - "Version B" + 'Version A', + 'Version B' ] # Shows changes even if columns not showing @@ -367,68 +367,68 @@ query.save! wp_table.visit_query(query) - baseline.expect_icon wp_milestone_date_changed, "changed" + baseline.expect_icon wp_milestone_date_changed, 'changed' end - shared_examples_for "selecting a builtin view" do - let(:builtin_view_name) { "All open" } + shared_examples_for 'selecting a builtin view' do + let(:builtin_view_name) { 'All open' } before do - within "#main-menu" do + within '#main-menu' do click_link builtin_view_name end end - it "does not show changes or render baseline details" do + it 'does not show changes or render baseline details' do wp_table.expect_title builtin_view_name baseline.expect_inactive baseline.expect_no_legends baseline_modal.toggle_drop_modal - baseline_modal.expect_selected "-" + baseline_modal.expect_selected '-' end end - context "when a baseline filter is set" do + context 'when a baseline filter is set' do before do wp_table.visit! wait_for_reload # Ensure page is fully loaded baseline_modal.toggle_drop_modal - baseline_modal.select_filter "yesterday" + baseline_modal.select_filter 'yesterday' baseline_modal.apply wait_for_reload # Ensure page is fully loaded end - context "and the query is saved" do + context 'and the query is saved' do before do - wp_table.save_as("My Baseline Query", by_title: true) + wp_table.save_as('My Baseline Query', by_title: true) end - it_behaves_like "selecting a builtin view" + it_behaves_like 'selecting a builtin view' end - context "and the query is not saved" do - it_behaves_like "selecting a builtin view" + context 'and the query is not saved' do + it_behaves_like 'selecting a builtin view' end end end - describe "without EE", with_ee: false do - it "disabled options" do + describe 'without EE', with_ee: false do + it 'disabled options' do wp_table.visit_query(query) baseline_modal.expect_closed baseline_modal.toggle_drop_modal baseline_modal.expect_open expect(page).to have_css(".op-baseline--enterprise-title") # only yesterday is selectable - page.select("a specific date", from: "op-baseline-filter") - expect(page).to have_no_select("op-baseline-filter", selected: "a specific date") + page.select('a specific date', from: 'op-baseline-filter') + expect(page).to have_no_select('op-baseline-filter', selected: 'a specific date') - page.select("yesterday", from: "op-baseline-filter") - expect(page).to have_select("op-baseline-filter", selected: "yesterday") + page.select('yesterday', from: 'op-baseline-filter') + expect(page).to have_select('op-baseline-filter', selected: 'yesterday') end end end diff --git a/spec/features/work_packages/table/configuration_modal/column_spec.rb b/spec/features/work_packages/table/configuration_modal/column_spec.rb index 51d272727f7d..50538dcab351 100644 --- a/spec/features/work_packages/table/configuration_modal/column_spec.rb +++ b/spec/features/work_packages/table/configuration_modal/column_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table configuration modal columns spec", :js do +RSpec.describe 'Work Package table configuration modal columns spec', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -22,31 +22,31 @@ login_as(user) wp_table.visit_query query wp_table.expect_work_package_listed work_package - expect(page).to have_css(".wp-table--table-header", text: "ID") - expect(page).to have_css(".wp-table--table-header", text: "SUBJECT") + expect(page).to have_css('.wp-table--table-header', text: 'ID') + expect(page).to have_css('.wp-table--table-header', text: 'SUBJECT') end - shared_examples "add and remove columns" do + shared_examples 'add and remove columns' do it do columns.open_modal - columns.expect_checked "ID" - columns.expect_checked "Subject" + columns.expect_checked 'ID' + columns.expect_checked 'Subject' - columns.remove "Subject", save_changes: false - columns.add "Project", save_changes: true - columns.expect_column_available "Subject" - columns.expect_column_not_available "Project" + columns.remove 'Subject', save_changes: false + columns.add 'Project', save_changes: true + columns.expect_column_available 'Subject' + columns.expect_column_not_available 'Project' - expect(page).to have_css(".wp-table--table-header", text: "ID") - expect(page).to have_css(".wp-table--table-header", text: "PROJECT") - expect(page).to have_no_css(".wp-table--table-header", text: "SUBJECT") + expect(page).to have_css('.wp-table--table-header', text: 'ID') + expect(page).to have_css('.wp-table--table-header', text: 'PROJECT') + expect(page).to have_no_css('.wp-table--table-header', text: 'SUBJECT') end end - context "When seeing the table" do - it_behaves_like "add and remove columns" + context 'When seeing the table' do + it_behaves_like 'add and remove columns' - context "with three columns", driver: :firefox_de do + context 'with three columns', driver: :firefox_de do let!(:query) do query = build(:query, user:, project:) query.column_names = %w[id project subject] @@ -55,15 +55,15 @@ query end - it "can reorder columns" do + it 'can reorder columns' do columns.open_modal - columns.expect_checked "ID" - columns.expect_checked "Project" - columns.expect_checked "Subject" + columns.expect_checked 'ID' + columns.expect_checked 'Project' + columns.expect_checked 'Subject' # Drag subject left of project - subject_column = columns.column_item("Subject").find("span") - project_column = columns.column_item("Project").find("span") + subject_column = columns.column_item('Subject').find('span') + project_column = columns.column_item('Project').find('span') page .driver @@ -76,11 +76,11 @@ sleep 1 columns.apply - expect(page).to have_css(".wp-table--table-header", text: "ID") - expect(page).to have_css(".wp-table--table-header", text: "PROJECT") - expect(page).to have_css(".wp-table--table-header", text: "SUBJECT") + expect(page).to have_css('.wp-table--table-header', text: 'ID') + expect(page).to have_css('.wp-table--table-header', text: 'PROJECT') + expect(page).to have_css('.wp-table--table-header', text: 'SUBJECT') - names = all(".wp-table--table-header").map(&:text) + names = all('.wp-table--table-header').map(&:text) # Depending on what browser is used, subject column may be first or second # it doesn't matter for the outcome of this test expect(names).to eq(%w[SUBJECT ID PROJECT]).or(eq(%w[ID SUBJECT PROJECT])) diff --git a/spec/features/work_packages/table/configuration_modal/filter_spec.rb b/spec/features/work_packages/table/configuration_modal/filter_spec.rb index 7e58c08409dc..27694868bd28 100644 --- a/spec/features/work_packages/table/configuration_modal/filter_spec.rb +++ b/spec/features/work_packages/table/configuration_modal/filter_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table configuration modal filters spec", :js do +RSpec.describe 'Work Package table configuration modal filters spec', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -12,7 +12,7 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "done_ratio"] + query.column_names = ['subject', 'done_ratio'] query.save! query @@ -22,7 +22,7 @@ login_as(user) end - context "by version in project" do + context 'by version in project' do let(:version) { create(:version, project:) } let(:work_package_with_version) { create(:work_package, project:, version:) } let(:work_package_without_version) { create(:work_package, project:) } @@ -34,22 +34,22 @@ wp_table.visit! end - it "allows filtering, saving, retrieving and altering the saved filter" do + it 'allows filtering, saving, retrieving and altering the saved filter' do wp_table.expect_work_package_listed work_package_with_version, work_package_without_version filters.open filters.expect_filter_count 2 - filters.add_filter_by("Version", "is (OR)", version.name) + filters.add_filter_by('Version', 'is (OR)', version.name) filters.save wp_table.expect_work_package_listed work_package_with_version wp_table.ensure_work_package_not_listed! work_package_without_version - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') filters.open filters.expect_filter_count 3 - filters.remove_filter "version" + filters.remove_filter 'version' filters.save loading_indicator_saveguard diff --git a/spec/features/work_packages/table/configuration_modal/table_configuration_modal_spec.rb b/spec/features/work_packages/table/configuration_modal/table_configuration_modal_spec.rb index 2e48119623c0..2cf00353f1a6 100644 --- a/spec/features/work_packages/table/configuration_modal/table_configuration_modal_spec.rb +++ b/spec/features/work_packages/table/configuration_modal/table_configuration_modal_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table configuration modal", :js do +RSpec.describe 'Work Package table configuration modal', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -11,7 +11,7 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "done_ratio"] + query.column_names = ['subject', 'done_ratio'] query.save! query @@ -24,14 +24,14 @@ wp_table.expect_work_package_listed wp_1 end - it "focuses on the columns tab when opened through header" do + it 'focuses on the columns tab when opened through header' do # Open header dropdown - find(".work-package-table--container th #subject").click + find('.work-package-table--container th #subject').click # Open insert columns entry - find("#column-context-menu .menu-item", text: "Insert columns").click + find('#column-context-menu .menu-item', text: 'Insert columns').click # Expect active tab is columns - expect(page).to have_css(".op-tab-row--link_selected", text: "COLUMNS") + expect(page).to have_css('.op-tab-row--link_selected', text: 'COLUMNS') end end diff --git a/spec/features/work_packages/table/context_menu/context_menu_shared_examples.rb b/spec/features/work_packages/table/context_menu/context_menu_shared_examples.rb index f09dfbb757db..3503e0025235 100644 --- a/spec/features/work_packages/table/context_menu/context_menu_shared_examples.rb +++ b/spec/features/work_packages/table/context_menu/context_menu_shared_examples.rb @@ -1,92 +1,92 @@ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "provides a single WP context menu" do - let(:open_context_menu) { raise "needs to be defined" } +RSpec.shared_examples_for 'provides a single WP context menu' do + let(:open_context_menu) { raise 'needs to be defined' } let(:destroy_modal) { Components::WorkPackages::DestroyModal.new } let(:time_logging_modal) { Components::TimeLoggingModal.new } let(:wp_timeline) { Pages::WorkPackagesTimeline.new(work_package.project) } - it "provides a context menu" do + it 'provides a context menu' do # Open detail pane open_context_menu.call - menu.choose("Open details view") + menu.choose('Open details view') split_page = Pages::SplitWorkPackage.new(work_package, work_package.project) split_page.expect_attributes Subject: work_package.subject # Open full view open_context_menu.call - menu.choose("Open fullscreen view") - expect(page).to have_css(".work-packages--show-view .inline-edit--container.subject", + menu.choose('Open fullscreen view') + expect(page).to have_css('.work-packages--show-view .inline-edit--container.subject', text: work_package.subject) # Open log time open_context_menu.call - menu.choose("Log time") + menu.choose('Log time') time_logging_modal.is_visible true time_logging_modal.work_package_is_missing false - time_logging_modal.perform_action "Cancel" + time_logging_modal.perform_action 'Cancel' # Open Move open_context_menu.call - menu.choose("Change project") - expect(page).to have_css("h2", text: I18n.t(:button_move)) - expect(page).to have_css("a.work_package", text: "##{work_package.id}") + menu.choose('Change project') + expect(page).to have_css('h2', text: I18n.t(:button_move)) + expect(page).to have_css('a.work_package', text: "##{work_package.id}") # Open Copy open_context_menu.call - menu.choose("Copy") + menu.choose('Copy') # Split view open in copy state expect(page) - .to have_css(".wp-new-top-row", + .to have_css('.wp-new-top-row', text: "#{work_package.status.name.capitalize}\n#{work_package.type.name.upcase}") - expect(page).to have_field("wp-new-inline-edit--field-subject", with: work_package.subject) + expect(page).to have_field('wp-new-inline-edit--field-subject', with: work_package.subject) # Open Delete open_context_menu.call - menu.choose("Delete") + menu.choose('Delete') destroy_modal.expect_listed(work_package) destroy_modal.cancel_deletion # Open create new child open_context_menu.call - menu.choose("Create new child") - expect(page).to have_css(".inline-edit--container.subject input") + menu.choose('Create new child') + expect(page).to have_css('.inline-edit--container.subject input') expect(current_url).to match(/.*\/create_new\?.*(&)*parent_id=#{work_package.id}/) - find_by_id("work-packages--edit-actions-cancel").click - expect(page).to have_no_css(".inline-edit--container.subject input") + find_by_id('work-packages--edit-actions-cancel').click + expect(page).to have_no_css('.inline-edit--container.subject input') # Timeline actions only shown when open wp_timeline.expect_timeline!(open: false) open_context_menu.call - menu.expect_no_options "Add predecessor", "Add follower, Show relations" + menu.expect_no_options 'Add predecessor', 'Add follower, Show relations' # Copy to other project open_context_menu.call - menu.choose("Copy to other project") - expect(page).to have_css("h2", text: I18n.t(:button_copy)) - expect(page).to have_css("a.work_package", text: "##{work_package.id}") + menu.choose('Copy to other project') + expect(page).to have_css('h2', text: I18n.t(:button_copy)) + expect(page).to have_css('a.work_package', text: "##{work_package.id}") end - describe "creating work packages" do + describe 'creating work packages' do let!(:priority) { create(:issue_priority, is_default: true) } let!(:status) { create(:default_status) } - it "can create a new child from the context menu (Regression #33329)" do + it 'can create a new child from the context menu (Regression #33329)' do open_context_menu.call - menu.choose("Create new child") - expect(page).to have_css(".inline-edit--container.subject input") + menu.choose('Create new child') + expect(page).to have_css('.inline-edit--container.subject input') expect(current_url).to match(/.*\/create_new\?.*(&)*parent_id=#{work_package.id}/) split_view = Pages::SplitWorkPackageCreate.new project: work_package.project subject = split_view.edit_field(:subject) - subject.set_value "Child task" + subject.set_value 'Child task' # Wait a bit for the split view to be fully initialized sleep 1 subject.submit_by_enter - split_view.expect_and_dismiss_toaster message: "Successful creation." + split_view.expect_and_dismiss_toaster message: 'Successful creation.' expect(page).to have_css('[data-test-selector="op-wp-breadcrumb"]', text: "Parent:\n#{work_package.subject}") wp = WorkPackage.last expect(wp.parent).to eq work_package diff --git a/spec/features/work_packages/table/context_menu/context_menu_spec.rb b/spec/features/work_packages/table/context_menu/context_menu_spec.rb index e919047e0981..39845bd9e298 100644 --- a/spec/features/work_packages/table/context_menu/context_menu_spec.rb +++ b/spec/features/work_packages/table/context_menu/context_menu_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" -require_relative "context_menu_shared_examples" +require 'spec_helper' +require_relative 'context_menu_shared_examples' -RSpec.describe "Work package table context menu", +RSpec.describe 'Work package table context menu', :js, :with_cuprite do shared_let(:user) { create(:admin) } @@ -16,7 +16,7 @@ query = build(:query_with_view_gantt, user:, project:) query.filters.clear query.timeline_visible = true - query.name = "Query with Timeline" + query.name = 'Query with Timeline' query.save! @@ -28,8 +28,8 @@ work_package end - context "when in the table" do - it_behaves_like "provides a single WP context menu" do + context 'when in the table' do + it_behaves_like 'provides a single WP context menu' do let(:open_context_menu) do -> { # Go to table @@ -43,10 +43,10 @@ } end - context "for multiple selected WPs" do + context 'for multiple selected WPs' do let!(:work_package2) { create(:work_package, project: work_package.project) } - it "provides a context menu with a subset of the available menu items" do + it 'provides a context menu with a subset of the available menu items' do # Go to table wp_table.visit! @@ -55,17 +55,17 @@ wp_table.expect_work_package_listed(work_package2) # Select all WPs - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] menu.open_for(work_package) - menu.expect_options "Open details view", "Open fullscreen view", - "Bulk edit", "Bulk copy", "Bulk change of project", "Bulk delete" + menu.expect_options 'Open details view', 'Open fullscreen view', + 'Bulk edit', 'Bulk copy', 'Bulk change of project', 'Bulk delete' end end end - context "when in Gantt" do - it "provides a context menu with timeline options" do + context 'when in Gantt' do + it 'provides a context menu with timeline options' do wp_timeline.visit_query(query_tl) loading_indicator_saveguard wp_timeline.expect_work_package_listed(work_package) @@ -74,11 +74,11 @@ # Open context menu menu.expect_closed menu.open_for(work_package) - menu.expect_options "Open details view", "Open fullscreen view", "Add predecessor", "Add follower", "Show relations" - menu.expect_no_options "Log time" + menu.expect_options 'Open details view', 'Open fullscreen view', 'Add predecessor', 'Add follower', 'Show relations' + menu.expect_no_options 'Log time' # Show relations tab when selecting show-relations from menu - menu.choose("Show relations") + menu.choose('Show relations') expect(page).to have_current_path /details\/#{work_package.id}\/relations/ end end diff --git a/spec/features/work_packages/table/delete_work_packages_spec.rb b/spec/features/work_packages/table/delete_work_packages_spec.rb index 42ce18edbd1e..4eef1626ce62 100644 --- a/spec/features/work_packages/table/delete_work_packages_spec.rb +++ b/spec/features/work_packages/table/delete_work_packages_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Delete work package", :js do +RSpec.describe 'Delete work package', :js do let(:user) { create(:admin) } let(:context_menu) { Components::WorkPackages::ContextMenu.new } let(:destroy_modal) { Components::WorkPackages::DestroyModal.new } @@ -37,8 +37,8 @@ login_as(user) end - shared_examples "close split view" do - describe "when deleting a work package that is opened in the split view" do + shared_examples 'close split view' do + describe 'when deleting a work package that is opened in the split view' do before do work_package @@ -46,7 +46,7 @@ split_view.ensure_page_loaded context_menu.open_for(work_package) - context_menu.choose("Delete") + context_menu.choose('Delete') destroy_modal.expect_listed(work_package) destroy_modal.confirm_deletion @@ -54,35 +54,35 @@ loading_indicator_saveguard end - it "closes the split view" do + it 'closes the split view' do split_view.expect_closed wp_table.expect_current_path end end end - describe "deleting multiple work packages in the table" do + describe 'deleting multiple work packages in the table' do let!(:wp1) { create(:work_package) } let!(:wp2) { create(:work_package) } let!(:wp_child) { create(:work_package, parent: wp1) } let(:wp_table) { Pages::WorkPackagesTable.new } - it "shows deletion for all selected work packages" do + it 'shows deletion for all selected work packages' do wp_table.visit! wp_table.expect_work_package_listed wp1, wp2, wp_child - find("body").send_keys [:control, "a"] + find('body').send_keys [:control, 'a'] context_menu.open_for(wp1) - context_menu.choose("Bulk delete") + context_menu.choose('Bulk delete') destroy_modal.expect_listed(wp1, wp2, wp_child) destroy_modal.cancel_deletion wp_table.expect_work_package_listed wp1, wp2, wp_child context_menu.open_for(wp1) - context_menu.choose("Bulk delete") + context_menu.choose('Bulk delete') destroy_modal.confirm_children_deletion destroy_modal.confirm_deletion @@ -91,20 +91,20 @@ end end - describe "when deleting it outside a project context" do + describe 'when deleting it outside a project context' do let(:work_package) { create(:work_package) } let(:split_view) { Pages::SplitWorkPackage.new(work_package) } let(:wp_table) { Pages::WorkPackagesTable.new } - it_behaves_like "close split view" + it_behaves_like 'close split view' end - describe "when deleting it within a project context" do + describe 'when deleting it within a project context' do let(:project) { create(:project) } let(:work_package) { create(:work_package, project:) } let(:split_view) { Pages::SplitWorkPackage.new(work_package, project.identifier) } let(:wp_table) { Pages::WorkPackagesTable.new(project.identifier) } - it_behaves_like "close split view" + it_behaves_like 'close split view' end end diff --git a/spec/features/work_packages/table/duration_field_spec.rb b/spec/features/work_packages/table/duration_field_spec.rb index 38fc4268b96a..81dbb374c80a 100644 --- a/spec/features/work_packages/table/duration_field_spec.rb +++ b/spec/features/work_packages/table/duration_field_spec.rb @@ -1,11 +1,11 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Duration field in the work package table", :js do +RSpec.describe 'Duration field in the work package table', :js do shared_let(:current_user) { create(:admin) } shared_let(:work_package) do next_monday = Time.zone.today.beginning_of_week.next_occurring(:monday) create(:work_package, - subject: "moved", + subject: 'moved', author: current_user, start_date: next_monday, due_date: next_monday.next_occurring(:thursday)) @@ -32,12 +32,12 @@ wp_table.expect_work_package_listed work_package end - it "shows the duration as days and opens the datepicker on click" do - duration.expect_state_text "4 days" + it 'shows the duration as days and opens the datepicker on click' do + duration.expect_state_text '4 days' duration.activate! date_field.expect_duration_highlighted expect(page).to have_focus_on("#{test_selector('op-datepicker-modal--duration-field')} input[name='duration']") - expect(page).to have_field("duration", with: "4", wait: 10) + expect(page).to have_field('duration', with: '4', wait: 10) end end diff --git a/spec/features/work_packages/table/edit_work_packages_spec.rb b/spec/features/work_packages/table/edit_work_packages_spec.rb index 6b49032e6fb3..72c409906413 100644 --- a/spec/features/work_packages/table/edit_work_packages_spec.rb +++ b/spec/features/work_packages/table/edit_work_packages_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Inline editing work packages", :js do +RSpec.describe 'Inline editing work packages', :js do let(:manager_role) do create(:project_role, permissions: %i[view_work_packages @@ -8,8 +8,8 @@ end let(:manager) do create(:user, - firstname: "Manager", - lastname: "Guy", + firstname: 'Manager', + lastname: 'Guy', member_with_roles: { project => manager_role }) end let(:type) { create(:type) } @@ -22,7 +22,7 @@ project:, type:, status: status1, - subject: "Foobar") + subject: 'Foobar') end let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -41,7 +41,7 @@ login_as(manager) end - context "simple work package" do + context 'simple work package' do before do work_package workflow @@ -50,35 +50,35 @@ wp_table.expect_work_package_listed(work_package) end - it "allows updating and seeing the results" do + it 'allows updating and seeing the results' do subject_field = wp_table.edit_field(work_package, :subject) - subject_field.expect_text("Foobar") + subject_field.expect_text('Foobar') subject_field.activate! - subject_field.set_value("New subject!") + subject_field.set_value('New subject!') expect(WorkPackages::UpdateService).to receive(:new).and_call_original subject_field.save! - subject_field.expect_text("New subject!") + subject_field.expect_text('New subject!') wp_table.expect_toast( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) work_package.reload - expect(work_package.subject).to eq("New subject!") + expect(work_package.subject).to eq('New subject!') end - it "allows to subsequently edit multiple fields" do + it 'allows to subsequently edit multiple fields' do subject_field = wp_table.edit_field(work_package, :subject) status_field = wp_table.edit_field(work_package, :status) subject_field.activate! - subject_field.set_value("Other subject!") + subject_field.set_value('Other subject!') subject_field.save! - wp_table.expect_and_dismiss_toaster(message: "Successful update") + wp_table.expect_and_dismiss_toaster(message: 'Successful update') status_field.activate! status_field.set_value(status2.name) @@ -86,36 +86,36 @@ subject_field.expect_inactive! status_field.expect_inactive! - subject_field.expect_text("Other subject!") + subject_field.expect_text('Other subject!') status_field.expect_text(status2.name) - wp_table.expect_and_dismiss_toaster(message: "Successful update") + wp_table.expect_and_dismiss_toaster(message: 'Successful update') work_package.reload - expect(work_package.subject).to eq("Other subject!") + expect(work_package.subject).to eq('Other subject!') expect(work_package.status.id).to eq(status2.id) end - it "provides error handling" do + it 'provides error handling' do subject_field = wp_table.edit_field(work_package, :subject) - subject_field.expect_text("Foobar") + subject_field.expect_text('Foobar') subject_field.activate! - subject_field.set_value("") + subject_field.set_value('') subject_field.expect_invalid subject_field.save! - expect(work_package.reload.subject).to eq "Foobar" + expect(work_package.reload.subject).to eq 'Foobar' end end - context "custom field" do + context 'custom field' do let!(:custom_fields) do fields = [ create( :work_package_custom_field, - field_format: "list", + field_format: 'list', possible_values: %w(foo bar xyz), is_required: false, is_for_all: false, @@ -124,7 +124,7 @@ ), create( :work_package_custom_field, - field_format: "string", + field_format: 'string', is_required: false, is_for_all: false, types: [type], @@ -138,7 +138,7 @@ let(:project) { create(:project, types: [type]) } let!(:work_package) do create(:work_package, - subject: "Foobar", + subject: 'Foobar', status: status1, type:, project:) @@ -155,12 +155,12 @@ wp_table.expect_work_package_listed(work_package) end - it "opens required custom fields when not set" do + it 'opens required custom fields when not set' do subject_field = wp_table.edit_field(work_package, :subject) - subject_field.expect_text("Foobar") + subject_field.expect_text('Foobar') subject_field.activate! - subject_field.set_value("New subject!") + subject_field.set_value('New subject!') subject_field.save! # Should raise two errors @@ -171,28 +171,28 @@ message: "#{cf_list_name} can't be blank.\n#{cf_text_name} can't be blank." ) - expect(page).to have_css("th a", text: cf_list_name.upcase) - expect(page).to have_css("th a", text: cf_text_name.upcase) - expect(wp_table.row(work_package)).to have_css(".wp-table--cell-container.-error", count: 2) + expect(page).to have_css('th a', text: cf_list_name.upcase) + expect(page).to have_css('th a', text: cf_text_name.upcase) + expect(wp_table.row(work_package)).to have_css('.wp-table--cell-container.-error', count: 2) cf_text = wp_table.edit_field(work_package, custom_fields.last.attribute_name(:camel_case)) - cf_text.update("my custom text", expect_failure: true) + cf_text.update('my custom text', expect_failure: true) cf_list = wp_table.edit_field(work_package, custom_fields.first.attribute_name(:camel_case)) - cf_list.field_type = "create-autocompleter" + cf_list.field_type = 'create-autocompleter' cf_list.openSelectField - cf_list.set_value("bar") + cf_list.set_value('bar') cf_text.expect_inactive! cf_list.expect_inactive! wp_table.expect_toast( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) work_package.reload - expect(work_package.send(custom_fields.first.attribute_getter)).to eq("bar") - expect(work_package.send(custom_fields.last.attribute_getter)).to eq("my custom text") + expect(work_package.send(custom_fields.first.attribute_getter)).to eq('bar') + expect(work_package.send(custom_fields.last.attribute_getter)).to eq('my custom text') # Saveguard to let the background update complete wp_table.visit! diff --git a/spec/features/work_packages/table/empty_filters_spec.rb b/spec/features/work_packages/table/empty_filters_spec.rb index cb9a70163369..8053a2766181 100644 --- a/spec/features/work_packages/table/empty_filters_spec.rb +++ b/spec/features/work_packages/table/empty_filters_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Empty query filters", :js do +RSpec.describe 'Empty query filters', :js do let(:user) { create(:admin) } let(:work_package) { create(:work_package) } let(:wp_table) { Pages::WorkPackagesTable.new } @@ -14,7 +14,7 @@ end # Tests for regression #23739 - it "allows to delete the last query filter" do + it 'allows to delete the last query filter' do # Open filter menu filters.expect_filter_count(1) filters.open diff --git a/spec/features/work_packages/table/group_by/group_by_boolean_spec.rb b/spec/features/work_packages/table/group_by/group_by_boolean_spec.rb index 881cace61ab1..bea6f49e021e 100644 --- a/spec/features/work_packages/table/group_by/group_by_boolean_spec.rb +++ b/spec/features/work_packages/table/group_by/group_by_boolean_spec.rb @@ -1,10 +1,10 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package group by boolean field", :js do +RSpec.describe 'Work Package group by boolean field', :js do let(:user) { create(:admin) } let(:project) { create(:project, types: [type], work_package_custom_fields: [bool_cf]) } - let(:bool_cf) { create(:boolean_wp_custom_field, name: "booleanField", types: [type]) } + let(:bool_cf) { create(:boolean_wp_custom_field, name: 'booleanField', types: [type]) } let(:type) { create(:type) } let!(:wp1) { create(:work_package, project:, type:) } @@ -20,15 +20,15 @@ wp_table.expect_work_package_listed wp1, wp2, wp3 end - it "shows group headers for groups by bool cf (regression test #34904)" do + it 'shows group headers for groups by bool cf (regression test #34904)' do # Group by category - group_by.enable_via_menu "booleanField" + group_by.enable_via_menu 'booleanField' loading_indicator_saveguard # Expect table to be grouped group_by.expect_number_of_groups 3 - group_by.expect_grouped_by_value "-", 1 - group_by.expect_grouped_by_value "true", 1 - group_by.expect_grouped_by_value "false", 1 + group_by.expect_grouped_by_value '-', 1 + group_by.expect_grouped_by_value 'true', 1 + group_by.expect_grouped_by_value 'false', 1 end end diff --git a/spec/features/work_packages/table/group_by/group_by_progress_spec.rb b/spec/features/work_packages/table/group_by/group_by_progress_spec.rb index fdf97f538e20..9fdbe3a8e908 100644 --- a/spec/features/work_packages/table/group_by/group_by_progress_spec.rb +++ b/spec/features/work_packages/table/group_by/group_by_progress_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package group by progress", :js do +RSpec.describe 'Work Package group by progress', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -15,7 +15,7 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "done_ratio"] + query.column_names = ['subject', 'done_ratio'] query.save! query @@ -28,39 +28,39 @@ wp_table.expect_work_package_listed wp_1, wp_2, wp_3, wp_4 end - it "shows group headers for group by progress (regression test #26717)" do + it 'shows group headers for group by progress (regression test #26717)' do # Group by category - group_by.enable_via_menu "% Complete" + group_by.enable_via_menu '% Complete' # Expect table to be grouped as WP created above group_by.expect_number_of_groups 3 - group_by.expect_grouped_by_value "0%", 1 - group_by.expect_grouped_by_value "10%", 2 - group_by.expect_grouped_by_value "50%", 1 + group_by.expect_grouped_by_value '0%', 1 + group_by.expect_grouped_by_value '10%', 2 + group_by.expect_grouped_by_value '50%', 1 # Update category of wp_none cat = wp_table.edit_field(wp_1, :percentageDone) - cat.update "50" + cat.update '50' loading_indicator_saveguard # Expect changed groups group_by.expect_number_of_groups 2 - group_by.expect_grouped_by_value "10%", 2 - group_by.expect_grouped_by_value "50%", 2 + group_by.expect_grouped_by_value '10%', 2 + group_by.expect_grouped_by_value '50%', 2 end - context "with grouped query" do + context 'with grouped query' do let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "done_ratio"] - query.group_by = "done_ratio" + query.column_names = ['subject', 'done_ratio'] + query.group_by = 'done_ratio' query.save! query end - it "keeps the disabled group by when reloading (Regression WP#26778)" do + it 'keeps the disabled group by when reloading (Regression WP#26778)' do # Expect table to be grouped as WP created above group_by.expect_number_of_groups 3 @@ -73,7 +73,7 @@ # But query has not been changed query.reload - expect(query.group_by).to eq "done_ratio" + expect(query.group_by).to eq 'done_ratio' end end end diff --git a/spec/features/work_packages/table/group_by/group_by_spec.rb b/spec/features/work_packages/table/group_by/group_by_spec.rb index 7eff288e4f81..b9b0fb6cbb01 100644 --- a/spec/features/work_packages/table/group_by/group_by_spec.rb +++ b/spec/features/work_packages/table/group_by/group_by_spec.rb @@ -28,9 +28,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package group by progress", :js do +RSpec.describe 'Work Package group by progress', :js do let(:user) { create(:admin) } let(:project) { create(:project) } let(:group_by) { Components::WorkPackages::GroupBy.new } @@ -49,6 +49,6 @@ # Expect table to be grouped into 1 group group_by.expect_number_of_groups 1 - group_by.expect_grouped_by_value "0%", 3 + group_by.expect_grouped_by_value '0%', 3 end end diff --git a/spec/features/work_packages/table/group_by/group_headers_spec.rb b/spec/features/work_packages/table/group_by/group_headers_spec.rb index b215e7a89565..37e32290854c 100644 --- a/spec/features/work_packages/table/group_by/group_headers_spec.rb +++ b/spec/features/work_packages/table/group_by/group_headers_spec.rb @@ -1,11 +1,11 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table group headers", :js do +RSpec.describe 'Work Package table group headers', :js do let(:user) { create(:admin) } let(:project) { create(:project) } - let(:category) { create(:category, project:, name: "Foo") } - let(:category2) { create(:category, project:, name: "Bar") } + let(:category) { create(:category, project:, name: 'Foo') } + let(:category2) { create(:category, project:, name: 'Bar') } let!(:wp_cat1) { create(:work_package, project:, category:) } let!(:wp_cat2) { create(:work_package, project:, category: category2) } @@ -15,7 +15,7 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "category"] + query.column_names = ['subject', 'category'] query.show_hierarchies = false query.save! @@ -31,26 +31,26 @@ wp_table.expect_work_package_listed(wp_none) end - it "shows group headers for group by category" do + it 'shows group headers for group by category' do # Group by category - group_by.enable_via_menu "Category" + group_by.enable_via_menu 'Category' # Expect table to be grouped as WP created above group_by.expect_number_of_groups 3 - group_by.expect_grouped_by_value "Foo", 1 - group_by.expect_grouped_by_value "Bar", 1 - group_by.expect_grouped_by_value "-", 1 + group_by.expect_grouped_by_value 'Foo', 1 + group_by.expect_grouped_by_value 'Bar', 1 + group_by.expect_grouped_by_value '-', 1 # Update category of wp_none cat = wp_table.edit_field(wp_none, :category) cat.activate! - cat.set_value "Foo" + cat.set_value 'Foo' loading_indicator_saveguard # Expect changed groups group_by.expect_number_of_groups 2 - group_by.expect_grouped_by_value "Foo", 2 - group_by.expect_grouped_by_value "Bar", 1 + group_by.expect_grouped_by_value 'Foo', 2 + group_by.expect_grouped_by_value 'Bar', 1 end end diff --git a/spec/features/work_packages/table/hierarchy/hierarchy_indent_spec.rb b/spec/features/work_packages/table/hierarchy/hierarchy_indent_spec.rb index aef59c3dd233..50e7bfc931fb 100644 --- a/spec/features/work_packages/table/hierarchy/hierarchy_indent_spec.rb +++ b/spec/features/work_packages/table/hierarchy/hierarchy_indent_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table hierarchy and sorting", :js, :with_cuprite do +RSpec.describe 'Work Package table hierarchy and sorting', :js, :with_cuprite do shared_let(:project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -10,33 +10,33 @@ shared_let(:wp_root) do create(:work_package, project:, - subject: "Parent") + subject: 'Parent') end shared_let(:wp_child1) do create(:work_package, project:, parent: wp_root, - subject: "WP child 1") + subject: 'WP child 1') end shared_let(:wp_child2) do create(:work_package, project:, parent: wp_root, - subject: "WP child 2") + subject: 'WP child 2') end shared_let(:wp_child3) do create(:work_package, project:, parent: wp_root, - subject: "WP child 3") + subject: 'WP child 3') end shared_current_user { create(:admin) } - it "can indent hierarchies" do + it 'can indent hierarchies' do wp_table.visit! wp_table.expect_work_package_listed(wp_root, wp_child1, wp_child2, wp_child3) hierarchy.expect_hierarchy_at(wp_root) @@ -51,7 +51,7 @@ # Indent last child hierarchy.indent! wp_child3 - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' hierarchy.expect_hierarchy_at(wp_root, wp_child2) hierarchy.expect_leaf_at(wp_child1, wp_child3) @@ -69,33 +69,33 @@ expect(wp_child3.parent).to eq(wp_child2) end - it "can edit a work package, then indent, and then edit again (Regression #30994)" do + it 'can edit a work package, then indent, and then edit again (Regression #30994)' do wp_table.visit! wp_table.expect_work_package_listed(wp_root, wp_child1, wp_child2, wp_child3) hierarchy.expect_hierarchy_at(wp_root) hierarchy.expect_leaf_at(wp_child1, wp_child2, wp_child3) subject = wp_table.edit_field(wp_child3, :subject) - subject.update "First edit" + subject.update 'First edit' wait_for_network_idle - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' # Indent last child hierarchy.indent! wp_child3 wait_for_network_idle - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' # Expect changed hierarchy.expect_hierarchy_at(wp_root, wp_child2) hierarchy.expect_leaf_at(wp_child1, wp_child3) subject = wp_table.edit_field(wp_child3, :subject) - subject.update "Second edit" + subject.update 'Second edit' wait_for_network_idle - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' wp_child3.reload - expect(wp_child3.subject).to eq "Second edit" + expect(wp_child3.subject).to eq 'Second edit' expect(wp_child3.parent).to eq wp_child2 end end diff --git a/spec/features/work_packages/table/hierarchy/hierarchy_parent_below_spec.rb b/spec/features/work_packages/table/hierarchy/hierarchy_parent_below_spec.rb index 75ff409c095e..cfacef7ab2fd 100644 --- a/spec/features/work_packages/table/hierarchy/hierarchy_parent_below_spec.rb +++ b/spec/features/work_packages/table/hierarchy/hierarchy_parent_below_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table hierarchy parent below", :js do +RSpec.describe 'Work Package table hierarchy parent below', :js do let(:user) { create(:admin) } let(:type_bug) { create(:type_bug) } let(:type_task) { create(:type_task) } @@ -33,17 +33,17 @@ # .. V Parent # .... Child # V Grandparent - describe "grand-parent sorted below child, parent invisible" do + describe 'grand-parent sorted below child, parent invisible' do let(:child) { create(:work_package, project:, type: type_task) } let(:parent) { create(:work_package, project:, type: type_bug) } let(:grandparent) { create(:work_package, project:, type: type_task) } let(:query) do query = build(:query, user:, project:) - query.column_names = ["id", "subject", "type"] + query.column_names = ['id', 'subject', 'type'] query.sort_criteria = [%w(id asc)] query.filters.clear - query.add_filter("type_id", "=", [type_task.id]) + query.add_filter('type_id', '=', [type_task.id]) query.show_hierarchies = true query.save! @@ -61,7 +61,7 @@ query end - it "shows hierarchy correctly" do + it 'shows hierarchy correctly' do wp_table.visit_query query wp_table.expect_work_package_listed(child, parent, grandparent) @@ -93,11 +93,11 @@ end end - describe "grand-parent of 2+ children visible anywhere on the page, but parent is not (Regression #29652)" do - let(:child) { create(:work_package, subject: "AA Child WP", project:, type: type_task) } - let(:child2) { create(:work_package, subject: "BB Child WP", project:, type: type_task) } - let(:parent) { create(:work_package, subject: "ZZ Parent WP", project:, type: type_task) } - let(:grandparent) { create(:work_package, subject: "Grandparent", project:, type: type_task) } + describe 'grand-parent of 2+ children visible anywhere on the page, but parent is not (Regression #29652)' do + let(:child) { create(:work_package, subject: 'AA Child WP', project:, type: type_task) } + let(:child2) { create(:work_package, subject: 'BB Child WP', project:, type: type_task) } + let(:parent) { create(:work_package, subject: 'ZZ Parent WP', project:, type: type_task) } + let(:grandparent) { create(:work_package, subject: 'Grandparent', project:, type: type_task) } let(:query) do query = build(:query, user:, project:) @@ -118,20 +118,20 @@ child2.update(parent_id: parent.id) parent.update(parent_id: grandparent.id) - allow(Setting).to receive(:per_page_options).and_return "3" + allow(Setting).to receive(:per_page_options).and_return '3' query end - it "shows hierarchy correctly" do + it 'shows hierarchy correctly' do wp_table.visit_query query wp_table.expect_work_package_listed(child, child2, parent, grandparent) # Expect pagination to be correct - expect(page).to have_css(".op-pagination--item_current", text: "3") + expect(page).to have_css('.op-pagination--item_current', text: '3') # Expect count to be correct (one additional parent shown) - expect(page).to have_css(".wp--row", count: 4) + expect(page).to have_css('.wp--row', count: 4) # Double order result from regression wp_table.expect_work_package_order(grandparent.id, parent.id, child.id, child2.id) @@ -142,9 +142,9 @@ end end - describe "An arrow is beside parent name" do - let(:child) { create(:work_package, subject: "AA Child WP", project:, parent:) } - let(:parent) { create(:work_package, subject: "ZZ Parent WP", project:) } + describe 'An arrow is beside parent name' do + let(:child) { create(:work_package, subject: 'AA Child WP', project:, parent:) } + let(:parent) { create(:work_package, subject: 'ZZ Parent WP', project:) } let(:relations) { Components::WorkPackages::Relations.new(parent) } before do @@ -155,14 +155,14 @@ wp_table.visit! wp_table.expect_work_package_listed(child, parent) - expect(page).to have_css(".wp-table--hierarchy-indicator-icon") + expect(page).to have_css('.wp-table--hierarchy-indicator-icon') split_page = wp_table.open_split_view(parent) split_page.visit_tab!("relations") relations.remove_child(child) loading_indicator_saveguard - expect(page).to have_no_css(".wp-table--hierarchy-indicator-icon") + expect(page).to have_no_css('.wp-table--hierarchy-indicator-icon') end end end diff --git a/spec/features/work_packages/table/hierarchy/hierarchy_sorting_spec.rb b/spec/features/work_packages/table/hierarchy/hierarchy_sorting_spec.rb index a36c81e3e81c..705b0fb5a6b4 100644 --- a/spec/features/work_packages/table/hierarchy/hierarchy_sorting_spec.rb +++ b/spec/features/work_packages/table/hierarchy/hierarchy_sorting_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table hierarchy and sorting", :js do +RSpec.describe 'Work Package table hierarchy and sorting', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -11,7 +11,7 @@ let!(:wp_root) do create(:work_package, project:, - subject: "Parent", + subject: 'Parent', start_date: 10.days.ago, due_date: Date.current) end @@ -20,7 +20,7 @@ create(:work_package, project:, parent: wp_root, - subject: "Child at end", + subject: 'Child at end', start_date: 2.days.ago, due_date: Date.current) end @@ -29,7 +29,7 @@ create(:work_package, project:, parent: wp_root, - subject: "Middle child", + subject: 'Middle child', start_date: 5.days.ago, due_date: 3.days.ago) end @@ -38,7 +38,7 @@ create(:work_package, project:, parent: wp_root, - subject: "Child at beginning", + subject: 'Child at beginning', start_date: 10.days.ago, due_date: 9.days.ago) end @@ -47,7 +47,7 @@ login_as(user) end - it "can show hierarchies and sort by start_date" do + it 'can show hierarchies and sort by start_date' do wp_table.visit! wp_table.expect_work_package_listed(wp_root, wp_child1, wp_child2, wp_child3) hierarchy.expect_hierarchy_at(wp_root) @@ -57,7 +57,7 @@ wp_table.expect_work_package_order wp_root, wp_child1, wp_child2, wp_child3 # Enable sort by start date - sort_by.update_criteria ["Start date", "asc"] + sort_by.update_criteria ['Start date', 'asc'] loading_indicator_saveguard # Hierarchy still exists diff --git a/spec/features/work_packages/table/hierarchy/hierarchy_spec.rb b/spec/features/work_packages/table/hierarchy/hierarchy_spec.rb index 04bd7c2b2306..d1e3a8d0b35a 100644 --- a/spec/features/work_packages/table/hierarchy/hierarchy_spec.rb +++ b/spec/features/work_packages/table/hierarchy/hierarchy_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table hierarchy", :js do +RSpec.describe 'Work Package table hierarchy', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -11,8 +11,8 @@ login_as(user) end - describe "hierarchies in same project" do - let(:category) { create(:category, project:, name: "Foo") } + describe 'hierarchies in same project' do + let(:category) { create(:category, project:, name: 'Foo') } let!(:wp_root) { create(:work_package, project:) } let!(:wp_inter) { create(:work_package, project:, parent: wp_root) } @@ -21,16 +21,16 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "category"] + query.column_names = ['subject', 'category'] query.filters.clear - query.add_filter("category_id", "=", [category.id]) + query.add_filter('category_id', '=', [category.id]) query.show_hierarchies = true query.save! query end - it "shows hierarchy correctly" do + it 'shows hierarchy correctly' do wp_table.visit! wp_table.expect_work_package_listed(wp_root, wp_inter, wp_leaf, wp_other) @@ -57,9 +57,9 @@ # Editing is possible while retaining hierarchy hierarchy.enable_hierarchy subject = wp_table.edit_field wp_inter, :subject - subject.update "New subject" + subject.update 'New subject' - wp_table.expect_toast message: "Successful update." + wp_table.expect_toast message: 'Successful update.' wp_table.dismiss_toaster! hierarchy.expect_hierarchy_at(wp_root, wp_inter) @@ -88,13 +88,13 @@ end end - describe "with a cross project hierarchy" do + describe 'with a cross project hierarchy' do let(:project2) { create(:project) } let!(:wp_root) { create(:work_package, project:) } let!(:wp_inter) { create(:work_package, project: project2, parent: wp_root) } let(:global_table) { Pages::WorkPackagesTable.new } - it "shows the hierarchy indicator only when the rows are both shown" do + it 'shows the hierarchy indicator only when the rows are both shown' do wp_table.visit! wp_table.expect_work_package_listed(wp_root) wp_table.ensure_work_package_not_listed!(wp_inter) @@ -108,23 +108,23 @@ end end - describe "flat table such that the parent appears below the child" do + describe 'flat table such that the parent appears below the child' do let!(:wp_root) { create(:work_package, project:) } let!(:wp_inter) { create(:work_package, project:, parent: wp_root) } let!(:wp_leaf) { create(:work_package, project:, parent: wp_inter) } let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "category"] + query.column_names = ['subject', 'category'] query.filters.clear query.show_hierarchies = false - query.sort_criteria = [["id", "asc"]] + query.sort_criteria = [['id', 'asc']] query.save! query end - it "removes the parent from the flow in hierarchy mode, moving it above" do + it 'removes the parent from the flow in hierarchy mode, moving it above' do # Hierarchy disabled, expect wp_inter before wp_root wp_table.visit_query query wp_table.expect_work_package_listed(wp_inter, wp_root, wp_leaf) @@ -136,7 +136,7 @@ hierarchy.enable_hierarchy # Should not be marked as additional row (grey) - expect(page).to have_no_css(".wp-table--hierarchy-aditional-row") + expect(page).to have_no_css('.wp-table--hierarchy-aditional-row') hierarchy.expect_hierarchy_at(wp_root, wp_inter) hierarchy.expect_leaf_at(wp_leaf) @@ -154,25 +154,25 @@ end end - describe "sorting by assignee" do - include_context "work package table helpers" + describe 'sorting by assignee' do + include_context 'work package table helpers' let(:root_assigned) do - create(:work_package, subject: "root_assigned", project:, assigned_to: user) + create(:work_package, subject: 'root_assigned', project:, assigned_to: user) end let(:inter_assigned) do - create(:work_package, subject: "inter_assigned", project:, assigned_to: user, parent: root_assigned) + create(:work_package, subject: 'inter_assigned', project:, assigned_to: user, parent: root_assigned) end let(:inter) do - create(:work_package, subject: "inter", project:, parent: root_assigned) + create(:work_package, subject: 'inter', project:, parent: root_assigned) end let(:leaf_assigned) do - create(:work_package, subject: "leaf_assigned", project:, assigned_to: user, parent: inter) + create(:work_package, subject: 'leaf_assigned', project:, assigned_to: user, parent: inter) end let(:leaf) do - create(:work_package, subject: "leaf", project:, parent: inter) + create(:work_package, subject: 'leaf', project:, parent: inter) end let(:root) do - create(:work_package, subject: "root", project:) + create(:work_package, subject: 'root', project:) end let(:user) do @@ -185,9 +185,9 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["id", "subject", "assigned_to"] + query.column_names = ['id', 'subject', 'assigned_to'] query.filters.clear - query.sort_criteria = [["assigned_to", "asc"], ["id", "asc"]] + query.sort_criteria = [['assigned_to', 'asc'], ['id', 'asc']] query.show_hierarchies = false query.save! @@ -205,7 +205,7 @@ leaf_assigned end - it "shows the respective order" do + it 'shows the respective order' do wp_table.visit_query query wp_table.expect_work_package_listed(leaf, inter, root) wp_table.expect_work_package_listed(leaf_assigned, inter_assigned, root_assigned) @@ -250,7 +250,7 @@ hierarchy.toggle_row(root_assigned) # Sort descending - sort_by.update_criteria(["Assignee", { descending: true }]) + sort_by.update_criteria(['Assignee', { descending: true }]) loading_indicator_saveguard wp_table.expect_work_package_listed(root, root_assigned) diff --git a/spec/features/work_packages/table/hierarchy/hierarchy_vs_grouping_spec.rb b/spec/features/work_packages/table/hierarchy/hierarchy_vs_grouping_spec.rb index 252976d4107a..9e2f4f2a0e32 100644 --- a/spec/features/work_packages/table/hierarchy/hierarchy_vs_grouping_spec.rb +++ b/spec/features/work_packages/table/hierarchy/hierarchy_vs_grouping_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table hierarchy vs grouping", :js do +RSpec.describe 'Work Package table hierarchy vs grouping', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -40,25 +40,25 @@ login_as(user) end - it "is mutually exclusive" do + it 'is mutually exclusive' do wp_table.visit! hierarchy.expect_mode_enabled - group_by.enable_via_header("Type") + group_by.enable_via_header('Type') hierarchy.expect_mode_disabled hierarchy.enable_via_menu - group_by.expect_not_grouped_by("Type") + group_by.expect_not_grouped_by('Type') - group_by.enable_via_menu("Type") + group_by.enable_via_menu('Type') hierarchy.expect_mode_disabled hierarchy.enable_via_header - group_by.expect_not_grouped_by("Type") + group_by.expect_not_grouped_by('Type') end end diff --git a/spec/features/work_packages/table/hierarchy/parent_column_spec.rb b/spec/features/work_packages/table/hierarchy/parent_column_spec.rb index a29da2d2bb0c..e4bf762a997d 100644 --- a/spec/features/work_packages/table/hierarchy/parent_column_spec.rb +++ b/spec/features/work_packages/table/hierarchy/parent_column_spec.rb @@ -1,13 +1,13 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table parent column", :js do +RSpec.describe 'Work Package table parent column', :js do let(:user) { create(:admin) } let!(:parent) { create(:work_package, project:) } let!(:child) { create(:work_package, project:, parent:) } let!(:other_wp) { create(:work_package, project:) } let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "parent"] + query.column_names = ['subject', 'parent'] query.filters.clear query.show_hierarchies = false @@ -22,28 +22,28 @@ login_as(user) end - it "shows parent columns correctly (Regression #26951)" do + it 'shows parent columns correctly (Regression #26951)' do wp_table.visit_query query wp_table.expect_work_package_listed(parent, child) # Hierarchy mode is enabled by default page.within(".wp-row-#{parent.id}") do - expect(page).to have_css("td.parent", text: "-") + expect(page).to have_css('td.parent', text: '-') end page.within(".wp-row-#{child.id}") do - expect(page).to have_css("td.parent", text: "##{parent.id}") + expect(page).to have_css('td.parent', text: "##{parent.id}") end end - it "can edit the parent work package (Regression #43647)" do + it 'can edit the parent work package (Regression #43647)' do wp_table.visit_query query wp_table.expect_work_package_listed(parent, child) parent_field = wp_table.edit_field(child, :parent) parent_field.update other_wp.subject - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' child.reload expect(child.parent).to eq other_wp diff --git a/spec/features/work_packages/table/inline_create/create_work_packages_spec.rb b/spec/features/work_packages/table/inline_create/create_work_packages_spec.rb index 4bcbd45d2a71..8450cc93b072 100644 --- a/spec/features/work_packages/table/inline_create/create_work_packages_spec.rb +++ b/spec/features/work_packages/table/inline_create/create_work_packages_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "inline create work package", :js do +RSpec.describe 'inline create work package', :js do let(:type) { create(:type) } let(:types) { [type] } @@ -28,67 +28,67 @@ login_as user end - shared_examples "inline create work package" do - context "when user may create work packages" do - it "allows to create work packages" do + shared_examples 'inline create work package' do + context 'when user may create work packages' do + it 'allows to create work packages' do wp_table.expect_work_package_listed(existing_wp) wp_table.click_inline_create - expect(page).to have_css(".wp--row", count: 2) - expect(page).to have_css(".wp-inline-create-row") - expect(page).to have_focus_on("#wp-new-inline-edit--field-subject") + expect(page).to have_css('.wp--row', count: 2) + expect(page).to have_css('.wp-inline-create-row') + expect(page).to have_focus_on('#wp-new-inline-edit--field-subject') # Expect subject to be activated subject_field = wp_table.edit_field(nil, :subject) subject_field.expect_active! - subject_field.set_value "Some subject" + subject_field.set_value 'Some subject' subject_field.save! # Callback for adjustments callback.call wp_table.expect_toast( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) # Expect new create row to exist - expect(page).to have_css(".wp--row", count: 2) - expect(page).to have_button(exact_text: "Create new work package") + expect(page).to have_css('.wp--row', count: 2) + expect(page).to have_button(exact_text: 'Create new work package') wp_table.click_inline_create subject_field = wp_table.edit_field(nil, :subject) subject_field.expect_active! - subject_field.set_value "Another subject" + subject_field.set_value 'Another subject' subject_field.save! # Callback for adjustments callback.call - expect(page).to have_css(".wp--row .subject", text: "Some subject") - expect(page).to have_css(".wp--row .subject", text: "Another subject") + expect(page).to have_css('.wp--row .subject', text: 'Some subject') + expect(page).to have_css('.wp--row .subject', text: 'Another subject') # safeguards wp_table.dismiss_toaster! wp_table.expect_no_toaster( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) # Expect no inline create open - expect(page).to have_no_css(".wp-inline-create-row") + expect(page).to have_no_css('.wp-inline-create-row') end end - context "when user may not create work packages" do + context 'when user may not create work packages' do let(:permissions) { [:view_work_packages] } - it "renders the work package, but no create row" do + it 'renders the work package, but no create row' do wp_table.expect_work_package_listed(existing_wp) - expect(page).to have_no_button(exact_text: "Create new work package") + expect(page).to have_no_button(exact_text: 'Create new work package') end end - context "when having filtered by custom field and switching to that type" do + context 'when having filtered by custom field and switching to that type' do let(:cf_list) do create(:list_wp_custom_field, is_for_all: true, is_filter: true) end @@ -98,10 +98,10 @@ let(:cf_type) { create(:type, custom_fields: [cf_list]) } let(:columns) { Components::WorkPackages::Columns.new } - it "applies the filter value for the custom field" do + it 'applies the filter value for the custom field' do wp_table.visit! filters.open - filters.add_filter_by cf_list.name, "is (OR)", cf_list.custom_options.second.name, cf_accessor_frontend + filters.add_filter_by cf_list.name, 'is (OR)', cf_list.custom_options.second.name, cf_accessor_frontend sleep(0.3) @@ -118,16 +118,16 @@ wp_table.expect_toast( type: :error, - message: "Subject can't be blank." + message: 'Subject can\'t be blank.' ) subject_field = wp_table.edit_field(nil, :subject) subject_field.expect_active! - subject_field.set_value "Some subject" + subject_field.set_value 'Some subject' subject_field.save! wp_table.expect_toast( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) created_wp = WorkPackage.last @@ -138,14 +138,14 @@ end end - describe "global create" do + describe 'global create' do let(:wp_table) { Pages::WorkPackagesTable.new } before do wp_table.visit! end - it_behaves_like "inline create work package" do + it_behaves_like 'inline create work package' do let(:callback) do -> { # Set project which will also select the type (first one in the selected project) @@ -159,20 +159,20 @@ end end - describe "project context create" do + describe 'project context create' do let(:wp_table) { Pages::WorkPackagesTable.new(project) } before do wp_table.visit! end - it_behaves_like "inline create work package" do + it_behaves_like 'inline create work package' do let(:callback) do -> {} end end - context "when user has permissions in other project" do + context 'when user has permissions in other project' do let(:permissions) { [:view_work_packages] } let(:project2) { create(:project) } @@ -188,10 +188,10 @@ roles: [role2]) end - it "renders the work packages, but no create" do + it 'renders the work packages, but no create' do wp_table.expect_work_package_listed(existing_wp) - expect(page).to have_no_button(exact_text: "Create new work package") - expect(page).to have_css(".add-work-package[disabled]") + expect(page).to have_no_button(exact_text: 'Create new work package') + expect(page).to have_css('.add-work-package[disabled]') end end end diff --git a/spec/features/work_packages/table/inline_create/inline_create_refresh_spec.rb b/spec/features/work_packages/table/inline_create/inline_create_refresh_spec.rb index 9d362f9a59a0..84cbcd892863 100644 --- a/spec/features/work_packages/table/inline_create/inline_create_refresh_spec.rb +++ b/spec/features/work_packages/table/inline_create/inline_create_refresh_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Refreshing in inline-create row", :flaky, :js do +RSpec.describe 'Refreshing in inline-create row', :flaky, :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -10,7 +10,7 @@ let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject", "category"] + query.column_names = ['subject', 'category'] query.filters.clear query.save! @@ -22,17 +22,17 @@ wp_table.visit_query(query) end - it "correctly updates the set of active columns" do - expect(page).to have_css(".wp--row", count: 0) + it 'correctly updates the set of active columns' do + expect(page).to have_css('.wp--row', count: 0) wp_table.click_inline_create - expect(page).to have_css(".wp--row", count: 1) + expect(page).to have_css('.wp--row', count: 1) - expect(page).to have_css(".wp-inline-create-row") - expect(page).to have_css(".wp-inline-create-row .wp-table--cell-td.subject") - expect(page).to have_css(".wp-inline-create-row .wp-table--cell-td.category") + expect(page).to have_css('.wp-inline-create-row') + expect(page).to have_css('.wp-inline-create-row .wp-table--cell-td.subject') + expect(page).to have_css('.wp-inline-create-row .wp-table--cell-td.category') - columns.add "% Complete" - expect(page).to have_css(".wp-inline-create-row .wp-table--cell-td.wp-table--cell-td.percentageDone") + columns.add '% Complete' + expect(page).to have_css('.wp-inline-create-row .wp-table--cell-td.wp-table--cell-td.percentageDone') end end diff --git a/spec/features/work_packages/table/inline_create/parallel_creation_spec.rb b/spec/features/work_packages/table/inline_create/parallel_creation_spec.rb index aa26dda79bc5..0e9b73355720 100644 --- a/spec/features/work_packages/table/inline_create/parallel_creation_spec.rb +++ b/spec/features/work_packages/table/inline_create/parallel_creation_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Parallel work package creation spec", :js do +RSpec.describe 'Parallel work package creation spec', :js do let(:type) { project.types.first } let(:permissions) { %i(view_work_packages add_work_packages edit_work_packages) } @@ -35,39 +35,39 @@ def new_work_package_in_both(subject, description) # Create in split screen split = wp_table.create_wp_by_button type - description_field = TextEditorField.new split, "description" + description_field = TextEditorField.new split, 'description' description_field.expect_active! description_field.set_value description end - it "with a new work package in split and inline create, both are saved" do + it 'with a new work package in split and inline create, both are saved' do # Expect table to be empty wp_table.visit! wp_table.expect_no_work_package_listed # Open split screen and inline create - new_work_package_in_both "Some subject", "My description!" + new_work_package_in_both 'Some subject', 'My description!' # Save in inline create - expect(page).to have_css(".wp-inline-create-row") - expect(page).to have_css(".wp--row", count: 1) + expect(page).to have_css('.wp-inline-create-row') + expect(page).to have_css('.wp--row', count: 1) subject_field = wp_table.edit_field(nil, :subject) subject_field.save! # There should be one row, and no open inline create row - expect(page).to have_css(".wp--row", count: 1) - expect(page).to have_no_css(".wp-inline-create-row") + expect(page).to have_css('.wp--row', count: 1) + expect(page).to have_no_css('.wp-inline-create-row') wp_table.expect_toast( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) wp_table.dismiss_toaster! # Get the last work package wp1 = WorkPackage.last - expect(wp1.subject).to eq "Some subject" - expect(wp1.description).to eq "My description!" + expect(wp1.subject).to eq 'Some subject' + expect(wp1.description).to eq 'My description!' wp_table.expect_work_package_listed wp1 @@ -75,31 +75,31 @@ def new_work_package_in_both(subject, description) created_split = Pages::SplitWorkPackage.new wp1, project subject_field = created_split.edit_field :subject subject_field.expect_inactive! - subject_field.expect_state_text "Some subject" + subject_field.expect_state_text 'Some subject' # Open split screen and inline create - new_work_package_in_both "New subject", "New description" + new_work_package_in_both 'New subject', 'New description' # Inline create still open - expect(page).to have_css(".wp-inline-create-row") + expect(page).to have_css('.wp-inline-create-row') # Save in split screen new_split = Pages::SplitWorkPackageCreate.new(project:) subject_field = new_split.edit_field :subject subject_field.expect_active! - subject_field.expect_value "New subject" + subject_field.expect_value 'New subject' subject_field.save! wp_table.expect_toast( - message: "Successful creation." + message: 'Successful creation.' ) wp_table.dismiss_toaster! - expect(page).to have_css(".wp--row", count: 2) - expect(page).to have_no_css(".wp-inline-create-row") + expect(page).to have_css('.wp--row', count: 2) + expect(page).to have_no_css('.wp-inline-create-row') # Get the last work package wp2 = WorkPackage.last - expect(wp2.subject).to eq "New subject" - expect(wp2.description).to eq "New description" + expect(wp2.subject).to eq 'New subject' + expect(wp2.description).to eq 'New description' end end diff --git a/spec/features/work_packages/table/invalid_query_spec.rb b/spec/features/work_packages/table/invalid_query_spec.rb index abb7c49432f9..c95955c7a3e7 100644 --- a/spec/features/work_packages/table/invalid_query_spec.rb +++ b/spec/features/work_packages/table/invalid_query_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Invalid query spec", :js do +RSpec.describe 'Invalid query spec', :js do let(:user) { create(:admin) } let(:project) { create(:project) } @@ -26,9 +26,9 @@ project:, user:) - query.add_filter("assigned_to_id", "=", [99999]) - query.columns << "cf_0815" - query.group_by = "cf_0815" + query.add_filter('assigned_to_id', '=', [99999]) + query.columns << 'cf_0815' + query.group_by = 'cf_0815' query.sort_criteria = [%w(cf_0815 desc)] query.save(validate: false) create(:view_work_packages_table, query:) @@ -57,55 +57,55 @@ work_package_assigned end - it "handles invalid queries" do + it 'handles invalid queries' do # should load a faulty query and also the drop down wp_table.visit_query(invalid_query) filters.open filters.expect_filter_count 1 - filters.expect_no_filter_by("Assignee") - filters.expect_filter_by("Status", "open", nil) + filters.expect_no_filter_by('Assignee') + filters.expect_filter_by('Status', 'open', nil) wp_table.expect_no_toaster(type: :error, - message: I18n.t("js.work_packages.faulty_query.description")) + message: I18n.t('js.work_packages.faulty_query.description')) wp_table.expect_work_package_listed work_package_assigned wp_table.expect_query_in_select_dropdown(invalid_query.name) - Capybara.current_session.driver.execute_script("window.localStorage.clear()") + Capybara.current_session.driver.execute_script('window.localStorage.clear()') # should not load with faulty parameters but can be fixed - filter_props = [{ n: "assignee", o: "=", v: ["999999"] }, - { n: "status", o: "=", v: [status.id.to_s, status2.id.to_s] }] + filter_props = [{ n: 'assignee', o: '=', v: ['999999'] }, + { n: 'status', o: '=', v: [status.id.to_s, status2.id.to_s] }] column_props = %w(id subject customField0815) invalid_props = JSON.dump({ f: filter_props, c: column_props, - g: "customField0815", - t: "customField0815:desc" }) + g: 'customField0815', + t: 'customField0815:desc' }) wp_table.visit_with_params("query_id=#{valid_query.id}&query_props=#{invalid_props}") wp_table.expect_toast(type: :error, - message: I18n.t("js.work_packages.faulty_query.description")) + message: I18n.t('js.work_packages.faulty_query.description')) wp_table.dismiss_toaster! wp_table.expect_no_work_package_listed filters.expect_filter_count 2 filters.open - filters.expect_filter_by("Assignee", "is (OR)", :placeholder) - filters.expect_filter_by("Status", "is (OR)", [status.name, status2.name]) + filters.expect_filter_by('Assignee', 'is (OR)', :placeholder) + filters.expect_filter_by('Status', 'is (OR)', [status.name, status2.name]) - group_by.enable_via_menu("Assignee") + group_by.enable_via_menu('Assignee') sleep(0.3) - filters.set_filter("Assignee", "is (OR)", user.name) + filters.set_filter('Assignee', 'is (OR)', user.name) sleep(0.3) wp_table.expect_work_package_listed work_package_assigned wp_table.save - wp_table.expect_toast(message: I18n.t("js.notice_successful_update")) + wp_table.expect_toast(message: I18n.t('js.notice_successful_update')) end end diff --git a/spec/features/work_packages/table/milestones_spec.rb b/spec/features/work_packages/table/milestones_spec.rb index 2b74d9a7c9b5..702a42791ba1 100644 --- a/spec/features/work_packages/table/milestones_spec.rb +++ b/spec/features/work_packages/table/milestones_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Inline editing milestones", :js do +RSpec.describe 'Inline editing milestones', :js do let(:user) { create(:admin) } let(:type) { create(:type, is_milestone: true) } @@ -9,7 +9,7 @@ create(:work_package, project:, type:, - subject: "Foobar") + subject: 'Foobar') end let!(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -30,7 +30,7 @@ wp_table.expect_work_package_listed work_package end - it "mapping for start and finish date in the table (regression #26044)" do + it 'mapping for start and finish date in the table (regression #26044)' do start_date = wp_table.edit_field(work_package, :startDate) due_date = wp_table.edit_field(work_package, :dueDate) @@ -48,14 +48,14 @@ start_date.expect_inactive! due_date.expect_inactive! - start_date.update "2017-08-07" + start_date.update '2017-08-07' start_date.expect_inactive! - start_date.expect_state_text "08/07/2017" - due_date.expect_state_text "08/07/2017" + start_date.expect_state_text '08/07/2017' + due_date.expect_state_text '08/07/2017' work_package.reload expect work_package.milestone? - expect(work_package.start_date.iso8601).to eq("2017-08-07") - expect(work_package.due_date.iso8601).to eq("2017-08-07") + expect(work_package.start_date.iso8601).to eq('2017-08-07') + expect(work_package.due_date.iso8601).to eq('2017-08-07') end end diff --git a/spec/features/work_packages/table/queries/assignee_filter_spec.rb b/spec/features/work_packages/table/queries/assignee_filter_spec.rb index ad0d73c314d4..547f7d34fc4f 100644 --- a/spec/features/work_packages/table/queries/assignee_filter_spec.rb +++ b/spec/features/work_packages/table/queries/assignee_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering by assignee", :js do +RSpec.describe 'Work package filtering by assignee', :js do let(:project) { create(:project) } let(:invisible_project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -36,14 +36,14 @@ let(:role) { create(:project_role, permissions: %i[view_work_packages save_queries]) } let(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_roles: { project => role }) end let(:invisible_user) do create(:user, - firstname: "Invisible", - lastname: "User", + firstname: 'Invisible', + lastname: 'User', member_with_roles: { invisible_project => role }) end let(:placeholder_user) do @@ -65,21 +65,21 @@ create(:user, member_with_roles: { project => role }) end - it "shows the work package matching the assigned to filter" do + it 'shows the work package matching the assigned to filter' do wp_table.visit! wp_table.expect_work_package_listed(work_package_user_assignee, work_package_placeholder_user_assignee) filters.open - filters.expect_missing_filter_value_by("Assignee", "is (OR)", [invisible_user.name]) + filters.expect_missing_filter_value_by('Assignee', 'is (OR)', [invisible_user.name]) - filters.add_filter_by("Assignee", "is (OR)", [other_user.name]) + filters.add_filter_by('Assignee', 'is (OR)', [other_user.name]) wp_table.ensure_work_package_not_listed!(work_package_placeholder_user_assignee) wp_table.expect_work_package_listed(work_package_user_assignee) - wp_table.save_as("Subject query") + wp_table.save_as('Subject query') - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') # Revisit query wp_table.visit_query Query.last @@ -87,9 +87,9 @@ wp_table.expect_work_package_listed(work_package_user_assignee) filters.open - filters.expect_filter_by("Assignee", "is (OR)", [other_user.name]) - filters.remove_filter "assignee" - filters.add_filter_by("Assignee", "is (OR)", [placeholder_user.name]) + filters.expect_filter_by('Assignee', 'is (OR)', [other_user.name]) + filters.remove_filter 'assignee' + filters.add_filter_by('Assignee', 'is (OR)', [placeholder_user.name]) wp_table.ensure_work_package_not_listed!(work_package_user_assignee) wp_table.expect_work_package_listed(work_package_placeholder_user_assignee) diff --git a/spec/features/work_packages/table/queries/assignees_role_filter_spec.rb b/spec/features/work_packages/table/queries/assignees_role_filter_spec.rb index 216722916e72..2f2cb0bd95b1 100644 --- a/spec/features/work_packages/table/queries/assignees_role_filter_spec.rb +++ b/spec/features/work_packages/table/queries/assignees_role_filter_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "Work package filtering by assignee's role", :js, :with_cuprite do shared_let(:project) { create(:project) } @@ -45,8 +45,8 @@ shared_let(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_roles: { project => project_role, work_package_user_assignee => visible_work_package_role }) end @@ -75,11 +75,11 @@ filters.open # It does not show builtin roles such as Anonymous and NonMember or roles that don't allow the user to become an assignee filters.expect_missing_filter_value_by("Assignee's role", - "is (OR)", + 'is (OR)', (builtin_roles + non_assignable_roles), - "assignedToRole") + 'assignedToRole') - filters.add_filter_by("Assignee's role", "is (OR)", assignable_roles, "assignedToRole") + filters.add_filter_by("Assignee's role", 'is (OR)', assignable_roles, 'assignedToRole') filters.expect_filter_count("2") @@ -93,8 +93,8 @@ sleep 1 - wp_table.save_as("Subject query", by_title: true) - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.save_as('Subject query', by_title: true) + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') # Revisit query wp_table.visit_query Query.last @@ -103,9 +103,9 @@ filters.open # Do not show the already selected roles in the autocomplete dropdown - filters.expect_missing_autocomplete_value("assignedToRole", assignable_roles) + filters.expect_missing_autocomplete_value('assignedToRole', assignable_roles) # Ensure that all assigned roles are shown in the filter - filters.expect_filter_by("Assignee's role", "is (OR)", assignable_roles, "assignedToRole") + filters.expect_filter_by("Assignee's role", 'is (OR)', assignable_roles, 'assignedToRole') end end diff --git a/spec/features/work_packages/table/queries/bool_cf_filter_spec.rb b/spec/features/work_packages/table/queries/bool_cf_filter_spec.rb index d5827945c2c4..246b34a378fe 100644 --- a/spec/features/work_packages/table/queries/bool_cf_filter_spec.rb +++ b/spec/features/work_packages/table/queries/bool_cf_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering by bool custom field", :js do +RSpec.describe 'Work package filtering by bool custom field', :js do let(:project) { create(:project) } let(:type) { project.types.first } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -74,7 +74,7 @@ member_with_permissions: { project => %i[view_work_packages save_queries] }) end - it "shows the work package matching the bool cf filter" do + it 'shows the work package matching the bool cf filter' do wp_table.visit! wp_table.expect_work_package_listed(work_package_true, work_package_false, work_package_without, work_package_other_type) @@ -86,9 +86,9 @@ wp_table.ensure_work_package_not_listed!(work_package_false, work_package_without, work_package_other_type) wp_table.expect_work_package_listed(work_package_true) - wp_table.save_as("Saved query") + wp_table.save_as('Saved query') - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') # Revisit query wp_table.visit_query Query.last diff --git a/spec/features/work_packages/table/queries/date_is_empty_filter_spec.rb b/spec/features/work_packages/table/queries/date_is_empty_filter_spec.rb index f48f5791ae75..af506d41aae5 100644 --- a/spec/features/work_packages/table/queries/date_is_empty_filter_spec.rb +++ b/spec/features/work_packages/table/queries/date_is_empty_filter_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe 'Filter by date with "is empty"', :js, :with_cuprite do let(:user) { create(:admin) } @@ -62,7 +62,7 @@ let(:custom_field_date) do create(:date_wp_custom_field, - name: "Date CF", + name: 'Date CF', is_filter: true, searchable: true) do |custom_field| project.work_package_custom_fields << custom_field @@ -79,7 +79,7 @@ def remove_default wp_table.expect_work_package_listed work_package_without_dates, work_package_with_start_date, work_package_with_custom_date filters.open - filters.remove_filter("status") + filters.remove_filter('status') end before do @@ -93,19 +93,19 @@ def remove_default wp_table.visit! end - it "works as intended for regular fields" do + it 'works as intended for regular fields' do remove_default - filters.add_filter_by("Start date", "is empty", nil, "startDate") + filters.add_filter_by('Start date', 'is empty', nil, 'startDate') wp_table.expect_work_package_listed work_package_without_dates wp_table.ensure_work_package_not_listed! work_package_with_start_date end - it "works as intended for custom fields" do + it 'works as intended for custom fields' do remove_default - filters.add_filter_by("Date CF", "is empty", nil, "customField#{custom_field_date.id}") + filters.add_filter_by('Date CF', 'is empty', nil, "customField#{custom_field_date.id}") wp_table.expect_work_package_listed work_package_without_dates wp_table.ensure_work_package_not_listed! work_package_with_custom_date diff --git a/spec/features/work_packages/table/queries/default_queries_spec.rb b/spec/features/work_packages/table/queries/default_queries_spec.rb index a8a04348ce4b..f2e3053bf8e6 100644 --- a/spec/features/work_packages/table/queries/default_queries_spec.rb +++ b/spec/features/work_packages/table/queries/default_queries_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Default work package queries", :js do +RSpec.describe 'Default work package queries', :js do create_shared_association_defaults_for_work_package_factory shared_let(:user) { create(:admin) } @@ -36,21 +36,21 @@ let(:wp_table) { Pages::WorkPackagesTable.new(project_with_types) } - describe "Overdue" do - let!(:work_package) { create(:work_package, subject: "Not overdue", due_date: 5.days.from_now) } - let!(:due_today_work_package) { create(:work_package, subject: "Not overdue", due_date: Time.zone.today) } - let!(:overdue_work_package_1_day_ago) { create(:work_package, subject: "Overdue 1 day ago", due_date: 1.day.ago) } - let!(:overdue_work_package_2_days_ago) { create(:work_package, subject: "Overdue 2 days ago", due_date: 2.days.ago) } + describe 'Overdue' do + let!(:work_package) { create(:work_package, subject: 'Not overdue', due_date: 5.days.from_now) } + let!(:due_today_work_package) { create(:work_package, subject: 'Not overdue', due_date: Time.zone.today) } + let!(:overdue_work_package_1_day_ago) { create(:work_package, subject: 'Overdue 1 day ago', due_date: 1.day.ago) } + let!(:overdue_work_package_2_days_ago) { create(:work_package, subject: 'Overdue 2 days ago', due_date: 2.days.ago) } let!(:closed_status) { create(:closed_status) } - let!(:closed_work_package) { create(:work_package, subject: "Closed", status: closed_status, due_date: 10.days.ago) } + let!(:closed_work_package) { create(:work_package, subject: 'Closed', status: closed_status, due_date: 10.days.ago) } - it "shows the overdue work package" do + it 'shows the overdue work package' do wp_table.visit! wp_table.expect_work_package_listed work_package, due_today_work_package, overdue_work_package_1_day_ago, overdue_work_package_2_days_ago - click_link "Overdue", wait: 10 + click_link 'Overdue', wait: 10 wp_table.expect_work_package_listed overdue_work_package_1_day_ago, overdue_work_package_2_days_ago wp_table.ensure_work_package_not_listed! closed_work_package, work_package, due_today_work_package diff --git a/spec/features/work_packages/table/queries/filter_pagination_spec.rb b/spec/features/work_packages/table/queries/filter_pagination_spec.rb index 54b34bc954d3..124acc8f64a3 100644 --- a/spec/features/work_packages/table/queries/filter_pagination_spec.rb +++ b/spec/features/work_packages/table/queries/filter_pagination_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Filter updates pagination", :js do +RSpec.describe 'Filter updates pagination', :js do let(:user) do create(:user, member_with_permissions: { project => %i[view_work_packages] }) @@ -44,7 +44,7 @@ let(:work_package_2) { create(:work_package, project:) } before do - allow(Setting).to receive(:per_page_options).and_return "1" + allow(Setting).to receive(:per_page_options).and_return '1' work_package_1 work_package_2 @@ -53,34 +53,34 @@ wp_table.visit! end - it "resets page to 1 if changing filter" do + it 'resets page to 1 if changing filter' do wp_table.expect_work_package_listed work_package_1 wp_table.ensure_work_package_not_listed! work_package_2 # Expect pagination to be correct - expect(page).to have_css(".op-pagination--item_current", text: "1") + expect(page).to have_css('.op-pagination--item_current', text: '1') # Go to second page - within(".op-pagination--pages") do - find(".op-pagination--item button", text: "2").click + within('.op-pagination--pages') do + find('.op-pagination--item button', text: '2').click end wp_table.expect_work_package_listed work_package_2 wp_table.ensure_work_package_not_listed! work_package_1 # Expect pagination to be correct - expect(page).to have_css(".op-pagination--item_current", text: "2") + expect(page).to have_css('.op-pagination--item_current', text: '2') # Change filter to assigned to filters.expect_filter_count 1 filters.open - filters.add_filter_by "Assignee", "is (OR)", user.name + filters.add_filter_by 'Assignee', 'is (OR)', user.name filters.expect_filter_count 2 wp_table.expect_work_package_listed work_package_1 wp_table.ensure_work_package_not_listed! work_package_2 # Expect pagination to be back to 1 - expect(page).to have_css(".op-pagination--range", text: "1 - 1/1") + expect(page).to have_css('.op-pagination--range', text: '1 - 1/1') end end diff --git a/spec/features/work_packages/table/queries/filter_spec.rb b/spec/features/work_packages/table/queries/filter_spec.rb index 5627aadac993..22c0155c451d 100644 --- a/spec/features/work_packages/table/queries/filter_spec.rb +++ b/spec/features/work_packages/table/queries/filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "filter work packages", :js do - shared_let(:user) { create(:admin, preferences: { time_zone: "Etc/UTC" }) } +RSpec.describe 'filter work packages', :js do + shared_let(:user) { create(:admin, preferences: { time_zone: 'Etc/UTC' }) } shared_let(:watcher) { create(:user) } shared_let(:role) { create(:existing_project_role, permissions: [:view_work_packages]) } shared_let(:project) { create(:project, members: { watcher => role }) } @@ -38,7 +38,7 @@ current_user { user } - context "by watchers" do + context 'by watchers' do let(:work_package_with_watcher) do wp = build(:work_package, project:) wp.add_watcher watcher @@ -56,11 +56,11 @@ end # Regression test for bug #24114 (broken watcher filter) - it "onlies filter work packages by watcher" do + it 'onlies filter work packages by watcher' do filters.open loading_indicator_saveguard - filters.add_filter_by "Watcher", "is (OR)", watcher.name + filters.add_filter_by 'Watcher', 'is (OR)', watcher.name loading_indicator_saveguard wp_table.expect_work_package_listed work_package_with_watcher @@ -68,12 +68,12 @@ end end - context "by version in project" do + context 'by version in project' do let(:version) { create(:version, project:) } let(:work_package_with_version) do - create(:work_package, project:, subject: "With version", version:) + create(:work_package, project:, subject: 'With version', version:) end - let(:work_package_without_version) { create(:work_package, subject: "Without version", project:) } + let(:work_package_without_version) { create(:work_package, subject: 'Without version', project:) } before do work_package_with_version @@ -82,18 +82,18 @@ wp_table.visit! end - it "allows filtering, saving, retrieving and altering the saved filter" do + it 'allows filtering, saving, retrieving and altering the saved filter' do filters.open - filters.add_filter_by("Version", "is (OR)", version.name) + filters.add_filter_by('Version', 'is (OR)', version.name) loading_indicator_saveguard wp_table.expect_work_package_listed work_package_with_version wp_table.ensure_work_package_not_listed! work_package_without_version - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') - filters.remove_filter "version" + filters.remove_filter 'version' loading_indicator_saveguard wp_table.expect_work_package_listed work_package_with_version, work_package_without_version @@ -108,9 +108,9 @@ filters.open - filters.expect_filter_by("Version", "is (OR)", version.name) + filters.expect_filter_by('Version', 'is (OR)', version.name) - filters.set_operator "Version", "is not" + filters.set_operator 'Version', 'is not' loading_indicator_saveguard wp_table.expect_work_package_listed work_package_without_version @@ -118,13 +118,13 @@ end end - context "when filtering by status in project" do - let(:status) { create(:status, name: "Open status") } - let(:closed_status) { create(:closed_status, name: "Closed status") } + context 'when filtering by status in project' do + let(:status) { create(:status, name: 'Open status') } + let(:closed_status) { create(:closed_status, name: 'Closed status') } let(:work_package_with_status) do - create(:work_package, project:, subject: "With open status", status:) + create(:work_package, project:, subject: 'With open status', status:) end - let(:work_package_without_status) { create(:work_package, subject: "With closed status", project:, status: closed_status) } + let(:work_package_without_status) { create(:work_package, subject: 'With closed status', project:, status: closed_status) } before do work_package_with_status @@ -133,12 +133,12 @@ wp_table.visit! end - it "allows filtering and matching the selected value" do + it 'allows filtering and matching the selected value' do filters.open filters.remove_filter :status filters.expect_no_filter_by :status - filters.add_filter_by("Status", "is (OR)", status.name) + filters.add_filter_by('Status', 'is (OR)', status.name) loading_indicator_saveguard wp_table.expect_work_package_listed work_package_with_status @@ -146,12 +146,12 @@ filters.open_autocompleter :status - expect(page).to have_css(".ng-option", text: closed_status.name) - expect(page).to have_no_css(".ng-option", text: status.name) + expect(page).to have_css('.ng-option', text: closed_status.name) + expect(page).to have_no_css('.ng-option', text: status.name) end end - context "by finish date outside of a project" do + context 'by finish date outside of a project' do let(:work_package_with_due_date) { create(:work_package, project:, due_date: Date.current) } let(:work_package_without_due_date) { create(:work_package, project:, due_date: 5.days.from_now) } let(:wp_table) { Pages::WorkPackagesTable.new } @@ -163,21 +163,21 @@ wp_table.visit! end - it "allows filtering, saving and retrieving and altering the saved filter" do + it 'allows filtering, saving and retrieving and altering the saved filter' do filters.open - filters.add_filter_by("Finish date", - "between", - [1.day.ago.strftime("%Y-%m-%d"), Date.current.strftime("%Y-%m-%d")], - "dueDate") + filters.add_filter_by('Finish date', + 'between', + [1.day.ago.strftime('%Y-%m-%d'), Date.current.strftime('%Y-%m-%d')], + 'dueDate') loading_indicator_saveguard wp_table.expect_work_package_listed work_package_with_due_date wp_table.ensure_work_package_not_listed! work_package_without_due_date - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') - filters.remove_filter "dueDate" + filters.remove_filter 'dueDate' loading_indicator_saveguard wp_table.expect_work_package_listed work_package_with_due_date, work_package_without_due_date @@ -192,12 +192,12 @@ filters.open - filters.expect_filter_by("Finish date", - "between", - [1.day.ago.strftime("%Y-%m-%d"), Date.current.strftime("%Y-%m-%d")], - "dueDate") + filters.expect_filter_by('Finish date', + 'between', + [1.day.ago.strftime('%Y-%m-%d'), Date.current.strftime('%Y-%m-%d')], + 'dueDate') - filters.set_filter "Finish date", "in more than", "1", "dueDate" + filters.set_filter 'Finish date', 'in more than', '1', 'dueDate' loading_indicator_saveguard wp_table.expect_work_package_listed work_package_without_due_date @@ -205,7 +205,7 @@ end end - context "by list cf inside a project" do + context 'by list cf inside a project' do let(:type) do type = create(:type) @@ -245,13 +245,13 @@ wp_table.visit! end - it "allows filtering, saving and retrieving the saved filter" do + it 'allows filtering, saving and retrieving the saved filter' do # Wait for form to load filters.expect_loaded filters.open filters.add_filter_by(list_cf.name, - "is not", + 'is not', list_cf.custom_options.last.value, list_cf.attribute_name(:camel_case)) @@ -262,9 +262,9 @@ # Do not display already selected values in the autocompleter (Regression #46249) filters.open_autocompleter list_cf.attribute_name(:camel_case) - expect(page).to have_no_css(".ng-option", text: list_cf.custom_options.last.value) + expect(page).to have_no_css('.ng-option', text: list_cf.custom_options.last.value) - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') filters.remove_filter list_cf.attribute_name(:camel_case) @@ -282,13 +282,13 @@ filters.open filters.expect_filter_by(list_cf.name, - "is not", + 'is not', list_cf.custom_options.last.value, "customField#{list_cf.id}") end end - context "by string cf inside a project with url-query relevant chars" do + context 'by string cf inside a project with url-query relevant chars' do let(:type) do type = create(:type) @@ -299,14 +299,14 @@ let(:work_package_plus) do wp = create(:work_package, project:, type:) - wp.send(string_cf.attribute_setter, "G+H") + wp.send(string_cf.attribute_setter, 'G+H') wp.save! wp end let(:work_package_and) do wp = create(:work_package, project:, type:) - wp.send(string_cf.attribute_setter, "A&B") + wp.send(string_cf.attribute_setter, 'A&B') wp.save! wp end @@ -328,21 +328,21 @@ wp_table.visit! end - it "allows filtering, saving and retrieving the saved filter" do + it 'allows filtering, saving and retrieving the saved filter' do # Wait for form to load filters.expect_loaded filters.open filters.add_filter_by(string_cf.name, - "is", - ["G+H"], + 'is', + ['G+H'], string_cf.attribute_name(:camel_case)) loading_indicator_saveguard wp_table.expect_work_package_listed work_package_plus wp_table.ensure_work_package_not_listed! work_package_and - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') filters.remove_filter string_cf.attribute_name(:camel_case) @@ -360,13 +360,13 @@ filters.open filters.expect_filter_by(string_cf.name, - "is", - ["G+H"], + 'is', + ['G+H'], "customField#{string_cf.id}") filters.set_filter(string_cf, - "is", - ["A&B"], + 'is', + ['A&B'], string_cf.attribute_name(:camel_case)) loading_indicator_saveguard @@ -375,104 +375,104 @@ end end - context "by attachment content" do - let(:attachment_a) { build(:attachment, filename: "attachment-first.pdf") } - let(:attachment_b) { build(:attachment, filename: "attachment-second.pdf") } + context 'by attachment content' do + let(:attachment_a) { build(:attachment, filename: 'attachment-first.pdf') } + let(:attachment_b) { build(:attachment, filename: 'attachment-second.pdf') } let(:wp_with_attachment_a) do - create(:work_package, subject: "WP attachment A", project:, attachments: [attachment_a]) + create(:work_package, subject: 'WP attachment A', project:, attachments: [attachment_a]) end let(:wp_with_attachment_b) do - create(:work_package, subject: "WP attachment B", project:, attachments: [attachment_b]) + create(:work_package, subject: 'WP attachment B', project:, attachments: [attachment_b]) end - let(:wp_without_attachment) { create(:work_package, subject: "WP no attachment", project:) } + let(:wp_without_attachment) { create(:work_package, subject: 'WP no attachment', project:) } let(:wp_table) { Pages::WorkPackagesTable.new } before do - allow_any_instance_of(Plaintext::Resolver).to receive(:text).and_return("I am the first text $1.99.") + allow_any_instance_of(Plaintext::Resolver).to receive(:text).and_return('I am the first text $1.99.') wp_with_attachment_a Attachments::ExtractFulltextJob.perform_now(attachment_a.id) - allow_any_instance_of(Plaintext::Resolver).to receive(:text).and_return("I am the second text.") + allow_any_instance_of(Plaintext::Resolver).to receive(:text).and_return('I am the second text.') wp_with_attachment_b Attachments::ExtractFulltextJob.perform_now(attachment_b.id) wp_without_attachment end - context "with full text search capabilities" do + context 'with full text search capabilities' do before do skip("Database does not support full text search.") unless OpenProject::Database::allows_tsv? end - it "allows filtering and retrieving and altering the saved filter" do + it 'allows filtering and retrieving and altering the saved filter' do wp_table.visit! wp_table.expect_work_package_listed wp_with_attachment_a, wp_with_attachment_b filters.open # content contains with multiple hits - filters.add_filter_by("Attachment content", - "contains", - ["text"], - "attachmentContent") + filters.add_filter_by('Attachment content', + 'contains', + ['text'], + 'attachmentContent') loading_indicator_saveguard wp_table.expect_work_package_listed wp_with_attachment_a, wp_with_attachment_b wp_table.ensure_work_package_not_listed! wp_without_attachment # content contains single hit with numbers - filters.remove_filter "attachmentContent" + filters.remove_filter 'attachmentContent' - filters.add_filter_by("Attachment content", - "contains", - ["first 1.99"], - "attachmentContent") + filters.add_filter_by('Attachment content', + 'contains', + ['first 1.99'], + 'attachmentContent') loading_indicator_saveguard wp_table.expect_work_package_listed wp_with_attachment_a wp_table.ensure_work_package_not_listed! wp_without_attachment, wp_with_attachment_b - filters.remove_filter "attachmentContent" + filters.remove_filter 'attachmentContent' # content does not contain - filters.add_filter_by("Attachment content", - "doesn't contain", - ["first"], - "attachmentContent") + filters.add_filter_by('Attachment content', + 'doesn\'t contain', + ['first'], + 'attachmentContent') loading_indicator_saveguard wp_table.expect_work_package_listed wp_with_attachment_b, wp_without_attachment wp_table.ensure_work_package_not_listed! wp_with_attachment_a - filters.remove_filter "attachmentContent" + filters.remove_filter 'attachmentContent' # ignores special characters - filters.add_filter_by("Attachment content", - "contains", - ["! first:* ')"], - "attachmentContent") + filters.add_filter_by('Attachment content', + 'contains', + ['! first:* \')'], + 'attachmentContent') loading_indicator_saveguard wp_table.expect_work_package_listed wp_with_attachment_a wp_table.ensure_work_package_not_listed! wp_without_attachment, wp_with_attachment_b - filters.remove_filter "attachmentContent" + filters.remove_filter 'attachmentContent' # file name contains - filters.add_filter_by("Attachment file name", - "contains", - ["first"], - "attachmentFileName") + filters.add_filter_by('Attachment file name', + 'contains', + ['first'], + 'attachmentFileName') loading_indicator_saveguard wp_table.expect_work_package_listed wp_with_attachment_a wp_table.ensure_work_package_not_listed! wp_without_attachment, wp_with_attachment_b - filters.remove_filter "attachmentFileName" + filters.remove_filter 'attachmentFileName' # file name does not contain - filters.add_filter_by("Attachment file name", - "doesn't contain", - ["first"], - "attachmentFileName") + filters.add_filter_by('Attachment file name', + 'doesn\'t contain', + ['first'], + 'attachmentFileName') loading_indicator_saveguard wp_table.expect_work_package_listed wp_with_attachment_b @@ -481,50 +481,50 @@ end end - context "DB does not offer TSVector support" do + context 'DB does not offer TSVector support' do before do allow(OpenProject::Database).to receive(:allows_tsv?).and_return(false) end it "does not offer attachment filters" do - expect(page).to have_no_select "add_filter_select", with_options: ["Attachment content", "Attachment file name"] + expect(page).to have_no_select 'add_filter_select', with_options: ['Attachment content', 'Attachment file name'] end end - describe "datetime filters" do + describe 'datetime filters' do shared_let(:wp_updated_today) do create(:work_package, - subject: "Created today", + subject: 'Created today', project:, created_at: Time.current.change(hour: 12), updated_at: Time.current.change(hour: 12)) end shared_let(:wp_updated_3d_ago) do create(:work_package, - subject: "Created 3d ago", + subject: 'Created 3d ago', project:, created_at: 3.days.ago, updated_at: 3.days.ago) end shared_let(:wp_updated_5d_ago) do create(:work_package, - subject: "Created 5d ago", + subject: 'Created 5d ago', project:, created_at: 5.days.ago, updated_at: 5.days.ago) end - it "filters on date by created_at (Regression #28459)" do + it 'filters on date by created_at (Regression #28459)' do wp_table.visit! loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago filters.open - filters.add_filter_by "Created on", - "on", + filters.add_filter_by 'Created on', + 'on', [Date.current.iso8601], - "createdAt" + 'createdAt' loading_indicator_saveguard @@ -532,17 +532,17 @@ wp_table.ensure_work_package_not_listed! wp_updated_3d_ago, wp_updated_5d_ago end - it "filters on date by updated_at" do + it 'filters on date by updated_at' do wp_table.visit! loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago filters.open - filters.add_filter_by "Updated", - "on", + filters.add_filter_by 'Updated', + 'on', [Date.current.iso8601], - "updatedAt" + 'updatedAt' loading_indicator_saveguard @@ -550,17 +550,17 @@ wp_table.ensure_work_package_not_listed! wp_updated_3d_ago, wp_updated_5d_ago end - it "filters between date by updated_at", :with_cuprite do + it 'filters between date by updated_at', :with_cuprite do wp_table.visit! loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago filters.open - filters.add_filter_by "Updated", - "between", + filters.add_filter_by 'Updated', + 'between', [4.days.ago.to_date.iso8601, 2.days.ago.to_date.iso8601], - "updatedAt" + 'updatedAt' wait_for_reload loading_indicator_saveguard @@ -568,15 +568,15 @@ wp_table.expect_work_package_listed wp_updated_3d_ago wp_table.ensure_work_package_not_listed! wp_updated_today, wp_updated_5d_ago - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') - filters.remove_filter "updatedAt" + filters.remove_filter 'updatedAt' wait_for_reload loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago - last_query = Query.where(name: "Some query name").first + last_query = Query.where(name: 'Some query name').first date_filter = last_query.filters.last # The frontend sends the date as a datetime string in utc where both bounds have the local offset deduced @@ -594,45 +594,45 @@ filters.open - filters.expect_filter_by "Updated on", - "between", + filters.expect_filter_by 'Updated on', + 'between', [4.days.ago.to_date.iso8601, 2.days.ago.to_date.iso8601], - "updatedAt" + 'updatedAt' end - it "filters between date by updated_at (lower boundary only)" do + it 'filters between date by updated_at (lower boundary only)' do wp_table.visit! loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago filters.open - filters.add_filter_by "Updated", - "between", + filters.add_filter_by 'Updated', + 'between', [3.days.ago.to_date.iso8601], - "updatedAt" + 'updatedAt' loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_3d_ago, wp_updated_today wp_table.ensure_work_package_not_listed! wp_updated_5d_ago - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') - filters.remove_filter "updatedAt" + filters.remove_filter 'updatedAt' loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_5d_ago - filters.add_filter_by "Updated", - "between", + filters.add_filter_by 'Updated', + 'between', [6.days.ago.to_date.iso8601], - "updatedAt" + 'updatedAt' loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago - last_query = Query.where(name: "Some query name").first + last_query = Query.where(name: 'Some query name').first date_filter = last_query.filters.last expect(date_filter.values) .to eq [3.days.ago.utc.beginning_of_day.iso8601] @@ -645,48 +645,48 @@ filters.open - filters.expect_filter_by "Updated on", - "between", - [3.days.ago.to_date.iso8601, ""], - "updatedAt" + filters.expect_filter_by 'Updated on', + 'between', + [3.days.ago.to_date.iso8601, ''], + 'updatedAt' end - it "filters between date by updated_at (upper boundary only)" do + it 'filters between date by updated_at (upper boundary only)' do wp_table.visit! loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago filters.open - filters.add_filter_by "Updated", - "between", + filters.add_filter_by 'Updated', + 'between', [nil, 4.days.ago.to_date.iso8601], - "updatedAt" + 'updatedAt' loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_5d_ago wp_table.ensure_work_package_not_listed! wp_updated_3d_ago, wp_updated_today - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') - filters.remove_filter "updatedAt" + filters.remove_filter 'updatedAt' loading_indicator_saveguard wp_table.expect_work_package_listed wp_updated_today, wp_updated_3d_ago, wp_updated_5d_ago - filters.add_filter_by "Updated", - "between", + filters.add_filter_by 'Updated', + 'between', [nil, 6.days.ago.to_date.iso8601], - "updatedAt" + 'updatedAt' loading_indicator_saveguard wp_table.ensure_work_package_not_listed! wp_updated_5d_ago, wp_updated_3d_ago, wp_updated_today - last_query = Query.where(name: "Some query name").first + last_query = Query.where(name: 'Some query name').first date_filter = last_query.filters.last expect(date_filter.values) - .to eq ["", 4.days.ago.utc.end_of_day.iso8601] + .to eq ['', 4.days.ago.utc.end_of_day.iso8601] wp_table.visit_query(last_query) @@ -696,40 +696,40 @@ filters.open - filters.expect_filter_by "Updated on", - "between", - ["", 4.days.ago.to_date.iso8601], - "updatedAt" + filters.expect_filter_by 'Updated on', + 'between', + ['', 4.days.ago.to_date.iso8601], + 'updatedAt' end end - describe "keep the filter attribute order (Regression #33136)" do - let(:version1) { create(:version, project:, name: "Version 1", id: 1) } - let(:version2) { create(:version, project:, name: "Version 2", id: 2) } + describe 'keep the filter attribute order (Regression #33136)' do + let(:version1) { create(:version, project:, name: 'Version 1', id: 1) } + let(:version2) { create(:version, project:, name: 'Version 2', id: 2) } it do wp_table.visit! loading_indicator_saveguard filters.open - filters.add_filter_by "Version", "is (OR)", [version2.name, version1.name] + filters.add_filter_by 'Version', 'is (OR)', [version2.name, version1.name] loading_indicator_saveguard sleep(3) - filters.expect_filter_by "Version", "is (OR)", [version1.name] - filters.expect_filter_by "Version", "is (OR)", [version2.name] + filters.expect_filter_by 'Version', 'is (OR)', [version1.name] + filters.expect_filter_by 'Version', 'is (OR)', [version2.name] # Order should stay unchanged - filters.expect_filter_order("Version", [version2.name, version1.name]) + filters.expect_filter_order('Version', [version2.name, version1.name]) end end - describe "add parent WP filter" do - let(:wp_parent) { create(:work_package, project:, subject: "project") } - let(:wp_child1) { create(:work_package, project:, subject: "child 1", parent: wp_parent) } - let(:wp_child2) { create(:work_package, project:, subject: "child 2", parent: wp_parent) } - let(:wp_default) { create(:work_package, project:, subject: "default") } + describe 'add parent WP filter' do + let(:wp_parent) { create(:work_package, project:, subject: 'project') } + let(:wp_child1) { create(:work_package, project:, subject: 'child 1', parent: wp_parent) } + let(:wp_child2) { create(:work_package, project:, subject: 'child 2', parent: wp_parent) } + let(:wp_default) { create(:work_package, project:, subject: 'default') } it do wp_parent @@ -740,7 +740,7 @@ loading_indicator_saveguard filters.expect_loaded filters.open - filters.add_filter_by "Parent", "is (OR)", [wp_parent.subject] + filters.add_filter_by 'Parent', 'is (OR)', [wp_parent.subject] loading_indicator_saveguard # It should show the children of the selected parent diff --git a/spec/features/work_packages/table/queries/id_filter_spec.rb b/spec/features/work_packages/table/queries/id_filter_spec.rb index 9700543ab4f1..ad5681f0c910 100644 --- a/spec/features/work_packages/table/queries/id_filter_spec.rb +++ b/spec/features/work_packages/table/queries/id_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering by id", :js do +RSpec.describe 'Work package filtering by id', :js do let(:project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:filters) { Components::WorkPackages::Filters.new } @@ -52,16 +52,16 @@ wp_table.expect_work_package_listed(work_package, other_work_package) filters.open - filters.add_filter_by("ID", "is (OR)", [work_package.subject]) + filters.add_filter_by('ID', 'is (OR)', [work_package.subject]) end - it "shows the work package matching the id filter" do + it 'shows the work package matching the id filter' do wp_table.ensure_work_package_not_listed!(other_work_package) wp_table.expect_work_package_listed(work_package) - wp_table.save_as("Id query") + wp_table.save_as('Id query') - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') # Revisit query wp_table.visit_query Query.last @@ -69,23 +69,23 @@ wp_table.expect_work_package_listed(work_package) filters.open - filters.expect_filter_by("ID", "is (OR)", ["##{work_package.id} #{work_package.subject}"]) - filters.remove_filter "id" - filters.add_filter_by("ID", "is not", [work_package.subject, other_work_package.subject]) + filters.expect_filter_by('ID', 'is (OR)', ["##{work_package.id} #{work_package.subject}"]) + filters.remove_filter 'id' + filters.add_filter_by('ID', 'is not', [work_package.subject, other_work_package.subject]) wp_table.expect_no_work_package_listed - filters.remove_filter "id" - filters.add_filter_by("ID", "is (OR)", [work_package.id.to_s]) - filters.expect_filter_by("ID", "is (OR)", ["##{work_package.id} #{work_package.subject}"]) + filters.remove_filter 'id' + filters.add_filter_by('ID', 'is (OR)', [work_package.id.to_s]) + filters.expect_filter_by('ID', 'is (OR)', ["##{work_package.id} #{work_package.subject}"]) wp_table.expect_work_package_listed(work_package) end - it "can still inline create a new work package (regression #41667)" do + it 'can still inline create a new work package (regression #41667)' do wp_table.click_inline_create - expect(page).to have_css(".wp--row", count: 2) + expect(page).to have_css('.wp--row', count: 2) - expect(page).to have_css(".wp-inline-create-row") + expect(page).to have_css('.wp-inline-create-row') end end diff --git a/spec/features/work_packages/table/queries/me_filter_spec.rb b/spec/features/work_packages/table/queries/me_filter_spec.rb index d6f3a5f732c3..4bf194817541 100644 --- a/spec/features/work_packages/table/queries/me_filter_spec.rb +++ b/spec/features/work_packages/table/queries/me_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "filter me value", :js do +RSpec.describe 'filter me value', :js do let(:status) { create(:default_status) } let!(:priority) { create(:default_priority) } let(:project) do @@ -49,33 +49,33 @@ end let!(:role_anonymous) { create(:anonymous_role, permissions: [:view_work_packages]) } - describe "assignee" do + describe 'assignee' do let(:wp_admin) { create(:work_package, status:, project:, assigned_to: admin) } let(:wp_user) { create(:work_package, status:, project:, assigned_to: user) } - context "as anonymous", with_settings: { login_required?: false } do + context 'as anonymous', with_settings: { login_required?: false } do current_user { User.anonymous } let(:assignee_query) do query = create(:query, - name: "Assignee Query", + name: 'Assignee Query', project:, user:) - query.add_filter("assigned_to_id", "=", ["me"]) + query.add_filter('assigned_to_id', '=', ['me']) query.save!(validate: false) query end - it "shows an error visiting a query with a me value" do + it 'shows an error visiting a query with a me value' do wp_table.visit_query assignee_query wp_table.expect_toast(type: :error, - message: I18n.t("js.work_packages.faulty_query.description")) + message: I18n.t('js.work_packages.faulty_query.description')) end end - context "logged in" do + context 'logged in' do current_user { admin } before do @@ -83,26 +83,26 @@ wp_user end - it "shows the one work package filtering for myself" do + it 'shows the one work package filtering for myself' do wp_table.visit! wp_table.expect_work_package_listed(wp_admin, wp_user) # Add and save query with me filter filters.open - filters.remove_filter "status" - filters.add_filter_by("Assignee", "is (OR)", "me") + filters.remove_filter 'status' + filters.add_filter_by('Assignee', 'is (OR)', 'me') wp_table.ensure_work_package_not_listed!(wp_user) wp_table.expect_work_package_listed(wp_admin) - wp_table.save_as("Me query") + wp_table.save_as('Me query') loading_indicator_saveguard # Expect correct while saving - wp_table.expect_title "Me query" + wp_table.expect_title 'Me query' query = Query.last - expect(query.filters.first.values).to eq ["me"] - filters.expect_filter_by("Assignee", "is (OR)", "me") + expect(query.filters.first.values).to eq ['me'] + filters.expect_filter_by('Assignee', 'is (OR)', 'me') # Revisit query wp_table.visit_query query @@ -110,7 +110,7 @@ wp_table.expect_work_package_listed(wp_admin) filters.open - filters.expect_filter_by("Assignee", "is (OR)", "me") + filters.expect_filter_by('Assignee', 'is (OR)', 'me') # Expect new work packages receive assignee split_screen = wp_table.create_wp_by_button wp_user.type @@ -119,10 +119,10 @@ sleep 2 subject = split_screen.edit_field :subject - subject.set_value "foobar" + subject.set_value 'foobar' subject.submit_by_enter - split_screen.expect_and_dismiss_toaster message: "Successful creation." + split_screen.expect_and_dismiss_toaster message: 'Successful creation.' wp = WorkPackage.last expect(wp.assigned_to_id).to eq(admin.id) @@ -130,11 +130,11 @@ end end - describe "custom_field of type user" do + describe 'custom_field of type user' do let(:custom_field) do create( :user_wp_custom_field, - name: "CF user", + name: 'CF user', is_required: false ) end @@ -163,14 +163,14 @@ custom_field_values: { custom_field.id => user.id }) end - context "as anonymous", with_settings: { login_required?: false } do + context 'as anonymous', with_settings: { login_required?: false } do let(:assignee_query) do query = create(:query, - name: "CF user Query", + name: 'CF user Query', project:, user:) - query.add_filter(cf_accessor, "=", ["me"]) + query.add_filter(cf_accessor, '=', ['me']) query.save!(validate: false) query @@ -178,14 +178,14 @@ current_user { User.anonymous } - it "shows an error visiting a query with a me value" do + it 'shows an error visiting a query with a me value' do wp_table.visit_query assignee_query wp_table.expect_toast(type: :error, - message: I18n.t("js.work_packages.faulty_query.description")) + message: I18n.t('js.work_packages.faulty_query.description')) end end - context "logged in" do + context 'logged in' do current_user { admin } before do @@ -193,26 +193,26 @@ wp_user end - it "shows the one work package filtering for myself" do + it 'shows the one work package filtering for myself' do wp_table.visit! wp_table.expect_work_package_listed(wp_admin, wp_user) # Add and save query with me filter filters.open - filters.remove_filter "status" - filters.add_filter_by("CF user", "is (OR)", "me", cf_accessor_frontend) + filters.remove_filter 'status' + filters.add_filter_by('CF user', 'is (OR)', 'me', cf_accessor_frontend) wp_table.ensure_work_package_not_listed!(wp_user) wp_table.expect_work_package_listed(wp_admin) - wp_table.save_as("Me query") + wp_table.save_as('Me query') loading_indicator_saveguard # Expect correct while saving - wp_table.expect_title "Me query" + wp_table.expect_title 'Me query' query = Query.last - expect(query.filters.first.values).to eq ["me"] - filters.expect_filter_by("CF user", "is (OR)", "me", cf_accessor_frontend) + expect(query.filters.first.values).to eq ['me'] + filters.expect_filter_by('CF user', 'is (OR)', 'me', cf_accessor_frontend) # Revisit query wp_table.visit_query query @@ -220,7 +220,7 @@ wp_table.expect_work_package_listed(wp_admin) filters.open - filters.expect_filter_by("CF user", "is (OR)", "me", cf_accessor_frontend) + filters.expect_filter_by('CF user', 'is (OR)', 'me', cf_accessor_frontend) end end end diff --git a/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb b/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb index f713d338d13a..9d44493d1c24 100644 --- a/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb +++ b/spec/features/work_packages/table/queries/mobile_date_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "mobile date filter work packages", :js, :with_cuprite do +RSpec.describe 'mobile date filter work packages', :js, :with_cuprite do shared_let(:user) { create(:admin) } shared_let(:project) { create(:project) } shared_let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -39,20 +39,20 @@ current_user { user } - include_context "with mobile screen size" + include_context 'with mobile screen size' before do wp_table.visit! end - context "when filtering between finish date" do - it "allows filtering, saving and retrieving and altering the saved filter" do + context 'when filtering between finish date' do + it 'allows filtering, saving and retrieving and altering the saved filter' do filters.open - filters.add_filter("Finish date") - filters.set_operator("Finish date", "between", "dueDate") + filters.add_filter('Finish date') + filters.set_operator('Finish date', 'between', 'dueDate') - start_field = find_test_selector("op-basic-range-date-picker-start") - end_field = find_test_selector("op-basic-range-date-picker-end") + start_field = find_test_selector('op-basic-range-date-picker-start') + end_field = find_test_selector('op-basic-range-date-picker-end') clear_input_field_contents(start_field) clear_input_field_contents(end_field) @@ -69,8 +69,8 @@ wp_cards.expect_work_package_listed work_package_with_due_date wp_cards.expect_work_package_not_listed work_package_without_due_date - wp_table.save_as("Some query name") - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.save_as('Some query name') + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') last_query = Query.last date_filter = last_query.filters.last @@ -78,14 +78,14 @@ end end - context "when filtering on finish date" do - it "allows filtering, saving and retrieving and altering the saved filter" do + context 'when filtering on finish date' do + it 'allows filtering, saving and retrieving and altering the saved filter' do filters.open - filters.add_filter("Finish date") - filters.set_operator("Finish date", "on", "dueDate") + filters.add_filter('Finish date') + filters.set_operator('Finish date', 'on', 'dueDate') - date_field = find_field "values-dueDate" - expect(date_field["type"]).to eq "date" + date_field = find_field 'values-dueDate' + expect(date_field['type']).to eq 'date' clear_input_field_contents(date_field) date_field.set Date.current @@ -97,8 +97,8 @@ wp_cards.expect_work_package_listed work_package_with_due_date wp_cards.expect_work_package_not_listed work_package_without_due_date - wp_table.save_as("Some query name") - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.save_as('Some query name') + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') last_query = Query.last date_filter = last_query.filters.last diff --git a/spec/features/work_packages/table/queries/query_history_spec.rb b/spec/features/work_packages/table/queries/query_history_spec.rb index 43eb03f071f9..68aca098eac1 100644 --- a/spec/features/work_packages/table/queries/query_history_spec.rb +++ b/spec/features/work_packages/table/queries/query_history_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Going back and forth through the browser history", :js do +RSpec.describe 'Going back and forth through the browser history', :js do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -63,22 +63,22 @@ end let(:assignee_query) do query = create(:query, - name: "Assignee Query", + name: 'Assignee Query', project:, user:) - query.add_filter("assigned_to_id", "=", [user.id]) + query.add_filter('assigned_to_id', '=', [user.id]) query.save! query end let(:version_query) do query = create(:query, - name: "Version Query", + name: 'Version Query', project:, user:) - query.add_filter("version_id", "=", [version.id]) + query.add_filter('version_id', '=', [version.id]) query.save! query @@ -97,9 +97,9 @@ version_query end - it "updates the filters and query results on history back and forth", retry: 1 do + it 'updates the filters and query results on history back and forth', retry: 1 do wp_table.visit! - wp_table.expect_title("All open", editable: true) + wp_table.expect_title('All open', editable: true) wp_table.visit_query(assignee_query) wp_table.expect_title(assignee_query.name) @@ -110,58 +110,58 @@ wp_table.expect_work_package_listed work_package_3 filters.open - filters.add_filter_by("Assignee", "is (OR)", user.name) + filters.add_filter_by('Assignee', 'is (OR)', user.name) filters.expect_filter_count 3 wp_table.expect_no_work_package_listed - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') wp_table.expect_title(version_query.name) wp_table.expect_work_package_listed work_package_3 filters.expect_filter_count 2 - filters.expect_filter_by("Status", "open", nil) - filters.expect_filter_by("Version", "is (OR)", version.name) + filters.expect_filter_by('Status', 'open', nil) + filters.expect_filter_by('Version', 'is (OR)', version.name) - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') wp_table.expect_title(assignee_query.name) wp_table.expect_work_package_listed work_package_2 filters.open - filters.expect_filter_by("Status", "open", nil) - filters.expect_filter_by("Assignee", "is (OR)", user.name) + filters.expect_filter_by('Status', 'open', nil) + filters.expect_filter_by('Assignee', 'is (OR)', user.name) - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') - wp_table.expect_title("All open", editable: true) + wp_table.expect_title('All open', editable: true) wp_table.expect_work_package_listed work_package_1 wp_table.expect_work_package_listed work_package_2 wp_table.expect_work_package_listed work_package_3 filters.open - filters.expect_filter_by("Status", "open", nil) + filters.expect_filter_by('Status', 'open', nil) - page.execute_script("window.history.forward()") + page.execute_script('window.history.forward()') wp_table.expect_title(assignee_query.name) wp_table.expect_work_package_listed work_package_2 filters.open - filters.expect_filter_by("Status", "open", nil) - filters.expect_filter_by("Assignee", "is (OR)", user.name) + filters.expect_filter_by('Status', 'open', nil) + filters.expect_filter_by('Assignee', 'is (OR)', user.name) - page.execute_script("window.history.forward()") + page.execute_script('window.history.forward()') wp_table.expect_title(version_query.name) wp_table.expect_work_package_listed work_package_3 filters.open - filters.expect_filter_by("Status", "open", nil) - filters.expect_filter_by("Version", "is (OR)", version.name) + filters.expect_filter_by('Status', 'open', nil) + filters.expect_filter_by('Version', 'is (OR)', version.name) - page.execute_script("window.history.forward()") + page.execute_script('window.history.forward()') wp_table.expect_title(version_query.name) wp_table.expect_no_work_package_listed filters.open - filters.expect_filter_by("Status", "open", nil) - filters.expect_filter_by("Version", "is (OR)", version.name) - filters.expect_filter_by("Assignee", "is (OR)", user.name) + filters.expect_filter_by('Status', 'open', nil) + filters.expect_filter_by('Version', 'is (OR)', version.name) + filters.expect_filter_by('Assignee', 'is (OR)', user.name) end end diff --git a/spec/features/work_packages/table/queries/query_menu_refresh_spec.rb b/spec/features/work_packages/table/queries/query_menu_refresh_spec.rb index bccccfa2ad80..628cb1680b7b 100644 --- a/spec/features/work_packages/table/queries/query_menu_refresh_spec.rb +++ b/spec/features/work_packages/table/queries/query_menu_refresh_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Refreshing query menu item", :js do +RSpec.describe 'Refreshing query menu item', :js do let(:user) { create(:admin) } let(:project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -42,17 +42,17 @@ wp_table.visit! end - it "allows refreshing the current query (Bug #26921)" do + it 'allows refreshing the current query (Bug #26921)' do wp_table.expect_work_package_listed work_package # Instantiate lazy let here wp_table.ensure_work_package_not_listed! other_work_package - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') # Publish query - wp_table.click_setting_item I18n.t("js.toolbar.settings.visibility_settings") - find_by_id("show-in-menu").set true - find(".button", text: "Save").click + wp_table.click_setting_item I18n.t('js.toolbar.settings.visibility_settings') + find_by_id('show-in-menu').set true + find('.button', text: 'Save').click last_query = Query.last url = URI.parse(page.current_url).query diff --git a/spec/features/work_packages/table/queries/query_menu_spec.rb b/spec/features/work_packages/table/queries/query_menu_spec.rb index 542f6da8d910..32c64a99b021 100644 --- a/spec/features/work_packages/table/queries/query_menu_spec.rb +++ b/spec/features/work_packages/table/queries/query_menu_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Query menu item", :js do +RSpec.describe 'Query menu item', :js do let(:project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:filters) { Components::WorkPackages::Filters.new } @@ -36,36 +36,36 @@ current_user { create(:admin) } - context "when visiting the global work packages page" do + context 'when visiting the global work packages page' do let(:wp_table) { Pages::WorkPackagesTable.new } let(:project) { nil } let!(:global_public_view) do create(:view, - query: create(:query, project: nil, public: true, name: "Global public")) + query: create(:query, project: nil, public: true, name: 'Global public')) end let!(:global_my_view) do create(:view, - query: create(:query, project: nil, public: false, user: current_user, name: "Global my view")) + query: create(:query, project: nil, public: false, user: current_user, name: 'Global my view')) end let!(:global_other_view) do create(:view, - query: create(:query, project: nil, public: false, user: create(:user), name: "Other user query")) + query: create(:query, project: nil, public: false, user: create(:user), name: 'Other user query')) end let!(:project_view) do create(:view, - query: create(:query, project: create(:project), name: "Project query")) + query: create(:query, project: create(:project), name: 'Project query')) end - it "shows the query menu with queries stored for the global page" do + it 'shows the query menu with queries stored for the global page' do wp_table.visit! - expect(page).to have_css(".op-view-select--search-results") - expect(page).to have_css(".op-sidemenu--item-action", wait: 20, minimum: 1) + expect(page).to have_css('.op-view-select--search-results') + expect(page).to have_css('.op-sidemenu--item-action', wait: 20, minimum: 1) - within ".op-sidebar" do + within '.op-sidebar' do expect(page) .to have_content(global_my_view.query.name, wait: 10) expect(page) @@ -78,7 +78,7 @@ end end - context "when filtering by version in project" do + context 'when filtering by version in project' do let(:version) { create(:version, project:) } let(:work_package_with_version) { create(:work_package, project:, version:) } let(:work_package_without_version) { create(:work_package, project:) } @@ -90,46 +90,46 @@ wp_table.visit! end - it "allows to save query as name with sharing options (Regression #27915)" do + it 'allows to save query as name with sharing options (Regression #27915)' do # Publish query - wp_table.click_setting_item "Save as" + wp_table.click_setting_item 'Save as' - fill_in "save-query-name", with: "Some query name" - find_by_id("show-in-menu").set true - find_by_id("show-public").set true + fill_in 'save-query-name', with: 'Some query name' + find_by_id('show-in-menu').set true + find_by_id('show-public').set true - find(".button", text: "Save").click + find('.button', text: 'Save').click - expect(page).to have_css(".op-sidemenu--item-action", text: "Some query name", wait: 20) + expect(page).to have_css('.op-sidemenu--item-action', text: 'Some query name', wait: 20) last_query = Query.last expect(last_query.public).to be_truthy end - it "only saves a single query when saving through the title input (Regression #31095)" do + it 'only saves a single query when saving through the title input (Regression #31095)' do filters.open - filters.remove_filter("status") + filters.remove_filter('status') filters.expect_filter_count 0 query_title.expect_changed query_title.input_field.click - query_title.rename "My special query!123" + query_title.rename 'My special query!123' - query_title.expect_title "My special query!123" - expect(page).to have_css(".op-sidemenu--item-action", text: "My special query!123", wait: 20, count: 1) + query_title.expect_title 'My special query!123' + expect(page).to have_css('.op-sidemenu--item-action', text: 'My special query!123', wait: 20, count: 1) end - it "allows filtering, saving, retrieving and altering the saved filter (Regression #25372)" do + it 'allows filtering, saving, retrieving and altering the saved filter (Regression #25372)' do filters.open - filters.add_filter_by("Version", "is (OR)", version.name) + filters.add_filter_by('Version', 'is (OR)', version.name) wp_table.expect_work_package_listed work_package_with_version wp_table.ensure_work_package_not_listed! work_package_without_version - wp_table.save_as("Some query name") + wp_table.save_as('Some query name') - filters.remove_filter "version" + filters.remove_filter 'version' filters.expect_filter_count 1 wp_table.expect_work_package_listed work_package_with_version, work_package_without_version @@ -139,27 +139,27 @@ expect(URI.parse(page.current_url).query).to include("query_id=#{last_query.id}&query_props=") # Publish query - wp_table.click_setting_item I18n.t("js.label_visibility_settings") - find_by_id("show-in-menu").set true - find(".button", text: "Save").click + wp_table.click_setting_item I18n.t('js.label_visibility_settings') + find_by_id('show-in-menu').set true + find('.button', text: 'Save').click wp_table.visit! loading_indicator_saveguard filters.open - filters.remove_filter "status" + filters.remove_filter 'status' filters.expect_filter_count 0 wp_table.expect_work_package_listed work_package_with_version, work_package_without_version # Locate query - query_item = page.find(".op-sidemenu--item-action", text: "Some query name") + query_item = page.find(".op-sidemenu--item-action", text: 'Some query name') query_item.click # Overrides the query_props retry_block do # Run in retry block because page.current_url is not synchronized - raise "query_props should not be in URL path" if page.current_url.include?("query_props") + raise 'query_props should not be in URL path' if page.current_url.include?('query_props') end wp_table.expect_work_package_listed work_package_with_version @@ -167,24 +167,24 @@ filters.expect_filter_count 2 filters.open - filters.expect_filter_by("Version", "is (OR)", version.name) + filters.expect_filter_by('Version', 'is (OR)', version.name) # Removing the filter and returning to query restores it - filters.remove_filter "version" + filters.remove_filter 'version' filters.expect_filter_count 1 - expect(page.current_url).to include("query_props") + expect(page.current_url).to include('query_props') - query_item = page.find(".op-sidemenu--item-action", text: "Some query name") + query_item = page.find(".op-sidemenu--item-action", text: 'Some query name') query_item.click retry_block do # Run in retry block because page.current_url is not synchronized - raise "query_props should not be in URL path" if page.current_url.include?("query_props") + raise 'query_props should not be in URL path' if page.current_url.include?('query_props') end filters.expect_filter_count 2 filters.open - filters.expect_filter_by("Version", "is (OR)", version.name) + filters.expect_filter_by('Version', 'is (OR)', version.name) end end end diff --git a/spec/features/work_packages/table/queries/query_name_inline_edit_spec.rb b/spec/features/work_packages/table/queries/query_name_inline_edit_spec.rb index 095d2e47754e..0a6494aa5ca3 100644 --- a/spec/features/work_packages/table/queries/query_name_inline_edit_spec.rb +++ b/spec/features/work_packages/table/queries/query_name_inline_edit_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Query name inline edit", :js do +RSpec.describe 'Query name inline edit', :js do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -49,11 +49,11 @@ let(:assignee_query) do query = create(:query, - name: "Assignee Query", + name: 'Assignee Query', project:, user:) - query.add_filter("assigned_to_id", "=", [user.id]) + query.add_filter('assigned_to_id', '=', [user.id]) query.save! query @@ -71,7 +71,7 @@ wp_table.visit_query assignee_query end - it "allows renaming the query and shows changed state" do + it 'allows renaming the query and shows changed state' do wp_table.expect_work_package_listed work_package query_title.expect_not_changed @@ -90,7 +90,7 @@ # TODO: The notification should actually not be shown at all since no update # has taken place - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' assignee_query.reload expect(assignee_query.filters.count).to eq(1) @@ -101,35 +101,35 @@ expect(url).not_to match(/query_props=.+/) # Rename query - query_title.rename "Not my assignee query" - wp_table.expect_and_dismiss_toaster message: "Successful update." + query_title.rename 'Not my assignee query' + wp_table.expect_and_dismiss_toaster message: 'Successful update.' assignee_query.reload - expect(assignee_query.name).to eq "Not my assignee query" + expect(assignee_query.name).to eq 'Not my assignee query' # Rename query through context menu - wp_table.click_setting_item "Rename view" + wp_table.click_setting_item 'Rename view' - expect(page).to have_focus_on(".editable-toolbar-title--input") - page.driver.browser.switch_to.active_element.send_keys("Some other name") + expect(page).to have_focus_on('.editable-toolbar-title--input') + page.driver.browser.switch_to.active_element.send_keys('Some other name') page.driver.browser.switch_to.active_element.send_keys(:return) - wp_table.expect_and_dismiss_toaster message: "Successful update." + wp_table.expect_and_dismiss_toaster message: 'Successful update.' assignee_query.reload - expect(assignee_query.name).to eq "Some other name" + expect(assignee_query.name).to eq 'Some other name' end - it "shows the save icon when changing the columns (Regression #32835)" do + it 'shows the save icon when changing the columns (Regression #32835)' do wp_table.expect_work_package_listed work_package query_title.expect_not_changed modal.open! - modal.switch_to "Columns" + modal.switch_to 'Columns' columns.assume_opened columns.uncheck_all save_changes: false - columns.add "Subject", save_changes: true + columns.add 'Subject', save_changes: true query_title.expect_changed end diff --git a/spec/features/work_packages/table/queries/responsible_filter_spec.rb b/spec/features/work_packages/table/queries/responsible_filter_spec.rb index 2e620d6806e1..8f2b2b46f923 100644 --- a/spec/features/work_packages/table/queries/responsible_filter_spec.rb +++ b/spec/features/work_packages/table/queries/responsible_filter_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering by responsible", :js do +RSpec.describe 'Work package filtering by responsible', :js do let(:project) { create(:project) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:filters) { Components::WorkPackages::Filters.new } let(:role) { create(:project_role, permissions: %i[view_work_packages save_queries]) } let(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_roles: { project => role }) end let(:placeholder_user) do @@ -59,19 +59,19 @@ create(:user, member_with_roles: { project => role }) end - it "shows the work package matching the responsible filter" do + it 'shows the work package matching the responsible filter' do wp_table.visit! wp_table.expect_work_package_listed(work_package_user_responsible, work_package_placeholder_user_responsible) filters.open - filters.add_filter_by("Accountable", "is (OR)", [other_user.name], "responsible") + filters.add_filter_by('Accountable', 'is (OR)', [other_user.name], 'responsible') wp_table.ensure_work_package_not_listed!(work_package_placeholder_user_responsible) wp_table.expect_work_package_listed(work_package_user_responsible) - wp_table.save_as("Responsible query") + wp_table.save_as('Responsible query') - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') # Revisit query wp_table.visit_query Query.last @@ -79,9 +79,9 @@ wp_table.expect_work_package_listed(work_package_user_responsible) filters.open - filters.expect_filter_by("Accountable", "is (OR)", [other_user.name], "responsible") - filters.remove_filter "responsible" - filters.add_filter_by("Accountable", "is (OR)", [placeholder_user.name], "responsible") + filters.expect_filter_by('Accountable', 'is (OR)', [other_user.name], 'responsible') + filters.remove_filter 'responsible' + filters.add_filter_by('Accountable', 'is (OR)', [placeholder_user.name], 'responsible') wp_table.ensure_work_package_not_listed!(work_package_user_responsible) wp_table.expect_work_package_listed(work_package_placeholder_user_responsible) diff --git a/spec/features/work_packages/table/queries/shared_with_user_filter_spec.rb b/spec/features/work_packages/table/queries/shared_with_user_filter_spec.rb index 92bf7c46d68a..19a24079fa70 100644 --- a/spec/features/work_packages/table/queries/shared_with_user_filter_spec.rb +++ b/spec/features/work_packages/table/queries/shared_with_user_filter_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering", - "by shared with user", +RSpec.describe 'Work package filtering', + 'by shared with user', :js, :with_cuprite do shared_let(:visible_project) do @@ -58,26 +58,26 @@ shared_let(:user_with_sufficient_permissions) do create(:user, - firstname: "Bruce", - lastname: "Wayne", + firstname: 'Bruce', + lastname: 'Wayne', member_with_roles: { visible_project => project_role_with_sufficient_permissions }) end shared_let(:user_with_insufficient_permissions) do create(:user, - firstname: "Alfred", - lastname: "Pennyworth", + firstname: 'Alfred', + lastname: 'Pennyworth', member_with_roles: { visible_project => project_role_with_insufficient_permissions }) end shared_let(:user_with_shared_work_package) do create(:user, - firstname: "Clark", - lastname: "Kent", + firstname: 'Clark', + lastname: 'Kent', member_with_roles: { visible_project => project_role_with_insufficient_permissions }) end shared_let(:invisible_user) do create(:user, - firstname: "Salvatore", - lastname: "Maroni", + firstname: 'Salvatore', + lastname: 'Maroni', member_with_roles: { invisible_project => project_role_with_insufficient_permissions }) end @@ -102,32 +102,32 @@ context 'when I have sufficient permissions for the "Shared with user" filter' do current_user { user_with_sufficient_permissions } - it "filters work packages by their shared status" do + it 'filters work packages by their shared status' do wp_table.visit! wp_table.expect_work_package_listed(shared_work_package, non_shared_work_package) filters.open aggregate_failures "Members of a Project I'm not a member of are invisible" do - filters.expect_missing_filter_value_by("Shared with user", - "is (OR)", + filters.expect_missing_filter_value_by('Shared with user', + 'is (OR)', [invisible_user.name], - "sharedWithUser") + 'sharedWithUser') end - aggregate_failures "operator filtering" do - filters.add_filter_by("Shared with user", - "is (OR)", + aggregate_failures 'operator filtering' do + filters.add_filter_by('Shared with user', + 'is (OR)', [user_with_shared_work_package.name], - "sharedWithUser") + 'sharedWithUser') wp_table.ensure_work_package_not_listed!(non_shared_work_package) wp_table.expect_work_package_listed(shared_work_package) end - aggregate_failures "Filters persist on saved query" do - wp_table.save_as("Non shared work packages") + aggregate_failures 'Filters persist on saved query' do + wp_table.save_as('Non shared work packages') - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') wp_table.visit_query Query.last wp_table.ensure_work_package_not_listed!(non_shared_work_package) @@ -143,7 +143,7 @@ wp_table.visit! wp_table.expect_work_package_listed(shared_work_package, non_shared_work_package) filters.open - filters.expect_missing_filter("Shared with user") + filters.expect_missing_filter('Shared with user') end end end diff --git a/spec/features/work_packages/table/queries/subject_filter_spec.rb b/spec/features/work_packages/table/queries/subject_filter_spec.rb index 15eebdf062ca..d752c73be0ab 100644 --- a/spec/features/work_packages/table/queries/subject_filter_spec.rb +++ b/spec/features/work_packages/table/queries/subject_filter_spec.rb @@ -26,41 +26,41 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering by subject", :js do +RSpec.describe 'Work package filtering by subject', :js do let(:project) { create(:project, public: true) } let(:admin) { create(:admin) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } let(:filters) { Components::WorkPackages::Filters.new } - let!(:wp_match) { create(:work_package, project:, subject: "R#1234 Foobar") } - let!(:wp_nomatch) { create(:work_package, project:, subject: "R!1234 Foobar") } + let!(:wp_match) { create(:work_package, project:, subject: 'R#1234 Foobar') } + let!(:wp_nomatch) { create(:work_package, project:, subject: 'R!1234 Foobar') } before do login_as admin end - it "shows the one work package filtering for myself" do + it 'shows the one work package filtering for myself' do wp_table.visit! wp_table.expect_work_package_listed(wp_match, wp_nomatch) # Add and save query with me filter filters.open - filters.remove_filter "status" - filters.add_filter_by("Subject", "contains", ["R#"]) + filters.remove_filter 'status' + filters.add_filter_by('Subject', 'contains', ['R#']) wp_table.ensure_work_package_not_listed!(wp_nomatch) wp_table.expect_work_package_listed(wp_match) - wp_table.save_as("Subject query") + wp_table.save_as('Subject query') loading_indicator_saveguard # Expect correct while saving - wp_table.expect_title "Subject query" + wp_table.expect_title 'Subject query' query = Query.last - expect(query.filters.first.values).to eq ["R#"] - filters.expect_filter_by("Subject", "contains", ["R#"]) + expect(query.filters.first.values).to eq ['R#'] + filters.expect_filter_by('Subject', 'contains', ['R#']) # Revisit query wp_table.visit_query query @@ -68,6 +68,6 @@ wp_table.expect_work_package_listed(wp_match) filters.open - filters.expect_filter_by("Subject", "contains", ["R#"]) + filters.expect_filter_by('Subject', 'contains', ['R#']) end end diff --git a/spec/features/work_packages/table/queries/summary_spec.rb b/spec/features/work_packages/table/queries/summary_spec.rb index 56bcbd4ac446..861f64f13a47 100644 --- a/spec/features/work_packages/table/queries/summary_spec.rb +++ b/spec/features/work_packages/table/queries/summary_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/work_packages/work_packages_page" +require 'spec_helper' +require 'features/work_packages/work_packages_page' -RSpec.describe "Work package query summary item", :js do - let(:project) { create(:project, identifier: "test_project", public: false) } +RSpec.describe 'Work package query summary item', :js do + let(:project) { create(:project, identifier: 'test_project', public: false) } let(:role) { create(:project_role, permissions: [:view_work_packages]) } let(:work_package) { create(:work_package, project:) } let(:wp_page) { Pages::WorkPackagesTable.new project } @@ -43,9 +43,9 @@ wp_page.visit! end - it "allows users to visit the summary page" do - find(".op-sidemenu--item-action", text: "Summary", wait: 10).click - expect(page).to have_css("h2", text: "Summary") - expect(page).to have_css("td", text: work_package.type.name) + it 'allows users to visit the summary page' do + find('.op-sidemenu--item-action', text: 'Summary', wait: 10).click + expect(page).to have_css('h2', text: 'Summary') + expect(page).to have_css('td', text: work_package.type.name) end end diff --git a/spec/features/work_packages/table/queries/user_cf_filter_spec.rb b/spec/features/work_packages/table/queries/user_cf_filter_spec.rb index 494544d4367a..d974c5ab2637 100644 --- a/spec/features/work_packages/table/queries/user_cf_filter_spec.rb +++ b/spec/features/work_packages/table/queries/user_cf_filter_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package filtering by user custom field", :js do +RSpec.describe 'Work package filtering by user custom field', :js do let(:project) { create(:project) } let(:type) { project.types.first } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -42,8 +42,8 @@ let(:role) { create(:project_role, permissions: %i[view_work_packages save_queries]) } let!(:other_user) do create(:user, - firstname: "Other", - lastname: "User", + firstname: 'Other', + lastname: 'User', member_with_roles: { project => role }) end let!(:placeholder_user) do @@ -84,7 +84,7 @@ create(:user, member_with_roles: { project => role }) end - it "shows the work package matching the user cf filter" do + it 'shows the work package matching the user cf filter' do wp_table.visit! wp_table.expect_work_package_listed(work_package_user, work_package_placeholder, work_package_group) @@ -92,14 +92,14 @@ # Filtering by user - filters.add_filter_by(user_cf.name, "is (OR)", [other_user.name], user_cf.attribute_name(:camel_case)) + filters.add_filter_by(user_cf.name, 'is (OR)', [other_user.name], user_cf.attribute_name(:camel_case)) wp_table.ensure_work_package_not_listed!(work_package_placeholder, work_package_group) wp_table.expect_work_package_listed(work_package_user) - wp_table.save_as("Saved query") + wp_table.save_as('Saved query') - wp_table.expect_and_dismiss_toaster(message: "Successful creation.") + wp_table.expect_and_dismiss_toaster(message: 'Successful creation.') # Revisit query wp_table.visit_query Query.last @@ -107,12 +107,12 @@ wp_table.expect_work_package_listed(work_package_user) filters.open - filters.expect_filter_by(user_cf.name, "is (OR)", [other_user.name], "customField#{user_cf.id}") + filters.expect_filter_by(user_cf.name, 'is (OR)', [other_user.name], "customField#{user_cf.id}") # Filtering by placeholder filters.remove_filter user_cf.attribute_name(:camel_case) - filters.add_filter_by(user_cf.name, "is (OR)", [placeholder_user.name], user_cf.attribute_name(:camel_case)) + filters.add_filter_by(user_cf.name, 'is (OR)', [placeholder_user.name], user_cf.attribute_name(:camel_case)) wp_table.ensure_work_package_not_listed!(work_package_user, work_package_group) wp_table.expect_work_package_listed(work_package_placeholder) @@ -120,7 +120,7 @@ # Filtering by group filters.remove_filter user_cf.attribute_name(:camel_case) - filters.add_filter_by(user_cf.name, "is (OR)", [group.name], user_cf.attribute_name(:camel_case)) + filters.add_filter_by(user_cf.name, 'is (OR)', [group.name], user_cf.attribute_name(:camel_case)) wp_table.ensure_work_package_not_listed!(work_package_user, work_package_placeholder) wp_table.expect_work_package_listed(work_package_group) diff --git a/spec/features/work_packages/table/queries/version_cf_filter_spec.rb b/spec/features/work_packages/table/queries/version_cf_filter_spec.rb index 027ee07e9820..939560142d79 100644 --- a/spec/features/work_packages/table/queries/version_cf_filter_spec.rb +++ b/spec/features/work_packages/table/queries/version_cf_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' # This is not strictly version CF specific, but targets regression #53198. -RSpec.describe "Work package filtering by version custom field", :js do +RSpec.describe 'Work package filtering by version custom field', :js do let!(:project) { create(:project) } let!(:type) { project.types.first } let!(:version_cf1) do @@ -50,8 +50,8 @@ projects: [project] ) end - let!(:version_1) { create(:version, project:, name: "Version 1") } - let!(:version_2) { create(:version, project:, name: "Version 2") } + let!(:version_1) { create(:version, project:, name: 'Version 1') } + let!(:version_2) { create(:version, project:, name: 'Version 2') } let(:role) { create(:project_role, permissions: %i[view_work_packages save_queries]) } @@ -101,14 +101,14 @@ # Filtering by cf1 "is (AND)" - filters.add_filter_by(version_cf1.name, "is (AND)", [version_1.name], version_cf1.attribute_name(:camel_case)) + filters.add_filter_by(version_cf1.name, 'is (AND)', [version_1.name], version_cf1.attribute_name(:camel_case)) wp_table.expect_work_package_listed(work_package_1_1, work_package_mix) wp_table.ensure_work_package_not_listed!(work_package_2_1) # Filtering by multiple cf1 values (nothing matches) filters.remove_filter version_cf1.attribute_name(:camel_case) - filters.add_filter_by(version_cf1.name, "is (AND)", [version_1.name, version_2.name], version_cf1.attribute_name(:camel_case)) + filters.add_filter_by(version_cf1.name, 'is (AND)', [version_1.name, version_2.name], version_cf1.attribute_name(:camel_case)) wp_table.ensure_work_package_not_listed!(work_package_2_1, work_package_1_1, work_package_mix) end @@ -120,7 +120,7 @@ filters.open # Filtering by cf1 "is not" - filters.add_filter_by(version_cf2.name, "is not", [version_1.name], version_cf2.attribute_name(:camel_case)) + filters.add_filter_by(version_cf2.name, 'is not', [version_1.name], version_cf2.attribute_name(:camel_case)) wp_table.expect_work_package_listed(work_package_mix, work_package_1_1) wp_table.ensure_work_package_not_listed!(work_package_2_1) diff --git a/spec/features/work_packages/table/relations_spec.rb b/spec/features/work_packages/table/relations_spec.rb index 09cfa53da44b..eb071852840f 100644 --- a/spec/features/work_packages/table/relations_spec.rb +++ b/spec/features/work_packages/table/relations_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Package table relations", :js, with_ee: %i[work_package_query_relation_columns] do +RSpec.describe 'Work Package table relations', :js, with_ee: %i[work_package_query_relation_columns] do let(:user) { create(:admin) } let(:type) { create(:type) } @@ -29,7 +29,7 @@ end let!(:query) do query = build(:query, user:, project:) - query.column_names = ["subject"] + query.column_names = ['subject'] query.filters.clear query.save! @@ -37,14 +37,14 @@ end let(:type_column_id) { "relationsToType#{type.id}" } - let(:type_column_follows) { "relationsOfTypeFollows" } + let(:type_column_follows) { 'relationsOfTypeFollows' } before do login_as(user) end - describe "with relation columns allowed by the enterprise token" do - it "displays expandable relation columns" do + describe 'with relation columns allowed by the enterprise token' do + it 'displays expandable relation columns' do # Now visiting the query for category wp_table.visit_query(query) wp_table.expect_work_package_listed(wp_from, wp_to, wp_to2) @@ -56,8 +56,8 @@ wp_from_to = wp_table.row(wp_to) # Expect count for wp_from in both columns to be one - expect(wp_from_row).to have_css(".#{type_column_id} .wp-table--relation-count", text: "2") - expect(wp_from_row).to have_css(".#{type_column_follows} .wp-table--relation-count", text: "2") + expect(wp_from_row).to have_css(".#{type_column_id} .wp-table--relation-count", text: '2') + expect(wp_from_row).to have_css(".#{type_column_follows} .wp-table--relation-count", text: '2') # Expect count for wp_to in both columns to be not rendered expect(wp_from_to).to have_no_css(".#{type_column_id} .wp-table--relation-count") @@ -67,7 +67,7 @@ wp_from_row.find(".#{type_column_id} .wp-table--relation-indicator").click expect(page).to have_css(".__relations-expanded-from-#{wp_from.id}", count: 2) related_row = page.first(".__relations-expanded-from-#{wp_from.id}") - expect(related_row).to have_css("td.wp-table--relation-cell-td", text: "Precedes") + expect(related_row).to have_css('td.wp-table--relation-cell-td', text: "Precedes") # Collapse wp_from_row.find(".#{type_column_id} .wp-table--relation-indicator").click @@ -77,16 +77,16 @@ wp_from_row.find(".#{type_column_follows} .wp-table--relation-indicator").click expect(page).to have_css(".__relations-expanded-from-#{wp_from.id}", count: 2) related_row = page.first(".__relations-expanded-from-#{wp_from.id}") - expect(related_row).to have_css(".wp-table--relation-cell-td", text: wp_to.type) + expect(related_row).to have_css('.wp-table--relation-cell-td', text: wp_to.type) end end - describe "with relation columns disallowed by the enterprise token", with_ee: false do - it "has no relation columns available for selection" do + describe 'with relation columns disallowed by the enterprise token', with_ee: false do + it 'has no relation columns available for selection' do # Now visiting the query for category wp_table.visit_query(query) - columns.expect_column_not_available "follows relations" + columns.expect_column_not_available 'follows relations' columns.expect_column_not_available "Relations to #{type.name}" end end diff --git a/spec/features/work_packages/table/scheduling/manual_scheduling_spec.rb b/spec/features/work_packages/table/scheduling/manual_scheduling_spec.rb index 206306393551..0e190e3806f9 100644 --- a/spec/features/work_packages/table/scheduling/manual_scheduling_spec.rb +++ b/spec/features/work_packages/table/scheduling/manual_scheduling_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Manual scheduling", :js do +RSpec.describe 'Manual scheduling', :js do let(:project) { create(:project, types: [type]) } let(:type) { create(:type) } @@ -10,7 +10,7 @@ create(:work_package, project:, type:, - subject: "Parent") + subject: 'Parent') end let!(:child) do @@ -18,7 +18,7 @@ project:, parent:, type:, - subject: "Child") + subject: 'Child') end let!(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -39,10 +39,10 @@ wp_table.expect_work_package_listed parent, child end - context "with a user allowed to edit dates" do + context 'with a user allowed to edit dates' do let(:role) { create(:project_role, permissions: %i[view_work_packages edit_work_packages]) } - it "allows to edit start and due date multiple times switching between scheduling modes" do + it 'allows to edit start and due date multiple times switching between scheduling modes' do start_date = wp_table.edit_field(parent, :startDate) due_date = wp_table.edit_field(parent, :dueDate) @@ -57,8 +57,8 @@ start_date.within_modal do expect(page).to have_css('input[name="startDate"][disabled]') expect(page).to have_css('input[name="endDate"][disabled]') - expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: "Cancel") - expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: "Save") + expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: 'Cancel') + expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: 'Save') end start_date.toggle_scheduling_mode @@ -67,8 +67,8 @@ start_date.within_modal do expect(page).to have_css('input[name="startDate"]:not([disabled])') expect(page).to have_css('input[name="endDate"]:not([disabled])') - expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: "Cancel") - expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: "Save") + expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: 'Cancel') + expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: 'Save') end start_date.cancel_by_click @@ -89,10 +89,10 @@ # Expect not editable start_date.within_modal do - expect(page).to have_css("input[name=startDate][disabled]") - expect(page).to have_css("input[name=endDate][disabled]") - expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: "Cancel") - expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: "Save") + expect(page).to have_css('input[name=startDate][disabled]') + expect(page).to have_css('input[name=endDate][disabled]') + expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: 'Cancel') + expect(page).to have_css("#{test_selector('op-datepicker-modal--action')}:not([disabled])", text: 'Save') end start_date.toggle_scheduling_mode @@ -100,25 +100,25 @@ # Expect not editable start_date.within_modal do - fill_in "startDate", with: "2020-07-20" - fill_in "endDate", with: "2020-07-25" + fill_in 'startDate', with: '2020-07-20' + fill_in 'endDate', with: '2020-07-25' end # Wait for the debounce to be done sleep 1 start_date.save! - start_date.expect_state_text "07/20/2020" - due_date.expect_state_text "07/25/2020" + start_date.expect_state_text '07/20/2020' + due_date.expect_state_text '07/25/2020' parent.reload expect(parent).to be_schedule_manually - expect(parent.start_date.iso8601).to eq("2020-07-20") - expect(parent.due_date.iso8601).to eq("2020-07-25") + expect(parent.start_date.iso8601).to eq('2020-07-20') + expect(parent.due_date.iso8601).to eq('2020-07-25') end end - context "with a user allowed to view only" do + context 'with a user allowed to view only' do let(:role) { create(:project_role, permissions: %i[view_work_packages]) } end end diff --git a/spec/features/work_packages/table/switch_types_spec.rb b/spec/features/work_packages/table/switch_types_spec.rb index e565ae3ccbeb..7299e1af63cf 100644 --- a/spec/features/work_packages/table/switch_types_spec.rb +++ b/spec/features/work_packages/table/switch_types_spec.rb @@ -1,14 +1,14 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Switching types in work package table", :js do +RSpec.describe 'Switching types in work package table', :js do let(:user) { create(:admin) } - describe "switching to required CF" do + describe 'switching to required CF' do let(:cf_req_text) do create( :work_package_custom_field, - field_format: "string", - name: "Required CF", + field_format: 'string', + name: 'Required CF', is_required: true, is_for_all: false ) @@ -16,7 +16,7 @@ let(:cf_text) do create( :work_package_custom_field, - field_format: "string", + field_format: 'string', is_required: false, is_for_all: false ) @@ -34,7 +34,7 @@ end let(:work_package) do create(:work_package, - subject: "Foobar", + subject: 'Foobar', type: type_task, project:) end @@ -42,7 +42,7 @@ let(:query) do query = build(:query, user:, project:) - query.column_names = ["id", "subject", "type", cf_text.column_name] + query.column_names = ['id', 'subject', 'type', cf_text.column_name] query.save! query @@ -71,16 +71,16 @@ def req_text_field wp_table.expect_work_package_listed(work_package) end - it "switches the types correctly" do + it 'switches the types correctly' do expect(text_field).to be_editable # Set non-required CF text_field.activate! - text_field.set_value "Foobar" + text_field.set_value 'Foobar' text_field.save! wp_table.expect_and_dismiss_toaster( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) # Switch type @@ -94,11 +94,11 @@ def req_text_field # Required CF requires activation req_text_field.activate! - req_text_field.set_value "Required" + req_text_field.set_value 'Required' req_text_field.save! wp_table.expect_and_dismiss_toaster( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) expect { text_field.display_element }.to raise_error(Capybara::ElementNotFound) @@ -107,14 +107,14 @@ def req_text_field type_field.set_value type_task.name wp_table.expect_and_dismiss_toaster( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) expect(page).to have_no_css "#{req_text_field.selector} #{req_text_field.display_selector}" expect { req_text_field.display_element }.to raise_error(Capybara::ElementNotFound) end - it "can switch back from an open required CF (Regression test #28099)" do + it 'can switch back from an open required CF (Regression test #28099)' do # Switch type type_field.activate! type_field.set_value type_bug.name @@ -133,17 +133,17 @@ def req_text_field type_field.set_value type_task.name wp_table.expect_and_dismiss_toaster( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) end - context "switching to single view" do + context 'switching to single view' do let(:wp_split) { wp_table.open_split_view(work_package) } let(:type_field) { wp_split.edit_field(:type) } let(:text_field) { wp_split.edit_field(cf_text.attribute_name(:camel_case)) } let(:req_text_field) { wp_split.edit_field(cf_req_text.attribute_name(:camel_case)) } - it "allows editing and cancelling the new required fields" do + it 'allows editing and cancelling the new required fields' do wp_split # Switch type @@ -161,25 +161,25 @@ def req_text_field # Cancel edition now SeleniumHubWaiter.wait req_text_field.cancel_by_escape - req_text_field.expect_state_text "-" + req_text_field.expect_state_text '-' # Set the value now - req_text_field.update "foobar" + req_text_field.update 'foobar' wp_table.expect_and_dismiss_toaster( - message: "Successful update. Click here to open this work package in fullscreen view." + message: 'Successful update. Click here to open this work package in fullscreen view.' ) - req_text_field.expect_state_text "foobar" + req_text_field.expect_state_text 'foobar' end end end - describe "switching to required bool CF with default value" do + describe 'switching to required bool CF with default value' do let(:cf_req_bool) do create( :work_package_custom_field, - field_format: "bool", + field_format: 'bool', is_required: true, default_value: false ) @@ -197,7 +197,7 @@ def req_text_field end let(:work_package) do create(:work_package, - subject: "Foobar", + subject: 'Foobar', type: type_task, project:) end @@ -210,11 +210,11 @@ def req_text_field wp_page.ensure_page_loaded end - it "can switch to the bug type without errors" do + it 'can switch to the bug type without errors' do type_field.expect_state_text type_task.name.upcase type_field.update type_bug.name - wp_page.expect_and_dismiss_toaster message: "Successful update." + wp_page.expect_and_dismiss_toaster message: 'Successful update.' type_field.expect_state_text type_bug.name.upcase @@ -224,7 +224,7 @@ def req_text_field end end - describe "switching to list CF" do + describe 'switching to list CF' do let!(:wp_page) { Pages::FullWorkPackageCreate.new } let!(:type_with_cf) { create(:type_task, custom_fields: [custom_field]) } let!(:type) { create(:type_bug) } @@ -264,7 +264,7 @@ def req_text_field let(:cf_edit_field) do field = wp_page.edit_field custom_field.attribute_name(:camel_case) - field.field_type = "create-autocompleter" + field.field_type = 'create-autocompleter' field end @@ -277,10 +277,10 @@ def req_text_field SeleniumHubWaiter.wait end - it "can switch to the type with CF list" do + it 'can switch to the type with CF list' do # Set subject subject = wp_page.edit_field :subject - subject.set_value "My subject" + subject.set_value 'My subject' # Switch type type_field = wp_page.edit_field :type @@ -297,11 +297,11 @@ def req_text_field wp_page.save! wp_page.expect_toast( - message: "Successful creation." + message: 'Successful creation.' ) new_wp = WorkPackage.last - expect(new_wp.subject).to eq("My subject") + expect(new_wp.subject).to eq('My subject') expect(new_wp.type_id).to eq(type_with_cf.id) expect(new_wp.custom_value_for(custom_field.id).map(&:typed_value)).to match_array(%w(pineapple mushrooms)) end diff --git a/spec/features/work_packages/table/work_packages_table_project_include_spec.rb b/spec/features/work_packages/table/work_packages_table_project_include_spec.rb index 8d34bf2d826a..9a7f79725644 100644 --- a/spec/features/work_packages/table/work_packages_table_project_include_spec.rb +++ b/spec/features/work_packages/table/work_packages_table_project_include_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../project_include/project_include_shared_examples" +require 'spec_helper' +require_relative '../project_include/project_include_shared_examples' -RSpec.describe "Work package project include", :js do +RSpec.describe 'Work package project include', :js do shared_let(:enabled_modules) { %w[work_package_tracking] } shared_let(:status) { create(:default_status) } shared_let(:priority) { create(:default_priority) } shared_let(:permissions) { %i[view_work_packages edit_work_packages add_work_packages save_queries manage_public_queries] } - it_behaves_like "has a project include dropdown" do + it_behaves_like 'has a project include dropdown' do shared_let(:work_package_view) { Pages::WorkPackagesTable.new(project) } - it "correctly filters work packages by project" do + it 'correctly filters work packages by project' do dropdown.expect_count 1 # Make sure the filter gets set once dropdown.toggle! dropdown.expect_open - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_closed work_package_view.expect_work_package_listed(task, other_task, sub_bug, sub_sub_bug) @@ -52,7 +52,7 @@ dropdown.toggle! dropdown.toggle_checkbox(sub_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_count 1 work_package_view.expect_work_package_listed(task, other_task, sub_sub_bug, sub_bug) @@ -60,7 +60,7 @@ dropdown.toggle! dropdown.toggle_checkbox(other_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_count 2 work_package_view.expect_work_package_listed(task, other_task, sub_sub_bug, sub_bug, other_other_task) @@ -70,14 +70,14 @@ work_package_view.expect_work_package_listed(task, other_task, sub_bug, sub_sub_bug, other_other_task) end - it "creates new work packages in the host project of the work package view (regression #42271)" do + it 'creates new work packages in the host project of the work package view (regression #42271)' do dropdown.expect_count 1 # Make sure the filter gets set once dropdown.toggle! dropdown.expect_open dropdown.toggle_checkbox(other_sub_sub_project.id) - dropdown.click_button "Apply" + dropdown.click_button 'Apply' dropdown.expect_count 2 work_package_view.click_inline_create @@ -85,14 +85,14 @@ subject_field.expect_active! # Save the WP - subject_field.set_value "Foobar!" + subject_field.set_value 'Foobar!' subject_field.submit_by_enter work_package_view.expect_and_dismiss_toaster( - message: "Successful creation. Click here to open this work package in fullscreen view." + message: 'Successful creation. Click here to open this work package in fullscreen view.' ) - work_package_view.expect_work_package_subject "Foobar!" + work_package_view.expect_work_package_subject 'Foobar!' inline_created = WorkPackage.last expect(inline_created.project).to eq(project) diff --git a/spec/features/work_packages/tabs/activity_notifications_spec.rb b/spec/features/work_packages/tabs/activity_notifications_spec.rb index 80b45c45c492..6b2152384430 100644 --- a/spec/features/work_packages/tabs/activity_notifications_spec.rb +++ b/spec/features/work_packages/tabs/activity_notifications_spec.rb @@ -1,23 +1,23 @@ -require "spec_helper" +require 'spec_helper' -require "features/work_packages/work_packages_page" -require "support/edit_fields/edit_field" +require 'features/work_packages/work_packages_page' +require 'support/edit_fields/edit_field' -RSpec.describe "Activity tab notifications", :js, :selenium do +RSpec.describe 'Activity tab notifications', :js, :selenium do shared_let(:project) { create(:project_with_types, public: true) } shared_let(:work_package) do create(:work_package, project:, journals: { 6.days.ago => {}, - 5.days.ago => { notes: "First comment on this wp." }, - 4.days.ago => { notes: "Second comment on this wp." }, - 3.days.ago => { notes: "Third comment on this wp." } + 5.days.ago => { notes: 'First comment on this wp.' }, + 4.days.ago => { notes: 'Second comment on this wp.' }, + 3.days.ago => { notes: 'Third comment on this wp.' } }) end shared_let(:admin) { create(:admin) } - shared_examples_for "when there are notifications for the work package" do + shared_examples_for 'when there are notifications for the work package' do shared_let(:notification) do create(:notification, recipient: admin, @@ -25,79 +25,79 @@ resource: work_package, journal: work_package.journals.last) end - it "shows a notification bubble with the right number" do - expect(page).to have_test_selector("tab-counter-Activity", text: "1") + it 'shows a notification bubble with the right number' do + expect(page).to have_test_selector('tab-counter-Activity', text: '1') end - it "shows a notification icon next to activities that have an unread notification" do - expect(page).to have_test_selector("user-activity-bubble", count: 1) + it 'shows a notification icon next to activities that have an unread notification' do + expect(page).to have_test_selector('user-activity-bubble', count: 1) expect(page).to have_css("[data-qa-activity-number='4'] #{test_selector('user-activity-bubble')}") end - it "shows a button to mark the notifications as read" do - expect(page).to have_test_selector("mark-notification-read-button") + it 'shows a button to mark the notifications as read' do + expect(page).to have_test_selector('mark-notification-read-button') # A click marks the notification as read ... - page.find_test_selector("mark-notification-read-button").click + page.find_test_selector('mark-notification-read-button').click # ... and updates the view accordingly - expect(page).not_to have_test_selector("mark-notification-read-button") - expect(page).not_to have_test_selector("tab-counter-Activity") - expect(page).not_to have_test_selector("user-activity-bubble") + expect(page).not_to have_test_selector('mark-notification-read-button') + expect(page).not_to have_test_selector('tab-counter-Activity') + expect(page).not_to have_test_selector('user-activity-bubble') end end - shared_examples_for "when there are no notifications for the work package" do - it "shows no notification bubble" do - expect(page).not_to have_test_selector("tab-counter-Activity") + shared_examples_for 'when there are no notifications for the work package' do + it 'shows no notification bubble' do + expect(page).not_to have_test_selector('tab-counter-Activity') end - it "does not show any notification icons next to activities" do - expect(page).not_to have_test_selector("user-activity-bubble") + it 'does not show any notification icons next to activities' do + expect(page).not_to have_test_selector('user-activity-bubble') end - it "shows no button to mark the notifications as read" do - expect(page).not_to have_test_selector("mark-notification-read-button") + it 'shows no button to mark the notifications as read' do + expect(page).not_to have_test_selector('mark-notification-read-button') end end - context "when on full view" do + context 'when on full view' do shared_let(:full_view) { Pages::FullWorkPackage.new(work_package, project) } before do login_as(admin) - full_view.visit_tab! "activity" + full_view.visit_tab! 'activity' end - it_behaves_like "when there are notifications for the work package" + it_behaves_like 'when there are notifications for the work package' - it_behaves_like "when there are no notifications for the work package" + it_behaves_like 'when there are no notifications for the work package' end - context "when on split view" do + context 'when on split view' do shared_let(:split_view) { Pages::SplitWorkPackage.new(work_package, project) } before do login_as(admin) - split_view.visit_tab! "activity" + split_view.visit_tab! 'activity' end - it_behaves_like "when there are notifications for the work package" + it_behaves_like 'when there are notifications for the work package' - it_behaves_like "when there are no notifications for the work package" + it_behaves_like 'when there are no notifications for the work package' end - context "when visiting as an anonymous user", with_settings: { login_required?: false } do + context 'when visiting as an anonymous user', with_settings: { login_required?: false } do let(:full_view) { Pages::FullWorkPackage.new(work_package, project) } let!(:anonymous_role) do create(:anonymous_role, permissions: [:view_work_packages]) end - it "does not show an error" do - full_view.visit_tab! "activity" + it 'does not show an error' do + full_view.visit_tab! 'activity' full_view.ensure_page_loaded - full_view.expect_no_toaster type: :error, message: "Http failure response for" + full_view.expect_no_toaster type: :error, message: 'Http failure response for' full_view.expect_no_toaster end end diff --git a/spec/features/work_packages/tabs/activity_revisions_spec.rb b/spec/features/work_packages/tabs/activity_revisions_spec.rb index 62a5da663f8e..065fce237595 100644 --- a/spec/features/work_packages/tabs/activity_revisions_spec.rb +++ b/spec/features/work_packages/tabs/activity_revisions_spec.rb @@ -1,9 +1,9 @@ -require "spec_helper" +require 'spec_helper' -require "features/work_packages/work_packages_page" -require "support/edit_fields/edit_field" +require 'features/work_packages/work_packages_page' +require 'support/edit_fields/edit_field' -RSpec.describe "Activity tab", :js, :with_cuprite do +RSpec.describe 'Activity tab', :js, :with_cuprite do let(:project) { create(:project_with_types, public: true) } let(:creation_time) { 5.days.ago } @@ -18,13 +18,13 @@ subject: initial_subject, journals: { creation_time => { notes: initial_comment }, - subject_change_time => { subject: "New subject", description: "Some not so long description." }, - comment_time => { notes: "A comment by a different user", user: create(:admin) } + subject_change_time => { subject: 'New subject', description: 'Some not so long description.' }, + comment_time => { notes: 'A comment by a different user', user: create(:admin) } }) end - let(:initial_subject) { "My Subject" } - let(:initial_comment) { "First comment on this wp." } + let(:initial_subject) { 'My Subject' } + let(:initial_comment) { 'First comment on this wp.' } let(:comments_in_reverse) { false } let(:activity_tab) { Components::WorkPackages::Activities.new(work_package) } @@ -43,10 +43,10 @@ repo.save! changeset = build(:changeset, - comments: "A comment on a changeset", + comments: 'A comment on a changeset', committed_on: revision_time, repository: repo, - committer: "cool@person.org") + committer: 'cool@person.org') work_package.changesets << changeset @@ -57,12 +57,12 @@ before do allow(user.pref).to receive(:warn_on_leaving_unsaved?).and_return(false) - allow(user.pref).to receive(:comments_sorting).and_return(comments_in_reverse ? "desc" : "asc") + allow(user.pref).to receive(:comments_sorting).and_return(comments_in_reverse ? 'desc' : 'asc') allow(user.pref).to receive(:comments_in_reverse_order?).and_return(comments_in_reverse) end - shared_examples "shows activities in order" do - it "shows activities in ascending order" do + shared_examples 'shows activities in order' do + it 'shows activities in ascending order' do activities.each_with_index do |activity, idx| actual_index = if comments_in_reverse @@ -86,15 +86,15 @@ activity = page.find("#activity-#{idx + 1}") if activity.is_a?(Journal) && activity.id != subject_change_journal.id - expect(activity).to have_css(".user", text: activity.user.name) - expect(activity).to have_css(".user-comment > .message", text: activity.notes, visible: :all) + expect(activity).to have_css('.user', text: activity.user.name) + expect(activity).to have_css('.user-comment > .message', text: activity.notes, visible: :all) elsif activity.is_a?(Changeset) - expect(activity).to have_css(".user", text: User.find(activity.user_id).name) - expect(activity).to have_css(".user-comment > .message", text: activity.notes, visible: :all) + expect(activity).to have_css('.user', text: User.find(activity.user_id).name) + expect(activity).to have_css('.user-comment > .message', text: activity.notes, visible: :all) elsif activity == subject_change_journal - expect(activity).to have_css(".work-package-details-activities-messages .message", + expect(activity).to have_css('.work-package-details-activities-messages .message', count: 2) - expect(activity).to have_css(".message", + expect(activity).to have_css('.message', text: "Subject changed from #{initial_subject} " \ "to #{activity.data.subject}") end @@ -102,13 +102,13 @@ end end - shared_examples "activity tab" do + shared_examples 'activity tab' do before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded end - context "with permission" do + context 'with permission' do let(:role) do create(:project_role, permissions: %i[view_work_packages view_changesets @@ -122,63 +122,63 @@ [creation_journal, subject_change_journal, revision, comment_journal] end - context "with ascending comments" do + context 'with ascending comments' do let(:comments_in_reverse) { false } - it_behaves_like "shows activities in order" + it_behaves_like 'shows activities in order' end - context "with reversed comments" do + context 'with reversed comments' do let(:comments_in_reverse) { true } - it_behaves_like "shows activities in order" + it_behaves_like 'shows activities in order' end - it "can toggle between activities and comments-only" do - expect(page).to have_css(".work-package-details-activities-activity-contents", count: 4) - expect(page).to have_css(".user-comment > .message", text: comment_journal.notes) + it 'can toggle between activities and comments-only' do + expect(page).to have_css('.work-package-details-activities-activity-contents', count: 4) + expect(page).to have_css('.user-comment > .message', text: comment_journal.notes) # Show only comments - find(".activity-comments--toggler").click + find('.activity-comments--toggler').click # It should remove the middle - expect(page).to have_css(".work-package-details-activities-activity-contents", count: 2) - expect(page).to have_css(".user-comment > .message", text: initial_comment) - expect(page).to have_css(".user-comment > .message", text: comment_journal.notes) + expect(page).to have_css('.work-package-details-activities-activity-contents', count: 2) + expect(page).to have_css('.user-comment > .message', text: initial_comment) + expect(page).to have_css('.user-comment > .message', text: comment_journal.notes) # Show all again - find(".activity-comments--toggler").click - expect(page).to have_css(".work-package-details-activities-activity-contents", count: 4) + find('.activity-comments--toggler').click + expect(page).to have_css('.work-package-details-activities-activity-contents', count: 4) end - it "can quote a previous comment" do - activity_tab.hover_action("1", :quote) + it 'can quote a previous comment' do + activity_tab.hover_action('1', :quote) field = TextEditorField.new work_package_page, - "comment", - selector: ".work-packages--activity--add-comment" + 'comment', + selector: '.work-packages--activity--add-comment' expect(field.editing?).to be true # Add our comment - editor = find(".ck-content") - expect(editor).to have_css("blockquote", text: initial_comment) + editor = find('.ck-content') + expect(editor).to have_css('blockquote', text: initial_comment) editor.base.send_keys "\nthis is some remark under a quote" field.submit_by_click - expect(page).to have_css(".user-comment > .message", count: 3) - expect(page).to have_css(".user-comment > .message blockquote") + expect(page).to have_css('.user-comment > .message', count: 3) + expect(page).to have_css('.user-comment > .message blockquote') end - it "can reference a changeset (Regression #30415)" do - work_package_page.visit_tab! "activity" + it 'can reference a changeset (Regression #30415)' do + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded - expect(page).to have_css(".user-comment > .message", text: initial_comment) + expect(page).to have_css('.user-comment > .message', text: initial_comment) comment_field = TextEditorField.new work_package_page, - "comment", - selector: ".work-packages--activity--add-comment" + 'comment', + selector: '.work-packages--activity--add-comment' comment_field.activate! comment_field.click_and_type_slowly "References r#{revision.revision}" @@ -188,7 +188,7 @@ end end - context "with no permission" do + context 'with no permission' do let(:role) do create(:project_role, permissions: [:view_work_packages]) end @@ -200,27 +200,27 @@ [creation_journal, subject_change_journal, comment_journal] end - context "with ascending comments" do + context 'with ascending comments' do let(:comments_in_reverse) { false } - it_behaves_like "shows activities in order" + it_behaves_like 'shows activities in order' end - it "shows the activities, but does not allow commenting" do - expect(page).to have_no_css(".work-packages--activity--add-comment", visible: :visible) + it 'shows the activities, but does not allow commenting' do + expect(page).to have_no_css('.work-packages--activity--add-comment', visible: :visible) end end end - context "when on the split screen" do + context 'when on the split screen' do let(:work_package_page) { Pages::SplitWorkPackage.new(work_package, project) } - it_behaves_like "activity tab" + it_behaves_like 'activity tab' end - context "when on the full screen" do + context 'when on the full screen' do let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "activity tab" + it_behaves_like 'activity tab' end end diff --git a/spec/features/work_packages/tabs/activity_tab_spec.rb b/spec/features/work_packages/tabs/activity_tab_spec.rb index 71a7144745d6..a56ad88a847f 100644 --- a/spec/features/work_packages/tabs/activity_tab_spec.rb +++ b/spec/features/work_packages/tabs/activity_tab_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require "features/work_packages/work_packages_page" -require "support/edit_fields/edit_field" +require 'features/work_packages/work_packages_page' +require 'support/edit_fields/edit_field' -RSpec.describe "Activity tab", :js, :with_cuprite do +RSpec.describe 'Activity tab', :js, :with_cuprite do let(:project) do create(:project_with_types, types: [type_with_cf], @@ -57,8 +57,8 @@ subject: initial_subject, journals: { creation_time => { notes: initial_comment }, - subject_change_time => { subject: "New subject", description: "Some not so long description." }, - comment_time => { notes: "A comment by a different user", user: create(:admin) } + subject_change_time => { subject: 'New subject', description: 'Some not so long description.' }, + comment_time => { notes: 'A comment by a different user', user: create(:admin) } }).tap do |wp| Journal::CustomizableJournal.create!(journal: wp.journals[1], custom_field_id: string_cf.id, @@ -66,8 +66,8 @@ end end - let(:initial_subject) { "My Subject" } - let(:initial_comment) { "First comment on this wp." } + let(:initial_subject) { 'My Subject' } + let(:initial_comment) { 'First comment on this wp.' } let(:comments_in_reverse) { false } let(:activity_tab) { Components::WorkPackages::Activities.new(work_package) } @@ -81,18 +81,18 @@ before do allow(user.pref).to receive(:warn_on_leaving_unsaved?).and_return(false) - allow(user.pref).to receive(:comments_sorting).and_return(comments_in_reverse ? "desc" : "asc") + allow(user.pref).to receive(:comments_sorting).and_return(comments_in_reverse ? 'desc' : 'asc') allow(user.pref).to receive(:comments_in_reverse_order?).and_return(comments_in_reverse) end - shared_examples "shows activities in order" do + shared_examples 'shows activities in order' do let(:journals) do journals = [creation_journal, subject_change_journal, comment_journal] journals end - it "shows activities in ascending order" do + it 'shows activities in ascending order' do journals.each_with_index do |journal, idx| actual_index = if comments_in_reverse @@ -110,14 +110,14 @@ activity = page.find("#activity-#{idx + 1}") if journal.id != subject_change_journal.id - expect(activity).to have_css(".op-user-activity--user-line", text: journal.user.name) - expect(activity).to have_css(".user-comment > .message", text: journal.notes, visible: :all) + expect(activity).to have_css('.op-user-activity--user-line', text: journal.user.name) + expect(activity).to have_css('.user-comment > .message', text: journal.notes, visible: :all) end if activity == subject_change_journal - expect(activity).to have_css(".work-package-details-activities-messages .message", + expect(activity).to have_css('.work-package-details-activities-messages .message', count: 2) - expect(activity).to have_css(".message", + expect(activity).to have_css('.message', text: "Subject changed from #{initial_subject} " \ "to #{journal.data.subject}") end @@ -125,15 +125,15 @@ end end - shared_examples "activity tab" do + shared_examples 'activity tab' do before do - work_package_page.visit_tab! "activity" + work_package_page.visit_tab! 'activity' work_package_page.ensure_page_loaded - expect(page).to have_css(".user-comment > .message", + expect(page).to have_css('.user-comment > .message', text: initial_comment) end - context "with permission" do + context 'with permission' do let(:role) do create(:project_role, permissions: %i[view_work_packages add_work_package_notes]) end @@ -142,51 +142,51 @@ member_with_roles: { project => role }) end - context "with ascending comments" do + context 'with ascending comments' do let(:comments_in_reverse) { false } - it_behaves_like "shows activities in order" + it_behaves_like 'shows activities in order' end - context "with reversed comments" do + context 'with reversed comments' do let(:comments_in_reverse) { true } - it_behaves_like "shows activities in order" + it_behaves_like 'shows activities in order' end - it "can deep link to an activity" do + it 'can deep link to an activity' do visit "/work_packages/#{work_package.id}/activity#activity-#{comment_journal.id}" work_package_page.ensure_page_loaded - expect(page).to have_css(".user-comment > .message", + expect(page).to have_css('.user-comment > .message', text: initial_comment) expect(page.current_url).to match /\/work_packages\/#{work_package.id}\/activity#activity-#{comment_journal.id}/ end - it "can toggle between activities and comments-only" do - expect(page).to have_css(".work-package-details-activities-activity-contents", count: 3) - expect(page).to have_css(".user-comment > .message", text: comment_journal.notes) + it 'can toggle between activities and comments-only' do + expect(page).to have_css('.work-package-details-activities-activity-contents', count: 3) + expect(page).to have_css('.user-comment > .message', text: comment_journal.notes) # Show only comments - find(".activity-comments--toggler").click + find('.activity-comments--toggler').click # It should remove the middle - expect(page).to have_css(".work-package-details-activities-activity-contents", count: 2) - expect(page).to have_css(".user-comment > .message", text: initial_comment) - expect(page).to have_css(".user-comment > .message", text: comment_journal.notes) + expect(page).to have_css('.work-package-details-activities-activity-contents', count: 2) + expect(page).to have_css('.user-comment > .message', text: initial_comment) + expect(page).to have_css('.user-comment > .message', text: comment_journal.notes) # Show all again - find(".activity-comments--toggler").click - expect(page).to have_css(".work-package-details-activities-activity-contents", count: 3) + find('.activity-comments--toggler').click + expect(page).to have_css('.work-package-details-activities-activity-contents', count: 3) end - it "can quote a previous comment" do - activity_tab.hover_action("1", :quote) + it 'can quote a previous comment' do + activity_tab.hover_action('1', :quote) field = TextEditorField.new work_package_page, - "comment", - selector: ".work-packages--activity--add-comment" + 'comment', + selector: '.work-packages--activity--add-comment' field.expect_active! @@ -196,21 +196,21 @@ field.input_element.base.send_keys "\nthis is some remark under a quote" field.submit_by_click - expect(page).to have_css(".user-comment > .message", count: 3) - expect(page).to have_css(".user-comment > .message blockquote") + expect(page).to have_css('.user-comment > .message', count: 3) + expect(page).to have_css('.user-comment > .message blockquote') end - it "can render checkboxes as part of the activity" do + it 'can render checkboxes as part of the activity' do task_list = page.all('[data-qa-activity-number="2"] ul.op-uc-list_task-list li.op-uc-list--item') expect(task_list.size).to eq(2) - expect(task_list[0]).to have_text("Task 1") + expect(task_list[0]).to have_text('Task 1') expect(task_list[0]).to have_checked_field(disabled: true) - expect(task_list[1]).to have_text("Task 2") + expect(task_list[1]).to have_text('Task 2') expect(task_list[1]).to have_unchecked_field(disabled: true) end end - context "with no permission" do + context 'with no permission' do let(:role) do create(:project_role, permissions: [:view_work_packages]) end @@ -219,21 +219,21 @@ member_with_roles: { project => role }) end - it "shows the activities, but does not allow commenting" do - expect(page).to have_no_css(".work-packages--activity--add-comment", visible: :visible) + it 'shows the activities, but does not allow commenting' do + expect(page).to have_no_css('.work-packages--activity--add-comment', visible: :visible) end end end - context "if on split screen" do + context 'if on split screen' do let(:work_package_page) { Pages::SplitWorkPackage.new(work_package, project) } - it_behaves_like "activity tab" + it_behaves_like 'activity tab' end - context "if on full screen" do + context 'if on full screen' do let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "activity tab" + it_behaves_like 'activity tab' end end diff --git a/spec/features/work_packages/tabs/keep_tab_spec.rb b/spec/features/work_packages/tabs/keep_tab_spec.rb index 20daf6e7c148..d30cd8d60df2 100644 --- a/spec/features/work_packages/tabs/keep_tab_spec.rb +++ b/spec/features/work_packages/tabs/keep_tab_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Keep current details tab", :js, :selenium do +RSpec.describe 'Keep current details tab', :js, :selenium do let(:user) { create(:admin) } let(:project) { create(:project) } let!(:wp1) { create(:work_package, project:) } @@ -42,7 +42,7 @@ wp_table.visit! end - it "Remembers the tab while navigating the page" do + it 'Remembers the tab while navigating the page' do wp_table.expect_work_package_listed(wp1) wp_table.expect_work_package_listed(wp2) @@ -64,7 +64,7 @@ wp_full = wp_split1.switch_to_fullscreen wp_full.expect_tab :activity - page.execute_script("window.history.back()") + page.execute_script('window.history.back()') wp_split1.expect_tab :activity # Assert that overview tab is mapped to activity in show diff --git a/spec/features/work_packages/tabs/watcher_tab_spec.rb b/spec/features/work_packages/tabs/watcher_tab_spec.rb index 91a93e617c22..cfb1aa0e6894 100644 --- a/spec/features/work_packages/tabs/watcher_tab_spec.rb +++ b/spec/features/work_packages/tabs/watcher_tab_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Watcher tab", :js, :selenium do +RSpec.describe 'Watcher tab', :js, :selenium do include Components::Autocompleter::NgSelectAutocompleteHelpers let(:project) { create(:project) } @@ -15,117 +15,117 @@ add_work_package_watchers) end - let(:watch_button) { find_by_id "watch-button" } - let(:watchers_tab) { find(".op-tab-row--link_selected", text: "WATCHERS") } + let(:watch_button) { find_by_id 'watch-button' } + let(:watchers_tab) { find('.op-tab-row--link_selected', text: 'WATCHERS') } def expect_button_is_watching - title = I18n.t("js.label_unwatch_work_package") + title = I18n.t('js.label_unwatch_work_package') expect(page).to have_css("#unwatch-button[title='#{title}']", wait: 10) - expect(page).to have_css("#unwatch-button .button--icon.icon-watched", wait: 10) + expect(page).to have_css('#unwatch-button .button--icon.icon-watched', wait: 10) end def expect_button_is_not_watching - title = I18n.t("js.label_watch_work_package") + title = I18n.t('js.label_watch_work_package') expect(page).to have_css("#watch-button[title='#{title}']") - expect(page).to have_css("#watch-button .button--icon.icon-unwatched") + expect(page).to have_css('#watch-button .button--icon.icon-unwatched') end - shared_examples "watch and unwatch with button" do - it "watching the WP modifies the watcher list" do + shared_examples 'watch and unwatch with button' do + it 'watching the WP modifies the watcher list' do # Expect WP watch button is in not-watched state expect_button_is_not_watching - expect(page).not_to have_test_selector("op-wp-watcher-name") + expect(page).not_to have_test_selector('op-wp-watcher-name') watch_button.click # Expect WP watch button causes watcher list to add user expect_button_is_watching - expect(page).to have_test_selector("op-wp-watcher-name", count: 1, text: user.name) + expect(page).to have_test_selector('op-wp-watcher-name', count: 1, text: user.name) # Expect WP unwatch button causes watcher list to remove user watch_button.click expect_button_is_not_watching - expect(page).not_to have_test_selector("op-wp-watcher-name") + expect(page).not_to have_test_selector('op-wp-watcher-name') end end - shared_examples "watchers tab" do + shared_examples 'watchers tab' do before do login_as(user) wp_page.visit_tab! :watchers expect_angular_frontend_initialized - expect(page).to have_css(".op-tab-row--link_selected", text: "WATCHERS") + expect(page).to have_css('.op-tab-row--link_selected', text: 'WATCHERS') end - it "modifying the watcher list modifies the watch button" do + it 'modifying the watcher list modifies the watch button' do # Add user as watcher - autocomplete = find(".wp-watcher--autocomplete ng-select") + autocomplete = find('.wp-watcher--autocomplete ng-select') select_autocomplete autocomplete, query: user.firstname, select_text: user.name, - results_selector: "body" + results_selector: 'body' # Expect the addition of the user to toggle WP watch button - expect(page).to have_test_selector("op-wp-watcher-name", count: 1, text: user.name) + expect(page).to have_test_selector('op-wp-watcher-name', count: 1, text: user.name) expect_button_is_watching # Expect watchers counter to increase tabs.expect_counter(watchers_tab, 1) # Remove watcher from list - page.find_test_selector("op-wp-watcher-name", text: user.name).hover - page.find(".form--selected-value--remover").click + page.find_test_selector('op-wp-watcher-name', text: user.name).hover + page.find('.form--selected-value--remover').click # Watchers counter should not be displayed tabs.expect_no_counter(watchers_tab) # Expect the removal of the user to toggle WP watch button - expect(page).not_to have_test_selector("op-wp-watcher-name") + expect(page).not_to have_test_selector('op-wp-watcher-name') expect_button_is_not_watching end - context "with a user with arbitrary characters" do + context 'with a user with arbitrary characters' do let!(:html_user) do create(:user, :skip_validations, - firstname: "foo", + firstname: 'foo', member_with_roles: { project => role }) end - it "escapes the user name" do - autocomplete = find(".wp-watcher--autocomplete ng-select") + it 'escapes the user name' do + autocomplete = find('.wp-watcher--autocomplete ng-select') target_dropdown = search_autocomplete autocomplete, - query: "foo", - results_selector: "body" + query: 'foo', + results_selector: 'body' expect(target_dropdown).to have_css(".ng-option", text: html_user.firstname) expect(target_dropdown).to have_no_css(".ng-option em") end end - context "with all permissions" do - it_behaves_like "watch and unwatch with button" + context 'with all permissions' do + it_behaves_like 'watch and unwatch with button' end - context "without watchers permission" do + context 'without watchers permission' do let(:permissions) { %i(view_work_packages view_work_package_watchers) } - it_behaves_like "watch and unwatch with button" + it_behaves_like 'watch and unwatch with button' end end - context "split screen" do + context 'split screen' do let(:wp_page) { Pages::SplitWorkPackage.new(work_package) } - it_behaves_like "watchers tab" + it_behaves_like 'watchers tab' end - context "full screen" do + context 'full screen' do let(:wp_page) { Pages::FullWorkPackage.new(work_package) } - it_behaves_like "watchers tab" + it_behaves_like 'watchers tab' end - context "when the work package has a watcher" do + context 'when the work package has a watcher' do let(:watchers) { create(:watcher, watchable: work_package, user:) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -136,14 +136,14 @@ def expect_button_is_not_watching wp_table.expect_work_package_listed work_package end - it "shows the number of watchers [#33685]" do + it 'shows the number of watchers [#33685]' do wp_table.open_full_screen_by_doubleclick(work_package) - expect(page).to have_test_selector("tab-count", text: "(1)") + expect(page).to have_test_selector('tab-count', text: "(1)") end end - context "with a placeholder user in the project" do - let!(:placeholder) { create(:placeholder_user, name: "PLACEHOLDER") } + context 'with a placeholder user in the project' do + let!(:placeholder) { create(:placeholder_user, name: 'PLACEHOLDER') } let(:wp_page) { Pages::FullWorkPackage.new(work_package) } before do @@ -151,11 +151,11 @@ def expect_button_is_not_watching wp_page.visit_tab! :watchers end - it "does not show the placeholder user as an option" do - autocomplete = find(".wp-watcher--autocomplete ng-select") + it 'does not show the placeholder user as an option' do + autocomplete = find('.wp-watcher--autocomplete ng-select') target_dropdown = search_autocomplete autocomplete, - query: "", - results_selector: "body" + query: '', + results_selector: 'body' expect(target_dropdown).to have_css(".ng-option", text: user.name) expect(target_dropdown).to have_no_css(".ng-option", text: placeholder.name) diff --git a/spec/features/work_packages/update_ancestors_spec.rb b/spec/features/work_packages/update_ancestors_spec.rb index cbb4932a5823..b888af574ffa 100644 --- a/spec/features/work_packages/update_ancestors_spec.rb +++ b/spec/features/work_packages/update_ancestors_spec.rb @@ -28,13 +28,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Update ancestors", :js, :with_cuprite do +RSpec.describe 'Update ancestors', :js, :with_cuprite do shared_let(:user) { create(:admin) } shared_let(:priority) { create(:default_priority) } - shared_let(:new_status) { create(:default_status, name: "New") } - shared_let(:closed_status) { create(:closed_status, name: "Closed") } + shared_let(:new_status) { create(:default_status, name: 'New') } + shared_let(:closed_status) { create(:closed_status, name: 'Closed') } shared_let(:type) { create(:type_task) } shared_let(:project_role) { create(:project_role) } shared_let(:project) { create(:project, types: [type]) } @@ -63,14 +63,14 @@ shared_let(:parent) do create(:work_package, - subject: "parent", + subject: 'parent', estimated_hours: 2, remaining_hours: 1) end shared_let(:child) do create(:work_package, parent:, - subject: "child", + subject: 'child', estimated_hours: 6, remaining_hours: 3, done_ratio: 50) @@ -78,7 +78,7 @@ shared_let(:second_child) do create(:work_package, parent:, - subject: "second child", + subject: 'second child', estimated_hours: 3, remaining_hours: 3, done_ratio: 0) @@ -101,7 +101,7 @@ wp_table.visit_query query end - context "when changing a child work and remaining work values", retry: 2 do + context 'when changing a child work and remaining work values', retry: 2 do it "updates the derived parent work, remaining work, and % complete values" do expect do wp_table.update_work_package_attributes(child, estimatedTime: child.estimated_hours + 1) @@ -115,8 +115,8 @@ end end - context "when changing a child % complete value" do - it "updates the derived parent % complete value" do + context 'when changing a child % complete value' do + it 'updates the derived parent % complete value' do expect do wp_table.update_work_package_attributes(child, percentageDone: 100) parent.reload @@ -124,17 +124,17 @@ end end - context "when setting a child status to closed" do - it "considers child % complete to be 100% and updates the derived parent % complete value accordingly" do + context 'when setting a child status to closed' do + it 'considers child % complete to be 100% and updates the derived parent % complete value accordingly' do expect do - wp_table.update_work_package_attributes(child, status: "Closed") + wp_table.update_work_package_attributes(child, status: 'Closed') parent.reload end.to change(parent, :derived_done_ratio).to(67) # 6h at 100% and 3h at 0% => 67% complete for 9h end end - context "when deleting a child" do - it "updates the derived parent work, remaining work, and % complete values" do + context 'when deleting a child' do + it 'updates the derived parent work, remaining work, and % complete values' do context_menu = wp_table.open_context_menu_for(second_child) context_menu.choose_delete_and_confirm_deletion @@ -145,15 +145,15 @@ end end - context "when adding a new child" do - it "updates the derived parent work, remaining work, and % complete values" do + context 'when adding a new child' do + it 'updates the derived parent work, remaining work, and % complete values' do context_menu = wp_table.open_context_menu_for(parent) - context_menu.choose(I18n.t("js.relation_buttons.add_new_child")) + context_menu.choose(I18n.t('js.relation_buttons.add_new_child')) split_view_create = Pages::SplitWorkPackageCreate.new(project:) - split_view_create.set_attributes({ subject: "new child", estimatedTime: 1, remainingTime: 3 }) + split_view_create.set_attributes({ subject: 'new child', estimatedTime: 1, remainingTime: 3 }) split_view_create.save! - split_view_create.expect_and_dismiss_toaster message: "Successful creation" + split_view_create.expect_and_dismiss_toaster message: 'Successful creation' parent.reload new_child = WorkPackage.last @@ -165,11 +165,11 @@ end end - context "when outdenting and indenting hierarchy of a child" do - it "updates the parent work and remaining work values" do + context 'when outdenting and indenting hierarchy of a child' do + it 'updates the parent work and remaining work values' do context_menu = wp_table.open_context_menu_for(second_child) - context_menu.choose(I18n.t("js.relation_buttons.hierarchy_outdent")) - wp_table.expect_and_dismiss_toaster message: "Successful update" + context_menu.choose(I18n.t('js.relation_buttons.hierarchy_outdent')) + wp_table.expect_and_dismiss_toaster message: 'Successful update' parent.reload expect(parent.derived_estimated_hours).to eq([parent, child].pluck(:estimated_hours).sum) @@ -177,8 +177,8 @@ expect(parent.derived_done_ratio).to eq(child.done_ratio) context_menu = wp_table.open_context_menu_for(second_child) - context_menu.choose(I18n.t("js.relation_buttons.hierarchy_indent")) - wp_table.expect_and_dismiss_toaster message: "Successful update" + context_menu.choose(I18n.t('js.relation_buttons.hierarchy_indent')) + wp_table.expect_and_dismiss_toaster message: 'Successful update' parent.reload expect(parent.derived_estimated_hours).to eq([parent, child, second_child].pluck(:estimated_hours).sum) diff --git a/spec/features/work_packages/work_package_index_spec.rb b/spec/features/work_packages/work_package_index_spec.rb index 14f9bd54160c..bb4523db326d 100644 --- a/spec/features/work_packages/work_package_index_spec.rb +++ b/spec/features/work_packages/work_package_index_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work Packages", "index view", :js, :with_cuprite do +RSpec.describe 'Work Packages', 'index view', :js, :with_cuprite do let(:user) { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[work_package_tracking]) } let(:wp_table) { Pages::WorkPackagesTable.new(project) } @@ -37,42 +37,42 @@ login_as(user) end - context "within a global context" do + context 'within a global context' do before do visit root_path end - it "is reachable by clicking the global menu item" do - within("#main-menu") do - click_link "Work packages" + it 'is reachable by clicking the global menu item' do + within('#main-menu') do + click_link 'Work packages' end expect(page).to have_current_path(work_packages_path) - within("#content") do - wp_table.expect_title("All open", editable: true) - expect(page).to have_content("No work packages to display") + within('#content') do + wp_table.expect_title('All open', editable: true) + expect(page).to have_content('No work packages to display') end end end - context "within a project-specific context" do - it "is reachable by clicking the sidebar menu item" do + context 'within a project-specific context' do + it 'is reachable by clicking the sidebar menu item' do visit project_path(project) - within("#content") do - expect(page).to have_content("Overview") + within('#content') do + expect(page).to have_content('Overview') end - within("#main-menu") do - click_link "Work packages" + within('#main-menu') do + click_link 'Work packages' end expect(page).to have_current_path(project_work_packages_path(project)) - within("#content") do - wp_table.expect_title("All open", editable: true) - expect(page).to have_content("No work packages to display") + within('#content') do + wp_table.expect_title('All open', editable: true) + expect(page).to have_content('No work packages to display') end end end diff --git a/spec/features/work_packages/work_package_workflow_form_spec.rb b/spec/features/work_packages/work_package_workflow_form_spec.rb index ccf8f18a0eb2..7fa55e6d1743 100644 --- a/spec/features/work_packages/work_package_workflow_form_spec.rb +++ b/spec/features/work_packages/work_package_workflow_form_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "features/page_objects/notification" +require 'spec_helper' +require 'features/page_objects/notification' -RSpec.describe "Work package transitive status workflows", :js do +RSpec.describe 'Work package transitive status workflows', :js do let(:dev_role) do create(:project_role, permissions: %i[view_work_packages @@ -37,8 +37,8 @@ end let(:dev) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_roles: { project => dev_role }) end @@ -89,7 +89,7 @@ ## # Regression test for #24129 - it "allows to move to the final status as defined in the workflow" do + it 'allows to move to the final status as defined in the workflow' do wp_page.update_attributes status: status_intermediate.name wp_page.expect_attributes status: status_intermediate.name diff --git a/spec/features/work_packages/work_packages_page.rb b/spec/features/work_packages/work_packages_page.rb index 6e2271455448..ad379239792c 100644 --- a/spec/features/work_packages/work_packages_page.rb +++ b/spec/features/work_packages/work_packages_page.rb @@ -55,24 +55,24 @@ def visit_edit(id) end def visit_calendar - visit index_path + "/calendar" + visit index_path + '/calendar' end def open_settings! - click_on "work-packages-settings-button" + click_on 'work-packages-settings-button' end def click_work_packages_menu_item - find("#main-menu .work-packages").click + find('#main-menu .work-packages').click end def click_toolbar_button(button) close_toasters - find(".toolbar-container", wait: 5).click_button button + find('.toolbar-container', wait: 5).click_button button end def close_toasters - page.all(:css, ".op-toast--close").each(&:click) + page.all(:css, '.op-toast--close').each(&:click) end def select_query(query) @@ -83,9 +83,9 @@ def select_query(query) def find_subject_field(text = nil) if text - find_by_id("inplace-edit--write-value--subject", text:) + find_by_id('inplace-edit--write-value--subject', text:) else - find_by_id("inplace-edit--write-value--subject") + find_by_id('inplace-edit--write-value--subject') end end @@ -107,7 +107,7 @@ def query_path(query) def ensure_index_page_loaded if Capybara.current_driver == Capybara.javascript_driver - expect(page).to have_css(".work-packages--filters-optional-container.-loaded", visible: :all, wait: 20) + expect(page).to have_css('.work-packages--filters-optional-container.-loaded', visible: :all, wait: 20) end end end diff --git a/spec/features/work_packages/zen_mode_spec.rb b/spec/features/work_packages/zen_mode_spec.rb index 3fc223e22dca..99a02e65e5d4 100644 --- a/spec/features/work_packages/zen_mode_spec.rb +++ b/spec/features/work_packages/zen_mode_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Zen mode", :js do +RSpec.describe 'Zen mode', :js do let(:dev_role) do create(:project_role, permissions: %i[view_work_packages @@ -8,8 +8,8 @@ end let(:dev) do create(:user, - firstname: "Dev", - lastname: "Guy", + firstname: 'Dev', + lastname: 'Guy', member_with_roles: { project => dev_role }) end @@ -34,13 +34,13 @@ wp_page.ensure_page_loaded end - it "hides menus" do + it 'hides menus' do wp_page.expect_no_zen_mode - wp_page.page.find_by_id("work-packages-zen-mode-toggle-button").click + wp_page.page.find_by_id('work-packages-zen-mode-toggle-button').click wp_page.expect_zen_mode wp_page.go_back wp_page.expect_zen_mode - wp_page.page.find_by_id("work-packages-zen-mode-toggle-button").click + wp_page.page.find_by_id('work-packages-zen-mode-toggle-button').click wp_page.expect_no_zen_mode end end diff --git a/spec/features/workflows/copy_spec.rb b/spec/features/workflows/copy_spec.rb index 38a3fc072be4..848ff35900a0 100644 --- a/spec/features/workflows/copy_spec.rb +++ b/spec/features/workflows/copy_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Workflow copy" do +RSpec.describe 'Workflow copy' do let(:role) { create(:project_role) } let(:type) { create(:type) } let(:admin) { create(:admin) } @@ -45,16 +45,16 @@ current_user { admin } before do - visit url_for(controller: "/workflows", action: :copy) + visit url_for(controller: '/workflows', action: :copy) end - it "shows existing types and roles" do + it 'shows existing types and roles' do select(role.name, from: :source_role_id) - within("#source_role_id") do + within('#source_role_id') do expect(page).to have_content(role.name) expect(page).to have_content("--- #{I18n.t(:actionview_instancetag_blank_option)} ---") end - within("#source_type_id") do + within('#source_type_id') do expect(page).to have_content(type.name) expect(page).to have_content("--- #{I18n.t(:actionview_instancetag_blank_option)} ---") end diff --git a/spec/features/workflows/missing_for_sharing_wp_spec.rb b/spec/features/workflows/missing_for_sharing_wp_spec.rb index 242f36d729b9..0af19fb1e91c 100644 --- a/spec/features/workflows/missing_for_sharing_wp_spec.rb +++ b/spec/features/workflows/missing_for_sharing_wp_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Configuring the workflow for work package sharing", +RSpec.describe 'Configuring the workflow for work package sharing', with_config: { show_warning_bars: true }, with_ee: %i[work_package_sharing] do let!(:role) { create(:project_role) } @@ -52,9 +52,9 @@ visit home_url end - it "shows a warning until a workflow is configured for the work package edit role" do + it 'shows a warning until a workflow is configured for the work package edit role' do # There is a warning bar at the bottom informing of the missing workflow - within ".warning-bar--item" do + within '.warning-bar--item' do expect(page) .to have_content("No workflow is configured for the '#{work_package_role.name}' role. " \ "Without a workflow, the shared with user cannot alter the status of the work package.") @@ -63,16 +63,16 @@ end # On the copy workflow form, select the already existing workflow for copying - select type.name, from: "source_type_id" - select role.name, from: "source_role_id" - select type.name, from: "target_type_ids" - select work_package_role.name, from: "target_role_ids" + select type.name, from: 'source_type_id' + select role.name, from: 'source_role_id' + select type.name, from: 'target_type_ids' + select work_package_role.name, from: 'target_role_ids' - click_button "Copy" + click_button 'Copy' # Copying succeeds which results in the edit role having a workflow and the warning disappearing. expect(page) - .to have_content "Successful update" + .to have_content 'Successful update' expect(Workflow.where(role_id: work_package_role.id, type_id: type.id, @@ -82,6 +82,6 @@ assignee: false).count).to eq(1) expect(page) - .to have_no_css(".warning-bar--item") + .to have_no_css('.warning-bar--item') end end diff --git a/spec/features/wysiwyg/bold_behavior_spec.rb b/spec/features/wysiwyg/bold_behavior_spec.rb index 1f4021a44acf..21ce519e9dea 100644 --- a/spec/features/wysiwyg/bold_behavior_spec.rb +++ b/spec/features/wysiwyg/bold_behavior_spec.rb @@ -26,45 +26,45 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg bold behavior", :js, :with_cuprite do +RSpec.describe 'Wysiwyg bold behavior', :js, :with_cuprite do current_user { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[wiki]) } let(:editor) { Components::WysiwygEditor.new } def mac_osx? - RUBY_PLATFORM.include?("darwin") + RUBY_PLATFORM.include?('darwin') end def bold_keystroke if mac_osx? - [:meta, "b"] + [:meta, 'b'] else - [:ctrl, "b"] + [:ctrl, 'b'] end end - describe "in wikis" do - describe "creating a wiki page" do + describe 'in wikis' do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can insert strong formatting with nbsp" do - editor.click_and_type_slowly "some text ", bold_keystroke, "with bold" + it 'can insert strong formatting with nbsp' do + editor.click_and_type_slowly 'some text ', bold_keystroke, 'with bold' # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css("p") { |node| - node.text.include?("some text") && node.text.include?("with bold") + within('#content') do + expect(page).to have_css('p') { |node| + node.text.include?('some text') && node.text.include?('with bold') } - expect(page).to have_css("strong", text: "with bold") + expect(page).to have_css('strong', text: 'with bold') end end end diff --git a/spec/features/wysiwyg/custom_css_classes_spec.rb b/spec/features/wysiwyg/custom_css_classes_spec.rb index 8108bce93e92..3b94f2db08ca 100644 --- a/spec/features/wysiwyg/custom_css_classes_spec.rb +++ b/spec/features/wysiwyg/custom_css_classes_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg paragraphs in lists behavior (Regression #28765)", :js do +RSpec.describe 'Wysiwyg paragraphs in lists behavior (Regression #28765)', :js do let(:user) { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[wiki]) } let(:editor) { Components::WysiwygEditor.new } @@ -114,61 +114,61 @@ visit edit_project_wiki_path(project, wiki_page.slug) end - it "custom classes are placed correctly" do + it 'custom classes are placed correctly' do editor.in_editor do |_container, editable| - expect(editable).to have_css("p.op-uc-p", count: 6) - expect(editable).to have_css("h1.op-uc-h1", count: 1) - expect(editable).to have_css("h2.op-uc-h2", count: 1) - expect(editable).to have_css("h3.op-uc-h3", count: 1) - expect(editable).to have_css("h4.op-uc-h4", count: 1) - expect(editable).to have_css("h5.op-uc-h5", count: 1) - expect(editable).to have_css("blockquote.op-uc-blockquote", count: 1) - expect(editable).to have_css("figure.op-uc-figure", count: 1) - expect(editable).to have_css("figure.op-uc-figure.op-uc-figure_align-center table.op-uc-table", count: 1) - expect(editable).to have_css("table.op-uc-table thead.op-uc-table--head", count: 1) - expect(editable).to have_css("table.op-uc-table tr.op-uc-table--row", count: 2) - expect(editable).to have_css("table.op-uc-table td.op-uc-table--cell", count: 2) - expect(editable).to have_css("table.op-uc-table th.op-uc-table--cell.op-uc-table--cell_head", count: 4) - expect(editable).to have_css("ul.op-uc-list", count: 2) - expect(editable).to have_css("ol.op-uc-list", count: 1) - expect(editable).to have_css("ul.op-uc-list_task-list", count: 1) - expect(editable).to have_css("ul.op-uc-list li.op-uc-list--item", count: 2) - expect(editable).to have_css("ol.op-uc-list li.op-uc-list--item", count: 1) - expect(editable).to have_css("ul.op-uc-list.op-uc-list_task-list li.op-uc-list--item", count: 1) - expect(editable).to have_css("pre.op-uc-code-block", count: 1) - expect(editable).to have_css("code.op-uc-code", count: 1) - expect(editable).to have_css("a.op-uc-link", count: 1) - expect(editable).to have_css("div.op-uc-placeholder", count: 3) - expect(editable).to have_css("span.op-uc-placeholder", count: 1) + expect(editable).to have_css('p.op-uc-p', count: 6) + expect(editable).to have_css('h1.op-uc-h1', count: 1) + expect(editable).to have_css('h2.op-uc-h2', count: 1) + expect(editable).to have_css('h3.op-uc-h3', count: 1) + expect(editable).to have_css('h4.op-uc-h4', count: 1) + expect(editable).to have_css('h5.op-uc-h5', count: 1) + expect(editable).to have_css('blockquote.op-uc-blockquote', count: 1) + expect(editable).to have_css('figure.op-uc-figure', count: 1) + expect(editable).to have_css('figure.op-uc-figure.op-uc-figure_align-center table.op-uc-table', count: 1) + expect(editable).to have_css('table.op-uc-table thead.op-uc-table--head', count: 1) + expect(editable).to have_css('table.op-uc-table tr.op-uc-table--row', count: 2) + expect(editable).to have_css('table.op-uc-table td.op-uc-table--cell', count: 2) + expect(editable).to have_css('table.op-uc-table th.op-uc-table--cell.op-uc-table--cell_head', count: 4) + expect(editable).to have_css('ul.op-uc-list', count: 2) + expect(editable).to have_css('ol.op-uc-list', count: 1) + expect(editable).to have_css('ul.op-uc-list_task-list', count: 1) + expect(editable).to have_css('ul.op-uc-list li.op-uc-list--item', count: 2) + expect(editable).to have_css('ol.op-uc-list li.op-uc-list--item', count: 1) + expect(editable).to have_css('ul.op-uc-list.op-uc-list_task-list li.op-uc-list--item', count: 1) + expect(editable).to have_css('pre.op-uc-code-block', count: 1) + expect(editable).to have_css('code.op-uc-code', count: 1) + expect(editable).to have_css('a.op-uc-link', count: 1) + expect(editable).to have_css('div.op-uc-placeholder', count: 3) + expect(editable).to have_css('span.op-uc-placeholder', count: 1) end end - it "custom align classes are placed correctly" do + it 'custom align classes are placed correctly' do editor.in_editor do |container, editable| # strangely, we need visible: :all here - editor.click_toolbar_button "Insert table" + editor.click_toolbar_button 'Insert table' # 2x2 - container.find(".ck-insert-table-dropdown-grid-box:nth-of-type(12)").click + container.find('.ck-insert-table-dropdown-grid-box:nth-of-type(12)').click sleep(0.1) # There are already multiple tables on the page. # To avoid mixing them up, we need to select the appropriate one - table = container.find(".op-uc-figure:first-of-type .op-uc-table") + table = container.find('.op-uc-figure:first-of-type .op-uc-table') - editor.align_table_by_label(editor, table, "Align table to the left") + editor.align_table_by_label(editor, table, 'Align table to the left') # Table figure should now has the proper alignment class - expect(editable).to have_css("figure.op-uc-figure_align-start") + expect(editable).to have_css('figure.op-uc-figure_align-start') - editor.align_table_by_label(editor, table, "Align table to the right") + editor.align_table_by_label(editor, table, 'Align table to the right') # Table figure should now has the proper alignment class - expect(editable).to have_css("figure.op-uc-figure_align-end") + expect(editable).to have_css('figure.op-uc-figure_align-end') - editor.align_table_by_label(editor, table, "Center table") + editor.align_table_by_label(editor, table, 'Center table') # Table figure should now has the proper alignment class - expect(editable).to have_css("figure.op-uc-figure_align-center") + expect(editable).to have_css('figure.op-uc-figure_align-center') end end end diff --git a/spec/features/wysiwyg/html_encoding_spec.rb b/spec/features/wysiwyg/html_encoding_spec.rb index 4fd85a110314..26c1786d9ec4 100644 --- a/spec/features/wysiwyg/html_encoding_spec.rb +++ b/spec/features/wysiwyg/html_encoding_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg escaping HTML entities (Regression #28906)", :js do +RSpec.describe 'Wysiwyg escaping HTML entities (Regression #28906)', :js do let(:user) { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[wiki]) } let(:editor) { Components::WysiwygEditor.new } @@ -38,31 +38,31 @@ visit project_wiki_path(project, :wiki) end - it "shows the list correctly" do + it 'shows the list correctly' do editor.in_editor do |_, editable| editor.click_and_type_slowly '', :enter, '\foo\' - expect(editable).to have_no_css("node") - expect(editable).to have_no_css("u") + expect(editable).to have_no_css('node') + expect(editable).to have_no_css('u') end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css("p", text: '') - expect(page).to have_no_css("u") - expect(page).to have_no_css("node") + within('#content') do + expect(page).to have_css('p', text: '') + expect(page).to have_no_css('u') + expect(page).to have_no_css('node') end text = WikiPage.last.text expect(text).to include "<node foo="bar" />" expect(text).to include "\\\\<u>foo\\\\</u>" - expect(text).not_to include "" - expect(text).not_to include "" + expect(text).not_to include '' + expect(text).not_to include '' end end diff --git a/spec/features/wysiwyg/linking_spec.rb b/spec/features/wysiwyg/linking_spec.rb index 277a5d4ef2c2..4d8265091e88 100644 --- a/spec/features/wysiwyg/linking_spec.rb +++ b/spec/features/wysiwyg/linking_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg linking", :js do +RSpec.describe 'Wysiwyg linking', :js do let(:user) { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[wiki work_package_tracking]) } let(:editor) { Components::WysiwygEditor.new } @@ -37,19 +37,19 @@ login_as(user) end - describe "creating a wiki page" do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can create links with spaces (Regression #29742)" do + it 'can create links with spaces (Regression #29742)' do # single hash autocomplete - editor.insert_link "http://example.org/link with spaces" + editor.insert_link 'http://example.org/link with spaces' # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') wiki_page = project.wiki.pages.first.reload diff --git a/spec/features/wysiwyg/macros/attribute_macros_spec.rb b/spec/features/wysiwyg/macros/attribute_macros_spec.rb index 5bb7d11c4fe9..0a054b9f4e57 100644 --- a/spec/features/wysiwyg/macros/attribute_macros_spec.rb +++ b/spec/features/wysiwyg/macros/attribute_macros_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg attribute macros", :js do +RSpec.describe 'Wysiwyg attribute macros', :js do shared_let(:admin) { create(:admin) } let(:user) { admin } - let!(:project) { create(:project, identifier: "some-project", enabled_module_names: %w[wiki work_package_tracking]) } + let!(:project) { create(:project, identifier: 'some-project', enabled_module_names: %w[wiki work_package_tracking]) } let!(:work_package) { create(:work_package, subject: "Foo Bar", project:) } let(:editor) { Components::WysiwygEditor.new } @@ -68,41 +68,41 @@ login_as(user) end - describe "creating a wiki page" do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can add and save multiple code blocks (Regression #28350)" do + it 'can add and save multiple code blocks (Regression #28350)' do editor.in_editor do |container,| editor.set_markdown markdown expect(container).to have_table end - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') # Expect output widget - within("#content") do - expect(page).to have_css("td", text: "Subject") - expect(page).to have_css("td", text: "Foo Bar") - expect(page).to have_css("td", text: "Identifier") - expect(page).to have_css("td", text: "some-project") - - expect(page).to have_css("td", text: "invalid subject Cannot expand macro: Requested resource could not be found") - expect(page).to have_css("td", text: "invalid project Cannot expand macro: Requested resource could not be found") + within('#content') do + expect(page).to have_css('td', text: 'Subject') + expect(page).to have_css('td', text: 'Foo Bar') + expect(page).to have_css('td', text: 'Identifier') + expect(page).to have_css('td', text: 'some-project') + + expect(page).to have_css('td', text: 'invalid subject Cannot expand macro: Requested resource could not be found') + expect(page).to have_css('td', text: 'invalid project Cannot expand macro: Requested resource could not be found') end # Edit page again - click_on "Edit" + click_on 'Edit' editor.in_editor do |container,| - expect(container).to have_css("tbody td", count: 6) + expect(container).to have_css('tbody td', count: 6) end end - context "with a multi-select CF" do + context 'with a multi-select CF' do let!(:type) { create(:type, projects: [project]) } let!(:custom_field) do create( @@ -126,18 +126,18 @@ wp end - it "expands all custom values (Regression #45538)" do + it 'expands all custom values (Regression #45538)' do editor.in_editor do |container,| editor.set_markdown 'workPackageValue:"Foo Bar":Ingredients' - expect(container).to have_text "workPackageValue" + expect(container).to have_text 'workPackageValue' end - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css(".custom-option", count: 6) + within('#content') do + expect(page).to have_css('.custom-option', count: 6) end end end diff --git a/spec/features/wysiwyg/macros/child_pages_spec.rb b/spec/features/wysiwyg/macros/child_pages_spec.rb index 6aa740e07b79..e3b0fcc56fdd 100644 --- a/spec/features/wysiwyg/macros/child_pages_spec.rb +++ b/spec/features/wysiwyg/macros/child_pages_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg child pages spec", :js do +RSpec.describe 'Wysiwyg child pages spec', :js do let(:project) do create(:project, enabled_module_names: %w[wiki]) @@ -41,20 +41,20 @@ let(:wiki_page) do create(:wiki_page, - title: "Test", - text: "# My page") + title: 'Test', + text: '# My page') end let(:parent_page) do create(:wiki_page, - title: "Parent page", - text: "# parent page") + title: 'Parent page', + text: '# parent page') end let(:child_page) do create(:wiki_page, - title: "Child page", - text: "# child page") + title: 'Child page', + text: '# child page') end before do @@ -69,92 +69,92 @@ login_as(user) end - describe "in wikis" do - describe "creating a wiki page" do + describe 'in wikis' do + describe 'creating a wiki page' do before do visit edit_project_wiki_path(project, :test) end - it "can add and edit an child pages widget" do + it 'can add and edit an child pages widget' do editor.in_editor do |_container, editable| - expect(editable).to have_css("h1", text: "My page") + expect(editable).to have_css('h1', text: 'My page') - editor.insert_macro "Links to child pages" + editor.insert_macro 'Links to child pages' # Find widget, click to show toolbar - placeholder = find(".op-uc-placeholder", text: "Links to child pages") + placeholder = find('.op-uc-placeholder', text: 'Links to child pages') # Placeholder states `this page` and no `Include parent` - expect(placeholder).to have_text("this page") - expect(placeholder).to have_no_text("Include parent") + expect(placeholder).to have_text('this page') + expect(placeholder).to have_no_text('Include parent') # Edit widget and cancel again placeholder.click - page.find(".ck-balloon-panel .ck-button", visible: :all, text: "Edit").click - expect(page).to have_css(".spot-modal") - expect(page).to have_field("selected-page", with: "") - find(".spot-modal--cancel-button").click + page.find('.ck-balloon-panel .ck-button', visible: :all, text: 'Edit').click + expect(page).to have_css('.spot-modal') + expect(page).to have_field('selected-page', with: '') + find('.spot-modal--cancel-button').click # Edit widget and save placeholder.click - page.find(".ck-balloon-panel .ck-button", visible: :all, text: "Edit").click - expect(page).to have_css(".spot-modal") - fill_in "selected-page", with: "parent-page" + page.find('.ck-balloon-panel .ck-button', visible: :all, text: 'Edit').click + expect(page).to have_css('.spot-modal') + fill_in 'selected-page', with: 'parent-page' # Save widget - find(".spot-modal--submit-button").click + find('.spot-modal--submit-button').click # Placeholder states `parent-page` and no `Include parent` - expect(placeholder).to have_text("parent-page") - expect(placeholder).to have_no_text("Include parent") + expect(placeholder).to have_text('parent-page') + expect(placeholder).to have_no_text('Include parent') end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css(".pages-hierarchy") - expect(page).to have_css(".pages-hierarchy", text: "Child page") - expect(page).to have_no_css(".pages-hierarchy", text: "Parent page") - expect(page).to have_css("h1", text: "My page") + within('#content') do + expect(page).to have_css('.pages-hierarchy') + expect(page).to have_css('.pages-hierarchy', text: 'Child page') + expect(page).to have_no_css('.pages-hierarchy', text: 'Parent page') + expect(page).to have_css('h1', text: 'My page') SeleniumHubWaiter.wait - find(".toolbar .icon-edit").click + find('.toolbar .icon-edit').click end editor.in_editor do |_container, _editable| # Find widget, click to show toolbar - placeholder = find(".op-uc-placeholder", text: "Links to child pages") + placeholder = find('.op-uc-placeholder', text: 'Links to child pages') # Edit widget and save placeholder.click - page.find(".ck-balloon-panel .ck-button", visible: :all, text: "Edit").click - expect(page).to have_css(".spot-modal") - page.check "include-parent" + page.find('.ck-balloon-panel .ck-button', visible: :all, text: 'Edit').click + expect(page).to have_css('.spot-modal') + page.check 'include-parent' # Save widget - find(".spot-modal--submit-button").click + find('.spot-modal--submit-button').click # Placeholder states `parent-page` and `Include parent` - expect(placeholder).to have_text("parent-page") - expect(placeholder).to have_text("Include parent") + expect(placeholder).to have_text('parent-page') + expect(placeholder).to have_text('Include parent') end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css(".pages-hierarchy") - expect(page).to have_css(".pages-hierarchy", text: "Child page") - expect(page).to have_css(".pages-hierarchy", text: "Parent page") - expect(page).to have_css("h1", text: "My page") + within('#content') do + expect(page).to have_css('.pages-hierarchy') + expect(page).to have_css('.pages-hierarchy', text: 'Child page') + expect(page).to have_css('.pages-hierarchy', text: 'Parent page') + expect(page).to have_css('h1', text: 'My page') SeleniumHubWaiter.wait - find(".toolbar .icon-edit").click + find('.toolbar .icon-edit').click end end end diff --git a/spec/features/wysiwyg/macros/code_block_macro_spec.rb b/spec/features/wysiwyg/macros/code_block_macro_spec.rb index 0f7383f75d4b..3decdad4dbd2 100644 --- a/spec/features/wysiwyg/macros/code_block_macro_spec.rb +++ b/spec/features/wysiwyg/macros/code_block_macro_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg code block macro", :js do +RSpec.describe 'Wysiwyg code block macro', :js do shared_let(:admin) { create(:admin) } let(:user) { admin } let(:project) { create(:project, enabled_module_names: %w[wiki]) } @@ -54,72 +54,72 @@ def foobar login_as(user) end - describe "in wikis" do - describe "creating a wiki page" do + describe 'in wikis' do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can add and save multiple code blocks (Regression #28350)" do + it 'can add and save multiple code blocks (Regression #28350)' do editor.in_editor do |container,| editor.set_markdown expected # Expect first macro saved to editor - expect(container).to have_css(".op-uc-code-block", text: snippet) - expect(container).to have_css(".op-uc-code-block--language", text: "ruby") + expect(container).to have_css('.op-uc-code-block', text: snippet) + expect(container).to have_css('.op-uc-code-block--language', text: 'ruby') editor.set_markdown "#{expected}\n#{expected}" - expect(container).to have_css(".op-uc-code-block", text: snippet, count: 2) - expect(container).to have_css(".op-uc-code-block--language", text: "ruby", count: 2) + expect(container).to have_css('.op-uc-code-block', text: snippet, count: 2) + expect(container).to have_css('.op-uc-code-block--language', text: 'ruby', count: 2) end - click_on "Save" - expect(page).to have_css(".op-toast.-success") + click_on 'Save' + expect(page).to have_css('.op-toast.-success') # Expect output widget - within("#content") do - expect(page).to have_css("pre.highlight-ruby", count: 2) + within('#content') do + expect(page).to have_css('pre.highlight-ruby', count: 2) end SeleniumHubWaiter.wait # Edit page again, expect widget - click_on "Edit" + click_on 'Edit' # SeleniumHubWaiter.wait editor.in_editor do |container,| - expect(container).to have_css(".op-uc-code-block", text: snippet, count: 2) - expect(container).to have_css(".op-uc-code-block--language", text: "ruby", count: 2) + expect(container).to have_css('.op-uc-code-block', text: snippet, count: 2) + expect(container).to have_css('.op-uc-code-block--language', text: 'ruby', count: 2) end end - it "respects the inserted whitespace" do + it 'respects the inserted whitespace' do editor.in_editor do |container,| - editor.click_toolbar_button "Insert code snippet" + editor.click_toolbar_button 'Insert code snippet' - expect(page).to have_css(".spot-modal") + expect(page).to have_css('.spot-modal') # CM wraps an accessor to the editor instance on the outer container - cm = page.find(".CodeMirror") - page.execute_script("arguments[0].CodeMirror.setValue(arguments[1]);", cm.native, "asdf") - find(".spot-modal--submit-button").click + cm = page.find('.CodeMirror') + page.execute_script('arguments[0].CodeMirror.setValue(arguments[1]);', cm.native, 'asdf') + find('.spot-modal--submit-button').click - expect(container).to have_css(".op-uc-code-block", text: "asdf") + expect(container).to have_css('.op-uc-code-block', text: 'asdf') - click_on "Save" - expect(page).to have_css(".op-toast.-success") + click_on 'Save' + expect(page).to have_css('.op-toast.-success') wp = WikiPage.last expect(wp.text.gsub("\r\n", "\n")).to eq("```text\nasdf\n```") SeleniumHubWaiter.wait - click_on "Edit" + click_on 'Edit' editor.in_editor do |container,| - expect(container).to have_css(".op-uc-code-block", text: "asdf") + expect(container).to have_css('.op-uc-code-block', text: 'asdf') end - click_on "Save" - expect(page).to have_css(".op-toast.-success") + click_on 'Save' + expect(page).to have_css('.op-toast.-success') wp.reload # Regression added two newlines before fence here @@ -127,58 +127,58 @@ def foobar end end - it "can add and edit a code block widget" do + it 'can add and edit a code block widget' do editor.in_editor do |container,| - editor.click_toolbar_button "Insert code snippet" + editor.click_toolbar_button 'Insert code snippet' - expect(page).to have_css(".spot-modal") + expect(page).to have_css('.spot-modal') # CM wraps an accessor to the editor instance on the outer container - cm = page.find(".CodeMirror") - page.execute_script("arguments[0].CodeMirror.setValue(arguments[1]);", cm.native, snippet) + cm = page.find('.CodeMirror') + page.execute_script('arguments[0].CodeMirror.setValue(arguments[1]);', cm.native, snippet) - fill_in "selected-language", with: "ruby" + fill_in 'selected-language', with: 'ruby' # Expect some highlighting classes - expect(page).to have_css(".cm-keyword", text: "def") - expect(page).to have_css(".cm-def", text: "foobar") + expect(page).to have_css('.cm-keyword', text: 'def') + expect(page).to have_css('.cm-def', text: 'foobar') - find(".spot-modal--submit-button").click + find('.spot-modal--submit-button').click # Expect macro saved to editor - expect(container).to have_css(".op-uc-code-block", text: snippet) - expect(container).to have_css(".op-uc-code-block--language", text: "ruby") + expect(container).to have_css('.op-uc-code-block', text: snippet) + expect(container).to have_css('.op-uc-code-block--language', text: 'ruby') end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - wiki_page = project.wiki.find_page("wiki") + wiki_page = project.wiki.find_page('wiki') text = wiki_page.text.gsub(/\r\n?/, "\n") expect(text.strip).to eq(expected.strip) # Expect output widget - within("#content") do - expect(page).to have_css("pre.highlight-ruby") + within('#content') do + expect(page).to have_css('pre.highlight-ruby') end # Edit page again, expect widget SeleniumHubWaiter.wait - click_on "Edit" + click_on 'Edit' editor.in_editor do |container,| - expect(container).to have_css(".op-uc-code-block", text: snippet) - expect(container).to have_css(".op-uc-code-block--language", text: "ruby") + expect(container).to have_css('.op-uc-code-block', text: snippet) + expect(container).to have_css('.op-uc-code-block--language', text: 'ruby') - widget = container.find(".op-uc-code-block") + widget = container.find('.op-uc-code-block') page.driver.browser.action.double_click(widget.native).perform - expect(page).to have_css(".spot-modal") + expect(page).to have_css('.spot-modal') - expect(page).to have_css(".op-uc-code-block--language", text: "ruby") - expect(page).to have_css(".cm-keyword", text: "def") - expect(page).to have_css(".cm-def", text: "foobar") + expect(page).to have_css('.op-uc-code-block--language', text: 'ruby') + expect(page).to have_css('.cm-keyword', text: 'def') + expect(page).to have_css('.cm-def', text: 'foobar') end end end diff --git a/spec/features/wysiwyg/macros/embedded_tables_spec.rb b/spec/features/wysiwyg/macros/embedded_tables_spec.rb index 8408db12c87b..f02d503dad44 100644 --- a/spec/features/wysiwyg/macros/embedded_tables_spec.rb +++ b/spec/features/wysiwyg/macros/embedded_tables_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg embedded work package tables", :js do +RSpec.describe 'Wysiwyg embedded work package tables', :js do shared_let(:admin) { create(:admin) } shared_let(:type_task) { create(:type_task) } shared_let(:type_bug) { create(:type_bug) } @@ -49,49 +49,49 @@ login_as(user) end - describe "in wikis" do - describe "creating a wiki page" do + describe 'in wikis' do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can add and edit an embedded table widget" do + it 'can add and edit an embedded table widget' do editor.in_editor do |_container, editable| - editor.insert_macro "Embed work package table" + editor.insert_macro 'Embed work package table' modal.expect_open - modal.switch_to "Filters" + modal.switch_to 'Filters' filters.expect_filter_count 2 - filters.add_filter_by("Type", "is (OR)", type_task.name) + filters.add_filter_by('Type', 'is (OR)', type_task.name) - modal.switch_to "Columns" + modal.switch_to 'Columns' columns.assume_opened columns.uncheck_all save_changes: false - columns.add "ID", save_changes: false - columns.add "Subject", save_changes: false - columns.add "Type", save_changes: false - columns.expect_checked "ID" - columns.expect_checked "Subject" - columns.expect_checked "Type" + columns.add 'ID', save_changes: false + columns.add 'Subject', save_changes: false + columns.add 'Type', save_changes: false + columns.expect_checked 'ID' + columns.expect_checked 'Subject' + columns.expect_checked 'Type' # Save widget modal.save # Find widget, click to show toolbar - macro = editable.find(".ck-widget.op-uc-placeholder") + macro = editable.find('.ck-widget.op-uc-placeholder') macro.click # Edit widget again - page.find(".ck-balloon-panel .ck-button", visible: :all, text: "Edit").click + page.find('.ck-balloon-panel .ck-button', visible: :all, text: 'Edit').click modal.expect_open - modal.switch_to "Filters" + modal.switch_to 'Filters' filters.expect_filter_count 3 - modal.switch_to "Columns" + modal.switch_to 'Columns' columns.assume_opened - columns.expect_checked "ID" - columns.expect_checked "Subject" - columns.expect_checked "Type" + columns.expect_checked 'ID' + columns.expect_checked 'Subject' + columns.expect_checked 'Type' modal.cancel # Expect we can preview the table within ckeditor-augmented-textarea @@ -103,11 +103,11 @@ end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - embedded_table = Pages::EmbeddedWorkPackagesTable.new find(".wiki-content") + embedded_table = Pages::EmbeddedWorkPackagesTable.new find('.wiki-content') embedded_table.expect_work_package_listed wp_task embedded_table.ensure_work_package_not_listed! wp_bug @@ -116,57 +116,57 @@ full_view.ensure_page_loaded end - context "with a subproject that gets deleted" do + context 'with a subproject that gets deleted' do let!(:subproject) do create(:project, parent: project, enabled_module_names: %w[wiki]) end - it "can still edit the embedded table widget" do + it 'can still edit the embedded table widget' do editor.in_editor do |_container, editable| - editor.insert_macro "Embed work package table" + editor.insert_macro 'Embed work package table' modal.expect_open - modal.switch_to "Filters" + modal.switch_to 'Filters' filters.expect_filter_count 2 - filters.add_filter_by("Including subproject", "is (OR)", subproject.name, "subprojectId") + filters.add_filter_by('Including subproject', 'is (OR)', subproject.name, 'subprojectId') # Save widget modal.save # Find widget, click to show toolbar - macro = editable.find(".ck-widget.op-uc-placeholder") + macro = editable.find('.ck-widget.op-uc-placeholder') macro.click end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') # Embedded queries wikipage = project.wiki.pages.last - expect(wikipage.text).to include("subprojectId") + expect(wikipage.text).to include('subprojectId') # Delete the project subproject.destroy! - click_on "Edit" + click_on 'Edit' # Find widget, click to show toolbar editor.in_editor do |_container, editable| - macro = editable.find(".ck-widget.op-uc-placeholder") + macro = editable.find('.ck-widget.op-uc-placeholder') macro.click end # Edit widget again - page.find(".ck-balloon-panel .ck-button", visible: :all, text: "Edit").click + page.find('.ck-balloon-panel .ck-button', visible: :all, text: 'Edit').click modal.expect_open - modal.switch_to "Filters" + modal.switch_to 'Filters' # Subproject filter is gone filters.expect_filter_count 2 - expect(page).to have_no_text "Subproject" + expect(page).to have_no_text 'Subproject' end end end diff --git a/spec/features/wysiwyg/macros/quicklink_macros_spec.rb b/spec/features/wysiwyg/macros/quicklink_macros_spec.rb index a9b4d44cae72..58919f33de3e 100644 --- a/spec/features/wysiwyg/macros/quicklink_macros_spec.rb +++ b/spec/features/wysiwyg/macros/quicklink_macros_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg work package quicklink macros", :js do +RSpec.describe 'Wysiwyg work package quicklink macros', :js do shared_let(:user) { create(:admin) } shared_let(:project) { create(:project_with_types) } let(:work_package) do create(:work_package, subject: "My subject", - start_date: Date.parse("2020-01-01"), - due_date: Date.parse("2020-02-01")) + start_date: Date.parse('2020-01-01'), + due_date: Date.parse('2020-02-01')) end let(:editor) { Components::WysiwygEditor.new } @@ -46,72 +46,72 @@ visit project_wiki_path(project, :wiki) end - it "renders work package quicklink macro # with id linking to work package" do + it 'renders work package quicklink macro # with id linking to work package' do editor.set_markdown "##{work_package.id}" - click_on "Save" + click_on 'Save' # Expect output widget - within("#content") do + within('#content') do expect(page).to have_link("##{work_package.id}") - expect(page).to have_no_css(".work-package--quickinfo.preview-trigger") + expect(page).to have_no_css('.work-package--quickinfo.preview-trigger') end # Edit page again - click_on "Edit" + click_on 'Edit' editor.in_editor do |container,| - expect(container).to have_css("p", text: "##{work_package.id}") + expect(container).to have_css('p', text: "##{work_package.id}") end end - it "renders work package quicklink macro ## with id link, subject and type" do + it 'renders work package quicklink macro ## with id link, subject and type' do editor.set_markdown "###{work_package.id}" - click_on "Save" + click_on 'Save' # Expect output widget - within("#content") do + within('#content') do expected_macro_text = "#{work_package.type.name.upcase} ##{work_package.id}: My subject" - expect(page).to have_css("opce-macro-wp-quickinfo", text: expected_macro_text) - expect(page).to have_css("span", text: work_package.type.name.upcase) - expect(page).to have_css(".work-package--quickinfo.preview-trigger", text: "##{work_package.id}") - expect(page).to have_css("span", text: "My subject") + expect(page).to have_css('opce-macro-wp-quickinfo', text: expected_macro_text) + expect(page).to have_css('span', text: work_package.type.name.upcase) + expect(page).to have_css('.work-package--quickinfo.preview-trigger', text: "##{work_package.id}") + expect(page).to have_css('span', text: 'My subject') end # Edit page again - click_on "Edit" + click_on 'Edit' editor.in_editor do |container,| - expect(container).to have_css("p", text: "###{work_package.id}") + expect(container).to have_css('p', text: "###{work_package.id}") end end - it "renders work package quicklink macro ### with id link, subject, type, status, and dates" do + it 'renders work package quicklink macro ### with id link, subject, type, status, and dates' do editor.set_markdown "####{work_package.id}" - click_on "Save" + click_on 'Save' # Expect output widget - within("#content") do + within('#content') do expected_macro_text = "#{work_package.status.name}#{work_package.type.name.upcase} " \ "##{work_package.id}: My subject (01/01/2020 - 02/01/2020)" - expect(page).to have_css("opce-macro-wp-quickinfo", text: expected_macro_text) - expect(page).to have_css("span", text: work_package.status.name) - expect(page).to have_css("span", text: work_package.type.name.upcase) - expect(page).to have_css(".work-package--quickinfo.preview-trigger", text: "##{work_package.id}") - expect(page).to have_css("span", text: "My subject") + expect(page).to have_css('opce-macro-wp-quickinfo', text: expected_macro_text) + expect(page).to have_css('span', text: work_package.status.name) + expect(page).to have_css('span', text: work_package.type.name.upcase) + expect(page).to have_css('.work-package--quickinfo.preview-trigger', text: "##{work_package.id}") + expect(page).to have_css('span', text: 'My subject') # Dates are being rendered in two nested spans - expect(page).to have_css("span", text: "01/01/2020", count: 2) - expect(page).to have_css("span", text: "02/01/2020", count: 2) + expect(page).to have_css('span', text: '01/01/2020', count: 2) + expect(page).to have_css('span', text: '02/01/2020', count: 2) end # Edit page again - click_on "Edit" + click_on 'Edit' editor.in_editor do |container,| - expect(container).to have_css("p", text: "####{work_package.id}") + expect(container).to have_css('p', text: "####{work_package.id}") end end - it "displays dates with work package detailed link macro only if a date is present" do + it 'displays dates with work package detailed link macro only if a date is present' do wp_no_dates = create(:work_package, subject: "No dates", @@ -120,24 +120,24 @@ wp_start_date_only = create(:work_package, subject: "Start date only", - start_date: Date.parse("2020-01-01"), + start_date: Date.parse('2020-01-01'), due_date: nil) wp_end_date_only = create(:work_package, subject: "End date only", start_date: nil, - due_date: Date.parse("2020-12-31")) + due_date: Date.parse('2020-12-31')) wp_both_dates = create(:work_package, subject: "Both dates", - start_date: Date.parse("2020-01-01"), - due_date: Date.parse("2020-12-31")) + start_date: Date.parse('2020-01-01'), + due_date: Date.parse('2020-12-31')) wp_milestone_with_date = create(:work_package, :is_milestone, subject: "Milestone with date", - start_date: Date.parse("2020-01-01"), - due_date: Date.parse("2020-01-01")) + start_date: Date.parse('2020-01-01'), + due_date: Date.parse('2020-01-01')) wp_milestone_without_date = create(:work_package, :is_milestone, @@ -159,15 +159,15 @@ ####{wp_milestone_without_date.id} MD - click_on "Save" + click_on 'Save' - within("#content") do - expect(page).to have_css("opce-macro-wp-quickinfo", text: /No dates$/) - expect(page).to have_css("opce-macro-wp-quickinfo", text: "Start date only (01/01/2020 - no finish date)") - expect(page).to have_css("opce-macro-wp-quickinfo", text: "End date only (no start date - 12/31/2020)") - expect(page).to have_css("opce-macro-wp-quickinfo", text: "Both dates (01/01/2020 - 12/31/2020)") - expect(page).to have_css("opce-macro-wp-quickinfo", text: "Milestone with date (01/01/2020)") - expect(page).to have_css("opce-macro-wp-quickinfo", text: /Milestone without date$/) + within('#content') do + expect(page).to have_css('opce-macro-wp-quickinfo', text: /No dates$/) + expect(page).to have_css('opce-macro-wp-quickinfo', text: 'Start date only (01/01/2020 - no finish date)') + expect(page).to have_css('opce-macro-wp-quickinfo', text: 'End date only (no start date - 12/31/2020)') + expect(page).to have_css('opce-macro-wp-quickinfo', text: 'Both dates (01/01/2020 - 12/31/2020)') + expect(page).to have_css('opce-macro-wp-quickinfo', text: 'Milestone with date (01/01/2020)') + expect(page).to have_css('opce-macro-wp-quickinfo', text: /Milestone without date$/) end end end diff --git a/spec/features/wysiwyg/macros/work_package_button_spec.rb b/spec/features/wysiwyg/macros/work_package_button_spec.rb index a57249f675e6..d8d601041d76 100644 --- a/spec/features/wysiwyg/macros/work_package_button_spec.rb +++ b/spec/features/wysiwyg/macros/work_package_button_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg work package button spec", :js do +RSpec.describe 'Wysiwyg work package button spec', :js do shared_let(:admin) { create(:admin) } let(:user) { admin } - let!(:type) { create(:type, name: "MyTaskName") } + let!(:type) { create(:type, name: 'MyTaskName') } let(:project) do create(:valid_project, - identifier: "my-project", + identifier: 'my-project', enabled_module_names: %w[wiki work_package_tracking], - name: "My project name", + name: 'My project name', types: [type]) end @@ -47,47 +47,47 @@ login_as(user) end - describe "in wikis" do - describe "creating a wiki page" do + describe 'in wikis' do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can add and edit an embedded table widget" do + it 'can add and edit an embedded table widget' do editor.in_editor do |_container, editable| - editor.insert_macro "Insert create work package button" + editor.insert_macro 'Insert create work package button' - expect(page).to have_css(".spot-modal") - select "MyTaskName", from: "selected-type" + expect(page).to have_css('.spot-modal') + select 'MyTaskName', from: 'selected-type' # Cancel editing - find(".spot-modal--cancel-button").click - expect(editable).to have_no_css(".macro.-create_work_package_link") + find('.spot-modal--cancel-button').click + expect(editable).to have_no_css('.macro.-create_work_package_link') - editor.insert_macro "Insert create work package button" - select "MyTaskName", from: "selected-type" - check "button_style" + editor.insert_macro 'Insert create work package button' + select 'MyTaskName', from: 'selected-type' + check 'button_style' # Save widget - find(".spot-modal--submit-button").click + find('.spot-modal--submit-button').click # Find widget, click to show toolbar - modal = find(".button.op-uc-placeholder", text: "Create work package") + modal = find('.button.op-uc-placeholder', text: 'Create work package') # Edit widget again modal.click - page.find(".ck-balloon-panel .ck-button", visible: :all, text: "Edit").click - expect(page).to have_checked_field("wp_button_macro_style") - expect(page).to have_select("selected-type", selected: "MyTaskName") - find(".spot-modal--cancel-button").click + page.find('.ck-balloon-panel .ck-button', visible: :all, text: 'Edit').click + expect(page).to have_checked_field('wp_button_macro_style') + expect(page).to have_select('selected-type', selected: 'MyTaskName') + find('.spot-modal--cancel-button').click end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do + within('#content') do expect(page).to have_css("a[href=\"/projects/my-project/work_packages/new?type=#{type.id}\"]") end end diff --git a/spec/features/wysiwyg/mentions_spec.rb b/spec/features/wysiwyg/mentions_spec.rb index e202759fd8e0..4836f3617c04 100644 --- a/spec/features/wysiwyg/mentions_spec.rb +++ b/spec/features/wysiwyg/mentions_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg work package mentions", +RSpec.describe 'Wysiwyg work package mentions', :js, :with_cuprite do let!(:user) do - create(:admin, firstname: "MeMyself", lastname: "AndI", + create(:admin, firstname: 'MeMyself', lastname: 'AndI', member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) end let!(:user2) do - create(:user, firstname: "Foo", lastname: "Bar", + create(:user, firstname: 'Foo', lastname: 'Bar', member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) end let!(:edit_work_package_role) { create(:edit_work_package_role) } @@ -44,19 +44,19 @@ let!(:view_work_package_role) { create(:view_work_package_role) } let!(:work_package_editor) do - create(:user, firstname: "Bertram", lastname: "Gilfoyle", + create(:user, firstname: 'Bertram', lastname: 'Gilfoyle', member_with_roles: { work_package => edit_work_package_role }) end let!(:work_package_commenter) do - create(:user, firstname: "Dinesh", lastname: "Chugtai", + create(:user, firstname: 'Dinesh', lastname: 'Chugtai', member_with_roles: { work_package => comment_work_package_role }) end let!(:work_package_viewer) do - create(:user, firstname: "Richard", lastname: "Hendricks", + create(:user, firstname: 'Richard', lastname: 'Hendricks', member_with_roles: { work_package => view_work_package_role }) end - let!(:group) { create(:group, firstname: "Foogroup", lastname: "Foogroup") } + let!(:group) { create(:group, firstname: 'Foogroup', lastname: 'Foogroup') } let!(:group_role) { create(:project_role) } let!(:group_member) do create(:member, @@ -67,17 +67,17 @@ let(:project) { create(:project, enabled_module_names: %w[work_package_tracking]) } let!(:work_package) do User.execute_as user do - create(:work_package, subject: "Foobar", project:) + create(:work_package, subject: 'Foobar', project:) end end let(:wp_page) { Pages::FullWorkPackage.new work_package, project } let(:editor) { Components::WysiwygEditor.new } - let(:selector) { ".work-packages--activity--add-comment" } + let(:selector) { '.work-packages--activity--add-comment' } let(:comment_field) do TextEditorField.new wp_page, - "comment", + 'comment', selector: end @@ -88,45 +88,45 @@ expect_angular_frontend_initialized end - it "can autocomplete users, groups and emojis" do + it 'can autocomplete users, groups and emojis' do # Mentioning a user works comment_field.activate! comment_field.clear with_backspace: true comment_field.input_element.send_keys("@Foo") - expect(page).to have_css(".mention-list-item", text: user2.name) - expect(page).to have_css(".mention-list-item", text: group.name) + expect(page).to have_css('.mention-list-item', text: user2.name) + expect(page).to have_css('.mention-list-item', text: group.name) - page.find(".mention-list-item", text: user2.name).click + page.find('.mention-list-item', text: user2.name).click expect(page) - .to have_css("a.mention", text: "@Foo Bar") + .to have_css('a.mention', text: '@Foo Bar') comment_field.submit_by_click if comment_field.active? wp_page.expect_and_dismiss_toaster message: "The comment was successfully added." expect(page) - .to have_css("a.user-mention", text: "Foo Bar") + .to have_css('a.user-mention', text: 'Foo Bar') # Mentioning myself works comment_field.activate! comment_field.clear with_backspace: true comment_field.input_element.send_keys("@MeMyself") - expect(page).to have_css(".mention-list-item", text: user.name) + expect(page).to have_css('.mention-list-item', text: user.name) - page.find(".mention-list-item", text: user.name).click + page.find('.mention-list-item', text: user.name).click expect(page) - .to have_css("a.mention", text: "@MeMyself AndI") + .to have_css('a.mention', text: '@MeMyself AndI') comment_field.submit_by_click if comment_field.active? wp_page.expect_and_dismiss_toaster message: "The comment was successfully added." expect(page) - .to have_css("a.user-mention", text: "MeMyself AndI") + .to have_css('a.user-mention', text: 'MeMyself AndI') # Mentioning a work package editor or commenter works # @@ -137,12 +137,12 @@ comment_field.input_element.send_keys("@Bertram Gilfoyle") page.find(".mention-list-item", text: work_package_editor.name).click expect(page) - .to have_css("a.mention", text: "@Bertram Gilfoyle") + .to have_css('a.mention', text: "@Bertram Gilfoyle") comment_field.submit_by_click if comment_field.active? wp_page.expect_and_dismiss_toaster message: "The comment was successfully added." expect(page) - .to have_css("a.user-mention", text: "Bertram Gilfoyle") + .to have_css('a.user-mention', text: 'Bertram Gilfoyle') # # Commenter # @@ -151,12 +151,12 @@ comment_field.input_element.send_keys("@Dinesh Chugtai") page.find(".mention-list-item", text: work_package_commenter.name).click expect(page) - .to have_css("a.mention", text: "@Dinesh Chugtai") + .to have_css('a.mention', text: "@Dinesh Chugtai") comment_field.submit_by_click if comment_field.active? wp_page.expect_and_dismiss_toaster message: "The comment was successfully added." expect(page) - .to have_css("a.user-mention", text: "Dinesh Chugtai") + .to have_css('a.user-mention', text: 'Dinesh Chugtai') # Work Package viewers aren't mentionable comment_field.activate! @@ -171,41 +171,41 @@ comment_field.activate! comment_field.clear with_backspace: true comment_field.input_element.send_keys(" @Foo") - expect(page).to have_css(".mention-list-item", text: user2.name) - expect(page).to have_css(".mention-list-item", text: group.name) + expect(page).to have_css('.mention-list-item', text: user2.name) + expect(page).to have_css('.mention-list-item', text: group.name) - page.find(".mention-list-item", text: group.name).click + page.find('.mention-list-item', text: group.name).click expect(page) - .to have_css("a.mention", text: "@Foogroup") + .to have_css('a.mention', text: '@Foogroup') comment_field.submit_by_click if comment_field.active? wp_page.expect_and_dismiss_toaster message: "The comment was successfully added." expect(page) - .to have_css("a.user-mention", text: "Foogroup") + .to have_css('a.user-mention', text: 'Foogroup') # The mention is still displayed as such when reentering the comment field - find("#activity-1 .op-user-activity") + find('#activity-1 .op-user-activity') .hover - within("#activity-1") do + within('#activity-1') do click_button("Edit this comment") end expect(page) - .to have_css("a.mention", text: "@Foo Bar") + .to have_css('a.mention', text: '@Foo Bar') # Mentioning an emoji works comment_field.activate! comment_field.clear with_backspace: true comment_field.input_element.send_keys(":thumbs") - expect(page).to have_css(".mention-list-item", text: "👍 thumbs_up") - expect(page).to have_css(".mention-list-item", text: "👎 thumbs_down") + expect(page).to have_css('.mention-list-item', text: '👍 thumbs_up') + expect(page).to have_css('.mention-list-item', text: '👎 thumbs_down') - page.find(".mention-list-item", text: "👍 thumbs_up").click + page.find('.mention-list-item', text: '👍 thumbs_up').click - expect(page).to have_css("span", text: "👍") + expect(page).to have_css('span', text: '👍') end end diff --git a/spec/features/wysiwyg/paragraphs_in_lists_spec.rb b/spec/features/wysiwyg/paragraphs_in_lists_spec.rb index 94024dfa181d..d808753f6aa6 100644 --- a/spec/features/wysiwyg/paragraphs_in_lists_spec.rb +++ b/spec/features/wysiwyg/paragraphs_in_lists_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg paragraphs in lists behavior (Regression #28765)", :js do +RSpec.describe 'Wysiwyg paragraphs in lists behavior (Regression #28765)', :js do let(:user) { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[wiki]) } let(:editor) { Components::WysiwygEditor.new } @@ -57,10 +57,10 @@ visit edit_project_wiki_path(project, wiki_page.slug) end - it "shows the list correctly" do + it 'shows the list correctly' do editor.in_editor do |_container, editable| - expect(editable).to have_css("ol li", count: 3) - expect(editable).to have_no_css("ol li p") + expect(editable).to have_css('ol li', count: 3) + expect(editable).to have_no_css('ol li p') end end end diff --git a/spec/features/wysiwyg/tables_spec.rb b/spec/features/wysiwyg/tables_spec.rb index 8f927d97dff6..1dd848d0af61 100644 --- a/spec/features/wysiwyg/tables_spec.rb +++ b/spec/features/wysiwyg/tables_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg tables", :js do +RSpec.describe 'Wysiwyg tables', :js do shared_let(:admin) { create(:admin) } let(:user) { admin } @@ -39,21 +39,21 @@ login_as(user) end - describe "in wikis" do - describe "creating a wiki page" do + describe 'in wikis' do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can add tables without headers" do + it 'can add tables without headers' do editor.in_editor do |container, editable| # strangely, we need visible: :all here - container.find(".ck-button", visible: :all, text: "Insert table").click + container.find('.ck-button', visible: :all, text: 'Insert table').click # 2x2 - container.find(".ck-insert-table-dropdown-grid-box:nth-of-type(12)").click + container.find('.ck-insert-table-dropdown-grid-box:nth-of-type(12)').click # Edit table - tds = editable.all(".op-uc-table .op-uc-table--cell") + tds = editable.all('.op-uc-table .op-uc-table--cell') expect(tds.length).to eq(4) values = %w(h1 h&2 c1 c&2) @@ -65,26 +65,26 @@ end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css("table td", text: "h1") - expect(page).to have_css("table td", text: "h&2") - expect(page).to have_css("table td", text: "c1") - expect(page).to have_css("table td", text: "c&2") + within('#content') do + expect(page).to have_css('table td', text: 'h1') + expect(page).to have_css('table td', text: 'h&2') + expect(page).to have_css('table td', text: 'c1') + expect(page).to have_css('table td', text: 'c&2') end end - it "can add tables with headers" do + it 'can add tables with headers' do editor.in_editor do |container, editable| - editor.click_toolbar_button "Insert table" + editor.click_toolbar_button 'Insert table' # 2x2 - container.find(".ck-insert-table-dropdown-grid-box:nth-of-type(12)").click + container.find('.ck-insert-table-dropdown-grid-box:nth-of-type(12)').click # Edit table - tds = editable.all(".op-uc-table .op-uc-table--cell") + tds = editable.all('.op-uc-table .op-uc-table--cell') values = %w(h1 h2 a) expect(tds.length).to eq(4) @@ -99,55 +99,55 @@ tds.first.send_keys :tab # Click row toolbar - editor.click_hover_toolbar_button "Row" + editor.click_hover_toolbar_button 'Row' # Enable header row - header_button = find(".ck-switchbutton", text: "Header row") - header_button.find(".ck-button__toggle").click + header_button = find('.ck-switchbutton', text: 'Header row') + header_button.find('.ck-button__toggle').click # Table should now have header - expect(editable).to have_css("th", count: 2) - expect(editable).to have_css("td", count: 2) - expect(editable).to have_css("th", text: "h1") - expect(editable).to have_css("th", text: "h2") - expect(editable).to have_css("td", text: "a") + expect(editable).to have_css('th', count: 2) + expect(editable).to have_css('td', count: 2) + expect(editable).to have_css('th', text: 'h1') + expect(editable).to have_css('th', text: 'h2') + expect(editable).to have_css('td', text: 'a') end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css("table th", text: "h1") - expect(page).to have_css("table th", text: "h2") - expect(page).to have_css("table td", count: 2) - expect(page).to have_css("td", text: "a") + within('#content') do + expect(page).to have_css('table th', text: 'h1') + expect(page).to have_css('table th', text: 'h2') + expect(page).to have_css('table td', count: 2) + expect(page).to have_css('td', text: 'a') end SeleniumHubWaiter.wait # Edit again - click_on "Edit" + click_on 'Edit' editor.in_editor do |_container, editable| # Table should still have header - expect(editable).to have_css("th", count: 2) - expect(editable).to have_css("td", count: 2) - expect(editable).to have_css("th", text: "h1") - expect(editable).to have_css("th", text: "h2") - expect(editable).to have_css("td", text: "a") + expect(editable).to have_css('th', count: 2) + expect(editable).to have_css('td', count: 2) + expect(editable).to have_css('th', text: 'h1') + expect(editable).to have_css('th', text: 'h2') + expect(editable).to have_css('td', text: 'a') end end - it "can add styled tables" do + it 'can add styled tables' do editor.in_editor do |container, editable| # strangely, we need visible: :all here - editor.click_toolbar_button "Insert table" + editor.click_toolbar_button 'Insert table' # 2x2 - container.find(".ck-insert-table-dropdown-grid-box:nth-of-type(12)").click + container.find('.ck-insert-table-dropdown-grid-box:nth-of-type(12)').click # Edit table - tds = editable.all(".op-uc-table .op-uc-table--cell") + tds = editable.all('.op-uc-table .op-uc-table--cell') expect(tds.length).to eq(4) values = %w(h1 h2 a) @@ -161,16 +161,16 @@ tds.first.click # Click row toolbar - editor.click_hover_toolbar_button "Cell properties" + editor.click_hover_toolbar_button 'Cell properties' # Enable header row - expect(page).to have_css(".ck-input-color input", count: 2) + expect(page).to have_css('.ck-input-color input', count: 2) # Pick the latter one, it's the background color - page.all(".ck-input-color input").last.set "#123456" + page.all('.ck-input-color input').last.set '#123456' # Set vertical center / horizontal top - editor.click_hover_toolbar_button "Align cell text to the center" - editor.click_hover_toolbar_button "Align cell text to the top" - find(".ck-button-save").click + editor.click_hover_toolbar_button 'Align cell text to the center' + editor.click_hover_toolbar_button 'Align cell text to the top' + find('.ck-button-save').click # Table should now have header expect(editable).to have_css('td[style*="background-color:#123456"]') @@ -179,11 +179,11 @@ end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do + within('#content') do expect(page).to have_css('td[style*="background-color:#123456"]') expect(page).to have_css('td[style*="text-align:center"]') expect(page).to have_css('td[style*="vertical-align:top"]') @@ -191,33 +191,33 @@ SeleniumHubWaiter.wait # Edit again - click_on "Edit" + click_on 'Edit' editor.in_editor do |_container, editable| expect(editable).to have_css('td[style*="background-color:#123456"]') # Change table styles - tds = editable.all(".op-uc-table .op-uc-table--cell") + tds = editable.all('.op-uc-table .op-uc-table--cell') # For some reason, the entire table is still selected so use tab to move to the next cell tds[0].click tds[0].send_keys :tab - editor.click_hover_toolbar_button "Table properties" + editor.click_hover_toolbar_button 'Table properties' # Set style to dotted - page.find(".ck-table-form__border-style").click - page.find(".ck-button_with-text", text: "Dotted").click - page.find(".ck-table-form__border-row .ck-input-color").set "black" - page.find(".ck-table-form__border-width .ck-input-text").set "10px" + page.find('.ck-table-form__border-style').click + page.find('.ck-button_with-text', text: 'Dotted').click + page.find('.ck-table-form__border-row .ck-input-color').set 'black' + page.find('.ck-table-form__border-width .ck-input-text').set '10px' # background - page.find(".ck-table-properties-form__background .ck-input-text").set "red" + page.find('.ck-table-properties-form__background .ck-input-text').set 'red' # width, height - page.find(".ck-table-form__dimensions-row__width .ck-input-text").set "500px" - page.find(".ck-table-form__dimensions-row__height .ck-input-text").set "500px" - find(".ck-button-save").click + page.find('.ck-table-form__dimensions-row__width .ck-input-text').set '500px' + page.find('.ck-table-form__dimensions-row__height .ck-input-text').set '500px' + find('.ck-button-save').click # table height and width is set on figure expect(editable).to have_css('figure[style*="width:500px"]') @@ -230,11 +230,11 @@ end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do + within('#content') do # table height and width is set on figure expect(page).to have_css('figure[style*="width:500px"]') expect(page).to have_css('figure[style*="height:500px"]') @@ -246,7 +246,7 @@ end # Edit again - click_on "Edit" + click_on 'Edit' # Expect all previous changes to be there editor.in_editor do |_container, editable| @@ -263,15 +263,15 @@ end end - it "can restrict table cell width" do + it 'can restrict table cell width' do editor.in_editor do |container, editable| # strangely, we need visible: :all here - editor.click_toolbar_button "Insert table" + editor.click_toolbar_button 'Insert table' # 2x2 - container.find(".ck-insert-table-dropdown-grid-box:nth-of-type(12)").click + container.find('.ck-insert-table-dropdown-grid-box:nth-of-type(12)').click # Edit table - tds = editable.all(".op-uc-table .op-uc-table--cell") + tds = editable.all('.op-uc-table .op-uc-table--cell') expect(tds.length).to eq(4) values = %w(h1 h2 a) @@ -285,27 +285,27 @@ tds.first.click # Click row toolbar - editor.click_hover_toolbar_button "Cell properties" + editor.click_hover_toolbar_button 'Cell properties' # Enable header row - find(".ck-table-form__dimensions-row__width input").set "250px" - find(".ck-button-save").click + find('.ck-table-form__dimensions-row__width input').set '250px' + find('.ck-button-save').click expect(editable).to have_css('td[style*="width:250px"]') end # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do + within('#content') do expect(page).to have_css('td[style*="width:250px"]') end SeleniumHubWaiter.wait # Edit again - click_on "Edit" + click_on 'Edit' editor.in_editor do |_container, editable| expect(editable).to have_css('td[style*="width:250px"]') @@ -313,10 +313,10 @@ end end - describe "editing a wiki page with tables" do + describe 'editing a wiki page with tables' do let(:wiki_page) do page = build(:wiki_page, - title: "Wiki page with titles") + title: 'Wiki page with titles') page.text = <<~MARKDOWN ## This is markdown! @@ -351,31 +351,31 @@ visit project_wiki_path(project, wiki_page.slug) end - it "can show the table with header" do - within("#content") do - expect(page).to have_css("h2", text: "This is markdown") + it 'can show the table with header' do + within('#content') do + expect(page).to have_css('h2', text: 'This is markdown') - expect(page).to have_css("table thead th", text: "A") - expect(page).to have_css("table thead th", text: "B") - expect(page).to have_css("table td", text: "c1") - expect(page).to have_css("table td", text: "c2") - expect(page).to have_css("table td", text: "c3") - expect(page).to have_css("table td", text: "c4") + expect(page).to have_css('table thead th', text: 'A') + expect(page).to have_css('table thead th', text: 'B') + expect(page).to have_css('table td', text: 'c1') + expect(page).to have_css('table td', text: 'c2') + expect(page).to have_css('table td', text: 'c3') + expect(page).to have_css('table td', text: 'c4') end # Edit the table - click_on "Edit" + click_on 'Edit' # Expect wysiwyg to render table editor.in_editor do |_, editable| - expect(editable).to have_css("h2", text: "This is markdown") - - expect(editable).to have_css("table thead th", text: "A") - expect(editable).to have_css("table thead th", text: "B") - expect(editable).to have_css("table td", text: "c1") - expect(editable).to have_css("table td", text: "c2") - expect(editable).to have_css("table td", text: "c3") - expect(editable).to have_css("table td", text: "c4") + expect(editable).to have_css('h2', text: 'This is markdown') + + expect(editable).to have_css('table thead th', text: 'A') + expect(editable).to have_css('table thead th', text: 'B') + expect(editable).to have_css('table td', text: 'c1') + expect(editable).to have_css('table td', text: 'c2') + expect(editable).to have_css('table td', text: 'c3') + expect(editable).to have_css('table td', text: 'c4') end end end diff --git a/spec/features/wysiwyg/ui_localization_spec.rb b/spec/features/wysiwyg/ui_localization_spec.rb index f6ede3559ce1..1c0756ad0e72 100644 --- a/spec/features/wysiwyg/ui_localization_spec.rb +++ b/spec/features/wysiwyg/ui_localization_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "WYSIWYG UI localization", :js do +RSpec.describe 'WYSIWYG UI localization', :js do let(:user) { create(:admin, language:) } let(:project) { create(:project, enabled_module_names: %w[wiki]) } let(:editor) { Components::WysiwygEditor.new } @@ -52,19 +52,19 @@ visit edit_project_wiki_path(project, wiki_page.slug) end - context "with german locale" do + context 'with german locale' do let(:language) { :de } - it "renders the UI in German" do - expect(page).to have_css(".ck-button__label", text: "Absatz") + it 'renders the UI in German' do + expect(page).to have_css('.ck-button__label', text: 'Absatz') end end - context "with english locale" do + context 'with english locale' do let(:language) { :en } - it "renders the UI in English" do - expect(page).to have_css(".ck-button__label", text: "Paragraph") + it 'renders the UI in English' do + expect(page).to have_css('.ck-button__label', text: 'Paragraph') end end end diff --git a/spec/features/wysiwyg/work_package_linking_spec.rb b/spec/features/wysiwyg/work_package_linking_spec.rb index fbd2f3f133de..97bbc66084df 100644 --- a/spec/features/wysiwyg/work_package_linking_spec.rb +++ b/spec/features/wysiwyg/work_package_linking_spec.rb @@ -26,37 +26,37 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Wysiwyg work package linking", :js do +RSpec.describe 'Wysiwyg work package linking', :js do let(:user) { create(:admin) } let(:project) { create(:project, enabled_module_names: %w[wiki work_package_tracking]) } - let(:work_package) { create(:work_package, subject: "Foobar", project:) } + let(:work_package) { create(:work_package, subject: 'Foobar', project:) } let(:editor) { Components::WysiwygEditor.new } before do login_as(user) end - describe "creating a wiki page" do + describe 'creating a wiki page' do before do visit project_wiki_path(project, :wiki) end - it "can reference work packages" do + it 'can reference work packages' do # single hash autocomplete editor.click_and_type_slowly "##{work_package.id}" editor.click_autocomplete work_package.subject - expect(editor.editor_element).to have_css("a.mention", text: "##{work_package.id}") + expect(editor.editor_element).to have_css('a.mention', text: "##{work_package.id}") # Save wiki page - click_on "Save" + click_on 'Save' - expect(page).to have_css(".op-toast.-success") + expect(page).to have_css('.op-toast.-success') - within("#content") do - expect(page).to have_css("a.issue", count: 1) + within('#content') do + expect(page).to have_css('a.issue', count: 1) end end end diff --git a/spec/helpers/additional_url_helper_spec.rb b/spec/helpers/additional_url_helper_spec.rb index 8fe015d39c5a..3106ed0e7d0b 100644 --- a/spec/helpers/additional_url_helper_spec.rb +++ b/spec/helpers/additional_url_helper_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AdditionalUrlHelpers do - describe "#configurable_home_url" do + describe '#configurable_home_url' do subject { helper.send :configurable_home_url } - context "when home_url is defined", with_settings: { home_url: "https://example.com/foo/bar" } do - it "outputs that" do - expect(subject).to eq "https://example.com/foo/bar" + context 'when home_url is defined', with_settings: { home_url: 'https://example.com/foo/bar' } do + it 'outputs that' do + expect(subject).to eq 'https://example.com/foo/bar' end end - context "when home_url is not defined", with_settings: { home_url: nil } do - it "falls back to the default" do - expect(subject).to eq "http://test.host/" + context 'when home_url is not defined', with_settings: { home_url: nil } do + it 'falls back to the default' do + expect(subject).to eq 'http://test.host/' end end end diff --git a/spec/helpers/angular_helper_spec.rb b/spec/helpers/angular_helper_spec.rb index 44df8dd34468..ae0127ccf993 100644 --- a/spec/helpers/angular_helper_spec.rb +++ b/spec/helpers/angular_helper_spec.rb @@ -26,32 +26,32 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AngularHelper do - let(:tag_name) { "op-test" } + let(:tag_name) { 'op-test' } let(:options) do { - class: "op-classname", + class: 'op-classname', inputs:, data: } end let(:data) do { - "test-selector": "foo" + 'test-selector': 'foo' } end subject { helper.angular_component_tag tag_name, options } - describe "inputs transformations" do + describe 'inputs transformations' do let(:inputs) do { - key: "value", + key: 'value', number: 1, anArray: [1, 2, 3], - someRandomObject: { complex: true, foo: "bar" } + someRandomObject: { complex: true, foo: 'bar' } } end @@ -68,7 +68,7 @@ HTML end - it "converts the inputs" do + it 'converts the inputs' do expect(subject).to be_html_eql(expected) end end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index a0aff1dc44e0..60661df54c3d 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ApplicationHelper do - describe ".link_to_if_authorized" do + describe '.link_to_if_authorized' do let(:project) { create(:valid_project) } let(:project_member) do create(:user, @@ -43,15 +43,15 @@ type: project.types.first) end - context "if user is authorized" do + context 'if user is authorized' do before do expect(self).to receive(:authorize_for).and_return(true) - @response = link_to_if_authorized("link_content", { - controller: "work_packages", - action: "show", + @response = link_to_if_authorized('link_content', { + controller: 'work_packages', + action: 'show', id: issue }, - class: "fancy_css_class") + class: 'fancy_css_class') end subject { @response } @@ -61,15 +61,15 @@ it { is_expected.to match /fancy_css_class/ } end - context "if user is unauthorized" do + context 'if user is unauthorized' do before do expect(self).to receive(:authorize_for).and_return(false) - @response = link_to_if_authorized("link_content", { - controller: "work_packages", - action: "show", + @response = link_to_if_authorized('link_content', { + controller: 'work_packages', + action: 'show', id: issue }, - class: "fancy_css_class") + class: 'fancy_css_class') end subject { @response } @@ -77,12 +77,12 @@ it { is_expected.to be_nil } end - context "allow using the :controller and :action for the target link" do + context 'allow using the :controller and :action for the target link' do before do expect(self).to receive(:authorize_for).and_return(true) - @response = link_to_if_authorized("By controller/action", - controller: "work_packages", - action: "show", + @response = link_to_if_authorized('By controller/action', + controller: 'work_packages', + action: 'show', id: issue.id) end @@ -92,10 +92,10 @@ end end - describe "other_formats_links" do - context "link given" do + describe 'other_formats_links' do + context 'link given' do before do - @links = other_formats_links { |f| f.link_to "Atom", url: { controller: :projects, action: :index } } + @links = other_formats_links { |f| f.link_to 'Atom', url: { controller: :projects, action: :index } } end it { @@ -103,29 +103,29 @@ } end - context "link given but disabled" do + context 'link given but disabled' do before do allow(Setting).to receive(:feeds_enabled?).and_return(false) - @links = other_formats_links { |f| f.link_to "Atom", url: { controller: :projects, action: :index } } + @links = other_formats_links { |f| f.link_to 'Atom', url: { controller: :projects, action: :index } } end it { expect(@links).to be_nil } end end - describe "time_tag" do + describe 'time_tag' do around do |example| I18n.with_locale(:en) { example.run } end subject { time_tag(time) } - context "with project" do + context 'with project' do before do @project = build(:project) end - context "right now" do + context 'right now' do let(:time) { Time.now } it { is_expected.to match /^
    Hello
    ", lastname: "world") + describe '.authoring_at' do + it 'escapes html from author name' do + created = '2023-06-02' + author = build(:user, firstname: 'Hello', lastname: 'world') author.save! validate: false expect(authoring_at(created, author)) .to eq("Added by <b>Hello</b> world at 2023-06-02") end end - describe ".all_lang_options_for_select" do + describe '.all_lang_options_for_select' do it 'has all languages translated ("English" should appear only once)' do impostor_locales = all_lang_options_for_select - .reject { |_lang, locale| locale == "en" } + .reject { |_lang, locale| locale == 'en' } .select { |lang, _locale| lang == "English" } .map { |_lang, locale| locale } expect(impostor_locales.count).to eq(0), <<~ERR @@ -202,7 +202,7 @@ ERR end - it "has distinct languages translation" do + it 'has distinct languages translation' do duplicate_langs = all_lang_options_for_select .map { |lang, _locale| lang } diff --git a/spec/helpers/archived_projects_helper_spec.rb b/spec/helpers/archived_projects_helper_spec.rb index f799ae256e98..a11256ffceae 100644 --- a/spec/helpers/archived_projects_helper_spec.rb +++ b/spec/helpers/archived_projects_helper_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ArchivedProjectsHelper do - describe "#archived_projects_urls_for" do + describe '#archived_projects_urls_for' do subject { helper.archived_projects_urls_for([archived_project, other_archived_project]) } shared_let(:archived_project) { create(:project, :archived) } @@ -43,7 +43,7 @@ "{\"name_and_identifier\":{\"operator\":\"=\",\"values\":[\"#{other_archived_project.name}\"]}}]" end - it "returns a comma-separated list of anchor tags for each archived project" do + it 'returns a comma-separated list of anchor tags for each archived project' do expect(subject) .to eq( "" \ diff --git a/spec/helpers/custom_styles_helper_spec.rb b/spec/helpers/custom_styles_helper_spec.rb index 4ed937c4dcf3..f9a5d5a25754 100644 --- a/spec/helpers/custom_styles_helper_spec.rb +++ b/spec/helpers/custom_styles_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomStylesHelper do let(:current_theme) { nil } @@ -37,45 +37,45 @@ allow(OpenProject::Configuration).to receive(:bim?).and_return(bim_edition?) end - describe ".apply_custom_styles?" do + describe '.apply_custom_styles?' do subject { helper.apply_custom_styles? } - context "no CustomStyle present" do - it "is falsey" do + context 'no CustomStyle present' do + it 'is falsey' do expect(subject).to be_falsey end end - context "CustomStyle present" do + context 'CustomStyle present' do let(:current_theme) { build_stubbed(:custom_style) } - context "without EE", with_ee: false do - context "no BIM edition" do - it "is falsey" do + context 'without EE', with_ee: false do + context 'no BIM edition' do + it 'is falsey' do expect(subject).to be_falsey end end - context "BIM edition" do + context 'BIM edition' do let(:bim_edition?) { true } - it "is truthy" do + it 'is truthy' do expect(subject).to be_truthy end end end - context "with EE", with_ee: %i[define_custom_style] do - context "no BIM edition" do - it "is truthy" do + context 'with EE', with_ee: %i[define_custom_style] do + context 'no BIM edition' do + it 'is truthy' do expect(subject).to be_truthy end end - context "BIM edition" do + context 'BIM edition' do let(:bim_edition?) { true } - it "is truthy" do + it 'is truthy' do expect(subject).to be_truthy end end @@ -83,14 +83,14 @@ end end - shared_examples("apply when ee present") do - context "no CustomStyle present" do - it "is falsey" do + shared_examples('apply when ee present') do + context 'no CustomStyle present' do + it 'is falsey' do expect(subject).to be_falsey end end - context "CustomStyle present" do + context 'CustomStyle present' do let(:current_theme) { build_stubbed(:custom_style) } before do @@ -98,29 +98,29 @@ allow(current_theme).to receive(:touch_icon).and_return(true) end - context "without EE", with_ee: false do - it "is falsey" do + context 'without EE', with_ee: false do + it 'is falsey' do expect(subject).to be_falsey end end - context "with EE", with_ee: %i[define_custom_style] do - it "is truthy" do + context 'with EE', with_ee: %i[define_custom_style] do + it 'is truthy' do expect(subject).to be_truthy end end end end - describe ".apply_custom_favicon?" do + describe '.apply_custom_favicon?' do subject { helper.apply_custom_favicon? } - it_behaves_like "apply when ee present" + it_behaves_like 'apply when ee present' end - describe ".apply_custom_touch_icon?" do + describe '.apply_custom_touch_icon?' do subject { helper.apply_custom_touch_icon? } - it_behaves_like "apply when ee present" + it_behaves_like 'apply when ee present' end end diff --git a/spec/helpers/error_message_helper_spec.rb b/spec/helpers/error_message_helper_spec.rb index fc4eb7043db1..27f5ba39649e 100644 --- a/spec/helpers/error_message_helper_spec.rb +++ b/spec/helpers/error_message_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ErrorMessageHelper do let(:model) { WikiPage.new } @@ -35,55 +35,55 @@ def escape_html(array) array.map { CGI.escapeHTML _1 } end - shared_examples "error messages rendering" do - context "when no errors" do - it { expect(rendered).to eq("") } + shared_examples 'error messages rendering' do + context 'when no errors' do + it { expect(rendered).to eq('') } end - context "with one field error" do + context 'with one field error' do before do errors.add(:title, :blank) end - it { expect(rendered).to include(t("activerecord.errors.template.header", model: "Wiki page", count: 1)) } - it { expect(rendered).to include(t("errors.header_invalid_fields", count: 1)) } + it { expect(rendered).to include(t('activerecord.errors.template.header', model: 'Wiki page', count: 1)) } + it { expect(rendered).to include(t('errors.header_invalid_fields', count: 1)) } it { expect(rendered).to include(*escape_html(errors.full_messages)) } end - context "with two field errors" do + context 'with two field errors' do before do errors.add(:title, :blank) errors.add(:author, :blank) end - it { expect(rendered).to include(t("activerecord.errors.template.header", model: "Wiki page", count: 2)) } - it { expect(rendered).to include(t("errors.header_invalid_fields", count: 2)) } + it { expect(rendered).to include(t('activerecord.errors.template.header', model: 'Wiki page', count: 2)) } + it { expect(rendered).to include(t('errors.header_invalid_fields', count: 2)) } it { expect(rendered).to include(*escape_html(errors.full_messages)) } end - context "with one base error" do + context 'with one base error' do before do errors.add(:base, :error_unauthorized) end - it { expect(rendered).to include(t("activerecord.errors.template.header", model: "Wiki page", count: 1)) } - it { expect(rendered).not_to include(t("errors.header_invalid_fields", count: 1)) } - it { expect(rendered).not_to include(t("errors.header_additional_invalid_fields", count: 1)) } + it { expect(rendered).to include(t('activerecord.errors.template.header', model: 'Wiki page', count: 1)) } + it { expect(rendered).not_to include(t('errors.header_invalid_fields', count: 1)) } + it { expect(rendered).not_to include(t('errors.header_additional_invalid_fields', count: 1)) } it { expect(rendered).to include(*escape_html(errors.full_messages)) } end - context "with one base error and one field error" do + context 'with one base error and one field error' do before do errors.add(:base, :error_unauthorized) errors.add(:title, :blank) end - it { expect(rendered).to include(t("activerecord.errors.template.header", model: "Wiki page", count: 2)) } - it { expect(rendered).to include(t("errors.header_additional_invalid_fields", count: 1)) } + it { expect(rendered).to include(t('activerecord.errors.template.header', model: 'Wiki page', count: 2)) } + it { expect(rendered).to include(t('errors.header_additional_invalid_fields', count: 1)) } it { expect(rendered).to include(*escape_html(errors.full_messages)) } end - context "with two base errors and two field errors" do + context 'with two base errors and two field errors' do before do errors.add(:base, :error_unauthorized) errors.add(:title, :blank) @@ -91,29 +91,29 @@ def escape_html(array) errors.add(:author, :blank) end - it { expect(rendered).to include(t("activerecord.errors.template.header", model: "Wiki page", count: 4)) } - it { expect(rendered).to include(t("errors.header_additional_invalid_fields", count: 2)) } + it { expect(rendered).to include(t('activerecord.errors.template.header', model: 'Wiki page', count: 4)) } + it { expect(rendered).to include(t('errors.header_additional_invalid_fields', count: 2)) } it { expect(rendered).to include(*escape_html(errors.full_messages)) } end end - describe "#error_messages_for" do + describe '#error_messages_for' do let(:errors) { model.errors } subject(:rendered) { helper.error_messages_for(model) } - it "accesses the model from instance variables if a name is given" do + it 'accesses the model from instance variables if a name is given' do helper.instance_variable_set(:@wiki_page, model) model.errors.add(:base, :error_conflict) - expect(helper.error_messages_for("wiki_page")).to include(*escape_html(errors.full_messages)) + expect(helper.error_messages_for('wiki_page')).to include(*escape_html(errors.full_messages)) end - it "renders nothing if there is no instance variable with the given name" do + it 'renders nothing if there is no instance variable with the given name' do helper.instance_variable_set(:@wiki_page, model) model.errors.add(:base, :error_conflict) - expect(helper.error_messages_for("work_package")).to be_nil + expect(helper.error_messages_for('work_package')).to be_nil end - include_examples "error messages rendering" + include_examples 'error messages rendering' end end diff --git a/spec/helpers/frontend_asset_helper_spec.rb b/spec/helpers/frontend_asset_helper_spec.rb index 0ac08a05ff76..d38d20346658 100644 --- a/spec/helpers/frontend_asset_helper_spec.rb +++ b/spec/helpers/frontend_asset_helper_spec.rb @@ -26,46 +26,46 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe FrontendAssetHelper do - describe "#include_frontend_assets" do - context "when in development or test", - with_env: { "OPENPROJECT_DISABLE_DEV_ASSET_PROXY" => "" } do + describe '#include_frontend_assets' do + context 'when in development or test', + with_env: { 'OPENPROJECT_DISABLE_DEV_ASSET_PROXY' => '' } do before do allow(Rails.env).to receive(:production?).and_return(false) end - it "returns the proxied frontend server" do + it 'returns the proxied frontend server' do expect(helper.include_frontend_assets).to match(%r{script src="http://localhost:4200/assets/frontend/main(.*).js"}) end end - context "when in production" do + context 'when in production' do before do allow(Rails.env).to receive(:production?).and_return(true) end - it "returns the path to the asset" do + it 'returns the path to the asset' do expect(helper.include_frontend_assets).to match(%r{script src="/assets/frontend/main(.*).js"}) end - context "when using relative_url_root" do + context 'when using relative_url_root' do before do controller.config.relative_url_root = "/openproject" end - it "prepends it to the asset path" do + it 'prepends it to the asset path' do expect(helper.include_frontend_assets).to match(%r{script src="/openproject/assets/frontend/main(.*).js"}) end end - context "when using relative_url_root ending with a slash" do + context 'when using relative_url_root ending with a slash' do before do controller.config.relative_url_root = "/openproject/" end - it "prepends it to the asset path only once (bug #41428)" do + it 'prepends it to the asset path only once (bug #41428)' do expect(helper.include_frontend_assets).to match(%r{script src="/openproject/assets/frontend/main(.*).js"}) end end diff --git a/spec/helpers/hook_helper_spec.rb b/spec/helpers/hook_helper_spec.rb index c0ac787826f7..e7966cf54e75 100644 --- a/spec/helpers/hook_helper_spec.rb +++ b/spec/helpers/hook_helper_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe HookHelper do - describe "#call_hook" do - context "when called within a controller" do + describe '#call_hook' do + context 'when called within a controller' do let(:test_hook_controller_class) do # Also tests that the application controller has the model included Class.new(ApplicationController) @@ -49,7 +49,7 @@ instance_double(ActionDispatch::Request) end - it "adds to the context" do + it 'adds to the context' do allow(OpenProject::Hook) .to receive(:call_hook) @@ -64,7 +64,7 @@ end end - context "when called within a view" do + context 'when called within a view' do let(:test_hook_view_class) do # Also tests that the application controller has the model included Class.new(ActionView::Base) do @@ -73,7 +73,7 @@ end let(:instance) do test_hook_view_class - .new(ActionView::LookupContext.new(Rails.root.join("app/views")), {}, nil) + .new(ActionView::LookupContext.new(Rails.root.join('app/views')), {}, nil) .tap do |inst| inst.instance_variable_set(:@project, project) allow(inst) @@ -94,7 +94,7 @@ instance_double(ApplicationController) end - it "adds to the context" do + it 'adds to the context' do # mimics having two different classes registered for the hook allow(OpenProject::Hook) .to receive(:call_hook) diff --git a/spec/helpers/individual_principal_hooks_helper_spec.rb b/spec/helpers/individual_principal_hooks_helper_spec.rb index 6c268d76441b..8130da348177 100644 --- a/spec/helpers/individual_principal_hooks_helper_spec.rb +++ b/spec/helpers/individual_principal_hooks_helper_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe IndividualPrincipalHooksHelper do let(:user) { build(:user) } let(:placeholder_user) { build(:placeholder_user) } - describe "#individual_principal_key" do - it "returns the class name in underscore format" do + describe '#individual_principal_key' do + it 'returns the class name in underscore format' do expect(helper.individual_principal_key(user)).to be(:user) expect(helper.individual_principal_key(placeholder_user)).to be(:placeholder_user) end end - describe "#call_individual_principals_memberships_hook" do + describe '#call_individual_principals_memberships_hook' do before do allow(helper) .to receive(:call_hook) end - context "with user and without context" do - it "call call_hook with the correct arguments" do - helper.call_individual_principals_memberships_hook(user, "foo") + context 'with user and without context' do + it 'call call_hook with the correct arguments' do + helper.call_individual_principals_memberships_hook(user, 'foo') expect(helper) .to have_received(:call_hook) @@ -56,9 +56,9 @@ end end - context "with placeholder user and without context" do - it "call call_hook with the correct arguments" do - helper.call_individual_principals_memberships_hook(placeholder_user, "foo") + context 'with placeholder user and without context' do + it 'call call_hook with the correct arguments' do + helper.call_individual_principals_memberships_hook(placeholder_user, 'foo') expect(helper) .to have_received(:call_hook) @@ -67,15 +67,15 @@ end end - context "with user and with context" do - it "call call_hook with the correct arguments" do - helper.call_individual_principals_memberships_hook(user, "foo", yay: "yo") + context 'with user and with context' do + it 'call call_hook with the correct arguments' do + helper.call_individual_principals_memberships_hook(user, 'foo', yay: 'yo') expect(helper) .to have_received(:call_hook) .with(:view_users_memberships_table_foo, user:, - yay: "yo") + yay: 'yo') end end end diff --git a/spec/helpers/journals_helper_spec.rb b/spec/helpers/journals_helper_spec.rb index 8dd35375916f..1a5d20b46fae 100644 --- a/spec/helpers/journals_helper_spec.rb +++ b/spec/helpers/journals_helper_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe JournalsHelper do - describe "back_to_activity_page_url" do + describe 'back_to_activity_page_url' do { - "all" => "http://test.host/activities", - "projects/some-identifier" => "http://test.host/projects/some-identifier/activities", - "unsupported_gizmo" => nil, - "users/5" => "http://test.host/users/5", - "work_packages/42" => "http://test.host/work_packages/42", + 'all' => 'http://test.host/activities', + 'projects/some-identifier' => 'http://test.host/projects/some-identifier/activities', + 'unsupported_gizmo' => nil, + 'users/5' => 'http://test.host/users/5', + 'work_packages/42' => 'http://test.host/work_packages/42', nil => nil }.each do |activity_page, expected_url| context "when activity page is #{activity_page.inspect}" do diff --git a/spec/helpers/no_results_helper_spec.rb b/spec/helpers/no_results_helper_spec.rb index 9def7d0d2549..e26b8f230400 100644 --- a/spec/helpers/no_results_helper_spec.rb +++ b/spec/helpers/no_results_helper_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe NoResultsHelper do before do - allow(helper).to receive(:t).with(".no_results_title_text", cascade: true).and_return("Nothing here!") - allow(helper).to receive(:t).with(".no_results_content_text").and_return("Add some foo") + allow(helper).to receive(:t).with('.no_results_title_text', cascade: true).and_return("Nothing here!") + allow(helper).to receive(:t).with('.no_results_content_text').and_return("Add some foo") end - describe "#no_results_box" do + describe '#no_results_box' do it "contains the just the title" do - expect(helper.no_results_box).to have_content "Nothing here!" - expect(helper.no_results_box).to have_no_link "Add some foo" + expect(helper.no_results_box).to have_content 'Nothing here!' + expect(helper.no_results_box).to have_no_link 'Add some foo' end it "contains the title and content link" do no_results_box = helper.no_results_box(action_url: root_path, display_action: true) - expect(no_results_box).to have_content "Nothing here!" - expect(no_results_box).to have_link "Add some foo", href: "/" + expect(no_results_box).to have_content 'Nothing here!' + expect(no_results_box).to have_link 'Add some foo', href: '/' end - it "contains title and content_link with custom text" do + it 'contains title and content_link with custom text' do no_results_box = helper.no_results_box(action_url: root_path, display_action: true, - custom_title: "This is a different title about foo", - custom_action_text: "Link to nowhere") + custom_title: 'This is a different title about foo', + custom_action_text: 'Link to nowhere') - expect(no_results_box).to have_content "This is a different title about foo" - expect(no_results_box).to have_link "Link to nowhere", href: "/" + expect(no_results_box).to have_content 'This is a different title about foo' + expect(no_results_box).to have_link 'Link to nowhere', href: '/' end end end diff --git a/spec/helpers/pagination_helper_spec.rb b/spec/helpers/pagination_helper_spec.rb index 211a598597bc..718e06fc454f 100644 --- a/spec/helpers/pagination_helper_spec.rb +++ b/spec/helpers/pagination_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe PaginationHelper do let(:paginator) do @@ -45,7 +45,7 @@ paginator end - describe "#pagination_links_full" do + describe '#pagination_links_full' do let(:per_page) { 10 } let(:total_entries) { 55 } let(:offset) { 1 } @@ -59,25 +59,25 @@ allow(helper) .to receive(:params) - .and_return(ActionController::Parameters.new(controller: "work_packages", action: "index")) + .and_return(ActionController::Parameters.new(controller: 'work_packages', action: 'index')) allow(helper) .to receive(:url_options) - .and_return(url_options.merge(controller: "work_packages", action: "index")) + .and_return(url_options.merge(controller: 'work_packages', action: 'index')) end it "is inside a 'pagination' div" do - expect(pagination).to have_css("div.op-pagination") + expect(pagination).to have_css('div.op-pagination') end - it "has a next_page reference" do - expect(pagination).to have_css(".op-pagination--item_next") + it 'has a next_page reference' do + expect(pagination).to have_css('.op-pagination--item_next') end - it "does not have a previous_page reference" do - expect(pagination).to have_no_css(".op-pagination--item_prev") + it 'does not have a previous_page reference' do + expect(pagination).to have_no_css('.op-pagination--item_prev') end - it "has links to every page except the current one" do + it 'has links to every page except the current one' do (1..(total_entries / per_page)).each do |i| next if i == current_page @@ -86,23 +86,23 @@ end end - it "does not have a link to the current page" do - expect(pagination).to have_no_css("a", text: Regexp.new("^#{current_page}$")) + it 'does not have a link to the current page' do + expect(pagination).to have_no_css('a', text: Regexp.new("^#{current_page}$")) end - it "has an element for the current page" do - expect(pagination).to have_css(".op-pagination--item_current", + it 'has an element for the current page' do + expect(pagination).to have_css('.op-pagination--item_current', text: Regexp.new("^#{current_page}$")) end - it "shows the range of the entries displayed" do + it 'shows the range of the entries displayed' do range = "(#{(current_page * per_page) - per_page + 1} - " + "#{current_page * per_page}/#{total_entries})" - expect(pagination).to have_css(".op-pagination--range", text: range) + expect(pagination).to have_css('.op-pagination--range', text: range) end - it "has different urls if the params are specified as options" do - params = { controller: "work_packages", action: "index" } + it 'has different urls if the params are specified as options' do + params = { controller: 'work_packages', action: 'index' } pagination = helper.pagination_links_full(paginator, params:) @@ -115,74 +115,74 @@ end end - it "shows the available per page options" do + it 'shows the available per page options' do allow(Setting) .to receive(:per_page_options) .and_return("#{per_page},#{per_page * 10}") - expect(pagination).to have_css(".op-pagination--options") + expect(pagination).to have_css('.op-pagination--options') - expect(pagination).to have_css(".op-pagination--options .op-pagination--item_current", text: per_page) + expect(pagination).to have_css('.op-pagination--options .op-pagination--item_current', text: per_page) path = work_packages_path(page: current_page, per_page: Setting.per_page_options_array.last) expect(pagination).to have_css(".op-pagination--options a[href='#{path}']") end - describe "WHEN the first page is the current" do + describe 'WHEN the first page is the current' do let(:current_page) { 1 } - it "deactivates the previous page link" do - expect(pagination).to have_no_css(".op-pagination--item_prev") + it 'deactivates the previous page link' do + expect(pagination).to have_no_css('.op-pagination--item_prev') end - it "has a link to the next page" do + it 'has a link to the next page' do path = work_packages_path(page: current_page + 1) expect(pagination).to have_css(".op-pagination--item_next a[href='#{path}']") end end - describe "WHEN the last page is the current" do + describe 'WHEN the last page is the current' do let(:current_page) { (total_entries / per_page) + 1 } - it "deactivates the next page link" do - expect(pagination).to have_no_css(".op-pagination--item_next") + it 'deactivates the next page link' do + expect(pagination).to have_no_css('.op-pagination--item_next') end - it "has a link to the previous page" do + it 'has a link to the previous page' do path = work_packages_path(page: current_page - 1) expect(pagination).to have_css(".op-pagination--item_prev a[href='#{path}']") end end - describe "WHEN the paginated object is empty" do + describe 'WHEN the paginated object is empty' do let(:total_entries) { 0 } - it "shows no pages" do - expect(pagination).to have_no_css(".op-pagination--items .op-pagination--item") + it 'shows no pages' do + expect(pagination).to have_no_css('.op-pagination--items .op-pagination--item') end - it "shows no pagination" do - expect(pagination).to have_no_css(".op-pagination") + it 'shows no pagination' do + expect(pagination).to have_no_css('.op-pagination') end end end - describe "#page_param" do - it "returns page if provided and sensible" do + describe '#page_param' do + it 'returns page if provided and sensible' do page = 2 expect(page_param(page:)).to eq(page) end - it "returns default page 1 if page provided but useless" do + it 'returns default page 1 if page provided but useless' do page = 0 expect(page_param(page:)).to eq(1) end - context "with multiples per_page", - with_settings: { per_page_options: "5,10,15" } do - it "calculates page from offset and limit if page is not provided" do + context 'with multiples per_page', + with_settings: { per_page_options: '5,10,15' } do + it 'calculates page from offset and limit if page is not provided' do # need to change settings as only multiples of per_page # are allowed for limit offset = 55 @@ -192,7 +192,7 @@ end end - it "ignores offset and limit if page is provided" do + it 'ignores offset and limit if page is provided' do offset = 55 limit = 10 page = 7 @@ -200,30 +200,30 @@ expect(page_param(offset:, limit:, page:)).to eq(page) end - context "faulty settings", - with_settings: { per_page_options: "-1,2,3" } do - it "does not break if limit is bogus (also faulty settings)" do + context 'faulty settings', + with_settings: { per_page_options: '-1,2,3' } do + it 'does not break if limit is bogus (also faulty settings)' do offset = 55 - limit = "lorem" + limit = 'lorem' expect(page_param(offset:, limit:)).to eq(28) end end - it "returns 1 if nothing is provided" do + it 'returns 1 if nothing is provided' do expect(page_param({})).to eq(1) end end - describe "#per_page_param", - with_settings: { per_page_options: "1,2,3" } do - it "returns per_page if provided and one of the values stored in the settings" do + describe '#per_page_param', + with_settings: { per_page_options: '1,2,3' } do + it 'returns per_page if provided and one of the values stored in the settings' do per_page = 2 expect(per_page_param(per_page:)).to eq(per_page) end - it "returns per_page if provided and store it in the session" do + it 'returns per_page if provided and store it in the session' do session[:per_page] = 3 per_page = 2 @@ -231,39 +231,39 @@ expect(session[:per_page]).to eq(2) end - it "should take the smallest value stored in the settings " + - "if provided per_page param is not one of the configured" do + it 'should take the smallest value stored in the settings ' + + 'if provided per_page param is not one of the configured' do per_page = 4 expect(per_page_param(per_page:)).to eq(1) end - it "prefers the value stored in the session if it is valid according to the settings" do + it 'prefers the value stored in the session if it is valid according to the settings' do session[:per_page] = 2 expect(per_page_param(per_page: 3)).to eq(session[:per_page]) end - it "ignores the value stored in the session if it is not valid according to the settings" do + it 'ignores the value stored in the session if it is not valid according to the settings' do session[:per_page] = 4 expect(per_page_param(per_page: 3)).to eq(3) end - it "uses limit synonymously to per_page" do + it 'uses limit synonymously to per_page' do limit = 2 expect(per_page_param(limit:)).to eq(limit) end - it "prefers per_page over limit" do + it 'prefers per_page over limit' do limit = 2 per_page = 3 expect(per_page_param(limit:, per_page:)).to eq(per_page) end - it "stores the value in the session" do + it 'stores the value in the session' do limit = 2 per_page_param(limit:) diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 7b5636d71aef..0bb6537acf12 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ProjectsHelper do include ApplicationHelper @@ -47,53 +47,53 @@ .and_return(query_instance) end - describe "#short_project_description" do + describe '#short_project_description' do let(:project) { build_stubbed(:project, description: "#{'Abcd ' * 5}\n" * 11) } - it "returns shortened description" do + it 'returns shortened description' do expect(helper.short_project_description(project)) .to eql("#{("#{'Abcd ' * 5}\n" * 10)[0..-2]}...") end end - describe "#projects_columns_options" do + describe '#projects_columns_options' do before do project_selects end - it "returns the columns options" do + it 'returns the columns options' do expect(helper.projects_columns_options) .to eql([ - { name: "Description", id: :description }, - { name: "Name", id: :name }, - { name: "Status", id: :project_status } + { name: 'Description', id: :description }, + { name: 'Name', id: :name }, + { name: 'Status', id: :project_status } ]) end end - describe "#selected_project_columns_options", with_settings: { enabled_projects_columns: %w[name description] } do + describe '#selected_project_columns_options', with_settings: { enabled_projects_columns: %w[name description] } do before do project_selects end - it "returns the columns options currently persisted in the setting (in that order)" do + it 'returns the columns options currently persisted in the setting (in that order)' do expect(helper.selected_projects_columns_options) .to eql([ - { name: "Name", id: :name }, - { name: "Description", id: :description } + { name: 'Name', id: :name }, + { name: 'Description', id: :description } ]) end end - describe "#protected_project_columns_options" do + describe '#protected_project_columns_options' do before do project_selects end - it "returns the columns options currently persisted in the setting (in that order)" do + it 'returns the columns options currently persisted in the setting (in that order)' do expect(helper.protected_projects_columns_options) .to eql([ - { name: "Name", id: :name } + { name: 'Name', id: :name } ]) end end diff --git a/spec/helpers/removed_js_helpers_helper_spec.rb b/spec/helpers/removed_js_helpers_helper_spec.rb index 270cf090ae73..4644f9282ec8 100644 --- a/spec/helpers/removed_js_helpers_helper_spec.rb +++ b/spec/helpers/removed_js_helpers_helper_spec.rb @@ -26,24 +26,24 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe RemovedJsHelpersHelper do include RemovedJsHelpersHelper - describe "link_to_function" do - it "returns a valid link" do - allow(SecureRandom).to receive(:uuid).and_return "uuid" + describe 'link_to_function' do + it 'returns a valid link' do + allow(SecureRandom).to receive(:uuid).and_return 'uuid' expect(self).to receive(:content_for).with(:additional_js_dom_ready) - expect(link_to_function("blubs", nil)) + expect(link_to_function('blubs', nil)) .to be_html_eql %{ blubs } end - it "adds the provided method to the onclick handler" do + it 'adds the provided method to the onclick handler' do expect(self).to receive(:content_for).with(:additional_js_dom_ready) - expect(link_to_function("blubs", "doTheMagic(now)", id: :foo)) + expect(link_to_function('blubs', 'doTheMagic(now)', id: :foo)) .to be_html_eql %{ blubs } diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 2c52aa6b73ff..da48346fda98 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -26,37 +26,37 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "search/index" do +RSpec.describe 'search/index' do let(:project) { create(:project) } - let(:scope) { "foobar" } + let(:scope) { 'foobar' } before do allow(helper).to receive(:params).and_return( - q: "foobar", - all_words: "1", + q: 'foobar', + all_words: '1', scope: ) assign(:project, project) end - describe "#highlight_tokens" do + describe '#highlight_tokens' do let(:maximum_length) { 1300 } subject(:highlighted_title) { helper.highlight_tokens title, tokens } - context "with single token" do + context 'with single token' do let(:tokens) { %w(token) } - let(:title) { "This is a token." } + let(:title) { 'This is a token.' } let(:expected_title) { 'This is a token.' } it { is_expected.to eq expected_title } end - context "with multiple tokens" do + context 'with multiple tokens' do let(:tokens) { %w(token another) } - let(:title) { "This is a token and another token." } + let(:title) { 'This is a token and another token.' } let(:expected_title) do <<~TITLE.squish This is a token @@ -68,19 +68,19 @@ it { is_expected.to eq expected_title } end - context "with huge content" do + context 'with huge content' do let(:tokens) { %w(token) } let(:title) { "#{'1234567890' * 100} token " * 100 } let(:highlighted_token) { 'token' } it { expect(highlighted_title).to include highlighted_token } - it "does not exceed maximum length" do + it 'does not exceed maximum length' do expect(highlighted_title.length).to be <= maximum_length end end - context "with multibyte title" do + context 'with multibyte title' do let(:tokens) { %w(token) } let(:title) { "#{'й' * 200} token #{'й' * 200}" } let(:expected_title) do @@ -91,7 +91,7 @@ end end - describe "#highlight_tokens_in_event" do + describe '#highlight_tokens_in_event' do let(:journal_notes) { "Journals notes" } let(:event_description) { "The description of the event" } let(:attachment_fulltext) { "The fulltext of the attachment" } @@ -118,58 +118,58 @@ end end - context "with the token in the journal notes" do + context 'with the token in the journal notes' do let(:tokens) { %w(journals) } - it "shows the text in the notes" do + it 'shows the text in the notes' do expect(helper.highlight_tokens_in_event(event, tokens)) .to eql 'Journals notes' end end - context "with the token in the description" do + context 'with the token in the description' do let(:tokens) { %w(description) } - it "shows the text in the description" do + it 'shows the text in the description' do expect(helper.highlight_tokens_in_event(event, tokens)) .to eql 'The description of the event' end end - context "with the token in the description and empty journal notes" do + context 'with the token in the description and empty journal notes' do let(:tokens) { %w(description) } let(:journal_notes) { "" } - it "shows the text in the description" do + it 'shows the text in the description' do expect(helper.highlight_tokens_in_event(event, tokens)) .to eql 'The description of the event' end end - context "with the token in the attachment text" do + context 'with the token in the attachment text' do let(:tokens) { %w(fulltext) } - it "shows the text in the fulltext" do + it 'shows the text in the fulltext' do expect(helper.highlight_tokens_in_event(event, tokens)) .to eql 'The fulltext of the attachment' end end - context "with the token in the attachment filename" do + context 'with the token in the attachment filename' do let(:tokens) { %w(filename) } - it "shows the text in the fulltext" do + it 'shows the text in the fulltext' do expect(helper.highlight_tokens_in_event(event, tokens)) .to eql 'attachment_filename.txt' end end - context "with the token in neither" do + context 'with the token in neither' do let(:tokens) { %w(bogus) } - it "shows the description (without highlight)" do + it 'shows the description (without highlight)' do expect(helper.highlight_tokens_in_event(event, tokens)) - .to eql "The description of the event" + .to eql 'The description of the event' end end end diff --git a/spec/helpers/security_badge_helper_spec.rb b/spec/helpers/security_badge_helper_spec.rb index 05c6c8443f23..9b53f468acd4 100644 --- a/spec/helpers/security_badge_helper_spec.rb +++ b/spec/helpers/security_badge_helper_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SecurityBadgeHelper do - describe "#security_badge_url" do + describe '#security_badge_url' do before do # can't use with_settings since Setting.installation_uuid has a custom implementation - allow(Setting).to receive(:installation_uuid).and_return "abcd1234" + allow(Setting).to receive(:installation_uuid).and_return 'abcd1234' end it "generates a URL with the release API path and the details of the installation" do diff --git a/spec/helpers/settings_helper_spec.rb b/spec/helpers/settings_helper_spec.rb index 96a9d04c47e0..d9f4f24d4484 100644 --- a/spec/helpers/settings_helper_spec.rb +++ b/spec/helpers/settings_helper_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "ostruct" +require 'spec_helper' +require 'ostruct' RSpec.describe SettingsHelper do include Capybara::RSpecMatchers - let(:options) { { class: "custom-class" } } + let(:options) { { class: 'custom-class' } } before do allow(Setting) @@ -40,145 +40,145 @@ .and_return true allow(I18n).to receive(:t).and_call_original - allow(I18n).to receive(:t).with("setting_field_a").and_return("Field A") - allow(I18n).to receive(:t).with("setting_field_b").and_return("Field B") - allow(I18n).to receive(:t).with("setting_field").and_return("Field") + allow(I18n).to receive(:t).with('setting_field_a').and_return('Field A') + allow(I18n).to receive(:t).with('setting_field_b').and_return('Field B') + allow(I18n).to receive(:t).with('setting_field').and_return('Field') end - shared_examples_for "field disabled if non writable" do - context "when the setting is writable" do - it "is enabled" do + shared_examples_for 'field disabled if non writable' do + context 'when the setting is writable' do + it 'is enabled' do expect(output) - .to have_field "settings_host_name", disabled: false + .to have_field 'settings_host_name', disabled: false end end - context "when the setting isn`t writable" do + context 'when the setting isn`t writable' do before do allow(Setting) .to receive(:host_name_writable?) .and_return false end - it "is disabled" do + it 'is disabled' do expect(output) - .to have_field "settings_host_name", disabled: true + .to have_field 'settings_host_name', disabled: true end end end - describe "#setting_select" do + describe '#setting_select' do subject(:output) do - helper.setting_select :host_name, [["Popsickle", "1"], ["Jello", "2"], ["Ice Cream", "3"]], options + helper.setting_select :host_name, [['Popsickle', '1'], ['Jello', '2'], ['Ice Cream', '3']], options end before do - allow(Setting).to receive(:host_name).and_return("2") + allow(Setting).to receive(:host_name).and_return('2') end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "select-container" - it_behaves_like "field disabled if non writable" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'select-container' + it_behaves_like 'field disabled if non writable' - it "outputs element" do - expect(output).to have_css "select.form--select > option", count: 3 - expect(output).to have_select "settings_host_name", selected: "Jello" + it 'outputs element' do + expect(output).to have_css 'select.form--select > option', count: 3 + expect(output).to have_select 'settings_host_name', selected: 'Jello' end end - describe "#setting_multiselect" do + describe '#setting_multiselect' do subject(:output) do - helper.setting_multiselect :host_name, [["Popsickle", "1"], ["Jello", "2"], ["Ice Cream", "3"]], options + helper.setting_multiselect :host_name, [['Popsickle', '1'], ['Jello', '2'], ['Ice Cream', '3']], options end before do - allow(Setting).to receive(:host_name).at_least(:once).and_return("1") + allow(Setting).to receive(:host_name).at_least(:once).and_return('1') end - it_behaves_like "wrapped in container" do + it_behaves_like 'wrapped in container' do let(:container_count) { 3 } end - it "has checkboxes wrapped in checkbox-container" do - expect(output).to have_css "span.form--check-box-container", count: 3 + it 'has checkboxes wrapped in checkbox-container' do + expect(output).to have_css 'span.form--check-box-container', count: 3 end - it "has three labels" do - expect(output).to have_css "label.form--label-with-check-box", count: 3 + it 'has three labels' do + expect(output).to have_css 'label.form--label-with-check-box', count: 3 end - it "outputs element" do + it 'outputs element' do expect(output).to have_css 'input[type="checkbox"].form--check-box', count: 3 end - context "when the setting isn`t writable" do + context 'when the setting isn`t writable' do before do allow(Setting) .to receive(:host_name_writable?) .and_return false end - it "is disabled and has no hidden field" do + it 'is disabled and has no hidden field' do expect(output).to have_no_css 'input[type="hidden"][value=""]', visible: :all expect(output).to have_css 'input[type="checkbox"][disabled="disabled"].form--check-box', count: 3 end end end - describe "#settings_matrix" do + describe '#settings_matrix' do subject(:output) do settings = %i[host_name protocol] choices = [ { - caption: "Popsickle", - value: "1" + caption: 'Popsickle', + value: '1' }, { - caption: "Jello", - value: "2" + caption: 'Jello', + value: '2' }, { - caption: "Ice Cream", - value: "3" + caption: 'Ice Cream', + value: '3' }, { - value: "Quarkspeise" + value: 'Quarkspeise' } ] helper.settings_matrix settings, choices end before do - allow(Setting).to receive(:host_name).at_least(:once).and_return("2") - allow(Setting).to receive(:protocol).at_least(:once).and_return("3") + allow(Setting).to receive(:host_name).at_least(:once).and_return('2') + allow(Setting).to receive(:protocol).at_least(:once).and_return('3') allow(Setting).to receive_messages( host_name_writable?: true, protocol_writable?: true ) end - it_behaves_like "not wrapped in container" + it_behaves_like 'not wrapped in container' - it "is structured as a table" do - expect(output).to have_css "table.form--matrix" + it 'is structured as a table' do + expect(output).to have_css 'table.form--matrix' end - it "has table headers" do - expect(output).to have_css "thead th.form--matrix-header-cell", count: 3 + it 'has table headers' do + expect(output).to have_css 'thead th.form--matrix-header-cell', count: 3 end - it "has three table rows" do - expect(output).to have_css "tbody > tr.form--matrix-row", count: 4 + it 'has three table rows' do + expect(output).to have_css 'tbody > tr.form--matrix-row', count: 4 end - it "has cells with text labels" do + it 'has cells with text labels' do expect(output).to be_html_eql(%{ Popsickle - }).at_path("tr:first-child > td:first-child") + }).at_path('tr:first-child > td:first-child') end - it "has cells with styled checkboxes" do + it 'has cells with styled checkboxes' do expect(output).to be_html_eql(%{ @@ -186,7 +186,7 @@ name="settings[host_name][]" type="checkbox" value="1"> - }).at_path("tr.form--matrix-row:first-child > td:nth-of-type(2)") + }).at_path('tr.form--matrix-row:first-child > td:nth-of-type(2)') expect(output).to be_html_eql(%{ @@ -195,22 +195,22 @@ name="settings[host_name][]" type="checkbox" value="Quarkspeise"> - }).at_path("tr.form--matrix-row:last-child > td:nth-of-type(2)") + }).at_path('tr.form--matrix-row:last-child > td:nth-of-type(2)') end - it "has the correct fields checked" do - expect(output).to have_checked_field "host_name_2" - expect(output).to have_checked_field "protocol_3" + it 'has the correct fields checked' do + expect(output).to have_checked_field 'host_name_2' + expect(output).to have_checked_field 'protocol_3' end - context "when the setting isn`t writable" do + context 'when the setting isn`t writable' do before do allow(Setting) .to receive(:host_name_writable?) .and_return false end - it "is disabled" do + it 'is disabled' do expect(output).to be_html_eql(%{ @@ -218,146 +218,146 @@ name="settings[host_name][]" type="checkbox" disabled="disabled" value="1"> - }).at_path("tr.form--matrix-row:first-child > td:nth-of-type(2)") + }).at_path('tr.form--matrix-row:first-child > td:nth-of-type(2)') end end end - describe "#setting_text_field" do + describe '#setting_text_field' do subject(:output) do helper.setting_text_field :host_name, options end before do - allow(Setting).to receive(:host_name).and_return("important value") + allow(Setting).to receive(:host_name).and_return('important value') end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" - it_behaves_like "field disabled if non writable" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' + it_behaves_like 'field disabled if non writable' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#setting_text_area" do + describe '#setting_text_area' do subject(:output) do helper.setting_text_area :host_name, options end before do - allow(Setting).to receive(:host_name).and_return("important text") + allow(Setting).to receive(:host_name).and_return('important text') end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-area-container" - it_behaves_like "field disabled if non writable" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-area-container' + it_behaves_like 'field disabled if non writable' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("textarea") + }).at_path('textarea') end end - describe "#setting_check_box" do + describe '#setting_check_box' do subject(:output) do helper.setting_check_box :host_name, options end - context "when setting is true" do + context 'when setting is true' do before do allow(Setting).to receive(:host_name?).and_return(true) end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "check-box-container" - it_behaves_like "field disabled if non writable" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'check-box-container' + it_behaves_like 'field disabled if non writable' - it "outputs element" do + it 'outputs element' do expect(output).to have_css 'input[type="hidden"][value=0]', visible: :hidden expect(output).to have_css 'input[type="checkbox"].custom-class.form--check-box' - expect(output).to have_checked_field "settings_host_name" + expect(output).to have_checked_field 'settings_host_name' end - context "when the setting isn`t writable" do + context 'when the setting isn`t writable' do before do allow(Setting) .to receive(:host_name_writable?) .and_return false end - it "does not output a hidden field" do + it 'does not output a hidden field' do expect(output).to have_no_css 'input[type="hidden"][value=0]', visible: :hidden end end end - context "when setting is false" do + context 'when setting is false' do before do allow(Setting).to receive(:host_name?).and_return(false) end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "check-box-container" - it_behaves_like "field disabled if non writable" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'check-box-container' + it_behaves_like 'field disabled if non writable' - it "outputs element" do + it 'outputs element' do expect(output).to have_css 'input[type="hidden"][value=0]', visible: :hidden expect(output).to have_css 'input[type="checkbox"].custom-class.form--check-box' - expect(output).to have_unchecked_field "settings_host_name" + expect(output).to have_unchecked_field 'settings_host_name' end - context "when the setting isn`t writable" do + context 'when the setting isn`t writable' do before do allow(Setting) .to receive(:host_name_writable?) .and_return false end - it "does not output a hidden field" do + it 'does not output a hidden field' do expect(output).to have_no_css 'input[type="hidden"][value=0]', visible: :hidden end end end end - describe "#setting_time_field" do + describe '#setting_time_field' do subject(:output) do helper.setting_time_field :host_name, options end before do - allow(Setting).to receive(:host_name).and_return("16:00") + allow(Setting).to receive(:host_name).and_return('16:00') end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#setting_label" do + describe '#setting_label' do subject(:output) do helper.setting_label :host_name end - it_behaves_like "labelled" - it_behaves_like "not wrapped in container" + it_behaves_like 'labelled' + it_behaves_like 'not wrapped in container' end end diff --git a/spec/helpers/sort_helper_spec.rb b/spec/helpers/sort_helper_spec.rb index 374782219614..d6cd9a256199 100644 --- a/spec/helpers/sort_helper_spec.rb +++ b/spec/helpers/sort_helper_spec.rb @@ -26,107 +26,107 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SortHelper do - describe "#sort_init/#sort_update/#sort_clause" do + describe '#sort_init/#sort_update/#sort_clause' do # Needed to mimic being included in a controller - def controller_name; "foo"; end + def controller_name; 'foo'; end - def action_name; "bar"; end + def action_name; 'bar'; end before do - sort_init "attr1", "desc" + sort_init 'attr1', 'desc' end - context "with arrays" do + context 'with arrays' do before do sort_update(%w[attr1 attr2]) end - it "returns the first attr in descending order" do + it 'returns the first attr in descending order' do expect(sort_clause) - .to eql "attr1 DESC" + .to eql 'attr1 DESC' end end - context "with hashes" do + context 'with hashes' do before do - sort_update("attr1" => "table1.attr1", "attr2" => "table2.attr2") + sort_update('attr1' => 'table1.attr1', 'attr2' => 'table2.attr2') end - it "returns the first attr in descending order with the table name prefixed" do + it 'returns the first attr in descending order with the table name prefixed' do expect(sort_clause) - .to eql "table1.attr1 DESC" + .to eql 'table1.attr1 DESC' end end - context "with hashes sorting by multiple values" do + context 'with hashes sorting by multiple values' do before do - sort_update("attr1" => %w[table1.attr1 table1.attr2], "attr2" => "table2.attr2") + sort_update('attr1' => %w[table1.attr1 table1.attr2], 'attr2' => 'table2.attr2') end - it "returns the first attr in descending order" do + it 'returns the first attr in descending order' do expect(sort_clause) - .to eql "table1.attr1 DESC, table1.attr2 DESC" + .to eql 'table1.attr1 DESC, table1.attr2 DESC' end end end - describe "#sort_init/#sort_update/params/session" do + describe '#sort_init/#sort_update/params/session' do # Needed to mimic being included in a controller - def controller_name; "foo"; end + def controller_name; 'foo'; end - def action_name; "bar"; end + def action_name; 'bar'; end def params; { sort: sort_param }; end def session; @session ||= {}; end before do - sort_init "attr1", "desc" - sort_update("attr1" => %w[table1.attr1 table1.attr2], "attr2" => "table2.attr2") + sort_init 'attr1', 'desc' + sort_update('attr1' => %w[table1.attr1 table1.attr2], 'attr2' => 'table2.attr2') end - context "with valid sort params" do - let(:sort_param) { "attr1,attr2:desc" } + context 'with valid sort params' do + let(:sort_param) { 'attr1,attr2:desc' } - it "persists the order in the session" do - expect(session["foo_bar_sort"]) - .to eql "attr1,attr2:desc" + it 'persists the order in the session' do + expect(session['foo_bar_sort']) + .to eql 'attr1,attr2:desc' end end - context "with invalid sort key" do - let(:sort_param) { "invalid_key" } + context 'with invalid sort key' do + let(:sort_param) { 'invalid_key' } - it "keeps the default sort in the session" do - expect(session["foo_bar_sort"]) - .to eql "attr1:desc" + it 'keeps the default sort in the session' do + expect(session['foo_bar_sort']) + .to eql 'attr1:desc' end end - context "with invalid sort direction" do - let(:sort_param) { "attr1:blubs,attr2" } + context 'with invalid sort direction' do + let(:sort_param) { 'attr1:blubs,attr2' } - it "falls back to the default sort order in the session" do - expect(session["foo_bar_sort"]) - .to eql "attr1,attr2" + it 'falls back to the default sort order in the session' do + expect(session['foo_bar_sort']) + .to eql 'attr1,attr2' end end end - describe "#sort_header_tag" do + describe '#sort_header_tag' do let(:output) do - helper.sort_header_tag("id") + helper.sort_header_tag('id') end - let(:sort_key) { "" } + let(:sort_key) { '' } let(:sort_asc) { true } let(:sort_criteria) do instance_double(SortHelper::SortCriteria, first_key: sort_key, first_asc?: sort_asc, - to_param: "sort_criteria_params").as_null_object + to_param: 'sort_criteria_params').as_null_object end before do @@ -136,10 +136,10 @@ def session; @session ||= {}; end # fake having called '/work_packages' allow(helper) .to receive(:url_options) - .and_return(url_options.merge(controller: "work_packages", action: "index")) + .and_return(url_options.merge(controller: 'work_packages', action: 'index')) end - it "renders a th with a sort link" do + it 'renders a th with a sort link' do expect(output).to be_html_eql(%{
    @@ -154,10 +154,10 @@ def session; @session ||= {}; end }) end - context "when sorting by the column" do - let(:sort_key) { "id" } + context 'when sorting by the column' do + let(:sort_key) { 'id' } - it "adds the sort class" do + it 'adds the sort class' do expect(output).to be_html_eql(%{
    @@ -173,11 +173,11 @@ def session; @session ||= {}; end end end - context "when sorting desc by the column" do - let(:sort_key) { "id" } + context 'when sorting desc by the column' do + let(:sort_key) { 'id' } let(:sort_asc) { false } - it "adds the sort class" do + it 'adds the sort class' do expect(output).to be_html_eql(%{
    diff --git a/spec/helpers/tabs_helper_spec.rb b/spec/helpers/tabs_helper_spec.rb index 72bca4a238dc..587f40d6b8a7 100644 --- a/spec/helpers/tabs_helper_spec.rb +++ b/spec/helpers/tabs_helper_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TabsHelper do include described_class let(:given_tab) do - { name: "avatar", - partial: "avatars/users/avatar_tab", + { name: 'avatar', + partial: 'avatars/users/avatar_tab', path: ->(params) { edit_user_path(params[:user], tab: :avatar) }, label: :label_avatar } end let(:expected_tab) do - { name: "avatar", - partial: "avatars/users/avatar_tab", - path: "/users/2/edit/avatar", + { name: 'avatar', + partial: 'avatars/users/avatar_tab', + path: '/users/2/edit/avatar', label: :label_avatar } end - describe "render_extensible_tabs" do + describe 'render_extensible_tabs' do let(:current_user) { build(:user) } let(:user) { build(:user, id: 2) } diff --git a/spec/helpers/text_formatting_helper_spec.rb b/spec/helpers/text_formatting_helper_spec.rb index 6026a2cc8935..c1f7fa78fbfb 100644 --- a/spec/helpers/text_formatting_helper_spec.rb +++ b/spec/helpers/text_formatting_helper_spec.rb @@ -26,40 +26,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TextFormattingHelper do - describe "#preview_context" do - context "for a News" do + describe '#preview_context' do + context 'for a News' do let(:news) { build_stubbed(:news) } - it "returns the v3 path" do + it 'returns the v3 path' do expect(helper.preview_context(news)) .to eql "/api/v3/news/#{news.id}" end end - context "for a Message" do + context 'for a Message' do let(:message) { build_stubbed(:message) } - it "returns the v3 path" do + it 'returns the v3 path' do expect(helper.preview_context(message)) .to eql "/api/v3/posts/#{message.id}" end end - context "for a WikiPage" do + context 'for a WikiPage' do let(:wiki_page) { build_stubbed(:wiki_page) } - it "returns the v3 path" do + it 'returns the v3 path' do expect(helper.preview_context(wiki_page)) .to eql "/api/v3/wiki_pages/#{wiki_page.id}" end end end - describe "truncate_formatted_text" do - context "with a long text" do + describe 'truncate_formatted_text' do + context 'with a long text' do let(:text) do <<~TEXT.squish Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam @@ -70,7 +70,7 @@ TEXT end - context "without specifying a length" do + context 'without specifying a length' do let(:text_html) do <<~TEXT.squish Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam @@ -78,13 +78,13 @@ TEXT end - it "truncates given text at 120 chars" do + it 'truncates given text at 120 chars' do expect(truncate_formatted_text(text)) .to be_html_eql(text_html) end end - context "when specifying a length" do + context 'when specifying a length' do let(:text_html) do <<~TEXT.squish Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam @@ -94,49 +94,49 @@ TEXT end - it "truncates given text at the specified length" do + it 'truncates given text at the specified length' do expect(truncate_formatted_text(text, length: 250)) .to be_html_eql(text_html) end end end - context "with newline characters" do + context 'with newline characters' do let(:text) do "Lorem ipsum dolor sit \namet, consetetur sadipscing elitr, sed diam nonumy eirmod\n tempor invidunt" end let(:text_html) do - "Lorem ipsum dolor sit
    amet, consetetur sadipscing elitr, sed diam nonumy eirmod
    tempor invidunt" + 'Lorem ipsum dolor sit
    amet, consetetur sadipscing elitr, sed diam nonumy eirmod
    tempor invidunt' end - it "replaces escaped line breaks with html line breaks and should be html_safe" do + it 'replaces escaped line breaks with html line breaks and should be html_safe' do expect(truncate_formatted_text(text)) .to be_html_eql(text_html) end - it "is html_safe" do + it 'is html_safe' do expect(truncate_formatted_text(text)) .to be_html_safe end - context "when specifying not to replace newlines" do - it "returns the text unaltered" do + context 'when specifying not to replace newlines' do + it 'returns the text unaltered' do expect(truncate_formatted_text(text, replace_newlines: false)) .to be_html_eql(text) end - it "is html_safe" do + it 'is html_safe' do expect(truncate_formatted_text(text, replace_newlines: false)) .to be_html_safe end end end - context "with potentially harmful code" do - it "escapes" do + context 'with potentially harmful code' do + it 'escapes' do text = "Lorem ipsum dolor tempor invidunt" expect(truncate_formatted_text(text)) - .to include("<script>alert('pwnd');</script>") + .to include('<script>alert(\'pwnd\');</script>') end end end diff --git a/spec/helpers/toolbar_helper_spec.rb b/spec/helpers/toolbar_helper_spec.rb index 7939896b4eb9..300f7966bbe7 100644 --- a/spec/helpers/toolbar_helper_spec.rb +++ b/spec/helpers/toolbar_helper_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ToolbarHelper do - describe ".toolbar" do - it "creates a default toolbar" do - result = toolbar title: "Title" + describe '.toolbar' do + it 'creates a default toolbar' do + result = toolbar title: 'Title' expect(result).to be_html_eql %{
    @@ -44,8 +44,8 @@ } end - it "is able to add a subtitle" do - result = toolbar title: "Title", subtitle: "lorem" + it 'is able to add a subtitle' do + result = toolbar title: 'Title', subtitle: 'lorem' expect(result).to be_html_eql %{
    @@ -59,8 +59,8 @@ } end - it "is able to add a link_to" do - result = toolbar title: "Title", link_to: link_to("foobar", user_path("1234")) + it 'is able to add a link_to' do + result = toolbar title: 'Title', link_to: link_to('foobar', user_path('1234')) expect(result).to be_html_eql %{
    @@ -73,7 +73,7 @@ } end - it "escapes the title" do + it 'escapes the title' do result = toolbar title: '' expect(result).to be_html_eql %{
    @@ -87,10 +87,10 @@ } end - it "includes capsulate html" do - result = toolbar title: "Title" do + it 'includes capsulate html' do + result = toolbar title: 'Title' do content_tag :li do - content_tag :p, "paragraph", data: { number: 2 } + content_tag :p, 'paragraph', data: { number: 2 } end end expect(result).to be_html_eql %{ @@ -110,10 +110,10 @@ end end - describe ".breadcrumb_toolbar" do - it "escapes properly" do + describe '.breadcrumb_toolbar' do + it 'escapes properly' do result = breadcrumb_toolbar '', - link_to("foobar", user_path("1234")) + link_to('foobar', user_path('1234')) expect(result).to be_html_eql %{
    diff --git a/spec/helpers/types_helper_spec.rb b/spec/helpers/types_helper_spec.rb index 4a573aa1c7c2..45b1d3fcc120 100644 --- a/spec/helpers/types_helper_spec.rb +++ b/spec/helpers/types_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TypesHelper do let(:type) { build_stubbed(:type) } @@ -43,17 +43,17 @@ before do allow(type) .to receive(:attribute_groups) - .and_return [Type::AttributeGroup.new(type, "group one", ["assignee"])] + .and_return [Type::AttributeGroup.new(type, 'group one', ["assignee"])] end - it "contains Hashes ordered by key :translation" do + it 'contains Hashes ordered by key :translation' do # The first left over attribute should currently be "date" expect(subject.first[:translation]).to be_present expect(subject.first[:translation] <= subject.second[:translation]).to be_truthy end # The "assignee" is in "group one". It should not appear in :inactives. - it "does not contain attributes that do not exist anymore" do + it 'does not contain attributes that do not exist anymore' do expect(subject.pluck(:key)).not_to include "assignee" end end @@ -64,10 +64,10 @@ before do allow(type) .to receive(:attribute_groups) - .and_return [Type::AttributeGroup.new(type, "group one", ["date"])] + .and_return [Type::AttributeGroup.new(type, 'group one', ["date"])] end - it "has a proper structure" do + it 'has a proper structure' do # The group's name/key expect(subject.first[:name]).to eq "group one" diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index c3bbe4c972e5..c33030d5b18b 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UsersHelper do def build_user(status, blocked) @@ -39,20 +39,20 @@ def build_user(status, blocked) end end - describe "full_user_status" do + describe 'full_user_status' do test_cases = { - [:active, false] => I18n.t("user.active"), - [:active, true] => I18n.t("user.blocked_num_failed_logins", + [:active, false] => I18n.t('user.active'), + [:active, true] => I18n.t('user.blocked_num_failed_logins', count: 3), - [:locked, false] => I18n.t("user.locked"), - [:locked, true] => I18n.t("user.status_user_and_brute_force", - user: I18n.t("user.locked"), - brute_force: I18n.t("user.blocked_num_failed_logins", + [:locked, false] => I18n.t('user.locked'), + [:locked, true] => I18n.t('user.status_user_and_brute_force', + user: I18n.t('user.locked'), + brute_force: I18n.t('user.blocked_num_failed_logins', count: 3)), - [:registered, false] => I18n.t("user.registered"), - [:registered, true] => I18n.t("user.status_user_and_brute_force", - user: I18n.t("user.registered"), - brute_force: I18n.t("user.blocked_num_failed_logins", + [:registered, false] => I18n.t('user.registered'), + [:registered, true] => I18n.t('user.status_user_and_brute_force', + user: I18n.t('user.registered'), + brute_force: I18n.t('user.blocked_num_failed_logins', count: 3)) } @@ -71,7 +71,7 @@ def build_user(status, blocked) end end - describe "change_user_status_buttons" do + describe 'change_user_status_buttons' do test_cases = { [:active, false] => :lock, [:locked, false] => :unlock, @@ -92,61 +92,61 @@ def build_user(status, blocked) expect(buttons).to include(expectation) end - it "contains a single button" do - expect(buttons.scan("#{test_project.name} - #{version.name}") end - it "generates a link within a project" do + it 'generates a link within a project' do @project = test_project expect(link_to_version(version)) .to be_html_eql("#{version.name}") @@ -84,20 +84,20 @@ end end - describe "#link_to_version_id" do - it "generates an escaped id" do + describe '#link_to_version_id' do + it 'generates an escaped id' do expect(link_to_version_id(version)) .to eql("version-#{ERB::Util.url_encode(version.name)}") end end end - describe "#version_options_for_select" do - it "generates nothing without a version" do + describe '#version_options_for_select' do + it 'generates nothing without a version' do expect(version_options_for_select([])).to be_empty end - it "generates an option tag" do + it 'generates an option tag' do expect(version_options_for_select([], version)).to eq("") end diff --git a/spec/helpers/wiki_pages/at_version_spec.rb b/spec/helpers/wiki_pages/at_version_spec.rb index 4b8eaf1224fa..87fbe1d42c82 100644 --- a/spec/helpers/wiki_pages/at_version_spec.rb +++ b/spec/helpers/wiki_pages/at_version_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiPages::AtVersion do let(:wiki_page) do @@ -74,435 +74,435 @@ version) end - describe "#author" do - context "without a version" do + describe '#author' do + context 'without a version' do let(:version) { nil } - it "is the most recent journal`s user" do + it 'is the most recent journal`s user' do expect(page_at_version.author) .to eq second_journal_user end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is the first journal`s user" do + it 'is the first journal`s user' do expect(page_at_version.author) .to eq first_journal_user end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is the last journal`s user" do + it 'is the last journal`s user' do expect(page_at_version.author) .to eq second_journal_user end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is the last journal`s user" do + it 'is the last journal`s user' do expect(page_at_version.author) .to eq second_journal_user end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is nil" do + it 'is nil' do expect(page_at_version.author) .to be_nil end end - context "with the version being less then 0" do + context 'with the version being less then 0' do let(:version) { -1 } - it "is nil" do + it 'is nil' do expect(page_at_version.author) .to be_nil end end end - describe "#journals" do - context "without a version" do + describe '#journals' do + context 'without a version' do let(:version) { nil } - it "is the full set of journals" do + it 'is the full set of journals' do expect(page_at_version.journals) .to contain_exactly(first_journal, second_journal) end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is only the first journal" do + it 'is only the first journal' do expect(page_at_version.journals) .to contain_exactly(first_journal) end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is the full set of journals" do + it 'is the full set of journals' do expect(page_at_version.journals) .to contain_exactly(first_journal, second_journal) end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is the full set of journals" do + it 'is the full set of journals' do expect(page_at_version.journals) .to contain_exactly(first_journal, second_journal) end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is empty" do + it 'is empty' do expect(page_at_version.journals) .to be_empty end end end - describe "#lock_version" do - context "without a version" do + describe '#lock_version' do + context 'without a version' do let(:version) { nil } - it "is the page`s lock_version" do + it 'is the page`s lock_version' do expect(page_at_version.lock_version) .to eq wiki_page.lock_version end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is the page`s lock_version" do + it 'is the page`s lock_version' do expect(page_at_version.lock_version) .to eq wiki_page.lock_version end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is the page`s lock_version" do + it 'is the page`s lock_version' do expect(page_at_version.lock_version) .to eq wiki_page.lock_version end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is the page`s lock_version" do + it 'is the page`s lock_version' do expect(page_at_version.lock_version) .to eq wiki_page.lock_version end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is the page`s lock_version" do + it 'is the page`s lock_version' do expect(page_at_version.lock_version) .to eq wiki_page.lock_version end end end - describe "#updated_at" do - context "without a version" do + describe '#updated_at' do + context 'without a version' do let(:version) { nil } - it "is the last journals`s updated_at" do + it 'is the last journals`s updated_at' do expect(page_at_version.updated_at) .to eq second_journal.updated_at end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is the first journals`s updated_at" do + it 'is the first journals`s updated_at' do expect(page_at_version.updated_at) .to eq first_journal.updated_at end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is the last journals`s updated_at" do + it 'is the last journals`s updated_at' do expect(page_at_version.updated_at) .to eq second_journal.updated_at end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is the last journals`s updated_at" do + it 'is the last journals`s updated_at' do expect(page_at_version.updated_at) .to eq second_journal.updated_at end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is nil" do + it 'is nil' do expect(page_at_version.updated_at) .to be_nil end end end - describe "#version" do - context "without a version" do + describe '#version' do + context 'without a version' do let(:version) { nil } - it "is the wiki_page`s version" do + it 'is the wiki_page`s version' do expect(page_at_version.version) .to eq wiki_page.version end end - context "with the version provided" do + context 'with the version provided' do let(:version) { 1 } - it "is the provided version" do + it 'is the provided version' do expect(page_at_version.version) .to eq version end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is the highest possible version" do + it 'is the highest possible version' do expect(page_at_version.version) .to eq 2 end end - context "with the version being 0" do + context 'with the version being 0' do let(:version) { 0 } - it "is 0" do + it 'is 0' do expect(page_at_version.version) .to eq 0 end end - context "with the version being less then 0" do + context 'with the version being less then 0' do let(:version) { -1 } - it "is 0" do + it 'is 0' do expect(page_at_version.version) .to eq 0 end end end - describe "#latest_version" do - context "without a version" do + describe '#latest_version' do + context 'without a version' do let(:version) { nil } - it "is the wiki_page`s version" do + it 'is the wiki_page`s version' do expect(page_at_version.latest_version) .to eq wiki_page.version end end - context "with the version provided" do + context 'with the version provided' do let(:version) { 1 } - it "is the wiki_page`s version" do + it 'is the wiki_page`s version' do expect(page_at_version.latest_version) .to eq wiki_page.version end end end - describe "#text" do - context "without a version" do + describe '#text' do + context 'without a version' do let(:version) { nil } - it "is the last journals`s version" do + it 'is the last journals`s version' do expect(page_at_version.text) .to eq second_journal_text end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is the first journals`s text" do + it 'is the first journals`s text' do expect(page_at_version.text) .to eq first_journal_text end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is the last journals`s text" do + it 'is the last journals`s text' do expect(page_at_version.text) .to eq second_journal_text end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is the last journals`s text" do + it 'is the last journals`s text' do expect(page_at_version.text) .to eq second_journal_text end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is the wiki pages`s text" do + it 'is the wiki pages`s text' do expect(page_at_version.text) .to eq wiki_page.text end end end - describe "#readonly?" do - context "without a version" do + describe '#readonly?' do + context 'without a version' do let(:version) { nil } - it "is false" do + it 'is false' do expect(page_at_version) .not_to be_readonly end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is true" do + it 'is true' do expect(page_at_version) .to be_readonly end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is false" do + it 'is false' do expect(page_at_version) .not_to be_readonly end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is false" do + it 'is false' do expect(page_at_version) .not_to be_readonly end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is true" do + it 'is true' do expect(page_at_version) .to be_readonly end end end - describe "#current_version?" do - context "without a version" do + describe '#current_version?' do + context 'without a version' do let(:version) { nil } - it "is true" do + it 'is true' do expect(page_at_version) .to be_current_version end end - context "with the version set to the first one" do + context 'with the version set to the first one' do let(:version) { 1 } - it "is true" do + it 'is true' do expect(page_at_version) .not_to be_current_version end end - context "with the version set to the last one" do + context 'with the version set to the last one' do let(:version) { 2 } - it "is true" do + it 'is true' do expect(page_at_version) .to be_current_version end end - context "with the version being larger then the current one" do + context 'with the version being larger then the current one' do let(:version) { 3 } - it "is true" do + it 'is true' do expect(page_at_version) .to be_current_version end end - context "with the version being less then 1" do + context 'with the version being less then 1' do let(:version) { 0 } - it "is true" do + it 'is true' do expect(page_at_version) .not_to be_current_version end end end - describe "#object" do - context "without a version" do + describe '#object' do + context 'without a version' do let(:version) { nil } - it "returns the wiki page" do + it 'returns the wiki page' do expect(page_at_version.object) .to eq wiki_page end end - context "with a version" do + context 'with a version' do let(:version) { 1 } - it "returns the wiki page" do + it 'returns the wiki page' do expect(page_at_version.object) .to eq wiki_page end end end - describe "#respond_to?" do + describe '#respond_to?' do let(:version) { 1 } - it "returns false for #to_model" do + it 'returns false for #to_model' do expect(page_at_version) .not_to respond_to(:to_model) end diff --git a/spec/helpers/work_packages_helper_spec.rb b/spec/helpers/work_packages_helper_spec.rb index 13cf3d236110..d663053f31ec 100644 --- a/spec/helpers/work_packages_helper_spec.rb +++ b/spec/helpers/work_packages_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackagesHelper do let(:stub_work_package) { build_stubbed(:work_package, type: stub_type) } @@ -36,40 +36,40 @@ let(:open_status) { build_stubbed(:status, is_closed: false) } let(:closed_status) { build_stubbed(:status, is_closed: true) } - describe "#link_to_work_package" do + describe '#link_to_work_package' do before do stub_work_package.status = open_status end - describe "without parameters" do - it "returns a link to the work package with type and id as the text if type is set" do + describe 'without parameters' do + it 'returns a link to the work package with type and id as the text if type is set' do link_text = Regexp.new("^#{stub_type.name} ##{stub_work_package.id}$") expect(helper.link_to_work_package(stub_work_package)).to have_css( "a[href='#{work_package_path(stub_work_package)}']", text: link_text ) end - it "additionally returns the subject" do + it 'additionally returns the subject' do text = Regexp.new("#{stub_work_package.subject}$") expect(helper.link_to_work_package(stub_work_package)).to have_text(text) end - it "prepends an invisible closed information if the work package is closed" do + it 'prepends an invisible closed information if the work package is closed' do stub_work_package.status = closed_status - expect(helper.link_to_work_package(stub_work_package)).to have_css("a span.hidden-for-sighted", text: "closed") + expect(helper.link_to_work_package(stub_work_package)).to have_css('a span.hidden-for-sighted', text: 'closed') end - it "omits the invisible closed information if told so even though the work package is closed" do + it 'omits the invisible closed information if told so even though the work package is closed' do stub_work_package.status = closed_status expect(helper.link_to_work_package(stub_work_package, no_hidden: true)) - .to have_no_css("a span.hidden-for-sighted", text: "closed") + .to have_no_css('a span.hidden-for-sighted', text: 'closed') end end - describe "with the all_link option provided" do - it "returns a link to the work package with the type, id, and subject as the text" do + describe 'with the all_link option provided' do + it 'returns a link to the work package with the type, id, and subject as the text' do link_text = Regexp.new("^#{stub_type} ##{stub_work_package.id}: #{stub_work_package.subject}$") expect(helper.link_to_work_package(stub_work_package, all_link: true)).to have_css( @@ -78,30 +78,30 @@ end end - describe "when truncating" do - it "truncates the subject if the subject is longer than the specified amount" do - stub_work_package.subject = "12345678" + describe 'when truncating' do + it 'truncates the subject if the subject is longer than the specified amount' do + stub_work_package.subject = '12345678' - text = Regexp.new("1234...$") + text = Regexp.new('1234...$') expect(helper.link_to_work_package(stub_work_package, truncate: 7)).to have_text(text) end - it "does not truncate the subject if the subject is shorter than the specified amount" do - stub_work_package.subject = "1234567" + it 'does not truncate the subject if the subject is shorter than the specified amount' do + stub_work_package.subject = '1234567' - text = Regexp.new("1234567$") + text = Regexp.new('1234567$') expect(helper.link_to_work_package(stub_work_package, truncate: 7)).to have_text(text) end end - describe "when omitting the subject" do - it "omits the subject" do + describe 'when omitting the subject' do + it 'omits the subject' do expect(helper.link_to_work_package(stub_work_package, subject: false)).to have_no_text(stub_work_package.subject) end end - describe "when omitting the type" do - it "omits the type" do + describe 'when omitting the type' do + it 'omits the type' do link_text = Regexp.new("^##{stub_work_package.id}$") expect(helper.link_to_work_package(stub_work_package, type: false)).to have_css("a[href='#{work_package_path(stub_work_package)}']", @@ -109,37 +109,37 @@ end end - describe "with a project" do + describe 'with a project' do let(:text) { Regexp.new("^#{stub_project.name} -") } before do stub_work_package.project = stub_project end - it "prepends the project if parameter set to true" do + it 'prepends the project if parameter set to true' do expect(helper.link_to_work_package(stub_work_package, project: true)).to have_text(text) end - it "does not include the project name if the parameter is missing/false" do + it 'does not include the project name if the parameter is missing/false' do expect(helper.link_to_work_package(stub_work_package)).to have_no_text(text) end end - describe "when only wanting the id" do - it "returns a link with the id as text only" do + describe 'when only wanting the id' do + it 'returns a link with the id as text only' do link_text = Regexp.new("^##{stub_work_package.id}$") expect(helper.link_to_work_package(stub_work_package, id_only: true)).to have_css("a[href='#{work_package_path(stub_work_package)}']", text: link_text) end - it "does not have the subject as text" do + it 'does not have the subject as text' do expect(helper.link_to_work_package(stub_work_package, id_only: true)).to have_no_text(stub_work_package.subject) end end - describe "when only wanting the subject" do - it "returns a link with the subject as text" do + describe 'when only wanting the subject' do + it 'returns a link with the subject as text' do link_text = Regexp.new("^#{stub_work_package.subject}$") expect(helper.link_to_work_package(stub_work_package, subject_only: true)).to have_css( @@ -148,8 +148,8 @@ end end - describe "with the status displayed" do - it "returns a link with the status name contained in the text" do + describe 'with the status displayed' do + it 'returns a link with the status name contained in the text' do link_text = Regexp.new("^#{stub_type.name} ##{stub_work_package.id} #{stub_work_package.status}$") expect(helper.link_to_work_package(stub_work_package, status: true)).to have_css("a[href='#{work_package_path(stub_work_package)}']", @@ -158,7 +158,7 @@ end end - describe "#work_package_css_classes" do + describe '#work_package_css_classes' do let(:statuses) { (1..5).map { |_i| build_stubbed(:status) } } let(:priority) { build_stubbed(:priority, is_default: true) } let(:status) { statuses[0] } @@ -168,142 +168,142 @@ priority:) end - it "always has the work_package class" do - expect(helper.work_package_css_classes(stub_work_package)).to include("work_package") + it 'always has the work_package class' do + expect(helper.work_package_css_classes(stub_work_package)).to include('work_package') end it "returns the position of the work_package's status" do stub_work_package.status = open_status allow(open_status).to receive(:position).and_return(5) - expect(helper.work_package_css_classes(stub_work_package)).to include("status-5") + expect(helper.work_package_css_classes(stub_work_package)).to include('status-5') end it "returns the position of the work_package's priority" do allow(priority).to receive(:position).and_return(5) - expect(helper.work_package_css_classes(stub_work_package)).to include("priority-5") + expect(helper.work_package_css_classes(stub_work_package)).to include('priority-5') end - it "has a closed class if the work_package is closed" do + it 'has a closed class if the work_package is closed' do allow(stub_work_package).to receive(:closed?).and_return(true) - expect(helper.work_package_css_classes(stub_work_package)).to include("closed") + expect(helper.work_package_css_classes(stub_work_package)).to include('closed') end - it "has no closed class if the work_package is not closed" do + it 'has no closed class if the work_package is not closed' do allow(stub_work_package).to receive(:closed?).and_return(false) - expect(helper.work_package_css_classes(stub_work_package)).not_to include("closed") + expect(helper.work_package_css_classes(stub_work_package)).not_to include('closed') end - it "has an overdue class if the work_package is overdue" do + it 'has an overdue class if the work_package is overdue' do allow(stub_work_package).to receive(:overdue?).and_return(true) - expect(helper.work_package_css_classes(stub_work_package)).to include("overdue") + expect(helper.work_package_css_classes(stub_work_package)).to include('overdue') end - it "has an overdue class if the work_package is not overdue" do + it 'has an overdue class if the work_package is not overdue' do allow(stub_work_package).to receive(:overdue?).and_return(false) - expect(helper.work_package_css_classes(stub_work_package)).not_to include("overdue") + expect(helper.work_package_css_classes(stub_work_package)).not_to include('overdue') end - it "has a child class if the work_package is a child" do + it 'has a child class if the work_package is a child' do allow(stub_work_package).to receive(:child?).and_return(true) - expect(helper.work_package_css_classes(stub_work_package)).to include("child") + expect(helper.work_package_css_classes(stub_work_package)).to include('child') end - it "has no child class if the work_package is not a child" do + it 'has no child class if the work_package is not a child' do allow(stub_work_package).to receive(:child?).and_return(false) - expect(helper.work_package_css_classes(stub_work_package)).not_to include("child") + expect(helper.work_package_css_classes(stub_work_package)).not_to include('child') end - it "has a parent class if the work_package is a parent" do + it 'has a parent class if the work_package is a parent' do allow(stub_work_package).to receive(:leaf?).and_return(false) - expect(helper.work_package_css_classes(stub_work_package)).to include("parent") + expect(helper.work_package_css_classes(stub_work_package)).to include('parent') end - it "has no parent class if the work_package is not a parent" do + it 'has no parent class if the work_package is not a parent' do allow(stub_work_package).to receive(:leaf?).and_return(true) - expect(helper.work_package_css_classes(stub_work_package)).not_to include("parent") + expect(helper.work_package_css_classes(stub_work_package)).not_to include('parent') end - it "has a created-by-me class if the work_package is a created by the current user" do - stub_user = double("user", logged?: true, id: 5) + it 'has a created-by-me class if the work_package is a created by the current user' do + stub_user = double('user', logged?: true, id: 5) allow(User).to receive(:current).and_return(stub_user) allow(stub_work_package).to receive(:author_id).and_return(5) - expect(helper.work_package_css_classes(stub_work_package)).to include("created-by-me") + expect(helper.work_package_css_classes(stub_work_package)).to include('created-by-me') end - it "has no created-by-me class if the work_package is not created by the current user" do - stub_user = double("user", logged?: true, id: 5) + it 'has no created-by-me class if the work_package is not created by the current user' do + stub_user = double('user', logged?: true, id: 5) allow(User).to receive(:current).and_return(stub_user) allow(stub_work_package).to receive(:author_id).and_return(4) - expect(helper.work_package_css_classes(stub_work_package)).not_to include("created-by-me") + expect(helper.work_package_css_classes(stub_work_package)).not_to include('created-by-me') end - it "has a created-by-me class if the work_package is the current user is not logged in" do - expect(helper.work_package_css_classes(stub_work_package)).not_to include("created-by-me") + it 'has a created-by-me class if the work_package is the current user is not logged in' do + expect(helper.work_package_css_classes(stub_work_package)).not_to include('created-by-me') end - it "has a assigned-to-me class if the work_package is a created by the current user" do - stub_user = double("user", logged?: true, id: 5) + it 'has a assigned-to-me class if the work_package is a created by the current user' do + stub_user = double('user', logged?: true, id: 5) allow(User).to receive(:current).and_return(stub_user) allow(stub_work_package).to receive(:assigned_to_id).and_return(5) - expect(helper.work_package_css_classes(stub_work_package)).to include("assigned-to-me") + expect(helper.work_package_css_classes(stub_work_package)).to include('assigned-to-me') end - it "has no assigned-to-me class if the work_package is not created by the current user" do - stub_user = double("user", logged?: true, id: 5) + it 'has no assigned-to-me class if the work_package is not created by the current user' do + stub_user = double('user', logged?: true, id: 5) allow(User).to receive(:current).and_return(stub_user) allow(stub_work_package).to receive(:assigned_to_id).and_return(4) - expect(helper.work_package_css_classes(stub_work_package)).not_to include("assigned-to-me") + expect(helper.work_package_css_classes(stub_work_package)).not_to include('assigned-to-me') end - it "has no assigned-to-me class if the work_package is the current user is not logged in" do - expect(helper.work_package_css_classes(stub_work_package)).not_to include("assigned-to-me") + it 'has no assigned-to-me class if the work_package is the current user is not logged in' do + expect(helper.work_package_css_classes(stub_work_package)).not_to include('assigned-to-me') end end - describe "#work_packages_columns_options" do - it "returns the columns options" do + describe '#work_packages_columns_options' do + it 'returns the columns options' do expect(helper.work_packages_columns_options) .to include( - { name: "Type", id: "type" }, - { name: "Subject", id: "subject" }, - { name: "Status", id: "status" } + { name: 'Type', id: 'type' }, + { name: 'Subject', id: 'subject' }, + { name: 'Status', id: 'status' } ) end end - describe "#selected_project_columns_options", + describe '#selected_project_columns_options', with_settings: { work_package_list_default_columns: %w[id subject type status] } do - it "returns the columns options currently persisted in the setting (in that order)" do + it 'returns the columns options currently persisted in the setting (in that order)' do expect(helper.selected_work_packages_columns_options) .to eql([ - { name: "ID", id: "id" }, - { name: "Subject", id: "subject" }, - { name: "Type", id: "type" }, - { name: "Status", id: "status" } + { name: 'ID', id: 'id' }, + { name: 'Subject', id: 'subject' }, + { name: 'Type', id: 'type' }, + { name: 'Status', id: 'status' } ]) end end - describe "#protected_project_columns_options" do - it "returns the columns options currently persisted in the setting (in that order)" do + describe '#protected_project_columns_options' do + it 'returns the columns options currently persisted in the setting (in that order)' do expect(helper.protected_work_packages_columns_options) .to eql([ - { name: "ID", id: "id" }, - { name: "Subject", id: "subject" } + { name: 'ID', id: 'id' }, + { name: 'Subject', id: 'subject' } ]) end end diff --git a/spec/jobs/attachments/virus_rescan_job_spec.rb b/spec/jobs/attachments/virus_rescan_job_spec.rb index 7d32f941a5d5..27bd0c36920f 100644 --- a/spec/jobs/attachments/virus_rescan_job_spec.rb +++ b/spec/jobs/attachments/virus_rescan_job_spec.rb @@ -1,4 +1,4 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe Attachments::VirusRescanJob, with_ee: %i[virus_scanning], @@ -15,8 +15,8 @@ allow(ClamAV::Client).to receive(:new).and_return(client_double) end - describe "#perform" do - let(:response) { ClamAV::SuccessResponse.new("wat") } + describe '#perform' do + let(:response) { ClamAV::SuccessResponse.new('wat') } before do allow(client_double) @@ -24,7 +24,7 @@ .and_return(response) end - it "updates the attachments" do + it 'updates the attachments' do subject expect(attachment1.reload).to be_status_uploaded diff --git a/spec/jobs/attachments/virus_scan_job_spec.rb b/spec/jobs/attachments/virus_scan_job_spec.rb index ec1584197502..5439ec64275d 100644 --- a/spec/jobs/attachments/virus_scan_job_spec.rb +++ b/spec/jobs/attachments/virus_scan_job_spec.rb @@ -1,4 +1,4 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe Attachments::VirusScanJob, with_ee: %i[virus_scanning], @@ -14,35 +14,35 @@ allow(ClamAV::Client).to receive(:new).and_return(client_double) end - describe "#perform when disabled", with_settings: { antivirus_scan_mode: :disabled } do - it "does not scan the attachment" do + describe '#perform when disabled', with_settings: { antivirus_scan_mode: :disabled } do + it 'does not scan the attachment' do subject expect(ClamAV::Client).not_to have_received(:new) end end - context "when status is not uploaded" do + context 'when status is not uploaded' do let(:attachment_status) { :prepared } - it "does not scan the attachment" do + it 'does not scan the attachment' do subject expect(ClamAV::Client).not_to have_received(:new) end end - describe "#perform" do + describe '#perform' do before do allow(client_double) .to receive(:execute).with(instance_of(ClamAV::Commands::InstreamCommand)) .and_return(response) end - context "when no virus is found" do - let(:response) { ClamAV::SuccessResponse.new("wat") } + context 'when no virus is found' do + let(:response) { ClamAV::SuccessResponse.new('wat') } - it "updates the file status" do + it 'updates the file status' do allow(attachment).to receive(:update!) subject @@ -51,10 +51,10 @@ end end - context "when error occurs in clamav" do - let(:response) { ClamAV::ErrorResponse.new("Oh noes") } + context 'when error occurs in clamav' do + let(:response) { ClamAV::ErrorResponse.new('Oh noes') } - it "does nothing to the file" do + it 'does nothing to the file' do allow(attachment).to receive(:update!) expect { subject }.not_to raise_error @@ -63,11 +63,11 @@ end end - context "when virus is found" do - let(:response) { ClamAV::VirusResponse.new("wat", "Eicar-Test-Signature") } + context 'when virus is found' do + let(:response) { ClamAV::VirusResponse.new('wat', 'Eicar-Test-Signature') } - context "when action is quarantine", with_settings: { antivirus_scan_action: :quarantine } do - it "quarantines the file" do + context 'when action is quarantine', with_settings: { antivirus_scan_action: :quarantine } do + it 'quarantines the file' do allow(attachment).to receive(:update!) allow(Journals::CreateService).to receive(:new).and_return(journal_service_double) allow(journal_service_double).to receive(:call) @@ -80,8 +80,8 @@ end end - context "when action is delete", with_settings: { antivirus_scan_action: :delete } do - it "deletes the file" do + context 'when action is delete', with_settings: { antivirus_scan_action: :delete } do + it 'deletes the file' do allow(attachment).to receive(:destroy!) allow(Journals::CreateService).to receive(:new).and_return(journal_service_double) allow(journal_service_double).to receive(:call) diff --git a/spec/lib/acts_as_journalized/journable_differ_spec.rb b/spec/lib/acts_as_journalized/journable_differ_spec.rb index f1572ee21b8f..fb93bb9d6a98 100644 --- a/spec/lib/acts_as_journalized/journable_differ_spec.rb +++ b/spec/lib/acts_as_journalized/journable_differ_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Acts::Journalized::JournableDiffer do - describe ".changes" do - context "when the objects are work packages" do + describe '.changes' do + context 'when the objects are work packages' do let(:original) do build_stubbed(:work_package, - subject: "The original work package title", + subject: 'The original work package title', description: "The description\n", assigned_to_id: nil, schedule_manually: false, @@ -42,7 +42,7 @@ end let(:changed) do build_stubbed(:work_package, - subject: "The changed work package title", + subject: 'The changed work package title', description: "The description\r\n", priority: original.priority, type: original.type, @@ -52,7 +52,7 @@ estimated_hours: nil) end - it "returns the changes" do + it 'returns the changes' do expect(described_class.changes(original, changed)) .to eql("subject" => [original.subject, changed.subject], "author_id" => [original.author_id, changed.author_id], @@ -63,10 +63,10 @@ end end - context "when the objects are WorkPackageJournal" do + context 'when the objects are WorkPackageJournal' do let(:original) do build_stubbed(:journal_work_package_journal, - subject: "The original work package title", + subject: 'The original work package title', description: nil, priority_id: 5, type_id: 89, @@ -78,8 +78,8 @@ end let(:changed) do build_stubbed(:journal_work_package_journal, - subject: "The changed work package title", - description: "", + subject: 'The changed work package title', + description: '', priority_id: original.priority_id, type_id: original.type_id, project_id: original.project_id, @@ -89,7 +89,7 @@ estimated_hours: 1) end - it "returns the changes" do + it 'returns the changes' do # The description field changes from nil to '', but we want filter those transitions out, # hence the expected hash does not contain the description related change. expect(described_class.changes(original, changed)) @@ -102,8 +102,8 @@ end end - describe ".association_changes" do - context "when the objects are work packages" do + describe '.association_changes' do + context 'when the objects are work packages' do let(:original) do build(:work_package, custom_values: [ @@ -122,8 +122,8 @@ ]) end - it "returns the changes" do - params = [original, changed, "custom_values", "custom_field", :custom_field_id, :value] + it 'returns the changes' do + params = [original, changed, 'custom_values', 'custom_field', :custom_field_id, :value] expect(described_class.association_changes(*params)) .to eql( "custom_field_1" => ["1", ""], diff --git a/spec/lib/acts_as_journalized/journal_formatter_cache_spec.rb b/spec/lib/acts_as_journalized/journal_formatter_cache_spec.rb index 3b4ea91e01cd..3bb168d06d35 100644 --- a/spec/lib/acts_as_journalized/journal_formatter_cache_spec.rb +++ b/spec/lib/acts_as_journalized/journal_formatter_cache_spec.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe JournalFormatterCache do subject(:cache) { described_class.new } - describe "#fetch" do - it "caches and returns the value returned by the block on cache miss" do - expect(cache.fetch(User, 3) { "user_3" }).to eq("user_3") - expect(cache.fetch("Answer", 42) { "Life Universe Everything" }).to eq("Life Universe Everything") + describe '#fetch' do + it 'caches and returns the value returned by the block on cache miss' do + expect(cache.fetch(User, 3) { 'user_3' }).to eq('user_3') + expect(cache.fetch('Answer', 42) { 'Life Universe Everything' }).to eq('Life Universe Everything') end - it "returns nil on cache miss if no block is given" do + it 'returns nil on cache miss if no block is given' do expect(cache.fetch(User, 3)).to be_nil expect(cache.fetch(User, 17)).to be_nil end - it "returns the cached value on cache hit" do - cache.fetch(User, 3) { "user_3" } + it 'returns the cached value on cache hit' do + cache.fetch(User, 3) { 'user_3' } - expect(cache.fetch(User, 3)).to eq("user_3") - expect(cache.fetch(User, 3) { "another value" }).to eq("user_3") + expect(cache.fetch(User, 3)).to eq('user_3') + expect(cache.fetch(User, 3) { 'another value' }).to eq('user_3') expect(cache.fetch(Project, 62)).to be_nil - cache.fetch(Project, 62) { "project_62" } - expect(cache.fetch(Project, 62)).to eq("project_62") - cache.fetch(Project, 62) { "another value" } - expect(cache.fetch(Project, 62)).to eq("project_62") + cache.fetch(Project, 62) { 'project_62' } + expect(cache.fetch(Project, 62)).to eq('project_62') + cache.fetch(Project, 62) { 'another value' } + expect(cache.fetch(Project, 62)).to eq('project_62') end end end diff --git a/spec/lib/acts_as_journalized/journaled_spec.rb b/spec/lib/acts_as_journalized/journaled_spec.rb index c25d902ea64d..60ec4f5d07a9 100644 --- a/spec/lib/acts_as_journalized/journaled_spec.rb +++ b/spec/lib/acts_as_journalized/journaled_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Journalized Objects" do - describe "journal_editable_by?" do - context "when the journable is a work package" do +RSpec.describe 'Journalized Objects' do + describe 'journal_editable_by?' do + context 'when the journable is a work package' do let!(:user) { create(:user, member_with_permissions: { project => [] }) } let!(:project) { create(:project_with_types) } let!(:work_package) do @@ -38,7 +38,7 @@ type: project.types.first, author: user, project:, - description: "") + description: '') end subject { work_package.journal_editable_by?(work_package.journals.first, user) } diff --git a/spec/lib/acts_as_list/acts_as_list_patch_spec.rb b/spec/lib/acts_as_list/acts_as_list_patch_spec.rb index 64cccc59b4ac..48b4b9e942e4 100644 --- a/spec/lib/acts_as_list/acts_as_list_patch_spec.rb +++ b/spec/lib/acts_as_list/acts_as_list_patch_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Models acting as list (acts_as_list)" do - it "includes the patch" do +RSpec.describe 'Models acting as list (acts_as_list)' do + it 'includes the patch' do expect(ActiveRecord::Acts::List::InstanceMethods.included_modules).to include(OpenProject::Patches::ActsAsList) end - describe "#move_to=" do + describe '#move_to=' do let(:includer) do class ActsAsListPatchIncluder include OpenProject::Patches::ActsAsList @@ -42,28 +42,28 @@ class ActsAsListPatchIncluder ActsAsListPatchIncluder.new end - it "moves to top when wanting to move highest" do + it 'moves to top when wanting to move highest' do expect(includer).to receive :move_to_top - includer.move_to = "highest" + includer.move_to = 'highest' end - it "moves to bottom when wanting to move lowest" do + it 'moves to bottom when wanting to move lowest' do expect(includer).to receive :move_to_bottom - includer.move_to = "lowest" + includer.move_to = 'lowest' end - it "moves higher when wanting to move higher" do + it 'moves higher when wanting to move higher' do expect(includer).to receive :move_higher - includer.move_to = "higher" + includer.move_to = 'higher' end - it "moves lower when wanting to move lower" do + it 'moves lower when wanting to move lower' do expect(includer).to receive :move_lower - includer.move_to = "lower" + includer.move_to = 'lower' end end end diff --git a/spec/lib/acts_as_watchable/lib/acts_as_watchable/routes_spec.rb b/spec/lib/acts_as_watchable/lib/acts_as_watchable/routes_spec.rb index c089a1b3be9c..a831a7cb2303 100644 --- a/spec/lib/acts_as_watchable/lib/acts_as_watchable/routes_spec.rb +++ b/spec/lib/acts_as_watchable/lib/acts_as_watchable/routes_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Acts::Watchable::Routes do let(:request) do @@ -37,38 +37,38 @@ def path_parameters end.new(type, id) end - describe "matches?" do - shared_examples_for "watched model" do - describe "for a valid id string" do - let(:id) { "1" } + describe 'matches?' do + shared_examples_for 'watched model' do + describe 'for a valid id string' do + let(:id) { '1' } - it "is true" do + it 'is true' do expect(OpenProject::Acts::Watchable::Routes.matches?(request)).to be_truthy end end - describe "for an invalid id string" do - let(:id) { "schmu" } + describe 'for an invalid id string' do + let(:id) { 'schmu' } - it "is false" do + it 'is false' do expect(OpenProject::Acts::Watchable::Routes.matches?(request)).to be_falsey end end end - ["work_packages", "news", "forums", "messages", "wikis", "wiki_pages"].each do |type| + ['work_packages', 'news', 'forums', 'messages', 'wikis', 'wiki_pages'].each do |type| describe "routing #{type} watches" do let(:type) { type } - it_behaves_like "watched model" + it_behaves_like 'watched model' end end - describe "for a non watched model" do - let(:type) { "schmu" } - let(:id) { "4" } + describe 'for a non watched model' do + let(:type) { 'schmu' } + let(:id) { '4' } - it "is false" do + it 'is false' do expect(OpenProject::Acts::Watchable::Routes.matches?(request)).to be_falsey end end diff --git a/spec/lib/api/contracts/model_contract_spec.rb b/spec/lib/api/contracts/model_contract_spec.rb index 7b7e165e8854..5fb6e803b5ef 100644 --- a/spec/lib/api/contracts/model_contract_spec.rb +++ b/spec/lib/api/contracts/model_contract_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe ModelContract do let(:model) do - double("The model", + double('The model', child_attribute: nil, grand_child_attribute: nil, overwritten_attribute: nil, @@ -41,7 +41,7 @@ errors: ActiveModel::Errors.new(nil)) end - context "with child and grand_child" do + context 'with child and grand_child' do let(:child_contract_class) do Class.new(ModelContract) do attr_accessor :child_value @@ -71,30 +71,30 @@ grand_child_contract.child_value = 0 end - describe "child" do - it "collects its own writable attributes" do - expect(child_contract.writable_attributes).to include("child_attribute", - "overwritten_attribute") + describe 'child' do + it 'collects its own writable attributes' do + expect(child_contract.writable_attributes).to include('child_attribute', + 'overwritten_attribute') end - it "collects its own attribute validations" do + it 'collects its own attribute validations' do child_contract.validate expect(child_contract.child_value).to eq(1) end end - describe "grand_child" do - it "considers its ancestor writable attributes" do - expect(grand_child_contract.writable_attributes).to include("child_attribute", - "overwritten_attribute", - "grand_child_attribute") + describe 'grand_child' do + it 'considers its ancestor writable attributes' do + expect(grand_child_contract.writable_attributes).to include('child_attribute', + 'overwritten_attribute', + 'grand_child_attribute') end - it "does not contain the same attribute twice, but also has the _id variant" do + it 'does not contain the same attribute twice, but also has the _id variant' do expect(grand_child_contract.writable_attributes.count).to eq(6) end - it "executes all the validations" do + it 'executes all the validations' do grand_child_contract.validate expect(grand_child_contract.child_value).to eq(1) expect(grand_child_contract.grand_child_value).to eq(2) @@ -102,7 +102,7 @@ end end - describe "valid?" do + describe 'valid?' do let(:model_contract_class) do Class.new(ModelContract) do attribute :custom_field1 @@ -111,49 +111,49 @@ end let(:model_contract) { model_contract_class.new(model, nil) } - context "when the model extends no plugins" do + context 'when the model extends no plugins' do before do allow(model).to receive(:changed).and_return([:custom_field1]) end - it "adds an error to the custom field attribute" do + it 'adds an error to the custom field attribute' do model_contract.valid? expect(model_contract.errors.symbols_for(:custom_field1)) .to include(:error_readonly) end end - context "when the model extends the acts_as_customizable plugin" do + context 'when the model extends the acts_as_customizable plugin' do before do allow(model).to receive(:changed_with_custom_fields).and_return([:custom_field1]) end - it "adds an error to the custom field attribute" do + it 'adds an error to the custom field attribute' do model_contract.valid? expect(model_contract.errors.symbols_for(:custom_field1)) .to include(:error_readonly) end end - context "when the model extends the OpenProject::ChangedBySystem module" do + context 'when the model extends the OpenProject::ChangedBySystem module' do before do allow(model).to receive(:changed_by_user).and_return([:custom_field1]) end - it "adds an error to the custom field attribute" do + it 'adds an error to the custom field attribute' do model_contract.valid? expect(model_contract.errors.symbols_for(:custom_field1)) .to include(:error_readonly) end end - context "when the model extends both modules" do + context 'when the model extends both modules' do before do allow(model).to receive(:changed_by_user).and_return([:custom_field1]) allow(model).to receive(:changed_with_custom_fields).and_return([:no_allowed]) end - it "adds an error to the custom field attribute from the OpenProject::ChangedBySystem module" do + it 'adds an error to the custom field attribute from the OpenProject::ChangedBySystem module' do model_contract.valid? expect(model_contract.errors.symbols_for(:custom_field1)) .to include(:error_readonly) diff --git a/spec/lib/api/decorators/aggregation_group_spec.rb b/spec/lib/api/decorators/aggregation_group_spec.rb index c3fafba02c08..617d9d628fee 100644 --- a/spec/lib/api/decorators/aggregation_group_spec.rb +++ b/spec/lib/api/decorators/aggregation_group_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::Decorators::AggregationGroup do let(:query) do @@ -35,19 +35,19 @@ query end - let(:group_key) { OpenStruct.new name: "ABC" } + let(:group_key) { OpenStruct.new name: 'ABC' } let(:count) { 5 } let(:current_user) { build_stubbed(:user) } subject { described_class.new(group_key, count, query:, current_user:).to_json } - context "with an empty array key" do + context 'with an empty array key' do let(:group_key) { [] } - it "has an empty value" do + it 'has an empty value' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("value") + .at_path('value') end end end diff --git a/spec/lib/api/decorators/formattable_spec.rb b/spec/lib/api/decorators/formattable_spec.rb index 118df4df5557..afad398937e5 100644 --- a/spec/lib/api/decorators/formattable_spec.rb +++ b/spec/lib/api/decorators/formattable_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::Decorators::Formattable do - let(:represented) { "A **raw** string!" } + let(:represented) { 'A **raw** string!' } subject { described_class.new(represented).to_json } - it "indicates its format" do - expect(subject).to be_json_eql("markdown".to_json).at_path("format") + it 'indicates its format' do + expect(subject).to be_json_eql('markdown'.to_json).at_path('format') end - it "contains the raw string" do - expect(subject).to be_json_eql(represented.to_json).at_path("raw") + it 'contains the raw string' do + expect(subject).to be_json_eql(represented.to_json).at_path('raw') end - it "contains the formatted string" do - expect(subject).to be_json_eql('

    A raw string!

    '.to_json).at_path("html") + it 'contains the formatted string' do + expect(subject).to be_json_eql('

    A raw string!

    '.to_json).at_path('html') end - context "when passing an object context" do + context 'when passing an object context' do let(:object) { build_stubbed(:work_package) } subject { described_class.new(represented, object:) } - it "passes that to format_text" do + it 'passes that to format_text' do # rubocop:disable RSpec/SubjectStub RSpec/MessageSpies expect(subject) .to receive(:format_text).with(anything, format: :markdown, object:) @@ -58,28 +58,28 @@ # rubocop:enable RSpec/SubjectStub RSpec/MessageSpies expect(subject.to_json) - .to be_json_eql('

    A raw string!

    '.to_json).at_path("html") + .to be_json_eql('

    A raw string!

    '.to_json).at_path('html') end end - context "when format specified explicitly" do + context 'when format specified explicitly' do subject { described_class.new(represented, plain: true).to_json } - it "indicates the explicit format" do - expect(subject).to be_json_eql("plain".to_json).at_path("format") + it 'indicates the explicit format' do + expect(subject).to be_json_eql('plain'.to_json).at_path('format') end - it "formats using the explicit format" do - expect(subject).to be_json_eql("

    A **raw** string!

    ".to_json).at_path("html") + it 'formats using the explicit format' do + expect(subject).to be_json_eql('

    A **raw** string!

    '.to_json).at_path('html') end end - context "when passing a nil object as input" do + context 'when passing a nil object as input' do let(:represented) { nil } - it "still outputs a string as per the specification" do - expect(subject).to be_json_eql("".to_json).at_path("raw") - expect(subject).to be_json_eql("".to_json).at_path("html") + it 'still outputs a string as per the specification' do + expect(subject).to be_json_eql(''.to_json).at_path('raw') + expect(subject).to be_json_eql(''.to_json).at_path('html') end end end diff --git a/spec/lib/api/decorators/link_object_spec.rb b/spec/lib/api/decorators/link_object_spec.rb index 5851d8bbeea9..fa891e70ed3f 100644 --- a/spec/lib/api/decorators/link_object_spec.rb +++ b/spec/lib/api/decorators/link_object_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::Decorators::LinkObject do include API::V3::Utilities::PathHelper let(:represented) { API::ParserStruct.new } - context "minimal constructor call" do + context 'minimal constructor call' do let(:representer) { described_class.new(represented, property_name: :foo) } before do @@ -41,34 +41,34 @@ allow(api_v3_paths).to receive(:foo) { |id| "/api/v3/foos/#{id}" } end - describe "generation" do + describe 'generation' do subject { representer.to_json } - it { is_expected.to be_json_eql("/api/v3/foos/1".to_json).at_path("href") } + it { is_expected.to be_json_eql('/api/v3/foos/1'.to_json).at_path('href') } end - describe "parsing" do + describe 'parsing' do subject { represented } let(:parsed_hash) do { - "href" => "/api/v3/foos/42" + 'href' => '/api/v3/foos/42' } end - it "parses the id from the URL" do + it 'parses the id from the URL' do representer.from_hash parsed_hash - expect(subject.foo_id).to eql("42") + expect(subject.foo_id).to eql('42') end - context "wrong namespace" do + context 'wrong namespace' do let(:parsed_hash) do { - "href" => "/api/v3/bars/42" + 'href' => '/api/v3/bars/42' } end - it "throws an error" do + it 'throws an error' do expect { representer.from_hash parsed_hash }.to raise_error( API::Errors::InvalidResourceLink ) @@ -77,14 +77,14 @@ end end - context "full constructor call" do + context 'full constructor call' do let(:representer) do described_class.new(represented, property_name: :foo, path: :foo_path, - namespace: "fuhs", + namespace: 'fuhs', getter: :getter, - setter: :"setter=") + setter: :'setter=') end before do @@ -92,34 +92,34 @@ allow(api_v3_paths).to receive(:foo_path) { |id| "/api/v3/fuhs/#{id}" } end - describe "generation" do + describe 'generation' do subject { representer.to_json } - it { is_expected.to be_json_eql("/api/v3/fuhs/1".to_json).at_path("href") } + it { is_expected.to be_json_eql('/api/v3/fuhs/1'.to_json).at_path('href') } end - describe "parsing" do + describe 'parsing' do subject { represented } let(:parsed_hash) do { - "href" => "/api/v3/fuhs/42" + 'href' => '/api/v3/fuhs/42' } end - it "parses the id from the URL" do + it 'parses the id from the URL' do representer.from_hash parsed_hash - expect(subject.setter).to eql("42") + expect(subject.setter).to eql('42') end - context "wrong namespace" do + context 'wrong namespace' do let(:parsed_hash) do { - "href" => "/api/v3/foos/42" + 'href' => '/api/v3/foos/42' } end - it "throws an error" do + it 'throws an error' do expect { representer.from_hash parsed_hash }.to raise_error( API::Errors::InvalidResourceLink ) diff --git a/spec/lib/api/utilities/property_name_converter_spec.rb b/spec/lib/api/utilities/property_name_converter_spec.rb index 62b23e12fbd7..a085efdd57ae 100644 --- a/spec/lib/api/utilities/property_name_converter_spec.rb +++ b/spec/lib/api/utilities/property_name_converter_spec.rb @@ -26,160 +26,160 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::Utilities::PropertyNameConverter do - describe "#from_ar_name" do + describe '#from_ar_name' do let(:attribute_name) { :an_attribute } subject { described_class.from_ar_name(attribute_name) } - it "stringifies attribute names" do + it 'stringifies attribute names' do expect(subject).to be_a(String) end - it "camelizes attribute names" do - expect(subject).to eql("anAttribute") + it 'camelizes attribute names' do + expect(subject).to eql('anAttribute') end - context "foreign keys" do + context 'foreign keys' do let(:attribute_name) { :thing_id } - it "eliminates the id suffix" do - expect(subject).to eql("thing") + it 'eliminates the id suffix' do + expect(subject).to eql('thing') end end - context "custom fields" do + context 'custom fields' do let(:attribute_name) { :cf_1337 } - it "converts short custom fields to their long form" do - expect(subject).to eql("customField1337") + it 'converts short custom fields to their long form' do + expect(subject).to eql('customField1337') end end # N.B. not re-iterating all existing known replacements here. Just using a single example # to verify that it is done at all - context "special replacements" do + context 'special replacements' do let(:attribute_name) { :assigned_to } - it "performs special replacements" do - expect(subject).to eql("assignee") + it 'performs special replacements' do + expect(subject).to eql('assignee') end - context "foreign keys" do + context 'foreign keys' do let(:attribute_name) { :assigned_to_id } - it "sanitizes id-suffix before replacement lookup" do - expect(subject).to eql("assignee") + it 'sanitizes id-suffix before replacement lookup' do + expect(subject).to eql('assignee') end end end end - describe "#to_ar_name" do - let(:attribute_name) { "anAttribute" } + describe '#to_ar_name' do + let(:attribute_name) { 'anAttribute' } let(:context) { build_stubbed(:work_package) } subject { described_class.to_ar_name(attribute_name, context:) } - it "snake_cases attribute names" do - expect(subject).to eql("an_attribute") + it 'snake_cases attribute names' do + expect(subject).to eql('an_attribute') end - context "foreign keys" do - let(:attribute_name) { "status" } + context 'foreign keys' do + let(:attribute_name) { 'status' } - it "does not add an id suffix by default" do - expect(subject).to eql("status") + it 'does not add an id suffix by default' do + expect(subject).to eql('status') end - context "requesting ids via refer_to_ids" do + context 'requesting ids via refer_to_ids' do subject { described_class.to_ar_name(attribute_name, context:, refer_to_ids: true) } - context "for keys referring to a belongs_to association" do - let(:attribute_name) { "status" } + context 'for keys referring to a belongs_to association' do + let(:attribute_name) { 'status' } - it "adds an id suffix" do - expect(subject).to eql("status_id") + it 'adds an id suffix' do + expect(subject).to eql('status_id') end end - context "for keys referring to a has_many association" do - let(:attribute_name) { "watcher" } + context 'for keys referring to a has_many association' do + let(:attribute_name) { 'watcher' } - it "adds an id suffix" do - expect(subject).to eql("watcher_ids") + it 'adds an id suffix' do + expect(subject).to eql('watcher_ids') end end - context "for non-foreign keys" do - let(:attribute_name) { "subject" } + context 'for non-foreign keys' do + let(:attribute_name) { 'subject' } - it "does not add an id suffix" do - expect(subject).to eql("subject") + it 'does not add an id suffix' do + expect(subject).to eql('subject') end end - context "does not append an id to pluarlized attributes" do - let(:attribute_name) { "estimatedTime" } + context 'does not append an id to pluarlized attributes' do + let(:attribute_name) { 'estimatedTime' } - it "does not add an id suffix" do - expect(subject).to eql("estimated_hours") + it 'does not add an id suffix' do + expect(subject).to eql('estimated_hours') end end end end - context "custom fields" do - let(:attribute_name) { "customField1337" } + context 'custom fields' do + let(:attribute_name) { 'customField1337' } - it "converts long custom fields to their short form" do - expect(subject).to eql("cf_1337") + it 'converts long custom fields to their short form' do + expect(subject).to eql('cf_1337') end end - context "special replacements" do - let(:attribute_name) { "assignee" } + context 'special replacements' do + let(:attribute_name) { 'assignee' } - it "performs special replacements" do - expect(subject).to eql("assigned_to") + it 'performs special replacements' do + expect(subject).to eql('assigned_to') end - context "foreign keys" do - let(:attribute_name) { "assignee" } + context 'foreign keys' do + let(:attribute_name) { 'assignee' } subject { described_class.to_ar_name(attribute_name, context:, refer_to_ids: true) } - it "correctly appends the id suffix" do - expect(subject).to eql("assigned_to_id") + it 'correctly appends the id suffix' do + expect(subject).to eql('assigned_to_id') end end - context "inapropriate back-replacement" do + context 'inapropriate back-replacement' do # should not be translated back to updated_at, which is transformed for ar->api - let(:attribute_name) { "updatedAt" } + let(:attribute_name) { 'updatedAt' } - it "is not performed" do - expect(subject).to eql("updated_at") + it 'is not performed' do + expect(subject).to eql('updated_at') end - context "in an appropriate context" do + context 'in an appropriate context' do let(:context) { build_stubbed(:version) } - it "is performed" do - expect(subject).to eql("updated_at") + it 'is performed' do + expect(subject).to eql('updated_at') end end end - context "inappropriate replacement as context does not respond to it with foreign key" do - let(:attribute_name) { "type" } + context 'inappropriate replacement as context does not respond to it with foreign key' do + let(:attribute_name) { 'type' } subject { described_class.to_ar_name(attribute_name, context:, refer_to_ids: true) } - it "does not take the special replacement but appends the id suffix" do - expect(subject).to eql("type_id") + it 'does not take the special replacement but appends the id suffix' do + expect(subject).to eql('type_id') end end end diff --git a/spec/lib/api/utilities/resource_link_parser_spec.rb b/spec/lib/api/utilities/resource_link_parser_spec.rb index 8fc87c3967de..cf7be9705d68 100644 --- a/spec/lib/api/utilities/resource_link_parser_spec.rb +++ b/spec/lib/api/utilities/resource_link_parser_spec.rb @@ -26,130 +26,130 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::Utilities::ResourceLinkParser do subject { described_class } - describe "#parse" do - shared_examples_for "accepts resource link" do - it "parses the version" do + describe '#parse' do + shared_examples_for 'accepts resource link' do + it 'parses the version' do expect(result[:version]).to eql(version) end - it "parses the namespace" do + it 'parses the namespace' do expect(result[:namespace]).to eql(namespace) end - it "parses the id" do + it 'parses the id' do expect(result[:id]).to eql(id) end end - shared_examples_for "rejects resource link" do - it "is nil" do + shared_examples_for 'rejects resource link' do + it 'is nil' do expect(result).to be_nil end end - describe "generic resource links" do - describe "accepts a simple resource" do - it_behaves_like "accepts resource link" do - let(:result) { subject.parse "/api/v3/statuses/12" } - let(:version) { "3" } - let(:namespace) { "statuses" } - let(:id) { "12" } + describe 'generic resource links' do + describe 'accepts a simple resource' do + it_behaves_like 'accepts resource link' do + let(:result) { subject.parse '/api/v3/statuses/12' } + let(:version) { '3' } + let(:namespace) { 'statuses' } + let(:id) { '12' } end end - describe "accepts a nested namespace resource" do - it_behaves_like "accepts resource link" do - let(:result) { subject.parse "/api/v3/time_entries/activities/12" } - let(:version) { "3" } - let(:namespace) { "time_entries/activities" } - let(:id) { "12" } + describe 'accepts a nested namespace resource' do + it_behaves_like 'accepts resource link' do + let(:result) { subject.parse '/api/v3/time_entries/activities/12' } + let(:version) { '3' } + let(:namespace) { 'time_entries/activities' } + let(:id) { '12' } end end - describe "rejects resources with empty id segment" do - it_behaves_like "rejects resource link" do - let(:result) { subject.parse "/api/v3/statuses/" } + describe 'rejects resources with empty id segment' do + it_behaves_like 'rejects resource link' do + let(:result) { subject.parse '/api/v3/statuses/' } end end - describe "rejects resource with missing id segment" do - it_behaves_like "rejects resource link" do - let(:result) { subject.parse "/api/v3/statuses" } + describe 'rejects resource with missing id segment' do + it_behaves_like 'rejects resource link' do + let(:result) { subject.parse '/api/v3/statuses' } end end - describe "rejects the api root" do - it_behaves_like "rejects resource link" do - let(:result) { subject.parse "/api/v3/" } + describe 'rejects the api root' do + it_behaves_like 'rejects resource link' do + let(:result) { subject.parse '/api/v3/' } end end - describe "rejects nested resources" do - it_behaves_like "rejects resource link" do - let(:result) { subject.parse "/api/v3/statuses/imaginary/" } + describe 'rejects nested resources' do + it_behaves_like 'rejects resource link' do + let(:result) { subject.parse '/api/v3/statuses/imaginary/' } end end end end - describe "#parse_id" do - it "parses the id" do - expect(subject.parse_id("/api/v3/statuses/14", property: "foo")).to eql("14") + describe '#parse_id' do + it 'parses the id' do + expect(subject.parse_id('/api/v3/statuses/14', property: 'foo')).to eql('14') end - it "parses the id with nested namespace" do - expect(subject.parse_id("/api/v3/statuses/nested/14", property: "foo")).to eql("14") + it 'parses the id with nested namespace' do + expect(subject.parse_id('/api/v3/statuses/nested/14', property: 'foo')).to eql('14') end - it "parses a non decimal id with nested namespace" do - expect(subject.parse_id("/api/v3/statuses/nested/=", property: "foo")).to eql("=") + it 'parses a non decimal id with nested namespace' do + expect(subject.parse_id('/api/v3/statuses/nested/=', property: 'foo')).to eql('=') end - it "accepts on matching version" do + it 'accepts on matching version' do expect do - subject.parse_id("/api/v3/statuses/14", property: "foo", expected_version: "3") + subject.parse_id('/api/v3/statuses/14', property: 'foo', expected_version: '3') end.not_to raise_error end - it "accepts on matching version as integer" do + it 'accepts on matching version as integer' do expect do - subject.parse_id("/api/v3/statuses/14", property: "foo", expected_version: 3) + subject.parse_id('/api/v3/statuses/14', property: 'foo', expected_version: 3) end.not_to raise_error end - it "accepts on matching namespace" do + it 'accepts on matching namespace' do expect do - subject.parse_id("/api/v3/statuses/14", property: "foo", expected_namespace: "statuses") + subject.parse_id('/api/v3/statuses/14', property: 'foo', expected_namespace: 'statuses') end.not_to raise_error end - it "accepts on matching namespace as symbol" do + it 'accepts on matching namespace as symbol' do expect do - subject.parse_id("/api/v3/statuses/14", property: "foo", expected_namespace: :statuses) + subject.parse_id('/api/v3/statuses/14', property: 'foo', expected_namespace: :statuses) end.not_to raise_error end - it "raises on version mismatch" do + it 'raises on version mismatch' do expect do - subject.parse_id("/api/v4/statuses/14", property: "foo", expected_version: "3") + subject.parse_id('/api/v4/statuses/14', property: 'foo', expected_version: '3') end.to raise_error(API::Errors::InvalidResourceLink) end - it "raises on namespace mismatch" do + it 'raises on namespace mismatch' do expect do - subject.parse_id("/api/v3/types/14", property: "foo", expected_namespace: "statuses") + subject.parse_id('/api/v3/types/14', property: 'foo', expected_namespace: 'statuses') end.to raise_error(API::Errors::InvalidResourceLink) end - it "contains the property name in exception messages" do - property_name = "My Property Name" + it 'contains the property name in exception messages' do + property_name = 'My Property Name' expect do - subject.parse_id("/api/v4/statuses/14", property: property_name, expected_version: "3") + subject.parse_id('/api/v4/statuses/14', property: property_name, expected_version: '3') end.to raise_error(Regexp.compile(property_name)) end end diff --git a/spec/lib/api/utilities/url_props_parsing_helper_spec.rb b/spec/lib/api/utilities/url_props_parsing_helper_spec.rb index 6926688580c0..01961bf99237 100644 --- a/spec/lib/api/utilities/url_props_parsing_helper_spec.rb +++ b/spec/lib/api/utilities/url_props_parsing_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::Utilities::UrlPropsParsingHelper do let(:clazz) do @@ -36,17 +36,17 @@ end let(:subject) { clazz.new } - describe "#maximum_page_size" do - context "when small values in per_page_options", - with_settings: { per_page_options: "20,100", apiv3_max_page_size: 57 } do - it "uses the value from settings" do + describe '#maximum_page_size' do + context 'when small values in per_page_options', + with_settings: { per_page_options: '20,100', apiv3_max_page_size: 57 } do + it 'uses the value from settings' do expect(subject.maximum_page_size).to eq(57) end end - context "when larger values in per_page_options", - with_settings: { per_page_options: "20,100,1000", apiv3_max_page_size: 57 } do - it "uses that value" do + context 'when larger values in per_page_options', + with_settings: { per_page_options: '20,100,1000', apiv3_max_page_size: 57 } do + it 'uses that value' do expect(subject.maximum_page_size).to eq(57) end end diff --git a/spec/lib/api/v3/actions/action_sql_respresenter_rendering_spec.rb b/spec/lib/api/v3/actions/action_sql_respresenter_rendering_spec.rb index 3d5248388317..83593c8404d4 100644 --- a/spec/lib/api/v3/actions/action_sql_respresenter_rendering_spec.rb +++ b/spec/lib/api/v3/actions/action_sql_respresenter_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Actions::ActionSqlRepresenter, "rendering" do +RSpec.describe API::V3::Actions::ActionSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:scope) do @@ -37,7 +37,7 @@ .limit(1) end let(:action_id) do - "memberships/create" + 'memberships/create' end current_user do @@ -48,13 +48,13 @@ API::V3::Utilities::SqlRepresenterWalker .new(scope, current_user:, - url_query: { select: { "id" => {}, "_type" => {}, "self" => {} } }) + url_query: { select: { 'id' => {}, '_type' => {}, 'self' => {} } }) .walk(API::V3::Actions::ActionSqlRepresenter) .to_json end - context "with a project action" do - it "renders as expected" do + context 'with a project action' do + it 'renders as expected' do expect(json) .to be_json_eql({ id: action_id, diff --git a/spec/lib/api/v3/activities/activity_eager_loading_wrapper_spec.rb b/spec/lib/api/v3/activities/activity_eager_loading_wrapper_spec.rb index 2bdd3ce9c36c..dd77a9f4a29b 100644 --- a/spec/lib/api/v3/activities/activity_eager_loading_wrapper_spec.rb +++ b/spec/lib/api/v3/activities/activity_eager_loading_wrapper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Activities::ActivityEagerLoadingWrapper, with_settings: { journal_aggregation_time_minutes: 0 } do shared_let(:user) { create(:user) } @@ -34,8 +34,8 @@ shared_let(:work_package) { create(:work_package, project:, author: user) } shared_let(:meeting) { create(:meeting, project:, author: user) } - describe ".wrap" do - it "returns wrapped journals with relations eager loaded" do + describe '.wrap' do + it 'returns wrapped journals with relations eager loaded' do 9.times { |i| work_package.update(subject: "Subject ##{i}") } journals = Journal.for_work_package @@ -50,59 +50,59 @@ end end - it "can wrap Project journals" do + it 'can wrap Project journals' do expect(project.journals).to be_wrappable end - it "can wrap Document journals" do + it 'can wrap Document journals' do document = create(:document, project:) expect(document.journals).to be_wrappable end - it "can wrap TimeEntry journals" do + it 'can wrap TimeEntry journals' do time_entry = create(:time_entry, project:, work_package:, user:) expect(time_entry.journals).to be_wrappable end - it "can wrap Meeting journals" do + it 'can wrap Meeting journals' do expect(meeting.journals).to be_wrappable end - it "can wrap MeetingAgenda journals" do + it 'can wrap MeetingAgenda journals' do meeting_agenda = create(:meeting_agenda, meeting:) expect(meeting_agenda.journals).to be_wrappable end - it "can wrap MeetingMinutes journals" do + it 'can wrap MeetingMinutes journals' do meeting_minutes = create(:meeting_minutes, meeting:) expect(meeting_minutes.journals).to be_wrappable end - it "can wrap Budget journals" do + it 'can wrap Budget journals' do budget = create(:budget, project:, author: user) expect(budget.journals).to be_wrappable end - it "can wrap WorkPackage journals" do + it 'can wrap WorkPackage journals' do expect(work_package.journals).to be_wrappable end - it "can wrap Changeset journals" do + it 'can wrap Changeset journals' do changeset = create(:changeset, repository: create(:repository_git, project:)) expect(changeset.journals).to be_wrappable end - it "can wrap News journals" do + it 'can wrap News journals' do news = create(:news, project:, author: user) expect(news.journals).to be_wrappable end - it "can wrap WikiPage journals" do + it 'can wrap WikiPage journals' do wiki_content = create(:wiki_page, author: user) expect(wiki_content.journals).to be_wrappable end - it "can wrap Message journals" do + it 'can wrap Message journals' do message = create(:message, author: user) expect(message.journals).to be_wrappable end diff --git a/spec/lib/api/v3/activities/activity_representer_rendering_spec.rb b/spec/lib/api/v3/activities/activity_representer_rendering_spec.rb index 419b88174ee8..426d4e755b4b 100644 --- a/spec/lib/api/v3/activities/activity_representer_rendering_spec.rb +++ b/spec/lib/api/v3/activities/activity_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Activities::ActivityRepresenter, "rendering" do +RSpec.describe API::V3::Activities::ActivityRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } @@ -56,87 +56,87 @@ subject(:generated) { representer.to_json } - describe "properties" do - describe "type" do - context "with notes" do - let(:notes) { "Some notes" } + describe 'properties' do + describe 'type' do + context 'with notes' do + let(:notes) { 'Some notes' } - it_behaves_like "property", :_type do - let(:value) { "Activity::Comment" } + it_behaves_like 'property', :_type do + let(:value) { 'Activity::Comment' } end end - context "with empty notes" do - let(:notes) { "" } + context 'with empty notes' do + let(:notes) { '' } - it_behaves_like "property", :_type do - let(:value) { "Activity" } + it_behaves_like 'property', :_type do + let(:value) { 'Activity' } end end - context "with empty notes and empty changes" do - let(:notes) { "" } + context 'with empty notes and empty changes' do + let(:notes) { '' } let(:changes) { {} } - it_behaves_like "property", :_type do - let(:value) { "Activity::Comment" } + it_behaves_like 'property', :_type do + let(:value) { 'Activity::Comment' } end end end - describe "id" do - it_behaves_like "property", :id do + describe 'id' do + it_behaves_like 'property', :id do let(:value) { journal.id } end end - describe "createdAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'createdAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { journal.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end - describe "updatedAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'updatedAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { journal.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - describe "version" do - it_behaves_like "property", :version do + describe 'version' do + it_behaves_like 'property', :version do let(:value) { journal.version } end end - describe "comment" do - it_behaves_like "API V3 formattable", "comment" do - let(:format) { "markdown" } + describe 'comment' do + it_behaves_like 'API V3 formattable', 'comment' do + let(:format) { 'markdown' } let(:raw) { journal.notes } let(:html) { "

    #{journal.notes}

    " } end - context "if having no change and notes" do + context 'if having no change and notes' do let(:notes) { "" } let(:changes) { {} } - it_behaves_like "API V3 formattable", "comment" do - let(:format) { "markdown" } - let(:raw) { "_#{I18n.t(:"journals.changes_retracted")}_" } - let(:html) { "

    #{I18n.t(:"journals.changes_retracted")}

    " } + it_behaves_like 'API V3 formattable', 'comment' do + let(:format) { 'markdown' } + let(:raw) { "_#{I18n.t(:'journals.changes_retracted')}_" } + let(:html) { "

    #{I18n.t(:'journals.changes_retracted')}

    " } end end end - describe "details" do - it { is_expected.to have_json_path("details") } + describe 'details' do + it { is_expected.to have_json_path('details') } - it { is_expected.to have_json_size(journal.details.count).at_path("details") } + it { is_expected.to have_json_size(journal.details.count).at_path('details') } - it "renders all details as formattable" do + it 'renders all details as formattable' do (0..journal.details.count - 1).each do |x| - expect(subject).to be_json_eql("custom".to_json).at_path("details/#{x}/format") + expect(subject).to be_json_eql('custom'.to_json).at_path("details/#{x}/format") expect(subject).to have_json_path("details/#{x}/raw") expect(subject).to have_json_path("details/#{x}/html") end @@ -144,43 +144,43 @@ end end - describe "_links" do - describe "self" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.activity journal.id } end end - describe "workPackage" do - it_behaves_like "has a titled link" do - let(:link) { "workPackage" } + describe 'workPackage' do + it_behaves_like 'has a titled link' do + let(:link) { 'workPackage' } let(:href) { api_v3_paths.work_package work_package.id } let(:title) { work_package.subject } end end - describe "user" do - it_behaves_like "has an untitled link" do - let(:link) { "user" } + describe 'user' do + it_behaves_like 'has an untitled link' do + let(:link) { 'user' } let(:href) { api_v3_paths.user other_user.id } end end - describe "update" do - let(:link) { "update" } + describe 'update' do + let(:link) { 'update' } let(:href) { api_v3_paths.activity(journal.id) } - it_behaves_like "has an untitled link" + it_behaves_like 'has an untitled link' - context "with a non own journal having edit_work_package_notes permission" do - it_behaves_like "has an untitled link" + context 'with a non own journal having edit_work_package_notes permission' do + it_behaves_like 'has an untitled link' end - context "with a non own journal having only edit_own work_package_notes permission" do + context 'with a non own journal having only edit_own work_package_notes permission' do let(:permissions) { %i(edit_own_work_package_notes) } - it_behaves_like "has no link" + it_behaves_like 'has no link' end end end diff --git a/spec/lib/api/v3/attachments/attachment_metadata_representer_spec.rb b/spec/lib/api/v3/attachments/attachment_metadata_representer_spec.rb index c28a8a10d317..e17c6b1b4e6b 100644 --- a/spec/lib/api/v3/attachments/attachment_metadata_representer_spec.rb +++ b/spec/lib/api/v3/attachments/attachment_metadata_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Attachments::AttachmentParsingRepresenter do let(:current_user) { build_stubbed(:user) } @@ -39,24 +39,24 @@ data.digest = original_digest data end - let(:original_file_name) { "a file name" } - let(:original_description) { "a description" } - let(:original_content_type) { "text/plain" } + let(:original_file_name) { 'a file name' } + let(:original_description) { 'a description' } + let(:original_content_type) { 'text/plain' } let(:original_file_size) { 42 } let(:original_digest) { "0xFF" } let(:representer) { described_class.new(metadata, current_user:) } include API::V3::Utilities::PathHelper - describe "parsing" do + describe 'parsing' do let(:parsed_hash) do { - "metadata" => { - "fileName" => "the parsed name", - "description" => { "raw" => "the parsed description" }, - "contentType" => "text/html", - "fileSize" => 43, - "digest" => "0x00" + 'metadata' => { + 'fileName' => 'the parsed name', + 'description' => { 'raw' => 'the parsed description' }, + 'contentType' => 'text/html', + 'fileSize' => 43, + 'digest' => '0x00' } } end @@ -67,10 +67,10 @@ representer.from_hash parsed_hash end - it { expect(subject.filename).to eql("the parsed name") } - it { expect(subject.description).to eql("the parsed description") } - it { expect(subject.content_type).to eql("text/html") } + it { expect(subject.filename).to eql('the parsed name') } + it { expect(subject.description).to eql('the parsed description') } + it { expect(subject.content_type).to eql('text/html') } it { expect(subject.filesize).to be(43) } - it { expect(subject.digest).to eql("0x00") } + it { expect(subject.digest).to eql('0x00') } end end diff --git a/spec/lib/api/v3/attachments/attachment_representer_spec.rb b/spec/lib/api/v3/attachments/attachment_representer_spec.rb index 1e1ea67625c9..d21ac1c975ba 100644 --- a/spec/lib/api/v3/attachments/attachment_representer_spec.rb +++ b/spec/lib/api/v3/attachments/attachment_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Attachments::AttachmentRepresenter do include API::V3::Utilities::PathHelper @@ -46,7 +46,7 @@ author:) do |attachment| allow(attachment) .to receive(:filename) - .and_return("some_file_of_mine.txt") + .and_return('some_file_of_mine.txt') end end @@ -62,73 +62,73 @@ subject { representer.to_json } - it { is_expected.to be_json_eql("Attachment".to_json).at_path("_type") } - it { is_expected.to be_json_eql(attachment.id.to_json).at_path("id") } - it { is_expected.to be_json_eql(attachment.filename.to_json).at_path("fileName") } - it { is_expected.to be_json_eql(attachment.filesize.to_json).at_path("fileSize") } - it { is_expected.to be_json_eql(attachment.content_type.to_json).at_path("contentType") } - it { is_expected.to be_json_eql("uploaded".to_json).at_path("status") } + it { is_expected.to be_json_eql('Attachment'.to_json).at_path('_type') } + it { is_expected.to be_json_eql(attachment.id.to_json).at_path('id') } + it { is_expected.to be_json_eql(attachment.filename.to_json).at_path('fileName') } + it { is_expected.to be_json_eql(attachment.filesize.to_json).at_path('fileSize') } + it { is_expected.to be_json_eql(attachment.content_type.to_json).at_path('contentType') } + it { is_expected.to be_json_eql('uploaded'.to_json).at_path('status') } - it_behaves_like "API V3 formattable", "description" do - let(:format) { "plain" } + it_behaves_like 'API V3 formattable', 'description' do + let(:format) { 'plain' } let(:raw) { attachment.description } end - it_behaves_like "API V3 digest" do - let(:path) { "digest" } - let(:algorithm) { "md5" } + it_behaves_like 'API V3 digest' do + let(:path) { 'digest' } + let(:algorithm) { 'md5' } let(:hash) { attachment.digest } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { attachment.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.attachment(attachment.id) } let(:title) { attachment.filename } end - context "for a work package container" do - it_behaves_like "has a titled link" do - let(:link) { "container" } + context 'for a work package container' do + it_behaves_like 'has a titled link' do + let(:link) { 'container' } let(:href) { api_v3_paths.work_package(container.id) } let(:title) { container.subject } end end - context "for a wiki page container" do + context 'for a wiki page container' do let(:container) { build_stubbed(:wiki_page) } - it_behaves_like "has a titled link" do - let(:link) { "container" } + it_behaves_like 'has a titled link' do + let(:link) { 'container' } let(:href) { api_v3_paths.wiki_page(container.id) } let(:title) { container.title } end end - context "without a container" do + context 'without a container' do let(:container) { nil } - it_behaves_like "has an untitled link" do - let(:link) { "container" } + it_behaves_like 'has an untitled link' do + let(:link) { 'container' } let(:href) { nil } end end - describe "downloadLocation link" do - context "for a local attachment" do - it_behaves_like "has an untitled link" do - let(:link) { "downloadLocation" } + describe 'downloadLocation link' do + context 'for a local attachment' do + it_behaves_like 'has an untitled link' do + let(:link) { 'downloadLocation' } let(:href) { api_v3_paths.attachment_content(attachment.id) } end end - context "for a remote attachment" do - let(:external_url) { "https://some.bogus/download/xyz" } + context 'for a remote attachment' do + let(:external_url) { 'https://some.bogus/download/xyz' } before do allow(attachment) @@ -139,65 +139,65 @@ .and_return(external_url) end - it_behaves_like "has an untitled link" do - let(:link) { "downloadLocation" } + it_behaves_like 'has an untitled link' do + let(:link) { 'downloadLocation' } let(:href) { external_url } end - it_behaves_like "has an untitled link" do - let(:link) { "staticDownloadLocation" } + it_behaves_like 'has an untitled link' do + let(:link) { 'staticDownloadLocation' } let(:href) { api_v3_paths.attachment_content(attachment.id) } end end end - it_behaves_like "has a titled link" do - let(:link) { "author" } + it_behaves_like 'has a titled link' do + let(:link) { 'author' } let(:href) { api_v3_paths.user(attachment.author.id) } let(:title) { attachment.author.name } end - describe "delete link" do - it_behaves_like "has an untitled link" do - let(:link) { "delete" } + describe 'delete link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.attachment(attachment.id) } end - it "has the DELETE method" do - expect(subject).to be_json_eql("delete".to_json).at_path("_links/delete/method") + it 'has the DELETE method' do + expect(subject).to be_json_eql('delete'.to_json).at_path('_links/delete/method') end - context "user is not allowed to edit the container" do + context 'user is not allowed to edit the container' do let(:permissions) { all_permissions - [:edit_work_packages] } - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end - context "attachment has no container" do + context 'attachment has no container' do let(:container) { nil } - context "user is the author" do - it_behaves_like "has an untitled link" do - let(:link) { "delete" } + context 'user is the author' do + it_behaves_like 'has an untitled link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.attachment(attachment.id) } end end - context "user is not the author" do + context 'user is not the author' do let(:author) { build_stubbed(:user) } - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end end end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -206,22 +206,22 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Attachments", "AttachmentRepresenter") + .to include('API', 'V3', 'Attachments', 'AttachmentRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the attachment is changed (has no update)" do + it 'changes when the attachment is changed (has no update)' do attachment.updated_at = Time.now + 10.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/capabilities/capability_sql_representer_rendering_spec.rb b/spec/lib/api/v3/capabilities/capability_sql_representer_rendering_spec.rb index d6fd2bf1abf1..2d9ac6042af5 100644 --- a/spec/lib/api/v3/capabilities/capability_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/capabilities/capability_sql_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Capabilities::CapabilitySqlRepresenter, "rendering" do +RSpec.describe API::V3::Capabilities::CapabilitySqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:scope) do @@ -59,14 +59,14 @@ .new( scope, current_user:, - url_query: { select: { "id" => {}, "_type" => {}, "self" => {}, "action" => {}, "context" => {}, "principal" => {} } } + url_query: { select: { 'id' => {}, '_type' => {}, 'self' => {}, 'action' => {}, 'context' => {}, 'principal' => {} } } ) .walk(described_class) .to_json end - context "with a project and user" do - it "renders as expected" do + context 'with a project and user' do + it 'renders as expected' do expect(json) .to be_json_eql({ id: "activities/read/p#{context.id}-#{principal.id}", @@ -91,13 +91,13 @@ end end - context "with a project and group" do + context 'with a project and group' do let(:principal) do create(:group, member_with_permissions: { project => %i[view_members] }) end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql({ id: "memberships/read/p#{context.id}-#{principal.id}", @@ -122,7 +122,7 @@ end end - context "with a global permission" do + context 'with a global permission' do let(:principal) do create(:user, global_permissions: %i[create_user], @@ -130,7 +130,7 @@ end let(:context) { nil } - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql({ id: "users/create/g-#{principal.id}", @@ -138,7 +138,7 @@ _links: { context: { href: api_v3_paths.capabilities_contexts_global, - title: "Global" + title: 'Global' }, principal: { href: api_v3_paths.user(principal.id), diff --git a/spec/lib/api/v3/capabilities/contexts/global_representer_rendering_spec.rb b/spec/lib/api/v3/capabilities/contexts/global_representer_rendering_spec.rb index 22c820e6c324..e0c59992d58e 100644 --- a/spec/lib/api/v3/capabilities/contexts/global_representer_rendering_spec.rb +++ b/spec/lib/api/v3/capabilities/contexts/global_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Capabilities::Contexts::GlobalRepresenter, "rendering" do +RSpec.describe API::V3::Capabilities::Contexts::GlobalRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject { representer.to_json } @@ -40,22 +40,22 @@ embed_links: true) end - describe "_links" do - describe "self" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.capabilities_contexts_global } end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "CapabilityContext" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'CapabilityContext' } end - it_behaves_like "property", :id do - let(:value) { "global" } + it_behaves_like 'property', :id do + let(:value) { 'global' } end end end diff --git a/spec/lib/api/v3/categories/category_collection_representer_spec.rb b/spec/lib/api/v3/categories/category_collection_representer_spec.rb index 0547487c75b1..d3d891197aa3 100644 --- a/spec/lib/api/v3/categories/category_collection_representer_spec.rb +++ b/spec/lib/api/v3/categories/category_collection_representer_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Categories::CategoryCollectionRepresenter do let(:categories) { build_list(:category, 3) } let(:representer) do described_class.new(categories, - self_link: "/api/v3/projects/1/categories", - current_user: double("current_user")) + self_link: '/api/v3/projects/1/categories', + current_user: double('current_user')) end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "projects/1/categories", "Category" + it_behaves_like 'unpaginated APIv3 collection', 3, 'projects/1/categories', 'Category' end end diff --git a/spec/lib/api/v3/categories/category_representer_spec.rb b/spec/lib/api/v3/categories/category_representer_spec.rb index 493d881b233a..9582d7dda3ae 100644 --- a/spec/lib/api/v3/categories/category_representer_spec.rb +++ b/spec/lib/api/v3/categories/category_representer_spec.rb @@ -26,67 +26,67 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Categories::CategoryRepresenter do let(:category) { build_stubbed(:category) } let(:user) { build(:user) } - let(:representer) { described_class.new(category, current_user: double("current_user")) } + let(:representer) { described_class.new(category, current_user: double('current_user')) } - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - shared_examples_for "category has core values" do - it { is_expected.to include_json("Category".to_json).at_path("_type") } + shared_examples_for 'category has core values' do + it { is_expected.to include_json('Category'.to_json).at_path('_type') } - it { is_expected.to have_json_type(Object).at_path("_links") } + it { is_expected.to have_json_type(Object).at_path('_links') } - it "links to self" do - expect(subject).to have_json_path("_links/self/href") + it 'links to self' do + expect(subject).to have_json_path('_links/self/href') end - it "displays its name as title in self" do - expect(subject).to have_json_path("_links/self/title") + it 'displays its name as title in self' do + expect(subject).to have_json_path('_links/self/title') end - it "links to its project" do - expect(subject).to have_json_path("_links/project/href") + it 'links to its project' do + expect(subject).to have_json_path('_links/project/href') end - it "displays its project title" do - expect(subject).to have_json_path("_links/project/title") + it 'displays its project title' do + expect(subject).to have_json_path('_links/project/title') end - it { is_expected.to have_json_path("id") } - it { is_expected.to have_json_path("name") } + it { is_expected.to have_json_path('id') } + it { is_expected.to have_json_path('name') } end - context "default assignee not set" do - it_behaves_like "category has core values" + context 'default assignee not set' do + it_behaves_like 'category has core values' - it "does not link to an assignee" do - expect(subject).not_to have_json_path("_links/defaultAssignee") + it 'does not link to an assignee' do + expect(subject).not_to have_json_path('_links/defaultAssignee') end end - context "default assignee set" do + context 'default assignee set' do let(:category) do build_stubbed(:category, assigned_to: user) end - it_behaves_like "category has core values" + it_behaves_like 'category has core values' - it "links to its default assignee" do - expect(subject).to have_json_path("_links/defaultAssignee/href") + it 'links to its default assignee' do + expect(subject).to have_json_path('_links/defaultAssignee/href') end - it "displays the name of its default assignee" do - expect(subject).to have_json_path("_links/defaultAssignee/title") + it 'displays the name of its default assignee' do + expect(subject).to have_json_path('_links/defaultAssignee/title') end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -95,7 +95,7 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let(:assigned_to) { build_stubbed(:user) } let!(:former_cache_key) { representer.json_cache_key } @@ -103,33 +103,33 @@ category.assigned_to = assigned_to end - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Categories", "CategoryRepresenter") + .to include('API', 'V3', 'Categories', 'CategoryRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the category is updated" do + it 'changes when the category is updated' do category.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the category's project is updated" do + it 'changes when the category\'s project is updated' do category.project.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the category's assigned_to is updated" do + it 'changes when the category\'s assigned_to is updated' do category.assigned_to.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/configuration/configuration_representer_spec.rb b/spec/lib/api/v3/configuration/configuration_representer_spec.rb index 1247a0d239c8..28f8187bc750 100644 --- a/spec/lib/api/v3/configuration/configuration_representer_spec.rb +++ b/spec/lib/api/v3/configuration/configuration_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Configuration::ConfigurationRepresenter do include API::V3::Utilities::PathHelper @@ -46,223 +46,223 @@ subject { representer.to_json } - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.configuration } end - describe "userPreferences" do - context "if logged in" do - it_behaves_like "has an untitled link" do - let(:link) { "userPreferences" } + describe 'userPreferences' do + context 'if logged in' do + it_behaves_like 'has an untitled link' do + let(:link) { 'userPreferences' } let(:href) { api_v3_paths.user_preferences(current_user.id) } end end - context "if not logged in" do + context 'if not logged in' do let(:current_user) { build_stubbed(:anonymous) } - it_behaves_like "has an untitled link" do - let(:link) { "userPreferences" } + it_behaves_like 'has an untitled link' do + let(:link) { 'userPreferences' } let(:href) { api_v3_paths.user_preferences(current_user.id) } end end end end - describe "properties" do - it "indicates its type" do - expect(subject).to be_json_eql("Configuration".to_json).at_path("_type") + describe 'properties' do + it 'indicates its type' do + expect(subject).to be_json_eql('Configuration'.to_json).at_path('_type') end - it "indicates maximumAttachmentFileSize in Bytes" do - allow(Setting).to receive(:attachment_max_size).and_return("1024") - expect(subject).to be_json_eql((1024 * 1024).to_json).at_path("maximumAttachmentFileSize") + it 'indicates maximumAttachmentFileSize in Bytes' do + allow(Setting).to receive(:attachment_max_size).and_return('1024') + expect(subject).to be_json_eql((1024 * 1024).to_json).at_path('maximumAttachmentFileSize') end - it "indicates perPageOptions as array of integers" do - allow(Setting).to receive(:per_page_options).and_return("1, 50 , 100 ") - expect(subject).to be_json_eql([1, 50, 100].to_json).at_path("perPageOptions") + it 'indicates perPageOptions as array of integers' do + allow(Setting).to receive(:per_page_options).and_return('1, 50 , 100 ') + expect(subject).to be_json_eql([1, 50, 100].to_json).at_path('perPageOptions') end - describe "timeFormat" do - context "with time format", with_settings: { time_format: "%I:%M %p" } do - it "indicates the timeFormat" do + describe 'timeFormat' do + context 'with time format', with_settings: { time_format: '%I:%M %p' } do + it 'indicates the timeFormat' do expect(subject) - .to be_json_eql("hh:mm a".to_json) - .at_path("timeFormat") + .to be_json_eql('hh:mm a'.to_json) + .at_path('timeFormat') end end - context "with time format", with_settings: { time_format: "%H:%M" } do - it "indicates the timeFormat" do + context 'with time format', with_settings: { time_format: '%H:%M' } do + it 'indicates the timeFormat' do expect(subject) - .to be_json_eql("HH:mm".to_json) - .at_path("timeFormat") + .to be_json_eql('HH:mm'.to_json) + .at_path('timeFormat') end end - context "with a time format", with_settings: { time_format: "" } do - it "indicates the timeFormat" do + context 'with a time format', with_settings: { time_format: '' } do + it 'indicates the timeFormat' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("timeFormat") + .at_path('timeFormat') end end end - describe "dateFormat" do - context "without a date format", with_settings: { date_format: "" } do - it "indicates the dateFormat" do + describe 'dateFormat' do + context 'without a date format', with_settings: { date_format: '' } do + it 'indicates the dateFormat' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("dateFormat") + .at_path('dateFormat') end end - context "with date format (%Y-%m-%d)", with_settings: { date_format: "%Y-%m-%d" } do - it "indicates the dateFormat" do + context 'with date format (%Y-%m-%d)', with_settings: { date_format: '%Y-%m-%d' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("YYYY-MM-DD".to_json) - .at_path("dateFormat") + .to be_json_eql('YYYY-MM-DD'.to_json) + .at_path('dateFormat') end end - context "with date format (%d.%m.%Y)", with_settings: { date_format: "%d.%m.%Y" } do - it "indicates the dateFormat" do + context 'with date format (%d.%m.%Y)', with_settings: { date_format: '%d.%m.%Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("DD.MM.YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('DD.MM.YYYY'.to_json) + .at_path('dateFormat') end end - context "with date format (%d-%m-%Y)", with_settings: { date_format: "%d-%m-%Y" } do - it "indicates the dateFormat" do + context 'with date format (%d-%m-%Y)', with_settings: { date_format: '%d-%m-%Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("DD-MM-YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('DD-MM-YYYY'.to_json) + .at_path('dateFormat') end end - context "with date format (%m/%d/%Y)", with_settings: { date_format: "%m/%d/%Y" } do - it "indicates the dateFormat" do + context 'with date format (%m/%d/%Y)', with_settings: { date_format: '%m/%d/%Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("MM/DD/YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('MM/DD/YYYY'.to_json) + .at_path('dateFormat') end end - context "with date format (%d %b %Y)", with_settings: { date_format: "%d %b %Y" } do - it "indicates the dateFormat" do + context 'with date format (%d %b %Y)', with_settings: { date_format: '%d %b %Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("DD MMM YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('DD MMM YYYY'.to_json) + .at_path('dateFormat') end end - context "with date format (%d %B %Y)", with_settings: { date_format: "%d %B %Y" } do - it "indicates the dateFormat" do + context 'with date format (%d %B %Y)', with_settings: { date_format: '%d %B %Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("DD MMMM YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('DD MMMM YYYY'.to_json) + .at_path('dateFormat') end end - context "with date format (%b %d, %Y)", with_settings: { date_format: "%b %d, %Y" } do - it "indicates the dateFormat" do + context 'with date format (%b %d, %Y)', with_settings: { date_format: '%b %d, %Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("MMM DD, YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('MMM DD, YYYY'.to_json) + .at_path('dateFormat') end end - context "with date format (%B %d, %Y)", with_settings: { date_format: "%B %d, %Y" } do - it "indicates the dateFormat" do + context 'with date format (%B %d, %Y)', with_settings: { date_format: '%B %d, %Y' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("MMMM DD, YYYY".to_json) - .at_path("dateFormat") + .to be_json_eql('MMMM DD, YYYY'.to_json) + .at_path('dateFormat') end end end - describe "user_default_timezone" do - context "without a setting", with_settings: { user_default_timezone: nil } do - it "is null" do + describe 'user_default_timezone' do + context 'without a setting', with_settings: { user_default_timezone: nil } do + it 'is null' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("userDefaultTimezone") + .at_path('userDefaultTimezone') end end - context "with `Europe/Berlin` being set", with_settings: { user_default_timezone: "Europe/Berlin" } do - it "indicates the dateFormat" do + context 'with `Europe/Berlin` being set', with_settings: { user_default_timezone: 'Europe/Berlin' } do + it 'indicates the dateFormat' do expect(subject) - .to be_json_eql("Europe/Berlin".to_json) - .at_path("userDefaultTimezone") + .to be_json_eql('Europe/Berlin'.to_json) + .at_path('userDefaultTimezone') end end end - describe "startOfWeek" do - context "without a setting", with_settings: { start_of_week: "" } do - it "is null" do + describe 'startOfWeek' do + context 'without a setting', with_settings: { start_of_week: '' } do + it 'is null' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("startOfWeek") + .at_path('startOfWeek') end end - context "with `Monday` being set", with_settings: { start_of_week: "1" } do - it "indicates the dateFormat" do + context 'with `Monday` being set', with_settings: { start_of_week: '1' } do + it 'indicates the dateFormat' do expect(subject) .to be_json_eql(1.to_json) - .at_path("startOfWeek") + .at_path('startOfWeek') end end end - describe "activeFeatureFlags" do - context "without any active flags" do - it "is an empty array" do + describe 'activeFeatureFlags' do + context 'without any active flags' do + it 'is an empty array' do expect(subject) .to be_json_eql([].to_json) - .at_path("activeFeatureFlags") + .at_path('activeFeatureFlags') end end - context "with active flags" do + context 'with active flags' do before do allow(OpenProject::FeatureDecisions) .to receive(:active) .and_return(%w(the active_flags)) end - it "is an array of strings of those flags" do + it 'is an array of strings of those flags' do expect(subject) .to be_json_eql(%w(the activeFlags).to_json) - .at_path("activeFeatureFlags") + .at_path('activeFeatureFlags') end end end end - describe "_embedded" do - describe "userPreferences" do - context "if embedding" do + describe '_embedded' do + describe 'userPreferences' do + context 'if embedding' do let(:embed_links) { true } - it "embedds the user preferences" do + it 'embedds the user preferences' do expect(subject) - .to be_json_eql("UserPreferences".to_json) - .at_path("_embedded/userPreferences/_type") + .to be_json_eql('UserPreferences'.to_json) + .at_path('_embedded/userPreferences/_type') end end - context "if not embedding" do - it "embedds the user preferences" do + context 'if not embedding' do + it 'embedds the user preferences' do expect(subject) - .not_to have_json_path("_embedded/userPreferences/_type") + .not_to have_json_path('_embedded/userPreferences/_type') end end end diff --git a/spec/lib/api/v3/custom_actions/custom_action_execute_representer_parsing_spec.rb b/spec/lib/api/v3/custom_actions/custom_action_execute_representer_parsing_spec.rb index 65bbd15b2142..84e184531ffb 100644 --- a/spec/lib/api/v3/custom_actions/custom_action_execute_representer_parsing_spec.rb +++ b/spec/lib/api/v3/custom_actions/custom_action_execute_representer_parsing_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::CustomActions::CustomActionExecuteRepresenter, "parsing" do +RSpec.describe API::V3::CustomActions::CustomActionExecuteRepresenter, 'parsing' do include API::V3::Utilities::PathHelper let(:struct) { OpenStruct.new } @@ -49,32 +49,32 @@ struct end - context "lockVersion" do + context 'lockVersion' do let(:payload) do { - "lockVersion" => 1 + 'lockVersion' => 1 } end - it "sets the lockVersion" do + it 'sets the lockVersion' do expect(subject.lock_version) - .to eql payload["lockVersion"] + .to eql payload['lockVersion'] end end - context "_links" do - context "workPackage" do + context '_links' do + context 'workPackage' do let(:payload) do { - "_links" => { - "workPackage" => { - "href" => api_v3_paths.work_package(work_package.id) + '_links' => { + 'workPackage' => { + 'href' => api_v3_paths.work_package(work_package.id) } } } end - it "sets the work_package_id" do + it 'sets the work_package_id' do expect(subject.work_package_id) .to eql work_package.id.to_s end diff --git a/spec/lib/api/v3/custom_actions/custom_action_representer_generation_spec.rb b/spec/lib/api/v3/custom_actions/custom_action_representer_generation_spec.rb index e19d6bbc1caf..54377cd52365 100644 --- a/spec/lib/api/v3/custom_actions/custom_action_representer_generation_spec.rb +++ b/spec/lib/api/v3/custom_actions/custom_action_representer_generation_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CustomActions::CustomActionRepresenter do include API::V3::Utilities::PathHelper @@ -40,38 +40,38 @@ subject { representer.to_json } - context "properties" do - it "has a _type property" do + context 'properties' do + it 'has a _type property' do expect(subject) - .to be_json_eql("CustomAction".to_json) - .at_path("_type") + .to be_json_eql('CustomAction'.to_json) + .at_path('_type') end - it "has a name property" do + it 'has a name property' do expect(subject) .to be_json_eql(custom_action.name.to_json) - .at_path("name") + .at_path('name') end - it "has a description property" do + it 'has a description property' do expect(subject) .to be_json_eql(custom_action.description.to_json) - .at_path("description") + .at_path('description') end end - context "links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + context 'links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.custom_action(custom_action.id) } let(:title) { custom_action.name } end - it_behaves_like "has a titled link" do - let(:link) { "executeImmediately" } + it_behaves_like 'has a titled link' do + let(:link) { 'executeImmediately' } let(:href) { api_v3_paths.custom_action_execute(custom_action.id) } let(:title) { "Execute #{custom_action.name}" } - let(:method) { "post" } + let(:method) { 'post' } end end end diff --git a/spec/lib/api/v3/custom_options/custom_option_representer_spec.rb b/spec/lib/api/v3/custom_options/custom_option_representer_spec.rb index 95a79f1601ad..abacb10ed003 100644 --- a/spec/lib/api/v3/custom_options/custom_option_representer_spec.rb +++ b/spec/lib/api/v3/custom_options/custom_option_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::CustomOptions::CustomOptionRepresenter do include API::V3::Utilities::PathHelper @@ -40,25 +40,25 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.custom_option custom_option.id } let(:title) { custom_option.to_s } end end it 'has the type "CustomOption"' do - expect(subject).to be_json_eql("CustomOption".to_json).at_path("_type") + expect(subject).to be_json_eql('CustomOption'.to_json).at_path('_type') end - it "has an id" do - expect(subject).to be_json_eql(custom_option.id.to_json).at_path("id") + it 'has an id' do + expect(subject).to be_json_eql(custom_option.id.to_json).at_path('id') end - it "has a value" do - expect(subject).to be_json_eql(custom_option.to_s.to_json).at_path("value") + it 'has a value' do + expect(subject).to be_json_eql(custom_option.to_s.to_json).at_path('value') end end end diff --git a/spec/lib/api/v3/days/day_collection_representer_spec.rb b/spec/lib/api/v3/days/day_collection_representer_spec.rb index b88184464472..6d58452985cd 100644 --- a/spec/lib/api/v3/days/day_collection_representer_spec.rb +++ b/spec/lib/api/v3/days/day_collection_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::DayCollectionRepresenter do let(:days) do @@ -36,16 +36,16 @@ build(:day, date: Date.new(2022, 12, 29)) ] end - let(:current_user) { instance_double(User, name: "current_user") } + let(:current_user) { instance_double(User, name: 'current_user') } let(:representer) do described_class.new(days, - self_link: "/api/v3/self_link_untested", + self_link: '/api/v3/self_link_untested', current_user:) end - describe "#to_json" do + describe '#to_json' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "self_link_untested", "Day" + it_behaves_like 'unpaginated APIv3 collection', 3, 'self_link_untested', 'Day' end end diff --git a/spec/lib/api/v3/days/day_representer_spec.rb b/spec/lib/api/v3/days/day_representer_spec.rb index ef1e86c6fb75..b8e636c84670 100644 --- a/spec/lib/api/v3/days/day_representer_spec.rb +++ b/spec/lib/api/v3/days/day_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::DayRepresenter do let(:working) { true } @@ -35,106 +35,106 @@ Day.from_range(from: Date.new(2022, 12, 1), to: Date.new(2022, 12, 31)) .find(date.strftime("%Y%m%d").to_i) end - let(:current_user) { instance_double(User, name: "current_user") } + let(:current_user) { instance_double(User, name: 'current_user') } let(:representer) { described_class.new(day, current_user:) } subject(:generated) { representer.to_json } before do - set_week_days("tuesday", working:) + set_week_days('tuesday', working:) end - it "has _type: Day" do - expect(subject).to be_json_eql("Day".to_json).at_path("_type") + it 'has _type: Day' do + expect(subject).to be_json_eql('Day'.to_json).at_path('_type') end - it "has date property" do - expect(subject).to have_json_type(String).at_path("date") - expect(subject).to be_json_eql("2022-12-27".to_json).at_path("date") + it 'has date property' do + expect(subject).to have_json_type(String).at_path('date') + expect(subject).to be_json_eql('2022-12-27'.to_json).at_path('date') end - it "has name string property" do - expect(subject).to have_json_type(String).at_path("name") - expect(subject).to be_json_eql(day.name.to_json).at_path("name") + it 'has name string property' do + expect(subject).to have_json_type(String).at_path('name') + expect(subject).to be_json_eql(day.name.to_json).at_path('name') end - it "has working boolean property" do - expect(subject).to have_json_type(TrueClass).at_path("working") - expect(subject).to be_json_eql(day.working.to_json).at_path("working") + it 'has working boolean property' do + expect(subject).to have_json_type(TrueClass).at_path('working') + expect(subject).to be_json_eql(day.working.to_json).at_path('working') end - describe "_links" do - it "is present" do - expect(subject).to have_json_type(Object).at_path("_links") + describe '_links' do + it 'is present' do + expect(subject).to have_json_type(Object).at_path('_links') end - describe "self" do - it "links to this resource" do + describe 'self' do + it 'links to this resource' do expected_json = { - href: "/api/v3/days/2022-12-27", - title: "Tuesday" + href: '/api/v3/days/2022-12-27', + title: 'Tuesday' }.to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/self") + expect(subject).to be_json_eql(expected_json).at_path('_links/self') end end - describe "nonWorkingReasons" do - context "when the day has working true" do - it { is_expected.not_to have_json_path("_links/nonWorkingReasons") } + describe 'nonWorkingReasons' do + context 'when the day has working true' do + it { is_expected.not_to have_json_path('_links/nonWorkingReasons') } end - context "when day has working false" do + context 'when day has working false' do let(:working) { false } - it "links to the day resource" do + it 'links to the day resource' do expected_json = [{ - href: "/api/v3/days/week/2", - title: "Tuesday" + href: '/api/v3/days/week/2', + title: 'Tuesday' }].to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/nonWorkingReasons") + expect(subject).to be_json_eql(expected_json).at_path('_links/nonWorkingReasons') end end - context "when a non-working day is present" do + context 'when a non-working day is present' do let!(:non_working_day) { create(:non_working_day, date:) } - it "links to the non-working day resource" do + it 'links to the non-working day resource' do expected_json = [{ href: "/api/v3/days/non_working/2022-12-27", title: non_working_day.name }].to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/nonWorkingReasons") + expect(subject).to be_json_eql(expected_json).at_path('_links/nonWorkingReasons') end end - context "when the day has working false and a non-working day is present" do + context 'when the day has working false and a non-working day is present' do let(:working) { false } let!(:non_working_day) { create(:non_working_day, date:) } - it "links to the day resource and to the non-working day resource" do + it 'links to the day resource and to the non-working day resource' do expected_json = [{ - href: "/api/v3/days/week/2", - title: "Tuesday" + href: '/api/v3/days/week/2', + title: 'Tuesday' }, { href: "/api/v3/days/non_working/2022-12-27", title: non_working_day.name }].to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/nonWorkingReasons") + expect(subject).to be_json_eql(expected_json).at_path('_links/nonWorkingReasons') end end end - describe "weekday" do - it "links to the weekday resource" do + describe 'weekday' do + it 'links to the weekday resource' do expected_json = { - href: "/api/v3/days/week/2", - title: "Tuesday" + href: '/api/v3/days/week/2', + title: 'Tuesday' }.to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/weekday") + expect(subject).to be_json_eql(expected_json).at_path('_links/weekday') end end end diff --git a/spec/lib/api/v3/days/non_working_day_collection_representer_spec.rb b/spec/lib/api/v3/days/non_working_day_collection_representer_spec.rb index 88fa0f2f21e1..39fd49e6afc7 100644 --- a/spec/lib/api/v3/days/non_working_day_collection_representer_spec.rb +++ b/spec/lib/api/v3/days/non_working_day_collection_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::NonWorkingDayCollectionRepresenter do let(:non_working_days) do @@ -36,16 +36,16 @@ build(:non_working_day, date: Date.new(2022, 12, 29)) ] end - let(:current_user) { instance_double(User, name: "current_user") } + let(:current_user) { instance_double(User, name: 'current_user') } let(:representer) do described_class.new(non_working_days, - self_link: "/api/v3/self_link_untested", + self_link: '/api/v3/self_link_untested', current_user:) end - describe "#to_json" do + describe '#to_json' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "self_link_untested", "NonWorkingDay" + it_behaves_like 'unpaginated APIv3 collection', 3, 'self_link_untested', 'NonWorkingDay' end end diff --git a/spec/lib/api/v3/days/non_working_day_representer_spec.rb b/spec/lib/api/v3/days/non_working_day_representer_spec.rb index aff701bfa27b..f82b6a3ccd36 100644 --- a/spec/lib/api/v3/days/non_working_day_representer_spec.rb +++ b/spec/lib/api/v3/days/non_working_day_representer_spec.rb @@ -26,51 +26,51 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::NonWorkingDayRepresenter do let(:non_working_day) { build_stubbed(:non_working_day, name: "Christmas day", date: Date.tomorrow) } - let(:representer) { described_class.new(non_working_day, current_user: instance_double(User, name: "current_user")) } + let(:representer) { described_class.new(non_working_day, current_user: instance_double(User, name: 'current_user')) } - describe "#to_json" do + describe '#to_json' do subject(:generated) { representer.to_json } - it_behaves_like "property", :_type do - let(:value) { "NonWorkingDay" } + it_behaves_like 'property', :_type do + let(:value) { 'NonWorkingDay' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { non_working_day.id } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { non_working_day.name } end - it_behaves_like "has ISO 8601 date only" do + it_behaves_like 'has ISO 8601 date only' do let(:date) { non_working_day.date } - let(:json_path) { "date" } + let(:json_path) { 'date' } end - describe "_links" do - it "is present" do - expect(subject).to have_json_type(Object).at_path("_links") + describe '_links' do + it 'is present' do + expect(subject).to have_json_type(Object).at_path('_links') end - describe "self" do - it "links to this resource" do + describe 'self' do + it 'links to this resource' do expected_json = { href: "/api/v3/days/non_working/#{non_working_day.date}", title: non_working_day.name }.to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/self") + expect(subject).to be_json_eql(expected_json).at_path('_links/self') end end end end - describe "caching" do - it "is based on the representer's json_cache_key" do + describe 'caching' do + it 'is based on the representer\'s json_cache_key' do allow(OpenProject::Cache) .to receive(:fetch) .and_call_original @@ -82,22 +82,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Days", "NonWorkingDayRepresenter") + .to include('API', 'V3', 'Days', 'NonWorkingDayRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the non_working_day is updated" do + it 'changes when the non_working_day is updated' do non_working_day.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/days/week_day_collection_representer_spec.rb b/spec/lib/api/v3/days/week_day_collection_representer_spec.rb index fb4713cb77a4..415b29039b68 100644 --- a/spec/lib/api/v3/days/week_day_collection_representer_spec.rb +++ b/spec/lib/api/v3/days/week_day_collection_representer_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::WeekDayCollectionRepresenter do let(:week_days) { WeekDay.all } let(:representer) do described_class.new(week_days, - self_link: "/api/v3/days/week", - current_user: instance_double(User, name: "current_user")) + self_link: '/api/v3/days/week', + current_user: instance_double(User, name: 'current_user')) end - describe "#to_json" do + describe '#to_json' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 7, "days/week", "WeekDay" + it_behaves_like 'unpaginated APIv3 collection', 7, 'days/week', 'WeekDay' end end diff --git a/spec/lib/api/v3/days/week_day_representer_spec.rb b/spec/lib/api/v3/days/week_day_representer_spec.rb index 9b8b2392fe8f..f3a02c3a960f 100644 --- a/spec/lib/api/v3/days/week_day_representer_spec.rb +++ b/spec/lib/api/v3/days/week_day_representer_spec.rb @@ -26,53 +26,53 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::WeekDayRepresenter do let(:week_day) { build(:week_day, day: 1) } - let(:representer) { described_class.new(week_day, current_user: instance_double(User, name: "current_user")) } + let(:representer) { described_class.new(week_day, current_user: instance_double(User, name: 'current_user')) } - describe "#to_json" do + describe '#to_json' do subject(:generated) { representer.to_json } - it "has _type: WeekDay" do - expect(subject).to be_json_eql("WeekDay".to_json).at_path("_type") + it 'has _type: WeekDay' do + expect(subject).to be_json_eql('WeekDay'.to_json).at_path('_type') end - it "has day integer property" do - expect(subject).to have_json_type(Integer).at_path("day") - expect(subject).to be_json_eql(week_day.day.to_json).at_path("day") + it 'has day integer property' do + expect(subject).to have_json_type(Integer).at_path('day') + expect(subject).to be_json_eql(week_day.day.to_json).at_path('day') end - it "has name string property" do - expect(subject).to have_json_type(String).at_path("name") - expect(subject).to be_json_eql(week_day.name.to_json).at_path("name") + it 'has name string property' do + expect(subject).to have_json_type(String).at_path('name') + expect(subject).to be_json_eql(week_day.name.to_json).at_path('name') end - it "has working boolean property" do - expect(subject).to have_json_type(TrueClass).at_path("working") - expect(subject).to be_json_eql(week_day.working.to_json).at_path("working") + it 'has working boolean property' do + expect(subject).to have_json_type(TrueClass).at_path('working') + expect(subject).to be_json_eql(week_day.working.to_json).at_path('working') end - describe "_links" do - it "is present" do - expect(subject).to have_json_type(Object).at_path("_links") + describe '_links' do + it 'is present' do + expect(subject).to have_json_type(Object).at_path('_links') end - describe "self" do - it "links to this resource" do + describe 'self' do + it 'links to this resource' do expected_json = { href: "/api/v3/days/week/#{week_day.day}", title: week_day.name }.to_json - expect(subject).to be_json_eql(expected_json).at_path("_links/self") + expect(subject).to be_json_eql(expected_json).at_path('_links/self') end end end end - describe "caching" do - it "is based on the representer's json_cache_key" do + describe 'caching' do + it 'is based on the representer\'s json_cache_key' do allow(OpenProject::Cache) .to receive(:fetch) .and_call_original @@ -84,23 +84,23 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Days", "WeekDayRepresenter") + .to include('API', 'V3', 'Days', 'WeekDayRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the Setting is updated" do - set_week_days("tuesday") + it 'changes when the Setting is updated' do + set_week_days('tuesday') expect(representer.json_cache_key) .not_to eql former_cache_key diff --git a/spec/lib/api/v3/formatter/txt_charset_spec.rb b/spec/lib/api/v3/formatter/txt_charset_spec.rb index 92585460a903..88eda06d68f1 100644 --- a/spec/lib/api/v3/formatter/txt_charset_spec.rb +++ b/spec/lib/api/v3/formatter/txt_charset_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Formatter::TxtCharset do - let(:umlaut_object_ascii) { "ümläutß".force_encoding("ASCII-8BIT") } - let(:umlaut_object_utf8) { umlaut_object_ascii.force_encoding("utf-8") } + let(:umlaut_object_ascii) { 'ümläutß'.force_encoding('ASCII-8BIT') } + let(:umlaut_object_utf8) { umlaut_object_ascii.force_encoding('utf-8') } let(:env) { {} } - describe "#call" do - it "returns the object (string) encoded in the charset defined in env" do - env["CONTENT_TYPE"] = "text/plain; charset=UTF-8" + describe '#call' do + it 'returns the object (string) encoded in the charset defined in env' do + env['CONTENT_TYPE'] = 'text/plain; charset=UTF-8' expect(described_class.call(umlaut_object_ascii.dup, env)).to eql umlaut_object_utf8 end - it "returns the object (string) in default encoding if nothing defined in env" do + it 'returns the object (string) in default encoding if nothing defined in env' do expect(described_class.call(umlaut_object_ascii.dup, env)).to eql umlaut_object_utf8 end - it "returns the object (string) unchanged if invalid charset is provided in env" do - env["CONTENT_TYPE"] = "text/plain; charset=bogus" + it 'returns the object (string) unchanged if invalid charset is provided in env' do + env['CONTENT_TYPE'] = 'text/plain; charset=bogus' expect(described_class.call(umlaut_object_ascii.dup, env)).to eql umlaut_object_ascii end diff --git a/spec/lib/api/v3/groups/group_collection_representer_spec.rb b/spec/lib/api/v3/groups/group_collection_representer_spec.rb index e561406c47e9..59d44e4e6b09 100644 --- a/spec/lib/api/v3/groups/group_collection_representer_spec.rb +++ b/spec/lib/api/v3/groups/group_collection_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Groups::GroupCollectionRepresenter do - let(:self_base_link) { "/api/v3/groups" } + let(:self_base_link) { '/api/v3/groups' } let(:groups) do build_stubbed_list(:group, 3).tap do |groups| allow(groups) @@ -59,13 +59,13 @@ let(:page) { 1 } let(:page_size) { 2 } let(:actual_count) { 3 } - let(:collection_inner_type) { "Group" } + let(:collection_inner_type) { 'Group' } include API::V3::Utilities::PathHelper - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection", 3, "groups", "Group" + it_behaves_like 'offset-paginated APIv3 collection', 3, 'groups', 'Group' end end diff --git a/spec/lib/api/v3/groups/group_representer_spec.rb b/spec/lib/api/v3/groups/group_representer_spec.rb index 6acb6102d7e6..4e06090f7b24 100644 --- a/spec/lib/api/v3/groups/group_representer_spec.rb +++ b/spec/lib/api/v3/groups/group_representer_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Groups::GroupRepresenter, "rendering" do +RSpec.describe API::V3::Groups::GroupRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:generated) { representer.to_json } @@ -53,20 +53,20 @@ end end - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.group group.id } let(:title) { group.name } end end - describe "members" do - let(:link) { "members" } + describe 'members' do + let(:link) { 'members' } - context "with the necessary permissions" do - it_behaves_like "has a link collection" do + context 'with the necessary permissions' do + it_behaves_like 'has a link collection' do let(:hrefs) do members.map do |member| { @@ -78,13 +78,13 @@ end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:permissions) { [] } - it_behaves_like "has no link" + it_behaves_like 'has no link' end - context "when first having the necessary permissions and then not (caching)" do + context 'when first having the necessary permissions and then not (caching)' do before do representer.to_json # here the json will have links, afterwards we change the permissions @@ -92,104 +92,104 @@ mock_permissions_for(current_user, &:forbid_everything) end - it_behaves_like "has no link" + it_behaves_like 'has no link' end end - describe "updateImmediately" do - let(:link) { "updateImmediately" } + describe 'updateImmediately' do + let(:link) { 'updateImmediately' } - context "with the necessary permissions" do + context 'with the necessary permissions' do let(:current_user_admin) { true } - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:href) { api_v3_paths.group group.id } end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:current_user_admin) { false } - it_behaves_like "has no link" + it_behaves_like 'has no link' end end - describe "delete" do - let(:link) { "delete" } + describe 'delete' do + let(:link) { 'delete' } - context "with the necessary permissions" do + context 'with the necessary permissions' do let(:current_user_admin) { true } - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:href) { api_v3_paths.group group.id } end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:current_user_admin) { false } - it_behaves_like "has no link" + it_behaves_like 'has no link' end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Group" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Group' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { group.id } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { group.name } end - describe "createdAt" do - context "without admin" do - it "hides the createdAt property" do - expect(subject).not_to have_json_path("createdAt") + describe 'createdAt' do + context 'without admin' do + it 'hides the createdAt property' do + expect(subject).not_to have_json_path('createdAt') end end - context "with an admin" do + context 'with an admin' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { group.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end end - describe "updatedAt" do - context "without admin" do - it "hides the updatedAt property" do - expect(subject).not_to have_json_path("updatedAt") + describe 'updatedAt' do + context 'without admin' do + it 'hides the updatedAt property' do + expect(subject).not_to have_json_path('updatedAt') end end - context "with an admin" do + context 'with an admin' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { group.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end end end - describe "_embedded" do - describe "members" do - let(:embedded_path) { "_embedded/members" } + describe '_embedded' do + describe 'members' do + let(:embedded_path) { '_embedded/members' } - context "with the necessary permissions" do - it "has an array of users embedded" do + context 'with the necessary permissions' do + it 'has an array of users embedded' do members.each_with_index do |user, index| expect(subject) - .to be_json_eql("User".to_json) + .to be_json_eql('User'.to_json) .at_path("#{embedded_path}/#{index}/_type") expect(subject) @@ -199,10 +199,10 @@ end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:permissions) { [] } - it "has no members embedded" do + it 'has no members embedded' do expect(subject) .not_to have_json_path embedded_path end @@ -210,10 +210,10 @@ end end - describe "caching" do + describe 'caching' do let(:embed_links) { false } - it "is based on the representer's cache_key" do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -222,22 +222,22 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Groups", "GroupRepresenter") + .to include('API', 'V3', 'Groups', 'GroupRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the group is updated" do + it 'changes when the group is updated' do group.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/groups/group_sql_representer_rendering_spec.rb b/spec/lib/api/v3/groups/group_sql_representer_rendering_spec.rb index 92e6aec80d3c..36667bc52db2 100644 --- a/spec/lib/api/v3/groups/group_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/groups/group_sql_representer_rendering_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Groups::GroupSqlRepresenter, "rendering" do +RSpec.describe API::V3::Groups::GroupSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do @@ -45,13 +45,13 @@ let(:group) { create(:group) } - let(:select) { { "*" => {} } } + let(:select) { { '*' => {} } } current_user do create(:user) end - context "when rendering all supported properties" do + context 'when rendering all supported properties' do let(:expected) do { _type: "Group", @@ -66,7 +66,7 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end diff --git a/spec/lib/api/v3/help_texts/help_text_collection_representer_spec.rb b/spec/lib/api/v3/help_texts/help_text_collection_representer_spec.rb index 894594515edb..0fc73248f65a 100644 --- a/spec/lib/api/v3/help_texts/help_text_collection_representer_spec.rb +++ b/spec/lib/api/v3/help_texts/help_text_collection_representer_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::HelpTexts::HelpTextCollectionRepresenter do let!(:help_texts) do [ - build_stubbed(:work_package_help_text, attribute_name: "id"), - build_stubbed(:work_package_help_text, attribute_name: "status") + build_stubbed(:work_package_help_text, attribute_name: 'id'), + build_stubbed(:work_package_help_text, attribute_name: 'status') ] end let(:representer) do @@ -44,15 +44,15 @@ let(:user) { build_stubbed(:user) } def self_link - "a link that is provided" + 'a link that is provided' end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", + it_behaves_like 'unpaginated APIv3 collection', 2, - "a link that is provided", - "HelpText" + 'a link that is provided', + 'HelpText' end end diff --git a/spec/lib/api/v3/help_texts/help_text_representer_spec.rb b/spec/lib/api/v3/help_texts/help_text_representer_spec.rb index 3813f1a28825..a2f5d7312b3b 100644 --- a/spec/lib/api/v3/help_texts/help_text_representer_spec.rb +++ b/spec/lib/api/v3/help_texts/help_text_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::HelpTexts::HelpTextRepresenter do include API::V3::Utilities::PathHelper @@ -35,8 +35,8 @@ let(:help_text) do build_stubbed(:work_package_help_text, - attribute_name: "status", - help_text: "This is a help text for **status** attribute.") + attribute_name: 'status', + help_text: 'This is a help text for **status** attribute.') end let(:representer) { described_class.new help_text, current_user: user } @@ -65,14 +65,14 @@ "attribute" => "status", "attributeCaption" => "Status", "helpText" => { - "format" => "markdown", - "raw" => "This is a help text for **status** attribute.", + "format" => 'markdown', + "raw" => 'This is a help text for **status** attribute.', "html" => '

    This is a help text for status attribute.

    ' } } end - it "serializes the relation correctly" do + it 'serializes the relation correctly' do data = JSON.parse representer.to_json expect(data).to eq result end diff --git a/spec/lib/api/v3/memberships/membership_collection_representer_spec.rb b/spec/lib/api/v3/memberships/membership_collection_representer_spec.rb index 96799c7f6e65..988de06424ee 100644 --- a/spec/lib/api/v3/memberships/membership_collection_representer_spec.rb +++ b/spec/lib/api/v3/memberships/membership_collection_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Memberships::MembershipCollectionRepresenter do - let(:self_base_link) { "/api/v3/members" } + let(:self_base_link) { '/api/v3/members' } let(:members) do build_stubbed_list(:member, 3).tap do |members| allow(members) @@ -59,13 +59,13 @@ let(:page) { 1 } let(:page_size) { 2 } let(:actual_count) { 3 } - let(:collection_inner_type) { "Membership" } + let(:collection_inner_type) { 'Membership' } include API::V3::Utilities::PathHelper - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection", 3, "members", "Membership" + it_behaves_like 'offset-paginated APIv3 collection', 3, 'members', 'Membership' end end diff --git a/spec/lib/api/v3/memberships/membership_payload_representer_spec.rb b/spec/lib/api/v3/memberships/membership_payload_representer_spec.rb index 417ddf586855..5cc8d17e0b58 100644 --- a/spec/lib/api/v3/memberships/membership_payload_representer_spec.rb +++ b/spec/lib/api/v3/memberships/membership_payload_representer_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Memberships::MembershipPayloadRepresenter do let(:membership) { build_stubbed(:member) } current_user { build_stubbed(:user) } - describe "generation" do + describe 'generation' do subject(:json) { representer.to_json } - describe "_meta" do - describe "notificationMessage" do - let(:meta) { OpenStruct.new notifiation_message: "Come to the dark side" } + describe '_meta' do + describe 'notificationMessage' do + let(:meta) { OpenStruct.new notifiation_message: 'Come to the dark side' } let(:representer) do described_class.create(membership, meta:, current_user:) end - it_behaves_like "formattable property", :"_meta/notificationMessage" do + it_behaves_like 'formattable property', :'_meta/notificationMessage' do let(:value) { meta.notification_message } end end - describe "sendNotifications" do + describe 'sendNotifications' do let(:meta) { OpenStruct.new send_notifications: true } let(:representer) do described_class.create(membership, @@ -58,14 +58,14 @@ current_user:) end - it_behaves_like "property", :"_meta/sendNotifications" do + it_behaves_like 'property', :'_meta/sendNotifications' do let(:value) { true } end end end end - describe "parsing" do + describe 'parsing' do subject(:parsed) { representer.from_hash parsed_hash } let(:representer) do @@ -74,25 +74,25 @@ current_user:) end - describe "_meta" do - context "with meta set" do + describe '_meta' do + context 'with meta set' do let(:parsed_hash) do { - "_meta" => { - "notificationMessage" => { - "raw" => "Come to the dark side" + '_meta' => { + 'notificationMessage' => { + "raw" => 'Come to the dark side' }, - "sendNotifications" => true + 'sendNotifications' => true } } end - it "sets the parsed message" do + it 'sets the parsed message' do expect(parsed.meta.notification_message) - .to eql "Come to the dark side" + .to eql 'Come to the dark side' end - it "sets the notification sending configuration" do + it 'sets the notification sending configuration' do expect(parsed.meta.send_notifications) .to be_truthy end diff --git a/spec/lib/api/v3/memberships/membership_representer_rendering_spec.rb b/spec/lib/api/v3/memberships/membership_representer_rendering_spec.rb index 7d99c8a882f0..4b204f033986 100644 --- a/spec/lib/api/v3/memberships/membership_representer_rendering_spec.rb +++ b/spec/lib/api/v3/memberships/membership_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Memberships::MembershipRepresenter, "rendering" do +RSpec.describe API::V3::Memberships::MembershipRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:member) do @@ -70,95 +70,95 @@ end end - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.membership member.id } let(:title) { user.name } end end - describe "schema" do - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + describe 'schema' do + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) { api_v3_paths.membership_schema } end end - describe "to update" do - context "if manage members permissions are granted" do - it_behaves_like "has an untitled link" do - let(:link) { "update" } + describe 'to update' do + context 'if manage members permissions are granted' do + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.membership_form(member.id) } end end - describe "if manage members permissions are lacking" do + describe 'if manage members permissions are lacking' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "update" } + it_behaves_like 'has no link' do + let(:link) { 'update' } end end end - describe "to updateImmediately" do - context "if manage members permissions are granted" do - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + describe 'to updateImmediately' do + context 'if manage members permissions are granted' do + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.membership(member.id) } end end - describe "if manage members permissions are lacking" do + describe 'if manage members permissions are lacking' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end end - describe "project" do - it_behaves_like "has a titled link" do - let(:link) { "project" } + describe 'project' do + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project(project.id) } let(:title) { project.name } end - context "for a global member" do + context 'for a global member' do let(:project) { nil } - it_behaves_like "has an empty link" do - let(:link) { "project" } + it_behaves_like 'has an empty link' do + let(:link) { 'project' } end end end - describe "principal" do - context "for a user principal" do - it_behaves_like "has a titled link" do - let(:link) { "principal" } + describe 'principal' do + context 'for a user principal' do + it_behaves_like 'has a titled link' do + let(:link) { 'principal' } let(:href) { api_v3_paths.user(user.id) } let(:title) { user.name } end end - context "for a group principal" do + context 'for a group principal' do let(:principal) { group } - it_behaves_like "has a titled link" do - let(:link) { "principal" } + it_behaves_like 'has a titled link' do + let(:link) { 'principal' } let(:href) { api_v3_paths.group(group.id) } let(:title) { group.name } end end end - describe "roles" do - it_behaves_like "has a link collection" do - let(:link) { "roles" } + describe 'roles' do + it_behaves_like 'has a link collection' do + let(:link) { 'roles' } # excludes member_roles marked for destruction # and duplicates let(:hrefs) do @@ -177,37 +177,37 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Membership" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Membership' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { member.id } end - describe "createdAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'createdAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { member.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end - describe "updatedAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'updatedAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { member.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end end - describe "_embedded" do - describe "project" do - let(:embedded_path) { "_embedded/project" } + describe '_embedded' do + describe 'project' do + let(:embedded_path) { '_embedded/project' } - it "has the project embedded" do + it 'has the project embedded' do expect(subject) - .to be_json_eql("Project".to_json) + .to be_json_eql('Project'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -215,23 +215,23 @@ .at_path("#{embedded_path}/name") end - context "for a global member" do + context 'for a global member' do let(:project) { nil } - it "has no project embedded" do + it 'has no project embedded' do expect(subject) .not_to have_json_path(embedded_path) end end end - describe "principal" do - let(:embedded_path) { "_embedded/principal" } + describe 'principal' do + let(:embedded_path) { '_embedded/principal' } - context "for a user principal" do - it "has the user embedded" do + context 'for a user principal' do + it 'has the user embedded' do expect(subject) - .to be_json_eql("User".to_json) + .to be_json_eql('User'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -240,12 +240,12 @@ end end - context "for a group principal" do + context 'for a group principal' do let(:principal) { group } - it "has the group embedded" do + it 'has the group embedded' do expect(subject) - .to be_json_eql("Group".to_json) + .to be_json_eql('Group'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -255,12 +255,12 @@ end end - describe "roles" do - let(:embedded_path) { "_embedded/roles" } + describe 'roles' do + let(:embedded_path) { '_embedded/roles' } - it "has an array of roles embedded that excludes member_roles marked for destruction" do + it 'has an array of roles embedded that excludes member_roles marked for destruction' do expect(subject) - .to be_json_eql("Role".to_json) + .to be_json_eql('Role'.to_json) .at_path("#{embedded_path}/0/_type") expect(subject) @@ -268,7 +268,7 @@ .at_path("#{embedded_path}/0/name") expect(subject) - .to be_json_eql("Role".to_json) + .to be_json_eql('Role'.to_json) .at_path("#{embedded_path}/1/_type") expect(subject) diff --git a/spec/lib/api/v3/memberships/schemas/membership_schema_representer_spec.rb b/spec/lib/api/v3/memberships/schemas/membership_schema_representer_spec.rb index 29a724cf6116..57f69470535b 100644 --- a/spec/lib/api/v3/memberships/schemas/membership_schema_representer_spec.rb +++ b/spec/lib/api/v3/memberships/schemas/membership_schema_representer_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Memberships::Schemas::MembershipSchemaRepresenter do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } - let(:self_link) { "/a/self/link" } + let(:self_link) { '/a/self/link' } let(:embedded) { true } let(:new_record) { true } let(:project) { build_stubbed(:project) } @@ -69,89 +69,89 @@ current_user:) end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do - expect(subject).to be_json_eql("Schema".to_json).at_path("_type") + describe '_type' do + it 'is indicated as Schema' do + expect(subject).to be_json_eql('Schema'.to_json).at_path('_type') end end - describe "id" do - let(:path) { "id" } + describe 'id' do + let(:path) { 'id' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } - let(:name) { I18n.t("attributes.id") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } + let(:name) { I18n.t('attributes.id') } let(:required) { true } let(:writable) { false } end end - describe "createdAt" do - let(:path) { "createdAt" } + describe 'createdAt' do + let(:path) { 'createdAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Member.human_attribute_name("created_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Member.human_attribute_name('created_at') } let(:required) { true } let(:writable) { false } end end - describe "updatedAt" do - let(:path) { "updatedAt" } + describe 'updatedAt' do + let(:path) { 'updatedAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Member.human_attribute_name("updated_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Member.human_attribute_name('updated_at') } let(:required) { true } let(:writable) { false } end end - describe "notificationMessage" do - let(:path) { "notificationMessage" } + describe 'notificationMessage' do + let(:path) { 'notificationMessage' } - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } - let(:name) { I18n.t("label_message") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } + let(:name) { I18n.t('label_message') } let(:required) { false } let(:writable) { true } let(:location) { :_meta } end end - describe "project" do - let(:path) { "project" } + describe 'project' do + let(:path) { 'project' } - context "if having a new record" do - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Member.human_attribute_name("project") } + context 'if having a new record' do + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Member.human_attribute_name('project') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - context "if having no principal" do - it_behaves_like "links to allowed values via collection link" do + context 'if having no principal' do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.memberships_available_projects end end end - context "if having a principal" do + context 'if having a principal' do let(:assigned_principal) { principal } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do - filters = [{ "principal" => { "operator" => "!", "values" => [principal.id.to_s] } }] + filters = [{ 'principal' => { 'operator' => '!', 'values' => [principal.id.to_s] } }] api_v3_paths.path_for(:memberships_available_projects, filters:) end @@ -159,66 +159,66 @@ end end - context "if not embedding" do + context 'if not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end - context "if having a persisted record" do + context 'if having a persisted record' do let(:new_record) { false } - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Version.human_attribute_name("project") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Version.human_attribute_name('project') } let(:required) { false } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end end - describe "principal" do - let(:path) { "principal" } + describe 'principal' do + let(:path) { 'principal' } - context "if having a new record" do - it_behaves_like "has basic schema properties" do - let(:type) { "Principal" } - let(:name) { Version.human_attribute_name("principal") } + context 'if having a new record' do + it_behaves_like 'has basic schema properties' do + let(:type) { 'Principal' } + let(:name) { Version.human_attribute_name('principal') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - context "if having no project" do - it_behaves_like "links to allowed values via collection link" do + context 'if having no project' do + it_behaves_like 'links to allowed values via collection link' do let(:href) do statuses = [Principal.statuses[:locked].to_s] - filters = [{ "status" => { "operator" => "!", "values" => statuses } }] + filters = [{ 'status' => { 'operator' => '!', 'values' => statuses } }] api_v3_paths.path_for(:principals, filters:) end end end - context "if having a project" do + context 'if having a project' do let(:assigned_project) { project } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do statuses = [Principal.statuses[:locked].to_s] - status_filter = { "status" => { "operator" => "!", "values" => statuses } } - member_filter = { "member" => { "operator" => "!", "values" => [assigned_project.id.to_s] } } + status_filter = { 'status' => { 'operator' => '!', 'values' => statuses } } + member_filter = { 'member' => { 'operator' => '!', 'values' => [assigned_project.id.to_s] } } filters = [status_filter, member_filter] @@ -228,96 +228,96 @@ end end - context "if not embedding" do + context 'if not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end - context "if having a persisted record" do + context 'if having a persisted record' do let(:new_record) { false } - it_behaves_like "has basic schema properties" do - let(:type) { "Principal" } - let(:name) { Version.human_attribute_name("principal") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Principal' } + let(:name) { Version.human_attribute_name('principal') } let(:required) { true } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end end - describe "roles" do - let(:path) { "roles" } + describe 'roles' do + let(:path) { 'roles' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]Role" } - let(:name) { Version.human_attribute_name("role") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]Role' } + let(:name) { Version.human_attribute_name('role') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - context "for a new record" do - it_behaves_like "links to allowed values via collection link" do + context 'for a new record' do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.path_for(:roles) end end end - context "for a persisted record without project (global)" do + context 'for a persisted record without project (global)' do let(:assigned_project) { nil } let(:new_record) { false } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do - api_v3_paths.path_for(:roles, filters: [{ unit: { operator: "=", values: ["system"] } }]) + api_v3_paths.path_for(:roles, filters: [{ unit: { operator: '=', values: ['system'] } }]) end end end - context "for a persisted record with project (global)" do + context 'for a persisted record with project (global)' do let(:assigned_project) { project } let(:new_record) { false } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do - api_v3_paths.path_for(:roles, filters: [{ unit: { operator: "=", values: ["project"] } }]) + api_v3_paths.path_for(:roles, filters: [{ unit: { operator: '=', values: ['project'] } }]) end end end end - context "if not embedding" do + context 'if not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end - context "_links" do - describe "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context '_links' do + describe 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end - context "embedded in a form" do + context 'embedded in a form' do let(:self_link) { nil } - it_behaves_like "has no link" do - let(:link) { "self" } + it_behaves_like 'has no link' do + let(:link) { 'self' } end end end diff --git a/spec/lib/api/v3/news/news_representer_rendering_spec.rb b/spec/lib/api/v3/news/news_representer_rendering_spec.rb index 0a9ffe61eaee..d8e4fbbf9c11 100644 --- a/spec/lib/api/v3/news/news_representer_rendering_spec.rb +++ b/spec/lib/api/v3/news/news_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::News::NewsRepresenter, "rendering" do +RSpec.describe API::V3::News::NewsRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:news) do @@ -46,71 +46,71 @@ subject { representer.to_json } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.news news.id } let(:title) { news.title } end - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { :project } let(:title) { project.name } let(:href) { api_v3_paths.project project.id } end - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { :author } let(:title) { user.name } let(:href) { api_v3_paths.user user.id } end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "News" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'News' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { news.id } end - it_behaves_like "property", :title do + it_behaves_like 'property', :title do let(:value) { news.title } end - it_behaves_like "property", :summary do + it_behaves_like 'property', :summary do let(:value) { news.summary } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { news.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { news.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end - it_behaves_like "API V3 formattable", "description" do - let(:format) { "markdown" } + it_behaves_like 'API V3 formattable', 'description' do + let(:format) { 'markdown' } let(:raw) { news.description } - let(:html) { '

    ' + news.description + "

    " } + let(:html) { '

    ' + news.description + '

    ' } end end - describe "_embedded" do - it "has project embedded" do + describe '_embedded' do + it 'has project embedded' do expect(subject) .to be_json_eql(project.name.to_json) - .at_path("_embedded/project/name") + .at_path('_embedded/project/name') end - it "has author embedded" do + it 'has author embedded' do expect(subject) .to be_json_eql(user.name.to_json) - .at_path("_embedded/author/name") + .at_path('_embedded/author/name') end end end diff --git a/spec/lib/api/v3/notifications/notification_collection_representer_spec.rb b/spec/lib/api/v3/notifications/notification_collection_representer_spec.rb index fc43ac6d866f..2a536f958165 100644 --- a/spec/lib/api/v3/notifications/notification_collection_representer_spec.rb +++ b/spec/lib/api/v3/notifications/notification_collection_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Notifications::NotificationCollectionRepresenter do - let(:self_base_link) { "/api/v3/notifications" } + let(:self_base_link) { '/api/v3/notifications' } let(:user) { build_stubbed(:user) } let(:notification_list) { build_stubbed_list(:notification, 3) } let(:notifications) do @@ -62,7 +62,7 @@ let(:page) { 1 } let(:page_size) { 2 } let(:actual_count) { 3 } - let(:collection_inner_type) { "Notification" } + let(:collection_inner_type) { 'Notification' } let(:groups) { nil } include API::V3::Utilities::PathHelper @@ -74,82 +74,82 @@ .and_return(notifications) end - describe "generation" do + describe 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection", 3, "notifications", "Notification" + it_behaves_like 'offset-paginated APIv3 collection', 3, 'notifications', 'Notification' - context "when passing groups" do + context 'when passing groups' do let(:groups) do [ - { value: "mentioned", count: 34 }, - { value: "involved", count: 5 } + { value: 'mentioned', count: 34 }, + { value: 'involved', count: 5 } ] end - it "renders the groups object as json" do - expect(subject).to be_json_eql(groups.to_json).at_path("groups") + it 'renders the groups object as json' do + expect(subject).to be_json_eql(groups.to_json).at_path('groups') end end - describe "detailsSchema" do - context "when no date alert notifications are present" do - it "does not renders the detailsSchemas" do - expect(subject).not_to have_json_path("_embedded/detailsSchemas") + describe 'detailsSchema' do + context 'when no date alert notifications are present' do + it 'does not renders the detailsSchemas' do + expect(subject).not_to have_json_path('_embedded/detailsSchemas') end end - shared_examples_for "rendering detailsSchemas" do |reasons: [], expected_schemas: reasons| + shared_examples_for 'rendering detailsSchemas' do |reasons: [], expected_schemas: reasons| before do reasons.each_with_index do |reason, idx| notifications[idx].reason = reason end end - it "renders the required detailsSchemas" do + it 'renders the required detailsSchemas' do properties = expected_schemas.map do |reason| API::V3::Notifications::PropertyFactory::PROPERTY_FOR_REASON[reason.to_sym] end details_schemas = API::V3::Values::Schemas::ValueSchemaFactory.all_for(properties) - expect(subject).to be_json_eql(details_schemas.to_json).at_path("_embedded/detailsSchemas") + expect(subject).to be_json_eql(details_schemas.to_json).at_path('_embedded/detailsSchemas') end end - context "when a start date notification is present" do - it_behaves_like "rendering detailsSchemas", reasons: ["date_alert_start_date"] + context 'when a start date notification is present' do + it_behaves_like 'rendering detailsSchemas', reasons: ['date_alert_start_date'] end - context "when a due date notification is present" do - it_behaves_like "rendering detailsSchemas", reasons: ["date_alert_due_date"] + context 'when a due date notification is present' do + it_behaves_like 'rendering detailsSchemas', reasons: ['date_alert_due_date'] end - context "when a due date and a start date notification is present for a milestone work package" do + context 'when a due date and a start date notification is present for a milestone work package' do let(:notification_list) { build_stubbed_list(:notification, 3, :for_milestone) } - it_behaves_like "rendering detailsSchemas", - reasons: ["date_alert_due_date", "date_alert_start_date"], - expected_schemas: ["date_alert_date"] + it_behaves_like 'rendering detailsSchemas', + reasons: ['date_alert_due_date', 'date_alert_start_date'], + expected_schemas: ['date_alert_date'] end - context "when both date alert notifications are present" do - it_behaves_like "rendering detailsSchemas", reasons: ["date_alert_start_date", "date_alert_due_date"] + context 'when both date alert notifications are present' do + it_behaves_like 'rendering detailsSchemas', reasons: ['date_alert_start_date', 'date_alert_due_date'] end - context "when a list of mixed date alerts are present" do + context 'when a list of mixed date alerts are present' do let(:notification_list) do [ - build_stubbed(:notification, :for_milestone, reason: "date_alert_start_date"), - build_stubbed(:notification, reason: "date_alert_start_date"), - build_stubbed(:notification, :for_milestone, reason: "date_alert_due_date"), - build_stubbed(:notification, reason: "date_alert_due_date") + build_stubbed(:notification, :for_milestone, reason: 'date_alert_start_date'), + build_stubbed(:notification, reason: 'date_alert_start_date'), + build_stubbed(:notification, :for_milestone, reason: 'date_alert_due_date'), + build_stubbed(:notification, reason: 'date_alert_due_date') ] end - it_behaves_like "rendering detailsSchemas", + it_behaves_like 'rendering detailsSchemas', expected_schemas: [ - "date_alert_date", - "date_alert_start_date", - "date_alert_due_date" + 'date_alert_date', + 'date_alert_start_date', + 'date_alert_due_date' ] end end diff --git a/spec/lib/api/v3/notifications/notification_representer_rendering_spec.rb b/spec/lib/api/v3/notifications/notification_representer_rendering_spec.rb index 595e2e779bb1..c8aea67efe42 100644 --- a/spec/lib/api/v3/notifications/notification_representer_rendering_spec.rb +++ b/spec/lib/api/v3/notifications/notification_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Notifications::NotificationRepresenter, "rendering" do +RSpec.describe API::V3::Notifications::NotificationRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:generated) { representer.to_json } @@ -59,56 +59,56 @@ let(:embed_links) { false } let(:read_ian) { false } - describe "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.notification notification.id } end end - describe "IAN read and unread links" do - context "when unread" do - it_behaves_like "has an untitled link" do - let(:link) { "readIAN" } + describe 'IAN read and unread links' do + context 'when unread' do + it_behaves_like 'has an untitled link' do + let(:link) { 'readIAN' } let(:href) { api_v3_paths.notification_read_ian notification.id } let(:method) { :post } end - it_behaves_like "has no link" do - let(:link) { "unreadIAN" } + it_behaves_like 'has no link' do + let(:link) { 'unreadIAN' } end end - context "when read" do + context 'when read' do let(:read_ian) { true } - it_behaves_like "has an untitled link" do - let(:link) { "unreadIAN" } + it_behaves_like 'has an untitled link' do + let(:link) { 'unreadIAN' } let(:href) { api_v3_paths.notification_unread_ian notification.id } let(:method) { :post } end - it_behaves_like "has no link" do - let(:link) { "readIAN" } + it_behaves_like 'has no link' do + let(:link) { 'readIAN' } end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Notification" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Notification' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { notification.id } end - describe "reason" do + describe 'reason' do (Notification::REASONS.keys - %i[date_alert_start_date date_alert_due_date]).each do |notification_reason| context "for a #{notification_reason} reason" do let(:reason) { notification_reason } - it_behaves_like "property", :reason do + it_behaves_like 'property', :reason do let(:value) { notification_reason } end end @@ -118,39 +118,39 @@ context "for a #{notification_reason} reason" do let(:reason) { notification_reason } - it_behaves_like "property", :reason do - let(:value) { "dateAlert" } + it_behaves_like 'property', :reason do + let(:value) { 'dateAlert' } end end end end - it_behaves_like "datetime property", :createdAt do + it_behaves_like 'datetime property', :createdAt do let(:value) { notification.created_at } end - it_behaves_like "datetime property", :updatedAt do + it_behaves_like 'datetime property', :updatedAt do let(:value) { notification.updated_at } end - it "is expected to not have a message" do - expect(subject).not_to have_json_path("message") + it 'is expected to not have a message' do + expect(subject).not_to have_json_path('message') end end - describe "project" do - it_behaves_like "has a titled link" do - let(:link) { "project" } + describe 'project' do + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project project.id } let(:title) { project.name } end - context "when embedding is true" do + context 'when embedding is true' do let(:embed_links) { true } - it "embeds the context" do + it 'embeds the context' do expect(generated) - .to be_json_eql("Project".to_json) + .to be_json_eql('Project'.to_json) .at_path("_embedded/project/_type") expect(generated) @@ -160,109 +160,109 @@ end end - describe "resource polymorphic resource" do - it_behaves_like "has a titled link" do - let(:link) { "resource" } + describe 'resource polymorphic resource' do + it_behaves_like 'has a titled link' do + let(:link) { 'resource' } let(:title) { resource.subject } let(:href) { api_v3_paths.work_package resource.id } end - context "when embedding is true" do + context 'when embedding is true' do let(:embed_links) { true } - it "embeds the resource" do + it 'embeds the resource' do expect(generated) - .to be_json_eql("WorkPackage".to_json) + .to be_json_eql('WorkPackage'.to_json) .at_path("_embedded/resource/_type") end end end - describe "actor" do - context "when not set" do - it_behaves_like "has no link" do - let(:link) { "actor" } + describe 'actor' do + context 'when not set' do + it_behaves_like 'has no link' do + let(:link) { 'actor' } end end - context "when set" do + context 'when set' do let(:actor) { create(:user) } - it_behaves_like "has a titled link" do - let(:link) { "actor" } + it_behaves_like 'has a titled link' do + let(:link) { 'actor' } let(:href) { api_v3_paths.user actor.id } let(:title) { actor.name } end end end - describe "journal" do - context "when not set" do - it_behaves_like "has no link" do - let(:link) { "activity" } + describe 'journal' do + context 'when not set' do + it_behaves_like 'has no link' do + let(:link) { 'activity' } end end - context "when set" do + context 'when set' do let(:journal) { build_stubbed(:work_package_journal) } - it_behaves_like "has an untitled link" do - let(:link) { "activity" } + it_behaves_like 'has an untitled link' do + let(:link) { 'activity' } let(:href) { api_v3_paths.activity journal.id } end - context "when embedding is true" do + context 'when embedding is true' do let(:embed_links) { true } - it "embeds the resource" do + it 'embeds the resource' do expect(generated) - .to be_json_eql("Activity".to_json) + .to be_json_eql('Activity'.to_json) .at_path("_embedded/activity/_type") end end end end - describe "details" do - shared_examples_for "embeds a Values::Property for startDate" do - it "embeds a Values::Property" do + describe 'details' do + shared_examples_for 'embeds a Values::Property for startDate' do + it 'embeds a Values::Property' do expect(generated) - .to be_json_eql("Values::Property".to_json) + .to be_json_eql('Values::Property'.to_json) .at_path("_embedded/details/0/_type") end - it "has a startDate value for the `property` property" do + it 'has a startDate value for the `property` property' do expect(generated) - .to be_json_eql("startDate".to_json) + .to be_json_eql('startDate'.to_json) .at_path("_embedded/details/0/property") end - it "has a work_package`s start_date for the value" do + it 'has a work_package`s start_date for the value' do expect(generated) .to be_json_eql(resource.start_date.to_json) .at_path("_embedded/details/0/value") end end - context "for a dateAlert when embedding" do + context 'for a dateAlert when embedding' do let(:reason) { :date_alert_start_date } let(:embed_links) { true } - it_behaves_like "embeds a Values::Property for startDate" + it_behaves_like 'embeds a Values::Property for startDate' end - context "for a dateAlert when not embedding" do + context 'for a dateAlert when not embedding' do let(:reason) { :date_alert_start_date } let(:embed_links) { false } - it_behaves_like "embeds a Values::Property for startDate" + it_behaves_like 'embeds a Values::Property for startDate' end - context "for a mention when embedding" do + context 'for a mention when embedding' do let(:reason) { :mentioned } let(:embed_links) { true } - it "has an empty details array" do + it 'has an empty details array' do expect(generated) .to have_json_size(0) .at_path("_embedded/details") diff --git a/spec/lib/api/v3/notifications/property_factory_spec.rb b/spec/lib/api/v3/notifications/property_factory_spec.rb index f76da0c16aed..e8fe05ab5819 100644 --- a/spec/lib/api/v3/notifications/property_factory_spec.rb +++ b/spec/lib/api/v3/notifications/property_factory_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Notifications::PropertyFactory do let(:traits) { [] } @@ -38,21 +38,21 @@ reason:) end - describe ".details_for" do - context "for a date_alert_start_date notification" do + describe '.details_for' do + context 'for a date_alert_start_date notification' do let(:reason) { :date_alert_start_date } - it "returns one detail" do + it 'returns one detail' do expect(described_class.details_for(notification).size) .to eq 1 end - it "returns an array of `Values::Property` representers" do + it 'returns an array of `Values::Property` representers' do expect(described_class.details_for(notification)[0]) .to be_a API::V3::Values::PropertyDateRepresenter end - it "sets the represented property to :start_date" do + it 'sets the represented property to :start_date' do represented = described_class.details_for(notification)[0].represented expect(represented) .to be_a API::V3::Values::PropertyModel @@ -61,20 +61,20 @@ end end - context "for a date_alert_due_date notification" do + context 'for a date_alert_due_date notification' do let(:reason) { :date_alert_due_date } - it "returns one detail" do + it 'returns one detail' do expect(described_class.details_for(notification).size) .to eq 1 end - it "returns an array of `Values::Property` representers" do + it 'returns an array of `Values::Property` representers' do expect(described_class.details_for(notification)[0]) .to be_a API::V3::Values::PropertyDateRepresenter end - it "sets the represented property to :due_date" do + it 'sets the represented property to :due_date' do represented = described_class.details_for(notification)[0].represented expect(represented) .to be_a API::V3::Values::PropertyModel @@ -83,21 +83,21 @@ end end - context "for a date_alert_due_date notification with milestone work package" do + context 'for a date_alert_due_date notification with milestone work package' do let(:traits) { [:is_milestone] } let(:reason) { :date_alert_due_date } - it "returns one detail" do + it 'returns one detail' do expect(described_class.details_for(notification).size) .to eq 1 end - it "returns an array of `Values::Property` representers" do + it 'returns an array of `Values::Property` representers' do expect(described_class.details_for(notification)[0]) .to be_a API::V3::Values::PropertyDateRepresenter end - it "sets the representer property to :date" do + it 'sets the representer property to :date' do represented = described_class.details_for(notification)[0].represented expect(represented) .to be_a API::V3::Values::PropertyModel @@ -110,7 +110,7 @@ context "for a #{possible_reason} notification" do let(:reason) { possible_reason } - it "is an empty array" do + it 'is an empty array' do expect(described_class.details_for(notification)) .to eq [] end @@ -118,21 +118,21 @@ end end - describe ".schemas_for" do - context "for a date_alert_start_date notification" do + describe '.schemas_for' do + context 'for a date_alert_start_date notification' do let(:reason) { :date_alert_start_date } - it "returns one detail for the same type" do + it 'returns one detail for the same type' do expect(described_class.schemas_for([notification, notification]).size) .to eq 1 end - it "returns an array of `Values::Schemas::PropertySchemaRepresenter` representers" do + it 'returns an array of `Values::Schemas::PropertySchemaRepresenter` representers' do expect(described_class.schemas_for([notification])[0]) .to be_a API::V3::Values::Schemas::PropertySchemaRepresenter end - it "returns `Values::Schemas::Model` representer for Start Date" do + it 'returns `Values::Schemas::Model` representer for Start Date' do representer = described_class.schemas_for([notification])[0].represented expect(representer) .to be_a API::V3::Values::Schemas::Model @@ -141,20 +141,20 @@ end end - context "for a date_alert_due_date notification" do + context 'for a date_alert_due_date notification' do let(:reason) { :date_alert_due_date } - it "returns one detail for the same type" do + it 'returns one detail for the same type' do expect(described_class.schemas_for([notification, notification]).size) .to eq 1 end - it "returns an array of `Values::Schemas::PropertySchemaRepresenter` representers" do + it 'returns an array of `Values::Schemas::PropertySchemaRepresenter` representers' do expect(described_class.schemas_for([notification])[0]) .to be_a API::V3::Values::Schemas::PropertySchemaRepresenter end - it "returns `Values::Schemas::Model` representer for Finish date" do + it 'returns `Values::Schemas::Model` representer for Finish date' do representer = described_class.schemas_for([notification])[0].represented expect(representer) .to be_a API::V3::Values::Schemas::Model @@ -163,21 +163,21 @@ end end - context "for a date_alert_due_date notification with milestone work package" do + context 'for a date_alert_due_date notification with milestone work package' do let(:traits) { [:is_milestone] } let(:reason) { :date_alert_due_date } - it "returns one detail for the same type" do + it 'returns one detail for the same type' do expect(described_class.schemas_for([notification, notification]).size) .to eq 1 end - it "returns an array of `Values::Schemas::PropertySchemaRepresenter` representers" do + it 'returns an array of `Values::Schemas::PropertySchemaRepresenter` representers' do expect(described_class.schemas_for([notification])[0]) .to be_a API::V3::Values::Schemas::PropertySchemaRepresenter end - it "returns `Values::Schemas::Model` representer for Date" do + it 'returns `Values::Schemas::Model` representer for Date' do representer = described_class.schemas_for([notification])[0].represented expect(representer) .to be_a API::V3::Values::Schemas::Model @@ -186,7 +186,7 @@ end end - context "for multiple notifications" do + context 'for multiple notifications' do let(:reason) { :date_alert_due_date } let(:reason_start) { :date_alert_start_date } @@ -213,17 +213,17 @@ ] end - it "returns two details for different types" do + it 'returns two details for different types' do expect(described_class.schemas_for(notifications).size) .to eq 3 end - it "returns an array of `Values::Schemas::PropertySchemaRepresenter` representers" do + it 'returns an array of `Values::Schemas::PropertySchemaRepresenter` representers' do expect(described_class.schemas_for(notifications)) .to all be_a API::V3::Values::Schemas::PropertySchemaRepresenter end - it "returns `Values::Schemas::Model` representer for Finish date" do + it 'returns `Values::Schemas::Model` representer for Finish date' do representers = described_class.schemas_for(notifications).map(&:represented) expect(representers) .to all be_a API::V3::Values::Schemas::Model @@ -240,7 +240,7 @@ context "for a #{possible_reason} notification" do let(:reason) { possible_reason } - it "is an empty array" do + it 'is an empty array' do expect(described_class.schemas_for([notification])) .to eq [] end @@ -248,29 +248,29 @@ end end - describe ".groups_for" do - context "with a date_alert_start_date notification" do + describe '.groups_for' do + context 'with a date_alert_start_date notification' do let(:group_values) { { "date_alert_start_date" => 1 } } - it "returns as a date alert" do + it 'returns as a date alert' do expect(described_class.groups_for(group_values)) .to eq({ "dateAlert" => 1 }) end end - context "for a date_alert_due_date notification" do + context 'for a date_alert_due_date notification' do let(:group_values) { { "date_alert_due_date" => 1 } } - it "returns as a date alert" do + it 'returns as a date alert' do expect(described_class.groups_for(group_values)) .to eq({ "dateAlert" => 1 }) end end - context "for multiple notifications" do + context 'for multiple notifications' do let(:group_values) { { "mentioned" => 1, "date_alert_due_date" => 2, "date_alert_start_date" => 1 } } - it "sums up date alerts" do + it 'sums up date alerts' do expect(described_class.groups_for(group_values)) .to eq({ "mentioned" => 1, "dateAlert" => 3 }) end @@ -280,7 +280,7 @@ context "for a #{possible_reason} notification" do let(:group_values) { { possible_reason => 1 } } - it "returns the unaltered reasons" do + it 'returns the unaltered reasons' do expect(described_class.groups_for(group_values)) .to eq group_values end diff --git a/spec/lib/api/v3/placeholder_users/placeholder_user_collection_representer_spec.rb b/spec/lib/api/v3/placeholder_users/placeholder_user_collection_representer_spec.rb index 1273928ba530..00809cddbc79 100644 --- a/spec/lib/api/v3/placeholder_users/placeholder_user_collection_representer_spec.rb +++ b/spec/lib/api/v3/placeholder_users/placeholder_user_collection_representer_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::PlaceholderUsers::PlaceholderUserCollectionRepresenter do - let(:self_base_link) { "/api/v3/placeholder_users" } - let(:collection_inner_type) { "PlaceholderUser" } + let(:self_base_link) { '/api/v3/placeholder_users' } + let(:collection_inner_type) { 'PlaceholderUser' } let(:total) { 3 } let(:page) { 1 } let(:page_size) { 2 } @@ -65,9 +65,9 @@ current_user:) end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection" + it_behaves_like 'offset-paginated APIv3 collection' end end diff --git a/spec/lib/api/v3/placeholder_users/placeholder_user_representer_rendering_spec.rb b/spec/lib/api/v3/placeholder_users/placeholder_user_representer_rendering_spec.rb index 5dfc16bd6291..030fa8d2c30c 100644 --- a/spec/lib/api/v3/placeholder_users/placeholder_user_representer_rendering_spec.rb +++ b/spec/lib/api/v3/placeholder_users/placeholder_user_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::PlaceholderUsers::PlaceholderUserRepresenter, "rendering" do +RSpec.describe API::V3::PlaceholderUsers::PlaceholderUserRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:placeholder_user) { build_stubbed(:placeholder_user) } @@ -38,7 +38,7 @@ filters = [ { principal: { - operator: "=", + operator: '=', values: [placeholder_user.id.to_s] } } @@ -58,32 +58,32 @@ end end - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.placeholder_user placeholder_user.id } let(:title) { placeholder_user.name } end end - describe "showUser" do - it_behaves_like "has an untitled link" do - let(:link) { "showUser" } + describe 'showUser' do + it_behaves_like 'has an untitled link' do + let(:link) { 'showUser' } let(:href) { "/placeholder_users/#{placeholder_user.id}" } end end - describe "delete" do - it_behaves_like "has no link" do - let(:link) { "delete" } + describe 'delete' do + it_behaves_like 'has no link' do + let(:link) { 'delete' } end - context "if user is allowed to manage" do + context 'if user is allowed to manage' do let(:global_permissions) { [:manage_placeholder_user] } - it_behaves_like "has a titled link" do - let(:link) { "delete" } + it_behaves_like 'has a titled link' do + let(:link) { 'delete' } let(:href) { "/api/v3/placeholder_users/#{placeholder_user.id}" } let(:method) { :delete } let(:title) { "Delete #{placeholder_user.name}" } @@ -91,16 +91,16 @@ end end - describe "updateImmediately" do - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + describe 'updateImmediately' do + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end - context "when user allowed to manage" do + context 'when user allowed to manage' do let(:global_permissions) { [:manage_placeholder_user] } - it_behaves_like "has a titled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has a titled link' do + let(:link) { 'updateImmediately' } let(:href) { "/api/v3/placeholder_users/#{placeholder_user.id}" } let(:method) { :patch } let(:title) { "Update #{placeholder_user.name}" } @@ -108,26 +108,26 @@ end end - describe "memberships" do - it_behaves_like "has no link" do - let(:link) { "memberships" } + describe 'memberships' do + it_behaves_like 'has no link' do + let(:link) { 'memberships' } end - context "if user is allowed to see members" do + context 'if user is allowed to see members' do let(:project_permissions) { [:view_members] } - it_behaves_like "has a titled link" do - let(:link) { "memberships" } + it_behaves_like 'has a titled link' do + let(:link) { 'memberships' } let(:href) { memberships_path } let(:title) { I18n.t(:label_membership_plural) } end end - context "if user is allowed to manage members" do + context 'if user is allowed to manage members' do let(:project_permissions) { [:manage_members] } - it_behaves_like "has a titled link" do - let(:link) { "memberships" } + it_behaves_like 'has a titled link' do + let(:link) { 'memberships' } let(:href) { memberships_path } let(:title) { I18n.t(:label_membership_plural) } end @@ -135,48 +135,48 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "PlaceholderUser" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'PlaceholderUser' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { placeholder_user.id } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { placeholder_user.name } end - context "as regular user" do - it "hides the updatedAt property" do - expect(subject).not_to have_json_path("updatedAt") + context 'as regular user' do + it 'hides the updatedAt property' do + expect(subject).not_to have_json_path('updatedAt') end - it "hides the createdAt property" do - expect(subject).not_to have_json_path("createdAt") + it 'hides the createdAt property' do + expect(subject).not_to have_json_path('createdAt') end end - context "if user is allowed to manage placeholder users" do + context 'if user is allowed to manage placeholder users' do let(:global_permissions) { [:manage_placeholder_user] } - it_behaves_like "property", :status do - let(:value) { "active" } + it_behaves_like 'property', :status do + let(:value) { 'active' } end - it_behaves_like "datetime property", :createdAt do + it_behaves_like 'datetime property', :createdAt do let(:value) { placeholder_user.created_at } end - it_behaves_like "datetime property", :updatedAt do + it_behaves_like 'datetime property', :updatedAt do let(:value) { placeholder_user.updated_at } end end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do allow(OpenProject::Cache) .to receive(:fetch) .and_call_original @@ -188,22 +188,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "PlaceholderUsers", "PlaceholderUserRepresenter") + .to include('API', 'V3', 'PlaceholderUsers', 'PlaceholderUserRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the placeholder is updated" do + it 'changes when the placeholder is updated' do placeholder_user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/placeholder_users/placeholder_user_sql_representer_rendering_spec.rb b/spec/lib/api/v3/placeholder_users/placeholder_user_sql_representer_rendering_spec.rb index 8cd0f3f87c7b..f09785c0ae90 100644 --- a/spec/lib/api/v3/placeholder_users/placeholder_user_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/placeholder_users/placeholder_user_sql_representer_rendering_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::PlaceholderUsers::PlaceholderUserSqlRepresenter, "rendering" do +RSpec.describe API::V3::PlaceholderUsers::PlaceholderUserSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do @@ -45,13 +45,13 @@ let(:placeholder_user) { create(:placeholder_user) } - let(:select) { { "*" => {} } } + let(:select) { { '*' => {} } } current_user do create(:user) end - context "when rendering all supported properties" do + context 'when rendering all supported properties' do let(:expected) do { _type: "PlaceholderUser", @@ -66,7 +66,7 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end diff --git a/spec/lib/api/v3/posts/post_representer_rendering_spec.rb b/spec/lib/api/v3/posts/post_representer_rendering_spec.rb index b3ede5e66a34..3198e133ccc2 100644 --- a/spec/lib/api/v3/posts/post_representer_rendering_spec.rb +++ b/spec/lib/api/v3/posts/post_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Posts::PostRepresenter, "rendering" do +RSpec.describe API::V3::Posts::PostRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:message) do @@ -48,24 +48,24 @@ subject { representer.to_json } - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.post message.id } end - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:link) { :attachments } let(:href) { api_v3_paths.attachments_by_post message.id } end - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { :project } let(:title) { project.name } let(:href) { api_v3_paths.project project.id } end - it_behaves_like "has an untitled action link" do + it_behaves_like 'has an untitled action link' do let(:link) { :addAttachment } let(:href) { api_v3_paths.attachments_by_post message.id } let(:method) { :post } @@ -73,25 +73,25 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Post" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Post' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { message.id } end - it_behaves_like "property", :subject do + it_behaves_like 'property', :subject do let(:value) { message.subject } end end - describe "_embedded" do - it "has project embedded" do + describe '_embedded' do + it 'has project embedded' do expect(subject) .to be_json_eql(project.name.to_json) - .at_path("_embedded/project/name") + .at_path('_embedded/project/name') end end end diff --git a/spec/lib/api/v3/principals/principal_representer_factory_spec.rb b/spec/lib/api/v3/principals/principal_representer_factory_spec.rb index 9211b1dd823e..687088507bab 100644 --- a/spec/lib/api/v3/principals/principal_representer_factory_spec.rb +++ b/spec/lib/api/v3/principals/principal_representer_factory_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' class TestRepresenter < API::Decorators::Single include ::API::Decorators::LinkedResource @@ -44,191 +44,191 @@ class TestRepresenter < API::Decorators::Single let(:placeholder) { build_stubbed(:placeholder_user) } let(:deleted) { build_stubbed(:deleted_user) } - describe ".create" do + describe '.create' do subject { described_class.create principal, current_user: } - context "with a user" do + context 'with a user' do let(:principal) { user } - it "returns a user representer" do + it 'returns a user representer' do expect(subject).to be_a API::V3::Users::UserRepresenter end end - context "with a group" do + context 'with a group' do let(:principal) { group } - it "returns a group representer" do + it 'returns a group representer' do expect(subject).to be_a API::V3::Groups::GroupRepresenter end end - context "with a placeholder user" do + context 'with a placeholder user' do let(:principal) { placeholder } - it "returns a user representer" do + it 'returns a user representer' do expect(subject).to be_a API::V3::PlaceholderUsers::PlaceholderUserRepresenter end end - context "with a deleted user" do + context 'with a deleted user' do let(:principal) { deleted } - it "returns a user representer" do + it 'returns a user representer' do expect(subject).to be_a API::V3::Users::UserRepresenter end end end - describe ".create_link_lambda" do + describe '.create_link_lambda' do subject(:link) do TestRepresenter .new(represented, current_user:) - .instance_exec(&described_class.create_link_lambda("association")) + .instance_exec(&described_class.create_link_lambda('association')) end - context "with a user" do + context 'with a user' do let(:principal) { user } - it "renders a link to the user" do + it 'renders a link to the user' do expect(link) .to eql({ "href" => "/api/v3/users/5", "title" => principal.name }) end end - context "with a group" do + context 'with a group' do let(:principal) { group } - it "renders a link to the group" do + it 'renders a link to the group' do expect(link) .to eql({ "href" => "/api/v3/groups/5", "title" => principal.name }) end end - context "with a placeholder user" do + context 'with a placeholder user' do let(:principal) { placeholder } - it "renders a link to the placeholder" do + it 'renders a link to the placeholder' do expect(link) .to eql({ "href" => "/api/v3/placeholder_users/5", "title" => principal.name }) end end - context "with a deleted user" do + context 'with a deleted user' do let(:principal) { deleted } - it "renders a link to the user (which is deleted)" do + it 'renders a link to the user (which is deleted)' do expect(link) .to eql({ "href" => "/api/v3/users/5", "title" => principal.name }) end end end - describe ".create_getter_lambda" do + describe '.create_getter_lambda' do subject(:getter) do TestRepresenter .new(represented, current_user:, embed_links:) - .instance_exec(&described_class.create_getter_lambda("association")) + .instance_exec(&described_class.create_getter_lambda('association')) end let(:embed_links) { true } - context "with a user" do + context 'with a user' do let(:principal) { user } - it "returns a user representer" do + it 'returns a user representer' do expect(getter) .to be_a API::V3::Users::UserRepresenter end end - context "with a group" do + context 'with a group' do let(:principal) { group } - it "renders a group representer" do + it 'renders a group representer' do expect(getter) .to be_a API::V3::Groups::GroupRepresenter end end - context "with a placeholder user" do + context 'with a placeholder user' do let(:principal) { placeholder } - it "renders a placeholder representer" do + it 'renders a placeholder representer' do expect(getter) .to be_a API::V3::PlaceholderUsers::PlaceholderUserRepresenter end end - context "with a deleted user" do + context 'with a deleted user' do let(:principal) { deleted } - it "renders a user representer" do + it 'renders a user representer' do expect(getter) .to be_a API::V3::Users::UserRepresenter end end - context "with nil" do + context 'with nil' do let(:principal) { nil } - it "return nil" do + it 'return nil' do expect(getter) .to be_nil end end - context "without embedding links" do + context 'without embedding links' do let(:principal) { user } let(:embed_links) { false } - it "returns a user representer" do + it 'returns a user representer' do expect(getter) .to be_nil end end end - describe ".create_setter_lambda" do + describe '.create_setter_lambda' do subject(:setter) do TestRepresenter .new(represented, current_user: nil) - .instance_exec(fragment: { "href" => link }, &described_class.create_setter_lambda("association")) + .instance_exec(fragment: { "href" => link }, &described_class.create_setter_lambda('association')) represented.association_id end - context "with a user link" do + context 'with a user link' do let(:link) { "/api/v3/users/90" } - it "sets the association" do + it 'sets the association' do expect(setter) .to eql("90") end end - context "with a group link" do + context 'with a group link' do let(:link) { "/api/v3/groups/90" } - it "sets the association" do + it 'sets the association' do expect(setter) .to eql("90") end end - context "with a placeholder user link" do + context 'with a placeholder user link' do let(:link) { "/api/v3/placeholder_users/90" } - it "sets the association" do + it 'sets the association' do expect(setter) .to eql("90") end end - context "with an invalid link" do + context 'with an invalid link' do let(:link) { "/api/v3/schum/90" } - it "raises an exception" do + it 'raises an exception' do expect { setter } .to raise_error(API::Errors::InvalidResourceLink) end diff --git a/spec/lib/api/v3/principals/principal_sql_representer_rendering_spec.rb b/spec/lib/api/v3/principals/principal_sql_representer_rendering_spec.rb index db5c61498fc3..8226277431be 100644 --- a/spec/lib/api/v3/principals/principal_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/principals/principal_sql_representer_rendering_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Principals::PrincipalSqlRepresenter, "rendering" do +RSpec.describe API::V3::Principals::PrincipalSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do @@ -46,13 +46,13 @@ let(:group) { create(:group) } let(:placeholder_user) { create(:placeholder_user) } - let(:select) { { "*" => {} } } + let(:select) { { '*' => {} } } current_user do create(:user) end - context "when rendering all supported properties for a group" do + context 'when rendering all supported properties for a group' do let(:rendered_principal) { group } let(:expected) do @@ -69,13 +69,13 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - context "when rendering all supported properties for a placeholder user" do + context 'when rendering all supported properties for a placeholder user' do let(:rendered_principal) { placeholder_user } let(:expected) do @@ -92,13 +92,13 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - context "when rendering all supported properties for a user" do + context 'when rendering all supported properties for a user' do let(:rendered_principal) { current_user } let(:expected) do @@ -117,15 +117,15 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - context "when rendering only the name property for a user" do + context 'when rendering only the name property for a user' do let(:rendered_principal) { current_user } - let(:select) { { "name" => {} } } + let(:select) { { 'name' => {} } } let(:expected) do { @@ -133,7 +133,7 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end diff --git a/spec/lib/api/v3/principals/principal_type_spec.rb b/spec/lib/api/v3/principals/principal_type_spec.rb index 63bf9df8639d..7d7ae6d44fad 100644 --- a/spec/lib/api/v3/principals/principal_type_spec.rb +++ b/spec/lib/api/v3/principals/principal_type_spec.rb @@ -26,65 +26,65 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Principals::PrincipalType do let(:principal) { nil } subject { described_class.for(instance) } - shared_examples "returns api type" do |type| + shared_examples 'returns api type' do |type| it do expect(subject).to eq type end end - describe "with a user" do + describe 'with a user' do let(:instance) { build_stubbed(:user) } - it_behaves_like "returns api type", :user + it_behaves_like 'returns api type', :user end - describe "with a user" do + describe 'with a user' do let(:instance) { build_stubbed(:user) } - it_behaves_like "returns api type", :user + it_behaves_like 'returns api type', :user end - describe "with a system user" do + describe 'with a system user' do let(:instance) { User.system } - it_behaves_like "returns api type", :user + it_behaves_like 'returns api type', :user end - describe "with a system user" do + describe 'with a system user' do let(:instance) { build_stubbed(:deleted_user) } - it_behaves_like "returns api type", :user + it_behaves_like 'returns api type', :user end - describe "with anonymous" do + describe 'with anonymous' do let(:instance) { User.anonymous } - it_behaves_like "returns api type", :user + it_behaves_like 'returns api type', :user end - describe "with a group" do + describe 'with a group' do let(:instance) { build_stubbed(:group) } - it_behaves_like "returns api type", :group + it_behaves_like 'returns api type', :group end - describe "with a placeholder" do + describe 'with a placeholder' do let(:instance) { build_stubbed(:placeholder_user) } - it_behaves_like "returns api type", :placeholder_user + it_behaves_like 'returns api type', :placeholder_user end - describe "with an invalid type" do - let(:instance) { "whatever" } + describe 'with an invalid type' do + let(:instance) { 'whatever' } - it "raises an exception" do + it 'raises an exception' do expect { subject }.to raise_error "undefined subclass for whatever" end end diff --git a/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb b/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb index 5e80364b71ae..ece191ff0b20 100644 --- a/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb +++ b/spec/lib/api/v3/priorities/priority_collection_representer_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Priorities::PriorityCollectionRepresenter do let(:priorities) { build_list(:priority, 3) } let(:representer) do - described_class.new(priorities, self_link: "/api/v3/priorities", current_user: double("current_user")) + described_class.new(priorities, self_link: '/api/v3/priorities', current_user: double('current_user')) end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "priorities", "Priority" + it_behaves_like 'unpaginated APIv3 collection', 3, 'priorities', 'Priority' end end diff --git a/spec/lib/api/v3/priorities/priority_representer_spec.rb b/spec/lib/api/v3/priorities/priority_representer_spec.rb index 1eb10f035626..6a12b5fe4530 100644 --- a/spec/lib/api/v3/priorities/priority_representer_spec.rb +++ b/spec/lib/api/v3/priorities/priority_representer_spec.rb @@ -26,59 +26,59 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Priorities::PriorityRepresenter do let(:priority) { build_stubbed(:priority) } - let(:representer) { described_class.new(priority, current_user: double("current_user")) } + let(:representer) { described_class.new(priority, current_user: double('current_user')) } include API::V3::Utilities::PathHelper - context "generation" do + context 'generation' do subject { representer.to_json } - it "indicates its type" do - expect(subject).to include_json("Priority".to_json).at_path("_type") + it 'indicates its type' do + expect(subject).to include_json('Priority'.to_json).at_path('_type') end - describe "links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe 'links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - it "links to self" do + it 'links to self' do path = api_v3_paths.priority(priority.id) - expect(subject).to be_json_eql(path.to_json).at_path("_links/self/href") + expect(subject).to be_json_eql(path.to_json).at_path('_links/self/href') end - it "displays its name as title in self" do - expect(subject).to be_json_eql(priority.name.to_json).at_path("_links/self/title") + it 'displays its name as title in self' do + expect(subject).to be_json_eql(priority.name.to_json).at_path('_links/self/title') end end - describe "priority" do - it "has an id" do - expect(subject).to be_json_eql(priority.id.to_json).at_path("id") + describe 'priority' do + it 'has an id' do + expect(subject).to be_json_eql(priority.id.to_json).at_path('id') end - it "has a name" do - expect(subject).to be_json_eql(priority.name.to_json).at_path("name") + it 'has a name' do + expect(subject).to be_json_eql(priority.name.to_json).at_path('name') end - it "has a position" do - expect(subject).to be_json_eql(priority.position.to_json).at_path("position") + it 'has a position' do + expect(subject).to be_json_eql(priority.position.to_json).at_path('position') end - it "has a default flag" do - expect(subject).to be_json_eql(priority.is_default.to_json).at_path("isDefault") + it 'has a default flag' do + expect(subject).to be_json_eql(priority.is_default.to_json).at_path('isDefault') end - it "has an active flag" do - expect(subject).to be_json_eql(priority.active.to_json).at_path("isActive") + it 'has an active flag' do + expect(subject).to be_json_eql(priority.active.to_json).at_path('isActive') end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -87,22 +87,22 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Priorities", "PriorityRepresenter") + .to include('API', 'V3', 'Priorities', 'PriorityRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the priority is updated" do + it 'changes when the priority is updated' do priority.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/projects/copy/project_copy_payload_representer_spec.rb b/spec/lib/api/v3/projects/copy/project_copy_payload_representer_spec.rb index f3c6b32e9bf3..c836e3881804 100644 --- a/spec/lib/api/v3/projects/copy/project_copy_payload_representer_spec.rb +++ b/spec/lib/api/v3/projects/copy/project_copy_payload_representer_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Projects::Copy::ProjectCopyPayloadRepresenter do shared_let(:current_user, reload: false) { build_stubbed(:user) } shared_let(:project, reload: false) { build_stubbed(:project) } - describe "generation" do + describe 'generation' do let(:meta) { OpenStruct.new } let(:representer) do described_class.create(project, @@ -42,8 +42,8 @@ subject { representer.to_json } - it "has a _meta property with the copy properties set to true by default but sendNotifications false by default" do - expect(subject).to have_json_path "_meta" + it 'has a _meta property with the copy properties set to true by default but sendNotifications false by default' do + expect(subject).to have_json_path '_meta' Projects::CopyService.copyable_dependencies.each do |dep| expect(subject) @@ -56,10 +56,10 @@ .at_path("_meta/sendNotifications") end - context "with the meta property containing which associations to copy" do + context 'with the meta property containing which associations to copy' do let(:meta) { OpenStruct.new only: %[work_packages wiki] } - it "renders only the selected dependencies as true" do + it 'renders only the selected dependencies as true' do Projects::CopyService.copyable_dependencies.each do |dep| expect(subject) .to be_json_eql(meta.only.include?(dep[:identifier].to_s).to_json) @@ -68,10 +68,10 @@ end end - context "with the meta property to send notifications disabled" do + context 'with the meta property to send notifications disabled' do let(:meta) { OpenStruct.new send_notifications: false } - it "renders only the selected dependencies as true" do + it 'renders only the selected dependencies as true' do expect(subject) .to be_json_eql(false.to_json) .at_path("_meta/sendNotifications") @@ -79,7 +79,7 @@ end end - describe "parsing" do + describe 'parsing' do let(:representer) do described_class.create(OpenStruct.new(available_custom_fields: []), meta: OpenStruct.new, @@ -88,70 +88,70 @@ subject { representer.from_hash parsed_hash } - context "with meta set" do + context 'with meta set' do let(:parsed_hash) do { - "name" => "The copied project", - "_meta" => { - "copyWorkPackages" => true, - "copyWiki" => true, - "sendNotifications" => false + 'name' => 'The copied project', + '_meta' => { + 'copyWorkPackages' => true, + 'copyWiki' => true, + 'sendNotifications' => false } } end - it "sets all of them to true" do - expect(subject.name).to eq "The copied project" + it 'sets all of them to true' do + expect(subject.name).to eq 'The copied project' expected_names = Projects::CopyService.copyable_dependencies.pluck(:identifier) expect(subject.meta.only).to match_array(expected_names) expect(subject.meta.send_notifications).to be false end end - context "with one meta copy set to false" do + context 'with one meta copy set to false' do let(:parsed_hash) do { - "name" => "The copied project", - "_meta" => { - "copyWorkPackages" => false + 'name' => 'The copied project', + '_meta' => { + 'copyWorkPackages' => false } } end - it "sets all others to true" do - expect(subject.name).to eq "The copied project" + it 'sets all others to true' do + expect(subject.name).to eq 'The copied project' expected_names = Projects::CopyService.copyable_dependencies.pluck(:identifier) expect(subject.meta.only).to match_array(expected_names - %w[work_packages]) end end - context "with a mixture of meta copy set to false" do + context 'with a mixture of meta copy set to false' do let(:parsed_hash) do { - "name" => "The copied project", - "_meta" => { - "copyWorkPackages" => false, - "copyWiki" => true + 'name' => 'The copied project', + '_meta' => { + 'copyWorkPackages' => false, + 'copyWiki' => true } } end - it "still sets all of them to true except work packages" do - expect(subject.name).to eq "The copied project" + it 'still sets all of them to true except work packages' do + expect(subject.name).to eq 'The copied project' expected_names = Projects::CopyService.copyable_dependencies.pluck(:identifier) expect(subject.meta.only).to match_array(expected_names - %w[work_packages]) end end - context "with meta unset" do + context 'with meta unset' do let(:parsed_hash) do { - "name" => "The copied project" + 'name' => 'The copied project' } end - it "does not set meta" do - expect(subject.name).to eq "The copied project" + it 'does not set meta' do + expect(subject.name).to eq 'The copied project' expect(subject.meta).to be_nil end end diff --git a/spec/lib/api/v3/projects/copy/project_copy_schema_representer_spec.rb b/spec/lib/api/v3/projects/copy/project_copy_schema_representer_spec.rb index 2c3630d4e85c..a35bbcaa61f0 100644 --- a/spec/lib/api/v3/projects/copy/project_copy_schema_representer_spec.rb +++ b/spec/lib/api/v3/projects/copy/project_copy_schema_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Projects::Copy::ProjectCopySchemaRepresenter do include API::V3::Utilities::PathHelper @@ -37,41 +37,41 @@ shared_let(:representer, reload: false) do described_class.create(contract, - self_link: "/a/self/link", + self_link: '/a/self/link', form_embedded: true, current_user:) end shared_let(:subject, reload: false) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do - expect(subject).to be_json_eql("Schema".to_json).at_path("_type") + describe '_type' do + it 'is indicated as Schema' do + expect(subject).to be_json_eql('Schema'.to_json).at_path('_type') end end - describe "send_notifications" do - it_behaves_like "has basic schema properties" do + describe 'send_notifications' do + it_behaves_like 'has basic schema properties' do let(:path) { "sendNotifications" } - let(:type) { "Boolean" } + let(:type) { 'Boolean' } let(:name) { I18n.t(:label_project_copy_notifications) } let(:required) { false } let(:has_default) { true } let(:writable) { true } - let(:location) { "_meta" } + let(:location) { '_meta' } end end - describe "copy properties" do + describe 'copy properties' do Projects::CopyService.copyable_dependencies.each do |dep| - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { "copy#{dep[:identifier].camelize}" } - let(:type) { "Boolean" } + let(:type) { 'Boolean' } let(:name) { dep[:name_source].call } let(:required) { false } let(:has_default) { true } let(:writable) { true } - let(:location) { "_meta" } + let(:location) { '_meta' } let(:description) { "No objects of this type" } end end diff --git a/spec/lib/api/v3/projects/project_collection_representer_spec.rb b/spec/lib/api/v3/projects/project_collection_representer_spec.rb index f5853fe25b4f..9ae04e4fbda8 100644 --- a/spec/lib/api/v3/projects/project_collection_representer_spec.rb +++ b/spec/lib/api/v3/projects/project_collection_representer_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Projects::ProjectCollectionRepresenter do shared_let(:projects) { create_list(:project, 3) } - let(:self_base_link) { "/api/v3/projects" } + let(:self_base_link) { '/api/v3/projects' } let(:current_user) { build(:user) } let(:representer) do described_class.new Project.all, @@ -42,40 +42,40 @@ let(:page) { 1 } let(:page_size) { 30 } let(:actual_count) { 3 } - let(:collection_inner_type) { "Project" } + let(:collection_inner_type) { 'Project' } subject { representer.to_json } - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection", 3, "projects", "Project" + it_behaves_like 'offset-paginated APIv3 collection', 3, 'projects', 'Project' end - describe "representation formats" do - it_behaves_like "has a link collection" do - let(:link) { "representations" } + describe 'representation formats' do + it_behaves_like 'has a link collection' do + let(:link) { 'representations' } let(:hrefs) do [ { - "href" => "/projects.csv?offset=1&pageSize=30", - "identifier" => "csv", - "type" => "text/csv", - "title" => "CSV" + 'href' => '/projects.csv?offset=1&pageSize=30', + 'identifier' => 'csv', + 'type' => 'text/csv', + 'title' => 'CSV' }, { - "href" => "/projects.xls?offset=1&pageSize=30", - "identifier" => "xls", - "type" => "application/vnd.ms-excel", - "title" => "XLS" + 'href' => '/projects.xls?offset=1&pageSize=30', + 'identifier' => 'xls', + 'type' => 'application/vnd.ms-excel', + 'title' => 'XLS' } ] end end end - describe ".checked_permissions" do - it "lists add_work_packages and view_projects" do + describe '.checked_permissions' do + it 'lists add_work_packages and view_projects' do expect(described_class.checked_permissions).to contain_exactly(:add_work_packages, :view_project) end end diff --git a/spec/lib/api/v3/projects/project_payload_representer_parsing_spec.rb b/spec/lib/api/v3/projects/project_payload_representer_parsing_spec.rb index 991b78c688bd..abe64f7ce7b9 100644 --- a/spec/lib/api/v3/projects/project_payload_representer_parsing_spec.rb +++ b/spec/lib/api/v3/projects/project_payload_representer_parsing_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Projects::ProjectPayloadRepresenter, "parsing" do +RSpec.describe API::V3::Projects::ProjectPayloadRepresenter, 'parsing' do include API::V3::Utilities::PathHelper let(:object) do @@ -39,84 +39,84 @@ described_class.create(object, current_user: user) end - describe "properties" do - context "for status" do + describe 'properties' do + context 'for status' do let(:hash) do { - "statusExplanation" => { "raw" => "status code explanation" }, - "_links" => { - "status" => { - "href" => api_v3_paths.project_status("on_track") + 'statusExplanation' => { 'raw' => 'status code explanation' }, + '_links' => { + 'status' => { + 'href' => api_v3_paths.project_status('on_track') } } } end - it "updates code" do + it 'updates code' do project = representer.from_hash(hash) expect(project.status_code) - .to eql("on_track") + .to eql('on_track') expect(project.status_explanation) - .to eql("status code explanation") + .to eql('status code explanation') end - context "with code not provided" do + context 'with code not provided' do let(:hash) do { - "statusExplanation" => { "raw" => "status code explanation" } + 'statusExplanation' => { 'raw' => 'status code explanation' } } end - it "does not set code" do + it 'does not set code' do project = representer.from_hash(hash) expect(project.status_code) .to be_nil end - it "updates explanation" do + it 'updates explanation' do project = representer.from_hash(hash) expect(project.status_explanation) - .to eql("status code explanation") + .to eql('status code explanation') end end - context "with explanation not provided" do + context 'with explanation not provided' do let(:hash) do { - "_links" => { - "status" => { - "href" => api_v3_paths.project_status("off_track") + '_links' => { + 'status' => { + 'href' => api_v3_paths.project_status('off_track') } } } end - it "does set code" do + it 'does set code' do project = representer.from_hash(hash) expect(project.status_code) - .to eql "off_track" + .to eql 'off_track' end - it "does not set explanation" do + it 'does not set explanation' do project = representer.from_hash(hash) expect(project.status_explanation) .to be_nil end end - context "with null for a status" do + context 'with null for a status' do let(:hash) do { - "_links" => { - "status" => { - "href" => nil + '_links' => { + 'status' => { + 'href' => nil } } } end - it "does set status to nil" do + it 'does set status to nil' do project = representer.from_hash(hash) expect(project) @@ -131,20 +131,20 @@ end end - describe "_links" do - context "with a parent link" do - context "with the href being an url" do + describe '_links' do + context 'with a parent link' do + context 'with the href being an url' do let(:hash) do { - "_links" => { - "parent" => { - "href" => api_v3_paths.project(5) + '_links' => { + 'parent' => { + 'href' => api_v3_paths.project(5) } } } end - it "sets the parent_id to the value" do + it 'sets the parent_id to the value' do project = representer.from_hash(hash) expect(project[:parent_id]) @@ -152,18 +152,18 @@ end end - context "with the href being nil" do + context 'with the href being nil' do let(:hash) do { - "_links" => { - "parent" => { - "href" => nil + '_links' => { + 'parent' => { + 'href' => nil } } } end - it "sets the parent_id to nil" do + it 'sets the parent_id to nil' do project = representer.from_hash(hash) expect(project) @@ -174,18 +174,18 @@ end end - context "with the href being the hidden uri" do + context 'with the href being the hidden uri' do let(:hash) do { - "_links" => { - "parent" => { - "href" => API::V3::URN_UNDISCLOSED + '_links' => { + 'parent' => { + 'href' => API::V3::URN_UNDISCLOSED } } } end - it "omits the parent information" do + it 'omits the parent information' do project = representer.from_hash(hash) expect(project) diff --git a/spec/lib/api/v3/projects/project_representer_rendering_spec.rb b/spec/lib/api/v3/projects/project_representer_rendering_spec.rb index daa71e7ca66e..a4b26c3a93ba 100644 --- a/spec/lib/api/v3/projects/project_representer_rendering_spec.rb +++ b/spec/lib/api/v3/projects/project_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Projects::ProjectRepresenter, "rendering" do +RSpec.describe API::V3::Projects::ProjectRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:generated) { representer.to_json } @@ -37,7 +37,7 @@ build_stubbed(:project, :with_status, parent: parent_project, - description: "some description").tap do |p| + description: 'some description').tap do |p| allow(p).to receive_messages(available_custom_fields: [int_custom_field, version_custom_field], ancestors_from_root: ancestors) @@ -56,7 +56,7 @@ let(:version_custom_field) { build_stubbed(:version_project_custom_field, visible: true) } let(:int_custom_value) do CustomValue.new(custom_field: int_custom_field, - value: "1234", + value: '1234', customized: nil) end let(:version) { build_stubbed(:version) } @@ -89,60 +89,60 @@ end end - it { is_expected.to include_json("Project".to_json).at_path("_type") } + it { is_expected.to include_json('Project'.to_json).at_path('_type') } - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Project" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Project' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { project.id } end - it_behaves_like "property", :identifier do + it_behaves_like 'property', :identifier do let(:value) { project.identifier } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { project.name } end - it_behaves_like "property", :active do + it_behaves_like 'property', :active do let(:value) { project.active } end - it_behaves_like "property", :public do + it_behaves_like 'property', :public do let(:value) { project.public } end - it_behaves_like "formattable property", :description do + it_behaves_like 'formattable property', :description do let(:value) { project.description } end - it_behaves_like "formattable property", "statusExplanation" do + it_behaves_like 'formattable property', 'statusExplanation' do let(:value) { project.status_explanation } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { project.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { project.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end - context "when the user does not have the view_project permission" do + context 'when the user does not have the view_project permission' do let(:permissions) { [] } - it_behaves_like "no property", "statusExplanation" - it_behaves_like "no property", :description + it_behaves_like 'no property', 'statusExplanation' + it_behaves_like 'no property', :description end - describe "int custom field" do - context "if the user is admin" do + describe 'int custom field' do + context 'if the user is admin' do before do allow(user) .to receive(:admin?) @@ -155,13 +155,13 @@ end end - context "if the user is no admin" do + context 'if the user is no admin' do it "has no property for the int custom field" do expect(subject).not_to have_json_path("customField#{int_custom_field.id}") end end - context "if the user is no admin and the field is visible" do + context 'if the user is no admin and the field is visible' do before do int_custom_field.visible = true end @@ -172,7 +172,7 @@ end end - context "if the user lacks the :view_project permission" do + context 'if the user lacks the :view_project permission' do let(:permissions) { [] } before do @@ -186,61 +186,61 @@ end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - it "links to self" do - expect(subject).to have_json_path("_links/self/href") + it 'links to self' do + expect(subject).to have_json_path('_links/self/href') end - it "has a title for link to self" do - expect(subject).to have_json_path("_links/self/title") + it 'has a title for link to self' do + expect(subject).to have_json_path('_links/self/title') end - describe "create work packages" do - context "if user is allowed to create work packages" do - it "has the correct path for a create form" do + describe 'create work packages' do + context 'if user is allowed to create work packages' do + it 'has the correct path for a create form' do expect(subject).to be_json_eql(api_v3_paths.create_project_work_package_form(project.id).to_json) - .at_path("_links/createWorkPackage/href") + .at_path('_links/createWorkPackage/href') end - it "has the correct path to create a work package" do + it 'has the correct path to create a work package' do expect(subject).to be_json_eql(api_v3_paths.work_packages_by_project(project.id).to_json) - .at_path("_links/createWorkPackageImmediately/href") + .at_path('_links/createWorkPackageImmediately/href') end end - context "if user is not allowed to create work packages" do + context 'if user is not allowed to create work packages' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "createWorkPackage" } + it_behaves_like 'has no link' do + let(:link) { 'createWorkPackage' } end - it_behaves_like "has no link" do - let(:link) { "createWorkPackageImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'createWorkPackageImmediately' } end end end - describe "parent" do - let(:link) { "parent" } + describe 'parent' do + let(:link) { 'parent' } - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:href) { api_v3_paths.project(parent_project.id) } let(:title) { parent_project.name } end - context "if lacking the permissions to see the parent" do + context 'if lacking the permissions to see the parent' do let(:parent_visible) { false } - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:href) { API::V3::URN_UNDISCLOSED } - let(:title) { I18n.t(:"api_v3.undisclosed.parent") } + let(:title) { I18n.t(:'api_v3.undisclosed.parent') } end end - context "if lacking the permissions to see the parent but being an admin (archived project)" do + context 'if lacking the permissions to see the parent but being an admin (archived project)' do let(:parent_visible) { false } before do @@ -249,24 +249,24 @@ .and_return(true) end - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:href) { api_v3_paths.project(parent_project.id) } let(:title) { parent_project.name } end end - context "without a parent" do + context 'without a parent' do let(:parent_project) { nil } let(:ancestors) { [] } - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:href) { nil } end end end - describe "ancestors" do - let(:link) { "ancestors" } + describe 'ancestors' do + let(:link) { 'ancestors' } let(:grandparent_project) do build_stubbed(:project).tap do |p| allow(p) @@ -283,7 +283,7 @@ end let(:ancestors) { [root_project, grandparent_project, parent_project] } - it_behaves_like "has a link collection" do + it_behaves_like 'has a link collection' do let(:hrefs) do [ { @@ -302,10 +302,10 @@ end end - context "if lacking the permissions to see the parent but being allowed to see the other ancestors" do + context 'if lacking the permissions to see the parent but being allowed to see the other ancestors' do let(:parent_visible) { false } - it_behaves_like "has a link collection" do + it_behaves_like 'has a link collection' do let(:hrefs) do [ { @@ -318,14 +318,14 @@ }, { href: API::V3::URN_UNDISCLOSED, - title: I18n.t(:"api_v3.undisclosed.ancestor") + title: I18n.t(:'api_v3.undisclosed.ancestor') } ] end end end - context "if lacking the permissions to see the parent but being an admin (archived project)" do + context 'if lacking the permissions to see the parent but being an admin (archived project)' do let(:parent_visible) { false } before do @@ -334,7 +334,7 @@ .and_return(true) end - it_behaves_like "has a link collection" do + it_behaves_like 'has a link collection' do let(:hrefs) do [ { @@ -354,128 +354,128 @@ end end - context "without an ancestor" do + context 'without an ancestor' do let(:parent_project) { nil } let(:ancestors) { [] } - it_behaves_like "has an empty link collection" + it_behaves_like 'has an empty link collection' end end - describe "status" do - it_behaves_like "has a titled link" do - let(:link) { "status" } + describe 'status' do + it_behaves_like 'has a titled link' do + let(:link) { 'status' } let(:status_code) { project.status_code } let(:href) { api_v3_paths.project_status(status_code) } let(:title) { I18n.t(:"activerecord.attributes.project.status_codes.#{status_code}") } end - context "if the status_code is nil" do + context 'if the status_code is nil' do before { project.status_code = nil } - it_behaves_like "has an untitled link" do - let(:link) { "status" } + it_behaves_like 'has an untitled link' do + let(:link) { 'status' } let(:href) { nil } end end - context "if the user does not have the view_project permission" do + context 'if the user does not have the view_project permission' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "status" } + it_behaves_like 'has no link' do + let(:link) { 'status' } end end end - describe "categories" do - it "has the correct link to its categories" do + describe 'categories' do + it 'has the correct link to its categories' do expect(subject).to be_json_eql(api_v3_paths.categories_by_project(project.id).to_json) - .at_path("_links/categories/href") + .at_path('_links/categories/href') end end - describe "versions" do - context "with only manage_versions permission" do + describe 'versions' do + context 'with only manage_versions permission' do let(:permissions) { [:manage_versions] } - it_behaves_like "has an untitled link" do - let(:link) { "versions" } + it_behaves_like 'has an untitled link' do + let(:link) { 'versions' } let(:href) { api_v3_paths.versions_by_project(project.id) } end end - context "with only view_work_packages permission" do + context 'with only view_work_packages permission' do let(:permissions) { [:view_work_packages] } - it_behaves_like "has an untitled link" do - let(:link) { "versions" } + it_behaves_like 'has an untitled link' do + let(:link) { 'versions' } let(:href) { api_v3_paths.versions_by_project(project.id) } end end - context "without both permissions" do + context 'without both permissions' do let(:permissions) { [:add_work_packages] } - it_behaves_like "has no link" do - let(:link) { "versions" } + it_behaves_like 'has no link' do + let(:link) { 'versions' } end end end - describe "types" do - context "for a user having the view_work_packages permission" do + describe 'types' do + context 'for a user having the view_work_packages permission' do let(:permissions) { [:view_work_packages] } - it "links to the types active in the project" do + it 'links to the types active in the project' do expect(subject).to be_json_eql(api_v3_paths.types_by_project(project.id).to_json) - .at_path("_links/types/href") + .at_path('_links/types/href') end - it "links to the work packages in the project" do + it 'links to the work packages in the project' do expect(subject).to be_json_eql(api_v3_paths.work_packages_by_project(project.id).to_json) - .at_path("_links/workPackages/href") + .at_path('_links/workPackages/href') end end - context "for a user having the manage_types permission" do + context 'for a user having the manage_types permission' do let(:permissions) { [:manage_types] } - it "links to the types active in the project" do + it 'links to the types active in the project' do expect(subject).to be_json_eql(api_v3_paths.types_by_project(project.id).to_json) - .at_path("_links/types/href") + .at_path('_links/types/href') end end - context "for a user not having the necessary permissions" do + context 'for a user not having the necessary permissions' do let(:permission) { [] } - it "has no types link" do - expect(subject).not_to have_json_path("_links/types/href") + it 'has no types link' do + expect(subject).not_to have_json_path('_links/types/href') end - it "has no work packages link" do - expect(subject).not_to have_json_path("_links/workPackages/href") + it 'has no work packages link' do + expect(subject).not_to have_json_path('_links/workPackages/href') end end end - describe "memberships" do - it_behaves_like "has an untitled link" do - let(:link) { "memberships" } + describe 'memberships' do + it_behaves_like 'has an untitled link' do + let(:link) { 'memberships' } let(:href) { api_v3_paths.path_for(:memberships, filters: [{ project: { operator: "=", values: [project.id.to_s] } }]) } end - context "without the view_members permission" do + context 'without the view_members permission' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "memberships" } + it_behaves_like 'has no link' do + let(:link) { 'memberships' } end end end - describe "storages" do + describe 'storages' do let(:storage) { build_stubbed(:nextcloud_storage) } let(:permissions) { %i[view_file_links] } @@ -483,8 +483,8 @@ allow(project).to receive(:storages).and_return([storage]) end - it_behaves_like "has a link collection" do - let(:link) { "storages" } + it_behaves_like 'has a link collection' do + let(:link) { 'storages' } let(:hrefs) do [ { @@ -495,17 +495,17 @@ end end - context "if user has no permission to view file links" do + context 'if user has no permission to view file links' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "storages" } + it_behaves_like 'has no link' do + let(:link) { 'storages' } end end end - describe "link custom field" do - context "if the user is admin and the field is invisible" do + describe 'link custom field' do + context 'if the user is admin and the field is invisible' do before do allow(user) .to receive(:admin?) @@ -514,13 +514,13 @@ version_custom_field.visible = false end - it "links custom fields" do + it 'links custom fields' do expect(subject).to be_json_eql(api_v3_paths.version(version.id).to_json) .at_path("_links/customField#{version_custom_field.id}/href") end end - context "if the user is no admin and the field is invisible" do + context 'if the user is no admin and the field is invisible' do before do version_custom_field.visible = false end @@ -530,87 +530,87 @@ end end - context "if the user is no admin and the field is visible" do - it "links custom fields" do + context 'if the user is no admin and the field is visible' do + it 'links custom fields' do expect(subject).to be_json_eql(api_v3_paths.version(version.id).to_json) .at_path("_links/customField#{version_custom_field.id}/href") end end - context "if the user lacks the :view_project permission" do + context 'if the user lacks the :view_project permission' do let(:permissions) { [] } - it "does not link the custom field" do + it 'does not link the custom field' do expect(subject).not_to have_json_path("links/customField#{version_custom_field.id}") end end end - describe "update" do - context "for a user having the edit_project permission" do + describe 'update' do + context 'for a user having the edit_project permission' do let(:permissions) { [:edit_project] } - it_behaves_like "has an untitled link" do - let(:link) { "update" } + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.project_form project.id } end end - context "for a user lacking the edit_project permission" do + context 'for a user lacking the edit_project permission' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "update" } + it_behaves_like 'has no link' do + let(:link) { 'update' } end end end - describe "updateImmediately" do - context "for a user having the edit_project permission" do + describe 'updateImmediately' do + context 'for a user having the edit_project permission' do let(:permissions) { [:edit_project] } - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.project project.id } end end - context "for a user lacking the edit_project permission" do + context 'for a user lacking the edit_project permission' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end end - describe "delete" do - context "for a user being admin" do + describe 'delete' do + context 'for a user being admin' do before do allow(user) .to receive(:admin?) .and_return(true) end - it_behaves_like "has an untitled link" do - let(:link) { "delete" } + it_behaves_like 'has an untitled link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.project project.id } end end - context "for a non admin user" do + context 'for a non admin user' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end end end - describe "_embedded" do - describe "parent" do - let(:embedded_path) { "_embedded/parent" } + describe '_embedded' do + describe 'parent' do + let(:embedded_path) { '_embedded/parent' } before do allow(parent_project) @@ -618,12 +618,12 @@ .and_return(parent_visible) end - context "when the user is allowed to see the parent" do + context 'when the user is allowed to see the parent' do let(:parent_visible) { true } - it "has the parent embedded" do + it 'has the parent embedded' do expect(generated) - .to be_json_eql("Project".to_json) + .to be_json_eql('Project'.to_json) .at_path("#{embedded_path}/_type") expect(generated) @@ -632,22 +632,22 @@ end end - context "when the user is forbidden to see the parent" do + context 'when the user is forbidden to see the parent' do let(:parent_visible) { false } - it "hides the parent" do + it 'hides the parent' do expect(generated) .not_to have_json_path(embedded_path) end end end - describe "status" do - let(:embedded_path) { "_embedded/status" } + describe 'status' do + let(:embedded_path) { '_embedded/status' } - it "has the status embedded" do + it 'has the status embedded' do expect(generated) - .to be_json_eql("ProjectStatus".to_json) + .to be_json_eql('ProjectStatus'.to_json) .at_path("#{embedded_path}/_type") expect(generated) @@ -655,19 +655,19 @@ .at_path("#{embedded_path}/name") end - context "if the status_code is nil" do + context 'if the status_code is nil' do before { project.status_code = nil } - it "has no status embedded" do + it 'has no status embedded' do expect(generated) .not_to have_json_path(embedded_path) end end - context "if the user does not have the view_project permission" do + context 'if the user does not have the view_project permission' do let(:permissions) { [] } - it "has no status embedded" do + it 'has no status embedded' do expect(generated) .not_to have_json_path(embedded_path) end @@ -675,8 +675,8 @@ end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do allow(OpenProject::Cache) .to receive(:fetch) .and_call_original @@ -688,22 +688,22 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Projects", "ProjectRepresenter") + .to include('API', 'V3', 'Projects', 'ProjectRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the project is updated" do + it 'changes when the project is updated' do project.updated_at = 20.seconds.from_now expect(representer.json_cache_key) @@ -712,8 +712,8 @@ end end - describe ".checked_permissions" do - it "lists add_work_packages and view_project" do + describe '.checked_permissions' do + it 'lists add_work_packages and view_project' do expect(described_class.checked_permissions).to contain_exactly(:add_work_packages, :view_project) end end diff --git a/spec/lib/api/v3/projects/project_sql_collection_representer_rendering_spec.rb b/spec/lib/api/v3/projects/project_sql_collection_representer_rendering_spec.rb index 1ac8c65cb9e0..4b7d9291e3d4 100644 --- a/spec/lib/api/v3/projects/project_sql_collection_representer_rendering_spec.rb +++ b/spec/lib/api/v3/projects/project_sql_collection_representer_rendering_spec.rb @@ -24,16 +24,16 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Projects::ProjectSqlCollectionRepresenter, "rendering" do +RSpec.describe API::V3::Projects::ProjectSqlCollectionRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do API::V3::Utilities::SqlRepresenterWalker .new(scope, current_user:, - self_path: "some_path", + self_path: 'some_path', url_query: { offset: 1, pageSize: 5, select: }) .walk(described_class) .to_json @@ -51,14 +51,14 @@ let(:role) { create(:project_role) } let(:select) do - { "*" => {}, "elements" => { "*" => {} } } + { '*' => {}, 'elements' => { '*' => {} } } end current_user do create(:user, member_with_roles: { project => role }) end - context "when rendering everything" do + context 'when rendering everything' do let(:expected) do { _type: "Collection", @@ -101,15 +101,15 @@ }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected) end end - context "when rendering only collection attributes" do + context 'when rendering only collection attributes' do let(:select) do - { "*" => {} } + { '*' => {} } end let(:expected) do @@ -135,19 +135,19 @@ }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected) end end - context "when not having a project to render" do + context 'when not having a project to render' do let(:scope) do Project.none end let(:select) do - { "*" => {} } + { '*' => {} } end let(:expected) do @@ -173,7 +173,7 @@ }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected) end diff --git a/spec/lib/api/v3/projects/project_sql_representer_rendering_spec.rb b/spec/lib/api/v3/projects/project_sql_representer_rendering_spec.rb index eb8539c8d16f..28aa950af458 100644 --- a/spec/lib/api/v3/projects/project_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/projects/project_sql_representer_rendering_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Projects::ProjectSqlRepresenter, "rendering" do +RSpec.describe API::V3::Projects::ProjectSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do @@ -49,14 +49,14 @@ let(:role) { create(:project_role) } - let(:select) { { "*" => {} } } + let(:select) { { '*' => {} } } current_user do create(:user, member_with_roles: { project => role }) end - context "when rendering all supported properties" do - it "renders as expected" do + context 'when rendering all supported properties' do + it 'renders as expected' do expect(json) .to be_json_eql( { @@ -78,7 +78,7 @@ end end - context "with an ancestor" do + context 'with an ancestor' do let!(:parent) do create(:project, members: { current_user => role }).tap do |parent| project.parent = parent @@ -93,9 +93,9 @@ end end - let(:select) { { "ancestors" => {} } } + let(:select) { { 'ancestors' => {} } } - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql( { @@ -116,7 +116,7 @@ end end - context "with an ancestor the user does not have permission to see" do + context 'with an ancestor the user does not have permission to see' do let!(:parent) do create(:project).tap do |parent| project.parent = parent @@ -131,9 +131,9 @@ end end - let(:select) { { "ancestors" => {} } } + let(:select) { { 'ancestors' => {} } } - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql( { @@ -145,7 +145,7 @@ }, { href: API::V3::URN_UNDISCLOSED, - title: I18n.t(:"api_v3.undisclosed.ancestor") + title: I18n.t(:'api_v3.undisclosed.ancestor') } ] } @@ -153,8 +153,8 @@ ) end - context "with relative url root", with_config: { rails_relative_url_root: "/foobar" } do - it "renders correctly" do + context 'with relative url root', with_config: { rails_relative_url_root: '/foobar' } do + it 'renders correctly' do expect(json) .to be_json_eql( { @@ -166,7 +166,7 @@ }, { href: API::V3::URN_UNDISCLOSED, - title: I18n.t(:"api_v3.undisclosed.ancestor") + title: I18n.t(:'api_v3.undisclosed.ancestor') } ] } @@ -175,12 +175,12 @@ end end - context "when in a foreign language with single quotes in the translation hint text" do + context 'when in a foreign language with single quotes in the translation hint text' do before do I18n.locale = :fr end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql( { @@ -192,7 +192,7 @@ }, { href: API::V3::URN_UNDISCLOSED, - title: I18n.t(:"api_v3.undisclosed.ancestor") + title: I18n.t(:'api_v3.undisclosed.ancestor') } ] } @@ -202,7 +202,7 @@ end end - context "with an archived ancestor but with the user being admin" do + context 'with an archived ancestor but with the user being admin' do let!(:parent) do create(:project, active: false).tap do |parent| project.parent = parent @@ -217,13 +217,13 @@ end end - let(:select) { { "ancestors" => {} } } + let(:select) { { 'ancestors' => {} } } current_user do create(:admin) end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql( { diff --git a/spec/lib/api/v3/projects/schemas/project_schema_representer_spec.rb b/spec/lib/api/v3/projects/schemas/project_schema_representer_spec.rb index 479c5cd24054..63ca1addd327 100644 --- a/spec/lib/api/v3/projects/schemas/project_schema_representer_spec.rb +++ b/spec/lib/api/v3/projects/schemas/project_schema_representer_spec.rb @@ -26,23 +26,23 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Projects::Schemas::ProjectSchemaRepresenter do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } - let(:self_link) { "/a/self/link" } + let(:self_link) { '/a/self/link' } let(:embedded) { true } let(:new_record) { true } let(:model_id) { 1 } let(:custom_field) do build_stubbed(:integer_project_custom_field) end - let(:allowed_status) { ["some status"] } + let(:allowed_status) { ['some status'] } let(:contract) do - contract = double("contract") - model = double("project") + contract = double('contract') + model = double('project') allow(contract) .to receive(:writable?) do |attribute| @@ -91,236 +91,236 @@ end end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do - expect(subject).to be_json_eql("Schema".to_json).at_path("_type") + describe '_type' do + it 'is indicated as Schema' do + expect(subject).to be_json_eql('Schema'.to_json).at_path('_type') end end - describe "id" do - let(:path) { "id" } + describe 'id' do + let(:path) { 'id' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } - let(:name) { I18n.t("attributes.id") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } + let(:name) { I18n.t('attributes.id') } let(:required) { true } let(:writable) { false } end end - describe "name" do - let(:path) { "name" } + describe 'name' do + let(:path) { 'name' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { I18n.t("attributes.name") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { I18n.t('attributes.name') } let(:required) { true } let(:writable) { true } end - it_behaves_like "indicates length requirements" do + it_behaves_like 'indicates length requirements' do let(:min_length) { 1 } let(:max_length) { 255 } end end - describe "identifier" do - let(:path) { "identifier" } + describe 'identifier' do + let(:path) { 'identifier' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.project.identifier") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.project.identifier') } let(:required) { true } let(:has_default) { true } let(:writable) { true } end - it_behaves_like "indicates length requirements" do + it_behaves_like 'indicates length requirements' do let(:min_length) { 1 } let(:max_length) { 100 } end end - describe "description" do - let(:path) { "description" } + describe 'description' do + let(:path) { 'description' } - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } - let(:name) { I18n.t("attributes.description") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } + let(:name) { I18n.t('attributes.description') } let(:required) { false } let(:writable) { true } end end - describe "public" do - let(:path) { "public" } + describe 'public' do + let(:path) { 'public' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { I18n.t("attributes.public") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { I18n.t('attributes.public') } let(:required) { false } let(:writable) { true } end end - describe "active" do - let(:path) { "active" } + describe 'active' do + let(:path) { 'active' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { I18n.t("attributes.active") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { I18n.t('attributes.active') } let(:required) { false } let(:writable) { true } end end - describe "statusExplanation" do - let(:path) { "statusExplanation" } + describe 'statusExplanation' do + let(:path) { 'statusExplanation' } - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } - let(:name) { I18n.t("activerecord.attributes.project.status_explanation") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } + let(:name) { I18n.t('activerecord.attributes.project.status_explanation') } let(:required) { false } let(:writable) { true } end end - describe "status" do - let(:path) { "status" } + describe 'status' do + let(:path) { 'status' } - it_behaves_like "has basic schema properties" do - let(:type) { "ProjectStatus" } - let(:name) { I18n.t("activerecord.attributes.project.status_code") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'ProjectStatus' } + let(:name) { I18n.t('activerecord.attributes.project.status_code') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "links to allowed values directly" do + it_behaves_like 'links to allowed values directly' do let(:hrefs) { Project.status_codes.keys.map { |code| api_v3_paths.project_status code } } end end - describe "createdAt" do - let(:path) { "createdAt" } + describe 'createdAt' do + let(:path) { 'createdAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { I18n.t("attributes.created_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { I18n.t('attributes.created_at') } let(:required) { true } let(:writable) { false } end end - describe "updatedAt" do - let(:path) { "updatedAt" } + describe 'updatedAt' do + let(:path) { 'updatedAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { I18n.t("attributes.updated_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { I18n.t('attributes.updated_at') } let(:required) { true } let(:writable) { false } end end - describe "int custom field" do + describe 'int custom field' do let(:path) { "customField#{custom_field.id}" } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } let(:name) { custom_field.name } let(:required) { false } let(:writable) { false } end end - describe "parent" do - let(:path) { "parent" } + describe 'parent' do + let(:path) { 'parent' } - context "when having a new record" do - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Project.human_attribute_name("parent") } + context 'when having a new record' do + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Project.human_attribute_name('parent') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "when embedding" do + context 'when embedding' do let(:embedded) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.projects_available_parents end end end - context "when not embedding" do + context 'when not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end - context "when only having the add_subprojects permissions" do + context 'when only having the add_subprojects permissions' do let(:project_permissions) { %i[add_subprojects] } let(:global_permissions) { [] } - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Project.human_attribute_name("parent") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Project.human_attribute_name('parent') } # Required is different when the add_project permission is lacking let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end end end - context "if having a persisted record" do + context 'if having a persisted record' do let(:new_record) { false } - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Project.human_attribute_name("parent") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Project.human_attribute_name('parent') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.projects_available_parents + "?of=#{model_id}" end end end - context "if not embedding" do + context 'if not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end end - context "_links" do - describe "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context '_links' do + describe 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end - context "embedded in a form" do + context 'embedded in a form' do let(:self_link) { nil } - it_behaves_like "has no link" do - let(:link) { "self" } + it_behaves_like 'has no link' do + let(:link) { 'self' } end end end diff --git a/spec/lib/api/v3/projects/statuses/status_representer_rendering_spec.rb b/spec/lib/api/v3/projects/statuses/status_representer_rendering_spec.rb index aba2eda8824f..e26e113cbe3c 100644 --- a/spec/lib/api/v3/projects/statuses/status_representer_rendering_spec.rb +++ b/spec/lib/api/v3/projects/statuses/status_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Projects::Statuses::StatusRepresenter, "rendering" do +RSpec.describe API::V3::Projects::Statuses::StatusRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject { representer.to_json } @@ -40,26 +40,26 @@ current_user { build_stubbed(:user) } - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.project_status status } let(:title) { I18n.t(:"activerecord.attributes.project.status_codes.#{status}") } end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "ProjectStatus" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'ProjectStatus' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { status } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { I18n.t(:"activerecord.attributes.project.status_codes.#{status}") } end end diff --git a/spec/lib/api/v3/queries/columns/query_property_column_representer_spec.rb b/spec/lib/api/v3/queries/columns/query_property_column_representer_spec.rb index d161ec718d00..dc36c230099a 100644 --- a/spec/lib/api/v3/queries/columns/query_property_column_representer_spec.rb +++ b/spec/lib/api/v3/queries/columns/query_property_column_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Columns::QueryPropertyColumnRepresenter do include API::V3::Utilities::PathHelper @@ -36,75 +36,75 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_column "status" } - let(:title) { "Status" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_column 'status' } + let(:title) { 'Status' } end end - it "has _type QueryColumn::Property" do + it 'has _type QueryColumn::Property' do expect(subject) - .to be_json_eql("QueryColumn::Property".to_json) - .at_path("_type") + .to be_json_eql('QueryColumn::Property'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("status".to_json) - .at_path("id") + .to be_json_eql('status'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Status".to_json) - .at_path("name") + .to be_json_eql('Status'.to_json) + .at_path('name') end - context "for a translated column" do + context 'for a translated column' do let(:column) { Query.available_columns.detect { |column| column.name == :assigned_to } } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_column "assignee" } - let(:title) { "Assignee" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_column 'assignee' } + let(:title) { 'Assignee' } end end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("assignee".to_json) - .at_path("id") + .to be_json_eql('assignee'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Assignee".to_json) - .at_path("name") + .to be_json_eql('Assignee'.to_json) + .at_path('name') end end end - describe "caching" do + describe 'caching' do before do # fill the cache representer.to_json end - it "is cached" do + it 'is cached' do expect(representer) .not_to receive(:to_hash) representer.to_json end - it "busts the cache on changes to the caption (cf rename)" do + it 'busts the cache on changes to the caption (cf rename)' do allow(column) .to receive(:caption) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -112,10 +112,10 @@ representer.to_json end - it "busts the cache on changes to the name" do + it 'busts the cache on changes to the name' do allow(column) .to receive(:name) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -123,7 +123,7 @@ representer.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(representer) .to receive(:to_hash) diff --git a/spec/lib/api/v3/queries/columns/query_relation_of_type_column_representer_spec.rb b/spec/lib/api/v3/queries/columns/query_relation_of_type_column_representer_spec.rb index fc1f73b93961..7b95b5fb444c 100644 --- a/spec/lib/api/v3/queries/columns/query_relation_of_type_column_representer_spec.rb +++ b/spec/lib/api/v3/queries/columns/query_relation_of_type_column_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Columns::QueryRelationOfTypeColumnRepresenter do include API::V3::Utilities::PathHelper @@ -37,57 +37,57 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.query_column "relationsOfType#{type[:sym].to_s.camelcase}" } let(:title) { "#{I18n.t(type[:name]).capitalize} relations" } end end - it "has _type QueryColumn::RelationOfType" do + it 'has _type QueryColumn::RelationOfType' do expect(subject) - .to be_json_eql("QueryColumn::RelationOfType".to_json) - .at_path("_type") + .to be_json_eql('QueryColumn::RelationOfType'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) .to be_json_eql("relationsOfType#{type[:sym].to_s.camelcase}".to_json) - .at_path("id") + .at_path('id') end - it "has relationType attribute" do + it 'has relationType attribute' do expect(subject) .to be_json_eql(type[:sym].to_json) - .at_path("relationType") + .at_path('relationType') end - it "has name attribute" do + it 'has name attribute' do expect(subject) .to be_json_eql("#{I18n.t(type[:name]).capitalize} relations".to_json) - .at_path("name") + .at_path('name') end end - describe "caching" do + describe 'caching' do before do # fill the cache representer.to_json end - it "is cached" do + it 'is cached' do expect(representer) .not_to receive(:to_hash) representer.to_json end - it "busts the cache on changes to the name" do + it 'busts the cache on changes to the name' do allow(column) .to receive(:name) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -95,7 +95,7 @@ representer.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(representer) .to receive(:to_hash) diff --git a/spec/lib/api/v3/queries/columns/query_relation_to_type_column_representer_spec.rb b/spec/lib/api/v3/queries/columns/query_relation_to_type_column_representer_spec.rb index 9f3a1c2cdd2a..79d4af9e0b47 100644 --- a/spec/lib/api/v3/queries/columns/query_relation_to_type_column_representer_spec.rb +++ b/spec/lib/api/v3/queries/columns/query_relation_to_type_column_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Columns::QueryRelationToTypeColumnRepresenter do include API::V3::Utilities::PathHelper @@ -37,57 +37,57 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.query_column "relationsToType#{type.id}" } let(:title) { "Relations to #{type.name}" } end - it_behaves_like "has a titled link" do - let(:link) { "type" } + it_behaves_like 'has a titled link' do + let(:link) { 'type' } let(:href) { api_v3_paths.type type.id } let(:title) { type.name } end end - it "has _type QueryColumn::RelationToType" do + it 'has _type QueryColumn::RelationToType' do expect(subject) - .to be_json_eql("QueryColumn::RelationToType".to_json) - .at_path("_type") + .to be_json_eql('QueryColumn::RelationToType'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) .to be_json_eql("relationsToType#{type.id}".to_json) - .at_path("id") + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) .to be_json_eql("Relations to #{type.name}".to_json) - .at_path("name") + .at_path('name') end end - describe "caching" do + describe 'caching' do before do # fill the cache representer.to_json end - it "is cached" do + it 'is cached' do expect(representer) .not_to receive(:to_hash) representer.to_json end - it "busts the cache on changes to the name" do + it 'busts the cache on changes to the name' do allow(column) .to receive(:name) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -95,10 +95,10 @@ representer.to_json end - it "busts the cache on changes to the type" do + it 'busts the cache on changes to the type' do allow(type) .to receive(:cache_key) - .and_return("a_different_one") + .and_return('a_different_one') expect(representer) .to receive(:to_hash) @@ -106,7 +106,7 @@ representer.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(representer) .to receive(:to_hash) diff --git a/spec/lib/api/v3/queries/filters/query_filter_instance_representer_spec.rb b/spec/lib/api/v3/queries/filters/query_filter_instance_representer_spec.rb index 29c186c01238..c2e14c666612 100644 --- a/spec/lib/api/v3/queries/filters/query_filter_instance_representer_spec.rb +++ b/spec/lib/api/v3/queries/filters/query_filter_instance_representer_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Filters::QueryFilterInstanceRepresenter do include API::V3::Utilities::PathHelper - let(:operator) { "=" } + let(:operator) { '=' } let(:values) { [status.id.to_s] } let(:status) { build_stubbed(:status) } @@ -52,25 +52,25 @@ .and_return([status]) end - describe "generation" do + describe 'generation' do subject { representer.to_json } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "filter" } - let(:href) { api_v3_paths.query_filter "status" } - let(:title) { "Status" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'filter' } + let(:href) { api_v3_paths.query_filter 'status' } + let(:title) { 'Status' } end - it_behaves_like "has a titled link" do - let(:link) { "operator" } - let(:href) { api_v3_paths.query_operator(CGI.escape("=")) } - let(:title) { "is (OR)" } + it_behaves_like 'has a titled link' do + let(:link) { 'operator' } + let(:href) { api_v3_paths.query_operator(CGI.escape('=')) } + let(:title) { 'is (OR)' } end - it_behaves_like "has an untitled link" do - let(:link) { "schema" } - let(:href) { api_v3_paths.query_filter_instance_schema "status" } + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } + let(:href) { api_v3_paths.query_filter_instance_schema 'status' } end it "has a 'values' collection" do @@ -81,7 +81,7 @@ expect(subject) .to be_json_eql([expected].to_json) - .at_path("_links/values") + .at_path('_links/values') end it "renders templated values as part of the 'values' collection" do @@ -90,30 +90,30 @@ .and_return([Queries::Filters::TemplatedValue.new(Status)]) expected = { - href: api_v3_paths.status("{id}"), + href: api_v3_paths.status('{id}'), title: nil, templated: true } expect(subject) .to be_json_eql([expected].to_json) - .at_path("_links/values") + .at_path('_links/values') end end - it "has _type StatusQueryFilter" do + it 'has _type StatusQueryFilter' do expect(subject) - .to be_json_eql("StatusQueryFilter".to_json) - .at_path("_type") + .to be_json_eql('StatusQueryFilter'.to_json) + .at_path('_type') end - it "has name Status" do + it 'has name Status' do expect(subject) - .to be_json_eql("Status".to_json) - .at_path("name") + .to be_json_eql('Status'.to_json) + .at_path('name') end - context "with an invalid value_objects" do + context 'with an invalid value_objects' do let(:filter) do f = Queries::WorkPackages::Filter::AssignedToFilter.create! f.operator = operator @@ -121,7 +121,7 @@ f end - let(:values) { ["1"] } + let(:values) { ['1'] } before do allow(filter) @@ -132,16 +132,16 @@ it "has a 'values' collection" do expected = { href: nil, - title: "Anonymous" + title: 'Anonymous' } expect(subject) .to be_json_eql([expected].to_json) - .at_path("_links/values") + .at_path('_links/values') end end - context "with a subproject filter value_objects" do + context 'with a subproject filter value_objects' do shared_let(:admin) { create(:admin) } let(:project) { create(:project) } @@ -151,7 +151,7 @@ project.reload f = Queries::WorkPackages::Filter::SubprojectFilter.create!(context: project) - f.operator = "=" + f.operator = '=' f.values = [subproject.id] f @@ -176,12 +176,12 @@ expect(subject) .to be_json_eql([expected].to_json) - .at_path("_links/values") + .at_path('_links/values') end end - context "with a non ar object filter" do - let(:values) { ["lorem ipsum"] } + context 'with a non ar object filter' do + let(:values) { ['lorem ipsum'] } let(:filter) do f = Queries::WorkPackages::Filter::SubjectFilter.create! f.operator = operator @@ -190,21 +190,21 @@ f end - describe "_links" do - it "has no values link" do + describe '_links' do + it 'has no values link' do expect(subject) - .not_to have_json_path("_links/values") + .not_to have_json_path('_links/values') end end it "has a 'values' array property" do expect(subject) .to be_json_eql(values.to_json) - .at_path("values") + .at_path('values') end end - context "with a bool custom field filter" do + context 'with a bool custom field filter' do let(:bool_cf) { create(:boolean_wp_custom_field) } let(:filter) do Queries::WorkPackages::Filter::CustomFieldFilter.create!(name: bool_cf.column_name, operator:, values:) @@ -216,7 +216,7 @@ it "has `true` for 'values'" do expect(subject) .to be_json_eql([true].to_json) - .at_path("values") + .at_path('values') end end @@ -226,17 +226,17 @@ it "has `true` for 'values'" do expect(subject) .to be_json_eql([false].to_json) - .at_path("values") + .at_path('values') end end context "with something as filter value" do - let(:values) { ["blubs"] } + let(:values) { ['blubs'] } it "has `true` for 'values'" do expect(subject) .to be_json_eql([false].to_json) - .at_path("values") + .at_path('values') end end end diff --git a/spec/lib/api/v3/queries/filters/query_filter_representer_spec.rb b/spec/lib/api/v3/queries/filters/query_filter_representer_spec.rb index da598c136af3..2f33b3857a40 100644 --- a/spec/lib/api/v3/queries/filters/query_filter_representer_spec.rb +++ b/spec/lib/api/v3/queries/filters/query_filter_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Filters::QueryFilterRepresenter do include API::V3::Utilities::PathHelper @@ -36,46 +36,46 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_filter "subject" } - let(:title) { "Subject" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_filter 'subject' } + let(:title) { 'Subject' } end end - it "has _type QueryFilter" do + it 'has _type QueryFilter' do expect(subject) - .to be_json_eql("QueryFilter".to_json) - .at_path("_type") + .to be_json_eql('QueryFilter'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("subject".to_json) - .at_path("id") + .to be_json_eql('subject'.to_json) + .at_path('id') end - context "for a translated filter" do + context 'for a translated filter' do let(:filter) { Queries::WorkPackages::Filter::AssignedToFilter.create! } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_filter "assignee" } - let(:title) { "Assignee" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_filter 'assignee' } + let(:title) { 'Assignee' } end end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("assignee".to_json) - .at_path("id") + .to be_json_eql('assignee'.to_json) + .at_path('id') end end - context "for a custom field filter" do + context 'for a custom field filter' do let(:custom_field) { build_stubbed(:list_wp_custom_field) } let(:filter) do Queries::WorkPackages::Filter::CustomFieldFilter.from_custom_field! custom_field: @@ -90,18 +90,18 @@ filter end - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.query_filter custom_field.attribute_name(:camel_case) } let(:title) { custom_field.name } end end - it "has id attribute" do + it 'has id attribute' do expect(subject) .to be_json_eql("customField#{custom_field.id}".to_json) - .at_path("id") + .at_path('id') end end end diff --git a/spec/lib/api/v3/queries/group_bys/query_group_by_representer_spec.rb b/spec/lib/api/v3/queries/group_bys/query_group_by_representer_spec.rb index 215885558027..32e3c380c75f 100644 --- a/spec/lib/api/v3/queries/group_bys/query_group_by_representer_spec.rb +++ b/spec/lib/api/v3/queries/group_bys/query_group_by_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::GroupBys::QueryGroupByRepresenter do include API::V3::Utilities::PathHelper @@ -36,75 +36,75 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_group_by "status" } - let(:title) { "Status" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_group_by 'status' } + let(:title) { 'Status' } end end - it "has _type QueryGroupBy" do + it 'has _type QueryGroupBy' do expect(subject) - .to be_json_eql("QueryGroupBy".to_json) - .at_path("_type") + .to be_json_eql('QueryGroupBy'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("status".to_json) - .at_path("id") + .to be_json_eql('status'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Status".to_json) - .at_path("name") + .to be_json_eql('Status'.to_json) + .at_path('name') end - context "for a translated column" do + context 'for a translated column' do let(:column) { Query.available_columns.detect { |column| column.name == :assigned_to } } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_group_by "assignee" } - let(:title) { "Assignee" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_group_by 'assignee' } + let(:title) { 'Assignee' } end end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("assignee".to_json) - .at_path("id") + .to be_json_eql('assignee'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Assignee".to_json) - .at_path("name") + .to be_json_eql('Assignee'.to_json) + .at_path('name') end end end - describe "caching" do + describe 'caching' do before do # fill the cache representer.to_json end - it "is cached" do + it 'is cached' do expect(representer) .not_to receive(:to_hash) representer.to_json end - it "busts the cache on changes to the caption (cf rename)" do + it 'busts the cache on changes to the caption (cf rename)' do allow(column) .to receive(:caption) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -112,10 +112,10 @@ representer.to_json end - it "busts the cache on changes to the name" do + it 'busts the cache on changes to the name' do allow(column) .to receive(:name) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -123,7 +123,7 @@ representer.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(representer) .to receive(:to_hash) diff --git a/spec/lib/api/v3/queries/ical_url/query_ical_url_representer_spec.rb b/spec/lib/api/v3/queries/ical_url/query_ical_url_representer_spec.rb index 6d48d1c14039..72325d3b249b 100644 --- a/spec/lib/api/v3/queries/ical_url/query_ical_url_representer_spec.rb +++ b/spec/lib/api/v3/queries/ical_url/query_ical_url_representer_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::ICalUrl::QueryICalUrlRepresenter do include API::V3::Utilities::PathHelper let(:query) { build_stubbed(:query) } - let(:mocked_ical_url) { "https://community.openproject.org/projects/3/calendars/46/ical?ical_token=66a44f91a18ad0355cfad77c319ef5ee2973291499fb8e44a220885f9124d2d2" } + let(:mocked_ical_url) { 'https://community.openproject.org/projects/3/calendars/46/ical?ical_token=66a44f91a18ad0355cfad77c319ef5ee2973291499fb8e44a220885f9124d2d2' } let(:data_to_be_represented) do ical_url_data = Struct.new(:ical_url, :query) ical_url_data.new(mocked_ical_url, query) @@ -45,31 +45,31 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.query_ical_url(query.id) } let(:method) { "post" } end - it_behaves_like "has an untitled link" do - let(:link) { "query" } + it_behaves_like 'has an untitled link' do + let(:link) { 'query' } let(:href) { api_v3_paths.query(query.id) } let(:method) { "get" } end - it_behaves_like "has an untitled link" do - let(:link) { "icalUrl" } + it_behaves_like 'has an untitled link' do + let(:link) { 'icalUrl' } let(:href) { mocked_ical_url } let(:method) { "get" } end end - it "has _type QueryICalUrl" do + it 'has _type QueryICalUrl' do expect(subject) - .to be_json_eql("QueryICalUrl".to_json) - .at_path("_type") + .to be_json_eql('QueryICalUrl'.to_json) + .at_path('_type') end end end diff --git a/spec/lib/api/v3/queries/operators/query_operator_representer_spec.rb b/spec/lib/api/v3/queries/operators/query_operator_representer_spec.rb index cbbf02241e63..b23629cdbcc7 100644 --- a/spec/lib/api/v3/queries/operators/query_operator_representer_spec.rb +++ b/spec/lib/api/v3/queries/operators/query_operator_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Operators::QueryOperatorRepresenter do include API::V3::Utilities::PathHelper @@ -36,31 +36,31 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.query_operator operator.to_query } let(:title) { I18n.t(:label_not_contains) } end end - it "has _type QueryOperator" do + it 'has _type QueryOperator' do expect(subject) - .to be_json_eql("QueryOperator".to_json) - .at_path("_type") + .to be_json_eql('QueryOperator'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) .to be_json_eql(operator.to_sym.to_json) - .at_path("id") + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) .to be_json_eql(I18n.t(:label_not_contains).to_json) - .at_path("name") + .at_path('name') end end end diff --git a/spec/lib/api/v3/queries/queries_params_representer_spec.rb b/spec/lib/api/v3/queries/queries_params_representer_spec.rb index 2e5bf88bed8b..b74d540df7a4 100644 --- a/spec/lib/api/v3/queries/queries_params_representer_spec.rb +++ b/spec/lib/api/v3/queries/queries_params_representer_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::QueryParamsRepresenter do let(:query) { build_stubbed(:query, **params) } let(:instance) { described_class.new(query) } - describe "#to_h" do + describe '#to_h' do subject { instance.to_h } - context "with include_subprojects true" do + context 'with include_subprojects true' do let(:params) { { include_subprojects: true } } - it "transports that to the params (Regression #44248)" do + it 'transports that to the params (Regression #44248)' do expect(subject[:includeSubprojects]).to be true end end - context "with include_subprojects false" do + context 'with include_subprojects false' do let(:params) { { include_subprojects: false } } - it "transports that to the params" do + it 'transports that to the params' do expect(subject.keys).to include :includeSubprojects expect(subject[:includeSubprojects]).to be false end diff --git a/spec/lib/api/v3/queries/query_representer_parsing_spec.rb b/spec/lib/api/v3/queries/query_representer_parsing_spec.rb index 833863160105..878b83cda865 100644 --- a/spec/lib/api/v3/queries/query_representer_parsing_spec.rb +++ b/spec/lib/api/v3/queries/query_representer_parsing_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Queries::QueryRepresenter, "parsing" do +RSpec.describe API::V3::Queries::QueryRepresenter, 'parsing' do include API::V3::Utilities::PathHelper let(:query) { API::ParserStruct.new } @@ -68,42 +68,42 @@ subject { representer.from_hash(request_body) } - describe "empty group_by (Regression #25606)" do + describe 'empty group_by (Regression #25606)' do before do - query.group_by = "project" + query.group_by = 'project' end let(:request_body) do { - "_links" => { - "groupBy" => { "href" => nil } + '_links' => { + 'groupBy' => { 'href' => nil } } } end - it "unsets group_by" do + it 'unsets group_by' do expect(subject.group_by).to be_nil end end - describe "highlighted_attributes", with_ee: %i[conditional_highlighting] do + describe 'highlighted_attributes', with_ee: %i[conditional_highlighting] do let(:request_body) do { - "_links" => { - "highlightedAttributes" => [{ "href" => "/api/v3/queries/columns/type" }] + '_links' => { + 'highlightedAttributes' => [{ 'href' => "/api/v3/queries/columns/type" }] } } end - it "sets highlighted_attributes" do + it 'sets highlighted_attributes' do expect(subject.highlighted_attributes).to eq(%i{type}) end end - describe "ordered work packages" do + describe 'ordered work packages' do let(:request_body) do { - "orderedWorkPackages" => { + 'orderedWorkPackages' => { 50 => 0, 38 => 1234, 102 => 81234123 @@ -111,18 +111,18 @@ } end - it "sets ordered_work_packages" do + it 'sets ordered_work_packages' do expect(subject.ordered_work_packages) .to eq({ "50" => 0, "38" => 1234, "102" => 81234123 }) end end - describe "project" do + describe 'project' do let(:request_body) do { - "_links" => { - "project" => { - "href" => "/api/v3/projects/#{project_id}" + '_links' => { + 'project' => { + 'href' => "/api/v3/projects/#{project_id}" } } } @@ -141,44 +141,44 @@ .and_return(project.id) end - context "for a number only id" do + context 'for a number only id' do let(:project_id) { project.id } - it "sets the project_id accordingly" do + it 'sets the project_id accordingly' do expect(subject.project_id) .to eql project.id end end - context "for a text only id (identifier)" do + context 'for a text only id (identifier)' do let(:project_id) { project.identifier } - it "deduces the id for the project_id accordingly" do + it 'deduces the id for the project_id accordingly' do expect(subject.project_id) .to eql project.id end end - context "for a text starting with numbers (identifier)" do - let(:project) { build_stubbed(:project, identifier: "5555-numbered-identifier") } + context 'for a text starting with numbers (identifier)' do + let(:project) { build_stubbed(:project, identifier: '5555-numbered-identifier') } let(:project_id) { project.identifier } - it "deduces the id for the project_id accordingly" do + it 'deduces the id for the project_id accordingly' do expect(subject.project_id) .to eql project.id end end end - describe "timestamps" do - let(:timestamp_params) { [1.week.ago.iso8601, "lastWorkingDay@12:00", "P0D"] } + describe 'timestamps' do + let(:timestamp_params) { [1.week.ago.iso8601, 'lastWorkingDay@12:00', 'P0D'] } let(:request_body) do - { "timestamps" => timestamp_params } + { 'timestamps' => timestamp_params } end - it "sets timestamps" do + it 'sets timestamps' do expect(subject.timestamps) - .to eq([1.week.ago.iso8601, "lastWorkingDay@12:00", "P0D"]) + .to eq([1.week.ago.iso8601, 'lastWorkingDay@12:00', 'P0D']) end end end diff --git a/spec/lib/api/v3/queries/query_representer_rendering_spec.rb b/spec/lib/api/v3/queries/query_representer_rendering_spec.rb index 0705103c9b11..bdf1f40037e5 100644 --- a/spec/lib/api/v3/queries/query_representer_rendering_spec.rb +++ b/spec/lib/api/v3/queries/query_representer_rendering_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::QueryRepresenter do include API::V3::Utilities::PathHelper @@ -75,47 +75,47 @@ def non_empty_to_query(hash) else value.to_query(key) end - end.sort! * "&" + end.sort! * '&' end subject { representer.to_json } - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.query(query.id) } let(:title) { query.name } end - context "with params" do + context 'with params' do let(:representer) do described_class.new(query, current_user: user, embed_links:, params: { "filters" => "something", "id" => "234" }) end - it_behaves_like "has a titled link" do - let(:link) { "self" } + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { "#{api_v3_paths.query(query.id)}?filters=something" } let(:title) { query.name } end end end - it_behaves_like "has a titled link" do - let(:link) { "user" } + it_behaves_like 'has a titled link' do + let(:link) { 'user' } let(:href) { api_v3_paths.user query.user_id } let(:title) { query.user.name } end - it_behaves_like "has a titled link" do - let(:link) { "project" } + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project query.project_id } let(:title) { query.project.name } end - it_behaves_like "has an untitled link" do - let(:link) { "results" } + it_behaves_like 'has an untitled link' do + let(:link) { 'results' } let(:href) do params = { offset: 1, @@ -129,25 +129,25 @@ def non_empty_to_query(hash) end end - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) { api_v3_paths.query_project_schema(project.identifier) } end - context "when the query has no project" do + context 'when the query has no project' do let(:query) { build_stubbed(:query, project: nil) } - it_behaves_like "has an empty link" do - let(:link) { "project" } + it_behaves_like 'has an empty link' do + let(:link) { 'project' } end - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) { api_v3_paths.query_schema } end - it_behaves_like "has an untitled link" do - let(:link) { "results" } + it_behaves_like 'has an untitled link' do + let(:link) { 'results' } let(:href) do params = { offset: 1, @@ -162,166 +162,166 @@ def non_empty_to_query(hash) end end - describe "update action link" do - it_behaves_like "has an untitled link" do - let(:link) { "update" } + describe 'update action link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.query_form(query.id) } end - context "without a project" do + context 'without a project' do let(:query) { build_stubbed(:query, project: nil) } - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) { api_v3_paths.query_schema } end end - context "when unpersisted" do + context 'when unpersisted' do let(:query) { unpersisted_query } - it_behaves_like "has an untitled link" do - let(:link) { "update" } + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.create_query_form } end end - context "when unpersisted outside a project" do + context 'when unpersisted outside a project' do let(:project) { nil } let(:query) { unpersisted_query } - it_behaves_like "has an untitled link" do - let(:link) { "update" } + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.create_query_form } end end end - describe "delete action link" do + describe 'delete action link' do let(:permissions) { [:destroy] } - it_behaves_like "has an untitled link" do - let(:link) { "delete" } + it_behaves_like 'has an untitled link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.query query.id } end - context "when not persisted" do + context 'when not persisted' do let(:query) { unpersisted_query } - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end - context "when not allowed to delete" do + context 'when not allowed to delete' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end - context "when no user is provided" do + context 'when no user is provided' do let(:user) { nil } let(:embed_links) { false } - it_behaves_like "has no link" do - let(:link) { "delete" } + it_behaves_like 'has no link' do + let(:link) { 'delete' } end end end - describe "updateImmediately action link" do + describe 'updateImmediately action link' do let(:permissions) { [:update] } - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.query query.id } end - context "when not persisted and lacking permission" do + context 'when not persisted and lacking permission' do let(:query) { unpersisted_query } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end - context "when not persisted and having permission" do + context 'when not persisted and having permission' do let(:permissions) { [:create] } let(:query) { unpersisted_query } - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.query query.id } end end - context "when not allowed to update" do + context 'when not allowed to update' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end - context "when no user is provided" do + context 'when no user is provided' do let(:user) { nil } let(:embed_links) { false } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end end - describe "updateOrderedWorkPackages action link" do + describe 'updateOrderedWorkPackages action link' do let(:permissions) { %i[update reorder_work_packages] } - it_behaves_like "has an untitled link" do - let(:link) { "updateOrderedWorkPackages" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateOrderedWorkPackages' } let(:href) { api_v3_paths.query_order query.id } end - context "when not persisted and lacking permission" do + context 'when not persisted and lacking permission' do let(:query) { unpersisted_query } - it_behaves_like "has no link" do - let(:link) { "updateOrderedWorkPackages" } + it_behaves_like 'has no link' do + let(:link) { 'updateOrderedWorkPackages' } end end - context "when not persisted and having permission" do + context 'when not persisted and having permission' do let(:permissions) { [:create] } let(:query) { unpersisted_query } - it_behaves_like "has an untitled link" do - let(:link) { "updateOrderedWorkPackages" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateOrderedWorkPackages' } let(:href) { api_v3_paths.query_order query.id } end end - context "when not allowed to update" do + context 'when not allowed to update' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "updateOrderedWorkPackages" } + it_behaves_like 'has no link' do + let(:link) { 'updateOrderedWorkPackages' } end end - context "when no user is provided" do + context 'when no user is provided' do let(:user) { nil } let(:embed_links) { false } - it_behaves_like "has no link" do - let(:link) { "updateOrderedWorkPackages" } + it_behaves_like 'has no link' do + let(:link) { 'updateOrderedWorkPackages' } end end end - context "with filter, sort, group by and pageSize" do + context 'with filter, sort, group by and pageSize' do let(:representer) do described_class.new(query, current_user: user) @@ -329,8 +329,8 @@ def non_empty_to_query(hash) let(:query) do query = build_stubbed(:query, project:) - query.add_filter("subject", "~", ["bogus"]) - query.group_by = "author" + query.add_filter('subject', '~', ['bogus']) + query.group_by = 'author' query.sort_criteria = [%w[assigned_to asc], %w[type desc]] query @@ -340,24 +340,24 @@ def non_empty_to_query(hash) params = { offset: 1, pageSize: Setting.per_page_options_array.first, - filters: JSON::dump([{ subject: { operator: "~", values: ["bogus"] } }]), + filters: JSON::dump([{ subject: { operator: '~', values: ['bogus'] } }]), showSums: false, showHierarchies: false, includeSubprojects: true, - groupBy: "author", + groupBy: 'author', sortBy: JSON::dump([%w[assignee asc], %w[type desc]]) } api_v3_paths.work_packages_by_project(project.id) + "?#{params.to_query}" end - it_behaves_like "has an untitled link" do - let(:link) { "results" } + it_behaves_like 'has an untitled link' do + let(:link) { 'results' } let(:href) { expected_href } end end - context "with offset and page size" do + context 'with offset and page size' do let(:representer) do described_class.new(query, current_user: user, @@ -377,31 +377,31 @@ def non_empty_to_query(hash) api_v3_paths.work_packages_by_project(project.id) + "?#{non_empty_to_query(params)}" end - it_behaves_like "has an untitled link" do - let(:link) { "results" } + it_behaves_like 'has an untitled link' do + let(:link) { 'results' } let(:href) { expected_href } end end - context "without columns" do + context 'without columns' do let(:query) do query = build_stubbed(:query, project:) # need to write bogus here because the query # will otherwise sport the default columns - query.column_names = ["blubs"] + query.column_names = ['blubs'] query end - it "has an empty columns array" do + it 'has an empty columns array' do expect(subject) .to be_json_eql([].to_json) - .at_path("_links/columns") + .at_path('_links/columns') end end - context "with columns" do + context 'with columns' do let(:query) do query = build_stubbed(:query, project:) @@ -410,85 +410,85 @@ def non_empty_to_query(hash) query end - it "has an array of columns" do + it 'has an array of columns' do status = { - href: "/api/v3/queries/columns/status", - title: "Status" + href: '/api/v3/queries/columns/status', + title: 'Status' } assignee = { - href: "/api/v3/queries/columns/assignee", - title: "Assignee" + href: '/api/v3/queries/columns/assignee', + title: 'Assignee' } subproject = { - href: "/api/v3/queries/columns/updatedAt", - title: "Updated on" + href: '/api/v3/queries/columns/updatedAt', + title: 'Updated on' } expected = [status, assignee, subproject] expect(subject) .to be_json_eql(expected.to_json) - .at_path("_links/columns") + .at_path('_links/columns') end end - context "without group_by" do - it_behaves_like "has a titled link" do + context 'without group_by' do + it_behaves_like 'has a titled link' do let(:href) { nil } - let(:link) { "groupBy" } + let(:link) { 'groupBy' } let(:title) { nil } end end - context "with group_by" do + context 'with group_by' do let(:query) do query = build_stubbed(:query, project:) - query.group_by = "status" + query.group_by = 'status' query end - it_behaves_like "has a titled link" do - let(:href) { "/api/v3/queries/group_bys/status" } - let(:link) { "groupBy" } - let(:title) { "Status" } + it_behaves_like 'has a titled link' do + let(:href) { '/api/v3/queries/group_bys/status' } + let(:link) { 'groupBy' } + let(:title) { 'Status' } end end - context "without sort_by" do - it "has an empty sortBy array" do + context 'without sort_by' do + it 'has an empty sortBy array' do expect(subject) .to be_json_eql([].to_json) - .at_path("_links/sortBy") + .at_path('_links/sortBy') end end - context "with sort_by" do + context 'with sort_by' do let(:query) do build_stubbed(:query, sort_criteria: [%w[subject asc], %w[assigned_to desc]]) end - it "has an array of sortBy" do + it 'has an array of sortBy' do expected = [ { - href: api_v3_paths.query_sort_by("subject", "asc"), - title: "Subject (Ascending)" + href: api_v3_paths.query_sort_by('subject', 'asc'), + title: 'Subject (Ascending)' }, { - href: api_v3_paths.query_sort_by("assignee", "desc"), - title: "Assignee (Descending)" + href: api_v3_paths.query_sort_by('assignee', 'desc'), + title: 'Assignee (Descending)' } ] expect(subject) .to be_json_eql(expected.to_json) - .at_path("_links/sortBy") + .at_path('_links/sortBy') end end - context "when not starred" do + context 'when not starred' do let(:permissions) { %i(star unstar) } before do @@ -497,27 +497,27 @@ def non_empty_to_query(hash) .and_return(false) end - it_behaves_like "has an untitled link" do - let(:link) { "star" } + it_behaves_like 'has an untitled link' do + let(:link) { 'star' } let(:href) { api_v3_paths.query_star query.id } end - it "has no unstar link" do + it 'has no unstar link' do expect(subject) - .not_to have_json_path("_links/unstar") + .not_to have_json_path('_links/unstar') end - context "when lacking permission" do + context 'when lacking permission' do let(:permissions) { [] } - it "has no star link" do + it 'has no star link' do expect(subject) - .not_to have_json_path("_links/star") + .not_to have_json_path('_links/star') end end end - context "when starred" do + context 'when starred' do let(:permissions) { %i(star unstar) } before do @@ -526,146 +526,146 @@ def non_empty_to_query(hash) .and_return(true) end - it_behaves_like "has an untitled link" do - let(:link) { "unstar" } + it_behaves_like 'has an untitled link' do + let(:link) { 'unstar' } let(:href) { api_v3_paths.query_unstar query.id } end - it "has no star link" do + it 'has no star link' do expect(subject) - .not_to have_json_path("_links/star") + .not_to have_json_path('_links/star') end - context "when lacking permission" do + context 'when lacking permission' do let(:permissions) { [] } - it "has no unstar link" do + it 'has no unstar link' do expect(subject) - .not_to have_json_path("_links/unstar") + .not_to have_json_path('_links/unstar') end end end end - describe "ical url" do - context "when allowed to subscribe to ical" do + describe 'ical url' do + context 'when allowed to subscribe to ical' do let(:permissions) { %i(share_via_ical) } - context "when icalendar sharing is enabled globally", with_settings: { ical_enabled: true } do - it_behaves_like "has an untitled link" do - let(:link) { "icalUrl" } + context 'when icalendar sharing is enabled globally', with_settings: { ical_enabled: true } do + it_behaves_like 'has an untitled link' do + let(:link) { 'icalUrl' } let(:href) { api_v3_paths.query_ical_url(query.id) } end end - context "when icalendar sharing is disabled globally", with_settings: { ical_enabled: false } do - it "has no icalUrl link" do + context 'when icalendar sharing is disabled globally', with_settings: { ical_enabled: false } do + it 'has no icalUrl link' do expect(subject) - .not_to have_json_path("_links/icalUrl") + .not_to have_json_path('_links/icalUrl') end end end - context "when lacking permission" do + context 'when lacking permission' do let(:permissions) { [] } - it "has no icalUrl link" do + it 'has no icalUrl link' do expect(subject) - .not_to have_json_path("_links/icalUrl") + .not_to have_json_path('_links/icalUrl') end end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Query" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Query' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { query.id } end - it_behaves_like "property", :name do + it_behaves_like 'property', :name do let(:value) { query.name } end - it_behaves_like "property", :sums do + it_behaves_like 'property', :sums do let(:value) { query.display_sums } end - it_behaves_like "property", :timelineVisible do + it_behaves_like 'property', :timelineVisible do let(:value) { query.timeline_visible } end - it_behaves_like "property", :timelineZoomLevel do + it_behaves_like 'property', :timelineZoomLevel do let(:value) { query.timeline_zoom_level } end - it_behaves_like "property", :timelineLabels do + it_behaves_like 'property', :timelineLabels do let(:value) { query.timeline_labels } end - it_behaves_like "property", :timestamps do + it_behaves_like 'property', :timestamps do let(:value) { query.timestamps } end - it_behaves_like "property", :public do + it_behaves_like 'property', :public do let(:value) { query.public } end - describe "hidden" do - context "with the query having a view" do - it_behaves_like "property", :hidden do + describe 'hidden' do + context 'with the query having a view' do + it_behaves_like 'property', :hidden do let(:value) { false } end end - context "without the query having a view" do + context 'without the query having a view' do let(:views) { [] } - it_behaves_like "property", :hidden do + it_behaves_like 'property', :hidden do let(:value) { true } end end end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { query.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { query.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end - describe "highlighting" do - context "with EE", with_ee: %i[conditional_highlighting] do + describe 'highlighting' do + context 'with EE', with_ee: %i[conditional_highlighting] do let :status do { - href: "/api/v3/queries/columns/status", - title: "Status" + href: '/api/v3/queries/columns/status', + title: 'Status' } end let :type do { - href: "/api/v3/queries/columns/type", - title: "Type" + href: '/api/v3/queries/columns/type', + title: 'Type' } end let :priority do { - href: "/api/v3/queries/columns/priority", - title: "Priority" + href: '/api/v3/queries/columns/priority', + title: 'Priority' } end let :due_date do { - href: "/api/v3/queries/columns/dueDate", - title: "Finish date" + href: '/api/v3/queries/columns/dueDate', + title: 'Finish date' } end @@ -681,25 +681,25 @@ def non_empty_to_query(hash) [status, priority, due_date] end - it "renders when the value is set" do - query.highlighting_mode = "status" + it 'renders when the value is set' do + query.highlighting_mode = 'status' - expect(subject).to be_json_eql("status".to_json).at_path("highlightingMode") + expect(subject).to be_json_eql('status'.to_json).at_path('highlightingMode') end - it "renders the default" do + it 'renders the default' do query.highlighting_mode = nil query.highlighted_attributes = nil - expect(subject).to be_json_eql("inline".to_json).at_path("highlightingMode") - expect(subject).not_to have_json_path("highlightedAttributes") + expect(subject).to be_json_eql('inline'.to_json).at_path('highlightingMode') + expect(subject).not_to have_json_path('highlightedAttributes') end - it "links an array of highlighted attributes" do + it 'links an array of highlighted attributes' do expect(subject) - .to be_json_eql(highlighted_attributes.to_json).at_path("_links/highlightedAttributes") + .to be_json_eql(highlighted_attributes.to_json).at_path('_links/highlightedAttributes') end - it "embeds selected inline attributes" do + it 'embeds selected inline attributes' do query.highlighted_attributes[0..0].each_with_index do |attr, index| expect(subject) .to be_json_eql("/api/v3/queries/columns/#{attr}".to_json) @@ -708,43 +708,43 @@ def non_empty_to_query(hash) end end - context "without EE" do - it "renders when the value is set" do - query.highlighting_mode = "status" + context 'without EE' do + it 'renders when the value is set' do + query.highlighting_mode = 'status' - expect(subject).to be_json_eql("none".to_json).at_path("highlightingMode") + expect(subject).to be_json_eql('none'.to_json).at_path('highlightingMode') end - it "renders none when not set" do + it 'renders none when not set' do query.highlighting_mode = nil - expect(subject).to be_json_eql("none".to_json).at_path("highlightingMode") + expect(subject).to be_json_eql('none'.to_json).at_path('highlightingMode') end end end - describe "showHierarchies" do - it "is true if query.show_hierarchies is true" do + describe 'showHierarchies' do + it 'is true if query.show_hierarchies is true' do query.show_hierarchies = true - expect(subject).to be_json_eql(true.to_json).at_path("showHierarchies") + expect(subject).to be_json_eql(true.to_json).at_path('showHierarchies') end - it "is false if query.show_hierarchies is false" do + it 'is false if query.show_hierarchies is false' do query.show_hierarchies = false - expect(subject).to be_json_eql(false.to_json).at_path("showHierarchies") + expect(subject).to be_json_eql(false.to_json).at_path('showHierarchies') end end - describe "with filters" do + describe 'with filters' do let(:query) do query = build_stubbed(:query) - query.add_filter("status_id", "=", [filter_status.id.to_s]) + query.add_filter('status_id', '=', [filter_status.id.to_s]) allow(query.filters.last) .to receive(:value_objects) .and_return([filter_status]) - query.add_filter("assigned_to_id", "!", [filter_user.id.to_s]) + query.add_filter('assigned_to_id', '!', [filter_user.id.to_s]) allow(query.filters.last) .to receive(:value_objects) .and_return([filter_user]) @@ -763,7 +763,7 @@ def non_empty_to_query(hash) title: "Status" }, operator: { - href: api_v3_paths.query_operator(CGI.escape("=")), + href: api_v3_paths.query_operator(CGI.escape('=')), title: "is (OR)" }, values: [ @@ -773,7 +773,7 @@ def non_empty_to_query(hash) } ], schema: { - href: api_v3_paths.query_filter_instance_schema("status") + href: api_v3_paths.query_filter_instance_schema('status') } } } @@ -788,7 +788,7 @@ def non_empty_to_query(hash) title: "Assignee" }, operator: { - href: api_v3_paths.query_operator(CGI.escape("!")), + href: api_v3_paths.query_operator(CGI.escape('!')), title: "is not" }, values: [ @@ -798,37 +798,37 @@ def non_empty_to_query(hash) } ], schema: { - href: api_v3_paths.query_filter_instance_schema("assignee") + href: api_v3_paths.query_filter_instance_schema('assignee') } } } end - it "renders the filters" do + it 'renders the filters' do expected = [expected_status, expected_assignee] - expect(subject).to be_json_eql(expected.to_json).at_path("filters") + expect(subject).to be_json_eql(expected.to_json).at_path('filters') end end - describe "with sort criteria" do + describe 'with sort criteria' do let(:query) do build_stubbed(:query, sort_criteria: [%w[subject asc], %w[assigned_to desc]]) end - it "has the sort criteria embedded" do + it 'has the sort criteria embedded' do expect(subject) - .to be_json_eql("/api/v3/queries/sort_bys/subject-asc".to_json) - .at_path("_embedded/sortBy/0/_links/self/href") + .to be_json_eql('/api/v3/queries/sort_bys/subject-asc'.to_json) + .at_path('_embedded/sortBy/0/_links/self/href') expect(subject) - .to be_json_eql("/api/v3/queries/sort_bys/assignee-desc".to_json) - .at_path("_embedded/sortBy/1/_links/self/href") + .to be_json_eql('/api/v3/queries/sort_bys/assignee-desc'.to_json) + .at_path('_embedded/sortBy/1/_links/self/href') end end - describe "with columns" do + describe 'with columns' do let(:query) do query = build_stubbed(:query, project:) @@ -837,52 +837,52 @@ def non_empty_to_query(hash) query end - it "has the columns embedded" do + it 'has the columns embedded' do expect(subject) - .to be_json_eql("/api/v3/queries/columns/status".to_json) - .at_path("_embedded/columns/0/_links/self/href") + .to be_json_eql('/api/v3/queries/columns/status'.to_json) + .at_path('_embedded/columns/0/_links/self/href') end - context "when not embedding" do + context 'when not embedding' do let(:representer) do described_class.new(query, current_user: user, embed_links: false) end - it "has no columns embedded" do + it 'has no columns embedded' do expect(subject) - .not_to have_json_path("_embedded/columns") + .not_to have_json_path('_embedded/columns') end end end - describe "with group by" do + describe 'with group by' do let(:query) do query = build_stubbed(:query, project:) - query.group_by = "status" + query.group_by = 'status' query end - it "has the group by embedded" do + it 'has the group by embedded' do expect(subject) - .to be_json_eql("/api/v3/queries/group_bys/status".to_json) - .at_path("_embedded/groupBy/_links/self/href") + .to be_json_eql('/api/v3/queries/group_bys/status'.to_json) + .at_path('_embedded/groupBy/_links/self/href') end - context "when not embedding" do + context 'when not embedding' do let(:representer) do described_class.new(query, current_user: user, embed_links: false) end - it "has no group bys embedded" do + it 'has no group bys embedded' do expect(subject) - .not_to have_json_path("_embedded/groupBy") + .not_to have_json_path('_embedded/groupBy') end end end - describe "when timeline is visible" do + describe 'when timeline is visible' do let(:query) do build_stubbed(:query_with_view_gantt, project:).tap do |query| query.timeline_visible = true @@ -890,26 +890,26 @@ def non_empty_to_query(hash) end it do - expect(subject).to be_json_eql("true").at_path("timelineVisible") + expect(subject).to be_json_eql('true').at_path('timelineVisible') end end - describe "when labels are overridden" do + describe 'when labels are overridden' do let(:query) do build_stubbed(:query, project:).tap do |query| query.timeline_labels = expected end end let(:expected) do - { "left" => "assignee", "right" => "status", "farRight" => "type" } + { 'left' => 'assignee', 'right' => 'status', 'farRight' => 'type' } end it do - expect(subject).to be_json_eql(expected.to_json).at_path("timelineLabels") + expect(subject).to be_json_eql(expected.to_json).at_path('timelineLabels') end end - describe "when timeline zoom level is changed" do + describe 'when timeline zoom level is changed' do let(:query) do build_stubbed(:query, project:).tap do |query| query.timeline_zoom_level = :weeks @@ -917,12 +917,12 @@ def non_empty_to_query(hash) end it do - expect(subject).to be_json_eql("weeks".to_json).at_path("timelineZoomLevel") + expect(subject).to be_json_eql('weeks'.to_json).at_path('timelineZoomLevel') end end end - describe "embedded results" do + describe 'embedded results' do let(:query) { build_stubbed(:query) } let(:representer) do described_class.new(query, @@ -930,26 +930,26 @@ def non_empty_to_query(hash) results: results_representer) end - context "when results are provided" do + context 'when results are provided' do let(:results_representer) do { - _type: "BogusResultType" + _type: 'BogusResultType' } end - it "embeds the results" do + it 'embeds the results' do expect(subject) - .to be_json_eql("BogusResultType".to_json) - .at_path("_embedded/results/_type") + .to be_json_eql('BogusResultType'.to_json) + .at_path('_embedded/results/_type') end end - context "when no results are provided" do + context 'when no results are provided' do let(:results_representer) { nil } - it "does not embed the results" do + it 'does not embed the results' do expect(subject) - .not_to have_json_path("_embedded/results") + .not_to have_json_path('_embedded/results') end end end diff --git a/spec/lib/api/v3/queries/schemas/blocks_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/blocks_filter_dependency_representer_spec.rb index 87bd0a0e1bdf..b825441b95bf 100644 --- a/spec/lib/api/v3/queries/schemas/blocks_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/blocks_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::BlocksFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::BlocksFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/boolean_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/boolean_filter_dependency_representer_spec.rb index 5295ccc783d8..6dc5d038299f 100644 --- a/spec/lib/api/v3/queries/schemas/boolean_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/boolean_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::BooleanFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -48,27 +48,27 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[1]Boolean" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[1]Boolean' } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -76,14 +76,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -92,7 +92,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -101,7 +101,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/category_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/category_filter_dependency_representer_spec.rb index 9a22e57020a0..c164266535b9 100644 --- a/spec/lib/api/v3/queries/schemas/category_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/category_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::CategoryFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,40 +44,40 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "value" do - let(:path) { "values" } - let(:type) { "[]Category" } + context 'generation' do + context 'properties' do + describe 'value' do + let(:path) { 'values' } + let(:type) { '[]Category' } let(:href) { api_v3_paths.categories_by_project(project.identifier) } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -86,14 +86,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -102,7 +102,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -111,7 +111,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -120,7 +120,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/custom_option_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/custom_option_filter_dependency_representer_spec.rb index f445fa224804..6917a7f9d59f 100644 --- a/spec/lib/api/v3/queries/schemas/custom_option_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/custom_option_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::CustomOptionFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -56,11 +56,11 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]CustomOption" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]CustomOption' } let(:hrefs) do custom_field.custom_options.map do |value| api_v3_paths.custom_option(value.id) @@ -70,30 +70,30 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed value link collection" + it_behaves_like 'filter dependency with allowed value link collection' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed value link collection" + it_behaves_like 'filter dependency with allowed value link collection' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -102,14 +102,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -118,10 +118,10 @@ instance.to_json end - it "busts the cache on a different cache_key" do + it 'busts the cache on a different cache_key' do allow(custom_field) .to receive(:cache_key) - .and_return("something else") + .and_return('something else') expect(instance) .to receive(:to_hash) @@ -129,7 +129,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -138,7 +138,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/date_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/date_filter_dependency_representer_spec.rb index 05c40684933d..76bfa366bab9 100644 --- a/spec/lib/api/v3/queries/schemas/date_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/date_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::DateFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,71 +44,71 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[1]Integer" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[1]Integer' } context "for operator 'Queries::Operators::InLessThan'" do let(:operator) { Queries::Operators::InLessThan } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::InMoreThan'" do let(:operator) { Queries::Operators::InMoreThan } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::In'" do let(:operator) { Queries::Operators::In } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::ThisWeek'" do let(:operator) { Queries::Operators::ThisWeek } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::LessThanAgo'" do let(:operator) { Queries::Operators::LessThanAgo } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::MoreThanAgo'" do let(:operator) { Queries::Operators::MoreThanAgo } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::Ago'" do let(:operator) { Queries::Operators::Ago } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::OnDate'" do let(:operator) { Queries::Operators::OnDate } - let(:type) { "[1]Date" } + let(:type) { '[1]Date' } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::BetweenDate'" do let(:operator) { Queries::Operators::BetweenDate } - let(:type) { "[2]Date" } + let(:type) { '[2]Date' } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -117,14 +117,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -133,7 +133,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -142,7 +142,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/date_time_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/date_time_filter_dependency_representer_spec.rb index 21e539fdf53c..e835c28adb57 100644 --- a/spec/lib/api/v3/queries/schemas/date_time_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/date_time_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::DateTimeFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,60 +44,60 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[1]Integer" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[1]Integer' } context "for operator 'Queries::Operators::LessThanAgo" do let(:operator) { Queries::Operators::LessThanAgo } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::MoreThanAgo'" do let(:operator) { Queries::Operators::MoreThanAgo } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::Ago'" do let(:operator) { Queries::Operators::Ago } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::Today'" do let(:operator) { Queries::Operators::Today } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::ThisWeek'" do let(:operator) { Queries::Operators::ThisWeek } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::OnDate'" do let(:operator) { Queries::Operators::OnDateTime } - let(:type) { "[1]DateTime" } + let(:type) { '[1]DateTime' } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::BetweenDate'" do let(:operator) { Queries::Operators::BetweenDateTime } - let(:type) { "[2]DateTime" } + let(:type) { '[2]DateTime' } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -106,14 +106,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -122,7 +122,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -131,7 +131,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/duplicated_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/duplicated_filter_dependency_representer_spec.rb index cf097638dda3..f220b21b0764 100644 --- a/spec/lib/api/v3/queries/schemas/duplicated_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/duplicated_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::DuplicatedFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::DuplicatedFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/duplicates_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/duplicates_filter_dependency_representer_spec.rb index b74b1b02444d..8d7e3f479501 100644 --- a/spec/lib/api/v3/queries/schemas/duplicates_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/duplicates_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::DuplicatesFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::DuplicatesFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/filter_dependency_representer_factory_spec.rb b/spec/lib/api/v3/queries/schemas/filter_dependency_representer_factory_spec.rb index d2988c54fb07..6a8d83d5ba55 100644 --- a/spec/lib/api/v3/queries/schemas/filter_dependency_representer_factory_spec.rb +++ b/spec/lib/api/v3/queries/schemas/filter_dependency_representer_factory_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::FilterDependencyRepresenterFactory do include API::V3::Utilities::PathHelper @@ -34,284 +34,284 @@ let(:operator) { Queries::Operators::Equals } let(:form_embedded) { true } - describe ".create" do + describe '.create' do subject { described_class.create(filter, operator, form_embedded:) } - context "assigned to filter" do + context 'assigned to filter' do let(:filter) { Queries::WorkPackages::Filter::AssignedToFilter.create! } - it "is a all principals with access to project dependency" do + it 'is a all principals with access to project dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::ProjectMembersFilterDependencyRepresenter) end end - context "shared with user filter" do + context 'shared with user filter' do let(:filter) { Queries::WorkPackages::Filter::SharedWithUserFilter.create! } - it "is a all principals with access to project dependency" do + it 'is a all principals with access to project dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::AccessToProjectFilterDependencyRepresenter) end end - context "responsible filter" do + context 'responsible filter' do let(:filter) { Queries::WorkPackages::Filter::ResponsibleFilter.create! } - it "is a project members dependency" do + it 'is a project members dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::ProjectMembersFilterDependencyRepresenter) end end - context "author filter" do + context 'author filter' do let(:filter) { Queries::WorkPackages::Filter::AuthorFilter.create! } - it "is the user dependency" do + it 'is the user dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::UserFilterDependencyRepresenter) end end - context "category filter" do + context 'category filter' do let(:filter) { Queries::WorkPackages::Filter::CategoryFilter.create! } - it "is the category dependency" do + it 'is the category dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::CategoryFilterDependencyRepresenter) end end - context "created_at filter" do + context 'created_at filter' do let(:filter) { Queries::WorkPackages::Filter::CreatedAtFilter.create! } - it "is the date dependency" do + it 'is the date dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::DateTimeFilterDependencyRepresenter) end end - context "custom_field filters" do + context 'custom_field filters' do let(:filter) do Queries::WorkPackages::Filter::CustomFieldFilter.from_custom_field! custom_field: end - shared_examples_for "includes the cf json_cache_key mixin" do + shared_examples_for 'includes the cf json_cache_key mixin' do it do expect(subject.singleton_class.included_modules) .to include(API::V3::Queries::Schemas::CustomFieldJsonCacheKeyMixin) end end - context "type int" do + context 'type int' do let(:custom_field) { build_stubbed(:integer_wp_custom_field) } - it "is the integer dependency" do + it 'is the integer dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::IntegerFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type float" do + context 'type float' do let(:custom_field) { build_stubbed(:float_wp_custom_field) } - it "is the float dependency" do + it 'is the float dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::FloatFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type text" do + context 'type text' do let(:custom_field) { build_stubbed(:text_wp_custom_field) } - it "is the text dependency" do + it 'is the text dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::TextFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type list" do + context 'type list' do let(:custom_field) { build_stubbed(:list_wp_custom_field) } - it "is the custom option dependency" do + it 'is the custom option dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::CustomOptionFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type user" do + context 'type user' do let(:custom_field) { build_stubbed(:user_wp_custom_field) } - it "is the user dependency" do + it 'is the user dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::UserFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type version" do + context 'type version' do let(:custom_field) { build_stubbed(:version_wp_custom_field) } - it "is the version dependency" do + it 'is the version dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::VersionFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type date" do + context 'type date' do let(:custom_field) { build_stubbed(:date_wp_custom_field) } - it "is the date dependency" do + it 'is the date dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::DateFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type bool" do + context 'type bool' do let(:custom_field) { build_stubbed(:boolean_wp_custom_field) } - it "is the boolean filter dependency" do + it 'is the boolean filter dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::BooleanFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end - context "type string" do + context 'type string' do let(:custom_field) { build_stubbed(:string_wp_custom_field) } - it "is the text dependency" do + it 'is the text dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::TextFilterDependencyRepresenter) end - it_behaves_like "includes the cf json_cache_key mixin" + it_behaves_like 'includes the cf json_cache_key mixin' end end - context "done_ratio filter" do + context 'done_ratio filter' do let(:filter) { Queries::WorkPackages::Filter::DoneRatioFilter.create! } - it "is the integer dependency" do + it 'is the integer dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::IntegerFilterDependencyRepresenter) end end - context "due_date filter" do + context 'due_date filter' do let(:filter) { Queries::WorkPackages::Filter::DueDateFilter.create! } - it "is the date dependency" do + it 'is the date dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::DateFilterDependencyRepresenter) end end - context "estimated_hours filter" do + context 'estimated_hours filter' do let(:filter) { Queries::WorkPackages::Filter::EstimatedHoursFilter.create! } - it "is the integer dependency" do + it 'is the integer dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::IntegerFilterDependencyRepresenter) end end - context "group filter" do + context 'group filter' do let(:filter) { Queries::WorkPackages::Filter::GroupFilter.create! } - it "is the group dependency" do + it 'is the group dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::GroupFilterDependencyRepresenter) end end - context "id filter" do + context 'id filter' do let(:filter) { Queries::WorkPackages::Filter::IdFilter.create! } - it "is the id dependency" do + it 'is the id dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::IdFilterDependencyRepresenter) end end - context "prioritiy filter" do + context 'prioritiy filter' do let(:filter) { Queries::WorkPackages::Filter::PriorityFilter.create! } - it "is the priority dependency" do + it 'is the priority dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::PriorityFilterDependencyRepresenter) end end - context "project filter" do + context 'project filter' do let(:filter) { Queries::WorkPackages::Filter::ProjectFilter.create! } - it "is the project dependency" do + it 'is the project dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::ProjectFilterDependencyRepresenter) end end - context "role filter" do + context 'role filter' do let(:filter) { Queries::WorkPackages::Filter::RoleFilter.create! } - it "is the role dependency" do + it 'is the role dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::RoleFilterDependencyRepresenter) end end - context "start_date filter" do + context 'start_date filter' do let(:filter) { Queries::WorkPackages::Filter::StartDateFilter.create! } - it "is the date dependency" do + it 'is the date dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::DateFilterDependencyRepresenter) end end - context "subject filter" do + context 'subject filter' do let(:filter) { Queries::WorkPackages::Filter::SubjectFilter.create! } - it "is the subject dependency" do + it 'is the subject dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::TextFilterDependencyRepresenter) end end - context "status filter" do + context 'status filter' do let(:filter) { Queries::WorkPackages::Filter::StatusFilter.create! } - it "is a status dependency" do + it 'is a status dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::StatusFilterDependencyRepresenter) end end - context "subproject filter" do + context 'subproject filter' do let(:filter) { Queries::WorkPackages::Filter::SubprojectFilter.create! } - it "is a subproject dependency" do + it 'is a subproject dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::SubprojectFilterDependencyRepresenter) end end - context "type filter" do + context 'type filter' do let(:filter) { Queries::WorkPackages::Filter::TypeFilter.create! } - it "is a type dependency" do + it 'is a type dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::TypeFilterDependencyRepresenter) end end - context "updated_at filter" do + context 'updated_at filter' do let(:filter) { Queries::WorkPackages::Filter::UpdatedAtFilter.create! } - it "is a type dependency" do + it 'is a type dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::DateTimeFilterDependencyRepresenter) end end - context "version filter" do + context 'version filter' do let(:filter) { Queries::WorkPackages::Filter::VersionFilter.create! } - it "is a version dependency" do + it 'is a version dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::VersionFilterDependencyRepresenter) end end - context "watcher filter" do + context 'watcher filter' do let(:filter) { Queries::WorkPackages::Filter::WatcherFilter.create! } - it "is a type dependency" do + it 'is a type dependency' do expect(subject).to be_a(API::V3::Queries::Schemas::UserFilterDependencyRepresenter) end end diff --git a/spec/lib/api/v3/queries/schemas/float_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/float_filter_dependency_representer_spec.rb index 3f42fa9b18c2..7edf481c4da9 100644 --- a/spec/lib/api/v3/queries/schemas/float_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/float_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::FloatFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -48,51 +48,51 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[1]Float" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[1]Float' } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::GreaterOrEqual'" do let(:operator) { Queries::Operators::GreaterOrEqual } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::LessOrEqual'" do let(:operator) { Queries::Operators::LessOrEqual } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -101,14 +101,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -117,7 +117,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -126,7 +126,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/follows_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/follows_filter_dependency_representer_spec.rb index 5327932369e1..720c24fa9bcf 100644 --- a/spec/lib/api/v3/queries/schemas/follows_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/follows_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::FollowsFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::FollowsFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/group_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/group_filter_dependency_representer_spec.rb index 7dd4c31689c2..7af11e7d00b7 100644 --- a/spec/lib/api/v3/queries/schemas/group_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/group_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::GroupFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,11 +44,11 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]User" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]User' } let(:href) do "#{api_v3_paths.principals}?filters=#{CGI.escape(JSON.dump(filter_query))}&pageSize=-1" end @@ -56,57 +56,57 @@ context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end - context "within a project" do + context 'within a project' do let(:filter_query) do - [{ type: { operator: "=", values: ["Group"] } }, - { member: { operator: "=", values: [project.id.to_s] } }] + [{ type: { operator: '=', values: ['Group'] } }, + { member: { operator: '=', values: [project.id.to_s] } }] end context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end - context "global" do + context 'global' do let(:project) { nil } let(:filter_query) do - [{ type: { operator: "=", values: ["Group"] } }, - { member: { operator: "*", values: [] } }] + [{ type: { operator: '=', values: ['Group'] } }, + { member: { operator: '*', values: [] } }] end context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -115,14 +115,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -131,7 +131,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -140,7 +140,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -149,7 +149,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/id_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/id_filter_dependency_representer_spec.rb index d81d3b697e5b..10a1fef20534 100644 --- a/spec/lib/api/v3/queries/schemas/id_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/id_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::IdFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,49 +44,49 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - context "within project" do - let(:path) { "values" } - let(:type) { "[]WorkPackage" } + context 'generation' do + context 'properties' do + describe 'values' do + context 'within project' do + let(:path) { 'values' } + let(:type) { '[]WorkPackage' } let(:href) { api_v3_paths.work_packages_by_project(project.id) } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - let(:path) { "values" } - let(:type) { "[]WorkPackage" } + let(:path) { 'values' } + let(:type) { '[]WorkPackage' } let(:href) { api_v3_paths.work_packages } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -95,14 +95,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -111,7 +111,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -120,7 +120,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -129,7 +129,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/includes_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/includes_filter_dependency_representer_spec.rb index 72285207b7e7..6ceec260253d 100644 --- a/spec/lib/api/v3/queries/schemas/includes_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/includes_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::IncludesFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::IncludesFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/integer_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/integer_filter_dependency_representer_spec.rb index 84e5150f4098..1e29748e9789 100644 --- a/spec/lib/api/v3/queries/schemas/integer_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/integer_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::IntegerFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,51 +44,51 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[1]Integer" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[1]Integer' } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::GreaterOrEqual'" do let(:operator) { Queries::Operators::GreaterOrEqual } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::LessOrEqual'" do let(:operator) { Queries::Operators::LessOrEqual } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -96,14 +96,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -112,7 +112,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -121,7 +121,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb index 4f0ac1f506c6..4f33f22c68cc 100644 --- a/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/parent_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::ParentFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::ParentFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/partof_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/partof_filter_dependency_representer_spec.rb index c91763412775..c049852d4987 100644 --- a/spec/lib/api/v3/queries/schemas/partof_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/partof_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::PartofFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::PartofFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/precedes_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/precedes_filter_dependency_representer_spec.rb index abf61587aaa4..f4d32532b847 100644 --- a/spec/lib/api/v3/queries/schemas/precedes_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/precedes_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::PrecedesFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::PrecedesFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/priority_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/priority_filter_dependency_representer_spec.rb index ba8a23cfec08..86c19ff5ef4d 100644 --- a/spec/lib/api/v3/queries/schemas/priority_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/priority_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::PriorityFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,28 +44,28 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]Priority" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]Priority' } let(:href) { api_v3_paths.priorities } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -73,14 +73,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -89,7 +89,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -98,7 +98,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb index c3f689d1d2cf..731c656a2067 100644 --- a/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/project_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::ProjectFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -42,10 +42,10 @@ subject(:generated) { instance.to_json } - context "with generation" do - context "for properties" do - let(:path) { "values" } - let(:type) { "[]Project" } + context 'with generation' do + context 'for properties' do + let(:path) { 'values' } + let(:type) { '[]Project' } let(:filters) do "?filters=%5B%7B%22active%22%3A%7B%22operator%22%3A%22%3D%22%2C%22values%22%3A%5B%22t%22%5D%7D%7D%5D&pageSize=-1" end @@ -54,29 +54,29 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -84,7 +84,7 @@ instance.to_json end - it "is cached" do + it 'is cached' do allow(instance) .to receive(:to_hash) @@ -94,7 +94,7 @@ .not_to have_received(:to_hash) end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) allow(instance) @@ -106,7 +106,7 @@ .to have_received(:to_hash) end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do allow(instance) .to receive(:to_hash) @@ -118,7 +118,7 @@ .to have_received(:to_hash) end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) @@ -131,7 +131,7 @@ .to have_received(:to_hash) end - it "busts the cache on different OpenProject::VERSION.product_version" do + it 'busts the cache on different OpenProject::VERSION.product_version' do allow(OpenProject::VERSION) .to receive(:instance_variable_get) .with(:@product_sha) @@ -146,10 +146,10 @@ .to have_received(:to_hash) end - it "busts the cache on different OpenProject::VERSION::ARRAY" do + it 'busts the cache on different OpenProject::VERSION::ARRAY' do new_version = OpenProject::VERSION::ARRAY new_version[2] = -1 - stub_const("OpenProject::VERSION::ARRAY", new_version) + stub_const('OpenProject::VERSION::ARRAY', new_version) allow(instance) .to receive(:to_hash) diff --git a/spec/lib/api/v3/queries/schemas/project_members_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/project_members_filter_dependency_representer_spec.rb index 3d74e61aa6dc..54067194243a 100644 --- a/spec/lib/api/v3/queries/schemas/project_members_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/project_members_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::ProjectMembersFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,11 +44,11 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]User" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]User' } let(:href) do "#{api_v3_paths.principals}?filters=#{CGI.escape(JSON.dump(filter_query))}&pageSize=-1" end @@ -56,57 +56,57 @@ context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end - context "within a project" do + context 'within a project' do let(:filter_query) do - [{ status: { operator: "!", values: ["3"] } }, - { member: { operator: "=", values: [project.id.to_s] } }] + [{ status: { operator: '!', values: ['3'] } }, + { member: { operator: '=', values: [project.id.to_s] } }] end context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end - context "global" do + context 'global' do let(:project) { nil } let(:filter_query) do - [{ status: { operator: "!", values: ["3"] } }, - { member: { operator: "*", values: [] } }] + [{ status: { operator: '!', values: ['3'] } }, + { member: { operator: '*', values: [] } }] end context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -115,14 +115,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::All) expect(instance) @@ -131,7 +131,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -140,7 +140,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -149,7 +149,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/query_filter_instance_schema_representer_spec.rb b/spec/lib/api/v3/queries/schemas/query_filter_instance_schema_representer_spec.rb index 7a1ff384ed62..ebd7178f6ac1 100644 --- a/spec/lib/api/v3/queries/schemas/query_filter_instance_schema_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/query_filter_instance_schema_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::QueryFilterInstanceSchemaRepresenter do include API::V3::Utilities::PathHelper @@ -51,19 +51,19 @@ form_embedded:) end let(:form_embedded) { false } - let(:self_link) { "bogus_self_path" } + let(:self_link) { 'bogus_self_path' } let(:project) { nil } let(:user) { build_stubbed(:user) } let(:json_cacheable) { true } - let(:json_cache_key) { "some key" } + let(:json_cache_key) { 'some key' } let(:dependency) do - double("dependency", - to_hash: { lorem: "ipsum" }, + double('dependency', + to_hash: { lorem: 'ipsum' }, json_cacheable?: json_cacheable, json_cache_key:) end - context "generation" do + context 'generation' do before do filter.available_operators.each do |operator| allow(API::V3::Queries::Schemas::FilterDependencyRepresenterFactory) @@ -77,138 +77,138 @@ subject(:generated) { instance.to_json } - context "_links" do - describe "self" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context '_links' do + describe 'self' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end end end - context "properties" do - describe "_type" do - it "QueryFilterInstanceSchema" do + context 'properties' do + describe '_type' do + it 'QueryFilterInstanceSchema' do expect(subject) - .to be_json_eql("QueryFilterInstanceSchema".to_json) - .at_path("_type") + .to be_json_eql('QueryFilterInstanceSchema'.to_json) + .at_path('_type') end end - describe "name" do - let(:path) { "name" } + describe 'name' do + let(:path) { 'name' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { "Name" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { 'Name' } let(:required) { true } let(:writable) { false } let(:has_default) { true } end end - describe "filter" do - let(:path) { "filter" } + describe 'filter' do + let(:path) { 'filter' } - it_behaves_like "has basic schema properties" do - let(:type) { "QueryFilter" } - let(:name) { Query.human_attribute_name("filter") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'QueryFilter' } + let(:name) { Query.human_attribute_name('filter') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "links to and embeds allowed values directly" do - let(:hrefs) { [api_v3_paths.query_filter("status")] } + it_behaves_like 'links to and embeds allowed values directly' do + let(:hrefs) { [api_v3_paths.query_filter('status')] } end - context "with a custom field filter" do + context 'with a custom field filter' do let(:filter) { custom_field_filter } - it_behaves_like "links to and embeds allowed values directly" do + it_behaves_like 'links to and embeds allowed values directly' do let(:hrefs) { [api_v3_paths.query_filter(custom_field.attribute_name(:camel_case))] } end end end end - describe "operator" do - let(:path) { "operator" } + describe 'operator' do + let(:path) { 'operator' } - it_behaves_like "has basic schema properties" do - let(:type) { "QueryOperator" } - let(:name) { Query.human_attribute_name("operator") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'QueryOperator' } + let(:name) { Query.human_attribute_name('operator') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "links to and embeds allowed values directly" do + it_behaves_like 'links to and embeds allowed values directly' do let(:hrefs) do - [api_v3_paths.query_operator(CGI.escape("o")), - api_v3_paths.query_operator(CGI.escape("=")), - api_v3_paths.query_operator(CGI.escape("c")), - api_v3_paths.query_operator(CGI.escape("!")), - api_v3_paths.query_operator(CGI.escape("*"))] + [api_v3_paths.query_operator(CGI.escape('o')), + api_v3_paths.query_operator(CGI.escape('=')), + api_v3_paths.query_operator(CGI.escape('c')), + api_v3_paths.query_operator(CGI.escape('!')), + api_v3_paths.query_operator(CGI.escape('*'))] end end end end - describe "_dependencies/0 (we only have one)" do - describe "_type" do - it "is SchemaDependency" do + describe '_dependencies/0 (we only have one)' do + describe '_type' do + it 'is SchemaDependency' do expect(subject) - .to be_json_eql("SchemaDependency".to_json) - .at_path("_dependencies/0/_type") + .to be_json_eql('SchemaDependency'.to_json) + .at_path('_dependencies/0/_type') end end - describe "on" do + describe 'on' do it 'is "operator"' do expect(subject) - .to be_json_eql("operator".to_json) - .at_path("_dependencies/0/on") + .to be_json_eql('operator'.to_json) + .at_path('_dependencies/0/on') end end - describe "dependencies" do - it "is the hash" do + describe 'dependencies' do + it 'is the hash' do expected = { - api_v3_paths.query_operator(CGI.escape("=")) => { lorem: "ipsum" }, - api_v3_paths.query_operator(CGI.escape("c")) => { lorem: "ipsum" }, - api_v3_paths.query_operator(CGI.escape("!")) => { lorem: "ipsum" }, - api_v3_paths.query_operator(CGI.escape("*")) => { lorem: "ipsum" }, - api_v3_paths.query_operator(CGI.escape("o")) => { lorem: "ipsum" } + api_v3_paths.query_operator(CGI.escape('=')) => { lorem: "ipsum" }, + api_v3_paths.query_operator(CGI.escape('c')) => { lorem: "ipsum" }, + api_v3_paths.query_operator(CGI.escape('!')) => { lorem: "ipsum" }, + api_v3_paths.query_operator(CGI.escape('*')) => { lorem: "ipsum" }, + api_v3_paths.query_operator(CGI.escape('o')) => { lorem: "ipsum" } } expect(subject) .to be_json_eql(expected.to_json) - .at_path("_dependencies/0/dependencies") + .at_path('_dependencies/0/dependencies') end - context "when filter is a list filter" do + context 'when filter is a list filter' do let(:filter) { Queries::WorkPackages::Filter::AuthorFilter.create! } - it "is the hash" do + it 'is the hash' do expected = { - api_v3_paths.query_operator(CGI.escape("=")) => { lorem: "ipsum" }, - api_v3_paths.query_operator(CGI.escape("!")) => { lorem: "ipsum" } + api_v3_paths.query_operator(CGI.escape('=')) => { lorem: "ipsum" }, + api_v3_paths.query_operator(CGI.escape('!')) => { lorem: "ipsum" } } expect(subject) .to be_json_eql(expected.to_json) - .at_path("_dependencies/0/dependencies") + .at_path('_dependencies/0/dependencies') end end end @@ -216,7 +216,7 @@ end end - describe "caching" do + describe 'caching' do before do filter.available_operators.each do |operator| allow(API::V3::Queries::Schemas::FilterDependencyRepresenterFactory) @@ -229,17 +229,17 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - context "with an uncacheable dependency" do + context 'with an uncacheable dependency' do let(:json_cacheable) { false } - it "is not cached" do + it 'is not cached' do expect(instance) .to receive(:to_hash) @@ -247,7 +247,7 @@ end end - it "busts the cache on the form_embedded attribute" do + it 'busts the cache on the form_embedded attribute' do instance.form_embedded = !form_embedded expect(instance) @@ -256,10 +256,10 @@ instance.to_json end - it "busts the cache on a different cache key from a dependency" do + it 'busts the cache on a different cache key from a dependency' do allow(dependency) .to receive(:json_cache_key) - .and_return(["and", "now", "to", "something", "completely", "different"]) + .and_return(['and', 'now', 'to', 'something', 'completely', 'different']) expect(instance) .to receive(:to_hash) @@ -267,7 +267,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) diff --git a/spec/lib/api/v3/queries/schemas/query_schema_representer_spec.rb b/spec/lib/api/v3/queries/schemas/query_schema_representer_spec.rb index 1e574c4f860e..68dae0b4adb3 100644 --- a/spec/lib/api/v3/queries/schemas/query_schema_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/query_schema_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::QuerySchemaRepresenter do include API::V3::Utilities::PathHelper @@ -51,7 +51,7 @@ end let(:form_embedded) { false } - let(:self_link) { "bogus_self_path" } + let(:self_link) { 'bogus_self_path' } let(:project) { nil } let(:instance) { described_class.new(query, self_link:, current_user: user, form_embedded:) } @@ -63,141 +63,141 @@ subject(:generated) { instance.to_json } - shared_examples_for "has a collection of allowed values" do + shared_examples_for 'has a collection of allowed values' do before do allow(query).to receive(available_values_method).and_return(available_values) end - context "when no values are allowed" do + context 'when no values are allowed' do let(:available_values) do [] end - it_behaves_like "links to and embeds allowed values directly" do + it_behaves_like 'links to and embeds allowed values directly' do let(:hrefs) { [] } end end - context "when values are allowed" do - it_behaves_like "links to and embeds allowed values directly" do + context 'when values are allowed' do + it_behaves_like 'links to and embeds allowed values directly' do let(:hrefs) { expected_hrefs } end end end - context "generation" do - context "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context 'generation' do + context '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end end - context "attributes" do - describe "_type" do - it "is Schema" do + context 'attributes' do + describe '_type' do + it 'is Schema' do expect(subject) - .to be_json_eql("Schema".to_json) - .at_path("_type") + .to be_json_eql('Schema'.to_json) + .at_path('_type') end end - describe "id" do - let(:path) { "id" } + describe 'id' do + let(:path) { 'id' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } - let(:name) { Query.human_attribute_name("id") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } + let(:name) { Query.human_attribute_name('id') } let(:required) { true } let(:writable) { false } end end - describe "name" do - let(:path) { "name" } + describe 'name' do + let(:path) { 'name' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Query.human_attribute_name("name") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Query.human_attribute_name('name') } let(:required) { true } let(:writable) { true } end - it_behaves_like "indicates length requirements" do + it_behaves_like 'indicates length requirements' do let(:min_length) { 1 } let(:max_length) { 255 } end end - describe "createdAt" do - let(:path) { "createdAt" } + describe 'createdAt' do + let(:path) { 'createdAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Query.human_attribute_name("created_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Query.human_attribute_name('created_at') } let(:required) { true } let(:writable) { false } end end - describe "updatedAt" do - let(:path) { "updatedAt" } + describe 'updatedAt' do + let(:path) { 'updatedAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Query.human_attribute_name("updated_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Query.human_attribute_name('updated_at') } let(:required) { true } let(:writable) { false } end end - describe "user" do - let(:path) { "user" } + describe 'user' do + let(:path) { 'user' } - it_behaves_like "has basic schema properties" do - let(:type) { "User" } - let(:name) { Query.human_attribute_name("user") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'User' } + let(:name) { Query.human_attribute_name('user') } let(:required) { true } let(:writable) { false } let(:has_default) { true } - let(:location) { "_links" } + let(:location) { '_links' } end end - describe "project" do - let(:path) { "project" } + describe 'project' do + let(:path) { 'project' } - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Query.human_attribute_name("project") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Query.human_attribute_name('project') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) { api_v3_paths.query_available_projects } end end end - describe "public" do - let(:path) { "public" } + describe 'public' do + let(:path) { 'public' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { Query.human_attribute_name("public") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { Query.human_attribute_name('public') } let(:required) { false } let(:writable) { false } let(:has_default) { true } end - context "when having the :manage_public_queries permission" do + context 'when having the :manage_public_queries permission' do let(:other_project) { build_stubbed(:project) } before do @@ -207,149 +207,149 @@ end end - it "marks public as writable" do + it 'marks public as writable' do expect(subject) .to be_json_eql(true) - .at_path("public/writable") + .at_path('public/writable') end end end - describe "hidden" do - let(:path) { "hidden" } + describe 'hidden' do + let(:path) { 'hidden' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { Query.human_attribute_name("hidden") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { Query.human_attribute_name('hidden') } let(:required) { true } let(:writable) { true } let(:has_default) { true } end end - describe "sums" do - let(:path) { "sums" } + describe 'sums' do + let(:path) { 'sums' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { Query.human_attribute_name("sums") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { Query.human_attribute_name('sums') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "timelineVisible" do - let(:path) { "timelineVisible" } + describe 'timelineVisible' do + let(:path) { 'timelineVisible' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { Query.human_attribute_name("timeline_visible") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { Query.human_attribute_name('timeline_visible') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "timelineZoomLevel" do - let(:path) { "timelineZoomLevel" } + describe 'timelineZoomLevel' do + let(:path) { 'timelineZoomLevel' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Query.human_attribute_name("timeline_zoom_level") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Query.human_attribute_name('timeline_zoom_level') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "timelineLabels" do - let(:path) { "timelineLabels" } + describe 'timelineLabels' do + let(:path) { 'timelineLabels' } - it_behaves_like "has basic schema properties" do - let(:type) { "QueryTimelineLabels" } - let(:name) { Query.human_attribute_name("timeline_labels") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'QueryTimelineLabels' } + let(:name) { Query.human_attribute_name('timeline_labels') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "timestamps" do - let(:path) { "timestamps" } + describe 'timestamps' do + let(:path) { 'timestamps' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]Timestamp" } - let(:name) { Query.human_attribute_name("timestamps") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]Timestamp' } + let(:name) { Query.human_attribute_name('timestamps') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "show hierarchies" do - let(:path) { "showHierarchies" } + describe 'show hierarchies' do + let(:path) { 'showHierarchies' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { Query.human_attribute_name("show_hierarchies") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { Query.human_attribute_name('show_hierarchies') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "starred" do - let(:path) { "starred" } + describe 'starred' do + let(:path) { 'starred' } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } - let(:name) { Query.human_attribute_name("starred") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } + let(:name) { Query.human_attribute_name('starred') } let(:required) { false } let(:writable) { false } let(:has_default) { true } end end - describe "highlighting_mode" do - let(:path) { "highlightingMode" } + describe 'highlighting_mode' do + let(:path) { 'highlightingMode' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Query.human_attribute_name("highlighting_mode") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Query.human_attribute_name('highlighting_mode') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "display_representation" do - let(:path) { "displayRepresentation" } + describe 'display_representation' do + let(:path) { 'displayRepresentation' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Query.human_attribute_name("display_representation") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Query.human_attribute_name('display_representation') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end end - describe "columns" do - let(:path) { "columns" } + describe 'columns' do + let(:path) { 'columns' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]QueryColumn" } - let(:name) { Query.human_attribute_name("columns") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]QueryColumn' } + let(:name) { Query.human_attribute_name('columns') } let(:required) { false } let(:writable) { true } let(:has_default) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } let(:type) { build_stubbed(:type) } let(:available_values) do @@ -365,19 +365,19 @@ end let(:available_values_method) { :displayable_columns } - it_behaves_like "has a collection of allowed values" do + it_behaves_like 'has a collection of allowed values' do let(:expected_hrefs) do available_values.map do |value| api_v3_paths.query_column(value.name.to_s.camelcase(:lower)) end end - it "has available columns of both types" do + it 'has available columns of both types' do types = JSON.parse(generated) - .dig("columns", - "_embedded", - "allowedValues") - .map { |v| v["_type"] } + .dig('columns', + '_embedded', + 'allowedValues') + .map { |v| v['_type'] } .uniq expect(types).to match_array(%w(QueryColumn::Property QueryColumn::RelationToType QueryColumn::RelationOfType)) @@ -386,21 +386,21 @@ end end - describe "show highlighted_attributes" do - let(:path) { "highlightedAttributes" } + describe 'show highlighted_attributes' do + let(:path) { 'highlightedAttributes' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]QueryColumn" } - let(:name) { Query.human_attribute_name("highlighted_attributes") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]QueryColumn' } + let(:name) { Query.human_attribute_name('highlighted_attributes') } let(:required) { false } let(:writable) { true } let(:has_default) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } let(:type) { build_stubbed(:type) } let(:available_values) do @@ -409,7 +409,7 @@ end let(:available_values_method) { :displayable_columns } - it_behaves_like "has a collection of allowed values" do + it_behaves_like 'has a collection of allowed values' do let(:expected_hrefs) do available_values.map do |value| api_v3_paths.query_column(value.name.to_s.camelcase(:lower)) @@ -419,34 +419,34 @@ end end - describe "filters" do - let(:path) { "filters" } + describe 'filters' do + let(:path) { 'filters' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]QueryFilterInstance" } - let(:name) { Query.human_attribute_name("filters") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]QueryFilterInstance' } + let(:name) { Query.human_attribute_name('filters') } let(:required) { false } let(:writable) { true } let(:has_default) { true } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when global query" do + context 'when global query' do let(:href) { api_v3_paths.query_filter_instance_schemas } - it "contains the link to the filter schemas" do + it 'contains the link to the filter schemas' do expect(subject) .to be_json_eql(href.to_json) .at_path("#{path}/_links/allowedValuesSchemas/href") end end - context "when project query" do + context 'when project query' do let(:project) { build_stubbed(:project) } let(:href) { api_v3_paths.query_project_filter_instance_schemas(project.id) } - it "contains the link to the filter schemas" do + it 'contains the link to the filter schemas' do expect(subject) .to be_json_eql(href.to_json) .at_path("#{path}/_links/allowedValuesSchemas/href") @@ -454,23 +454,23 @@ end end - describe "groupBy" do - let(:path) { "groupBy" } + describe 'groupBy' do + let(:path) { 'groupBy' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]QueryGroupBy" } - let(:name) { Query.human_attribute_name("group_by") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]QueryGroupBy' } + let(:name) { Query.human_attribute_name('group_by') } let(:required) { false } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "has a collection of allowed values" do + it_behaves_like 'has a collection of allowed values' do let(:available_values) do [Queries::WorkPackages::Selects::PropertySelect.new(:bogus1), Queries::WorkPackages::Selects::PropertySelect.new(:bogus2), @@ -486,24 +486,24 @@ end end - describe "sortBy" do - let(:path) { "sortBy" } + describe 'sortBy' do + let(:path) { 'sortBy' } - it_behaves_like "has basic schema properties" do - let(:type) { "[]QuerySortBy" } - let(:name) { Query.human_attribute_name("sort_by") } + it_behaves_like 'has basic schema properties' do + let(:type) { '[]QuerySortBy' } + let(:name) { Query.human_attribute_name('sort_by') } let(:required) { false } let(:writable) { true } let(:has_default) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "has a collection of allowed values" do + it_behaves_like 'has a collection of allowed values' do before do allow(Query) .to receive(:sortable_columns) @@ -519,8 +519,8 @@ let(:expected_hrefs) do expected = available_values.map do |value| - [api_v3_paths.query_sort_by(value.name, "asc"), - api_v3_paths.query_sort_by(value.name, "desc")] + [api_v3_paths.query_sort_by(value.name, 'asc'), + api_v3_paths.query_sort_by(value.name, 'desc')] end expected.flatten @@ -529,37 +529,37 @@ end end - describe "results" do - let(:path) { "results" } + describe 'results' do + let(:path) { 'results' } - it_behaves_like "has basic schema properties" do - let(:type) { "WorkPackageCollection" } - let(:name) { Query.human_attribute_name("results") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'WorkPackageCollection' } + let(:name) { Query.human_attribute_name('results') } let(:required) { false } let(:writable) { false } end end end - context "_embedded" do - describe "filtersSchemas" do - let(:path) { "_embedded/filtersSchemas" } + context '_embedded' do + describe 'filtersSchemas' do + let(:path) { '_embedded/filtersSchemas' } - context "when global query" do + context 'when global query' do let(:href) { api_v3_paths.query_filter_instance_schemas } - it "contains a collection of filter schemas" do + it 'contains a collection of filter schemas' do expect(subject) .to be_json_eql(href.to_json) .at_path("#{path}/_links/self/href") end end - context "when project query" do + context 'when project query' do let(:project) { build_stubbed(:project) } let(:href) { api_v3_paths.query_project_filter_instance_schemas(project.id) } - it "contains a collection of filter schemas" do + it 'contains a collection of filter schemas' do expect(subject) .to be_json_eql(href.to_json) .at_path("#{path}/_links/self/href") diff --git a/spec/lib/api/v3/queries/schemas/relates_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/relates_filter_dependency_representer_spec.rb index 7d3bcb26f665..023f646e8d32 100644 --- a/spec/lib/api/v3/queries/schemas/relates_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/relates_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::RelatesFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::RelatesFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/required_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/required_filter_dependency_representer_spec.rb index 3a473eac6128..9280a44e9f1e 100644 --- a/spec/lib/api/v3/queries/schemas/required_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/required_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::RequiredFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::RequiredFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/requires_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/requires_filter_dependency_representer_spec.rb index 9e08d71afa50..e7d1806892e5 100644 --- a/spec/lib/api/v3/queries/schemas/requires_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/requires_filter_dependency_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' 5 RSpec.describe API::V3::Queries::Schemas::RequiresFilterDependencyRepresenter do - it_behaves_like "relation filter dependency" do + it_behaves_like 'relation filter dependency' do let(:filter) { Queries::WorkPackages::Filter::RequiresFilter.create!(context: query) } end end diff --git a/spec/lib/api/v3/queries/schemas/role_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/role_filter_dependency_representer_spec.rb index 5a001f0b9765..2cc7a8946045 100644 --- a/spec/lib/api/v3/queries/schemas/role_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/role_filter_dependency_representer_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::RoleFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,15 +44,15 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]Role" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]Role' } let(:filters) do [ - allows_becoming_assignee: { operator: "=", values: ["t"] }, - grantable: { operator: "=", values: ["t"] } + allows_becoming_assignee: { operator: '=', values: ['t'] }, + grantable: { operator: '=', values: ['t'] } ] end let(:filter_params) do @@ -63,30 +63,30 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -94,14 +94,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -110,7 +110,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -119,7 +119,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/status_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/status_filter_dependency_representer_spec.rb index a6984d0c4832..a443a06733f9 100644 --- a/spec/lib/api/v3/queries/schemas/status_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/status_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::StatusFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -42,46 +42,46 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]Status" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]Status' } let(:href) { api_v3_paths.statuses } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::OpenWorkPackages'" do let(:operator) { Queries::Operators::OpenWorkPackages } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::ClosedWorkPackages'" do let(:operator) { Queries::Operators::ClosedWorkPackages } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -89,14 +89,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -105,7 +105,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -114,7 +114,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/subproject_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/subproject_filter_dependency_representer_spec.rb index 1bd3bd3d6505..eff518d7c5a0 100644 --- a/spec/lib/api/v3/queries/schemas/subproject_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/subproject_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::SubprojectFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,13 +44,13 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]Project" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]Project' } let(:filters_params) do - [ancestor: { operator: "=", values: [project.id.to_s] }] + [ancestor: { operator: '=', values: [project.id.to_s] }] end let(:href) do "#{api_v3_paths.projects}?filters=#{CGI.escape(JSON.dump(filters_params))}&pageSize=-1" @@ -59,24 +59,24 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -85,14 +85,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -101,7 +101,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -110,7 +110,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -119,7 +119,7 @@ end end - it "does not use the project for caching if no project is provided and as such busts the cache" do + it 'does not use the project for caching if no project is provided and as such busts the cache' do query.project = nil expect(instance) @@ -128,7 +128,7 @@ instance.to_json end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/text_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/text_filter_dependency_representer_spec.rb index a5ea0916ff89..6ec0b01ec2a6 100644 --- a/spec/lib/api/v3/queries/schemas/text_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/text_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::TextFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,39 +44,39 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[1]String" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[1]String' } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::Contains'" do let(:operator) { Queries::Operators::Contains } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end context "for operator 'Queries::Operators::NotContains'" do let(:operator) { Queries::Operators::NotContains } - it_behaves_like "filter dependency" + it_behaves_like 'filter dependency' end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } before do @@ -84,14 +84,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -100,7 +100,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -109,7 +109,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/type_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/type_filter_dependency_representer_spec.rb index 2543632bd7cf..797e7871fcbb 100644 --- a/spec/lib/api/v3/queries/schemas/type_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/type_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::TypeFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,13 +44,13 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]Type" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]Type' } - context "within project" do + context 'within project' do let(:href) do api_v3_paths.types_by_project(project.id) end @@ -58,17 +58,17 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end - context "global" do + context 'global' do let(:project) { nil } let(:href) do api_v3_paths.types @@ -77,19 +77,19 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -98,14 +98,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -114,7 +114,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -123,7 +123,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -132,7 +132,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/user_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/user_filter_dependency_representer_spec.rb index ba9491e98416..101585dd4ec2 100644 --- a/spec/lib/api/v3/queries/schemas/user_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/user_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::UserFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,15 +44,15 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]User" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]User' } let(:filter_query) do - [{ type: { operator: "=", values: %w[User Group PlaceholderUser] } }, - { status: { operator: "!", values: ["3"] } }, - { member: { operator: "=", values: [project.id.to_s] } }] + [{ type: { operator: '=', values: %w[User Group PlaceholderUser] } }, + { status: { operator: '!', values: ['3'] } }, + { member: { operator: '=', values: [project.id.to_s] } }] end let(:href) do "#{api_v3_paths.principals}?filters=#{CGI.escape(JSON.dump(filter_query))}&pageSize=-1" @@ -61,38 +61,38 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end - context "global" do + context 'global' do let(:project) { nil } let(:filter_query) do - [{ type: { operator: "=", values: %w[User Group PlaceholderUser] } }, - { status: { operator: "!", values: ["3"] } }] + [{ type: { operator: '=', values: %w[User Group PlaceholderUser] } }, + { status: { operator: '!', values: ['3'] } }] end context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -101,14 +101,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -117,7 +117,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -126,7 +126,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -135,7 +135,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/schemas/version_filter_dependency_representer_spec.rb b/spec/lib/api/v3/queries/schemas/version_filter_dependency_representer_spec.rb index 23fae6304e9e..cdd841bddf3f 100644 --- a/spec/lib/api/v3/queries/schemas/version_filter_dependency_representer_spec.rb +++ b/spec/lib/api/v3/queries/schemas/version_filter_dependency_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::Schemas::VersionFilterDependencyRepresenter do include API::V3::Utilities::PathHelper @@ -44,26 +44,26 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - let(:path) { "values" } - let(:type) { "[]Version" } + context 'generation' do + context 'properties' do + describe 'values' do + let(:path) { 'values' } + let(:type) { '[]Version' } let(:order) { "sortBy=#{CGI.escape(JSON.dump([%i(semver_name asc)]))}&pageSize=-1" } context "for operator 'Queries::Operators::All'" do let(:operator) { Queries::Operators::All } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end context "for operator 'Queries::Operators::None'" do let(:operator) { Queries::Operators::None } - it_behaves_like "filter dependency empty" + it_behaves_like 'filter dependency empty' end - context "within project" do + context 'within project' do let(:href) do "#{api_v3_paths.versions_by_project(project.id)}?#{order}" end @@ -71,20 +71,20 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end - context "global" do + context 'global' do let(:project) { nil } let(:filter_params) do - [{ sharing: { operator: "=", values: ["system"] } }] + [{ sharing: { operator: '=', values: ['system'] } }] end let(:href) do "#{api_v3_paths.versions}?filters=#{CGI.escape(JSON.dump(filter_params))}&#{order}" @@ -93,19 +93,19 @@ context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -114,14 +114,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -130,7 +130,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -139,7 +139,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -148,7 +148,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/queries/sort_bys/query_sort_by_representer_spec.rb b/spec/lib/api/v3/queries/sort_bys/query_sort_by_representer_spec.rb index 7354c0f2cd7b..75376e8418ae 100644 --- a/spec/lib/api/v3/queries/sort_bys/query_sort_by_representer_spec.rb +++ b/spec/lib/api/v3/queries/sort_bys/query_sort_by_representer_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Queries::SortBys::QuerySortByRepresenter do include API::V3::Utilities::PathHelper - let(:column_name) { "status" } - let(:direction) { "desc" } + let(:column_name) { 'status' } + let(:direction) { 'desc' } let(:column) { Queries::WorkPackages::Selects::PropertySelect.new(column_name) } let(:decorator) { API::V3::Queries::SortBys::SortByDecorator.new(column, direction) } let(:representer) do @@ -42,111 +42,111 @@ subject { representer.to_json } - describe "generation" do - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_sort_by "status", "desc" } - let(:title) { "Status (Descending)" } + describe 'generation' do + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_sort_by 'status', 'desc' } + let(:title) { 'Status (Descending)' } end end - it "has _type QuerySortBy" do + it 'has _type QuerySortBy' do expect(subject) - .to be_json_eql("QuerySortBy".to_json) - .at_path("_type") + .to be_json_eql('QuerySortBy'.to_json) + .at_path('_type') end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("status-desc".to_json) - .at_path("id") + .to be_json_eql('status-desc'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Status (Descending)".to_json) - .at_path("name") + .to be_json_eql('Status (Descending)'.to_json) + .at_path('name') end - it_behaves_like "has a titled link" do - let(:link) { "column" } - let(:href) { api_v3_paths.query_column "status" } - let(:title) { "Status" } + it_behaves_like 'has a titled link' do + let(:link) { 'column' } + let(:href) { api_v3_paths.query_column 'status' } + let(:title) { 'Status' } end - it_behaves_like "has a titled link" do - let(:link) { "direction" } + it_behaves_like 'has a titled link' do + let(:link) { 'direction' } let(:href) { "urn:openproject-org:api:v3:queries:directions:#{direction}" } - let(:title) { "Descending" } + let(:title) { 'Descending' } end - context "when providing an unsupported sort direction" do - let(:direction) { "bogus" } + context 'when providing an unsupported sort direction' do + let(:direction) { 'bogus' } - it "raises error" do + it 'raises error' do expect { subject }.to raise_error(ArgumentError) end end - context "when sorting differently" do - let(:direction) { "asc" } + context 'when sorting differently' do + let(:direction) { 'asc' } - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("status-asc".to_json) - .at_path("id") + .to be_json_eql('status-asc'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Status (Ascending)".to_json) - .at_path("name") + .to be_json_eql('Status (Ascending)'.to_json) + .at_path('name') end end - context "for a translated column" do - let(:column_name) { "assigned_to" } + context 'for a translated column' do + let(:column_name) { 'assigned_to' } - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } - let(:href) { api_v3_paths.query_sort_by "assignee", "desc" } - let(:title) { "Assignee (Descending)" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } + let(:href) { api_v3_paths.query_sort_by 'assignee', 'desc' } + let(:title) { 'Assignee (Descending)' } end end - it "has id attribute" do + it 'has id attribute' do expect(subject) - .to be_json_eql("assignee-desc".to_json) - .at_path("id") + .to be_json_eql('assignee-desc'.to_json) + .at_path('id') end - it "has name attribute" do + it 'has name attribute' do expect(subject) - .to be_json_eql("Assignee (Descending)".to_json) - .at_path("name") + .to be_json_eql('Assignee (Descending)'.to_json) + .at_path('name') end end end - describe "caching" do + describe 'caching' do before do # fill the cache representer.to_json end - it "is cached" do + it 'is cached' do expect(representer) .not_to receive(:to_hash) representer.to_json end - it "busts the cache on changes to the column_caption (cf rename)" do + it 'busts the cache on changes to the column_caption (cf rename)' do allow(decorator) .to receive(:column_caption) - .and_return("blubs") + .and_return('blubs') expect(representer) .to receive(:to_hash) @@ -154,10 +154,10 @@ representer.to_json end - it "busts the cache on a different direction" do + it 'busts the cache on a different direction' do allow(decorator) .to receive(:direction_name) - .and_return("asc") + .and_return('asc') expect(representer) .to receive(:to_hash) @@ -165,7 +165,7 @@ representer.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(representer) .to receive(:to_hash) diff --git a/spec/lib/api/v3/relations/relation_collection_representer_spec.rb b/spec/lib/api/v3/relations/relation_collection_representer_spec.rb index 0c6ef534c7ff..d9b5ddb46838 100644 --- a/spec/lib/api/v3/relations/relation_collection_representer_spec.rb +++ b/spec/lib/api/v3/relations/relation_collection_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Relations::RelationCollectionRepresenter do let(:work_package) do @@ -50,15 +50,15 @@ end def self_link - "a link that is provided" + 'a link that is provided' end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", + it_behaves_like 'unpaginated APIv3 collection', 3, - "a link that is provided", - "Relation" + 'a link that is provided', + 'Relation' end end diff --git a/spec/lib/api/v3/relations/relation_paginated_collection_representer_spec.rb b/spec/lib/api/v3/relations/relation_paginated_collection_representer_spec.rb index cc7788a3715e..e238d9f606da 100644 --- a/spec/lib/api/v3/relations/relation_paginated_collection_representer_spec.rb +++ b/spec/lib/api/v3/relations/relation_paginated_collection_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Relations::RelationPaginatedCollectionRepresenter do let(:work_package) do @@ -66,10 +66,10 @@ let(:page) { 1 } let(:page_size) { 20 } let(:actual_count) { total } - let(:self_base_link) { "api/v3/relations" } - let(:collection_inner_type) { "Relation" } + let(:self_base_link) { 'api/v3/relations' } + let(:collection_inner_type) { 'Relation' } subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection", 3, "relations", "Relation" + it_behaves_like 'offset-paginated APIv3 collection', 3, 'relations', 'Relation' end diff --git a/spec/lib/api/v3/relations/relation_representer_spec.rb b/spec/lib/api/v3/relations/relation_representer_spec.rb index 13f313fefb65..c07b0ad68262 100644 --- a/spec/lib/api/v3/relations/relation_representer_spec.rb +++ b/spec/lib/api/v3/relations/relation_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Relations::RelationRepresenter do let(:user) { build_stubbed(:admin) } @@ -83,13 +83,13 @@ } end - it "serializes the relation correctly" do + it 'serializes the relation correctly' do data = JSON.parse representer.to_json expect(data).to eq result end - it "deserializes the relation correctly" do + it 'deserializes the relation correctly' do rep = API::V3::Relations::RelationRepresenter.new OpenStruct.new, current_user: user rel = rep.from_json result.except(:id).to_json diff --git a/spec/lib/api/v3/repositories/revision_representer_spec.rb b/spec/lib/api/v3/repositories/revision_representer_spec.rb index 772f956034f5..2478305b2736 100644 --- a/spec/lib/api/v3/repositories/revision_representer_spec.rb +++ b/spec/lib/api/v3/repositories/revision_representer_spec.rb @@ -26,75 +26,75 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Repositories::RevisionRepresenter do include API::V3::Utilities::PathHelper - let(:representer) { described_class.new(revision, current_user: double("current_user")) } + let(:representer) { described_class.new(revision, current_user: double('current_user')) } let(:project) { build(:project) } let(:repository) { build(:repository_subversion, project:) } let(:revision) do build(:changeset, id: 42, - revision: "1234", + revision: '1234', repository:, comments: commit_message, - committer: "foo bar ", + committer: 'foo bar ', committed_on: DateTime.now) end - let(:commit_message) { "Some commit message" } + let(:commit_message) { 'Some commit message' } - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - it { is_expected.to be_json_eql("Revision".to_json).at_path("_type") } + it { is_expected.to be_json_eql('Revision'.to_json).at_path('_type') } - describe "revision" do - it { is_expected.to have_json_path("id") } + describe 'revision' do + it { is_expected.to have_json_path('id') } - it_behaves_like "API V3 formattable", "message" do - let(:format) { "plain" } + it_behaves_like 'API V3 formattable', 'message' do + let(:format) { 'plain' } let(:raw) { revision.comments } - let(:html) { "

    " + revision.comments + "

    " } + let(:html) { '

    ' + revision.comments + '

    ' } end - describe "identifier" do - it { is_expected.to have_json_path("identifier") } - it { is_expected.to be_json_eql("1234".to_json).at_path("identifier") } + describe 'identifier' do + it { is_expected.to have_json_path('identifier') } + it { is_expected.to be_json_eql('1234'.to_json).at_path('identifier') } end - describe "formattedIdentifier" do + describe 'formattedIdentifier' do before do - allow(revision).to receive(:format_identifier).and_return("123") + allow(revision).to receive(:format_identifier).and_return('123') end - it { is_expected.to have_json_path("formattedIdentifier") } - it { is_expected.to be_json_eql("123".to_json).at_path("formattedIdentifier") } + it { is_expected.to have_json_path('formattedIdentifier') } + it { is_expected.to be_json_eql('123'.to_json).at_path('formattedIdentifier') } end - describe "createdAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'createdAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { revision.committed_on } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end - describe "authorName" do - it { is_expected.to have_json_path("authorName") } - it { is_expected.to be_json_eql("foo bar ".to_json).at_path("authorName") } + describe 'authorName' do + it { is_expected.to have_json_path('authorName') } + it { is_expected.to be_json_eql('foo bar '.to_json).at_path('authorName') } end end - context "with referencing commit message" do + context 'with referencing commit message' do let(:work_package) { build_stubbed(:work_package, project:) } let(:commit_message) { "Totally references ##{work_package.id}" } let(:html_reference) do id = work_package.id - str = "Totally references " str << "##{id}" @@ -103,42 +103,42 @@ before do allow(User).to receive(:current).and_return(build_stubbed(:admin)) allow(WorkPackage) - .to receive_message_chain("includes.references.find_by") + .to receive_message_chain('includes.references.find_by') .and_return(work_package) end - it_behaves_like "API V3 formattable", "message" do - let(:format) { "plain" } + it_behaves_like 'API V3 formattable', 'message' do + let(:format) { 'plain' } let(:raw) { revision.comments } - let(:html) { "

    " + html_reference + "

    " } + let(:html) { '

    ' + html_reference + '

    ' } end end - describe "author" do - context "with no linked user" do - it_behaves_like "has no link" do - let(:link) { "author" } + describe 'author' do + context 'with no linked user' do + it_behaves_like 'has no link' do + let(:link) { 'author' } end end - context "with linked user as author" do + context 'with linked user as author' do let(:user) { build(:user) } before do allow(revision).to receive(:user).and_return(user) end - it_behaves_like "has a titled link" do - let(:link) { "author" } + it_behaves_like 'has a titled link' do + let(:link) { 'author' } let(:href) { api_v3_paths.user(user.id) } let(:title) { user.name } end end end - describe "showRevision" do - it_behaves_like "has an untitled link" do - let(:link) { "showRevision" } + describe 'showRevision' do + it_behaves_like 'has an untitled link' do + let(:link) { 'showRevision' } let(:href) { api_v3_paths.show_revision(project.identifier, revision.identifier) } end end diff --git a/spec/lib/api/v3/root_representer_spec.rb b/spec/lib/api/v3/root_representer_spec.rb index d389894c1eca..1a52832b825b 100644 --- a/spec/lib/api/v3/root_representer_spec.rb +++ b/spec/lib/api/v3/root_representer_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::RootRepresenter do include API::V3::Utilities::PathHelper let(:user) { build_stubbed(:user) } let(:representer) { described_class.new({}, current_user: user) } - let(:app_title) { "Foo Project" } - let(:version) { "The version is over 9000!" } + let(:app_title) { 'Foo Project' } + let(:version) { 'The version is over 9000!' } let(:permissions) { [:view_members] } before do @@ -43,7 +43,7 @@ end end - context "generation" do + context 'generation' do subject { representer.to_json } before do @@ -51,123 +51,123 @@ allow(OpenProject::VERSION).to receive(:to_semver).and_return version end - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.root } end - it_behaves_like "has an untitled link" do - let(:link) { "configuration" } + it_behaves_like 'has an untitled link' do + let(:link) { 'configuration' } let(:href) { api_v3_paths.configuration } end - describe "memberships" do - context "if having the view_members permission in any project" do + describe 'memberships' do + context 'if having the view_members permission in any project' do let(:permissions) { [:view_members] } - it_behaves_like "has an untitled link" do - let(:link) { "memberships" } + it_behaves_like 'has an untitled link' do + let(:link) { 'memberships' } let(:href) { api_v3_paths.memberships } end end - context "if having the manage_members permission in any project" do + context 'if having the manage_members permission in any project' do let(:permissions) { [:manage_members] } - it_behaves_like "has an untitled link" do - let(:link) { "memberships" } + it_behaves_like 'has an untitled link' do + let(:link) { 'memberships' } let(:href) { api_v3_paths.memberships } end end - context "if lacking permissions" do + context 'if lacking permissions' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "members" } + it_behaves_like 'has no link' do + let(:link) { 'members' } end end end - it_behaves_like "has an untitled link" do - let(:link) { "priorities" } + it_behaves_like 'has an untitled link' do + let(:link) { 'priorities' } let(:href) { api_v3_paths.priorities } end - it_behaves_like "has an untitled link" do - let(:link) { "statuses" } + it_behaves_like 'has an untitled link' do + let(:link) { 'statuses' } let(:href) { api_v3_paths.statuses } end - it_behaves_like "has an untitled link" do - let(:link) { "types" } + it_behaves_like 'has an untitled link' do + let(:link) { 'types' } let(:href) { api_v3_paths.types } end - it_behaves_like "has an untitled link" do - let(:link) { "workPackages" } + it_behaves_like 'has an untitled link' do + let(:link) { 'workPackages' } let(:href) { api_v3_paths.work_packages } end - it_behaves_like "has a titled link" do - let(:link) { "user" } + it_behaves_like 'has a titled link' do + let(:link) { 'user' } let(:href) { api_v3_paths.user(user.id) } let(:title) { user.name } end - it_behaves_like "has an untitled link" do - let(:link) { "userPreferences" } + it_behaves_like 'has an untitled link' do + let(:link) { 'userPreferences' } let(:href) { api_v3_paths.user_preferences(user.id) } end - context "anonymous user" do + context 'anonymous user' do let(:representer) { described_class.new({}, current_user: User.anonymous) } - it_behaves_like "has no link" do - let(:link) { "user" } + it_behaves_like 'has no link' do + let(:link) { 'user' } end - it_behaves_like "has an untitled link" do - let(:link) { "userPreferences" } + it_behaves_like 'has an untitled link' do + let(:link) { 'userPreferences' } let(:href) { api_v3_paths.user_preferences(User.anonymous.id) } end end end - context "attributes" do - describe "_type" do + context 'attributes' do + describe '_type' do it 'is "Root"' do expect(subject) - .to be_json_eql("Root".to_json) - .at_path("_type") + .to be_json_eql('Root'.to_json) + .at_path('_type') end end - describe "coreVersion" do - context "for a non admin user" do - it "has no coreVersion property" do + describe 'coreVersion' do + context 'for a non admin user' do + it 'has no coreVersion property' do expect(subject) - .not_to have_json_path("coreVersion") + .not_to have_json_path('coreVersion') end end - context "for an admin user" do + context 'for an admin user' do let(:user) { build_stubbed(:admin) } - it "indicates the OpenProject version number" do + it 'indicates the OpenProject version number' do expect(subject) .to be_json_eql(version.to_json) - .at_path("coreVersion") + .at_path('coreVersion') end end end - describe "instanceName" do - it "shows the name of the instance" do + describe 'instanceName' do + it 'shows the name of the instance' do expect(subject) .to be_json_eql(app_title.to_json) - .at_path("instanceName") + .at_path('instanceName') end end end diff --git a/spec/lib/api/v3/shares/share_collection_representer_spec.rb b/spec/lib/api/v3/shares/share_collection_representer_spec.rb index c4d4eb44b6e4..76f425eef7b6 100644 --- a/spec/lib/api/v3/shares/share_collection_representer_spec.rb +++ b/spec/lib/api/v3/shares/share_collection_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Shares::ShareCollectionRepresenter do - let(:self_base_link) { "/api/v3/shares" } + let(:self_base_link) { '/api/v3/shares' } let(:members) do build_stubbed_list(:work_package_member, 3).tap do |members| allow(members).to receive(:limit).with(page_size).and_return(members) @@ -49,13 +49,13 @@ let(:page) { 1 } let(:page_size) { 2 } let(:actual_count) { 3 } - let(:collection_inner_type) { "Share" } + let(:collection_inner_type) { 'Share' } include API::V3::Utilities::PathHelper - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection", 3, "shares", "Share" + it_behaves_like 'offset-paginated APIv3 collection', 3, 'shares', 'Share' end end diff --git a/spec/lib/api/v3/shares/share_representer_rendering_spec.rb b/spec/lib/api/v3/shares/share_representer_rendering_spec.rb index f7703f0c1486..c3a9b578e033 100644 --- a/spec/lib/api/v3/shares/share_representer_rendering_spec.rb +++ b/spec/lib/api/v3/shares/share_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Shares::ShareRepresenter, "rendering" do +RSpec.describe API::V3::Shares::ShareRepresenter, 'rendering' do include API::V3::Utilities::PathHelper shared_let(:project) { create(:project_with_types) } @@ -73,54 +73,54 @@ end end - describe "_links" do - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.share member.id } let(:title) { user.name } end end - describe "entity" do - it_behaves_like "has a titled link" do - let(:link) { "entity" } + describe 'entity' do + it_behaves_like 'has a titled link' do + let(:link) { 'entity' } let(:href) { api_v3_paths.work_package(work_package.id) } let(:title) { work_package.subject } end end - describe "project" do - it_behaves_like "has a titled link" do - let(:link) { "project" } + describe 'project' do + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project(project.id) } let(:title) { project.name } end end - describe "principal" do - context "for a user principal" do - it_behaves_like "has a titled link" do - let(:link) { "principal" } + describe 'principal' do + context 'for a user principal' do + it_behaves_like 'has a titled link' do + let(:link) { 'principal' } let(:href) { api_v3_paths.user(user.id) } let(:title) { user.name } end end - context "for a group principal" do + context 'for a group principal' do let(:principal) { group } - it_behaves_like "has a titled link" do - let(:link) { "principal" } + it_behaves_like 'has a titled link' do + let(:link) { 'principal' } let(:href) { api_v3_paths.group(group.id) } let(:title) { group.name } end end end - describe "roles" do - it_behaves_like "has a link collection" do - let(:link) { "roles" } + describe 'roles' do + it_behaves_like 'has a link collection' do + let(:link) { 'roles' } # excludes member_roles marked for destruction # and duplicates let(:hrefs) do @@ -139,38 +139,38 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "Share" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'Share' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { member.id } end - describe "createdAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'createdAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { member.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end - describe "updatedAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'updatedAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { member.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end end - describe "_embedded" do - describe "entity" do - let(:embedded_path) { "_embedded/entity" } + describe '_embedded' do + describe 'entity' do + let(:embedded_path) { '_embedded/entity' } - context "for a work package" do - it "has the work package embedded" do + context 'for a work package' do + it 'has the work package embedded' do expect(subject) - .to be_json_eql("WorkPackage".to_json) + .to be_json_eql('WorkPackage'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -184,12 +184,12 @@ end end - describe "project" do - let(:embedded_path) { "_embedded/project" } + describe 'project' do + let(:embedded_path) { '_embedded/project' } - it "has the project embedded" do + it 'has the project embedded' do expect(subject) - .to be_json_eql("Project".to_json) + .to be_json_eql('Project'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -198,13 +198,13 @@ end end - describe "principal" do - let(:embedded_path) { "_embedded/principal" } + describe 'principal' do + let(:embedded_path) { '_embedded/principal' } - context "for a user principal" do - it "has the user embedded" do + context 'for a user principal' do + it 'has the user embedded' do expect(subject) - .to be_json_eql("User".to_json) + .to be_json_eql('User'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -213,12 +213,12 @@ end end - context "for a group principal" do + context 'for a group principal' do let(:principal) { group } - it "has the group embedded" do + it 'has the group embedded' do expect(subject) - .to be_json_eql("Group".to_json) + .to be_json_eql('Group'.to_json) .at_path("#{embedded_path}/_type") expect(subject) @@ -228,12 +228,12 @@ end end - describe "roles" do - let(:embedded_path) { "_embedded/roles" } + describe 'roles' do + let(:embedded_path) { '_embedded/roles' } - it "has an array of roles embedded that excludes member_roles marked for destruction" do + it 'has an array of roles embedded that excludes member_roles marked for destruction' do expect(subject) - .to be_json_eql("Role".to_json) + .to be_json_eql('Role'.to_json) .at_path("#{embedded_path}/0/_type") expect(subject) @@ -241,7 +241,7 @@ .at_path("#{embedded_path}/0/name") expect(subject) - .to be_json_eql("Role".to_json) + .to be_json_eql('Role'.to_json) .at_path("#{embedded_path}/1/_type") expect(subject) diff --git a/spec/lib/api/v3/statuses/status_collection_representer_spec.rb b/spec/lib/api/v3/statuses/status_collection_representer_spec.rb index cd02db3da391..c8e4a38d1083 100644 --- a/spec/lib/api/v3/statuses/status_collection_representer_spec.rb +++ b/spec/lib/api/v3/statuses/status_collection_representer_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Statuses::StatusCollectionRepresenter do include API::V3::Utilities::PathHelper let(:statuses) { build_list(:status, 3) } let(:representer) do - described_class.new(statuses, self_link: api_v3_paths.statuses, current_user: double("current_user")) + described_class.new(statuses, self_link: api_v3_paths.statuses, current_user: double('current_user')) end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "statuses", "Status" + it_behaves_like 'unpaginated APIv3 collection', 3, 'statuses', 'Status' end end diff --git a/spec/lib/api/v3/statuses/status_representer_spec.rb b/spec/lib/api/v3/statuses/status_representer_spec.rb index 799a822cc116..8cb9c70fc7c2 100644 --- a/spec/lib/api/v3/statuses/status_representer_spec.rb +++ b/spec/lib/api/v3/statuses/status_representer_spec.rb @@ -26,54 +26,54 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Statuses::StatusRepresenter do let(:status) { build_stubbed(:status) } - let(:representer) { described_class.new(status, current_user: double("current_user")) } + let(:representer) { described_class.new(status, current_user: double('current_user')) } - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - it { is_expected.to include_json("Status".to_json).at_path("_type") } - - describe "status" do - it { is_expected.to have_json_path("id") } - it { is_expected.to have_json_path("name") } - it { is_expected.to have_json_path("isClosed") } - it { is_expected.to have_json_path("isDefault") } - it { is_expected.to have_json_path("isReadonly") } - it { is_expected.to have_json_path("position") } - it { is_expected.to have_json_path("defaultDoneRatio") } - - describe "values" do - it { is_expected.to be_json_eql(status.id.to_json).at_path("id") } - it { is_expected.to be_json_eql(status.name.to_json).at_path("name") } - it { is_expected.to be_json_eql(status.is_closed.to_json).at_path("isClosed") } - it { is_expected.to be_json_eql(status.is_default.to_json).at_path("isDefault") } - it { is_expected.to be_json_eql(status.is_readonly.to_json).at_path("isReadonly") } - it { is_expected.to be_json_eql(status.position.to_json).at_path("position") } + it { is_expected.to include_json('Status'.to_json).at_path('_type') } + + describe 'status' do + it { is_expected.to have_json_path('id') } + it { is_expected.to have_json_path('name') } + it { is_expected.to have_json_path('isClosed') } + it { is_expected.to have_json_path('isDefault') } + it { is_expected.to have_json_path('isReadonly') } + it { is_expected.to have_json_path('position') } + it { is_expected.to have_json_path('defaultDoneRatio') } + + describe 'values' do + it { is_expected.to be_json_eql(status.id.to_json).at_path('id') } + it { is_expected.to be_json_eql(status.name.to_json).at_path('name') } + it { is_expected.to be_json_eql(status.is_closed.to_json).at_path('isClosed') } + it { is_expected.to be_json_eql(status.is_default.to_json).at_path('isDefault') } + it { is_expected.to be_json_eql(status.is_readonly.to_json).at_path('isReadonly') } + it { is_expected.to be_json_eql(status.position.to_json).at_path('position') } it { - expect(subject).to be_json_eql(status.default_done_ratio.to_json).at_path("defaultDoneRatio") + expect(subject).to be_json_eql(status.default_done_ratio.to_json).at_path('defaultDoneRatio') } end end - describe "_links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe '_links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - describe "self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { "/api/v3/statuses/#{status.id}" } let(:title) { status.name } end end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -82,22 +82,22 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Statuses", "StatusRepresenter") + .to include('API', 'V3', 'Statuses', 'StatusRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the status is updated" do + it 'changes when the status is updated' do status.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/support/api_v3_collection.rb b/spec/lib/api/v3/support/api_v3_collection.rb index cb52fdb9d3c3..8d4ac347148d 100644 --- a/spec/lib/api/v3/support/api_v3_collection.rb +++ b/spec/lib/api/v3/support/api_v3_collection.rb @@ -26,96 +26,96 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "generic APIv3 collection" do - describe "_links" do - it "has a self link" do - expect(collection).to be_json_eql(self_link.to_json).at_path("_links/self/href") +RSpec.shared_examples_for 'generic APIv3 collection' do + describe '_links' do + it 'has a self link' do + expect(collection).to be_json_eql(self_link.to_json).at_path('_links/self/href') end end - it "has a collection type" do - expected_type = defined?(collection_type) ? collection_type : "Collection" - expect(collection).to be_json_eql(expected_type.to_json).at_path("_type") + it 'has a collection type' do + expected_type = defined?(collection_type) ? collection_type : 'Collection' + expect(collection).to be_json_eql(expected_type.to_json).at_path('_type') end - describe "elements are typed correctly" do + describe 'elements are typed correctly' do it do expect(collection).to be_json_eql(collection_inner_type.to_json) - .at_path("_embedded/elements/0/_type") + .at_path('_embedded/elements/0/_type') end end end -RSpec.shared_examples_for "unpaginated APIv3 collection" do |count, self_link, type| - it_behaves_like "generic APIv3 collection" do +RSpec.shared_examples_for 'unpaginated APIv3 collection' do |count, self_link, type| + it_behaves_like 'generic APIv3 collection' do let(:self_link) { "/api/v3/#{self_link}" } let(:collection_inner_type) { type } end - describe "quantities" do - it { expect(collection).to be_json_eql(count.to_json).at_path("total") } + describe 'quantities' do + it { expect(collection).to be_json_eql(count.to_json).at_path('total') } - it { expect(collection).to be_json_eql(count.to_json).at_path("count") } + it { expect(collection).to be_json_eql(count.to_json).at_path('count') } - it { expect(collection).to have_json_size(count).at_path("_embedded/elements") } + it { expect(collection).to have_json_size(count).at_path('_embedded/elements') } end end -RSpec.shared_examples_for "offset-paginated APIv3 collection" do +RSpec.shared_examples_for 'offset-paginated APIv3 collection' do def make_link_for(page:, page_size:) page = ERB::Util::url_encode(page) page_size = ERB::Util::url_encode(page_size) "#{self_base_link}?offset=#{page}&pageSize=#{page_size}" end - it_behaves_like "generic APIv3 collection" do + it_behaves_like 'generic APIv3 collection' do let(:self_link) { make_link_for(page:, page_size:) } end - describe "_links" do - it_behaves_like "has a templated link" do - let(:link) { "jumpTo" } - let(:href) { make_link_for(page: "{offset}", page_size:) } + describe '_links' do + it_behaves_like 'has a templated link' do + let(:link) { 'jumpTo' } + let(:href) { make_link_for(page: '{offset}', page_size:) } end - it_behaves_like "has a templated link" do - let(:link) { "changeSize" } - let(:href) { make_link_for(page:, page_size: "{size}") } + it_behaves_like 'has a templated link' do + let(:link) { 'changeSize' } + let(:href) { make_link_for(page:, page_size: '{size}') } end end - it "indicates the page number as offset" do - expect(collection).to be_json_eql(page.to_json).at_path("offset") + it 'indicates the page number as offset' do + expect(collection).to be_json_eql(page.to_json).at_path('offset') end - it "indicates the expected pageSize" do - expect(collection).to be_json_eql(page_size.to_json).at_path("pageSize") + it 'indicates the expected pageSize' do + expect(collection).to be_json_eql(page_size.to_json).at_path('pageSize') end - it "indicates the total amount of elements (over all pages)" do - expect(collection).to be_json_eql(total.to_json).at_path("total") + it 'indicates the total amount of elements (over all pages)' do + expect(collection).to be_json_eql(total.to_json).at_path('total') end - it "indicates the number of elements on this page" do - expect(collection).to be_json_eql(actual_count.to_json).at_path("count") + it 'indicates the number of elements on this page' do + expect(collection).to be_json_eql(actual_count.to_json).at_path('count') end - it "embeds the expected number of elements" do - expect(collection).to have_json_size(actual_count).at_path("_embedded/elements") + it 'embeds the expected number of elements' do + expect(collection).to have_json_size(actual_count).at_path('_embedded/elements') end - shared_examples_for "links to previous page by offset" do - it_behaves_like "has an untitled link" do - let(:link) { "previousByOffset" } + shared_examples_for 'links to previous page by offset' do + it_behaves_like 'has an untitled link' do + let(:link) { 'previousByOffset' } let(:href) { make_link_for(page: page - 1, page_size:) } end end - shared_examples_for "links to next page by offset" do - it_behaves_like "has an untitled link" do - let(:link) { "nextByOffset" } + shared_examples_for 'links to next page by offset' do + it_behaves_like 'has an untitled link' do + let(:link) { 'nextByOffset' } let(:href) { make_link_for(page: page + 1, page_size:) } end end diff --git a/spec/lib/api/v3/support/api_v3_digest.rb b/spec/lib/api/v3/support/api_v3_digest.rb index e79fa8b3c1f0..7df836c39eef 100644 --- a/spec/lib/api/v3/support/api_v3_digest.rb +++ b/spec/lib/api/v3/support/api_v3_digest.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "API V3 digest" do - it "defines an algorithm" do +RSpec.shared_examples_for 'API V3 digest' do + it 'defines an algorithm' do expect(subject).to be_json_eql(algorithm.to_json).at_path("#{path}/algorithm") end - it "has a hash" do + it 'has a hash' do expect(subject).to be_json_eql(hash.to_json).at_path("#{path}/hash") end end diff --git a/spec/lib/api/v3/support/api_v3_filter_dependency.rb b/spec/lib/api/v3/support/api_v3_filter_dependency.rb index d74e6b39722d..df69a4507bc8 100644 --- a/spec/lib/api/v3/support/api_v3_filter_dependency.rb +++ b/spec/lib/api/v3/support/api_v3_filter_dependency.rb @@ -26,68 +26,68 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "filter dependency" do - it_behaves_like "has basic schema properties" do - let(:name) { "Values" } +RSpec.shared_examples_for 'filter dependency' do + it_behaves_like 'has basic schema properties' do + let(:name) { 'Values' } let(:required) { true } let(:writable) { true } let(:has_default) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end -RSpec.shared_examples_for "filter dependency with allowed link" do - it_behaves_like "has basic schema properties" do - let(:name) { "Values" } +RSpec.shared_examples_for 'filter dependency with allowed link' do + it_behaves_like 'has basic schema properties' do + let(:name) { 'Values' } let(:required) { true } let(:writable) { true } let(:has_default) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "links to allowed values via collection link" + it_behaves_like 'links to allowed values via collection link' end end -RSpec.shared_examples_for "filter dependency with allowed value link collection" do - it_behaves_like "has basic schema properties" do - let(:name) { "Values" } +RSpec.shared_examples_for 'filter dependency with allowed value link collection' do + it_behaves_like 'has basic schema properties' do + let(:name) { 'Values' } let(:required) { true } let(:writable) { true } let(:has_default) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' - context "when embedding" do + context 'when embedding' do let(:form_embedded) { true } - it_behaves_like "links to allowed values directly" + it_behaves_like 'links to allowed values directly' end end -RSpec.shared_examples_for "filter dependency empty" do - it "is an empty object" do +RSpec.shared_examples_for 'filter dependency empty' do + it 'is an empty object' do expect(subject) .to be_json_eql({}.to_json) end end -RSpec.shared_examples_for "relation filter dependency" do +RSpec.shared_examples_for 'relation filter dependency' do include API::V3::Utilities::PathHelper let(:project) { build_stubbed(:project) } @@ -102,49 +102,49 @@ subject(:generated) { instance.to_json } - context "generation" do - context "properties" do - describe "values" do - context "within project" do - let(:path) { "values" } - let(:type) { "[]WorkPackage" } + context 'generation' do + context 'properties' do + describe 'values' do + context 'within project' do + let(:path) { 'values' } + let(:type) { '[]WorkPackage' } let(:href) { api_v3_paths.work_packages_by_project(project.id) } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - let(:path) { "values" } - let(:type) { "[]WorkPackage" } + let(:path) { 'values' } + let(:type) { '[]WorkPackage' } let(:href) { api_v3_paths.work_packages } context "for operator 'Queries::Operators::Equals'" do let(:operator) { Queries::Operators::Equals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end context "for operator 'Queries::Operators::NotEquals'" do let(:operator) { Queries::Operators::NotEquals } - it_behaves_like "filter dependency with allowed link" + it_behaves_like 'filter dependency with allowed link' end end end end - describe "caching" do + describe 'caching' do let(:operator) { Queries::Operators::Equals } let(:other_project) { build_stubbed(:project) } @@ -153,14 +153,14 @@ instance.to_json end - it "is cached" do + it 'is cached' do expect(instance) .not_to receive(:to_hash) instance.to_json end - it "busts the cache on a different operator" do + it 'busts the cache on a different operator' do instance.send(:operator=, Queries::Operators::NotEquals) expect(instance) @@ -169,7 +169,7 @@ instance.to_json end - it "busts the cache on a different project" do + it 'busts the cache on a different project' do query.project = other_project expect(instance) @@ -178,7 +178,7 @@ instance.to_json end - it "busts the cache on changes to the locale" do + it 'busts the cache on changes to the locale' do expect(instance) .to receive(:to_hash) @@ -187,7 +187,7 @@ end end - it "busts the cache on different form_embedded" do + it 'busts the cache on different form_embedded' do embedded_instance = described_class.new(filter, operator, form_embedded: !form_embedded) diff --git a/spec/lib/api/v3/support/api_v3_formattable.rb b/spec/lib/api/v3/support/api_v3_formattable.rb index c27f490f5770..05edf52cd12a 100644 --- a/spec/lib/api/v3/support/api_v3_formattable.rb +++ b/spec/lib/api/v3/support/api_v3_formattable.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "API V3 formattable" do |property| +RSpec.shared_examples_for 'API V3 formattable' do |property| it { is_expected.to have_json_path(property) } - it { is_expected.to be_json_eql(format.to_json).at_path(property + "/format") } + it { is_expected.to be_json_eql(format.to_json).at_path(property + '/format') } - it_behaves_like "formattable property", property do + it_behaves_like 'formattable property', property do let(:value) { raw } end it do if defined?(html) - expect(subject).to be_json_eql(html.to_json).at_path(property + "/html") + expect(subject).to be_json_eql(html.to_json).at_path(property + '/html') end end end diff --git a/spec/lib/api/v3/support/collection_examples.rb b/spec/lib/api/v3/support/collection_examples.rb index 0d632e2f3b6b..a57f98ee39e8 100644 --- a/spec/lib/api/v3/support/collection_examples.rb +++ b/spec/lib/api/v3/support/collection_examples.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "collection" do |name| +RSpec.shared_examples_for 'collection' do |name| it "has the #{name} property" do represented_elements = value.map { |v| element_decorator.call(v) } diff --git a/spec/lib/api/v3/support/date_time_examples.rb b/spec/lib/api/v3/support/date_time_examples.rb index ece25fd3770d..79a0516fab76 100644 --- a/spec/lib/api/v3/support/date_time_examples.rb +++ b/spec/lib/api/v3/support/date_time_examples.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "has ISO 8601 date only" do - it "exists" do +RSpec.shared_examples_for 'has ISO 8601 date only' do + it 'exists' do expect(subject).to have_json_path(json_path) end - it "indicates date only as ISO 8601" do + it 'indicates date only as ISO 8601' do allow(API::V3::Utilities::DateTimeFormatter).to receive(:format_date) subject @@ -45,12 +45,12 @@ end end -RSpec.shared_examples_for "has UTC ISO 8601 date and time" do - it "exists" do +RSpec.shared_examples_for 'has UTC ISO 8601 date and time' do + it 'exists' do expect(subject).to have_json_path(json_path) end - it "indicates date and time as ISO 8601" do + it 'indicates date and time as ISO 8601' do allow(API::V3::Utilities::DateTimeFormatter).to receive(:format_datetime) subject diff --git a/spec/lib/api/v3/support/link_examples.rb b/spec/lib/api/v3/support/link_examples.rb index be3c6b5f442f..f085aaed860e 100644 --- a/spec/lib/api/v3/support/link_examples.rb +++ b/spec/lib/api/v3/support/link_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_context "action link shared" do +RSpec.shared_context 'action link shared' do let(:all_permissions) { OpenProject::AccessControl.permissions.map(&:name) } let(:permissions) { all_permissions } let(:action_link_user) do @@ -47,7 +47,7 @@ end end - it "indicates the desired method" do + it 'indicates the desired method' do verb = begin # the standard method #method on an object interferes # with the let named 'method' conditionally defined @@ -66,60 +66,60 @@ end end - describe "without permission" do + describe 'without permission' do let(:permissions) { all_permissions - Array(permission) } - it_behaves_like "has no link" + it_behaves_like 'has no link' end end -RSpec.shared_examples_for "has an untitled action link" do - include_context "action link shared" +RSpec.shared_examples_for 'has an untitled action link' do + include_context 'action link shared' - it_behaves_like "has an untitled link" + it_behaves_like 'has an untitled link' end -RSpec.shared_examples_for "has a titled action link" do - include_context "action link shared" +RSpec.shared_examples_for 'has a titled action link' do + include_context 'action link shared' - it_behaves_like "has a titled link" + it_behaves_like 'has a titled link' end -RSpec.shared_examples_for "has a titled link" do +RSpec.shared_examples_for 'has a titled link' do it { is_expected.to be_json_eql(href.to_json).at_path("_links/#{link}/href") } it { is_expected.to be_json_eql(title.to_json).at_path("_links/#{link}/title") } end -RSpec.shared_examples_for "has an untitled link" do +RSpec.shared_examples_for 'has an untitled link' do it { is_expected.to be_json_eql(href.to_json).at_path("_links/#{link}/href") } it { is_expected.not_to have_json_path("_links/#{link}/title") } end -RSpec.shared_examples_for "has a templated link" do +RSpec.shared_examples_for 'has a templated link' do it { is_expected.to be_json_eql(href.to_json).at_path("_links/#{link}/href") } it { is_expected.to be_json_eql(true.to_json).at_path("_links/#{link}/templated") } end -RSpec.shared_examples_for "has an empty link" do +RSpec.shared_examples_for 'has an empty link' do it { is_expected.to be_json_eql(nil.to_json).at_path("_links/#{link}/href") } - it "has no embedded resource" do + it 'has no embedded resource' do expect(subject).not_to have_json_path("_embedded/#{link}") end end -RSpec.shared_examples_for "has an empty link collection" do +RSpec.shared_examples_for 'has an empty link collection' do it { is_expected.to be_json_eql([].to_json).at_path("_links/#{link}") } end -RSpec.shared_examples_for "has a link collection" do +RSpec.shared_examples_for 'has a link collection' do it { is_expected.to be_json_eql(hrefs.to_json).at_path("_links/#{link}") } end -RSpec.shared_examples_for "has no link" do +RSpec.shared_examples_for 'has no link' do it { is_expected.not_to have_json_path("_links/#{link}") } - it "has no embedded resource" do + it 'has no embedded resource' do expect(subject).not_to have_json_path("_embedded/#{link}") end end diff --git a/spec/lib/api/v3/support/property_examples.rb b/spec/lib/api/v3/support/property_examples.rb index 4854832d89e7..3eb25d14e53e 100644 --- a/spec/lib/api/v3/support/property_examples.rb +++ b/spec/lib/api/v3/support/property_examples.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "property" do |name| +RSpec.shared_examples_for 'property' do |name| it "has the #{name} property" do expect(subject) .to be_json_eql(value.to_json) @@ -34,13 +34,13 @@ end end -RSpec.shared_examples_for "no property" do |name| +RSpec.shared_examples_for 'no property' do |name| it "does not have the #{name} property" do expect(subject).not_to have_json_path(name.to_s) end end -RSpec.shared_examples_for "formattable property" do |name| +RSpec.shared_examples_for 'formattable property' do |name| it "has the #{name} property" do expect(subject) .to be_json_eql(value.to_s.to_json) @@ -48,15 +48,15 @@ end end -RSpec.shared_examples_for "date property" do |name| - it_behaves_like "has ISO 8601 date only" do +RSpec.shared_examples_for 'date property' do |name| + it_behaves_like 'has ISO 8601 date only' do let(:json_path) { name.to_s } let(:date) { value } end end -RSpec.shared_examples_for "datetime property" do |name| - it_behaves_like "has UTC ISO 8601 date and time" do +RSpec.shared_examples_for 'datetime property' do |name| + it_behaves_like 'has UTC ISO 8601 date and time' do let(:json_path) { name.to_s } let(:date) { value } end diff --git a/spec/lib/api/v3/support/schema_examples.rb b/spec/lib/api/v3/support/schema_examples.rb index b6e34a1bba80..118f26879617 100644 --- a/spec/lib/api/v3/support/schema_examples.rb +++ b/spec/lib/api/v3/support/schema_examples.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "has basic schema properties" do - it "exists" do +RSpec.shared_examples_for 'has basic schema properties' do + it 'exists' do expect(subject).to have_json_path(path) end - it "has a type" do + it 'has a type' do expect(subject).to be_json_eql(type.to_json).at_path("#{path}/type") end - it "has a name" do + it 'has a name' do expect(subject).to be_json_eql(name.to_json).at_path("#{path}/name") end - it "indicates if it is required" do + it 'indicates if it is required' do expect(subject).to be_json_eql(required.to_json).at_path("#{path}/required") end - it "indicates if it is writable" do + it 'indicates if it is writable' do expect(subject).to be_json_eql(writable.to_json).at_path("#{path}/writable") end - it "indicates if it has default" do + it 'indicates if it has default' do expected_has_default = if defined?(has_default) has_default else @@ -61,7 +61,7 @@ .at_path("#{path}/hasDefault") end - it "indicates if it has a location" do + it 'indicates if it has a location' do if defined?(location) expect(subject) .to be_json_eql(location.to_json) @@ -71,7 +71,7 @@ end end - it "indicates if it has a description" do + it 'indicates if it has a description' do if defined?(description) expect(subject) .to be_json_eql(description.to_json) @@ -82,8 +82,8 @@ end end -RSpec.shared_examples_for "indicates length requirements" do - it "indicates its minimum length" do +RSpec.shared_examples_for 'indicates length requirements' do + it 'indicates its minimum length' do if defined?(min_length) expect(subject) .to be_json_eql(min_length.to_json) @@ -94,7 +94,7 @@ end end - it "indicates its maximum length" do + it 'indicates its maximum length' do if defined?(max_length) expect(subject) .to be_json_eql(max_length.to_json) @@ -106,12 +106,12 @@ end end -RSpec.shared_examples_for "links to allowed values directly" do - it "has the expected number of links" do +RSpec.shared_examples_for 'links to allowed values directly' do + it 'has the expected number of links' do expect(subject).to have_json_size(hrefs.size).at_path("#{path}/_links/allowedValues") end - it "contains links to the allowed values" do + it 'contains links to the allowed values' do index = 0 hrefs.each do |href| href_path = "#{path}/_links/allowedValues/#{index}/href" @@ -121,14 +121,14 @@ end end -RSpec.shared_examples_for "links to and embeds allowed values directly" do - it_behaves_like "links to allowed values directly" +RSpec.shared_examples_for 'links to and embeds allowed values directly' do + it_behaves_like 'links to allowed values directly' - it "has the expected number of embedded values" do + it 'has the expected number of embedded values' do expect(subject).to have_json_size(hrefs.size).at_path("#{path}/_embedded/allowedValues") end - it "embeds the allowed values" do + it 'embeds the allowed values' do index = 0 hrefs.each do |href| href_path = "#{path}/_embedded/allowedValues/#{index}/_links/self/href" @@ -138,18 +138,18 @@ end end -RSpec.shared_examples_for "links to allowed values via collection link" do - it "contains the link to the allowed values" do +RSpec.shared_examples_for 'links to allowed values via collection link' do + it 'contains the link to the allowed values' do expect(subject).to be_json_eql(href.to_json).at_path("#{path}/_links/allowedValues/href") end end -RSpec.shared_examples_for "does not link to allowed values" do - it "contains no link to the allowed values" do +RSpec.shared_examples_for 'does not link to allowed values' do + it 'contains no link to the allowed values' do expect(subject).not_to have_json_path("#{path}/_links/allowedValues") end - it "does not embed allowed values" do + it 'does not embed allowed values' do expect(subject).not_to have_json_path("#{path}/_embedded/allowedValues") end end diff --git a/spec/lib/api/v3/types/type_representer_spec.rb b/spec/lib/api/v3/types/type_representer_spec.rb index 99fdc3c9e4d8..d0f81073a330 100644 --- a/spec/lib/api/v3/types/type_representer_spec.rb +++ b/spec/lib/api/v3/types/type_representer_spec.rb @@ -26,85 +26,85 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Types::TypeRepresenter do let(:type) { build_stubbed(:type, color: build_stubbed(:color)) } - let(:representer) { described_class.new(type, current_user: double("current_user")) } + let(:representer) { described_class.new(type, current_user: double('current_user')) } include API::V3::Utilities::PathHelper - context "generation" do + context 'generation' do subject { representer.to_json } - describe "links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.type(type.id) } let(:title) { type.name } end end - it "indicates its id" do - expect(subject).to be_json_eql(type.id.to_json).at_path("id") + it 'indicates its id' do + expect(subject).to be_json_eql(type.id.to_json).at_path('id') end - it "indicates its name" do - expect(subject).to be_json_eql(type.name.to_json).at_path("name") + it 'indicates its name' do + expect(subject).to be_json_eql(type.name.to_json).at_path('name') end - it "indicates its color" do - expect(subject).to be_json_eql(type.color.hexcode.to_json).at_path("color") + it 'indicates its color' do + expect(subject).to be_json_eql(type.color.hexcode.to_json).at_path('color') end - context "no color set" do + context 'no color set' do let(:type) { build_stubbed(:type, color: nil) } - it "indicates a missing color" do - expect(subject).to be_json_eql(nil.to_json).at_path("color") + it 'indicates a missing color' do + expect(subject).to be_json_eql(nil.to_json).at_path('color') end end - it "indicates its position" do - expect(subject).to be_json_eql(type.position.to_json).at_path("position") + it 'indicates its position' do + expect(subject).to be_json_eql(type.position.to_json).at_path('position') end - it "indicates that it is not the default type" do - expect(subject).to be_json_eql(false.to_json).at_path("isDefault") + it 'indicates that it is not the default type' do + expect(subject).to be_json_eql(false.to_json).at_path('isDefault') end - context "as default type" do + context 'as default type' do let(:type) { build_stubbed(:type, is_default: true) } - it "indicates that it is the default type" do - expect(subject).to be_json_eql(true.to_json).at_path("isDefault") + it 'indicates that it is the default type' do + expect(subject).to be_json_eql(true.to_json).at_path('isDefault') end end - it "indicates that it is not a milestone" do - expect(subject).to be_json_eql(false.to_json).at_path("isMilestone") + it 'indicates that it is not a milestone' do + expect(subject).to be_json_eql(false.to_json).at_path('isMilestone') end - context "as milestone" do + context 'as milestone' do let(:type) { build_stubbed(:type, is_milestone: true) } - it "indicates that it is a milestone" do - expect(subject).to be_json_eql(true.to_json).at_path("isMilestone") + it 'indicates that it is a milestone' do + expect(subject).to be_json_eql(true.to_json).at_path('isMilestone') end end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { type.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { type.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -113,22 +113,22 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Types", "TypeRepresenter") + .to include('API', 'V3', 'Types', 'TypeRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the type is updated" do + it 'changes when the type is updated' do type.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/user_preferences/notification_setting_representer_rendering_spec.rb b/spec/lib/api/v3/user_preferences/notification_setting_representer_rendering_spec.rb index ead492a84976..f8f8c5f025f8 100644 --- a/spec/lib/api/v3/user_preferences/notification_setting_representer_rendering_spec.rb +++ b/spec/lib/api/v3/user_preferences/notification_setting_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::UserPreferences::NotificationSettingRepresenter, "rendering" do +RSpec.describe API::V3::UserPreferences::NotificationSettingRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:generated) { representer.to_json } @@ -46,73 +46,73 @@ current_user { build_stubbed(:user) } - describe "_links" do - describe "self" do + describe '_links' do + describe 'self' do # No self link as the representer is rendered as part of the user preferences. - it_behaves_like "has no link" do - let(:link) { "self" } + it_behaves_like 'has no link' do + let(:link) { 'self' } end end - describe "project" do - it_behaves_like "has a titled link" do - let(:link) { "project" } + describe 'project' do + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project(project.id) } let(:title) { project.name } end end end - describe "properties" do - it "has no _type" do + describe 'properties' do + it 'has no _type' do expect(generated) - .not_to have_json_path("_type") + .not_to have_json_path('_type') end (NotificationSetting.all_settings - NotificationSetting.date_alert_settings).each do |property| - it_behaves_like "property", property.to_s.camelize(:lower) do + it_behaves_like 'property', property.to_s.camelize(:lower) do let(:value) do notification_setting.send property end end end - context "without enterprise" do - it "does not have the date alert settings in the resulting json" do + context 'without enterprise' do + it 'does not have the date alert settings in the resulting json' do expect(subject).not_to have_json_path("startDate") expect(subject).not_to have_json_path("dueDate") expect(subject).not_to have_json_path("overdue") end end - context "with enterprise", with_ee: %i[date_alerts] do - it_behaves_like "property", :startDate do - let(:value) { "P1D" } + context 'with enterprise', with_ee: %i[date_alerts] do + it_behaves_like 'property', :startDate do + let(:value) { 'P1D' } end - it_behaves_like "property", :dueDate do - let(:value) { "P1D" } + it_behaves_like 'property', :dueDate do + let(:value) { 'P1D' } end - it_behaves_like "property", :overdue do - let(:value) { "P3D" } + it_behaves_like 'property', :overdue do + let(:value) { 'P3D' } end end end - describe "_embedded" do - describe "project" do - it "skips embedding the project" do + describe '_embedded' do + describe 'project' do + it 'skips embedding the project' do expect(generated) - .not_to have_json_path("_embedded/project") + .not_to have_json_path('_embedded/project') end end end - context "when duration settings are all nil" do + context 'when duration settings are all nil' do let(:notification_setting) do build_stubbed(:notification_setting, project:, start_date: nil, due_date: nil, overdue: nil) end - it "does not represent them in the resulting json" do + it 'does not represent them in the resulting json' do expect(subject).not_to have_json_path("startDate") expect(subject).not_to have_json_path("dueDate") expect(subject).not_to have_json_path("overdue") diff --git a/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb b/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb index 71c7f25ab223..5ce1548920c7 100644 --- a/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb +++ b/spec/lib/api/v3/user_preferences/user_preference_representer_parsing_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::UserPreferences::UserPreferenceRepresenter, - "parsing" do + 'parsing' do subject(:parsed) { representer.from_hash request_body } include API::V3::Utilities::PathHelper @@ -38,26 +38,26 @@ let(:user) { build_stubbed(:user) } let(:representer) { described_class.new(preference, current_user: user) } - describe "notification_settings" do + describe 'notification_settings' do let(:request_body) do { - "notifications" => [ + 'notifications' => [ { - "assignee" => true, - "responsible" => true, - "_links" => { - "project" => { - "href" => "/api/v3/projects/1" + 'assignee' => true, + 'responsible' => true, + '_links' => { + 'project' => { + 'href' => '/api/v3/projects/1' } } }, { - "assignee" => false, - "responsible" => false, - "mentioned" => true, - "_links" => { - "project" => { - "href" => nil + 'assignee' => false, + 'responsible' => false, + 'mentioned' => true, + '_links' => { + 'project' => { + 'href' => nil } } } @@ -65,7 +65,7 @@ } end - it "parses them into an array of structs" do + it 'parses them into an array of structs' do expect(subject.notification_settings).to be_a Array expect(subject.notification_settings.length).to eq 2 in_project, global = subject.notification_settings @@ -82,7 +82,7 @@ end end - describe "daily_reminders" do + describe 'daily_reminders' do let(:request_body) do { "dailyReminders" => { @@ -92,7 +92,7 @@ } end - it "parses the times into full iso8601 time format" do + it 'parses the times into full iso8601 time format' do expect(parsed.daily_reminders) .to eql({ "enabled" => true, @@ -101,7 +101,7 @@ end end - describe "pause_reminders" do + describe 'pause_reminders' do let(:request_body) do { "pauseReminders" => { @@ -112,11 +112,11 @@ } end - context "with all set" do - let(:first_day) { "2021-10-10" } - let(:last_day) { "2021-10-20" } + context 'with all set' do + let(:first_day) { '2021-10-10' } + let(:last_day) { '2021-10-20' } - it "sets both dates" do + it 'sets both dates' do expect(parsed.pause_reminders) .to eql({ "enabled" => true, @@ -126,11 +126,11 @@ end end - context "with first only set" do - let(:first_day) { "2021-10-10" } + context 'with first only set' do + let(:first_day) { '2021-10-10' } let(:last_day) { nil } - it "uses the first day for the last day" do + it 'uses the first day for the last day' do expect(parsed.pause_reminders) .to eql({ "enabled" => true, @@ -140,11 +140,11 @@ end end - context "with last only set" do + context 'with last only set' do let(:first_day) { nil } - let(:last_day) { "2021-10-10" } + let(:last_day) { '2021-10-10' } - it "uses the first day for the last day" do + it 'uses the first day for the last day' do expect(parsed.pause_reminders) .to eql({ "enabled" => true, diff --git a/spec/lib/api/v3/user_preferences/user_preference_representer_rendering_spec.rb b/spec/lib/api/v3/user_preferences/user_preference_representer_rendering_spec.rb index ce1c2c9e9af0..b92a087eb6bc 100644 --- a/spec/lib/api/v3/user_preferences/user_preference_representer_rendering_spec.rb +++ b/spec/lib/api/v3/user_preferences/user_preference_representer_rendering_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::UserPreferences::UserPreferenceRepresenter, - "rendering" do + 'rendering' do include API::V3::Utilities::PathHelper let(:preference) do @@ -52,34 +52,34 @@ subject(:generated) { representer.to_json } - it { expect(subject).to have_json_path("hideMail") } - it { expect(subject).to have_json_path("timeZone") } - it { expect(subject).to have_json_path("commentSortDescending") } - it { expect(subject).to have_json_path("warnOnLeavingUnsaved") } - it { expect(subject).to have_json_path("autoHidePopups") } + it { expect(subject).to have_json_path('hideMail') } + it { expect(subject).to have_json_path('timeZone') } + it { expect(subject).to have_json_path('commentSortDescending') } + it { expect(subject).to have_json_path('warnOnLeavingUnsaved') } + it { expect(subject).to have_json_path('autoHidePopups') } - describe "timeZone" do - context "without a timezone set" do - let(:preference) { build(:user_preference, time_zone: "") } + describe 'timeZone' do + context 'without a timezone set' do + let(:preference) { build(:user_preference, time_zone: '') } - it "shows the timeZone as nil" do - expect(subject).to be_json_eql(nil.to_json).at_path("timeZone") + it 'shows the timeZone as nil' do + expect(subject).to be_json_eql(nil.to_json).at_path('timeZone') end end - context "with a timezone set" do - let(:preference) { build(:user_preference, time_zone: "Europe/Paris") } + context 'with a timezone set' do + let(:preference) { build(:user_preference, time_zone: 'Europe/Paris') } - it "shows the canonical time zone" do - expect(subject).to be_json_eql("Europe/Paris".to_json).at_path("timeZone") + it 'shows the canonical time zone' do + expect(subject).to be_json_eql('Europe/Paris'.to_json).at_path('timeZone') end end end - describe "notification_settings", with_ee: %i[date_alerts] do - it "renders them as a nested array" do - expect(subject).to have_json_type(Array).at_path("notifications") - expect(subject).to be_json_eql(nil.to_json).at_path("notifications/0/_links/project/href") + describe 'notification_settings', with_ee: %i[date_alerts] do + it 'renders them as a nested array' do + expect(subject).to have_json_type(Array).at_path('notifications') + expect(subject).to be_json_eql(nil.to_json).at_path('notifications/0/_links/project/href') date_keys = [NotificationSetting::START_DATE, NotificationSetting::DUE_DATE, NotificationSetting::OVERDUE] NotificationSetting.all_settings.each do |key| @@ -95,15 +95,15 @@ end end - describe "properties" do - describe "_type" do - it_behaves_like "property", :_type do - let(:value) { "UserPreferences" } + describe 'properties' do + describe '_type' do + it_behaves_like 'property', :_type do + let(:value) { 'UserPreferences' } end end - describe "dailyReminders" do - it_behaves_like "property", :dailyReminders do + describe 'dailyReminders' do + it_behaves_like 'property', :dailyReminders do let(:value) do { "enabled" => true, @@ -114,26 +114,26 @@ end end - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.user_preferences(user.id) } end - it_behaves_like "has a titled link" do - let(:link) { "user" } + it_behaves_like 'has a titled link' do + let(:link) { 'user' } let(:title) { user.name } let(:href) { api_v3_paths.user(user.id) } end - describe "immediate update" do - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + describe 'immediate update' do + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.user_preferences(user.id) } end - it "is a patch link" do - expect(subject).to be_json_eql("patch".to_json).at_path("_links/updateImmediately/method") + it 'is a patch link' do + expect(subject).to be_json_eql('patch'.to_json).at_path('_links/updateImmediately/method') end end end diff --git a/spec/lib/api/v3/users/unpaginated_user_collection_representer_spec.rb b/spec/lib/api/v3/users/unpaginated_user_collection_representer_spec.rb index bb71a3540d4f..f38e086f3e62 100644 --- a/spec/lib/api/v3/users/unpaginated_user_collection_representer_spec.rb +++ b/spec/lib/api/v3/users/unpaginated_user_collection_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Users::UnpaginatedUserCollectionRepresenter do let(:users) do @@ -35,13 +35,13 @@ end let(:representer) do described_class.new(users, - self_link: "/api/v3/work_package/1/watchers", + self_link: '/api/v3/work_package/1/watchers', current_user: users.first) end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "work_package/1/watchers", "User" + it_behaves_like 'unpaginated APIv3 collection', 3, 'work_package/1/watchers', 'User' end end diff --git a/spec/lib/api/v3/users/user_collection_representer_spec.rb b/spec/lib/api/v3/users/user_collection_representer_spec.rb index 0595c98cfc3b..44b9655e97b6 100644 --- a/spec/lib/api/v3/users/user_collection_representer_spec.rb +++ b/spec/lib/api/v3/users/user_collection_representer_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Users::UserCollectionRepresenter do - let(:self_base_link) { "/api/v3/users" } - let(:collection_inner_type) { "User" } + let(:self_base_link) { '/api/v3/users' } + let(:collection_inner_type) { 'User' } let(:total) { 3 } let(:page) { 1 } let(:page_size) { 2 } @@ -58,15 +58,15 @@ let(:representer) do described_class.new(users, - self_link: "/api/v3/users", + self_link: '/api/v3/users', per_page: page_size, page:, current_user: users.first) end - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "offset-paginated APIv3 collection" + it_behaves_like 'offset-paginated APIv3 collection' end end diff --git a/spec/lib/api/v3/users/user_representer_spec.rb b/spec/lib/api/v3/users/user_representer_spec.rb index 76344665c759..fe12cac792ad 100644 --- a/spec/lib/api/v3/users/user_representer_spec.rb +++ b/spec/lib/api/v3/users/user_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Users::UserRepresenter do let(:status) { Principal.statuses[:active] } @@ -36,202 +36,202 @@ include API::V3::Utilities::PathHelper - describe "generation" do + describe 'generation' do subject(:generated) { representer.to_json } it do - expect(subject).to include_json("User".to_json).at_path("_type") + expect(subject).to include_json('User'.to_json).at_path('_type') end - context "as regular user" do - it "hides as much information as possible" do - expect(subject).to have_json_path("id") - expect(subject).to have_json_path("name") - - expect(subject).not_to have_json_path("login") - expect(subject).not_to have_json_path("firstName") - expect(subject).not_to have_json_path("lastName") - expect(subject).not_to have_json_path("admin") - expect(subject).not_to have_json_path("updatedAt") - expect(subject).not_to have_json_path("createdAt") - expect(subject).not_to have_json_path("status") - expect(subject).not_to have_json_path("email") - expect(subject).not_to have_json_path("language") + context 'as regular user' do + it 'hides as much information as possible' do + expect(subject).to have_json_path('id') + expect(subject).to have_json_path('name') + + expect(subject).not_to have_json_path('login') + expect(subject).not_to have_json_path('firstName') + expect(subject).not_to have_json_path('lastName') + expect(subject).not_to have_json_path('admin') + expect(subject).not_to have_json_path('updatedAt') + expect(subject).not_to have_json_path('createdAt') + expect(subject).not_to have_json_path('status') + expect(subject).not_to have_json_path('email') + expect(subject).not_to have_json_path('language') end end - context "as the represented user" do + context 'as the represented user' do let(:current_user) { user } - it "shows the information of the user" do - expect(subject).to have_json_path("id") - expect(subject).to have_json_path("name") - expect(subject).to have_json_path("login") - expect(subject).to have_json_path("firstName") - expect(subject).to have_json_path("lastName") - expect(subject).to have_json_path("updatedAt") - expect(subject).to have_json_path("createdAt") - expect(subject).to have_json_path("status") - expect(subject).to have_json_path("email") - expect(subject).to have_json_path("language") - - expect(subject).not_to have_json_path("admin") + it 'shows the information of the user' do + expect(subject).to have_json_path('id') + expect(subject).to have_json_path('name') + expect(subject).to have_json_path('login') + expect(subject).to have_json_path('firstName') + expect(subject).to have_json_path('lastName') + expect(subject).to have_json_path('updatedAt') + expect(subject).to have_json_path('createdAt') + expect(subject).to have_json_path('status') + expect(subject).to have_json_path('email') + expect(subject).to have_json_path('language') + + expect(subject).not_to have_json_path('admin') end end - context "as admin" do + context 'as admin' do let(:current_user) { build_stubbed(:admin) } - it "shows everything" do - expect(subject).to have_json_path("id") - expect(subject).to have_json_path("login") - expect(subject).to have_json_path("firstName") - expect(subject).to have_json_path("lastName") - expect(subject).to have_json_path("name") - expect(subject).to have_json_path("status") - expect(subject).to have_json_path("email") - expect(subject).to have_json_path("admin") - expect(subject).to have_json_path("language") + it 'shows everything' do + expect(subject).to have_json_path('id') + expect(subject).to have_json_path('login') + expect(subject).to have_json_path('firstName') + expect(subject).to have_json_path('lastName') + expect(subject).to have_json_path('name') + expect(subject).to have_json_path('status') + expect(subject).to have_json_path('email') + expect(subject).to have_json_path('admin') + expect(subject).to have_json_path('language') end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { user.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { user.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - describe "email" do + describe 'email' do let(:user) { build_stubbed(:user, status: 1, preference:) } - shared_examples_for "shows the users E-Mail address" do + shared_examples_for 'shows the users E-Mail address' do it do - expect(subject).to be_json_eql(user.mail.to_json).at_path("email") + expect(subject).to be_json_eql(user.mail.to_json).at_path('email') end end - context "if user shows his E-Mail address" do + context 'if user shows his E-Mail address' do let(:preference) { build(:user_preference, hide_mail: false) } - it_behaves_like "shows the users E-Mail address" + it_behaves_like 'shows the users E-Mail address' end - context "if user hides his E-Mail address" do + context 'if user hides his E-Mail address' do let(:preference) { build(:user_preference, hide_mail: true) } - it "does not render the users E-Mail address" do + it 'does not render the users E-Mail address' do expect(subject) - .not_to have_json_path("email") + .not_to have_json_path('email') end - context "if an admin inquires" do + context 'if an admin inquires' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "shows the users E-Mail address" + it_behaves_like 'shows the users E-Mail address' end - context "if the user inquires himself" do + context 'if the user inquires himself' do let(:current_user) { user } - it_behaves_like "shows the users E-Mail address" + it_behaves_like 'shows the users E-Mail address' end end end - describe "status" do + describe 'status' do # as only admin or self can see the status let(:current_user) { user } - it "contains the name of the account status" do - expect(subject).to be_json_eql("active".to_json).at_path("status") + it 'contains the name of the account status' do + expect(subject).to be_json_eql('active'.to_json).at_path('status') end end - describe "_links" do - it "links to self" do - expect(subject).to have_json_path("_links/self/href") + describe '_links' do + it 'links to self' do + expect(subject).to have_json_path('_links/self/href') end - describe "showUser" do - it_behaves_like "has an untitled link" do - let(:link) { "showUser" } + describe 'showUser' do + it_behaves_like 'has an untitled link' do + let(:link) { 'showUser' } let(:href) { "/users/#{user.id}" } end - context "with a locked user" do + context 'with a locked user' do let(:status) { Principal.statuses[:locked] } - it_behaves_like "has no link" do - let(:link) { "showUser" } + it_behaves_like 'has no link' do + let(:link) { 'showUser' } end end end - context "when regular current_user" do - it "has no lock-related links" do - expect(subject).not_to have_json_path("_links/lock/href") - expect(subject).not_to have_json_path("_links/unlock/href") - expect(subject).not_to have_json_path("_links/update/href") + context 'when regular current_user' do + it 'has no lock-related links' do + expect(subject).not_to have_json_path('_links/lock/href') + expect(subject).not_to have_json_path('_links/unlock/href') + expect(subject).not_to have_json_path('_links/update/href') end end - context "when current_user is admin" do + context 'when current_user is admin' do let(:current_user) { build_stubbed(:admin) } - it "links to lock and update" do - expect(subject).to have_json_path("_links/lock/href") - expect(subject).to have_json_path("_links/updateImmediately/href") + it 'links to lock and update' do + expect(subject).to have_json_path('_links/lock/href') + expect(subject).to have_json_path('_links/updateImmediately/href') end - context "when account is locked" do - it "links to unlock" do + context 'when account is locked' do + it 'links to unlock' do user.lock - expect(subject).to have_json_path("_links/unlock/href") + expect(subject).to have_json_path('_links/unlock/href') end end - context "when deletion is allowed" do + context 'when deletion is allowed' do before do allow(Users::DeleteContract).to receive(:deletion_allowed?) .with(user, current_user) .and_return(true) end - it "links to delete" do - expect(subject).to have_json_path("_links/delete/href") + it 'links to delete' do + expect(subject).to have_json_path('_links/delete/href') end end end - context "when deletion is allowed" do + context 'when deletion is allowed' do before do allow(Users::DeleteContract).to receive(:deletion_allowed?) .with(user, current_user) .and_return(true) end - it "links to delete" do - expect(subject).to have_json_path("_links/delete/href") + it 'links to delete' do + expect(subject).to have_json_path('_links/delete/href') end end - context "when deletion is not allowed" do + context 'when deletion is not allowed' do before do allow(Users::DeleteContract).to receive(:deletion_allowed?) .with(user, current_user) .and_return(false) end - it "does not link to delete" do - expect(subject).not_to have_json_path("_links/delete/href") + it 'does not link to delete' do + expect(subject).not_to have_json_path('_links/delete/href') end end - describe "memberships" do + describe 'memberships' do before do mock_permissions_for(current_user) do |mock| mock.allow_in_project *permissions, project: build_stubbed(:project) # any project @@ -239,44 +239,44 @@ end let(:href) do - filters = [{ "principal" => { - "operator" => "=", - "values" => [user.id.to_s] + filters = [{ 'principal' => { + 'operator' => '=', + 'values' => [user.id.to_s] } }] api_v3_paths.path_for(:memberships, filters:) end - context "if the user has the :view_members permissions" do + context 'if the user has the :view_members permissions' do let(:permissions) { [:view_members] } - it_behaves_like "has a titled link" do - let(:link) { "memberships" } + it_behaves_like 'has a titled link' do + let(:link) { 'memberships' } let(:title) { I18n.t(:label_membership_plural) } end end - context "if the user has the :manage_members permissions" do + context 'if the user has the :manage_members permissions' do let(:permissions) { [:manage_members] } - it_behaves_like "has a titled link" do - let(:link) { "memberships" } + it_behaves_like 'has a titled link' do + let(:link) { 'memberships' } let(:title) { I18n.t(:label_membership_plural) } end end - context "if the user lacks permissions" do + context 'if the user lacks permissions' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "memberships" } + it_behaves_like 'has no link' do + let(:link) { 'memberships' } end end end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do allow(OpenProject::Cache) .to receive(:fetch) .and_call_original @@ -288,7 +288,7 @@ .with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let(:auth_source) { build_stubbed(:ldap_auth_source) } let(:former_cache_key) { representer.json_cache_key } @@ -298,53 +298,53 @@ former_cache_key end - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Users", "UserRepresenter") + .to include('API', 'V3', 'Users', 'UserRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the user is updated" do + it 'changes when the user is updated' do user.updated_at = 20.seconds.from_now expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when user format setting changes" do + it 'changes when user format setting changes' do allow(Setting) .to receive(:user_format) - .and_return "something else" + .and_return 'something else' expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the avatars plugin settings change" do + it 'changes when the avatars plugin settings change' do allow(Setting) .to receive(:plugin_openproject_avatars) - .and_return "something else" + .and_return 'something else' expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the protocol settings change" do + it 'changes when the protocol settings change' do allow(Setting) .to receive(:protocol) - .and_return "something else" + .and_return 'something else' expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the user's auth_source is updated" do + it 'changes when the user\'s auth_source is updated' do user.ldap_auth_source.updated_at = 20.seconds.from_now expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/users/user_sql_representer_rendering_spec.rb b/spec/lib/api/v3/users/user_sql_representer_rendering_spec.rb index f760b6052e16..e2e26cdc67ed 100644 --- a/spec/lib/api/v3/users/user_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/users/user_sql_representer_rendering_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Users::UserSqlRepresenter, "rendering" do +RSpec.describe API::V3::Users::UserSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do @@ -45,13 +45,13 @@ let(:rendered_user) { current_user } - let(:select) { { "*" => {} } } + let(:select) { { '*' => {} } } current_user do create(:user) end - context "when rendering all supported properties" do + context 'when rendering all supported properties' do let(:expected) do { _type: "User", @@ -68,15 +68,15 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - describe "name property" do - shared_examples_for "name property depending on user format setting" do - let(:select) { { "name" => {} } } + describe 'name property' do + shared_examples_for 'name property depending on user format setting' do + let(:select) { { 'name' => {} } } let(:expected) do { @@ -84,38 +84,38 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - context "when user_format is set to firstname", with_settings: { user_format: :firstname } do - it_behaves_like "name property depending on user format setting" + context 'when user_format is set to firstname', with_settings: { user_format: :firstname } do + it_behaves_like 'name property depending on user format setting' end - context "when user_format is set to lastname_firstname", with_settings: { user_format: :lastname_firstname } do - it_behaves_like "name property depending on user format setting" + context 'when user_format is set to lastname_firstname', with_settings: { user_format: :lastname_firstname } do + it_behaves_like 'name property depending on user format setting' end - context "when user_format is set to lastname_coma_firstname", with_settings: { user_format: :lastname_coma_firstname } do - it_behaves_like "name property depending on user format setting" + context 'when user_format is set to lastname_coma_firstname', with_settings: { user_format: :lastname_coma_firstname } do + it_behaves_like 'name property depending on user format setting' end - context "when user_format is set to lastname_n_firstname", with_settings: { user_format: :lastname_n_firstname } do - it_behaves_like "name property depending on user format setting" + context 'when user_format is set to lastname_n_firstname', with_settings: { user_format: :lastname_n_firstname } do + it_behaves_like 'name property depending on user format setting' end - context "when user_format is set to username", with_settings: { user_format: :username } do - it_behaves_like "name property depending on user format setting" + context 'when user_format is set to username', with_settings: { user_format: :username } do + it_behaves_like 'name property depending on user format setting' end end - describe "firstname property" do - let(:select) { { "firstname" => {} } } + describe 'firstname property' do + let(:select) { { 'firstname' => {} } } - context "when the user is the current user" do - it "renders the firstname" do + context 'when the user is the current user' do + it 'renders the firstname' do expect(json) .to be_json_eql( { @@ -125,20 +125,20 @@ end end - context "when the user is a user not having manage_user permission" do + context 'when the user is a user not having manage_user permission' do let(:rendered_user) { create(:user) } - it "hides the firstname" do + it 'hides the firstname' do expect(json) .to be_json_eql({}.to_json) end end - context "when the user is a user having manage_user permission" do + context 'when the user is a user having manage_user permission' do let(:current_user) { create(:user, global_permissions: [:manage_user]) } let(:rendered_user) { create(:user) } - it "renders the firstname" do + it 'renders the firstname' do expect(json) .to be_json_eql( { @@ -149,11 +149,11 @@ end end - describe "lastname property" do - let(:select) { { "lastname" => {} } } + describe 'lastname property' do + let(:select) { { 'lastname' => {} } } - context "when the user is the current user" do - it "renders the lastname" do + context 'when the user is the current user' do + it 'renders the lastname' do expect(json) .to be_json_eql( { @@ -163,20 +163,20 @@ end end - context "when the user is a user not having manage_user permission" do + context 'when the user is a user not having manage_user permission' do let(:rendered_user) { create(:user) } - it "hides the lastname" do + it 'hides the lastname' do expect(json) .to be_json_eql({}.to_json) end end - context "when the user is a user having manage_user permission" do + context 'when the user is a user having manage_user permission' do let(:current_user) { create(:user, global_permissions: [:manage_user]) } let(:rendered_user) { create(:user) } - it "renders the lastname" do + it 'renders the lastname' do expect(json) .to be_json_eql( { diff --git a/spec/lib/api/v3/utilities/custom_field_injector_spec.rb b/spec/lib/api/v3/utilities/custom_field_injector_spec.rb index 76d1d23f431c..f388e8c00b0b 100644 --- a/spec/lib/api/v3/utilities/custom_field_injector_spec.rb +++ b/spec/lib/api/v3/utilities/custom_field_injector_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::CustomFieldInjector do include API::V3::Utilities::PathHelper let(:cf_path) { custom_field.attribute_name(:camel_case) } - let(:field_format) { "bool" } + let(:field_format) { 'bool' } let(:custom_field) do build(:custom_field, id: 1, @@ -40,15 +40,15 @@ is_required: true) end - describe "TYPE_MAP" do - it "supports all available formats" do + describe 'TYPE_MAP' do + it 'supports all available formats' do OpenProject::CustomFieldFormat.available_formats.each do |format| expect(described_class::TYPE_MAP[format]).not_to be_nil end end end - describe "#inject_schema" do + describe '#inject_schema' do let(:base_class) { Class.new(API::Decorators::SchemaRepresenter) } let(:modified_class) { described_class.create_schema_representer([custom_field], base_class) } let(:schema_writable) { true } @@ -63,22 +63,22 @@ subject { modified_class.new(schema, current_user: nil, form_embedded: true).to_json } - describe "basic custom field" do + describe 'basic custom field' do let(:path) { cf_path } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { true } let(:has_default) { false } end - context "with schema not writable" do + context 'with schema not writable' do let(:schema_writable) { false } - it_behaves_like "has basic schema properties" do - let(:type) { "Boolean" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Boolean' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { false } @@ -86,17 +86,17 @@ end end - context "with default set" do + context 'with default set' do let(:custom_field) do build(:custom_field, id: 1, - field_format: "string", - default_value: "foo", + field_format: 'string', + default_value: 'foo', is_required: true) end - it_behaves_like "has basic schema properties" do - let(:type) { "String" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { true } @@ -104,47 +104,47 @@ end end - it "indicates no regular expression" do + it 'indicates no regular expression' do expect(subject).not_to have_json_path("#{cf_path}/regularExpression") end # meaning they won't as no values are specified - it_behaves_like "indicates length requirements" + it_behaves_like 'indicates length requirements' - context "when custom field is not required" do + context 'when custom field is not required' do let(:custom_field) { build(:custom_field, is_required: false) } - it "marks the field as not required" do + it 'marks the field as not required' do expect(subject).to be_json_eql(false.to_json).at_path("#{cf_path}/required") end end - context "when custom field has regex" do - let(:custom_field) { build(:custom_field, regexp: "Foo+bar") } + context 'when custom field has regex' do + let(:custom_field) { build(:custom_field, regexp: 'Foo+bar') } - it "renders the regular expression" do - expect(subject).to be_json_eql("Foo+bar".to_json).at_path("#{cf_path}/regularExpression") + it 'renders the regular expression' do + expect(subject).to be_json_eql('Foo+bar'.to_json).at_path("#{cf_path}/regularExpression") end end - context "when custom field has minimum length" do + context 'when custom field has minimum length' do let(:custom_field) { build(:custom_field, min_length: 5) } - it_behaves_like "indicates length requirements" do + it_behaves_like 'indicates length requirements' do let(:min_length) { 5 } end end - context "when custom field has maximum length" do + context 'when custom field has maximum length' do let(:custom_field) { build(:custom_field, max_length: 5) } - it_behaves_like "indicates length requirements" do + it_behaves_like 'indicates length requirements' do let(:max_length) { 5 } end end end - describe "version custom field" do + describe 'version custom field' do let(:custom_field) do build(:version_wp_custom_field, is_required: true) @@ -161,34 +161,34 @@ allow(API::V3::Versions::VersionRepresenter).to receive(:create).and_return(double) end - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { cf_path } - let(:type) { "Version" } + let(:type) { 'Version' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "with schema not writable" do + context 'with schema not writable' do let(:schema_writable) { false } - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { cf_path } - let(:type) { "Version" } + let(:type) { 'Version' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end end - it_behaves_like "links to allowed values directly" do + it_behaves_like 'links to allowed values directly' do let(:path) { cf_path } let(:hrefs) { assignable_versions.map { |version| api_v3_paths.version version.id } } end - it "embeds allowed values" do + it 'embeds allowed values' do # N.B. we do not use the stricter 'links to and embeds allowed values directly' helper # because this would not allow us to easily mock the VersionRepresenter away expect(subject) @@ -197,7 +197,7 @@ end end - describe "list custom field" do + describe 'list custom field' do before do allow(schema) .to receive(:assignable_custom_field_values) @@ -213,31 +213,31 @@ ) end - let(:values) { ["foo", "bar", "baz"] } + let(:values) { ['foo', 'bar', 'baz'] } - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { cf_path } - let(:type) { "CustomOption" } + let(:type) { 'CustomOption' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "with schema not writable" do + context 'with schema not writable' do let(:schema_writable) { false } - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { cf_path } - let(:type) { "CustomOption" } + let(:type) { 'CustomOption' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end end - it_behaves_like "links to and embeds allowed values directly" do + it_behaves_like 'links to and embeds allowed values directly' do let(:path) { cf_path } let(:hrefs) do custom_field.possible_values.map do |value| @@ -247,42 +247,42 @@ end end - describe "user custom field" do + describe 'user custom field' do let(:custom_field) do build(:custom_field, - field_format: "user", + field_format: 'user', is_required: true) end - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { cf_path } - let(:type) { "User" } + let(:type) { 'User' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "with schema not writable" do + context 'with schema not writable' do let(:schema_writable) { false } - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:path) { cf_path } - let(:type) { "User" } + let(:type) { 'User' } let(:name) { custom_field.name } let(:required) { true } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end end - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:path) { cf_path } let(:href) do params = [ - { status: { operator: "!", values: [Principal.statuses[:locked].to_s] } }, - { type: { operator: "=", values: %w[User Group PlaceholderUser] } }, - { member: { operator: "=", values: [schema.project_id.to_s] } } + { status: { operator: '!', values: [Principal.statuses[:locked].to_s] } }, + { type: { operator: '=', values: %w[User Group PlaceholderUser] } }, + { member: { operator: '=', values: [schema.project_id.to_s] } } ] query = CGI.escape(JSON.dump(params)) @@ -292,7 +292,7 @@ end end - describe "user custom field on new project" do + describe 'user custom field on new project' do let(:schema) do instance_double(API::V3::WorkPackages::Schema::SpecificWorkPackageSchema, id: nil, @@ -301,17 +301,17 @@ end let(:custom_field) do build(:custom_field, - field_format: "user", + field_format: 'user', is_required: true) end - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:path) { cf_path } let(:href) do params = [ - { status: { operator: "!", values: [Principal.statuses[:locked].to_s] } }, - { type: { operator: "=", values: %w[User Group PlaceholderUser] } }, - { member: { operator: "*", values: [] } } + { status: { operator: '!', values: [Principal.statuses[:locked].to_s] } }, + { type: { operator: '=', values: %w[User Group PlaceholderUser] } }, + { member: { operator: '*', values: [] } } ] query = CGI.escape(JSON.dump(params)) @@ -322,13 +322,13 @@ end end - describe "#inject_value" do - shared_examples_for "injects property custom field" do - it "has a readable value" do + describe '#inject_value' do + shared_examples_for 'injects property custom field' do + it 'has a readable value' do expect(subject).to be_json_eql(json_value.to_json).at_path(cf_path) end - it "on writing it sets on the represented" do + it 'on writing it sets on the represented' do allow(represented).to receive(custom_field.attribute_setter) modified_class .new(represented, current_user: nil) @@ -349,14 +349,14 @@ def self.custom_field_injector_config end let(:modified_class) { described_class.create_value_representer([custom_field], base_class) } let(:represented) do - double("represented", + double('represented', available_custom_fields: [custom_field], custom_field.attribute_name => value) end let(:custom_value) { instance_double(CustomValue, value: raw_value, typed_value:) } let(:raw_value) { nil } let(:typed_value) { raw_value } - let(:value) { "" } + let(:value) { '' } let(:current_user) { build(:user) } subject { modified_class.new(represented, current_user:, embed_links: true).to_json } @@ -366,99 +366,99 @@ def self.custom_field_injector_config allow(represented).to receive(:custom_value_for).with(custom_field).and_return(custom_value) end - context "for user custom field" do + context 'for user custom field' do let(:raw_value) { value.id.to_s } let(:typed_value) { value } - let(:field_format) { "user" } + let(:field_format) { 'user' } %w[user group placeholder_user].each do |type| describe "#{type} assignment" do let(:value) { build(type, id: 2) } - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { cf_path } let(:href) { api_v3_paths.send type, 2 } let(:title) { value.name } end - it "has the user embedded" do + it 'has the user embedded' do expect(subject).to be_json_eql(type.classify.to_json).at_path("_embedded/#{cf_path}/_type") expect(subject).to be_json_eql(value.name.to_json).at_path("_embedded/#{cf_path}/name") end end end - context "when value is nil" do + context 'when value is nil' do let(:value) { nil } - let(:raw_value) { "" } + let(:raw_value) { '' } - it_behaves_like "has an empty link" do + it_behaves_like 'has an empty link' do let(:link) { cf_path } end end end - context "for version custom field" do + context 'for version custom field' do let(:value) { build_stubbed(:version, id: 2) } let(:raw_value) { value.id.to_s } let(:typed_value) { value } - let(:field_format) { "version" } + let(:field_format) { 'version' } - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { cf_path } let(:href) { api_v3_paths.version 2 } let(:title) { value.name } end - it "has the version embedded" do - expect(subject).to be_json_eql("Version".to_json).at_path("_embedded/#{cf_path}/_type") + it 'has the version embedded' do + expect(subject).to be_json_eql('Version'.to_json).at_path("_embedded/#{cf_path}/_type") expect(subject).to be_json_eql(value.name.to_json).at_path("_embedded/#{cf_path}/name") end - context "when value is nil" do + context 'when value is nil' do let(:value) { nil } - let(:raw_value) { "" } + let(:raw_value) { '' } - it_behaves_like "has an empty link" do + it_behaves_like 'has an empty link' do let(:link) { cf_path } end end end - context "for list custom field" do + context 'for list custom field' do let(:value) { build_stubbed(:custom_option) } let(:typed_value) { value.value } let(:raw_value) { value.id.to_s } - let(:field_format) { "list" } + let(:field_format) { 'list' } - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { cf_path } let(:href) { api_v3_paths.custom_option(value.id) } let(:title) { value.value } end - context "when value is nil" do + context 'when value is nil' do let(:value) { nil } - let(:raw_value) { "" } - let(:typed_value) { "" } + let(:raw_value) { '' } + let(:typed_value) { '' } - it_behaves_like "has an empty link" do + it_behaves_like 'has an empty link' do let(:link) { cf_path } end end - context "when value is some invalid string" do - let(:value) { "some invalid string" } - let(:raw_value) { "some invalid string" } - let(:typed_value) { "some invalid string not found" } + context 'when value is some invalid string' do + let(:value) { 'some invalid string' } + let(:raw_value) { 'some invalid string' } + let(:typed_value) { 'some invalid string not found' } - it "has an empty href" do + it 'has an empty href' do expect(subject) .to be_json_eql(nil.to_json) .at_path("_links/#{cf_path}/href") end - it "has the invalid value as title" do + it 'has the invalid value as title' do expect(subject) .to be_json_eql(typed_value.to_json) .at_path("_links/#{cf_path}/title") @@ -466,58 +466,58 @@ def self.custom_field_injector_config end end - context "for string custom field" do - it_behaves_like "injects property custom field" do - let(:field_format) { "string" } - let(:value) { "Foobar" } - let(:json_value) { "Foobar" } + context 'for string custom field' do + it_behaves_like 'injects property custom field' do + let(:field_format) { 'string' } + let(:value) { 'Foobar' } + let(:json_value) { 'Foobar' } let(:expected_setter) { json_value } end end - context "for int custom field" do - it_behaves_like "injects property custom field" do - let(:field_format) { "int" } + context 'for int custom field' do + it_behaves_like 'injects property custom field' do + let(:field_format) { 'int' } let(:value) { 42 } let(:json_value) { 42 } let(:expected_setter) { json_value } end end - context "for float custom field" do - it_behaves_like "injects property custom field" do - let(:field_format) { "float" } + context 'for float custom field' do + it_behaves_like 'injects property custom field' do + let(:field_format) { 'float' } let(:value) { 3.14 } let(:json_value) { 3.14 } let(:expected_setter) { json_value } end end - context "for bool custom field" do - it_behaves_like "injects property custom field" do - let(:field_format) { "bool" } + context 'for bool custom field' do + it_behaves_like 'injects property custom field' do + let(:field_format) { 'bool' } let(:value) { true } let(:json_value) { true } let(:expected_setter) { json_value } end end - context "for date custom field" do - it_behaves_like "injects property custom field" do - let(:field_format) { "date" } + context 'for date custom field' do + it_behaves_like 'injects property custom field' do + let(:field_format) { 'date' } let(:value) { Date.current } let(:json_value) { value.to_date.iso8601 } let(:expected_setter) { json_value } end end - context "for text custom field" do - it_behaves_like "injects property custom field" do - let(:field_format) { "text" } - let(:value) { "**Foobar**" } + context 'for text custom field' do + it_behaves_like 'injects property custom field' do + let(:field_format) { 'text' } + let(:value) { '**Foobar**' } let(:json_value) do { - format: "markdown", + format: 'markdown', raw: value, html: '

    Foobar

    ' } @@ -527,7 +527,7 @@ def self.custom_field_injector_config end end - describe "#inject_patchable_link_value" do + describe '#inject_patchable_link_value' do let(:base_class) do Class.new(API::Decorators::Single) do def self.custom_field_injector_config @@ -539,10 +539,10 @@ def self.custom_field_injector_config described_class.create_value_representer([custom_field], base_class) end let(:represented) do - double("represented", available_custom_fields: [custom_field]) + double('represented', available_custom_fields: [custom_field]) end let(:custom_value) { instance_double(CustomValue, value:, typed_value:) } - let(:value) { "" } + let(:value) { '' } let(:user) { build_stubbed(:user) } let(:typed_value) { value } @@ -553,15 +553,15 @@ def self.custom_field_injector_config allow(represented).to receive(custom_field.attribute_getter).and_return(typed_value) end - context "for reading" do - let(:value) { "2" } - let(:field_format) { "user" } + context 'for reading' do + let(:value) { '2' } + let(:field_format) { 'user' } %w[user group placeholder_user].each do |type| describe "#{type} reading" do let(:typed_value) { build(type, id: 2) } - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { cf_path } let(:href) { api_v3_paths.send type, 2 } let(:title) { typed_value.name } @@ -569,25 +569,25 @@ def self.custom_field_injector_config end end - context "when value is nil" do + context 'when value is nil' do let(:value) { nil } let(:typed_value) { nil } - it_behaves_like "has an empty link" do + it_behaves_like 'has an empty link' do let(:link) { cf_path } end end end - context "for writing" do + context 'for writing' do let(:value) { nil } - let(:field_format) { "user" } + let(:field_format) { 'user' } %w[user group placeholder_user].each do |type| it "accepts a valid link of type #{type}" do path = api_v3_paths.send type, 2 json = { cf_path => { href: path } }.to_json - expected = ["2"] + expected = ['2'] allow(represented).to receive(custom_field.attribute_setter) modified_class.new(represented, current_user: nil).from_json(json) @@ -596,7 +596,7 @@ def self.custom_field_injector_config end end - it "accepts an empty link" do + it 'accepts an empty link' do json = { cf_path => { href: nil } }.to_json expected = [] diff --git a/spec/lib/api/v3/utilities/date_time_formatter_spec.rb b/spec/lib/api/v3/utilities/date_time_formatter_spec.rb index e8c0a1787381..54e9430fdfab 100644 --- a/spec/lib/api/v3/utilities/date_time_formatter_spec.rb +++ b/spec/lib/api/v3/utilities/date_time_formatter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::DateTimeFormatter do subject { described_class } @@ -34,128 +34,128 @@ let(:date) { Time.zone.today } let(:datetime) { DateTime.now } - shared_examples_for "can format nil" do - it "accepts nil if asked to" do + shared_examples_for 'can format nil' do + it 'accepts nil if asked to' do expect(subject.send(method, nil, allow_nil: true)).to be_nil end - it "returns usual result for non-nils" do + it 'returns usual result for non-nils' do expected = subject.send(method, input) expect(subject.send(method, input, allow_nil: true)).to eq(expected) end end - shared_examples_for "can parse nil" do - it "accepts nil if asked to" do - expect(subject.send(method, nil, "prop", allow_nil: true)).to be_nil + shared_examples_for 'can parse nil' do + it 'accepts nil if asked to' do + expect(subject.send(method, nil, 'prop', allow_nil: true)).to be_nil end - it "returns usual result for non-nils" do - expected = subject.send(method, input, "prop") - expect(subject.send(method, input, "prop", allow_nil: true)).to eq(expected) + it 'returns usual result for non-nils' do + expected = subject.send(method, input, 'prop') + expect(subject.send(method, input, 'prop', allow_nil: true)).to eq(expected) end end - shared_examples_for "rejects durations with parsing errors" do - it "rejects parsing non sense" do + shared_examples_for 'rejects durations with parsing errors' do + it 'rejects parsing non sense' do expect do - subject.send(method, "foo", "prop") + subject.send(method, 'foo', 'prop') end.to raise_error(API::Errors::PropertyFormatError) end - it "rejects parsing pure number strings" do + it 'rejects parsing pure number strings' do expect do - subject.send(method, "5", "prop") + subject.send(method, '5', 'prop') end.to raise_error(API::Errors::PropertyFormatError) end - it "rejects parsing pure numbers" do + it 'rejects parsing pure numbers' do expect do - subject.send(method, 5, "prop") + subject.send(method, 5, 'prop') end.to raise_error(API::Errors::PropertyFormatError) end end - describe "format_date" do - it "formats dates" do + describe 'format_date' do + it 'formats dates' do expect(subject.format_date(date)).to eq(date.iso8601) end - it "formats datetimes" do + it 'formats datetimes' do expect(subject.format_date(datetime)).to eq(datetime.to_date.iso8601) end - it_behaves_like "can format nil" do + it_behaves_like 'can format nil' do let(:method) { :format_date } let(:input) { date } end end - describe "parse_date" do - it "parses ISO 8601 dates" do - expect(subject.parse_date(date.iso8601, "prop")).to eq(date) + describe 'parse_date' do + it 'parses ISO 8601 dates' do + expect(subject.parse_date(date.iso8601, 'prop')).to eq(date) end - it "rejects parsing non ISO date formats" do - bad_format = date.strftime("%d.%m.%Y") + it 'rejects parsing non ISO date formats' do + bad_format = date.strftime('%d.%m.%Y') expect do - subject.parse_date(bad_format, "prop") + subject.parse_date(bad_format, 'prop') end.to raise_error(API::Errors::PropertyFormatError) do |error| # rubocop:disable Style/MultilineBlockChain expect(error.message).to include("Invalid format for property 'prop'") expect(error.message).to include("Expected format like 'YYYY-MM-DD (ISO 8601 date only)'") end end - it "rejects parsing ISO 8601 date + time formats" do + it 'rejects parsing ISO 8601 date + time formats' do bad_format = datetime.iso8601 expect do - subject.parse_date(bad_format, "prop") + subject.parse_date(bad_format, 'prop') end.to raise_error(API::Errors::PropertyFormatError) do |error| # rubocop:disable Style/MultilineBlockChain expect(error.message).to include("Invalid format for property 'prop'") expect(error.message).to include("Expected format like 'YYYY-MM-DD (ISO 8601 date only)'") end end - it_behaves_like "can parse nil" do + it_behaves_like 'can parse nil' do let(:method) { :parse_date } let(:input) { date.iso8601 } end end - describe "format_datetime" do - it "formats dates" do + describe 'format_datetime' do + it 'formats dates' do expect(subject.format_datetime(date)).to eq(date.to_datetime.utc.iso8601(3)) end - it "formats datetimes" do + it 'formats datetimes' do expect(subject.format_datetime(datetime)).to eq(datetime.utc.iso8601(3)) end - it_behaves_like "can format nil" do + it_behaves_like 'can format nil' do let(:method) { :format_datetime } let(:input) { datetime } end end - describe "parse_datetime" do - it "parses ISO 8601 datetimes" do - expect(subject.parse_datetime(datetime.utc.iso8601(9), "prop")).to eq(datetime) - expect(subject.parse_datetime("1999-12-31T14:15:16", "prop")) + describe 'parse_datetime' do + it 'parses ISO 8601 datetimes' do + expect(subject.parse_datetime(datetime.utc.iso8601(9), 'prop')).to eq(datetime) + expect(subject.parse_datetime('1999-12-31T14:15:16', 'prop')) .to eq(DateTime.new(1999, 12, 31, 14, 15, 16)) - expect(subject.parse_datetime("1999-12-31", "prop")) + expect(subject.parse_datetime('1999-12-31', 'prop')) .to eq(DateTime.new(1999, 12, 31, 0, 0, 0)) - expect(subject.parse_datetime("1999-12-31T14:15:16Z", "prop")) - .to eq(DateTime.new(1999, 12, 31, 14, 15, 16, "+00:00")) - expect(subject.parse_datetime("1999-12-31T14:15:16+02:30", "prop")) - .to eq(DateTime.new(1999, 12, 31, 11, 45, 16, "+00:00")) - expect(subject.parse_datetime("1999-12-31T14:15:16.4242", "prop")) + expect(subject.parse_datetime('1999-12-31T14:15:16Z', 'prop')) + .to eq(DateTime.new(1999, 12, 31, 14, 15, 16, '+00:00')) + expect(subject.parse_datetime('1999-12-31T14:15:16+02:30', 'prop')) + .to eq(DateTime.new(1999, 12, 31, 11, 45, 16, '+00:00')) + expect(subject.parse_datetime('1999-12-31T14:15:16.4242', 'prop')) .to eq(DateTime.new(1999, 12, 31, 14, 15, 16.4242)) end - it "rejects parsing non ISO date formats" do - bad_format = datetime.strftime("%d.%m.%Y") + it 'rejects parsing non ISO date formats' do + bad_format = datetime.strftime('%d.%m.%Y') expect do - subject.parse_datetime(bad_format, "prop") + subject.parse_datetime(bad_format, 'prop') end.to raise_error(API::Errors::PropertyFormatError) do |error| # rubocop:disable Style/MultilineBlockChain expect(error.message).to include("Invalid format for property 'prop'") expect(error.message).to include("Expected format like 'YYYY-MM-DDThh:mm:ss[.lll][+hh:mm] " + @@ -163,101 +163,101 @@ end end - it_behaves_like "can parse nil" do + it_behaves_like 'can parse nil' do let(:method) { :parse_datetime } let(:input) { datetime.iso8601(9) } end end - describe "format_duration_from_hours" do - it "formats floats" do - expect(subject.format_duration_from_hours(5.0)).to eq("PT5H") + describe 'format_duration_from_hours' do + it 'formats floats' do + expect(subject.format_duration_from_hours(5.0)).to eq('PT5H') end - it "formats fractional floats" do - expect(subject.format_duration_from_hours(5.5)).to eq("PT5H30M") + it 'formats fractional floats' do + expect(subject.format_duration_from_hours(5.5)).to eq('PT5H30M') end - it "includes seconds" do - expect(subject.format_duration_from_hours(5.501)).to eq("PT5H30M3S") + it 'includes seconds' do + expect(subject.format_duration_from_hours(5.501)).to eq('PT5H30M3S') end - it "formats ints" do - expect(subject.format_duration_from_hours(5)).to eq("PT5H") + it 'formats ints' do + expect(subject.format_duration_from_hours(5)).to eq('PT5H') end - it_behaves_like "can format nil" do + it_behaves_like 'can format nil' do let(:method) { :format_duration_from_hours } let(:input) { 5 } end end - describe "parse_duration_to_hours" do - it "parses ISO 8601 durations of full hours" do - expect(subject.parse_duration_to_hours("PT5H", "prop")).to eq(5.0) + describe 'parse_duration_to_hours' do + it 'parses ISO 8601 durations of full hours' do + expect(subject.parse_duration_to_hours('PT5H', 'prop')).to eq(5.0) end - it "parses ISO 8601 durations of fractional hours" do - expect(subject.parse_duration_to_hours("PT5H30M", "prop")).to eq(5.5) + it 'parses ISO 8601 durations of fractional hours' do + expect(subject.parse_duration_to_hours('PT5H30M', 'prop')).to eq(5.5) end - it "parses ISO 8601 durations of days" do - expect(subject.parse_duration_to_hours("P1D", "prop")).to eq(24.0) + it 'parses ISO 8601 durations of days' do + expect(subject.parse_duration_to_hours('P1D', 'prop')).to eq(24.0) end - it_behaves_like "rejects durations with parsing errors" do + it_behaves_like 'rejects durations with parsing errors' do let(:method) { :parse_duration_to_hours } end - it_behaves_like "can parse nil" do + it_behaves_like 'can parse nil' do let(:method) { :parse_duration_to_hours } - let(:input) { "PT5H" } + let(:input) { 'PT5H' } end end - describe "format_duration_from_days" do - it "formats floats" do - expect(subject.format_duration_from_days(5.0)).to eq("P5D") + describe 'format_duration_from_days' do + it 'formats floats' do + expect(subject.format_duration_from_days(5.0)).to eq('P5D') end - it "formats fractional floats" do - expect(subject.format_duration_from_days(5.5)).to eq("P5DT12H") + it 'formats fractional floats' do + expect(subject.format_duration_from_days(5.5)).to eq('P5DT12H') end - it "includes minutes and seconds" do - expect(subject.format_duration_from_days(5.501)).to eq("P5DT12H1M26S") + it 'includes minutes and seconds' do + expect(subject.format_duration_from_days(5.501)).to eq('P5DT12H1M26S') end - it "formats ints" do - expect(subject.format_duration_from_days(5)).to eq("P5D") + it 'formats ints' do + expect(subject.format_duration_from_days(5)).to eq('P5D') end - it_behaves_like "can format nil" do + it_behaves_like 'can format nil' do let(:method) { :format_duration_from_days } let(:input) { 5 } end end - describe "parse_duration_to_days" do - it "parses ISO 8601 durations of full days" do - expect(subject.parse_duration_to_days("P5D", "prop")).to eq(5) + describe 'parse_duration_to_days' do + it 'parses ISO 8601 durations of full days' do + expect(subject.parse_duration_to_days('P5D', 'prop')).to eq(5) end - it "parses ISO 8601 durations of fractional days as whole" do - expect(subject.parse_duration_to_days("P5DT18H30M", "prop")).to eq(5) + it 'parses ISO 8601 durations of fractional days as whole' do + expect(subject.parse_duration_to_days('P5DT18H30M', 'prop')).to eq(5) end - it "parses ISO 8601 durations of hours as 0 days" do - expect(subject.parse_duration_to_days("PT1H30M", "prop")).to eq(0) + it 'parses ISO 8601 durations of hours as 0 days' do + expect(subject.parse_duration_to_days('PT1H30M', 'prop')).to eq(0) end - it_behaves_like "rejects durations with parsing errors" do + it_behaves_like 'rejects durations with parsing errors' do let(:method) { :parse_duration_to_days } end - it_behaves_like "can parse nil" do + it_behaves_like 'can parse nil' do let(:method) { :parse_duration_to_days } - let(:input) { "PT5H" } + let(:input) { 'PT5H' } end end end diff --git a/spec/lib/api/v3/utilities/path_helper_spec.rb b/spec/lib/api/v3/utilities/path_helper_spec.rb index e028b911e9a3..cb9b6c3debe4 100644 --- a/spec/lib/api/v3/utilities/path_helper_spec.rb +++ b/spec/lib/api/v3/utilities/path_helper_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::PathHelper do let(:helper) { Class.new.tap { |c| c.extend(API::V3::Utilities::PathHelper) }.api_v3_paths } - shared_examples_for "path" do |url| - it "provides the path" do + shared_examples_for 'path' do |url| + it 'provides the path' do expect(subject).to match(url) end - it "prepends the sub uri if configured" do + it 'prepends the sub uri if configured' do allow(OpenProject::Configuration).to receive(:rails_relative_url_root) - .and_return("/open_project") + .and_return('/open_project') expect(subject).to match("/open_project#{url}") end @@ -52,623 +52,623 @@ RequestStore.clear! end - shared_examples_for "api v3 path" do |url| - it_behaves_like "path", "/api/v3#{url}" + shared_examples_for 'api v3 path' do |url| + it_behaves_like 'path', "/api/v3#{url}" end - shared_examples_for "index" do |name| + shared_examples_for 'index' do |name| plural_name = name.to_s.pluralize describe "##{plural_name}" do subject { helper.send(plural_name) } - it_behaves_like "api v3 path", "/#{plural_name}" + it_behaves_like 'api v3 path', "/#{plural_name}" end end - shared_examples_for "show" do |name| + shared_examples_for 'show' do |name| describe "##{name}" do subject { helper.send(:"#{name}", 42) } - it_behaves_like "api v3 path", "/#{name.to_s.pluralize}/42" + it_behaves_like 'api v3 path', "/#{name.to_s.pluralize}/42" end end - shared_examples_for "create form" do |name| + shared_examples_for 'create form' do |name| describe "#create_#{name}_form" do subject { helper.send(:"create_#{name}_form") } - it_behaves_like "api v3 path", "/#{name.to_s.pluralize}/form" + it_behaves_like 'api v3 path', "/#{name.to_s.pluralize}/form" end end - shared_examples_for "update form" do |name| + shared_examples_for 'update form' do |name| describe "##{name}_form" do subject { helper.send(:"#{name}_form", 42) } - it_behaves_like "api v3 path", "/#{name.to_s.pluralize}/42/form" + it_behaves_like 'api v3 path', "/#{name.to_s.pluralize}/42/form" end end - shared_examples_for "schema" do |name| + shared_examples_for 'schema' do |name| describe "##{name}_schema" do subject { helper.send(:"#{name}_schema") } - it_behaves_like "api v3 path", "/#{name.to_s.pluralize}/schema" + it_behaves_like 'api v3 path', "/#{name.to_s.pluralize}/schema" end end - shared_examples_for "resource" do |name, except: []| - it_behaves_like("index", name) unless except.include?(:index) - it_behaves_like("show", name) unless except.include?(:show) - it_behaves_like("update form", name) unless except.include?(:update_form) - it_behaves_like("create form", name) unless except.include?(:create_form) - it_behaves_like("schema", name) unless except.include?(:schema) + shared_examples_for 'resource' do |name, except: []| + it_behaves_like('index', name) unless except.include?(:index) + it_behaves_like('show', name) unless except.include?(:show) + it_behaves_like('update form', name) unless except.include?(:update_form) + it_behaves_like('create form', name) unless except.include?(:create_form) + it_behaves_like('schema', name) unless except.include?(:schema) end - describe "#root" do + describe '#root' do subject { helper.root } - it_behaves_like "api v3 path" + it_behaves_like 'api v3 path' end - context "actions paths" do - it_behaves_like "index", :action - it_behaves_like "show", :action + context 'actions paths' do + it_behaves_like 'index', :action + it_behaves_like 'show', :action end - context "activities paths" do - it_behaves_like "index", :activities - it_behaves_like "show", :activity + context 'activities paths' do + it_behaves_like 'index', :activities + it_behaves_like 'show', :activity end - context "attachments paths" do - it_behaves_like "index", :attachment - it_behaves_like "show", :attachment + context 'attachments paths' do + it_behaves_like 'index', :attachment + it_behaves_like 'show', :attachment - describe "#attachment_content" do + describe '#attachment_content' do subject { helper.attachment_content 1 } - it_behaves_like "api v3 path", "/attachments/1/content" + it_behaves_like 'api v3 path', '/attachments/1/content' end - describe "#attachments_by_post" do + describe '#attachments_by_post' do subject { helper.attachments_by_post 1 } - it_behaves_like "api v3 path", "/posts/1/attachments" + it_behaves_like 'api v3 path', '/posts/1/attachments' end - describe "#attachments_by_work_package" do + describe '#attachments_by_work_package' do subject { helper.attachments_by_work_package 1 } - it_behaves_like "api v3 path", "/work_packages/1/attachments" + it_behaves_like 'api v3 path', '/work_packages/1/attachments' end - describe "#attachments_by_wiki_page" do + describe '#attachments_by_wiki_page' do subject { helper.attachments_by_wiki_page 1 } - it_behaves_like "api v3 path", "/wiki_pages/1/attachments" + it_behaves_like 'api v3 path', '/wiki_pages/1/attachments' end end - context "category paths" do - it_behaves_like "index", :category - it_behaves_like "show", :category + context 'category paths' do + it_behaves_like 'index', :category + it_behaves_like 'show', :category - describe "#categories_by_project" do + describe '#categories_by_project' do subject { helper.categories_by_project 42 } - it_behaves_like "api v3 path", "/projects/42/categories" + it_behaves_like 'api v3 path', '/projects/42/categories' end end - context "capabilities paths" do - it_behaves_like "index", :capability - it_behaves_like "show", :capability + context 'capabilities paths' do + it_behaves_like 'index', :capability + it_behaves_like 'show', :capability - describe "#capabilties_contexts_global" do + describe '#capabilties_contexts_global' do subject { helper.capabilities_contexts_global } - it_behaves_like "api v3 path", "/capabilities/contexts/global" + it_behaves_like 'api v3 path', '/capabilities/contexts/global' end end - context "configuration paths" do - describe "#configuration" do + context 'configuration paths' do + describe '#configuration' do subject { helper.configuration } - it_behaves_like "api v3 path", "/configuration" + it_behaves_like 'api v3 path', '/configuration' end end - context "custom action paths" do - it_behaves_like "show", :custom_action + context 'custom action paths' do + it_behaves_like 'show', :custom_action - describe "#custom_action_execute" do + describe '#custom_action_execute' do subject { helper.custom_action_execute 42 } - it_behaves_like "api v3 path", "/custom_actions/42/execute" + it_behaves_like 'api v3 path', '/custom_actions/42/execute' end - it_behaves_like "show", :custom_option + it_behaves_like 'show', :custom_option end - describe "memberships paths" do - it_behaves_like "resource", :membership + describe 'memberships paths' do + it_behaves_like 'resource', :membership - describe "#memberships_available_projects" do + describe '#memberships_available_projects' do subject { helper.memberships_available_projects } - it_behaves_like "api v3 path", "/memberships/available_projects" + it_behaves_like 'api v3 path', '/memberships/available_projects' end end - describe "messages paths" do - it_behaves_like "index", :message - it_behaves_like "show", :message + describe 'messages paths' do + it_behaves_like 'index', :message + it_behaves_like 'show', :message end - describe "news paths" do - describe "#newses" do + describe 'news paths' do + describe '#newses' do subject { helper.newses } - it_behaves_like "api v3 path", "/news" + it_behaves_like 'api v3 path', '/news' end - it_behaves_like "show", :news + it_behaves_like 'show', :news end - describe "notifications paths" do - it_behaves_like "index", :notifications - it_behaves_like "show", :notification + describe 'notifications paths' do + it_behaves_like 'index', :notifications + it_behaves_like 'show', :notification - describe "#notification_bulk_read_ian" do + describe '#notification_bulk_read_ian' do subject { helper.notification_bulk_read_ian } - it_behaves_like "api v3 path", "/notifications/read_ian" + it_behaves_like 'api v3 path', '/notifications/read_ian' end - describe "#notification_bulk_unread_ian" do + describe '#notification_bulk_unread_ian' do subject { helper.notification_bulk_unread_ian } - it_behaves_like "api v3 path", "/notifications/unread_ian" + it_behaves_like 'api v3 path', '/notifications/unread_ian' end - describe "#notification_read_ian" do + describe '#notification_read_ian' do subject { helper.notification_read_ian(42) } - it_behaves_like "api v3 path", "/notifications/42/read_ian" + it_behaves_like 'api v3 path', '/notifications/42/read_ian' end - describe "#notification_unread_ian" do + describe '#notification_unread_ian' do subject { helper.notification_unread_ian(42) } - it_behaves_like "api v3 path", "/notifications/42/unread_ian" + it_behaves_like 'api v3 path', '/notifications/42/unread_ian' end - describe "#notification_detail" do + describe '#notification_detail' do subject { helper.notification_detail(42, 0) } - it_behaves_like "api v3 path", "/notifications/42/details/0" + it_behaves_like 'api v3 path', '/notifications/42/details/0' end end - describe "markup paths" do - describe "#render_markup" do - subject { helper.render_markup(link: "link-ish") } + describe 'markup paths' do + describe '#render_markup' do + subject { helper.render_markup(link: 'link-ish') } - it_behaves_like "api v3 path", "/render/markdown?context=link-ish" + it_behaves_like 'api v3 path', '/render/markdown?context=link-ish' - context "no link given" do + context 'no link given' do subject { helper.render_markup } - it { is_expected.to eql("/api/v3/render/markdown") } + it { is_expected.to eql('/api/v3/render/markdown') } end end end - describe "placeholder_users path" do - it_behaves_like "index", :placeholder_user - it_behaves_like "show", :placeholder_user + describe 'placeholder_users path' do + it_behaves_like 'index', :placeholder_user + it_behaves_like 'show', :placeholder_user end - describe "posts paths" do - it_behaves_like "index", :post - it_behaves_like "show", :post + describe 'posts paths' do + it_behaves_like 'index', :post + it_behaves_like 'show', :post end - describe "principals paths" do - it_behaves_like "index", :principals + describe 'principals paths' do + it_behaves_like 'index', :principals end - describe "priorities paths" do - it_behaves_like "index", :priority - it_behaves_like "show", :priority + describe 'priorities paths' do + it_behaves_like 'index', :priority + it_behaves_like 'show', :priority end - describe "projects paths" do - it_behaves_like "resource", :project + describe 'projects paths' do + it_behaves_like 'resource', :project - describe "#projects_available_parents" do + describe '#projects_available_parents' do subject { helper.projects_available_parents } - it_behaves_like "api v3 path", "/projects/available_parent_projects" + it_behaves_like 'api v3 path', '/projects/available_parent_projects' end end - describe "project status paths" do - it_behaves_like "show", :project_status + describe 'project status paths' do + it_behaves_like 'show', :project_status end - describe "query paths" do - it_behaves_like "resource", :query + describe 'query paths' do + it_behaves_like 'resource', :query - describe "#query_default" do + describe '#query_default' do subject { helper.query_default } - it_behaves_like "api v3 path", "/queries/default" + it_behaves_like 'api v3 path', '/queries/default' end - describe "#query_project_default" do + describe '#query_project_default' do subject { helper.query_project_default(42) } - it_behaves_like "api v3 path", "/projects/42/queries/default" + it_behaves_like 'api v3 path', '/projects/42/queries/default' end - describe "#query_star" do + describe '#query_star' do subject { helper.query_star 1 } - it_behaves_like "api v3 path", "/queries/1/star" + it_behaves_like 'api v3 path', '/queries/1/star' end - describe "#query_unstar" do + describe '#query_unstar' do subject { helper.query_unstar 1 } - it_behaves_like "api v3 path", "/queries/1/unstar" + it_behaves_like 'api v3 path', '/queries/1/unstar' end - describe "#query_column" do - subject { helper.query_column "updated_at" } + describe '#query_column' do + subject { helper.query_column 'updated_at' } - it_behaves_like "api v3 path", "/queries/columns/updated_at" + it_behaves_like 'api v3 path', '/queries/columns/updated_at' end - describe "#query_group_by" do - subject { helper.query_group_by "status" } + describe '#query_group_by' do + subject { helper.query_group_by 'status' } - it_behaves_like "api v3 path", "/queries/group_bys/status" + it_behaves_like 'api v3 path', '/queries/group_bys/status' end - describe "#query_sort_by" do - subject { helper.query_sort_by "status", "desc" } + describe '#query_sort_by' do + subject { helper.query_sort_by 'status', 'desc' } - it_behaves_like "api v3 path", "/queries/sort_bys/status-desc" + it_behaves_like 'api v3 path', '/queries/sort_bys/status-desc' end - describe "#query_filter" do - subject { helper.query_filter "status" } + describe '#query_filter' do + subject { helper.query_filter 'status' } - it_behaves_like "api v3 path", "/queries/filters/status" + it_behaves_like 'api v3 path', '/queries/filters/status' end - describe "#query_filter_instance_schemas" do + describe '#query_filter_instance_schemas' do subject { helper.query_filter_instance_schemas } - it_behaves_like "api v3 path", "/queries/filter_instance_schemas" + it_behaves_like 'api v3 path', '/queries/filter_instance_schemas' end - describe "#query_filter_instance_schema" do - subject { helper.query_filter_instance_schema("bogus") } + describe '#query_filter_instance_schema' do + subject { helper.query_filter_instance_schema('bogus') } - it_behaves_like "api v3 path", "/queries/filter_instance_schemas/bogus" + it_behaves_like 'api v3 path', '/queries/filter_instance_schemas/bogus' end - describe "#query_project_form" do + describe '#query_project_form' do subject { helper.query_project_form(42) } - it_behaves_like "api v3 path", "/projects/42/queries/form" + it_behaves_like 'api v3 path', '/projects/42/queries/form' end - describe "#query_project_filter_instance_schemas" do + describe '#query_project_filter_instance_schemas' do subject { helper.query_project_filter_instance_schemas(42) } - it_behaves_like "api v3 path", "/projects/42/queries/filter_instance_schemas" + it_behaves_like 'api v3 path', '/projects/42/queries/filter_instance_schemas' end - describe "#query_operator" do - subject { helper.query_operator "=" } + describe '#query_operator' do + subject { helper.query_operator '=' } - it_behaves_like "api v3 path", "/queries/operators/=" + it_behaves_like 'api v3 path', '/queries/operators/=' end - describe "#query_project_schema" do - subject { helper.query_project_schema("42") } + describe '#query_project_schema' do + subject { helper.query_project_schema('42') } - it_behaves_like "api v3 path", "/projects/42/queries/schema" + it_behaves_like 'api v3 path', '/projects/42/queries/schema' end - describe "#query_available_projects" do + describe '#query_available_projects' do subject { helper.query_available_projects } - it_behaves_like "api v3 path", "/queries/available_projects" + it_behaves_like 'api v3 path', '/queries/available_projects' end end - describe "relations paths" do - it_behaves_like "index", :relation - it_behaves_like "show", :relation + describe 'relations paths' do + it_behaves_like 'index', :relation + it_behaves_like 'show', :relation end - describe "revisions paths" do - it_behaves_like "show", :revision + describe 'revisions paths' do + it_behaves_like 'show', :revision - describe "#show_revision" do - subject { helper.show_revision "foo", 1234 } + describe '#show_revision' do + subject { helper.show_revision 'foo', 1234 } - it_behaves_like "path", "/projects/foo/repository/revision/1234" + it_behaves_like 'path', '/projects/foo/repository/revision/1234' end end - describe "roles paths" do - it_behaves_like "index", :role - it_behaves_like "show", :role + describe 'roles paths' do + it_behaves_like 'index', :role + it_behaves_like 'show', :role end - describe "statuses paths" do - it_behaves_like "index", :status - it_behaves_like "show", :status + describe 'statuses paths' do + it_behaves_like 'index', :status + it_behaves_like 'show', :status end - describe "grids paths" do - it_behaves_like "resource", :grid + describe 'grids paths' do + it_behaves_like 'resource', :grid end - describe "string object paths" do - describe "#string_object" do - subject { helper.string_object "foo" } + describe 'string object paths' do + describe '#string_object' do + subject { helper.string_object 'foo' } - it_behaves_like "api v3 path", "/string_objects?value=foo" + it_behaves_like 'api v3 path', '/string_objects?value=foo' - it "escapes correctly" do - value = "foo/bar baz" - expect(helper.string_object(value)).to eql("/api/v3/string_objects?value=foo%2Fbar%20baz") + it 'escapes correctly' do + value = 'foo/bar baz' + expect(helper.string_object(value)).to eql('/api/v3/string_objects?value=foo%2Fbar%20baz') end end end - context "status paths" do - it_behaves_like "show", :status + context 'status paths' do + it_behaves_like 'show', :status end - context "time_entry paths" do - it_behaves_like "resource", :time_entry + context 'time_entry paths' do + it_behaves_like 'resource', :time_entry - describe "#time_entries_activity" do + describe '#time_entries_activity' do subject { helper.time_entries_activity 42 } - it_behaves_like "api v3 path", "/time_entries/activities/42" + it_behaves_like 'api v3 path', '/time_entries/activities/42' end - describe "#time_entries_available_projects" do + describe '#time_entries_available_projects' do subject { helper.time_entries_available_projects } - it_behaves_like "api v3 path", "/time_entries/available_projects" + it_behaves_like 'api v3 path', '/time_entries/available_projects' end end - describe "types paths" do - it_behaves_like "index", :type - it_behaves_like "show", :type + describe 'types paths' do + it_behaves_like 'index', :type + it_behaves_like 'show', :type - describe "#types_by_project" do + describe '#types_by_project' do subject { helper.types_by_project 12 } - it_behaves_like "api v3 path", "/projects/12/types" + it_behaves_like 'api v3 path', '/projects/12/types' end end - describe "users paths" do - it_behaves_like "index", :user - it_behaves_like "show", :user + describe 'users paths' do + it_behaves_like 'index', :user + it_behaves_like 'show', :user end - describe "user_preferences path" do + describe 'user_preferences path' do subject { helper.user_preferences(42) } - it_behaves_like "api v3 path", "/users/42/preferences" + it_behaves_like 'api v3 path', '/users/42/preferences' end - describe "group paths" do - it_behaves_like "index", :group - it_behaves_like "show", :group + describe 'group paths' do + it_behaves_like 'index', :group + it_behaves_like 'show', :group end - describe "values paths" do - describe "#values_schema" do - subject { helper.value_schema("bogus_value") } + describe 'values paths' do + describe '#values_schema' do + subject { helper.value_schema('bogus_value') } - it_behaves_like "api v3 path", "/values/schemas/bogus_value" + it_behaves_like 'api v3 path', '/values/schemas/bogus_value' end end - describe "version paths" do - it_behaves_like "resource", :version + describe 'version paths' do + it_behaves_like 'resource', :version - describe "#versions_available_projects" do + describe '#versions_available_projects' do subject { helper.versions_available_projects } - it_behaves_like "api v3 path", "/versions/available_projects" + it_behaves_like 'api v3 path', '/versions/available_projects' end - describe "#versions_by_project" do + describe '#versions_by_project' do subject { helper.versions_by_project 42 } - it_behaves_like "api v3 path", "/projects/42/versions" + it_behaves_like 'api v3 path', '/projects/42/versions' end - describe "#projects_by_version" do + describe '#projects_by_version' do subject { helper.projects_by_version 42 } - it_behaves_like "api v3 path", "/versions/42/projects" + it_behaves_like 'api v3 path', '/versions/42/projects' end end - describe "view paths" do - it_behaves_like "show", :view - it_behaves_like "index", :view + describe 'view paths' do + it_behaves_like 'show', :view + it_behaves_like 'index', :view - describe "#views_type" do - subject { helper.views_type("work_packages_table") } + describe '#views_type' do + subject { helper.views_type('work_packages_table') } - it_behaves_like "api v3 path", "/views/work_packages_table" + it_behaves_like 'api v3 path', '/views/work_packages_table' end end - describe "wiki pages paths" do - it_behaves_like "show", :wiki_page + describe 'wiki pages paths' do + it_behaves_like 'show', :wiki_page end - describe "work packages paths" do - it_behaves_like "resource", :work_package, except: [:schema] + describe 'work packages paths' do + it_behaves_like 'resource', :work_package, except: [:schema] # The simple case (with an id) is already covered by the 'it_behaves_like' - describe "#work_package with an historic timestamp" do + describe '#work_package with an historic timestamp' do subject { helper.work_package 42, timestamps: Timestamp.parse("2020-02-02T02:02:02Z") } - it_behaves_like "api v3 path", "/work_packages/42?timestamps=2020-02-02T02%3A02%3A02Z" + it_behaves_like 'api v3 path', '/work_packages/42?timestamps=2020-02-02T02%3A02%3A02Z' end - describe "#work_package with a NOW timestamp" do + describe '#work_package with a NOW timestamp' do subject { helper.work_package 42, timestamps: Timestamp.now } - it_behaves_like "api v3 path", "/work_packages/42" + it_behaves_like 'api v3 path', '/work_packages/42' end - describe "#work_package_activities" do + describe '#work_package_activities' do subject { helper.work_package_activities 42 } - it_behaves_like "api v3 path", "/work_packages/42/activities" + it_behaves_like 'api v3 path', '/work_packages/42/activities' end - describe "#work_package_relations" do + describe '#work_package_relations' do subject { helper.work_package_relations 42 } - it_behaves_like "api v3 path", "/work_packages/42/relations" + it_behaves_like 'api v3 path', '/work_packages/42/relations' end - describe "#work_package_relation" do + describe '#work_package_relation' do subject { helper.work_package_relation 1, 42 } - it_behaves_like "api v3 path", "/work_packages/42/relations/1" + it_behaves_like 'api v3 path', '/work_packages/42/relations/1' end - describe "#work_package_revisions" do + describe '#work_package_revisions' do subject { helper.work_package_revisions 42 } - it_behaves_like "api v3 path", "/work_packages/42/revisions" + it_behaves_like 'api v3 path', '/work_packages/42/revisions' end - describe "#work_package_watchers" do + describe '#work_package_watchers' do subject { helper.work_package_watchers 1 } - it_behaves_like "api v3 path", "/work_packages/1/watchers" + it_behaves_like 'api v3 path', '/work_packages/1/watchers' end - describe "#work_packages_by_project" do + describe '#work_packages_by_project' do subject { helper.work_packages_by_project 42 } - it_behaves_like "api v3 path", "/projects/42/work_packages" + it_behaves_like 'api v3 path', '/projects/42/work_packages' end - describe "#create_project_work_package_form" do + describe '#create_project_work_package_form' do subject { helper.create_project_work_package_form 42 } - it_behaves_like "api v3 path", "/projects/42/work_packages/form" + it_behaves_like 'api v3 path', '/projects/42/work_packages/form' end - describe "#watcher" do + describe '#watcher' do subject { helper.watcher 1, 42 } - it_behaves_like "api v3 path", "/work_packages/42/watchers/1" + it_behaves_like 'api v3 path', '/work_packages/42/watchers/1' end - describe "available ... paths" do - describe "#available_assignees_in_project" do + describe 'available ... paths' do + describe '#available_assignees_in_project' do subject { helper.available_assignees_in_project 42 } - it_behaves_like "api v3 path", "/projects/42/available_assignees" + it_behaves_like 'api v3 path', '/projects/42/available_assignees' end - describe "#available_assignees_in_work_package" do + describe '#available_assignees_in_work_package' do subject { helper.available_assignees_in_work_package 42 } - it_behaves_like "api v3 path", "/work_packages/42/available_assignees" + it_behaves_like 'api v3 path', '/work_packages/42/available_assignees' end - describe "#available_responsibles" do + describe '#available_responsibles' do subject { helper.available_responsibles 42 } - it_behaves_like "api v3 path", "/projects/42/available_responsibles" + it_behaves_like 'api v3 path', '/projects/42/available_responsibles' end - describe "#available_watchers" do + describe '#available_watchers' do subject { helper.available_watchers 42 } - it_behaves_like "api v3 path", "/work_packages/42/available_watchers" + it_behaves_like 'api v3 path', '/work_packages/42/available_watchers' end - describe "#available_projects_on_edit" do + describe '#available_projects_on_edit' do subject { helper.available_projects_on_edit 42 } - it_behaves_like "api v3 path", "/work_packages/42/available_projects" + it_behaves_like 'api v3 path', '/work_packages/42/available_projects' end - describe "#available_projects_on_create" do + describe '#available_projects_on_create' do subject { helper.available_projects_on_create } - it_behaves_like "api v3 path", "/work_packages/available_projects" + it_behaves_like 'api v3 path', '/work_packages/available_projects' end end - describe "schemas paths" do - describe "#work_package_schema" do + describe 'schemas paths' do + describe '#work_package_schema' do subject { helper.work_package_schema 1, 2 } - it_behaves_like "api v3 path", "/work_packages/schemas/1-2" + it_behaves_like 'api v3 path', '/work_packages/schemas/1-2' end - describe "#work_package_schemas" do + describe '#work_package_schemas' do subject { helper.work_package_schemas } - it_behaves_like "api v3 path", "/work_packages/schemas" + it_behaves_like 'api v3 path', '/work_packages/schemas' end - describe "#work_package_schemas with filters" do + describe '#work_package_schemas with filters' do subject { helper.work_package_schemas [1, 2], [3, 4] } def self.filter - CGI.escape([{ id: { operator: "=", values: ["1-2", "3-4"] } }].to_s) + CGI.escape([{ id: { operator: '=', values: ['1-2', '3-4'] } }].to_s) end - it_behaves_like "api v3 path", + it_behaves_like 'api v3 path', "/work_packages/schemas?filters=#{filter}" end - describe "#work_package_sums_schema" do + describe '#work_package_sums_schema' do subject { helper.work_package_sums_schema } - it_behaves_like "api v3 path", "/work_packages/schemas/sums" + it_behaves_like 'api v3 path', '/work_packages/schemas/sums' end end end - describe ".timestamps_to_param_value" do + describe '.timestamps_to_param_value' do subject { helper.timestamps_to_param_value(timestamps) } - context "for a single relative iso8601 string" do - let(:timestamps) { "PT0S" } + context 'for a single relative iso8601 string' do + let(:timestamps) { 'PT0S' } - it "returns the value as an absolute value in ISO8601 format" do + it 'returns the value as an absolute value in ISO8601 format' do Timecop.freeze(Time.current) do expect(subject) .to eql Time.current.iso8601 @@ -676,19 +676,19 @@ def self.filter end end - context "for a single absolute iso8601 string" do - let(:timestamps) { "2023-01-31T21:34:11Z" } + context 'for a single absolute iso8601 string' do + let(:timestamps) { '2023-01-31T21:34:11Z' } - it "returns the value unchanged" do + it 'returns the value unchanged' do expect(subject) .to eql timestamps end end - context "for a single timestamp (NOW)" do + context 'for a single timestamp (NOW)' do let(:timestamps) { Timestamp.now } - it "returns the value unchanged" do + it 'returns the value unchanged' do Timecop.freeze(Time.current) do expect(subject) .to eql Time.current.iso8601 @@ -696,10 +696,10 @@ def self.filter end end - context "for an array in different formats" do - let(:timestamps) { ["2023-01-31T21:34:11Z", Timestamp.new("2022-04-30T21:34:11Z"), "PT0S"] } + context 'for an array in different formats' do + let(:timestamps) { ['2023-01-31T21:34:11Z', Timestamp.new('2022-04-30T21:34:11Z'), 'PT0S'] } - it "returns the value unchanged" do + it 'returns the value unchanged' do Timecop.freeze(Time.current) do expect(subject) .to eql "2023-01-31T21:34:11Z,2022-04-30T21:34:11Z,#{Time.current.iso8601}" diff --git a/spec/lib/api/v3/utilities/resource_link_generator_spec.rb b/spec/lib/api/v3/utilities/resource_link_generator_spec.rb index 2e612169a440..f59a8f84e88c 100644 --- a/spec/lib/api/v3/utilities/resource_link_generator_spec.rb +++ b/spec/lib/api/v3/utilities/resource_link_generator_spec.rb @@ -26,40 +26,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Utilities::ResourceLinkGenerator do include API::V3::Utilities::PathHelper subject { described_class } - describe ":make_link" do - it "supports work packages" do + describe ':make_link' do + it 'supports work packages' do wp = build_stubbed(:work_package) expect(subject.make_link(wp)).to eql api_v3_paths.work_package(wp.id) end - it "supports priorities" do + it 'supports priorities' do prio = build_stubbed(:priority) expect(subject.make_link(prio)).to eql api_v3_paths.priority(prio.id) end - it "supports statuses" do + it 'supports statuses' do status = build_stubbed(:status) expect(subject.make_link(status)).to eql api_v3_paths.status(status.id) end - it "supports the anonymous user" do + it 'supports the anonymous user' do user = build_stubbed(:anonymous) expect(subject.make_link(user)).to eql api_v3_paths.user(user.id) end - it "returns nil for unsupported records" do + it 'returns nil for unsupported records' do record = create(:custom_field) expect(subject.make_link(record)).to be_nil end - it "returns nil for non-AR types" do + it 'returns nil for non-AR types' do record = Object.new expect(subject.make_link(record)).to be_nil end diff --git a/spec/lib/api/v3/values/property_date_representer_rendering_spec.rb b/spec/lib/api/v3/values/property_date_representer_rendering_spec.rb index 9141ade7c5a7..da638f76193a 100644 --- a/spec/lib/api/v3/values/property_date_representer_rendering_spec.rb +++ b/spec/lib/api/v3/values/property_date_representer_rendering_spec.rb @@ -26,56 +26,56 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Values::PropertyDateRepresenter, "rendering" do +RSpec.describe API::V3::Values::PropertyDateRepresenter, 'rendering' do subject(:generated) { representer.to_json } - let(:property) { "abc" } + let(:property) { 'abc' } let(:date_value) { Date.current } let(:key_value) { Struct.new(:property, :value, keyword_init: true).new(property:, value: date_value) } - let(:self_link) { "api/bogus/value" } + let(:self_link) { 'api/bogus/value' } let(:representer) do described_class.new key_value, self_link: end - describe "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end end - describe "properties" do - describe "_type" do - it_behaves_like "property", :_type do - let(:value) { "Values::Property" } + describe 'properties' do + describe '_type' do + it_behaves_like 'property', :_type do + let(:value) { 'Values::Property' } end end - describe "property" do - it_behaves_like "property", :property do + describe 'property' do + it_behaves_like 'property', :property do let(:value) { property } end - context "with a snake_case property" do - let(:property) { "snake_case" } + context 'with a snake_case property' do + let(:property) { 'snake_case' } - it_behaves_like "property", :property do - let(:value) { "snakeCase" } + it_behaves_like 'property', :property do + let(:value) { 'snakeCase' } end end end - describe "value" do - it_behaves_like "date property", :value do + describe 'value' do + it_behaves_like 'date property', :value do let(:value) { date_value } end - context "with an empty value" do + context 'with an empty value' do let(:date_value) { nil } - it_behaves_like "date property", :value do + it_behaves_like 'date property', :value do let(:value) { nil } end end diff --git a/spec/lib/api/v3/values/schemas/property_schema_representer_rendering_spec.rb b/spec/lib/api/v3/values/schemas/property_schema_representer_rendering_spec.rb index 2d006d23ad86..25a406ddc37b 100644 --- a/spec/lib/api/v3/values/schemas/property_schema_representer_rendering_spec.rb +++ b/spec/lib/api/v3/values/schemas/property_schema_representer_rendering_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Values::Schemas::PropertySchemaRepresenter, "rendering" do +RSpec.describe API::V3::Values::Schemas::PropertySchemaRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } - let(:self_link) { "/a/self/link" } + let(:self_link) { '/a/self/link' } let(:model) do API::V3::Values::Schemas::Model - .new("The start date to that object", - "ADate") + .new('The start date to that object', + 'ADate') end let(:representer) do @@ -49,29 +49,29 @@ subject(:generated) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do + describe '_type' do + it 'is indicated as Schema' do expect(subject) - .to be_json_eql("Schema".to_json) - .at_path("_type") + .to be_json_eql('Schema'.to_json) + .at_path('_type') end end - describe "property" do - let(:path) { "property" } + describe 'property' do + let(:path) { 'property' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { I18n.t(:"api_v3.attributes.property") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { I18n.t(:'api_v3.attributes.property') } let(:required) { true } let(:writable) { false } end end - describe "value" do - let(:path) { "value" } + describe 'value' do + let(:path) { 'value' } - it_behaves_like "has basic schema properties" do + it_behaves_like 'has basic schema properties' do let(:type) { model.type } let(:name) { model.name } let(:required) { true } @@ -79,10 +79,10 @@ end end - describe "_links" do - describe "self" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end end diff --git a/spec/lib/api/v3/values/schemas/value_schema_factory_spec.rb b/spec/lib/api/v3/values/schemas/value_schema_factory_spec.rb index 0ffdaef94346..1672fd93b7c6 100644 --- a/spec/lib/api/v3/values/schemas/value_schema_factory_spec.rb +++ b/spec/lib/api/v3/values/schemas/value_schema_factory_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Values::Schemas::ValueSchemaFactory do include API::V3::Utilities::PathHelper - describe ".for" do + describe '.for' do let!(:representer_instance) do instance_double(API::V3::Values::Schemas::PropertySchemaRepresenter) end @@ -41,67 +41,67 @@ .and_return(representer_instance) end - context "for the start_date property" do - let(:property) { "start_date" } + context 'for the start_date property' do + let(:property) { 'start_date' } - it "returns a schema representer" do + it 'returns a schema representer' do expect(described_class.for(property)) .to eq representer_instance end - it "instantiates the representer with the proper params" do + it 'instantiates the representer with the proper params' do described_class.for(property) expect(API::V3::Values::Schemas::PropertySchemaRepresenter) .to have_received(:new) - .with(API::V3::Values::Schemas::Model.new(I18n.t("attributes.start_date"), "Date"), + .with(API::V3::Values::Schemas::Model.new(I18n.t('attributes.start_date'), 'Date'), current_user: nil, self_link: api_v3_paths.value_schema(property.camelcase(:lower))) end end - context "for the due_date property" do - let(:property) { "due_date" } + context 'for the due_date property' do + let(:property) { 'due_date' } - it "returns a schema representer" do + it 'returns a schema representer' do expect(described_class.for(property)) .to eq representer_instance end - it "instantiates the representer with the proper params" do + it 'instantiates the representer with the proper params' do described_class.for(property) expect(API::V3::Values::Schemas::PropertySchemaRepresenter) .to have_received(:new) - .with(API::V3::Values::Schemas::Model.new(I18n.t("attributes.due_date"), "Date"), + .with(API::V3::Values::Schemas::Model.new(I18n.t('attributes.due_date'), 'Date'), current_user: nil, self_link: api_v3_paths.value_schema(property.camelcase(:lower))) end end - context "for the date property (for milestones)" do - let(:property) { "date" } + context 'for the date property (for milestones)' do + let(:property) { 'date' } - it "returns a schema representer" do + it 'returns a schema representer' do expect(described_class.for(property)) .to eq representer_instance end - it "instantiates the representer with the proper params" do + it 'instantiates the representer with the proper params' do described_class.for(property) expect(API::V3::Values::Schemas::PropertySchemaRepresenter) .to have_received(:new) - .with(API::V3::Values::Schemas::Model.new(I18n.t("attributes.date"), "Date"), + .with(API::V3::Values::Schemas::Model.new(I18n.t('attributes.date'), 'Date'), current_user: nil, self_link: api_v3_paths.value_schema(property.camelcase(:lower))) end end - context "for another property" do - let(:property) { "bogus" } + context 'for another property' do + let(:property) { 'bogus' } - it "returns nil" do + it 'returns nil' do expect(described_class.for(property)) .to be_nil end diff --git a/spec/lib/api/v3/versions/schemas/version_schema_representer_spec.rb b/spec/lib/api/v3/versions/schemas/version_schema_representer_spec.rb index 2c2fbaea7696..5fe277f2959f 100644 --- a/spec/lib/api/v3/versions/schemas/version_schema_representer_spec.rb +++ b/spec/lib/api/v3/versions/schemas/version_schema_representer_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Versions::Schemas::VersionSchemaRepresenter do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } - let(:self_link) { "/a/self/link" } + let(:self_link) { '/a/self/link' } let(:embedded) { true } let(:new_record) { true } let(:allowed_sharings) { %w(tree system) } @@ -53,7 +53,7 @@ writable = %w(name description start_date due_date status sharing) if new_record - writable << "project" + writable << 'project' end writable.include?(attribute.to_s) @@ -82,173 +82,173 @@ current_user:) end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - describe "_type" do - it "is indicated as Schema" do - expect(subject).to be_json_eql("Schema".to_json).at_path("_type") + describe '_type' do + it 'is indicated as Schema' do + expect(subject).to be_json_eql('Schema'.to_json).at_path('_type') end end - describe "id" do - let(:path) { "id" } + describe 'id' do + let(:path) { 'id' } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } - let(:name) { I18n.t("attributes.id") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } + let(:name) { I18n.t('attributes.id') } let(:required) { true } let(:writable) { false } end end - describe "createdAt" do - let(:path) { "createdAt" } + describe 'createdAt' do + let(:path) { 'createdAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Version.human_attribute_name("created_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Version.human_attribute_name('created_at') } let(:required) { true } let(:writable) { false } end end - describe "updatedAt" do - let(:path) { "updatedAt" } + describe 'updatedAt' do + let(:path) { 'updatedAt' } - it_behaves_like "has basic schema properties" do - let(:type) { "DateTime" } - let(:name) { Version.human_attribute_name("updated_at") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'DateTime' } + let(:name) { Version.human_attribute_name('updated_at') } let(:required) { true } let(:writable) { false } end end - describe "name" do - let(:path) { "name" } + describe 'name' do + let(:path) { 'name' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Version.human_attribute_name("name") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Version.human_attribute_name('name') } let(:required) { true } let(:writable) { true } end - it_behaves_like "indicates length requirements" do + it_behaves_like 'indicates length requirements' do let(:min_length) { 1 } let(:max_length) { 60 } end end - describe "description" do - let(:path) { "description" } + describe 'description' do + let(:path) { 'description' } - it_behaves_like "has basic schema properties" do - let(:type) { "Formattable" } - let(:name) { Version.human_attribute_name("description") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Formattable' } + let(:name) { Version.human_attribute_name('description') } let(:required) { false } let(:writable) { true } end end - describe "int custom field" do + describe 'int custom field' do let(:path) { custom_field.attribute_name(:camel_case) } - it_behaves_like "has basic schema properties" do - let(:type) { "Integer" } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Integer' } let(:name) { custom_field.name } let(:required) { false } let(:writable) { false } end end - describe "startDate" do - let(:path) { "startDate" } + describe 'startDate' do + let(:path) { 'startDate' } - it_behaves_like "has basic schema properties" do - let(:type) { "Date" } - let(:name) { Version.human_attribute_name("start_date") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Date' } + let(:name) { Version.human_attribute_name('start_date') } let(:required) { false } let(:writable) { true } end end - describe "endDate" do - let(:path) { "endDate" } + describe 'endDate' do + let(:path) { 'endDate' } - it_behaves_like "has basic schema properties" do - let(:type) { "Date" } - let(:name) { Version.human_attribute_name("due_date") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Date' } + let(:name) { Version.human_attribute_name('due_date') } let(:required) { false } let(:writable) { true } end end - describe "definingProject" do - let(:path) { "definingProject" } + describe 'definingProject' do + let(:path) { 'definingProject' } - context "if having a new record" do - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Version.human_attribute_name("project") } + context 'if having a new record' do + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Version.human_attribute_name('project') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "links to allowed values via collection link" do + it_behaves_like 'links to allowed values via collection link' do let(:href) do api_v3_paths.versions_available_projects end end end - context "if not embedding" do + context 'if not embedding' do let(:embedded) { false } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end - context "if having a persisted record" do + context 'if having a persisted record' do let(:new_record) { false } - it_behaves_like "has basic schema properties" do - let(:type) { "Project" } - let(:name) { Version.human_attribute_name("project") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'Project' } + let(:name) { Version.human_attribute_name('project') } let(:required) { true } let(:writable) { false } - let(:location) { "_links" } + let(:location) { '_links' } end - context "if embedding" do + context 'if embedding' do let(:embedded) { true } - it_behaves_like "does not link to allowed values" + it_behaves_like 'does not link to allowed values' end end end - describe "status" do - let(:path) { "status" } + describe 'status' do + let(:path) { 'status' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Version.human_attribute_name("status") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Version.human_attribute_name('status') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it "contains no link to the allowed values" do + it 'contains no link to the allowed values' do expect(subject) .not_to have_json_path("#{path}/_links/allowedValues") end - it "embeds the allowed values" do + it 'embeds the allowed values' do allowed_path = "#{path}/_embedded/allowedValues" expect(subject) @@ -257,23 +257,23 @@ end end - describe "sharing" do - let(:path) { "sharing" } + describe 'sharing' do + let(:path) { 'sharing' } - it_behaves_like "has basic schema properties" do - let(:type) { "String" } - let(:name) { Version.human_attribute_name("sharing") } + it_behaves_like 'has basic schema properties' do + let(:type) { 'String' } + let(:name) { Version.human_attribute_name('sharing') } let(:required) { true } let(:writable) { true } - let(:location) { "_links" } + let(:location) { '_links' } end - it "contains no link to the allowed values" do + it 'contains no link to the allowed values' do expect(subject) .not_to have_json_path("#{path}/_links/allowedValues") end - it "embeds the allowed values" do + it 'embeds the allowed values' do allowed_path = "#{path}/_embedded/allowedValues" expect(subject) @@ -282,18 +282,18 @@ end end - context "_links" do - describe "self link" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + context '_links' do + describe 'self link' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { self_link } end - context "embedded in a form" do + context 'embedded in a form' do let(:self_link) { nil } - it_behaves_like "has no link" do - let(:link) { "self" } + it_behaves_like 'has no link' do + let(:link) { 'self' } end end end diff --git a/spec/lib/api/v3/versions/version_collection_representer_spec.rb b/spec/lib/api/v3/versions/version_collection_representer_spec.rb index 52b4c69e8ecd..95cbbd571522 100644 --- a/spec/lib/api/v3/versions/version_collection_representer_spec.rb +++ b/spec/lib/api/v3/versions/version_collection_representer_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Versions::VersionCollectionRepresenter do - let(:self_link) { "/api/v3/projects/1/versions" } + let(:self_link) { '/api/v3/projects/1/versions' } let(:versions) { build_stubbed_list(:version, 3) } let(:user) { build_stubbed(:user) } let(:representer) { described_class.new(versions, self_link:, current_user: user) } @@ -37,48 +37,48 @@ include API::V3::Utilities::PathHelper - context "generation" do + context 'generation' do subject(:collection) { representer.to_json } - it_behaves_like "unpaginated APIv3 collection", 3, "projects/1/versions", "Version" + it_behaves_like 'unpaginated APIv3 collection', 3, 'projects/1/versions', 'Version' - context "_links" do + context '_links' do before do mock_permissions_for(user) do |mock| mock.allow_in_project *permissions, project: build_stubbed(:project) # any project end end - describe "createVersionImmediately" do - context "if the user is allowed to" do - it_behaves_like "has an untitled link" do - let(:link) { "createVersionImmediately" } + describe 'createVersionImmediately' do + context 'if the user is allowed to' do + it_behaves_like 'has an untitled link' do + let(:link) { 'createVersionImmediately' } let(:href) { api_v3_paths.versions } end end - context "if the user is not allowed to" do + context 'if the user is not allowed to' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "createVersionImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'createVersionImmediately' } end end end - describe "createVersion" do - context "if the user is allowed to" do - it_behaves_like "has an untitled link" do - let(:link) { "createVersion" } + describe 'createVersion' do + context 'if the user is allowed to' do + it_behaves_like 'has an untitled link' do + let(:link) { 'createVersion' } let(:href) { api_v3_paths.create_version_form } end end - context "if the user is not allowed to" do + context 'if the user is not allowed to' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "createVersion" } + it_behaves_like 'has no link' do + let(:link) { 'createVersion' } end end end diff --git a/spec/lib/api/v3/versions/version_representer_rendering_spec.rb b/spec/lib/api/v3/versions/version_representer_rendering_spec.rb index 486a47816a2b..9e47139f6116 100644 --- a/spec/lib/api/v3/versions/version_representer_rendering_spec.rb +++ b/spec/lib/api/v3/versions/version_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Versions::VersionRepresenter, "rendering" do +RSpec.describe API::V3::Versions::VersionRepresenter, 'rendering' do let(:version) { build_stubbed(:version) } let(:permissions) { [:manage_versions] } let(:user) { build_stubbed(:user) } @@ -44,95 +44,95 @@ end end - it { is_expected.to include_json("Version".to_json).at_path("_type") } + it { is_expected.to include_json('Version'.to_json).at_path('_type') } - describe "links" do - it { is_expected.to have_json_type(Object).at_path("_links") } + describe 'links' do + it { is_expected.to have_json_type(Object).at_path('_links') } - describe "to self" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe 'to self' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.version(version.id) } let(:title) { version.name } end end - describe "to schema" do - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + describe 'to schema' do + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) { api_v3_paths.version_schema } end end - describe "to update" do - context "if manage versions permissions are granted" do - it_behaves_like "has an untitled link" do - let(:link) { "update" } + describe 'to update' do + context 'if manage versions permissions are granted' do + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.version_form(version.id) } end end - describe "if manage versions permissions are lacking" do + describe 'if manage versions permissions are lacking' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "update" } + it_behaves_like 'has no link' do + let(:link) { 'update' } end end end - describe "to updateImmediately" do - context "if manage versions permissions are granted" do - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + describe 'to updateImmediately' do + context 'if manage versions permissions are granted' do + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.version(version.id) } end end - describe "if manage versions permissions are lacking" do + describe 'if manage versions permissions are lacking' do let(:permissions) { [] } - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end end - describe "to the defining project" do - context "if the user has the permission to see the project" do + describe 'to the defining project' do + context 'if the user has the permission to see the project' do before do allow(version.project).to receive(:visible?).with(user).and_return(true) end - it_behaves_like "has a titled link" do - let(:link) { "definingProject" } + it_behaves_like 'has a titled link' do + let(:link) { 'definingProject' } let(:href) { api_v3_paths.project(version.project.id) } let(:title) { version.project.name } end end - context "if the user lacks the permission to see the project" do + context 'if the user lacks the permission to see the project' do before do allow(version.project).to receive(:visible?).with(user).and_return(false) end - it_behaves_like "has no link" do - let(:link) { "definingProject" } + it_behaves_like 'has no link' do + let(:link) { 'definingProject' } end end end - describe "to available projects" do - it_behaves_like "has an untitled link" do - let(:link) { "availableInProjects" } + describe 'to available projects' do + it_behaves_like 'has an untitled link' do + let(:link) { 'availableInProjects' } let(:href) { api_v3_paths.projects_by_version(version.id) } end end - context "custom value" do + context 'custom value' do let(:custom_field) { build_stubbed(:version_custom_field, :list) } let(:custom_value) do - build_stubbed(:custom_value, custom_field:, value: "1") + build_stubbed(:custom_value, custom_field:, value: '1') end before do @@ -154,52 +154,52 @@ end end - describe "properties" do - it { is_expected.to be_json_eql(version.id.to_json).at_path("id") } - it { is_expected.to be_json_eql(version.name.to_json).at_path("name") } + describe 'properties' do + it { is_expected.to be_json_eql(version.id.to_json).at_path('id') } + it { is_expected.to be_json_eql(version.name.to_json).at_path('name') } - it_behaves_like "API V3 formattable", "description" do - let(:format) { "plain" } + it_behaves_like 'API V3 formattable', 'description' do + let(:format) { 'plain' } let(:raw) { version.description } end - it_behaves_like "has ISO 8601 date only" do + it_behaves_like 'has ISO 8601 date only' do let(:date) { version.start_date } - let(:json_path) { "startDate" } + let(:json_path) { 'startDate' } end - it_behaves_like "has ISO 8601 date only" do + it_behaves_like 'has ISO 8601 date only' do let(:date) { version.due_date } - let(:json_path) { "endDate" } + let(:json_path) { 'endDate' } end - it "has a status" do + it 'has a status' do expect(subject) .to be_json_eql(version.status.to_json) - .at_path("status") + .at_path('status') end - it "has a sharing" do + it 'has a sharing' do expect(subject) .to be_json_eql(version.sharing.to_json) - .at_path("sharing") + .at_path('sharing') end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { version.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end - it_behaves_like "has UTC ISO 8601 date and time" do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { version.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end - context "custom value" do + context 'custom value' do let(:custom_field) { build_stubbed(:version_custom_field) } let(:custom_value) do CustomValue.new(custom_field:, - value: "1234", + value: '1234', customized: version) end @@ -227,8 +227,8 @@ end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do expect(OpenProject::Cache) .to receive(:fetch) .with(representer.json_cache_key) @@ -237,36 +237,36 @@ representer.to_json end - describe "#json_cache_key" do + describe '#json_cache_key' do let!(:former_cache_key) { representer.json_cache_key } - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "Versions", "VersionRepresenter") + .to include('API', 'V3', 'Versions', 'VersionRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do I18n.with_locale(:fr) do expect(representer.json_cache_key) .not_to eql former_cache_key end end - it "changes when the version is updated" do + it 'changes when the version is updated' do version.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) .not_to eql former_cache_key end - it "changes when the version's project is updated" do + it 'changes when the version\'s project is updated' do version.project.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) .not_to eql former_cache_key end - context "custom fields" do + context 'custom fields' do let(:version) do build_stubbed(:version).tap do |_v| # Use this to force the custom field to be defined before the former_cache_key is calculated @@ -282,10 +282,10 @@ allow(version) .to receive(custom_field.attribute_getter) - .and_return("123") + .and_return('123') end - it "changes when a custom field changes" do + it 'changes when a custom field changes' do custom_field.updated_at = Time.now + 20.seconds expect(representer.json_cache_key) diff --git a/spec/lib/api/v3/views/view_representer_rendering_spec.rb b/spec/lib/api/v3/views/view_representer_rendering_spec.rb index be2fc35945fc..83709d38aed9 100644 --- a/spec/lib/api/v3/views/view_representer_rendering_spec.rb +++ b/spec/lib/api/v3/views/view_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::Views::ViewRepresenter, "rendering" do +RSpec.describe API::V3::Views::ViewRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:generated) { representer.to_json } @@ -47,89 +47,89 @@ embed_links: end - describe "properties" do - describe "_type" do - it_behaves_like "property", :_type do - let(:value) { "Views::WorkPackagesTable" } + describe 'properties' do + describe '_type' do + it_behaves_like 'property', :_type do + let(:value) { 'Views::WorkPackagesTable' } end end - describe "id" do - it_behaves_like "property", :id do + describe 'id' do + it_behaves_like 'property', :id do let(:value) { view.id } end end - describe "public" do - context "with the query being public" do - it_behaves_like "property", :public do + describe 'public' do + context 'with the query being public' do + it_behaves_like 'property', :public do let(:value) { true } end end - context "with the query being private" do + context 'with the query being private' do let(:query_public) { false } - it_behaves_like "property", :public do + it_behaves_like 'property', :public do let(:value) { false } end end end - describe "starred" do - context "with the query being starred" do - it_behaves_like "property", :starred do + describe 'starred' do + context 'with the query being starred' do + it_behaves_like 'property', :starred do let(:value) { true } end end - context "without the query being starred" do + context 'without the query being starred' do let(:query_starred) { false } - it_behaves_like "property", :starred do + it_behaves_like 'property', :starred do let(:value) { false } end end end - describe "name" do - context "with the query being name" do - it_behaves_like "property", :name do + describe 'name' do + context 'with the query being name' do + it_behaves_like 'property', :name do let(:value) { query.name } end end end - describe "timestamps" do - it_behaves_like "datetime property", :createdAt do + describe 'timestamps' do + it_behaves_like 'datetime property', :createdAt do let(:value) { view.created_at } end - it_behaves_like "datetime property", :updatedAt do + it_behaves_like 'datetime property', :updatedAt do let(:value) { view.updated_at } end end end - describe "_links" do - describe "self" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + describe 'self' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.view view.id } end end - describe "query" do - it_behaves_like "has a titled link" do - let(:link) { "query" } + describe 'query' do + it_behaves_like 'has a titled link' do + let(:link) { 'query' } let(:href) { api_v3_paths.query query.id } let(:title) { query.name } end end - describe "project" do - it_behaves_like "has a titled link" do - let(:link) { "project" } + describe 'project' do + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project query.project_id } let(:title) { query.project.name } end diff --git a/spec/lib/api/v3/wiki_pages/wiki_page_representer_rendering_spec.rb b/spec/lib/api/v3/wiki_pages/wiki_page_representer_rendering_spec.rb index d9d3a00f21e7..7934983f299f 100644 --- a/spec/lib/api/v3/wiki_pages/wiki_page_representer_rendering_spec.rb +++ b/spec/lib/api/v3/wiki_pages/wiki_page_representer_rendering_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::WikiPages::WikiPageRepresenter, "rendering" do +RSpec.describe API::V3::WikiPages::WikiPageRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:wiki_page) do @@ -46,24 +46,24 @@ subject { representer.to_json } - describe "_links" do - it_behaves_like "has an untitled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.wiki_page wiki_page.id } end - it_behaves_like "has an untitled link" do + it_behaves_like 'has an untitled link' do let(:link) { :attachments } let(:href) { api_v3_paths.attachments_by_wiki_page wiki_page.id } end - it_behaves_like "has a titled link" do + it_behaves_like 'has a titled link' do let(:link) { :project } let(:title) { project.name } let(:href) { api_v3_paths.project project.id } end - it_behaves_like "has an untitled action link" do + it_behaves_like 'has an untitled action link' do let(:link) { :addAttachment } let(:href) { api_v3_paths.attachments_by_wiki_page wiki_page.id } let(:method) { :post } @@ -71,25 +71,25 @@ end end - describe "properties" do - it_behaves_like "property", :_type do - let(:value) { "WikiPage" } + describe 'properties' do + it_behaves_like 'property', :_type do + let(:value) { 'WikiPage' } end - it_behaves_like "property", :id do + it_behaves_like 'property', :id do let(:value) { wiki_page.id } end - it_behaves_like "property", :title do + it_behaves_like 'property', :title do let(:value) { wiki_page.title } end end - describe "_embedded" do - it "has project embedded" do + describe '_embedded' do + it 'has project embedded' do expect(subject) .to be_json_eql(project.name.to_json) - .at_path("_embedded/project/name") + .at_path('_embedded/project/name') end end end diff --git a/spec/lib/api/v3/work_packages/create_form_representer_spec.rb b/spec/lib/api/v3/work_packages/create_form_representer_spec.rb index ced35654e028..331e657b26ce 100644 --- a/spec/lib/api/v3/work_packages/create_form_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/create_form_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++require 'rspec' -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::CreateFormRepresenter do include API::V3::Utilities::PathHelper @@ -49,109 +49,109 @@ subject(:generated) { representer.to_json } - describe "_links" do - it "links to the create form api" do + describe '_links' do + it 'links to the create form api' do expect(generated) .to be_json_eql(api_v3_paths.create_work_package_form.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - it "is a post" do + it 'is a post' do expect(generated) .to be_json_eql(:post.to_json) - .at_path("_links/self/method") + .at_path('_links/self/method') end - describe "validate" do - it "links to the create form api" do + describe 'validate' do + it 'links to the create form api' do expect(generated) .to be_json_eql(api_v3_paths.create_work_package_form.to_json) - .at_path("_links/validate/href") + .at_path('_links/validate/href') end - it "is a post" do + it 'is a post' do expect(generated) .to be_json_eql(:post.to_json) - .at_path("_links/validate/method") + .at_path('_links/validate/method') end end - describe "preview markup" do - it "links to the markup api" do + describe 'preview markup' do + it 'links to the markup api' do path = api_v3_paths.render_markup(link: api_v3_paths.project(work_package.project_id)) expect(generated) .to be_json_eql(path.to_json) - .at_path("_links/previewMarkup/href") + .at_path('_links/previewMarkup/href') end - it "is a post" do + it 'is a post' do expect(generated) .to be_json_eql(:post.to_json) - .at_path("_links/previewMarkup/method") + .at_path('_links/previewMarkup/method') end - it "contains link to work package" do + it 'contains link to work package' do expected_preview_link = api_v3_paths.render_markup(link: "/api/v3/projects/#{work_package.project_id}") expect(subject) .to be_json_eql(expected_preview_link.to_json) - .at_path("_links/previewMarkup/href") + .at_path('_links/previewMarkup/href') end end - describe "commit" do + describe 'commit' do before do mock_permissions_for(current_user) do |mock| mock.allow_in_project :add_work_packages, project: end end - context "for a valid work package" do - it "links to the work package create api" do + context 'for a valid work package' do + it 'links to the work package create api' do expect(generated) .to be_json_eql(api_v3_paths.work_packages.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end - it "is a post" do + it 'is a post' do expect(generated) .to be_json_eql(:post.to_json) - .at_path("_links/commit/method") + .at_path('_links/commit/method') end end - context "for an invalid work package" do - let(:errors) { [API::Errors::Validation.new(:subject, "it is broken")] } + context 'for an invalid work package' do + let(:errors) { [API::Errors::Validation.new(:subject, 'it is broken')] } - it "has no link" do - expect(generated).not_to have_json_path("_links/commit/href") + it 'has no link' do + expect(generated).not_to have_json_path('_links/commit/href') end end - context "for a user with insufficient permissions" do + context 'for a user with insufficient permissions' do before do mock_permissions_for(current_user, &:forbid_everything) end - it "has no link" do - expect(generated).not_to have_json_path("_links/commit/href") + it 'has no link' do + expect(generated).not_to have_json_path('_links/commit/href') end end end - describe "customFields" do + describe 'customFields' do before do mock_permissions_for(current_user, &:forbid_everything) end - context "with the permission to select custom fields" do + context 'with the permission to select custom fields' do before do mock_permissions_for(current_user) do |mock| mock.allow_in_project :select_custom_fields, project: end end - it "has a link to set the custom fields for that project" do + it 'has a link to set the custom fields for that project' do expected = { href: project_settings_custom_fields_path(work_package.project), type: "text/html", @@ -160,23 +160,23 @@ expect(generated) .to be_json_eql(expected.to_json) - .at_path("_links/customFields") + .at_path('_links/customFields') end end - context "without the permission to select custom fields" do - it "has no link to set the custom fields for that project" do - expect(generated).not_to have_json_path("_links/customFields") + context 'without the permission to select custom fields' do + it 'has no link to set the custom fields for that project' do + expect(generated).not_to have_json_path('_links/customFields') end end end - describe "configureForm" do + describe 'configureForm' do before do mock_permissions_for(current_user, &:allow_everything) end - context "for an admin and with type" do + context 'for an admin and with type' do let(:type) { build_stubbed(:type) } let(:current_user) { build_stubbed(:admin) } let(:work_package) do @@ -187,7 +187,7 @@ type:) end - it "has a link to configure the form" do + it 'has a link to configure the form' do expected = { href: "/types/#{type.id}/edit?tab=form_configuration", type: "text/html", @@ -196,24 +196,24 @@ expect(generated) .to be_json_eql(expected.to_json) - .at_path("_links/configureForm") + .at_path('_links/configureForm') end end - context "for an admin and without type" do + context 'for an admin and without type' do before do allow(work_package).to receive(:type).and_return(nil) allow(work_package).to receive(:type_id).and_return(nil) end - it "has no link to configure the form" do - expect(generated).not_to have_json_path("_links/configureForm") + it 'has no link to configure the form' do + expect(generated).not_to have_json_path('_links/configureForm') end end - context "for a nonadmin" do - it "has no link to configure the form" do - expect(generated).not_to have_json_path("_links/configureForm") + context 'for a nonadmin' do + it 'has no link to configure the form' do + expect(generated).not_to have_json_path('_links/configureForm') end end end diff --git a/spec/lib/api/v3/work_packages/create_project_form_representer_spec.rb b/spec/lib/api/v3/work_packages/create_project_form_representer_spec.rb index a34da6d38309..38972e528dbe 100644 --- a/spec/lib/api/v3/work_packages/create_project_form_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/create_project_form_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++require 'rspec' -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::CreateProjectFormRepresenter do include API::V3::Utilities::PathHelper @@ -53,89 +53,89 @@ subject(:generated) { representer.to_json } - describe "_links" do + describe '_links' do it do expect(generated).to be_json_eql( api_v3_paths.create_project_work_package_form(work_package.project_id).to_json ) - .at_path("_links/self/href") + .at_path('_links/self/href') end it do - expect(generated).to be_json_eql(:post.to_json).at_path("_links/self/method") + expect(generated).to be_json_eql(:post.to_json).at_path('_links/self/method') end - describe "validate" do + describe 'validate' do it do expect(generated).to be_json_eql( api_v3_paths.create_project_work_package_form(work_package.project_id).to_json ) - .at_path("_links/validate/href") + .at_path('_links/validate/href') end it do - expect(generated).to be_json_eql(:post.to_json).at_path("_links/validate/method") + expect(generated).to be_json_eql(:post.to_json).at_path('_links/validate/method') end end - describe "preview markup" do + describe 'preview markup' do it do expect(generated).to be_json_eql( api_v3_paths.render_markup( link: api_v3_paths.project(work_package.project_id) ).to_json ) - .at_path("_links/previewMarkup/href") + .at_path('_links/previewMarkup/href') end it do - expect(generated).to be_json_eql(:post.to_json).at_path("_links/previewMarkup/method") + expect(generated).to be_json_eql(:post.to_json).at_path('_links/previewMarkup/method') end - it "contains link to work package" do + it 'contains link to work package' do expected_preview_link = api_v3_paths.render_markup(link: "/api/v3/projects/#{work_package.project_id}") expect(subject).to be_json_eql(expected_preview_link.to_json) - .at_path("_links/previewMarkup/href") + .at_path('_links/previewMarkup/href') end end - describe "commit" do - context "with a valid work package" do + describe 'commit' do + context 'with a valid work package' do it do expect(generated).to be_json_eql( api_v3_paths.work_packages_by_project(work_package.project_id).to_json ) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end it do - expect(generated).to be_json_eql(:post.to_json).at_path("_links/commit/method") + expect(generated).to be_json_eql(:post.to_json).at_path('_links/commit/method') end end - context "with an invalid work package" do - let(:errors) { [API::Errors::Validation.new(:subject, "it is broken")] } + context 'with an invalid work package' do + let(:errors) { [API::Errors::Validation.new(:subject, 'it is broken')] } it do - expect(generated).not_to have_json_path("_links/commit/href") + expect(generated).not_to have_json_path('_links/commit/href') end end - context "with the user having insufficient permissions" do + context 'with the user having insufficient permissions' do let(:permissions) { [] } it do - expect(generated).not_to have_json_path("_links/commit/href") + expect(generated).not_to have_json_path('_links/commit/href') end end end - describe "customFields" do - context "with the permission to select custom fields" do + describe 'customFields' do + context 'with the permission to select custom fields' do let(:permissions) { [:select_custom_fields] } - it "has a link to set the custom fields for that project" do + it 'has a link to set the custom fields for that project' do expected = { href: project_settings_custom_fields_path(work_package.project), type: "text/html", @@ -144,22 +144,22 @@ expect(generated) .to be_json_eql(expected.to_json) - .at_path("_links/customFields") + .at_path('_links/customFields') end end - context "without the permission to select custom fields" do - it "has no link to set the custom fields for that project" do - expect(generated).not_to have_json_path("_links/customFields") + context 'without the permission to select custom fields' do + it 'has no link to set the custom fields for that project' do + expect(generated).not_to have_json_path('_links/customFields') end end end - describe "configureForm" do + describe 'configureForm' do context "for an admin and with a type" do let(:user) { build_stubbed(:user, admin: true) } - it "has a link to configure the form" do + it 'has a link to configure the form' do expected = { href: "/types/#{type.id}/edit?tab=form_configuration", type: "text/html", @@ -168,23 +168,23 @@ expect(generated) .to be_json_eql(expected.to_json) - .at_path("_links/configureForm") + .at_path('_links/configureForm') end end - context "for an admin and without type" do + context 'for an admin and without type' do let(:type) { nil } let(:user) { build_stubbed(:user, admin: true) } - it "has no link to configure the form" do - expect(generated).not_to have_json_path("_links/configureForm") + it 'has no link to configure the form' do + expect(generated).not_to have_json_path('_links/configureForm') end end - context "for a non admin" do - it "has no link to configure the form" do - expect(generated).not_to have_json_path("_links/configureForm") + context 'for a non admin' do + it 'has no link to configure the form' do + expect(generated).not_to have_json_path('_links/configureForm') end end end diff --git a/spec/lib/api/v3/work_packages/eager_loading/cache_checksum_integration_spec.rb b/spec/lib/api/v3/work_packages/eager_loading/cache_checksum_integration_spec.rb index 5519a7e381e7..f0ebbf238428 100644 --- a/spec/lib/api/v3/work_packages/eager_loading/cache_checksum_integration_spec.rb +++ b/spec/lib/api/v3/work_packages/eager_loading/cache_checksum_integration_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++require 'rspec' -require "spec_helper" -require_relative "eager_loading_mock_wrapper" +require 'spec_helper' +require_relative 'eager_loading_mock_wrapper' RSpec.describe API::V3::WorkPackages::EagerLoading::Checksum do let(:project) { create(:project) } @@ -47,7 +47,7 @@ end let!(:type) { work_package.type } - describe ".apply" do + describe '.apply' do let!(:orig_checksum) do EagerLoadingMockWrapper .wrap(described_class, [work_package]) @@ -62,7 +62,7 @@ .cache_checksum end - it "produces a different checksum on changes to the status id" do + it 'produces a different checksum on changes to the status id' do new_status = create(:status) WorkPackage.where(id: work_package.id).update_all(status_id: new_status.id) @@ -71,70 +71,70 @@ .not_to eql orig_checksum end - it "produces a different checksum on changes to the status" do + it 'produces a different checksum on changes to the status' do work_package.status.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the author id" do + it 'produces a different checksum on changes to the author id' do WorkPackage.where(id: work_package.id).update_all(author_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the author" do + it 'produces a different checksum on changes to the author' do work_package.author.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the assigned_to id" do + it 'produces a different checksum on changes to the assigned_to id' do WorkPackage.where(id: work_package.id).update_all(assigned_to_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the assigned_to" do + it 'produces a different checksum on changes to the assigned_to' do work_package.assigned_to.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the responsible id" do + it 'produces a different checksum on changes to the responsible id' do WorkPackage.where(id: work_package.id).update_all(responsible_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the responsible" do + it 'produces a different checksum on changes to the responsible' do work_package.responsible.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the version id" do + it 'produces a different checksum on changes to the version id' do WorkPackage.where(id: work_package.id).update_all(version_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the version" do + it 'produces a different checksum on changes to the version' do work_package.version.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the type id" do + it 'produces a different checksum on changes to the type id' do new_type = create(:type) WorkPackage.where(id: work_package.id).update_all(type_id: new_type.id) @@ -142,49 +142,49 @@ .not_to eql orig_checksum end - it "produces a different checksum on changes to the type" do + it 'produces a different checksum on changes to the type' do work_package.type.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the priority id" do + it 'produces a different checksum on changes to the priority id' do WorkPackage.where(id: work_package.id).update_all(priority_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the priority" do + it 'produces a different checksum on changes to the priority' do work_package.priority.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the category id" do + it 'produces a different checksum on changes to the category id' do WorkPackage.where(id: work_package.id).update_all(category_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the category" do + it 'produces a different checksum on changes to the category' do work_package.category.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the budget id" do + it 'produces a different checksum on changes to the budget id' do WorkPackage.where(id: work_package.id).update_all(budget_id: 0) expect(new_checksum) .not_to eql orig_checksum end - it "produces a different checksum on changes to the budget" do + it 'produces a different checksum on changes to the budget' do work_package.budget.update_attribute(:updated_at, 10.seconds.from_now) expect(new_checksum) diff --git a/spec/lib/api/v3/work_packages/eager_loading/cost_eager_loading_integration_spec.rb b/spec/lib/api/v3/work_packages/eager_loading/cost_eager_loading_integration_spec.rb index 6114d77c6bf4..e89e434aed63 100644 --- a/spec/lib/api/v3/work_packages/eager_loading/cost_eager_loading_integration_spec.rb +++ b/spec/lib/api/v3/work_packages/eager_loading/cost_eager_loading_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::WorkPackages::WorkPackageEagerLoadingWrapper, "cost eager loading", type: :model do +RSpec.describe API::V3::WorkPackages::WorkPackageEagerLoadingWrapper, 'cost eager loading', type: :model do let(:project) do work_package.project end @@ -105,15 +105,15 @@ time_entry2 end - it "correctly calculates spent time" do + it 'correctly calculates spent time' do expect(scope.to_a.first.hours).to eql time_entry1.hours + time_entry2.hours end - it "correctly calculates labor costs" do + it 'correctly calculates labor costs' do expect(scope.first.labor_costs).to eql (user_rates.rate * (time_entry1.hours + time_entry2.hours)).to_f end - it "correctly calculates material costs" do + it 'correctly calculates material costs' do expect(scope.first.material_costs).to eql (cost_entry1.costs + cost_entry2.costs).to_f end end diff --git a/spec/lib/api/v3/work_packages/eager_loading/custom_actions_integration_spec.rb b/spec/lib/api/v3/work_packages/eager_loading/custom_actions_integration_spec.rb index 12b4cb180597..1f888d132ff0 100644 --- a/spec/lib/api/v3/work_packages/eager_loading/custom_actions_integration_spec.rb +++ b/spec/lib/api/v3/work_packages/eager_loading/custom_actions_integration_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++require 'rspec' -require "spec_helper" -require_relative "eager_loading_mock_wrapper" +require 'spec_helper' +require_relative 'eager_loading_mock_wrapper' RSpec.describe API::V3::WorkPackages::EagerLoading::CustomAction do let!(:work_package1) { create(:work_package) } @@ -50,8 +50,8 @@ login_as(user) end - describe ".apply" do - it "preloads the correct custom_actions" do + describe '.apply' do + it 'preloads the correct custom_actions' do wrapped = EagerLoadingMockWrapper.wrap(described_class, [work_package1, work_package2]) expect(work_package1) diff --git a/spec/lib/api/v3/work_packages/eager_loading/project_integration_spec.rb b/spec/lib/api/v3/work_packages/eager_loading/project_integration_spec.rb index 4953c0afd86b..0cd8c7814852 100644 --- a/spec/lib/api/v3/work_packages/eager_loading/project_integration_spec.rb +++ b/spec/lib/api/v3/work_packages/eager_loading/project_integration_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++require 'rspec' -require "spec_helper" -require_relative "eager_loading_mock_wrapper" +require 'spec_helper' +require_relative 'eager_loading_mock_wrapper' RSpec.describe API::V3::WorkPackages::EagerLoading::Project do let!(:parent_work_package1) { create(:work_package, project: parent_project) } @@ -39,8 +39,8 @@ let!(:parent_project) { create(:project) } let!(:child_project) { create(:project) } - describe ".apply" do - it "preloads the projects of the work packages, their parents and children" do + describe '.apply' do + it 'preloads the projects of the work packages, their parents and children' do wrapped = EagerLoadingMockWrapper.wrap(described_class, [work_package1, work_package2]) wrapped.each do |w| diff --git a/spec/lib/api/v3/work_packages/form_representer_spec.rb b/spec/lib/api/v3/work_packages/form_representer_spec.rb index 66edecbf4c68..3ee21d19a613 100644 --- a/spec/lib/api/v3/work_packages/form_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/form_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::FormRepresenter do include API::V3::Utilities::PathHelper @@ -45,19 +45,19 @@ described_class.new(work_package, current_user:, errors:) end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - it { is_expected.to be_json_eql("Form".to_json).at_path("_type") } + it { is_expected.to be_json_eql('Form'.to_json).at_path('_type') } - describe "validation errors" do - context "w/o errors" do - it { is_expected.to be_json_eql({}.to_json).at_path("_embedded/validationErrors") } + describe 'validation errors' do + context 'w/o errors' do + it { is_expected.to be_json_eql({}.to_json).at_path('_embedded/validationErrors') } end - context "with errors" do - let(:subject_error_message) { "Subject can't be blank!" } - let(:status_error_message) { "Status can't be blank!" } + context 'with errors' do + let(:subject_error_message) { 'Subject can\'t be blank!' } + let(:status_error_message) { 'Status can\'t be blank!' } let(:errors) { [subject_error, status_error] } let(:subject_error) { API::Errors::Validation.new(:subject, subject_error_message) } let(:status_error) { API::Errors::Validation.new(:status, status_error_message) } @@ -65,11 +65,11 @@ let(:api_status_error) { API::V3::Errors::ErrorRepresenter.new(status_error) } let(:api_errors) { { subject: api_subject_error, status: api_status_error } } - it { is_expected.to be_json_eql(api_errors.to_json).at_path("_embedded/validationErrors") } + it { is_expected.to be_json_eql(api_errors.to_json).at_path('_embedded/validationErrors') } end end - it { is_expected.to have_json_path("_embedded/payload") } - it { is_expected.to have_json_path("_embedded/schema") } + it { is_expected.to have_json_path('_embedded/payload') } + it { is_expected.to have_json_path('_embedded/schema') } end end diff --git a/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_representer_spec.rb b/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_representer_spec.rb index 9668be23d3c8..a27aaebc7173 100644 --- a/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_representer_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::Schema::WorkPackageSumsSchemaRepresenter do include API::V3::Utilities::PathHelper let(:custom_field) { build_stubbed(:issue_custom_field, :integer) } let(:available_custom_fields) { [custom_field] } - let(:schema) { double("wp_schema", available_custom_fields:) } - let(:current_user) { double("user", admin?: false) } + let(:schema) { double('wp_schema', available_custom_fields:) } + let(:current_user) { double('user', admin?: false) } let(:representer) do described_class.create(schema, current_user:) @@ -42,80 +42,80 @@ subject { representer.to_json } - context "self link" do - it "has a self link" do + context 'self link' do + it 'has a self link' do expected = { href: api_v3_paths.work_package_sums_schema } - expect(subject).to be_json_eql(expected.to_json).at_path("_links/self") + expect(subject).to be_json_eql(expected.to_json).at_path('_links/self') end end - context "estimated_time" do - it_behaves_like "has basic schema properties" do - let(:path) { "estimatedTime" } - let(:type) { "Duration" } - let(:name) { I18n.t("attributes.estimated_hours") } + context 'estimated_time' do + it_behaves_like 'has basic schema properties' do + let(:path) { 'estimatedTime' } + let(:type) { 'Duration' } + let(:name) { I18n.t('attributes.estimated_hours') } let(:required) { false } let(:writable) { false } end end - describe "storyPoints" do - it_behaves_like "has basic schema properties" do - let(:path) { "storyPoints" } - let(:type) { "Integer" } - let(:name) { I18n.t("activerecord.attributes.work_package.story_points") } + describe 'storyPoints' do + it_behaves_like 'has basic schema properties' do + let(:path) { 'storyPoints' } + let(:type) { 'Integer' } + let(:name) { I18n.t('activerecord.attributes.work_package.story_points') } let(:required) { false } let(:writable) { false } end end - describe "remainingTime" do - it_behaves_like "has basic schema properties" do - let(:path) { "remainingTime" } - let(:type) { "Duration" } - let(:name) { I18n.t("activerecord.attributes.work_package.remaining_hours") } + describe 'remainingTime' do + it_behaves_like 'has basic schema properties' do + let(:path) { 'remainingTime' } + let(:type) { 'Duration' } + let(:name) { I18n.t('activerecord.attributes.work_package.remaining_hours') } let(:required) { false } let(:writable) { false } end end - describe "overallCosts" do - it_behaves_like "has basic schema properties" do - let(:path) { "overallCosts" } - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.work_package.overall_costs") } + describe 'overallCosts' do + it_behaves_like 'has basic schema properties' do + let(:path) { 'overallCosts' } + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.work_package.overall_costs') } let(:required) { false } let(:writable) { false } end end - describe "laborCosts" do - it_behaves_like "has basic schema properties" do - let(:path) { "laborCosts" } - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.work_package.labor_costs") } + describe 'laborCosts' do + it_behaves_like 'has basic schema properties' do + let(:path) { 'laborCosts' } + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.work_package.labor_costs') } let(:required) { false } let(:writable) { false } end end - describe "materialCosts" do - it_behaves_like "has basic schema properties" do - let(:path) { "materialCosts" } - let(:type) { "String" } - let(:name) { I18n.t("activerecord.attributes.work_package.material_costs") } + describe 'materialCosts' do + it_behaves_like 'has basic schema properties' do + let(:path) { 'materialCosts' } + let(:type) { 'String' } + let(:name) { I18n.t('activerecord.attributes.work_package.material_costs') } let(:required) { false } let(:writable) { false } end end - context "custom field x" do - it_behaves_like "has basic schema properties" do + context 'custom field x' do + it_behaves_like 'has basic schema properties' do let(:path) { "customField#{custom_field.id}" } - let(:type) { "Integer" } + let(:type) { 'Integer' } let(:name) { custom_field.name } let(:required) { false } let(:writable) { false } diff --git a/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_spec.rb b/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_spec.rb index 31d45708cc18..40d85854f72d 100644 --- a/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_spec.rb +++ b/spec/lib/api/v3/work_packages/schema/work_package_sums_schema_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::Schema::WorkPackageSumsSchema do - let(:current_user) { double("current user") } + let(:current_user) { double('current user') } subject { described_class.new } - describe "#available_custom_fields" do + describe '#available_custom_fields' do let(:cf1) { double } let(:cf2) { double } let(:cf3) { double } - it "returns all custom fields listed as summable" do + it 'returns all custom fields listed as summable' do allow(WorkPackageCustomField) .to receive(:summable) { [cf1, cf2, cf3] } diff --git a/spec/lib/api/v3/work_packages/update_form_representer_spec.rb b/spec/lib/api/v3/work_packages/update_form_representer_spec.rb index 98a19232938a..2e52b256999c 100644 --- a/spec/lib/api/v3/work_packages/update_form_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/update_form_representer_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::UpdateFormRepresenter do include API::V3::Utilities::PathHelper @@ -49,51 +49,51 @@ end end - context "generation" do + context 'generation' do subject(:generated) { representer.to_json } - describe "_links" do - it { is_expected.to have_json_path("_links") } + describe '_links' do + it { is_expected.to have_json_path('_links') } - it { is_expected.to have_json_path("_links/self/href") } + it { is_expected.to have_json_path('_links/self/href') } - describe "validate" do - it { is_expected.to have_json_path("_links/validate/href") } + describe 'validate' do + it { is_expected.to have_json_path('_links/validate/href') } - it { is_expected.to be_json_eql(:post.to_json).at_path("_links/validate/method") } + it { is_expected.to be_json_eql(:post.to_json).at_path('_links/validate/method') } end - describe "preview markup" do - it { is_expected.to have_json_path("_links/previewMarkup/href") } + describe 'preview markup' do + it { is_expected.to have_json_path('_links/previewMarkup/href') } - it { is_expected.to be_json_eql(:post.to_json).at_path("_links/previewMarkup/method") } + it { is_expected.to be_json_eql(:post.to_json).at_path('_links/previewMarkup/method') } - it "contains link to work package" do + it 'contains link to work package' do body = parse_json(subject) - actual_preview_link = body["_links"]["previewMarkup"]["href"] - expected_preview_link = api_v3_paths.render_markup link: body["_links"]["commit"]["href"] + actual_preview_link = body['_links']['previewMarkup']['href'] + expected_preview_link = api_v3_paths.render_markup link: body['_links']['commit']['href'] expect(actual_preview_link).to eq(expected_preview_link) end end - describe "commit" do - context "valid work package" do - it { is_expected.to have_json_path("_links/commit/href") } + describe 'commit' do + context 'valid work package' do + it { is_expected.to have_json_path('_links/commit/href') } - it { is_expected.to be_json_eql(:patch.to_json).at_path("_links/commit/method") } + it { is_expected.to be_json_eql(:patch.to_json).at_path('_links/commit/method') } end - context "invalid work package" do - let(:errors) { [API::Errors::Validation.new(:subject, "it is broken")] } + context 'invalid work package' do + let(:errors) { [API::Errors::Validation.new(:subject, 'it is broken')] } - it { is_expected.not_to have_json_path("_links/commit/href") } + it { is_expected.not_to have_json_path('_links/commit/href') } end - context "user with insufficient permissions" do + context 'user with insufficient permissions' do let(:permissions) { [] } - it { is_expected.not_to have_json_path("_links/commit/href") } + it { is_expected.not_to have_json_path('_links/commit/href') } end end end diff --git a/spec/lib/api/v3/work_packages/work_package_at_timestamp_representer_rendering_spec.rb b/spec/lib/api/v3/work_packages/work_package_at_timestamp_representer_rendering_spec.rb index 3f51f419ea84..e88059b1f395 100644 --- a/spec/lib/api/v3/work_packages/work_package_at_timestamp_representer_rendering_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_at_timestamp_representer_rendering_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' # Note: The specs in this file do not attempt to test the properties themselves with all their possible # variations. This is done in length in the work_package_representer_spec.rb. Instead, the focus of the tests # here are on the selection of properties. -RSpec.describe API::V3::WorkPackages::WorkPackageAtTimestampRepresenter, "rendering" do +RSpec.describe API::V3::WorkPackages::WorkPackageAtTimestampRepresenter, 'rendering' do include API::V3::Utilities::PathHelper let(:current_user) { build_stubbed(:user) } @@ -57,7 +57,7 @@ let(:project) { build_stubbed(:project) } let(:custom_field) do build_stubbed(:string_wp_custom_field, - name: "String CF", + name: 'String CF', types: project.types, projects: [project]) end @@ -66,7 +66,7 @@ let(:custom_value) do build_stubbed(:custom_value, custom_field:, - value: "This is a string value") + value: 'This is a string value') end let(:work_package) do @@ -134,169 +134,169 @@ subject(:generated) { representer.to_json } - context "with all supported properties requested" do + context 'with all supported properties requested' do let(:expected_json) do { - "subject" => work_package.subject, - "startDate" => work_package.start_date, - "dueDate" => work_package.due_date, - "customField#{custom_field.id}" => "This is a string value", - "_meta" => { - "matchesFilters" => true, - "exists" => true, - "timestamp" => timestamp.to_s + 'subject' => work_package.subject, + 'startDate' => work_package.start_date, + 'dueDate' => work_package.due_date, + "customField#{custom_field.id}" => 'This is a string value', + '_meta' => { + 'matchesFilters' => true, + 'exists' => true, + 'timestamp' => timestamp.to_s }, - "_links" => { - "assignee" => { - "href" => api_v3_paths.user(assigned_to.id), - "title" => assigned_to.name + '_links' => { + 'assignee' => { + 'href' => api_v3_paths.user(assigned_to.id), + 'title' => assigned_to.name }, - "responsible" => { - "href" => api_v3_paths.user(responsible.id), - "title" => responsible.name + 'responsible' => { + 'href' => api_v3_paths.user(responsible.id), + 'title' => responsible.name }, - "project" => { - "href" => api_v3_paths.project(project.id), - "title" => project.name + 'project' => { + 'href' => api_v3_paths.project(project.id), + 'title' => project.name }, - "status" => { - "href" => api_v3_paths.status(status.id), - "title" => status.name + 'status' => { + 'href' => api_v3_paths.status(status.id), + 'title' => status.name }, - "type" => { - "href" => api_v3_paths.type(type.id), - "title" => type.name + 'type' => { + 'href' => api_v3_paths.type(type.id), + 'title' => type.name }, - "priority" => { - "href" => api_v3_paths.priority(priority.id), - "title" => priority.name + 'priority' => { + 'href' => api_v3_paths.priority(priority.id), + 'title' => priority.name }, - "version" => { - "href" => api_v3_paths.version(version.id), - "title" => version.name + 'version' => { + 'href' => api_v3_paths.version(version.id), + 'title' => version.name }, - "parent" => { - "href" => api_v3_paths.work_package(parent.id), - "title" => parent.subject + 'parent' => { + 'href' => api_v3_paths.work_package(parent.id), + 'title' => parent.subject }, - "self" => { - "href" => api_v3_paths.work_package(work_package.id, timestamps: timestamp), - "title" => work_package.subject + 'self' => { + 'href' => api_v3_paths.work_package(work_package.id, timestamps: timestamp), + 'title' => work_package.subject }, - "schema" => { - "href" => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) + 'schema' => { + 'href' => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) } } }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(subject) .to be_json_eql(expected_json) end end - context "with a subset of supported properties" do + context 'with a subset of supported properties' do let(:attributes_changed_to_baseline) { %w[start_date assigned_to_id version_id] } let(:expected_json) do { - "startDate" => work_package.start_date, - "_meta" => { - "matchesFilters" => true, - "exists" => true, - "timestamp" => timestamp.to_s + 'startDate' => work_package.start_date, + '_meta' => { + 'matchesFilters' => true, + 'exists' => true, + 'timestamp' => timestamp.to_s }, - "_links" => { - "assignee" => { - "href" => api_v3_paths.user(assigned_to.id), - "title" => assigned_to.name + '_links' => { + 'assignee' => { + 'href' => api_v3_paths.user(assigned_to.id), + 'title' => assigned_to.name }, - "version" => { - "href" => api_v3_paths.version(version.id), - "title" => version.name + 'version' => { + 'href' => api_v3_paths.version(version.id), + 'title' => version.name }, - "self" => { - "href" => api_v3_paths.work_package(work_package.id, timestamps: timestamp), - "title" => work_package.subject + 'self' => { + 'href' => api_v3_paths.work_package(work_package.id, timestamps: timestamp), + 'title' => work_package.subject }, - "schema" => { - "href" => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) + 'schema' => { + 'href' => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) } } }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(subject) .to be_json_eql(expected_json) end end - context "without a linked property" do + context 'without a linked property' do let(:attributes_changed_to_baseline) { %w[subject start_date] } let(:expected_json) do { - "subject" => work_package.subject, - "startDate" => work_package.start_date, - "_meta" => { - "matchesFilters" => true, - "exists" => true, - "timestamp" => timestamp.to_s + 'subject' => work_package.subject, + 'startDate' => work_package.start_date, + '_meta' => { + 'matchesFilters' => true, + 'exists' => true, + 'timestamp' => timestamp.to_s }, - "_links" => { - "self" => { - "href" => api_v3_paths.work_package(work_package.id, timestamps: timestamp), - "title" => work_package.subject + '_links' => { + 'self' => { + 'href' => api_v3_paths.work_package(work_package.id, timestamps: timestamp), + 'title' => work_package.subject }, - "schema" => { - "href" => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) + 'schema' => { + 'href' => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) } } }.to_json end - it "renders with only `self` in links" do + it 'renders with only `self` in links' do expect(subject) .to be_json_eql(expected_json) end end - context "with a nil value for a linked property" do + context 'with a nil value for a linked property' do let(:assigned_to) { nil } let(:attributes_changed_to_baseline) { %w[assigned_to_id] } let(:expected_json) do { - "_meta" => { - "matchesFilters" => true, - "exists" => true, - "timestamp" => timestamp.to_s + '_meta' => { + 'matchesFilters' => true, + 'exists' => true, + 'timestamp' => timestamp.to_s }, - "_links" => { - "assignee" => { - "href" => nil + '_links' => { + 'assignee' => { + 'href' => nil }, - "self" => { - "href" => api_v3_paths.work_package(work_package.id, timestamps: timestamp), - "title" => work_package.subject + 'self' => { + 'href' => api_v3_paths.work_package(work_package.id, timestamps: timestamp), + 'title' => work_package.subject }, - "schema" => { - "href" => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) + 'schema' => { + 'href' => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) } } }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(subject) .to be_json_eql(expected_json) end end - context "without the timestamp being in the attributes_by_timestamp collection" do + context 'without the timestamp being in the attributes_by_timestamp collection' do let(:attributes_changed_to_baseline) { %w[] } let(:exists_at_timestamp) { false } @@ -305,21 +305,21 @@ let(:expected_json) do { - "_meta" => { - "matchesFilters" => false, - "exists" => false, - "timestamp" => timestamp.to_s + '_meta' => { + 'matchesFilters' => false, + 'exists' => false, + 'timestamp' => timestamp.to_s } }.to_json end - it "has only the meta noting that the wp did not exist" do + it 'has only the meta noting that the wp did not exist' do expect(subject) .to be_json_eql(expected_json) end end - context "with a milestone typed work package" do + context 'with a milestone typed work package' do let(:type) { build_stubbed(:type_milestone) } # On a milestone, both dates will be the same let(:start_date) { due_date } @@ -327,31 +327,31 @@ let(:expected_json) do { - "date" => work_package.start_date, - "_meta" => { - "matchesFilters" => true, - "exists" => true, - "timestamp" => timestamp.to_s + 'date' => work_package.start_date, + '_meta' => { + 'matchesFilters' => true, + 'exists' => true, + 'timestamp' => timestamp.to_s }, - "_links" => { - "self" => { - "href" => api_v3_paths.work_package(work_package.id, timestamps: timestamp), - "title" => work_package.subject + '_links' => { + 'self' => { + 'href' => api_v3_paths.work_package(work_package.id, timestamps: timestamp), + 'title' => work_package.subject }, - "schema" => { - "href" => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) + 'schema' => { + 'href' => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) } } }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(subject) .to be_json_eql(expected_json) end end - context "with only one attribute changed to baseline but with the work package not existing (not visible) at current time" do + context 'with only one attribute changed to baseline but with the work package not existing (not visible) at current time' do # Note that while the work package in this test is configured to not exist at the current time (not visible), # the timestamp passed in isn't the current time. So this represents a case where the work package is no longer # visible but was visible at the timestamp provided. @@ -399,59 +399,59 @@ let(:expected_json) do { - "subject" => work_package.subject, - "startDate" => work_package.start_date, - "dueDate" => work_package.due_date, - "_meta" => { - "matchesFilters" => true, - "exists" => true, - "timestamp" => timestamp.to_s + 'subject' => work_package.subject, + 'startDate' => work_package.start_date, + 'dueDate' => work_package.due_date, + '_meta' => { + 'matchesFilters' => true, + 'exists' => true, + 'timestamp' => timestamp.to_s }, - "_links" => { - "assignee" => { - "href" => api_v3_paths.user(assigned_to.id), - "title" => assigned_to.name + '_links' => { + 'assignee' => { + 'href' => api_v3_paths.user(assigned_to.id), + 'title' => assigned_to.name }, - "responsible" => { - "href" => api_v3_paths.user(responsible.id), - "title" => responsible.name + 'responsible' => { + 'href' => api_v3_paths.user(responsible.id), + 'title' => responsible.name }, - "project" => { - "href" => api_v3_paths.project(project.id), - "title" => project.name + 'project' => { + 'href' => api_v3_paths.project(project.id), + 'title' => project.name }, - "status" => { - "href" => api_v3_paths.status(status.id), - "title" => status.name + 'status' => { + 'href' => api_v3_paths.status(status.id), + 'title' => status.name }, - "type" => { - "href" => api_v3_paths.type(type.id), - "title" => type.name + 'type' => { + 'href' => api_v3_paths.type(type.id), + 'title' => type.name }, - "priority" => { - "href" => api_v3_paths.priority(priority.id), - "title" => priority.name + 'priority' => { + 'href' => api_v3_paths.priority(priority.id), + 'title' => priority.name }, - "version" => { - "href" => api_v3_paths.version(version.id), - "title" => version.name + 'version' => { + 'href' => api_v3_paths.version(version.id), + 'title' => version.name }, - "parent" => { - "href" => api_v3_paths.work_package(parent.id), - "title" => parent.subject + 'parent' => { + 'href' => api_v3_paths.work_package(parent.id), + 'title' => parent.subject }, - "self" => { - "href" => api_v3_paths.work_package(work_package.id, timestamps: timestamp), - "title" => work_package.subject + 'self' => { + 'href' => api_v3_paths.work_package(work_package.id, timestamps: timestamp), + 'title' => work_package.subject }, - "schema" => { - "href" => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) + 'schema' => { + 'href' => api_v3_paths.work_package_schema(work_package.project_id, work_package.type_id) } } }.to_json end - it "renders as expected" do + it 'renders as expected' do expect(subject) .to be_json_eql(expected_json) end diff --git a/spec/lib/api/v3/work_packages/work_package_collection_representer_spec.rb b/spec/lib/api/v3/work_packages/work_package_collection_representer_spec.rb index 3b9889dc8726..96f317f3b805 100644 --- a/spec/lib/api/v3/work_packages/work_package_collection_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_collection_representer_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::WorkPackageCollectionRepresenter do include API::V3::Utilities::PathHelper create_shared_association_defaults_for_work_package_factory - let(:self_base_link) { "/api/v3/example" } + let(:self_base_link) { '/api/v3/example' } let(:work_packages) do created_work_packages WorkPackage.all @@ -72,7 +72,7 @@ query: ) end - let(:collection_inner_type) { "WorkPackage" } + let(:collection_inner_type) { 'WorkPackage' } current_user { user } @@ -88,78 +88,78 @@ subject(:collection) { representer.to_json } - describe "_links" do - describe "self" do - describe "when providing timestamps" do + describe '_links' do + describe 'self' do + describe 'when providing timestamps' do let(:timestamps) { [Timestamp.parse("2022-01-01T00:00:00Z"), Timestamp.parse("PT0S")] } let(:absolute_timestamp_strings) { timestamps.collect(&:absolute) } let(:absolute_timestamps_query_param) { { timestamps: absolute_timestamp_strings.join(",") }.to_query } - it "has the absolute timestamps within the self link" do + it 'has the absolute timestamps within the self link' do Timecop.freeze do expect(subject) .to include_json(absolute_timestamps_query_param.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end end - describe "when providing only the current timestamp" do + describe 'when providing only the current timestamp' do let(:timestamps) { [Timestamp.parse("PT0S")] } - it "has no timestamps within the self link" do + it 'has no timestamps within the self link' do Timecop.freeze do expect(subject) .not_to include_json("timestamps".to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end end end - describe "representations" do - context "when outside of a project and the user has the export_work_packages permission" do - let(:query_params) { { foo: "bar" } } + describe 'representations' do + context 'when outside of a project and the user has the export_work_packages permission' do + let(:query_params) { { foo: 'bar' } } let(:expected) do expected_query_params = query_params.merge(pageSize: 30, offset: 1) JSON.parse([ { - href: work_packages_path({ format: "pdf" }.merge(expected_query_params)), - type: "application/pdf", - identifier: "pdf", - title: I18n.t("export.format.pdf_overview_table") + href: work_packages_path({ format: 'pdf' }.merge(expected_query_params)), + type: 'application/pdf', + identifier: 'pdf', + title: I18n.t('export.format.pdf_overview_table') }, { - href: work_packages_path({ format: "pdf", show_images: true, show_report: true } + href: work_packages_path({ format: 'pdf', show_images: true, show_report: true } .merge(expected_query_params)), - identifier: "pdf-with-descriptions", - type: "application/pdf", - title: I18n.t("export.format.pdf_report_with_images") + identifier: 'pdf-with-descriptions', + type: 'application/pdf', + title: I18n.t('export.format.pdf_report_with_images') }, { - href: work_packages_path({ format: "pdf", show_report: true }.merge(expected_query_params)), - identifier: "pdf-descr", - type: "application/pdf", - title: I18n.t("export.format.pdf_report") + href: work_packages_path({ format: 'pdf', show_report: true }.merge(expected_query_params)), + identifier: 'pdf-descr', + type: 'application/pdf', + title: I18n.t('export.format.pdf_report') }, { - href: work_packages_path({ format: "csv" }.merge(expected_query_params)), - type: "text/csv", - identifier: "csv", - title: I18n.t("export.format.csv") + href: work_packages_path({ format: 'csv' }.merge(expected_query_params)), + type: 'text/csv', + identifier: 'csv', + title: I18n.t('export.format.csv') }, { - href: work_packages_path({ format: "atom" }.merge(expected_query_params)), - identifier: "atom", - type: "application/atom+xml", - title: I18n.t("export.format.atom") + href: work_packages_path({ format: 'atom' }.merge(expected_query_params)), + identifier: 'atom', + type: 'application/atom+xml', + title: I18n.t('export.format.atom') } ].to_json) end - it "has a collection of export formats" do - actual = JSON.parse(subject).dig("_links", "representations") + it 'has a collection of export formats' do + actual = JSON.parse(subject).dig('_links', 'representations') # As plugins might extend the representation, we only # check for a subset @@ -168,48 +168,48 @@ end end - context "when inside of a project and the user has the export_work_packages permission" do + context 'when inside of a project and the user has the export_work_packages permission' do let(:project) { build_stubbed(:project) } let(:expected) do expected_query_params = query_params.merge(pageSize: 30, offset: 1) JSON.parse([ { - href: project_work_packages_path(project, { format: "pdf" }.merge(expected_query_params)), - type: "application/pdf", - identifier: "pdf", - title: I18n.t("export.format.pdf_overview_table") + href: project_work_packages_path(project, { format: 'pdf' }.merge(expected_query_params)), + type: 'application/pdf', + identifier: 'pdf', + title: I18n.t('export.format.pdf_overview_table') }, { - href: project_work_packages_path(project, { format: "pdf", show_images: true, show_report: true } + href: project_work_packages_path(project, { format: 'pdf', show_images: true, show_report: true } .merge(expected_query_params)), - type: "application/pdf", - identifier: "pdf-with-descriptions", - title: I18n.t("export.format.pdf_report_with_images") + type: 'application/pdf', + identifier: 'pdf-with-descriptions', + title: I18n.t('export.format.pdf_report_with_images') }, { - href: project_work_packages_path(project, { format: "pdf", show_report: true }.merge(expected_query_params)), - type: "application/pdf", - identifier: "pdf-descr", - title: I18n.t("export.format.pdf_report") + href: project_work_packages_path(project, { format: 'pdf', show_report: true }.merge(expected_query_params)), + type: 'application/pdf', + identifier: 'pdf-descr', + title: I18n.t('export.format.pdf_report') }, { - href: project_work_packages_path(project, { format: "csv" }.merge(expected_query_params)), - identifier: "csv", - type: "text/csv", - title: I18n.t("export.format.csv") + href: project_work_packages_path(project, { format: 'csv' }.merge(expected_query_params)), + identifier: 'csv', + type: 'text/csv', + title: I18n.t('export.format.csv') }, { - href: project_work_packages_path(project, { format: "atom" }.merge(expected_query_params)), - identifier: "atom", - type: "application/atom+xml", - title: I18n.t("export.format.atom") + href: project_work_packages_path(project, { format: 'atom' }.merge(expected_query_params)), + identifier: 'atom', + type: 'application/atom+xml', + title: I18n.t('export.format.atom') } ].to_json) end - it "has a project scoped collection of export formats if inside a project" do - actual = JSON.parse(subject).dig("_links", "representations") + it 'has a project scoped collection of export formats if inside a project' do + actual = JSON.parse(subject).dig('_links', 'representations') # As plugins might extend the representation, we only # check for a subset @@ -218,29 +218,29 @@ end end - context "when the user lacks the export_work_packages permission" do + context 'when the user lacks the export_work_packages permission' do before do mock_permissions_for(user, &:forbid_everything) end - it "has no export links" do + it 'has no export links' do expect(collection) - .not_to have_json_path("_links/representations") + .not_to have_json_path('_links/representations') end end end - describe "customFields" do + describe 'customFields' do let(:project) { build_stubbed(:project) } - context "with the permission to select custom fields" do + context 'with the permission to select custom fields' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :select_custom_fields, project: end end - it "has a link to set the custom fields for that project" do + it 'has a link to set the custom fields for that project' do expected = { href: project_settings_custom_fields_path(project), type: "text/html", @@ -249,73 +249,73 @@ expect(collection) .to be_json_eql(expected.to_json) - .at_path("_links/customFields") + .at_path('_links/customFields') end end - context "without the permission to select custom fields" do + context 'without the permission to select custom fields' do before do mock_permissions_for(user, &:forbid_everything) end - it "has no link to set the custom fields for that project" do - expect(collection).not_to have_json_path("_links/customFields") + it 'has no link to set the custom fields for that project' do + expect(collection).not_to have_json_path('_links/customFields') end end - context "when not in a project" do + context 'when not in a project' do let(:project) { nil } - it "has no link to set the custom fields for that project" do - expect(collection).not_to have_json_path("_links/customFields") + it 'has no link to set the custom fields for that project' do + expect(collection).not_to have_json_path('_links/customFields') end end end end - describe "_embedded" do - describe "elements" do - context "for a work package that is not visible" do + describe '_embedded' do + describe 'elements' do + context 'for a work package that is not visible' do let(:total) { 1 } let(:permissions) { [] } let(:project) { created_work_packages.first.project } - it "renders a reduced WorkPackage element" do + it 'renders a reduced WorkPackage element' do expect(collection) .to be_json_eql( { - _type: "WorkPackage", + _type: 'WorkPackage', _links: { self: { href: api_v3_paths.work_package(first_wp.id) } } }.to_json - ).at_path("_embedded/elements/0") + ).at_path('_embedded/elements/0') end end end end - it "does not render groups" do - expect(collection).not_to have_json_path("groups") + it 'does not render groups' do + expect(collection).not_to have_json_path('groups') end - it "does not render sums" do - expect(collection).not_to have_json_path("totalSums") + it 'does not render sums' do + expect(collection).not_to have_json_path('totalSums') end - it "has a schemas link" do + it 'has a schemas link' do # All work packages in the collection are from the same project and have the same type path = api_v3_paths.work_package_schemas [first_wp.project_id, first_wp.type_id] expect(collection) .to be_json_eql(path.to_json) - .at_path("_links/schemas/href") + .at_path('_links/schemas/href') end - describe "ancestors" do - it "are being eager loaded" do + describe 'ancestors' do + it 'are being eager loaded' do representer.represented.each do |wp| expect(wp.work_package_ancestors).to be_a(Array) expect(wp.ancestors).to eq(wp.work_package_ancestors) @@ -323,219 +323,219 @@ end end - context "when the user has the edit_work_package permission in any project" do + context 'when the user has the edit_work_package permission in any project' do before do mock_permissions_for(user) do |mock| mock.allow_in_project *permissions, project: build_stubbed(:project) # any project end end - context "when allowed" do + context 'when allowed' do let(:permissions) { [:edit_work_packages] } - it "has a link to templated edit work_package" do + it 'has a link to templated edit work_package' do expect(collection) - .to be_json_eql(api_v3_paths.work_package_form("{work_package_id}").to_json) - .at_path("_links/editWorkPackage/href") + .to be_json_eql(api_v3_paths.work_package_form('{work_package_id}').to_json) + .at_path('_links/editWorkPackage/href') end end - context "when not allowed" do + context 'when not allowed' do let(:permissions) { [] } - it "has no link to templated edit work_package" do - expect(collection).not_to have_json_path("_links/editWorkPackage") + it 'has no link to templated edit work_package' do + expect(collection).not_to have_json_path('_links/editWorkPackage') end end end - context "when the user has the add_work_package permission in any project" do + context 'when the user has the add_work_package permission in any project' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_packages, project: build_stubbed(:project) # any project end end - it "has a link to create work_packages" do + it 'has a link to create work_packages' do expect(collection) .to be_json_eql(api_v3_paths.create_work_package_form.to_json) - .at_path("_links/createWorkPackage/href") + .at_path('_links/createWorkPackage/href') end - it "declares to use POST to create work_packages" do + it 'declares to use POST to create work_packages' do expect(collection) .to be_json_eql(:post.to_json) - .at_path("_links/createWorkPackage/method") + .at_path('_links/createWorkPackage/method') end - it "has a link to create work_packages immediately" do + it 'has a link to create work_packages immediately' do expect(collection) .to be_json_eql(api_v3_paths.work_packages.to_json) - .at_path("_links/createWorkPackageImmediate/href") + .at_path('_links/createWorkPackageImmediate/href') end - it "declares to use POST to create work_packages immediately" do + it 'declares to use POST to create work_packages immediately' do expect(collection) .to be_json_eql(:post.to_json) - .at_path("_links/createWorkPackageImmediate/method") + .at_path('_links/createWorkPackageImmediate/method') end - context "when in project context" do + context 'when in project context' do let(:project) { build_stubbed(:project) } - it "has no link to create work_packages" do + it 'has no link to create work_packages' do expect(collection) - .not_to have_json_path("_links/createWorkPackage") + .not_to have_json_path('_links/createWorkPackage') end - it "has no link to create work_packages immediately" do + it 'has no link to create work_packages immediately' do expect(collection) - .not_to have_json_path("_links/createWorkPackageImmediate") + .not_to have_json_path('_links/createWorkPackageImmediate') end end end - context "when the user lacks the add_work_package permission" do + context 'when the user lacks the add_work_package permission' do before do mock_permissions_for(user, &:forbid_everything) end - it "has no link to create work_packages" do + it 'has no link to create work_packages' do expect(collection) - .not_to have_json_path("_links/createWorkPackage") + .not_to have_json_path('_links/createWorkPackage') end - it "has no link to create work_packages immediately" do + it 'has no link to create work_packages immediately' do expect(collection) - .not_to have_json_path("_links/createWorkPackageImmediate") + .not_to have_json_path('_links/createWorkPackageImmediate') end end - context "with a magic page size" do + context 'with a magic page size' do let(:page_size_parameter) { -1 } - it_behaves_like "offset-paginated APIv3 collection" do + it_behaves_like 'offset-paginated APIv3 collection' do let(:page) { 1 } let(:page_size) { Setting.apiv3_max_page_size } let(:actual_count) { 5 } - let(:collection_type) { "WorkPackageCollection" } + let(:collection_type) { 'WorkPackageCollection' } end end - context "with a limited page size" do + context 'with a limited page size' do let(:page_size_parameter) { 2 } - context "when on the first page" do - it_behaves_like "offset-paginated APIv3 collection" do + context 'when on the first page' do + it_behaves_like 'offset-paginated APIv3 collection' do let(:page) { 1 } let(:page_size) { page_size_parameter } let(:actual_count) { page_size_parameter } - let(:collection_type) { "WorkPackageCollection" } + let(:collection_type) { 'WorkPackageCollection' } - it_behaves_like "links to next page by offset" + it_behaves_like 'links to next page by offset' end - it_behaves_like "has no link" do - let(:link) { "previousByOffset" } + it_behaves_like 'has no link' do + let(:link) { 'previousByOffset' } end end - context "when on the last page" do + context 'when on the last page' do let(:page_parameter) { 3 } - it_behaves_like "offset-paginated APIv3 collection" do + it_behaves_like 'offset-paginated APIv3 collection' do let(:page) { 3 } let(:page_size) { page_size_parameter } let(:actual_count) { 1 } - let(:collection_type) { "WorkPackageCollection" } + let(:collection_type) { 'WorkPackageCollection' } - it_behaves_like "links to previous page by offset" + it_behaves_like 'links to previous page by offset' end - it_behaves_like "has no link" do - let(:link) { "nextByOffset" } + it_behaves_like 'has no link' do + let(:link) { 'nextByOffset' } end end end - context "when passing a query_params hash" do - let(:query_params) { { a: "b", b: "c" } } + context 'when passing a query_params hash' do + let(:query_params) { { a: 'b', b: 'c' } } - it_behaves_like "has an untitled link" do - let(:link) { "self" } - let(:href) { "/api/v3/example?a=b&b=c&offset=1&pageSize=30" } + it_behaves_like 'has an untitled link' do + let(:link) { 'self' } + let(:href) { '/api/v3/example?a=b&b=c&offset=1&pageSize=30' } end end - context "when passing groups" do + context 'when passing groups' do let(:groups) do - group = { "custom" => "object" } + group = { 'custom' => 'object' } allow(group).to receive(:has_sums?).and_return false [group] end - it "renders the groups object as json" do - expect(collection).to be_json_eql(groups.to_json).at_path("groups") + it 'renders the groups object as json' do + expect(collection).to be_json_eql(groups.to_json).at_path('groups') end end - context "when passing groups with sums" do + context 'when passing groups with sums' do let(:groups) do - group = { "sums" => {} } + group = { 'sums' => {} } allow(group).to receive(:has_sums?).and_return true [group] end - it "renders the groups object as json" do - expect(collection).to be_json_eql(groups.to_json).at_path("groups") + it 'renders the groups object as json' do + expect(collection).to be_json_eql(groups.to_json).at_path('groups') end - it "has a link to the sums schema" do + it 'has a link to the sums schema' do expected = { href: api_v3_paths.work_package_sums_schema } - expect(collection).to be_json_eql(expected.to_json).at_path("_links/sumsSchema") + expect(collection).to be_json_eql(expected.to_json).at_path('_links/sumsSchema') end end - context "when passing sums" do + context 'when passing sums' do let(:total_sums) { OpenStruct.new(estimated_hours: 1) } - it "renders the groups object as json" do - expected = { "estimatedTime" => "PT1H", - "remainingTime" => nil, - "storyPoints" => nil } - expect(collection).to be_json_eql(expected.to_json).at_path("totalSums") + it 'renders the groups object as json' do + expected = { 'estimatedTime' => 'PT1H', + 'remainingTime' => nil, + 'storyPoints' => nil } + expect(collection).to be_json_eql(expected.to_json).at_path('totalSums') end - it "has a link to the sums schema" do + it 'has a link to the sums schema' do expected = { href: api_v3_paths.work_package_sums_schema } - expect(collection).to be_json_eql(expected.to_json).at_path("_links/sumsSchema") + expect(collection).to be_json_eql(expected.to_json).at_path('_links/sumsSchema') end end - context "when passing schemas" do + context 'when passing schemas' do let(:embed_schemas) { true } - it "embeds a schema collection", :aggregate_failures do + it 'embeds a schema collection', :aggregate_failures do expected_path = api_v3_paths.work_package_schema(first_wp.project.id, first_wp.type.id) expect(collection) .to be_json_eql(expected_path.to_json) - .at_path("_embedded/schemas/_embedded/elements/0/_links/self/href") + .at_path('_embedded/schemas/_embedded/elements/0/_links/self/href') # All work packages share the same project and type expect(collection) .to have_json_size(1) - .at_path("_embedded/schemas/_embedded/elements") + .at_path('_embedded/schemas/_embedded/elements') end - context "when having timestamps leads to a different schema at the baseline time (because of a different type)", + context 'when having timestamps leads to a different schema at the baseline time (because of a different type)', with_settings: { journal_aggregation_time_minutes: 0 } do let(:other_type) { create(:type) } let(:timestamps) { [Timestamp.parse("2023-01-01T00:00:00Z"), Timestamp.parse("PT0S")] } @@ -550,34 +550,34 @@ # another schema and set the creation date to be before the baseline time. create_list(:work_package, 1, - subject: "Some new subject", + subject: 'Some new subject', journals: { DateTime.parse("2022-01-01T00:00:00Z") => { type_id: other_type.id }, 1.day.ago => {} }) end - it "embeds a schema collection", :aggregate_failures do + it 'embeds a schema collection', :aggregate_failures do expect(collection) .to have_json_size(2) - .at_path("_embedded/schemas/_embedded/elements") + .at_path('_embedded/schemas/_embedded/elements') expected_former_path = api_v3_paths.work_package_schema(first_wp.project.id, other_type.id) expect(collection) .to be_json_eql(expected_former_path.to_json) - .at_path("_embedded/schemas/_embedded/elements/0/_links/self/href") + .at_path('_embedded/schemas/_embedded/elements/0/_links/self/href') expected_current_path = api_v3_paths.work_package_schema(first_wp.project.id, first_wp.type.id) expect(collection) .to be_json_eql(expected_current_path.to_json) - .at_path("_embedded/schemas/_embedded/elements/1/_links/self/href") + .at_path('_embedded/schemas/_embedded/elements/1/_links/self/href') end end end - context "when passing timestamps" do + context 'when passing timestamps' do let(:work_package) do create(:work_package, subject: "The current work package", @@ -595,103 +595,103 @@ let(:project) { create(:project) } let(:current_user) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project => %i[view_work_packages] }) end - shared_examples_for "includes the properties of the current work package" do - it "includes the properties of the current work package" do + shared_examples_for 'includes the properties of the current work package' do + it 'includes the properties of the current work package' do expect(collection) .to be_json_eql("The current work package".to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') end end - shared_examples_for "embeds the properties of the baseline work package" do - it "embeds the properties of the baseline work package in attributesByTimestamp" do + shared_examples_for 'embeds the properties of the baseline work package' do + it 'embeds the properties of the baseline work package in attributesByTimestamp' do expect(collection) .to be_json_eql("The original work package".to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") end - it "embeds the link to the baseline work package in attributesByTimestamp" do + it 'embeds the link to the baseline work package in attributesByTimestamp' do expect(collection) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.first).to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/self/href") end end - shared_examples_for "has the absolute timestamps within the self link" do + shared_examples_for 'has the absolute timestamps within the self link' do let(:absolute_timestamp_strings) { timestamps.collect(&:absolute) } let(:absolute_timestamps_query_param) { { timestamps: absolute_timestamp_strings.join(",") }.to_query } - it "has the absolute timestamps within the self link" do + it 'has the absolute timestamps within the self link' do expect(subject) .to include_json(absolute_timestamps_query_param.to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end - context "with baseline and current timestamps" do + context 'with baseline and current timestamps' do let(:timestamps) { [Timestamp.parse("2022-01-01T00:00:00Z"), Timestamp.parse("PT0S")] } - it_behaves_like "includes the properties of the current work package" - it_behaves_like "embeds the properties of the baseline work package" - it_behaves_like "has the absolute timestamps within the self link" + it_behaves_like 'includes the properties of the current work package' + it_behaves_like 'embeds the properties of the baseline work package' + it_behaves_like 'has the absolute timestamps within the self link' end - context "with current timestamp only" do + context 'with current timestamp only' do let(:timestamps) { [Timestamp.parse("PT0S")] } - it_behaves_like "includes the properties of the current work package" + it_behaves_like 'includes the properties of the current work package' - it "has no timestamps within the self link" do + it 'has no timestamps within the self link' do expect(subject) .not_to include_json("timestamps".to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end - context "with baseline timestamp only" do + context 'with baseline timestamp only' do let(:timestamps) { [Timestamp.parse("2022-01-01T00:00:00Z")] } - it "includes the properties of the baseline work package" do + it 'includes the properties of the baseline work package' do expect(collection) .to be_json_eql("The original work package".to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') end - it_behaves_like "has the absolute timestamps within the self link" + it_behaves_like 'has the absolute timestamps within the self link' end - context "with empty timestamp" do + context 'with empty timestamp' do let(:timestamps) { [] } - it_behaves_like "includes the properties of the current work package" + it_behaves_like 'includes the properties of the current work package' - it "has no timestamps within the self link" do + it 'has no timestamps within the self link' do expect(subject) .not_to include_json("timestamps".to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end - context "when passing a query" do - let(:search_term) { "original" } + context 'when passing a query' do + let(:search_term) { 'original' } let(:query) do build(:query, user: current_user, project: nil).tap do |query| query.filters.clear - query.add_filter "subject", "~", search_term + query.add_filter 'subject', '~', search_term query.timestamps = timestamps end end - context "with baseline and current timestamps", with_ee: %i[baseline_comparison] do + context 'with baseline and current timestamps', with_ee: %i[baseline_comparison] do let(:timestamps) { [Timestamp.parse("2022-01-01T00:00:00Z"), Timestamp.parse("PT0S")] } - describe "attributesByTimestamp" do - it "states whether the work package matches the query filters at the timestamp" do + describe 'attributesByTimestamp' do + it 'states whether the work package matches the query filters at the timestamp' do expect(subject) .to be_json_eql(true.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") diff --git a/spec/lib/api/v3/work_packages/work_package_representer_spec.rb b/spec/lib/api/v3/work_packages/work_package_representer_spec.rb index 89b590260ab1..c6d90efec6a0 100644 --- a/spec/lib/api/v3/work_packages/work_package_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::WorkPackageRepresenter do include API::V3::Utilities::PathHelper @@ -120,720 +120,720 @@ end end - describe ".new" do - it "is prevented as .create is to be used" do + describe '.new' do + it 'is prevented as .create is to be used' do expect { described_class.new(work_package, current_user:, embed_links:) } .to raise_error NoMethodError end end - include_context "eager loaded work package representer" + include_context 'eager loaded work package representer' - describe "generation" do + describe 'generation' do subject(:generated) { representer.to_json } - it { is_expected.to include_json("WorkPackage".to_json).at_path("_type") } + it { is_expected.to include_json('WorkPackage'.to_json).at_path('_type') } - describe "work_package" do - it { is_expected.to have_json_path("id") } + describe 'work_package' do + it { is_expected.to have_json_path('id') } - it_behaves_like "API V3 formattable", "description" do - let(:format) { "markdown" } + it_behaves_like 'API V3 formattable', 'description' do + let(:format) { 'markdown' } let(:raw) { work_package.description } let(:html) { "

    #{work_package.description}

    " } end - describe "scheduleManually" do - context "when no value" do - it "renders as false (default value)" do - expect(subject).to be_json_eql(false.to_json).at_path("scheduleManually") + describe 'scheduleManually' do + context 'when no value' do + it 'renders as false (default value)' do + expect(subject).to be_json_eql(false.to_json).at_path('scheduleManually') end end - context "when false" do + context 'when false' do let(:schedule_manually) { false } - it "renders as false" do - expect(subject).to be_json_eql(false.to_json).at_path("scheduleManually") + it 'renders as false' do + expect(subject).to be_json_eql(false.to_json).at_path('scheduleManually') end end - context "when true" do + context 'when true' do let(:schedule_manually) { true } - it "renders as true" do - expect(subject).to be_json_eql(true.to_json).at_path("scheduleManually") + it 'renders as true' do + expect(subject).to be_json_eql(true.to_json).at_path('scheduleManually') end end end - describe "startDate" do - it_behaves_like "has ISO 8601 date only" do + describe 'startDate' do + it_behaves_like 'has ISO 8601 date only' do let(:date) { start_date } - let(:json_path) { "startDate" } + let(:json_path) { 'startDate' } end - context "when it's nil" do + context 'when it\'s nil' do let(:start_date) { nil } - it "renders as null" do - expect(subject).to be_json_eql(nil.to_json).at_path("startDate") + it 'renders as null' do + expect(subject).to be_json_eql(nil.to_json).at_path('startDate') end end - context "when the work package has a milestone type" do + context 'when the work package has a milestone type' do let(:type_milestone) { true } - it "has no startDate" do - expect(subject).not_to have_json_path("startDate") + it 'has no startDate' do + expect(subject).not_to have_json_path('startDate') end end end - describe "dueDate" do - context "with a non milestone type" do - it_behaves_like "has ISO 8601 date only" do + describe 'dueDate' do + context 'with a non milestone type' do + it_behaves_like 'has ISO 8601 date only' do let(:date) { work_package.due_date } - let(:json_path) { "dueDate" } + let(:json_path) { 'dueDate' } end - context "with no finish date" do + context 'with no finish date' do let(:due_date) { nil } - it "renders as null" do - expect(subject).to be_json_eql(nil.to_json).at_path("dueDate") + it 'renders as null' do + expect(subject).to be_json_eql(nil.to_json).at_path('dueDate') end end end - context "with a milestone type" do + context 'with a milestone type' do let(:type_milestone) { true } - it "with no startDate" do - expect(subject).not_to have_json_path("dueDate") + it 'with no startDate' do + expect(subject).not_to have_json_path('dueDate') end end end - describe "date" do - context "with a milestone type" do + describe 'date' do + context 'with a milestone type' do let(:type_milestone) { true } - it_behaves_like "has ISO 8601 date only" do + it_behaves_like 'has ISO 8601 date only' do let(:date) { due_date } # could just as well be start_date - let(:json_path) { "date" } + let(:json_path) { 'date' } end - context "with no finish date" do + context 'with no finish date' do let(:due_date) { nil } - it "renders as null" do - expect(subject).to be_json_eql(nil.to_json).at_path("date") + it 'renders as null' do + expect(subject).to be_json_eql(nil.to_json).at_path('date') end end end - context "with not a milestone type" do - it "with no date" do - expect(subject).not_to have_json_path("date") + context 'with not a milestone type' do + it 'with no date' do + expect(subject).not_to have_json_path('date') end end end - describe "derivedStartDate" do - it_behaves_like "has ISO 8601 date only" do + describe 'derivedStartDate' do + it_behaves_like 'has ISO 8601 date only' do let(:date) { derived_start_date } - let(:json_path) { "derivedStartDate" } + let(:json_path) { 'derivedStartDate' } end - context "with no derived start date" do + context 'with no derived start date' do let(:derived_start_date) { nil } - it "renders as null" do + it 'renders as null' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("derivedStartDate") + .at_path('derivedStartDate') end end - context "when the work package has a milestone type" do + context 'when the work package has a milestone type' do let(:type_milestone) { true } - it "with no derivedStartDate" do + it 'with no derivedStartDate' do expect(subject) - .not_to have_json_path("derivedStartDate") + .not_to have_json_path('derivedStartDate') end end end - describe "derivedDueDate" do - it_behaves_like "has ISO 8601 date only" do + describe 'derivedDueDate' do + it_behaves_like 'has ISO 8601 date only' do let(:date) { derived_due_date } - let(:json_path) { "derivedDueDate" } + let(:json_path) { 'derivedDueDate' } end - context "with no derived due date" do + context 'with no derived due date' do let(:derived_due_date) { nil } - it "renders as null" do + it 'renders as null' do expect(subject) .to be_json_eql(nil.to_json) - .at_path("derivedDueDate") + .at_path('derivedDueDate') end end - context "when the work package has a milestone type" do + context 'when the work package has a milestone type' do let(:type_milestone) { true } - it "with no derivedDueDate" do + it 'with no derivedDueDate' do expect(subject) - .not_to have_json_path("derivedDueDate") + .not_to have_json_path('derivedDueDate') end end end - describe "duration" do + describe 'duration' do let(:duration) { 6 } - it { is_expected.to be_json_eql("P6D".to_json).at_path("duration") } + it { is_expected.to be_json_eql('P6D'.to_json).at_path('duration') } - context "with no duration" do + context 'with no duration' do let(:duration) { nil } - it "renders as null" do - expect(subject).to be_json_eql(nil.to_json).at_path("duration") + it 'renders as null' do + expect(subject).to be_json_eql(nil.to_json).at_path('duration') end end - context "when the work_package is a milestone" do + context 'when the work_package is a milestone' do let(:type_milestone) { true } - it "with no duration" do - expect(subject).not_to have_json_path("duration") + it 'with no duration' do + expect(subject).not_to have_json_path('duration') end end end - describe "ignoreNonWorkingDays" do + describe 'ignoreNonWorkingDays' do let(:ignore_non_working_days) { true } - context "with the value being `true`" do - it { is_expected.to be_json_eql(true.to_json).at_path("ignoreNonWorkingDays") } + context 'with the value being `true`' do + it { is_expected.to be_json_eql(true.to_json).at_path('ignoreNonWorkingDays') } end - context "with the value being `false`" do + context 'with the value being `false`' do let(:ignore_non_working_days) { false } - it { is_expected.to be_json_eql(false.to_json).at_path("ignoreNonWorkingDays") } + it { is_expected.to be_json_eql(false.to_json).at_path('ignoreNonWorkingDays') } end end - describe "createdAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'createdAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { work_package.created_at } - let(:json_path) { "createdAt" } + let(:json_path) { 'createdAt' } end end - describe "updatedAt" do - it_behaves_like "has UTC ISO 8601 date and time" do + describe 'updatedAt' do + it_behaves_like 'has UTC ISO 8601 date and time' do let(:date) { work_package.updated_at } - let(:json_path) { "updatedAt" } + let(:json_path) { 'updatedAt' } end end - it { is_expected.to have_json_path("subject") } + it { is_expected.to have_json_path('subject') } - describe "lock version" do - it { is_expected.to have_json_path("lockVersion") } + describe 'lock version' do + it { is_expected.to have_json_path('lockVersion') } - it { is_expected.to have_json_type(Integer).at_path("lockVersion") } + it { is_expected.to have_json_type(Integer).at_path('lockVersion') } - it { is_expected.to be_json_eql(work_package.lock_version.to_json).at_path("lockVersion") } + it { is_expected.to be_json_eql(work_package.lock_version.to_json).at_path('lockVersion') } end - describe "readonly" do - context "with no status" do + describe 'readonly' do + context 'with no status' do let(:status) { nil } - it "renders nothing" do - expect(subject).not_to have_json_path("readonly") + it 'renders nothing' do + expect(subject).not_to have_json_path('readonly') end end - context "when false", with_ee: %i[readonly_work_packages] do + context 'when false', with_ee: %i[readonly_work_packages] do let(:status) { build_stubbed(:status, is_readonly: false) } - it "renders as false" do - expect(subject).to be_json_eql(false.to_json).at_path("readonly") + it 'renders as false' do + expect(subject).to be_json_eql(false.to_json).at_path('readonly') end end - context "when true", with_ee: %i[readonly_work_packages] do + context 'when true', with_ee: %i[readonly_work_packages] do let(:status) { build_stubbed(:status, is_readonly: true) } - it "renders as true" do - expect(subject).to be_json_eql(true.to_json).at_path("readonly") + it 'renders as true' do + expect(subject).to be_json_eql(true.to_json).at_path('readonly') end end end end - describe "estimatedTime" do + describe 'estimatedTime' do let(:estimated_hours) { 6.5 } - it { is_expected.to be_json_eql("PT6H30M".to_json).at_path("estimatedTime") } + it { is_expected.to be_json_eql('PT6H30M'.to_json).at_path('estimatedTime') } end - describe "derivedEstimatedTime" do + describe 'derivedEstimatedTime' do let(:derived_estimated_hours) { 3.75 } - it { is_expected.to be_json_eql("PT3H45M".to_json).at_path("derivedEstimatedTime") } + it { is_expected.to be_json_eql('PT3H45M'.to_json).at_path('derivedEstimatedTime') } end - xdescribe "spentTime" do + xdescribe 'spentTime' do # spentTime is completely overwritten by costs # TODO: move specs from costs to here end - describe "percentageDone" do - describe "work package done ratio setting behavior" do - context "when setting enabled" do - it { expect(parse_json(subject)["percentageDone"]).to eq(50) } + describe 'percentageDone' do + describe 'work package done ratio setting behavior' do + context 'when setting enabled' do + it { expect(parse_json(subject)['percentageDone']).to eq(50) } end - context "when setting disabled" do + context 'when setting disabled' do before do allow(Setting) .to receive(:work_package_done_ratio) - .and_return("disabled") + .and_return('disabled') end - it { is_expected.not_to have_json_path("percentageDone") } + it { is_expected.not_to have_json_path('percentageDone') } end end end - describe "custom fields" do + describe 'custom fields' do let(:available_custom_fields) { [build_stubbed(:integer_wp_custom_field)] } - it "uses a CustomFieldInjector" do + it 'uses a CustomFieldInjector' do allow(API::V3::Utilities::CustomFieldInjector).to receive(:create_value_representer).and_call_original representer.to_json expect(API::V3::Utilities::CustomFieldInjector).to have_received(:create_value_representer) end end - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { "/api/v3/work_packages/#{work_package.id}" } let(:title) { work_package.subject } end - describe "update links" do - describe "update by form" do - it_behaves_like "has an untitled link" do - let(:link) { "update" } + describe 'update links' do + describe 'update by form' do + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.work_package_form(work_package.id) } end - it "is a post link" do - expect(subject).to be_json_eql("post".to_json).at_path("_links/update/method") + it 'is a post link' do + expect(subject).to be_json_eql('post'.to_json).at_path('_links/update/method') end end - describe "immediate update" do - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + describe 'immediate update' do + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.work_package(work_package.id) } end - it "is a patch link" do - expect(subject).to be_json_eql("patch".to_json).at_path("_links/updateImmediately/method") + it 'is a patch link' do + expect(subject).to be_json_eql('patch'.to_json).at_path('_links/updateImmediately/method') end end - context "when user is not allowed to edit work packages" do + context 'when user is not allowed to edit work packages' do let(:permissions) { all_permissions - [:edit_work_packages] } - it_behaves_like "has no link" do - let(:link) { "update" } + it_behaves_like 'has no link' do + let(:link) { 'update' } end - it_behaves_like "has no link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has no link' do + let(:link) { 'updateImmediately' } end end - context "when user lacks edit permission but has assign_versions" do + context 'when user lacks edit permission but has assign_versions' do let(:permissions) { all_permissions - [:edit_work_packages] + [:assign_versions] } - it_behaves_like "has an untitled link" do - let(:link) { "update" } + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.work_package_form(work_package.id) } end - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.work_package(work_package.id) } end end - context "when user lacks edit permission but has change_work_package_status" do + context 'when user lacks edit permission but has change_work_package_status' do let(:permissions) { all_permissions - [:edit_work_packages] + [:change_work_package_status] } - it_behaves_like "has an untitled link" do - let(:link) { "update" } + it_behaves_like 'has an untitled link' do + let(:link) { 'update' } let(:href) { api_v3_paths.work_package_form(work_package.id) } end - it_behaves_like "has an untitled link" do - let(:link) { "updateImmediately" } + it_behaves_like 'has an untitled link' do + let(:link) { 'updateImmediately' } let(:href) { api_v3_paths.work_package(work_package.id) } end end end - describe "status" do - it_behaves_like "has a titled link" do - let(:link) { "status" } + describe 'status' do + it_behaves_like 'has a titled link' do + let(:link) { 'status' } let(:href) { "/api/v3/statuses/#{work_package.status_id}" } let(:title) { work_package.status.name } end end - describe "type" do - it_behaves_like "has a titled link" do - let(:link) { "type" } + describe 'type' do + it_behaves_like 'has a titled link' do + let(:link) { 'type' } let(:href) { "/api/v3/types/#{work_package.type_id}" } let(:title) { work_package.type.name } end end - describe "author" do - it_behaves_like "has a titled link" do - let(:link) { "author" } + describe 'author' do + it_behaves_like 'has a titled link' do + let(:link) { 'author' } let(:href) { "/api/v3/users/#{work_package.author.id}" } let(:title) { work_package.author.name } end end - describe "assignee" do - context "as a user" do + describe 'assignee' do + context 'as a user' do let(:assignee) { build_stubbed(:user) } - it_behaves_like "has a titled link" do - let(:link) { "assignee" } + it_behaves_like 'has a titled link' do + let(:link) { 'assignee' } let(:href) { "/api/v3/users/#{work_package.assigned_to.id}" } let(:title) { work_package.assigned_to.name } end end - context "as a group" do + context 'as a group' do let(:assignee) { build_stubbed(:group) } - it_behaves_like "has a titled link" do - let(:link) { "assignee" } + it_behaves_like 'has a titled link' do + let(:link) { 'assignee' } let(:href) { "/api/v3/groups/#{work_package.assigned_to.id}" } let(:title) { work_package.assigned_to.name } end end - context "as a placeholder user" do + context 'as a placeholder user' do let(:assignee) { build_stubbed(:placeholder_user) } - it_behaves_like "has a titled link" do - let(:link) { "assignee" } + it_behaves_like 'has a titled link' do + let(:link) { 'assignee' } let(:href) { "/api/v3/placeholder_users/#{work_package.assigned_to.id}" } let(:title) { work_package.assigned_to.name } end end - context "as a deleted user" do + context 'as a deleted user' do let(:assignee) { build_stubbed(:deleted_user) } - it_behaves_like "has a titled link" do - let(:link) { "assignee" } + it_behaves_like 'has a titled link' do + let(:link) { 'assignee' } let(:href) { "/api/v3/users/#{work_package.assigned_to.id}" } let(:title) { work_package.assigned_to.name } end end - context "as not set" do - it_behaves_like "has an empty link" do - let(:link) { "assignee" } + context 'as not set' do + it_behaves_like 'has an empty link' do + let(:link) { 'assignee' } end end end - describe "responsible" do - context "as a user" do + describe 'responsible' do + context 'as a user' do let(:responsible) { build_stubbed(:user) } - it_behaves_like "has a titled link" do - let(:link) { "responsible" } + it_behaves_like 'has a titled link' do + let(:link) { 'responsible' } let(:href) { "/api/v3/users/#{work_package.responsible.id}" } let(:title) { work_package.responsible.name } end end - context "as a group" do + context 'as a group' do let(:responsible) { build_stubbed(:group) } - it_behaves_like "has a titled link" do - let(:link) { "responsible" } + it_behaves_like 'has a titled link' do + let(:link) { 'responsible' } let(:href) { "/api/v3/groups/#{work_package.responsible.id}" } let(:title) { work_package.responsible.name } end end - context "as a placeholder user" do + context 'as a placeholder user' do let(:responsible) { build_stubbed(:placeholder_user) } - it_behaves_like "has a titled link" do - let(:link) { "responsible" } + it_behaves_like 'has a titled link' do + let(:link) { 'responsible' } let(:href) { "/api/v3/placeholder_users/#{work_package.responsible.id}" } let(:title) { work_package.responsible.name } end end - context "as a deleted user" do + context 'as a deleted user' do let(:responsible) { build_stubbed(:deleted_user) } - it_behaves_like "has a titled link" do - let(:link) { "responsible" } + it_behaves_like 'has a titled link' do + let(:link) { 'responsible' } let(:href) { "/api/v3/users/#{work_package.responsible.id}" } let(:title) { work_package.responsible.name } end end - context "as not set" do - it_behaves_like "has an empty link" do - let(:link) { "responsible" } + context 'as not set' do + it_behaves_like 'has an empty link' do + let(:link) { 'responsible' } end end end - describe "revisions" do - it_behaves_like "has an untitled link" do - let(:link) { "revisions" } + describe 'revisions' do + it_behaves_like 'has an untitled link' do + let(:link) { 'revisions' } let(:href) do api_v3_paths.work_package_revisions(work_package.id) end end - context "when user lacks the view_changesets permission" do + context 'when user lacks the view_changesets permission' do let(:permissions) { all_permissions - [:view_changesets] } - it_behaves_like "has no link" do - let(:link) { "revisions" } + it_behaves_like 'has no link' do + let(:link) { 'revisions' } end end end - describe "version" do - let(:embedded_path) { "_embedded/version" } - let(:href_path) { "_links/version/href" } + describe 'version' do + let(:embedded_path) { '_embedded/version' } + let(:href_path) { '_links/version/href' } - context "when no version set" do - it_behaves_like "has an empty link" do - let(:link) { "version" } + context 'when no version set' do + it_behaves_like 'has an empty link' do + let(:link) { 'version' } end end - context "when version is set" do + context 'when version is set' do let!(:version) { create(:version, project:) } before do work_package.version = version end - it_behaves_like "has a titled link" do - let(:link) { "version" } + it_behaves_like 'has a titled link' do + let(:link) { 'version' } let(:href) { api_v3_paths.version(version.id) } let(:title) { version.to_s } end - it "has the version embedded" do - expect(subject).to be_json_eql("Version".to_json).at_path("#{embedded_path}/_type") + it 'has the version embedded' do + expect(subject).to be_json_eql('Version'.to_json).at_path("#{embedded_path}/_type") expect(subject).to be_json_eql(version.name.to_json).at_path("#{embedded_path}/name") end end end - describe "project" do - let(:embedded_path) { "_embedded/project" } - let(:href_path) { "_links/project/href" } + describe 'project' do + let(:embedded_path) { '_embedded/project' } + let(:href_path) { '_links/project/href' } - it_behaves_like "has a titled link" do - let(:link) { "project" } + it_behaves_like 'has a titled link' do + let(:link) { 'project' } let(:href) { api_v3_paths.project(project.id) } let(:title) { project.name } end - it "has the project embedded" do - expect(subject).to be_json_eql("Project".to_json).at_path("#{embedded_path}/_type") + it 'has the project embedded' do + expect(subject).to be_json_eql('Project'.to_json).at_path("#{embedded_path}/_type") expect(subject).to be_json_eql(project.name.to_json).at_path("#{embedded_path}/name") end end - describe "category" do - let(:embedded_path) { "_embedded/category" } - let(:href_path) { "_links/category/href" } + describe 'category' do + let(:embedded_path) { '_embedded/category' } + let(:href_path) { '_links/category/href' } - context "when no category set" do - it_behaves_like "has an empty link" do - let(:link) { "category" } + context 'when no category set' do + it_behaves_like 'has an empty link' do + let(:link) { 'category' } end end - context "when category is set" do + context 'when category is set' do let!(:category) { build_stubbed(:category) } before do work_package.category = category end - it_behaves_like "has a titled link" do - let(:link) { "category" } + it_behaves_like 'has a titled link' do + let(:link) { 'category' } let(:href) { api_v3_paths.category(category.id) } let(:title) { category.name } end - it "has the category embedded" do - expect(subject).to have_json_type(Hash).at_path("_embedded/category") - expect(subject).to be_json_eql("Category".to_json).at_path("#{embedded_path}/_type") + it 'has the category embedded' do + expect(subject).to have_json_type(Hash).at_path('_embedded/category') + expect(subject).to be_json_eql('Category'.to_json).at_path("#{embedded_path}/_type") expect(subject).to be_json_eql(category.name.to_json).at_path("#{embedded_path}/name") end end end - describe "priority" do - it_behaves_like "has a titled link" do - let(:link) { "priority" } + describe 'priority' do + it_behaves_like 'has a titled link' do + let(:link) { 'priority' } let(:href) { api_v3_paths.priority(priority.id) } let(:title) { priority.name } end - it "has the priority embedded" do - expect(subject).to be_json_eql("Priority".to_json).at_path("_embedded/priority/_type") - expect(subject).to be_json_eql(priority.name.to_json).at_path("_embedded/priority/name") + it 'has the priority embedded' do + expect(subject).to be_json_eql('Priority'.to_json).at_path('_embedded/priority/_type') + expect(subject).to be_json_eql(priority.name.to_json).at_path('_embedded/priority/name') end end - describe "budget" do - context "with the user having the view_budgets permission" do + describe 'budget' do + context 'with the user having the view_budgets permission' do let(:permissions) { [:view_budgets] } - it_behaves_like "has a titled link" do - let(:link) { "budget" } + it_behaves_like 'has a titled link' do + let(:link) { 'budget' } let(:href) { "/api/v3/budgets/#{budget.id}" } let(:title) { budget.subject } end - it "has the budget embedded" do + it 'has the budget embedded' do expect(subject) .to be_json_eql(budget.subject.to_json) - .at_path("_embedded/budget/subject") + .at_path('_embedded/budget/subject') end end - context "with the user lacking the view_budgets permission" do - it "has no link to the budget" do + context 'with the user lacking the view_budgets permission' do + it 'has no link to the budget' do expect(subject) - .not_to have_json_path("_links/budget") + .not_to have_json_path('_links/budget') end - it "has no budget embedded" do + it 'has no budget embedded' do expect(subject) - .not_to have_json_path("_embedded/budget") + .not_to have_json_path('_embedded/budget') end end end - describe "schema" do - it_behaves_like "has an untitled link" do - let(:link) { "schema" } + describe 'schema' do + it_behaves_like 'has an untitled link' do + let(:link) { 'schema' } let(:href) do api_v3_paths.work_package_schema(work_package.project.id, work_package.type.id) end end end - describe "attachments" do - it_behaves_like "has an untitled link" do - let(:link) { "attachments" } + describe 'attachments' do + it_behaves_like 'has an untitled link' do + let(:link) { 'attachments' } let(:href) { api_v3_paths.attachments_by_work_package(work_package.id) } end - it "embeds the attachments as collection" do - expect(subject).to be_json_eql("Collection".to_json).at_path("_embedded/attachments/_type") + it 'embeds the attachments as collection' do + expect(subject).to be_json_eql('Collection'.to_json).at_path('_embedded/attachments/_type') end - it_behaves_like "has an untitled link" do - let(:link) { "addAttachment" } + it_behaves_like 'has an untitled link' do + let(:link) { 'addAttachment' } let(:href) { api_v3_paths.attachments_by_work_package(work_package.id) } end - context "when work package blocked" do + context 'when work package blocked' do before do allow(work_package).to receive(:readonly_status?).and_return true end - it_behaves_like "has no link" do - let(:link) { "addAttachment" } + it_behaves_like 'has no link' do + let(:link) { 'addAttachment' } end end - it "addAttachments is a post link" do - expect(subject).to be_json_eql("post".to_json).at_path("_links/addAttachment/method") + it 'addAttachments is a post link' do + expect(subject).to be_json_eql('post'.to_json).at_path('_links/addAttachment/method') end - context "when user is not allowed to edit work packages" do + context 'when user is not allowed to edit work packages' do let(:permissions) { all_permissions - %i[edit_work_packages] } - it_behaves_like "has no link" do - let(:link) { "addAttachment" } + it_behaves_like 'has no link' do + let(:link) { 'addAttachment' } end end end - describe "fileLinks" do - it_behaves_like "has an untitled link" do - let(:link) { "fileLinks" } + describe 'fileLinks' do + it_behaves_like 'has an untitled link' do + let(:link) { 'fileLinks' } let(:href) { api_v3_paths.file_links(work_package.id) } end - it_behaves_like "has an untitled action link" do + it_behaves_like 'has an untitled action link' do let(:permission) { :manage_file_links } - let(:link) { "addFileLink" } + let(:link) { 'addFileLink' } let(:href) { api_v3_paths.file_links(work_package.id) } - let(:method) { "post" } + let(:method) { 'post' } end - context "when user has no permission to view file links" do + context 'when user has no permission to view file links' do let(:permissions) { all_permissions - %i[view_file_links] } - it_behaves_like "has no link" do - let(:link) { "fileLinks" } + it_behaves_like 'has no link' do + let(:link) { 'fileLinks' } end end end - context "when the user is not watching the work package" do - it "has a link to watch" do + context 'when the user is not watching the work package' do + it 'has a link to watch' do expect(subject) .to be_json_eql(api_v3_paths.work_package_watchers(work_package.id).to_json) - .at_path("_links/watch/href") + .at_path('_links/watch/href') end - it "does not have a link to unwatch" do - expect(subject).not_to have_json_path("_links/unwatch/href") + it 'does not have a link to unwatch' do + expect(subject).not_to have_json_path('_links/unwatch/href') end end - context "when the user is watching the work package" do + context 'when the user is watching the work package' do let(:watchers) { [build_stubbed(:watcher, watchable: work_package, user: current_user)] } before do @@ -842,138 +842,138 @@ .and_return(watchers) end - it "has a link to unwatch" do + it 'has a link to unwatch' do expect(subject) .to be_json_eql(api_v3_paths.watcher(current_user.id, work_package.id).to_json) - .at_path("_links/unwatch/href") + .at_path('_links/unwatch/href') end - it "does not have a link to watch" do - expect(subject).not_to have_json_path("_links/watch/href") + it 'does not have a link to watch' do + expect(subject).not_to have_json_path('_links/watch/href') end end - context "when the user has permission to add comments" do - it "has a link to add comment" do - expect(subject).to have_json_path("_links/addComment") + context 'when the user has permission to add comments' do + it 'has a link to add comment' do + expect(subject).to have_json_path('_links/addComment') end end - context "when the user does not have the permission to add comments" do + context 'when the user does not have the permission to add comments' do let(:permissions) { all_permissions - [:add_work_package_notes] } - it "does not have a link to add comment" do - expect(subject).not_to have_json_path("_links/addComment/href") + it 'does not have a link to add comment' do + expect(subject).not_to have_json_path('_links/addComment/href') end end - context "when the user has the permission to add and remove watchers" do - it "has a link to add watcher" do + context 'when the user has the permission to add and remove watchers' do + it 'has a link to add watcher' do expect(subject).to be_json_eql( api_v3_paths.work_package_watchers(work_package.id).to_json ) - .at_path("_links/addWatcher/href") + .at_path('_links/addWatcher/href') end - it "has a link to remove watcher" do + it 'has a link to remove watcher' do expect(subject).to be_json_eql( - api_v3_paths.watcher("{user_id}", work_package.id).to_json + api_v3_paths.watcher('{user_id}', work_package.id).to_json ) - .at_path("_links/removeWatcher/href") + .at_path('_links/removeWatcher/href') end end - context "when the user does not have the permission to add watchers" do + context 'when the user does not have the permission to add watchers' do let(:permissions) { all_permissions - [:add_work_package_watchers] } - it "does not have a link to add watcher" do - expect(subject).not_to have_json_path("_links/addWatcher/href") + it 'does not have a link to add watcher' do + expect(subject).not_to have_json_path('_links/addWatcher/href') end end - context "when the user does not have the permission to remove watchers" do + context 'when the user does not have the permission to remove watchers' do let(:permissions) { all_permissions - [:delete_work_package_watchers] } - it "does not have a link to remove watcher" do - expect(subject).not_to have_json_path("_links/removeWatcher/href") + it 'does not have a link to remove watcher' do + expect(subject).not_to have_json_path('_links/removeWatcher/href') end end - describe "watchers link" do - context "when the user is allowed to see watchers" do - it_behaves_like "has an untitled link" do - let(:link) { "watchers" } + describe 'watchers link' do + context 'when the user is allowed to see watchers' do + it_behaves_like 'has an untitled link' do + let(:link) { 'watchers' } let(:href) { api_v3_paths.work_package_watchers work_package.id } end end - context "when the user is not allowed to see watchers" do + context 'when the user is not allowed to see watchers' do let(:permissions) { all_permissions - [:view_work_package_watchers] } - it_behaves_like "has no link" do - let(:link) { "watchers" } + it_behaves_like 'has no link' do + let(:link) { 'watchers' } end end end - describe "relations" do - it_behaves_like "has an untitled link" do - let(:link) { "relations" } + describe 'relations' do + it_behaves_like 'has an untitled link' do + let(:link) { 'relations' } let(:href) { "/api/v3/work_packages/#{work_package.id}/relations" } end - context "when the user has the permission to manage relations" do - it "has a link to add relation" do - expect(subject).to have_json_path("_links/addRelation/href") + context 'when the user has the permission to manage relations' do + it 'has a link to add relation' do + expect(subject).to have_json_path('_links/addRelation/href') end end - context "when the user does not have the permission to manage relations" do + context 'when the user does not have the permission to manage relations' do let(:permissions) { all_permissions - [:manage_work_package_relations] } - it "does not have a link to add relation" do - expect(subject).not_to have_json_path("_links/addRelation/href") + it 'does not have a link to add relation' do + expect(subject).not_to have_json_path('_links/addRelation/href') end end end - context "when the user has the permission to add work packages" do - it "has a link to add child" do + context 'when the user has the permission to add work packages' do + it 'has a link to add child' do expect(subject).to be_json_eql("/api/v3/projects/#{project.identifier}/work_packages".to_json) - .at_path("_links/addChild/href") + .at_path('_links/addChild/href') end end - context "when the user does not have the permission to add work packages" do + context 'when the user does not have the permission to add work packages' do let(:permissions) { all_permissions - [:add_work_packages] } - it "does not have a link to add child" do - expect(subject).not_to have_json_path("_links/addChild/href") + it 'does not have a link to add child' do + expect(subject).not_to have_json_path('_links/addChild/href') end end - describe "timeEntries" do - context "when the user has the permission to view time entries" do - it_behaves_like "has a titled link" do - let(:link) { "timeEntries" } + describe 'timeEntries' do + context 'when the user has the permission to view time entries' do + it_behaves_like 'has a titled link' do + let(:link) { 'timeEntries' } let(:href) do api_v3_paths.path_for(:time_entries, filters: [{ work_package_id: { operator: "=", values: [work_package.id.to_s] } }]) end - let(:title) { "Time entries" } + let(:title) { 'Time entries' } end end - context "when the user does not have the permission to view time entries" do + context 'when the user does not have the permission to view time entries' do let(:permissions) { all_permissions - [:view_time_entries] } - it "does not have a link to timeEntries" do - expect(subject).not_to have_json_path("_links/timeEntries/href") + it 'does not have a link to timeEntries' do + expect(subject).not_to have_json_path('_links/timeEntries/href') end end end - describe "linked relations" do + describe 'linked relations' do let(:project) { create(:project, public: false) } let(:forbidden_project) { create(:project, public: false) } let(:user) { create(:user, member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) } @@ -983,7 +983,7 @@ allow(Setting).to receive(:cross_project_work_package_relations?).and_return(true) end - describe "parent" do + describe 'parent' do let(:visible_parent) do build_stubbed(:work_package) do |wp| allow(wp) @@ -999,67 +999,67 @@ end end - context "with no parent" do - it_behaves_like "has an empty link" do - let(:link) { "parent" } + context 'with no parent' do + it_behaves_like 'has an empty link' do + let(:link) { 'parent' } end end - context "when parent is visible" do + context 'when parent is visible' do let(:parent) { visible_parent } - it_behaves_like "has a titled link" do - let(:link) { "parent" } + it_behaves_like 'has a titled link' do + let(:link) { 'parent' } let(:href) { api_v3_paths.work_package(visible_parent.id) } let(:title) { visible_parent.subject } end end - context "when parent not visible" do + context 'when parent not visible' do let(:parent) { invisible_parent } - it_behaves_like "has an empty link" do - let(:link) { "parent" } + it_behaves_like 'has an empty link' do + let(:link) { 'parent' } end end end - describe "ancestors" do + describe 'ancestors' do let(:root) { build_stubbed(:work_package, project:) } let(:intermediate) do build_stubbed(:work_package, parent: root, project:) end - context "when ancestors are visible" do + context 'when ancestors are visible' do before do allow(work_package).to receive(:visible_ancestors) .and_return([root, intermediate]) end - it "renders two items in ancestors" do - expect(subject).to have_json_size(2).at_path("_links/ancestors") - expect(parse_json(subject)["_links"]["ancestors"][0]["title"]) + it 'renders two items in ancestors' do + expect(subject).to have_json_size(2).at_path('_links/ancestors') + expect(parse_json(subject)['_links']['ancestors'][0]['title']) .to eq(root.subject) - expect(parse_json(subject)["_links"]["ancestors"][1]["title"]) + expect(parse_json(subject)['_links']['ancestors'][1]['title']) .to eq(intermediate.subject) expect(work_package).to have_received(:visible_ancestors) end end - context "when ancestors are invisible" do + context 'when ancestors are invisible' do before do allow(work_package).to receive(:visible_ancestors) .and_return([]) end - it "renders empty ancestors" do - expect(subject).to have_json_size(0).at_path("_links/ancestors") + it 'renders empty ancestors' do + expect(subject).to have_json_size(0).at_path('_links/ancestors') expect(work_package).to have_received(:visible_ancestors) end end end - describe "children" do + describe 'children' do let(:work_package) { create(:work_package, project:) } let!(:forbidden_work_package) do create(:work_package, @@ -1067,89 +1067,89 @@ parent: work_package) end - it { expect(subject).not_to have_json_path("_links/children") } + it { expect(subject).not_to have_json_path('_links/children') } - describe "visible and invisible children" do + describe 'visible and invisible children' do let!(:child) do create(:work_package, project:, parent: work_package) end - it { expect(subject).to have_json_size(1).at_path("_links/children") } + it { expect(subject).to have_json_size(1).at_path('_links/children') } it do - expect(parse_json(subject)["_links"]["children"][0]["title"]).to eq(child.subject) + expect(parse_json(subject)['_links']['children'][0]['title']).to eq(child.subject) end end end end - it_behaves_like "has an untitled action link" do - let(:link) { "delete" } + it_behaves_like 'has an untitled action link' do + let(:link) { 'delete' } let(:href) { api_v3_paths.work_package(work_package.id) } let(:method) { :delete } let(:permission) { :delete_work_packages } end - describe "logTime" do - it_behaves_like "has a titled action link" do - let(:link) { "logTime" } + describe 'logTime' do + it_behaves_like 'has a titled action link' do + let(:link) { 'logTime' } let(:permission) { %i(log_time log_own_time) } let(:href) { api_v3_paths.time_entries } let(:title) { "Log time on #{work_package.subject}" } end end - describe "move" do - it_behaves_like "has a titled action link" do - let(:link) { "move" } - let(:href) { work_package_path(work_package, "move/new") } + describe 'move' do + it_behaves_like 'has a titled action link' do + let(:link) { 'move' } + let(:href) { work_package_path(work_package, 'move/new') } let(:permission) { :move_work_packages } let(:title) { "Move #{work_package.subject}" } end end - describe "copy" do - it_behaves_like "has a titled action link" do - let(:link) { "copy" } - let(:href) { work_package_path(work_package, "copy") } + describe 'copy' do + it_behaves_like 'has a titled action link' do + let(:link) { 'copy' } + let(:href) { work_package_path(work_package, 'copy') } let(:permission) { :add_work_packages } let(:title) { "Copy #{work_package.subject}" } end end - describe "pdf" do - it_behaves_like "has a titled action link" do - let(:link) { "pdf" } + describe 'pdf' do + it_behaves_like 'has a titled action link' do + let(:link) { 'pdf' } let(:permission) { :export_work_packages } let(:href) { "/work_packages/#{work_package.id}.pdf" } let(:title) { "Export as PDF" } end end - describe "atom" do - context "with feeds enabled", with_settings: { feeds_enabled?: true } do - it_behaves_like "has a titled action link" do - let(:link) { "atom" } + describe 'atom' do + context 'with feeds enabled', with_settings: { feeds_enabled?: true } do + it_behaves_like 'has a titled action link' do + let(:link) { 'atom' } let(:permission) { :export_work_packages } let(:href) { "/work_packages/#{work_package.id}.atom" } let(:title) { "Atom feed" } end end - context "with feeds disabled", with_settings: { feeds_enabled?: false } do + context 'with feeds disabled', with_settings: { feeds_enabled?: false } do let(:permissions) { all_permissions + [:export_work_packages] } - it_behaves_like "has no link" do - let(:link) { "atom" } + it_behaves_like 'has no link' do + let(:link) { 'atom' } end end end - describe "changeParent" do - it_behaves_like "has a titled action link" do - let(:link) { "changeParent" } + describe 'changeParent' do + it_behaves_like 'has a titled action link' do + let(:link) { 'changeParent' } let(:href) { api_v3_paths.work_package(work_package.id) } let(:permission) { :manage_subtasks } let(:title) { "Change parent of #{work_package.subject}" } @@ -1157,46 +1157,46 @@ end end - describe "availableWatchers" do - it_behaves_like "has an untitled action link" do - let(:link) { "availableWatchers" } + describe 'availableWatchers' do + it_behaves_like 'has an untitled action link' do + let(:link) { 'availableWatchers' } let(:href) { api_v3_paths.available_watchers(work_package.id) } let(:permission) { :add_work_package_watchers } end end - describe "customFields" do - it_behaves_like "has a titled action link" do - let(:link) { "customFields" } + describe 'customFields' do + it_behaves_like 'has a titled action link' do + let(:link) { 'customFields' } let(:permission) { :select_custom_fields } let(:href) { project_settings_custom_fields_path(work_package.project.identifier) } - let(:title) { "Custom fields" } + let(:title) { 'Custom fields' } end end - describe "formConfiguration" do - context "when not admin" do - it_behaves_like "has no link" do - let(:link) { "formConfiguration" } + describe 'formConfiguration' do + context 'when not admin' do + it_behaves_like 'has no link' do + let(:link) { 'formConfiguration' } end end - context "when admin" do + context 'when admin' do let(:current_user) { build_stubbed(:admin) } - it_behaves_like "has a titled link" do - let(:link) { "configureForm" } - let(:href) { edit_type_path(work_package.type_id, tab: "form_configuration") } - let(:title) { "Configure form" } + it_behaves_like 'has a titled link' do + let(:link) { 'configureForm' } + let(:href) { edit_type_path(work_package.type_id, tab: 'form_configuration') } + let(:title) { 'Configure form' } end end end - describe "customActions" do - it "has a collection of customActions" do + describe 'customActions' do + it 'has a collection of customActions' do unassign_action = build_stubbed(:custom_action, actions: [CustomActions::Actions::AssignedTo.new(value: nil)], - name: "Unassign") + name: 'Unassign') allow(work_package) .to receive(:custom_actions) .and_return([unassign_action]) @@ -1210,33 +1210,33 @@ expect(subject) .to be_json_eql(expected.to_json) - .at_path("_links/customActions") + .at_path('_links/customActions') end end end - describe "_embedded" do - it { is_expected.to have_json_type(Object).at_path("_embedded") } + describe '_embedded' do + it { is_expected.to have_json_type(Object).at_path('_embedded') } - describe "status" do - it { is_expected.to have_json_path("_embedded/status") } + describe 'status' do + it { is_expected.to have_json_path('_embedded/status') } - it { is_expected.to be_json_eql("Status".to_json).at_path("_embedded/status/_type") } + it { is_expected.to be_json_eql('Status'.to_json).at_path('_embedded/status/_type') } - it { is_expected.to be_json_eql(status.name.to_json).at_path("_embedded/status/name") } + it { is_expected.to be_json_eql(status.name.to_json).at_path('_embedded/status/name') } it { - expect(subject).to be_json_eql(status.is_closed.to_json).at_path("_embedded/status/isClosed") + expect(subject).to be_json_eql(status.is_closed.to_json).at_path('_embedded/status/isClosed') } end - describe "activities" do - it "is not embedded" do - expect(subject).not_to have_json_path("_embedded/activities") + describe 'activities' do + it 'is not embedded' do + expect(subject).not_to have_json_path('_embedded/activities') end end - describe "relations" do + describe 'relations' do let(:relation) do build_stubbed(:relation, from: work_package) @@ -1254,30 +1254,30 @@ .and_return([relation]) end - it "embeds a collection" do + it 'embeds a collection' do expect(subject) - .to be_json_eql("Collection".to_json) - .at_path("_embedded/relations/_type") + .to be_json_eql('Collection'.to_json) + .at_path('_embedded/relations/_type') end - it "embeds with an href containing the work_package" do + it 'embeds with an href containing the work_package' do expect(subject) .to be_json_eql(api_v3_paths.work_package_relations(work_package.id).to_json) - .at_path("_embedded/relations/_links/self/href") + .at_path('_embedded/relations/_links/self/href') end - it "embeds the visible relations" do + it 'embeds the visible relations' do expect(subject) .to be_json_eql(1.to_json) - .at_path("_embedded/relations/total") + .at_path('_embedded/relations/total') expect(subject) .to be_json_eql(api_v3_paths.relation(relation.id).to_json) - .at_path("_embedded/relations/_embedded/elements/0/_links/self/href") + .at_path('_embedded/relations/_embedded/elements/0/_links/self/href') end end - describe "fileLinks" do + describe 'fileLinks' do let(:storage) { build_stubbed(:nextcloud_storage) } let(:file_link) { build_stubbed(:file_link, storage:, container: work_package) } @@ -1285,45 +1285,45 @@ allow(work_package).to receive(:file_links).and_return([file_link]) end - it "embeds a collection" do + it 'embeds a collection' do expect(subject) - .to be_json_eql("Collection".to_json) - .at_path("_embedded/fileLinks/_type") + .to be_json_eql('Collection'.to_json) + .at_path('_embedded/fileLinks/_type') end - it "embeds with an href containing the work_package" do + it 'embeds with an href containing the work_package' do expect(subject) .to be_json_eql(api_v3_paths.file_links(work_package.id).to_json) - .at_path("_embedded/fileLinks/_links/self/href") + .at_path('_embedded/fileLinks/_links/self/href') end - it "embeds the visible file links" do + it 'embeds the visible file links' do expect(subject) .to be_json_eql(1.to_json) - .at_path("_embedded/fileLinks/total") + .at_path('_embedded/fileLinks/total') expect(subject) .to be_json_eql(api_v3_paths.file_link(file_link.id).to_json) - .at_path("_embedded/fileLinks/_embedded/elements/0/_links/self/href") + .at_path('_embedded/fileLinks/_embedded/elements/0/_links/self/href') end end - describe "customActions" do - it "has an array of customActions" do + describe 'customActions' do + it 'has an array of customActions' do unassign_action = build_stubbed(:custom_action, actions: [CustomActions::Actions::AssignedTo.new(value: nil)], - name: "Unassign") + name: 'Unassign') allow(work_package) .to receive(:custom_actions) .and_return([unassign_action]) expect(subject) - .to be_json_eql("Unassign".to_json) - .at_path("_embedded/customActions/0/name") + .to be_json_eql('Unassign'.to_json) + .at_path('_embedded/customActions/0/name') end end - context "when passing timestamps" do + context 'when passing timestamps' do let(:timestamps) { [Timestamp.new(baseline_time), Timestamp.now] } let(:baseline_time) { Time.zone.parse("2022-01-01") } let(:work_pacakges) { WorkPackage.where(id: work_package.id) } @@ -1341,8 +1341,8 @@ current_user do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project => %i[view_work_packages view_file_links] }) end @@ -1356,25 +1356,25 @@ .and_call_original end - describe "attributesByTimestamp" do - it "has an array" do - expect(JSON.parse(subject)["_embedded"]["attributesByTimestamp"]).to be_an Array + describe 'attributesByTimestamp' do + it 'has an array' do + expect(JSON.parse(subject)['_embedded']['attributesByTimestamp']).to be_an Array end - it "has the historic attributes for each timestamp when they differ from the current attributes" do + it 'has the historic attributes for each timestamp when they differ from the current attributes' do expect(subject) - .to be_json_eql("The original work package".to_json) + .to be_json_eql('The original work package'.to_json) .at_path("_embedded/attributesByTimestamp/0/subject") end - it "skips the historic attributes when they are the same as the current attributes" do + it 'skips the historic attributes when they are the same as the current attributes' do expect(subject) .to have_json_path("_embedded/attributesByTimestamp/1") expect(subject) .not_to have_json_path("_embedded/attributesByTimestamp/1/subject") end - it "has a link to the work package at the timestamp" do + it 'has a link to the work package at the timestamp' do expect(subject) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: [timestamps[0]]).to_json) .at_path("_embedded/attributesByTimestamp/0/_links/self/href") @@ -1383,8 +1383,8 @@ .at_path("_embedded/attributesByTimestamp/1/_links/self/href") end - it "has no information about whether the work package matches the query filters at the timestamp " \ - "because there are no filters without a query" do + it 'has no information about whether the work package matches the query filters at the timestamp ' \ + 'because there are no filters without a query' do expect(subject) .not_to have_json_path("_embedded/attributesByTimestamp/0/_meta/matchesFilters") expect(subject) @@ -1392,27 +1392,27 @@ end end - describe "_meta" do - describe "matchesFilters" do - it "does not have this meta field without a query given" do + describe '_meta' do + describe 'matchesFilters' do + it 'does not have this meta field without a query given' do expect(subject) - .not_to have_json_path("_meta/matchesFilters") + .not_to have_json_path('_meta/matchesFilters') end end end - context "when passing a query" do - let(:search_term) { "original" } + context 'when passing a query' do + let(:search_term) { 'original' } let(:query) do build(:query, user: current_user, project: nil).tap do |query| query.filters.clear - query.add_filter "subject", "~", search_term + query.add_filter 'subject', '~', search_term query.timestamps = timestamps end end - describe "attributesByTimestamp", with_ee: %i[baseline_comparison] do - it "states whether the work package matches the query filters at the timestamp" do + describe 'attributesByTimestamp', with_ee: %i[baseline_comparison] do + it 'states whether the work package matches the query filters at the timestamp' do expect(subject) .to be_json_eql(true.to_json) .at_path("_embedded/attributesByTimestamp/0/_meta/matchesFilters") @@ -1422,35 +1422,35 @@ end end - describe "_links" do - it_behaves_like "has a titled link" do - let(:link) { "self" } + describe '_links' do + it_behaves_like 'has a titled link' do + let(:link) { 'self' } let(:href) { api_v3_paths.work_package(work_package.id, timestamps:) } let(:title) { work_package.name } end - context "when changing timestamps it updates the link" do - it_behaves_like "has a titled link" do + context 'when changing timestamps it updates the link' do + it_behaves_like 'has a titled link' do before do representer.to_json representer.timestamps = [] end - let(:link) { "self" } + let(:link) { 'self' } let(:href) { api_v3_paths.work_package(work_package.id) } let(:title) { work_package.name } end end end - describe "_meta" do - describe "matchesFilters" do - it "states whether the work package matches the query filters at the last timestamp" do + describe '_meta' do + describe 'matchesFilters' do + it 'states whether the work package matches the query filters at the last timestamp' do # If this value is false, it means that the work package has been found by the query # at another of the given timestamps, e.g. the baseline timestamp. expect(subject) .to be_json_eql(false.to_json) - .at_path("_meta/matchesFilters") + .at_path('_meta/matchesFilters') end end end @@ -1458,8 +1458,8 @@ end end - describe "caching" do - it "is based on the representer's cache_key" do + describe 'caching' do + it 'is based on the representer\'s cache_key' do allow(OpenProject::Cache) .to receive(:fetch) .and_return({ _links: {} }.to_json) @@ -1475,7 +1475,7 @@ .to have_received(:fetch).with(representer.json_cache_key) end - describe "#json_cache_key" do + describe '#json_cache_key' do let(:category) { build_stubbed(:category) } let(:assigned_to) { build_stubbed(:user) } let(:responsible) { build_stubbed(:user) } @@ -1486,18 +1486,18 @@ work_package.responsible = responsible end - it "includes the name of the representer class" do + it 'includes the name of the representer class' do expect(representer.json_cache_key) - .to include("API", "V3", "WorkPackages", "WorkPackageRepresenter") + .to include('API', 'V3', 'WorkPackages', 'WorkPackageRepresenter') end - it "changes when the locale changes" do + it 'changes when the locale changes' do expect( I18n.with_locale(:fr) { representer.json_cache_key } ).not_to eq(representer.json_cache_key) end - it "changes when the feeds_enabled? setting is switched" do + it 'changes when the feeds_enabled? setting is switched' do expect do allow(Setting) .to receive(:feeds_enabled?) @@ -1505,21 +1505,21 @@ end.to change(representer, :json_cache_key) end - it "changes when the work_package_done_ratio setting is changes" do + it 'changes when the work_package_done_ratio setting is changes' do expect do allow(Setting) .to receive(:work_package_done_ratio) - .and_return("status") + .and_return('status') end.to change(representer, :json_cache_key) end - it "changes when the work_package is updated" do + it 'changes when the work_package is updated' do expect do work_package.updated_at = 20.seconds.from_now end.to change(representer, :json_cache_key) end - it "factors in the eager loaded cache_checksum" do + it 'factors in the eager loaded cache_checksum' do allow(work_package) .to receive(:cache_checksum) .and_return(srand) @@ -1533,12 +1533,12 @@ end end - describe "parsing" do - describe "duration" do + describe 'parsing' do + describe 'duration' do subject { representer } - it "parses form iso8601 format" do - subject.duration = "P6D" + it 'parses form iso8601 format' do + subject.duration = 'P6D' expect(subject.represented.duration).to eq(6) end end diff --git a/spec/lib/api/v3/work_packages/work_package_sql_representer_rendering_spec.rb b/spec/lib/api/v3/work_packages/work_package_sql_representer_rendering_spec.rb index 3a82a1dfb20e..08e8c0caff49 100644 --- a/spec/lib/api/v3/work_packages/work_package_sql_representer_rendering_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_sql_representer_rendering_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe API::V3::WorkPackages::WorkPackageSqlRepresenter, "rendering" do +RSpec.describe API::V3::WorkPackages::WorkPackageSqlRepresenter, 'rendering' do include API::V3::Utilities::PathHelper subject(:json) do @@ -56,14 +56,14 @@ let(:author) { create(:user) } let(:responsible) { nil } - let(:select) { { "*" => {} } } + let(:select) { { '*' => {} } } current_user do create(:user) end - context "when rendering all supported properties" do - context "for a work_package" do + context 'when rendering all supported properties' do + context 'for a work_package' do let(:expected) do { _type: "WorkPackage", @@ -94,13 +94,13 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - context "for a milestone work_package" do + context 'for a milestone work_package' do let(:is_milestone) { true } let(:expected) do { @@ -131,16 +131,16 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json).to be_json_eql(expected.to_json) end end end - shared_examples_for "principal link" do |link_name, only_user: false| + shared_examples_for 'principal link' do |link_name, only_user: false| let(:select) { { link_name => {} } } - context "with a user" do + context 'with a user' do let(:principal_object) { create(:user) } let(:expected) do @@ -154,14 +154,14 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end unless only_user - context "with a group" do + context 'with a group' do let(:principal_object) { create(:group) } let(:expected) do @@ -175,13 +175,13 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end end - context "with a placeholder user" do + context 'with a placeholder user' do let(:principal_object) { create(:placeholder_user) } let(:expected) do @@ -195,7 +195,7 @@ } end - it "renders as expected" do + it 'renders as expected' do expect(json) .to be_json_eql(expected.to_json) end @@ -203,20 +203,20 @@ end end - describe "assignee link" do - it_behaves_like "principal link", "assignee" do + describe 'assignee link' do + it_behaves_like 'principal link', 'assignee' do let(:assignee) { principal_object } end end - describe "responsible link" do - it_behaves_like "principal link", "responsible" do + describe 'responsible link' do + it_behaves_like 'principal link', 'responsible' do let(:responsible) { principal_object } end end - describe "author link" do - it_behaves_like "principal link", "author", only_user: true do + describe 'author link' do + it_behaves_like 'principal link', 'author', only_user: true do let(:author) { principal_object } end end diff --git a/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb b/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb index 732a48bb2cab..e2c7ff6254dd 100644 --- a/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb +++ b/spec/lib/api/v3/work_packages/work_package_sums_representer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::WorkPackageSumsRepresenter do let(:custom_field) do @@ -37,7 +37,7 @@ end end let(:sums) do - double("sums", + double('sums', story_points: 5, remaining_hours: 10, estimated_hours: 5, @@ -54,50 +54,50 @@ subject { representer.to_json } - context "estimated_time" do - it "is represented" do - expected = "PT5H" - expect(subject).to be_json_eql(expected.to_json).at_path("estimatedTime") + context 'estimated_time' do + it 'is represented' do + expected = 'PT5H' + expect(subject).to be_json_eql(expected.to_json).at_path('estimatedTime') end end - context "remainingTime" do - it "is represented" do - expected = "PT10H" - expect(subject).to be_json_eql(expected.to_json).at_path("remainingTime") + context 'remainingTime' do + it 'is represented' do + expected = 'PT10H' + expect(subject).to be_json_eql(expected.to_json).at_path('remainingTime') end end - context "storyPoints" do - it "is represented" do - expect(subject).to be_json_eql(sums.story_points.to_json).at_path("storyPoints") + context 'storyPoints' do + it 'is represented' do + expect(subject).to be_json_eql(sums.story_points.to_json).at_path('storyPoints') end end - context "materialCosts" do - it "is represented" do + context 'materialCosts' do + it 'is represented' do expected = "5.00 EUR" - expect(subject).to be_json_eql(expected.to_json).at_path("materialCosts") + expect(subject).to be_json_eql(expected.to_json).at_path('materialCosts') end end - context "laborCosts" do - it "is represented" do + context 'laborCosts' do + it 'is represented' do expected = "10.00 EUR" - expect(subject).to be_json_eql(expected.to_json).at_path("laborCosts") + expect(subject).to be_json_eql(expected.to_json).at_path('laborCosts') end end - context "overallCosts" do - it "is represented" do + context 'overallCosts' do + it 'is represented' do expected = "15.00 EUR" - expect(subject).to be_json_eql(expected.to_json).at_path("overallCosts") + expect(subject).to be_json_eql(expected.to_json).at_path('overallCosts') end end - context "custom field x" do - it "is represented" do - expect(subject).to be_json_eql(sums.custom_field_1.to_json).at_path("customField1") + context 'custom field x' do + it 'is represented' do + expect(subject).to be_json_eql(sums.custom_field_1.to_json).at_path('customField1') end end end diff --git a/spec/lib/core_extensions/squish_sql_spec.rb b/spec/lib/core_extensions/squish_sql_spec.rb index 0a7d9e16cc22..cd61de0b655e 100644 --- a/spec/lib/core_extensions/squish_sql_spec.rb +++ b/spec/lib/core_extensions/squish_sql_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CoreExtensions::SquishSql do using described_class - it "removes single line SQL comments" do + it 'removes single line SQL comments' do sql = <<~SQL.squish -- select existing users from given IDs -- diff --git a/spec/lib/core_extensions/to_localized_slug_spec.rb b/spec/lib/core_extensions/to_localized_slug_spec.rb index 956060b16716..1a4f90526331 100644 --- a/spec/lib/core_extensions/to_localized_slug_spec.rb +++ b/spec/lib/core_extensions/to_localized_slug_spec.rb @@ -1,46 +1,46 @@ -require "spec_helper" +require 'spec_helper' -RSpec.describe CoreExtensions::String, "#to_localized_slug" do +RSpec.describe CoreExtensions::String, '#to_localized_slug' do let(:input) { "dübelbädel! ..." } let(:slug) { input.to_localized_slug } - it "uses english by default" do - expect(slug).to eq "dubelbadel-dot-dot-dot" + it 'uses english by default' do + expect(slug).to eq 'dubelbadel-dot-dot-dot' end - context "with a limit and german locale" do + context 'with a limit and german locale' do let(:slug) { input.to_localized_slug(locale: :de, limit: 4) } - it "limits the localized string" do - expect(slug).to eq "dueb" + it 'limits the localized string' do + expect(slug).to eq 'dueb' end end - context "with a limit and english locale" do + context 'with a limit and english locale' do let(:slug) { input.to_localized_slug(locale: :en, limit: 4) } - it "limits the localized string" do - expect(slug).to eq "dube" + it 'limits the localized string' do + expect(slug).to eq 'dube' end end - context "with a different I18n.locale" do + context 'with a different I18n.locale' do before do I18n.locale = :de end - it "uses that locale but does not change the backend locale" do + it 'uses that locale but does not change the backend locale' do expect { slug }.not_to change { Stringex::Localization.locale } - expect(slug).to eq "duebelbaedel-punkt-punkt-punkt" + expect(slug).to eq 'duebelbaedel-punkt-punkt-punkt' end end - context "passing in the locale" do + context 'passing in the locale' do let(:slug) { input.to_localized_slug(locale: :de) } - it "uses that locale but does not change the backend locale" do + it 'uses that locale but does not change the backend locale' do expect { slug }.not_to change { Stringex::Localization.locale } - expect(slug).to eq "duebelbaedel-punkt-punkt-punkt" + expect(slug).to eq 'duebelbaedel-punkt-punkt-punkt' end end end diff --git a/spec/lib/custom_field_form_builder_spec.rb b/spec/lib/custom_field_form_builder_spec.rb index 200a666147a4..a8f7a299a4be 100644 --- a/spec/lib/custom_field_form_builder_spec.rb +++ b/spec/lib/custom_field_form_builder_spec.rb @@ -25,13 +25,13 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "ostruct" +require 'spec_helper' +require 'ostruct' RSpec.describe CustomFieldFormBuilder do include Capybara::RSpecMatchers - let(:helper) { ActionView::Base.new(ActionView::LookupContext.new(""), {}, @controller) } + let(:helper) { ActionView::Base.new(ActionView::LookupContext.new(''), {}, @controller) } let(:builder) { described_class.new(:user, resource, helper, builder_options) } let(:builder_options) do { @@ -40,8 +40,8 @@ } end - describe "#custom_field" do - let(:options) { { class: "custom-class" } } + describe '#custom_field' do + let(:options) { { class: 'custom-class' } } let(:custom_field) do build_stubbed(:custom_field) @@ -67,37 +67,37 @@ builder.cf_form_field options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" do + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' do let(:container_count) { 2 } end - context "for a bool custom field" do - it_behaves_like "wrapped in container", "check-box-container" do + context 'for a bool custom field' do + it_behaves_like 'wrapped in container', 'check-box-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input:nth-of-type(2)") + }).at_path('input:nth-of-type(2)') end end - context "for a date custom field" do + context 'for a date custom field' do before do - custom_field.field_format = "date" + custom_field.field_format = 'date' end - it_behaves_like "wrapped in container", "field-container" do + it_behaves_like 'wrapped in container', 'field-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql( <<~HTML HTML - ).at_path("op-basic-single-date-picker") + ).at_path('op-basic-single-date-picker') end end - context "for a text custom field" do + context 'for a text custom field' do before do - custom_field.field_format = "text" + custom_field.field_format = 'text' end - it_behaves_like "wrapped in container", "text-area-container" do + it_behaves_like 'wrapped in container', 'text-area-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("textarea") + }).at_path('textarea') end end - context "for a string custom field" do + context 'for a string custom field' do before do - custom_field.field_format = "string" + custom_field.field_format = 'string' end - it_behaves_like "wrapped in container", "text-field-container" do + it_behaves_like 'wrapped in container', 'text-field-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - context "for an int custom field" do + context 'for an int custom field' do before do - custom_field.field_format = "int" + custom_field.field_format = 'int' end - it_behaves_like "wrapped in container", "text-field-container" do + it_behaves_like 'wrapped in container', 'text-field-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - context "for a float custom field" do + context 'for a float custom field' do before do - custom_field.field_format = "float" + custom_field.field_format = 'float' end - it_behaves_like "wrapped in container", "text-field-container" do + it_behaves_like 'wrapped in container', 'text-field-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - context "for a list custom field" do + context 'for a list custom field' do let(:custom_field) do create(:list_wp_custom_field, custom_options: [custom_option]) end let(:custom_option) do - create(:custom_option, value: "my_option") + create(:custom_option, value: 'my_option') end - it_behaves_like "wrapped in container", "select-container" do + it_behaves_like 'wrapped in container', 'select-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end - context "which is required and has no default value" do + context 'which is required and has no default value' do before do custom_field.update(is_required: true) end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end end - context "which is required and a default value" do + context 'which is required and a default value' do before do custom_field.update(is_required: true) custom_option.update(default_value: true) end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end end end - context "for a user custom field" do + context 'for a user custom field' do let(:project) { build_stubbed(:project) } let(:user1) { build_stubbed(:user) } let(:user2) { build_stubbed(:user) } @@ -257,7 +257,7 @@ let(:resource) { project } before do - custom_field.field_format = "user" + custom_field.field_format = 'user' allow(project) .to receive(custom_field.attribute_getter) @@ -268,11 +268,11 @@ .and_return([user1, user2]) end - it_behaves_like "wrapped in container", "select-container" do + it_behaves_like 'wrapped in container', 'select-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end - context "which is required and has no default value" do + context 'which is required and has no default value' do before do custom_field.is_required = true end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end end end - context "for a version custom field" do + context 'for a version custom field' do let(:project) { build_stubbed(:project) } let(:version1) { build_stubbed(:version) } let(:version2) { build_stubbed(:version) } @@ -313,7 +313,7 @@ let(:resource) { project } before do - custom_field.field_format = "version" + custom_field.field_format = 'version' allow(project) .to receive(custom_field.attribute_getter) .and_return typed_value @@ -323,11 +323,11 @@ .and_return([version1, version2]) end - it_behaves_like "wrapped in container", "select-container" do + it_behaves_like 'wrapped in container', 'select-container' do let(:container_count) { 2 } end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end - context "which is required and has no default value" do + context 'which is required and has no default value' do before do custom_field.is_required = true end - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end end end diff --git a/spec/lib/database_spec.rb b/spec/lib/database_spec.rb index c2d46ed9d080..6fdb8b535be4 100644 --- a/spec/lib/database_spec.rb +++ b/spec/lib/database_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Database do before do @@ -36,24 +36,24 @@ described_class.instance_variable_set(:@version, nil) end - it "returns the correct identifier" do - allow(OpenProject::Database).to receive(:adapter_name).and_return "PostgresQL" + it 'returns the correct identifier' do + allow(OpenProject::Database).to receive(:adapter_name).and_return 'PostgresQL' expect(OpenProject::Database.name).to equal(:postgresql) end - it "is able to use the helper methods" do - allow(OpenProject::Database).to receive(:adapter_name).and_return "PostgresQL" + it 'is able to use the helper methods' do + allow(OpenProject::Database).to receive(:adapter_name).and_return 'PostgresQL' expect(OpenProject::Database.postgresql?).to equal(true) end - it "returns a version string for PostgreSQL" do - allow(OpenProject::Database).to receive(:adapter_name).and_return "PostgreSQL" - raw_version = "PostgreSQL 8.3.11 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2" + it 'returns a version string for PostgreSQL' do + allow(OpenProject::Database).to receive(:adapter_name).and_return 'PostgreSQL' + raw_version = 'PostgreSQL 8.3.11 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2' allow(ActiveRecord::Base.connection).to receive(:select_value).and_return raw_version - expect(OpenProject::Database.version).to eq("8.3.11") + expect(OpenProject::Database.version).to eq('8.3.11') expect(OpenProject::Database.version(true)).to eq(raw_version) end end diff --git a/spec/lib/deprecated_alias_spec.rb b/spec/lib/deprecated_alias_spec.rb index c1f07c2b0359..0098b49775bd 100644 --- a/spec/lib/deprecated_alias_spec.rb +++ b/spec/lib/deprecated_alias_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DeprecatedAlias do let(:clazz) do @@ -34,7 +34,7 @@ extend DeprecatedAlias def secret_key - "happiness" + 'happiness' end deprecated_alias :special_key, :secret_key end @@ -55,7 +55,7 @@ def secret_key .with(deprecation_warning, an_instance_of(Array)) end - it "aliases the method" do - expect(object.special_key).to eq("happiness") + it 'aliases the method' do + expect(object.special_key).to eq('happiness') end end diff --git a/spec/lib/i18n/pluralization_spec.rb b/spec/lib/i18n/pluralization_spec.rb index e723654d5c1e..089e93056246 100644 --- a/spec/lib/i18n/pluralization_spec.rb +++ b/spec/lib/i18n/pluralization_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe I18n, "pluralization", type: :helper do - describe "with slowenian language and the :two plural key missing" do +RSpec.describe I18n, 'pluralization', type: :helper do + describe 'with slowenian language and the :two plural key missing' do before do I18n.locale = :sl allow(I18n.backend) @@ -42,16 +42,16 @@ .and_return({ one: "1 projekt", other: "%s projektov", zero: "Brez projektov" }) end - it "allows to pluralize without exceptions (Regression #37607)", :aggregate_failures do - expect(I18n.t(:label_x_projects, count: 0)).to eq "Brez projektov" - expect(I18n.t(:label_x_projects, count: 1)).to eq "1 projekt" - expect(I18n.t(:label_x_projects, count: 2)).to eq "2 projektov" - expect(I18n.t(:label_x_projects, count: 10)).to eq "10 projektov" - expect(I18n.t(:label_x_projects, count: 20)).to eq "20 projektov" + it 'allows to pluralize without exceptions (Regression #37607)', :aggregate_failures do + expect(I18n.t(:label_x_projects, count: 0)).to eq 'Brez projektov' + expect(I18n.t(:label_x_projects, count: 1)).to eq '1 projekt' + expect(I18n.t(:label_x_projects, count: 2)).to eq '2 projektov' + expect(I18n.t(:label_x_projects, count: 10)).to eq '10 projektov' + expect(I18n.t(:label_x_projects, count: 20)).to eq '20 projektov' end end - describe "with slowenian language and the :other plural key missing" do + describe 'with slowenian language and the :other plural key missing' do before do I18n.locale = :sl allow(I18n.backend) @@ -64,12 +64,12 @@ .and_return({ one: "1 projekt", zero: "Brez projektov" }) end - it "falls back to english translation (Regression #37607)", :aggregate_failures do - expect(I18n.t(:label_x_projects, count: 0)).to eq "Brez projektov" - expect(I18n.t(:label_x_projects, count: 1)).to eq "1 projekt" - expect(I18n.t(:label_x_projects, count: 2)).to eq "2 projects" - expect(I18n.t(:label_x_projects, count: 10)).to eq "10 projects" - expect(I18n.t(:label_x_projects, count: 20)).to eq "20 projects" + it 'falls back to english translation (Regression #37607)', :aggregate_failures do + expect(I18n.t(:label_x_projects, count: 0)).to eq 'Brez projektov' + expect(I18n.t(:label_x_projects, count: 1)).to eq '1 projekt' + expect(I18n.t(:label_x_projects, count: 2)).to eq '2 projects' + expect(I18n.t(:label_x_projects, count: 10)).to eq '10 projects' + expect(I18n.t(:label_x_projects, count: 20)).to eq '20 projects' end end end diff --git a/spec/lib/journal_formatter/active_status_spec.rb b/spec/lib/journal_formatter/active_status_spec.rb index 9afa81479351..3fee81b05161 100644 --- a/spec/lib/journal_formatter/active_status_spec.rb +++ b/spec/lib/journal_formatter/active_status_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::ActiveStatus do let(:instance) { described_class.new(build(:project_journal)) } diff --git a/spec/lib/journal_formatter/attachment_spec.rb b/spec/lib/journal_formatter/attachment_spec.rb index 9affb4a9a669..fc5c7d00b86d 100644 --- a/spec/lib/journal_formatter/attachment_spec.rb +++ b/spec/lib/journal_formatter/attachment_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::Attachment do include ApplicationHelper @@ -47,37 +47,37 @@ def self.default_url_options subject(:instance) { described_class.new(journal) } - describe "#render" do - describe "WITH the first value being nil, and the second an id as string" do - it "adds an attachment added text" do + describe '#render' do + describe 'WITH the first value being nil, and the second an id as string' do + it 'adds an attachment added text' do link = "#{Setting.protocol}://#{Setting.host_name}/api/v3/attachments/#{attachment.id}/content" expect(instance.render(key, [nil, attachment.filename.to_s])) .to eq(I18n.t(:text_journal_attachment_added, - label: "#{I18n.t(:"activerecord.models.attachment")}", + label: "#{I18n.t(:'activerecord.models.attachment')}", value: "#{attachment.filename}")) end - context "WITH a relative_url_root" do + context 'WITH a relative_url_root' do before do allow(OpenProject::Configuration) .to receive(:rails_relative_url_root) - .and_return("/blubs") + .and_return('/blubs') end - it "adds an attachment added text" do + it 'adds an attachment added text' do link = "#{Setting.protocol}://#{Setting.host_name}/blubs/api/v3/attachments/#{attachment.id}/content" expect(instance.render(key, [nil, attachment.filename.to_s])) .to eq(I18n.t(:text_journal_attachment_added, - label: "#{I18n.t(:"activerecord.models.attachment")}", + label: "#{I18n.t(:'activerecord.models.attachment')}", value: "#{attachment.filename}")) end end end - describe "WITH the first value being an id as string, and the second nil" do + describe 'WITH the first value being an id as string, and the second nil' do let(:expected) do I18n.t(:text_journal_attachment_deleted, - label: "#{I18n.t(:"activerecord.models.attachment")}", + label: "#{I18n.t(:'activerecord.models.attachment')}", old: "#{attachment.filename}") end @@ -88,7 +88,7 @@ def self.default_url_options WITH specifying not to output html" do let(:expected) do I18n.t(:text_journal_attachment_added, - label: I18n.t(:"activerecord.models.attachment"), + label: I18n.t(:'activerecord.models.attachment'), value: attachment.filename) end @@ -99,7 +99,7 @@ def self.default_url_options WITH specifying not to output html" do let(:expected) do I18n.t(:text_journal_attachment_deleted, - label: I18n.t(:"activerecord.models.attachment"), + label: I18n.t(:'activerecord.models.attachment'), old: attachment.filename) end diff --git a/spec/lib/journal_formatter/attribute_spec.rb b/spec/lib/journal_formatter/attribute_spec.rb index fb79a7e7cd56..3557819e87d5 100644 --- a/spec/lib/journal_formatter/attribute_spec.rb +++ b/spec/lib/journal_formatter/attribute_spec.rb @@ -28,26 +28,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe JournalFormatter::Attribute do - describe ".render" do + describe '.render' do let(:journal) { build_stubbed(:work_package_journal) } let(:instance) { described_class.new(journal) } - context "with two string values where one is longer than 100 characters" do - let(:old_value) { "For strings longer than 100 characters, a line break is added between values for a better readability" } - let(:new_value) { "Hello, World!" } + context 'with two string values where one is longer than 100 characters' do + let(:old_value) { 'For strings longer than 100 characters, a line break is added between values for a better readability' } + let(:new_value) { 'Hello, World!' } - it "adds a newline between values" do - expect(instance.render("name", [old_value, new_value])) + it 'adds a newline between values' do + expect(instance.render('name', [old_value, new_value])) .to eq(I18n.t(:text_journal_changed_plain, label: "Name", linebreak: "
    ", old: "#{old_value}", new: "#{new_value}")) - expect(instance.render("name", [old_value, new_value], html: false)) + expect(instance.render('name', [old_value, new_value], html: false)) .to eq(I18n.t(:text_journal_changed_plain, label: "Name", linebreak: "\n", diff --git a/spec/lib/journal_formatter/cause_spec.rb b/spec/lib/journal_formatter/cause_spec.rb index 213a7e80ad99..8f134e473d44 100644 --- a/spec/lib/journal_formatter/cause_spec.rb +++ b/spec/lib/journal_formatter/cause_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::Cause do include ApplicationHelper @@ -45,7 +45,7 @@ subject { instance.render("cause", [nil, cause], html:) } - context "when the change was caused by a change to the parent" do + context 'when the change was caused by a change to the parent' do let(:cause) do { "type" => "work_package_parent_changed_times", @@ -53,10 +53,10 @@ } end - context "when rendering HTML variant" do + context 'when rendering HTML variant' do let(:html) { true } - context "when the user is able to access the related work package" do + context 'when the user is able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.where(id: work_package.id)) end @@ -67,7 +67,7 @@ end end - context "when the user is not able to access the related work package" do + context 'when the user is not able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.none) end @@ -79,10 +79,10 @@ end end - context "when rendering raw variant" do + context 'when rendering raw variant' do let(:html) { false } - context "when the user is able to access the related work package" do + context 'when the user is able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.where(id: work_package.id)) end @@ -95,7 +95,7 @@ end end - context "when the user is not able to access the related work package" do + context 'when the user is not able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.none) end @@ -108,7 +108,7 @@ end end - context "when the change was caused by a change to a predecessor" do + context 'when the change was caused by a change to a predecessor' do let(:cause) do { "type" => "work_package_predecessor_changed_times", @@ -116,10 +116,10 @@ } end - context "when rendering HTML variant" do + context 'when rendering HTML variant' do let(:html) { true } - context "when the user is able to access the related work package" do + context 'when the user is able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.where(id: work_package.id)) end @@ -130,7 +130,7 @@ end end - context "when the user is not able to access the related work package" do + context 'when the user is not able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.none) end @@ -142,10 +142,10 @@ end end - context "when rendering raw variant" do + context 'when rendering raw variant' do let(:html) { false } - context "when the user is able to access the related work package" do + context 'when the user is able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.where(id: work_package.id)) end @@ -158,7 +158,7 @@ end end - context "when the user is not able to access the related work package" do + context 'when the user is not able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.none) end @@ -171,7 +171,7 @@ end end - context "when the change was caused by a change to a child" do + context 'when the change was caused by a change to a child' do let(:cause) do { "type" => "work_package_children_changed_times", @@ -179,10 +179,10 @@ } end - context "when rendering HTML variant" do + context 'when rendering HTML variant' do let(:html) { true } - context "when the user is able to access the related work package" do + context 'when the user is able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.where(id: work_package.id)) end @@ -193,7 +193,7 @@ end end - context "when the user is not able to access the related work package" do + context 'when the user is not able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.none) end @@ -205,10 +205,10 @@ end end - context "when rendering raw variant" do + context 'when rendering raw variant' do let(:html) { false } - context "when the user is able to access the related work package" do + context 'when the user is able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.where(id: work_package.id)) end @@ -221,7 +221,7 @@ end end - context "when the user is not able to access the related work package" do + context 'when the user is not able to access the related work package' do before do allow(WorkPackage).to receive(:visible).with(User.current).and_return(WorkPackage.none) end @@ -234,10 +234,10 @@ end end - context "when the change was caused by working day changes" do + context 'when the change was caused by working day changes' do let(:cause) do { - "type" => "working_days_changed", + "type" => 'working_days_changed', "changed_days" => { "working_days" => { "2" => false, @@ -252,7 +252,7 @@ } end - context "when rendering HTML variant" do + context 'when rendering HTML variant' do let(:html) { true } it do @@ -267,7 +267,7 @@ end end - context "when rendering raw variant" do + context 'when rendering raw variant' do let(:html) { false } it do @@ -283,15 +283,15 @@ end end - context "when the change was caused by a system update" do + context 'when the change was caused by a system update' do let(:cause) do { - "type" => "system_update", - "feature" => "file_links_journal" + "type" => 'system_update', + "feature" => 'file_links_journal' } end - context "when rendering HTML variant" do + context 'when rendering HTML variant' do let(:html) { true } it do @@ -300,7 +300,7 @@ end end - context "when rendering raw variant" do + context 'when rendering raw variant' do let(:html) { false } it do diff --git a/spec/lib/journal_formatter/custom_field_spec.rb b/spec/lib/journal_formatter/custom_field_spec.rb index 32f6c7b422c3..d812570eef4c 100644 --- a/spec/lib/journal_formatter/custom_field_spec.rb +++ b/spec/lib/journal_formatter/custom_field_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::CustomField do include CustomFieldsHelper @@ -51,9 +51,9 @@ "custom_fields_#{custom_field.id}" end - describe "a multi-select user field" do - let(:user1) { build_stubbed(:user, firstname: "Foo", lastname: "Bar") } - let(:user2) { build_stubbed(:user, firstname: "Bla", lastname: "Blub") } + describe 'a multi-select user field' do + let(:user1) { build_stubbed(:user, firstname: 'Foo', lastname: 'Bar') } + let(:user2) { build_stubbed(:user, firstname: 'Bla', lastname: 'Blub') } let(:custom_field) do build_stubbed(:user_wp_custom_field).tap do |cf| @@ -79,7 +79,7 @@ .and_return(visible_users) end - context "with two visible users" do + context 'with two visible users' do let(:visible_users) { [user1, user2] } let(:formatted_value) do @@ -91,11 +91,11 @@ value: "#{formatted_value}") end - it "outputs both formatted names" do + it 'outputs both formatted names' do expect(rendered).to eq expected end - context "with only one visible user" do + context 'with only one visible user' do let(:visible_users) { [user1] } let(:formatted_value) do @@ -107,15 +107,15 @@ value: "#{formatted_value}") end - it "outputs the one visible formatted name" do + it 'outputs the one visible formatted name' do expect(rendered).to eq expected end end end end - describe "WITH the first value being nil, and the second a valid value as string" do - let(:values) { [nil, "1"] } + describe 'WITH the first value being nil, and the second a valid value as string' do + let(:values) { [nil, '1'] } let(:formatted_value) { format_value(values.last, custom_field) } let(:expected) do @@ -127,7 +127,7 @@ it { expect(instance.render(key, values)).to eq(expected) } end - describe "WITH the first value being a valid value as a string, and the second being a valid value as a string" do + describe 'WITH the first value being a valid value as a string, and the second being a valid value as a string' do let(:values) { %w[0 1] } let(:old_formatted_value) { format_value(values.first, custom_field) } let(:new_formatted_value) { format_value(values.last, custom_field) } @@ -135,7 +135,7 @@ let(:expected) do I18n.t(:text_journal_changed_plain, label: "#{custom_field.name}", - linebreak: "", + linebreak: '', old: "#{old_formatted_value}", new: "#{new_formatted_value}") end @@ -143,8 +143,8 @@ it { expect(instance.render(key, values)).to eq(expected) } end - describe "WITH the first value being a valid value as a string, and the second being nil" do - let(:values) { ["0", nil] } + describe 'WITH the first value being a valid value as a string, and the second being nil' do + let(:values) { ['0', nil] } let(:formatted_value) { format_value(values.first, custom_field) } let(:expected) do @@ -158,7 +158,7 @@ describe "WITH the first value being nil, and the second a valid value as string " \ "and WITH no html requested" do - let(:values) { [nil, "1"] } + let(:values) { [nil, '1'] } let(:expected) do I18n.t(:text_journal_set_to, @@ -177,7 +177,7 @@ I18n.t(:text_journal_changed_plain, label: custom_field.name, old: format_value(values.first, custom_field), - linebreak: "", + linebreak: '', new: format_value(values.last, custom_field)) end @@ -186,7 +186,7 @@ describe "WITH the first value being a valid value as a string, and the second being nil " \ "and WITH no html requested" do - let(:values) { ["0", nil] } + let(:values) { ['0', nil] } let(:expected) do I18n.t(:text_journal_deleted, @@ -199,8 +199,8 @@ describe "WITH the first value being nil, and the second a valid value as string " \ "and WITH the custom field being deleted" do - let(:values) { [nil, "1"] } - let(:key) { "custom_values0" } + let(:values) { [nil, '1'] } + let(:key) { 'custom_values0' } let(:expected) do I18n.t(:text_journal_set_to, @@ -214,12 +214,12 @@ describe "WITH the first value being a valid value as a string, and the second being a valid value as a string " \ "and WITH the custom field being deleted" do let(:values) { %w[0 1] } - let(:key) { "custom_values0" } + let(:key) { 'custom_values0' } let(:expected) do I18n.t(:text_journal_changed_plain, label: "#{I18n.t(:label_deleted_custom_field)}", - linebreak: "", + linebreak: '', old: "#{values.first}", new: "#{values.last}") end @@ -229,8 +229,8 @@ describe "WITH the first value being a valid value as a string, and the second being nil " \ "and WITH the custom field being deleted" do - let(:values) { ["0", nil] } - let(:key) { "custom_values0" } + let(:values) { ['0', nil] } + let(:key) { 'custom_values0' } let(:expected) do I18n.t(:text_journal_deleted, @@ -241,7 +241,7 @@ it { expect(instance.render(key, values)).to eq(expected) } end - context "for a multi list cf" do + context 'for a multi list cf' do let(:custom_field) do build_stubbed(:list_wp_custom_field, multi_value: true).tap do |cf| allow(CustomField) @@ -249,9 +249,9 @@ .with(id: cf.id) .and_return(cf) - cf_options = double("custom_options") - old_options = double("selected options") - new_options = double("selected options") + cf_options = double('custom_options') + old_options = double('selected options') + new_options = double('selected options') allow(cf) .to receive(:custom_options) @@ -288,8 +288,8 @@ .and_return(new_custom_option_names) end end - let(:old_custom_option_names) { [[1, "cf 1"], [2, "cf 2"]] } - let(:new_custom_option_names) { [[3, "cf 3"], [4, "cf 4"]] } + let(:old_custom_option_names) { [[1, 'cf 1'], [2, 'cf 2']] } + let(:new_custom_option_names) { [[3, 'cf 3'], [4, 'cf 4']] } describe "WITH the first value being a comma separated list of ids, " \ "and the second being a comma separated list of ids" do @@ -298,7 +298,7 @@ let(:expected) do I18n.t(:text_journal_changed_plain, label: "#{custom_field.name}", - linebreak: "", + linebreak: '', old: "cf 1, cf 2", new: "cf 3, cf 4") end @@ -309,12 +309,12 @@ describe "WITH the first value being a comma separated list of ids, " \ "and the second being a comma separated list of ids that no longer exist" do let(:values) { %w[1,2 3,4] } - let(:new_custom_option_names) { [[4, "cf 4"]] } + let(:new_custom_option_names) { [[4, 'cf 4']] } let(:expected) do I18n.t(:text_journal_changed_plain, label: "#{custom_field.name}", - linebreak: "", + linebreak: '', old: "cf 1, cf 2", new: "(deleted option), cf 4") end diff --git a/spec/lib/journal_formatter/day_count_spec.rb b/spec/lib/journal_formatter/day_count_spec.rb index 0d2dc22e1984..52476252b01d 100644 --- a/spec/lib/journal_formatter/day_count_spec.rb +++ b/spec/lib/journal_formatter/day_count_spec.rb @@ -37,34 +37,34 @@ let(:instance) { klass.new(journal) } let(:key) { :duration } - describe "#render" do - describe "when setting the old value to 1 day, and the new value to 3 days" do + describe '#render' do + describe 'when setting the old value to 1 day, and the new value to 3 days' do let(:expected) do I18n.t(:text_journal_changed_plain, label: "Duration", - old: "1 day", - new: "3 days", - linebreak: "") + old: '1 day', + new: '3 days', + linebreak: '') end it { expect(instance.render(key, [1, 3])).to eq(expected) } end - describe "when setting the initial value to 3 days" do + describe 'when setting the initial value to 3 days' do let(:expected) do I18n.t(:text_journal_set_to, label: "Duration", - value: "3 days") + value: '3 days') end it { expect(instance.render(key, [nil, 3])).to eq(expected) } end - describe "when deleting the initial value of 3 days" do + describe 'when deleting the initial value of 3 days' do let(:expected) do I18n.t(:text_journal_deleted, label: "Duration", - old: "3 days") + old: '3 days') end it { expect(instance.render(key, [3, nil])).to eq(expected) } diff --git a/spec/lib/journal_formatter/diff_spec.rb b/spec/lib/journal_formatter/diff_spec.rb index 46e7051342c2..2e6bb1d07241 100644 --- a/spec/lib/journal_formatter/diff_spec.rb +++ b/spec/lib/journal_formatter/diff_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::Diff do include ActionView::Helpers::TagHelper @@ -42,7 +42,7 @@ def url_helper let(:id) { 1 } let(:work_package) do build_stubbed(:work_package, - subject: "Test subject", + subject: 'Test subject', status_id: 1, type_id: 1, project_id: 1) @@ -59,7 +59,7 @@ def url_helper project_id: work_package.project_id)) end let(:instance) { klass.new(journal) } - let(:key) { "description" } + let(:key) { 'description' } let(:path) do url_helper.diff_journal_path(id: journal.id, @@ -71,35 +71,35 @@ def url_helper protocol: Setting.protocol, host: Setting.host_name) end - let(:link) { link_to(I18n.t(:label_details), path, class: "description-details") } - let(:full_url_link) { link_to(I18n.t(:label_details), url, class: "description-details") } + let(:link) { link_to(I18n.t(:label_details), path, class: 'description-details') } + let(:full_url_link) { link_to(I18n.t(:label_details), url, class: 'description-details') } - describe "#render" do - describe "WITH the first value being nil, and the second a string" do + describe '#render' do + describe 'WITH the first value being nil, and the second a string' do let(:expected) do I18n.t(:text_journal_set_with_diff, label: "#{key.camelize}", link:) end - it { expect(instance.render(key, [nil, "new value"])).to eq(expected) } + it { expect(instance.render(key, [nil, 'new value'])).to eq(expected) } end - describe "WITH the first value being a string, and the second a string" do + describe 'WITH the first value being a string, and the second a string' do let(:expected) do I18n.t(:text_journal_changed_with_diff, label: "#{key.camelize}", link:) end - it { expect(instance.render(key, ["old value", "new value"])).to eq(expected) } + it { expect(instance.render(key, ['old value', 'new value'])).to eq(expected) } end describe "WITH the first value being a string, and the second a string WITH de as locale" do let(:expected) do I18n.t(:text_journal_changed_with_diff, - label: "Beschreibung", + label: 'Beschreibung', link:) end @@ -111,17 +111,17 @@ def url_helper I18n.locale = :en end - it { expect(instance.render(key, ["old value", "new value"])).to eq(expected) } + it { expect(instance.render(key, ['old value', 'new value'])).to eq(expected) } end - describe "WITH the first value being a string, and the second nil (with link)" do + describe 'WITH the first value being a string, and the second nil (with link)' do let(:expected) do I18n.t(:text_journal_deleted_with_diff, label: "#{key.camelize}", link:) end - it { expect(instance.render(key, ["old_value", nil])).to eq(expected) } + it { expect(instance.render(key, ['old_value', nil])).to eq(expected) } end describe "WITH the first value being nil, and the second a string @@ -132,7 +132,7 @@ def url_helper link: path) end - it { expect(instance.render(key, [nil, "new value"], html: false)).to eq(expected) } + it { expect(instance.render(key, [nil, 'new value'], html: false)).to eq(expected) } end describe "WITH the first value being a string, and the second a string @@ -143,7 +143,7 @@ def url_helper link: path) end - it { expect(instance.render(key, ["old value", "new value"], html: false)).to eq(expected) } + it { expect(instance.render(key, ['old value', 'new value'], html: false)).to eq(expected) } end describe "WITH the first value being a string, and the second a string @@ -154,17 +154,17 @@ def url_helper link: full_url_link) end - it { expect(instance.render(key, ["old value", "new value"], only_path: false)).to eq(expected) } + it { expect(instance.render(key, ['old value', 'new value'], only_path: false)).to eq(expected) } end - describe "WITH the first value being a string, and the second nil (with url)" do + describe 'WITH the first value being a string, and the second nil (with url)' do let(:expected) do I18n.t(:text_journal_deleted_with_diff, label: key.camelize, link: path) end - it { expect(instance.render(key, ["old_value", nil], html: false)).to eq(expected) } + it { expect(instance.render(key, ['old_value', nil], html: false)).to eq(expected) } end end end diff --git a/spec/lib/journal_formatter/file_link_spec.rb b/spec/lib/journal_formatter/file_link_spec.rb index ce381e2fe18d..8adaca32b850 100644 --- a/spec/lib/journal_formatter/file_link_spec.rb +++ b/spec/lib/journal_formatter/file_link_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::FileLink do let(:work_package) { build(:work_package) } @@ -40,11 +40,11 @@ subject(:instance) { described_class.new(journal) } - describe "#render" do - context "having the origin_name as nil" do + describe '#render' do + context 'having the origin_name as nil' do let(:changes) { { "link_name" => file_link.origin_name, "storage_name" => nil } } - it "if the storage name is nil it tries to find it out looking at the file link" do + it 'if the storage name is nil it tries to find it out looking at the file link' do link = "#{Setting.protocol}://#{Setting.host_name}/api/v3/file_links/#{file_link.id}/open" expect(instance.render(key, [nil, changes])) @@ -55,20 +55,20 @@ end it 'if the storage name is nil and the file link does not exist, "Unknown storage" is used' do - expect(instance.render("file_links_12", [changes, nil])) + expect(instance.render('file_links_12', [changes, nil])) .to eq(I18n.t(:text_journal_file_link_deleted, label: "#{I18n.t('activerecord.models.file_link')}", old: "#{file_link.origin_name}", storage: I18n.t( - "unknown_storage", - scope: "my_account.access_tokens.storages" + 'unknown_storage', + scope: 'my_account.access_tokens.storages' ))) end end - context "having the first value being nil, and the second an hash of properties" do - context "as HTML" do - it "adds a file link added text" do + context 'having the first value being nil, and the second an hash of properties' do + context 'as HTML' do + it 'adds a file link added text' do link = "#{Setting.protocol}://#{Setting.host_name}/api/v3/file_links/#{file_link.id}/open" expect(instance.render(key, [nil, changes])) .to eq(I18n.t(:text_journal_file_link_added, @@ -77,10 +77,10 @@ storage: file_link.storage.name)) end - context "with a configured relative url root" do - before { allow(OpenProject::Configuration).to receive(:rails_relative_url_root).and_return("/blubs") } + context 'with a configured relative url root' do + before { allow(OpenProject::Configuration).to receive(:rails_relative_url_root).and_return('/blubs') } - it "adds an file link added text" do + it 'adds an file link added text' do link = "#{Setting.protocol}://#{Setting.host_name}/blubs/api/v3/file_links/#{file_link.id}/open" expect(instance.render(key, [nil, changes])) .to eq(I18n.t(:text_journal_file_link_added, @@ -91,10 +91,10 @@ end end - context "as plain text" do - it "adds a file link added text" do + context 'as plain text' do + it 'adds a file link added text' do message = I18n.t(:text_journal_file_link_added, - label: I18n.t("activerecord.models.file_link"), + label: I18n.t('activerecord.models.file_link'), value: file_link.origin_name, storage: file_link.storage.name) @@ -103,9 +103,9 @@ end end - context "having the first value being an props hash, and the second nil" do - context "as HTML" do - it "adds a file link remove text" do + context 'having the first value being an props hash, and the second nil' do + context 'as HTML' do + it 'adds a file link remove text' do message = I18n.t(:text_journal_file_link_deleted, label: "#{I18n.t('activerecord.models.file_link')}", old: "#{file_link.origin_name}", @@ -115,10 +115,10 @@ end end - context "as plain text" do - it "adds a file link removed" do + context 'as plain text' do + it 'adds a file link removed' do message = I18n.t(:text_journal_file_link_deleted, - label: I18n.t("activerecord.models.file_link"), + label: I18n.t('activerecord.models.file_link'), old: file_link.origin_name, storage: file_link.storage.name) diff --git a/spec/lib/journal_formatter/ignore_non_working_days_spec.rb b/spec/lib/journal_formatter/ignore_non_working_days_spec.rb index b4da6bf65e84..484b068fde72 100644 --- a/spec/lib/journal_formatter/ignore_non_working_days_spec.rb +++ b/spec/lib/journal_formatter/ignore_non_working_days_spec.rb @@ -37,8 +37,8 @@ let(:instance) { klass.new(journal) } let(:key) { :ignore_non_working_days } - describe "#render" do - context "when setting the old value to false, and the new value to true" do + describe '#render' do + context 'when setting the old value to false, and the new value to true' do let(:expected) do I18n.t(:text_journal_set_to, label: "Working days", @@ -48,7 +48,7 @@ it { expect(instance.render(key, [false, true])).to eq(expected) } end - context "when setting the old value to true, and the new value to false" do + context 'when setting the old value to true, and the new value to false' do let(:expected) do I18n.t(:text_journal_set_to, label: "Working days", diff --git a/spec/lib/journal_formatter/project_status_code_spec.rb b/spec/lib/journal_formatter/project_status_code_spec.rb index 08e785e98ce2..e9325f057f09 100644 --- a/spec/lib/journal_formatter/project_status_code_spec.rb +++ b/spec/lib/journal_formatter/project_status_code_spec.rb @@ -28,21 +28,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::ProjectStatusCode do def status_code_as_integer(status) Project.status_codes.fetch(status, nil) end - describe "#render" do + describe '#render' do let(:journal) { build_stubbed(:project_journal) } let(:instance) { described_class.new(journal) } - let(:status_code_key) { "status_code" } + let(:status_code_key) { 'status_code' } - context "when setting a status" do + context 'when setting a status' do let(:old_value) { nil } - let(:new_value) { status_code_as_integer("off_track") } + let(:new_value) { status_code_as_integer('off_track') } let(:expected) do I18n.t(:text_journal_set_to, label: "Project status", @@ -52,8 +52,8 @@ def status_code_as_integer(status) it { expect(instance.render(status_code_key, [old_value, new_value])).to eq(expected) } end - context "when deleting a status" do - let(:old_value) { status_code_as_integer("discontinued") } + context 'when deleting a status' do + let(:old_value) { status_code_as_integer('discontinued') } let(:new_value) { nil } let(:expected) do I18n.t(:text_journal_deleted, @@ -64,9 +64,9 @@ def status_code_as_integer(status) it { expect(instance.render(status_code_key, [old_value, new_value])).to eq(expected) } end - context "when modifying a status" do - let(:old_value) { status_code_as_integer("off_track") } - let(:new_value) { status_code_as_integer("on_track") } + context 'when modifying a status' do + let(:old_value) { status_code_as_integer('off_track') } + let(:new_value) { status_code_as_integer('on_track') } let(:expected) do I18n.t(:text_journal_changed_plain, label: "Project status", diff --git a/spec/lib/journal_formatter/schedule_manually_spec.rb b/spec/lib/journal_formatter/schedule_manually_spec.rb index 9440f8016785..3f3c69074158 100644 --- a/spec/lib/journal_formatter/schedule_manually_spec.rb +++ b/spec/lib/journal_formatter/schedule_manually_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::ScheduleManually do let(:klass) { described_class } @@ -35,24 +35,24 @@ OpenStruct.new(id:, journable: WorkPackage.new) end let(:instance) { klass.new(journal) } - let(:key) { "schedule_manually" } + let(:key) { 'schedule_manually' } - describe "#render" do - describe "with the first value being true, and the second false" do + describe '#render' do + describe 'with the first value being true, and the second false' do let(:expected) do I18n.t(:text_journal_label_value, label: "Manual scheduling", - value: "deactivated") + value: 'deactivated') end it { expect(instance.render(key, [true, false])).to eq(expected) } end - describe "with the first value being false, and the second true" do + describe 'with the first value being false, and the second true' do let(:expected) do I18n.t(:text_journal_label_value, label: "Manual scheduling", - value: "activated") + value: 'activated') end it { expect(instance.render(key, [false, true])).to eq(expected) } diff --git a/spec/lib/journal_formatter/template_spec.rb b/spec/lib/journal_formatter/template_spec.rb index 1f258d0945eb..fecb3075a003 100644 --- a/spec/lib/journal_formatter/template_spec.rb +++ b/spec/lib/journal_formatter/template_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::Template do let(:instance) { described_class.new(build(:project_journal)) } diff --git a/spec/lib/journal_formatter/wiki_diff_spec.rb b/spec/lib/journal_formatter/wiki_diff_spec.rb index 7bd8cee86739..a2ad4fa69e36 100644 --- a/spec/lib/journal_formatter/wiki_diff_spec.rb +++ b/spec/lib/journal_formatter/wiki_diff_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::JournalFormatter::WikiDiff do include ActionView::Helpers::TagHelper @@ -42,7 +42,7 @@ def url_helper let(:project) { build_stubbed(:project) } let(:wiki) { build_stubbed(:wiki, project:) } let(:wiki_page) do - build_stubbed(:wiki_page, wiki:, slug: "test-slug", text: "").tap do |page| + build_stubbed(:wiki_page, wiki:, slug: 'test-slug', text: '').tap do |page| allow(page).to receive(:project).and_return(project) end end @@ -52,7 +52,7 @@ def url_helper version: 1) end let(:wiki_instance) { klass.new(wiki_journal) } - let(:wiki_key) { "text" } + let(:wiki_key) { 'text' } let(:path) do # path url_helper.wiki_diff_compare_project_wiki_path(id: wiki_page.slug, project_id: project.identifier, @@ -67,18 +67,18 @@ def url_helper protocol: Setting.protocol, host: Setting.host_name) end - let(:link) { link_to(I18n.t(:label_details), path, class: "description-details") } - let(:full_url_link) { link_to(I18n.t(:label_details), url, class: "description-details") } + let(:link) { link_to(I18n.t(:label_details), path, class: 'description-details') } + let(:full_url_link) { link_to(I18n.t(:label_details), url, class: 'description-details') } - describe "#render" do - describe "a wiki diff for a wiki journal correctly" do + describe '#render' do + describe 'a wiki diff for a wiki journal correctly' do let(:expected) do I18n.t(:text_journal_changed_with_diff, label: "#{wiki_key.camelize}", link:) end - it { expect(wiki_instance.render(wiki_key, ["old value", "new value"])).to eq(expected) } + it { expect(wiki_instance.render(wiki_key, ['old value', 'new value'])).to eq(expected) } end end end diff --git a/spec/lib/open_project/access_control/permission_spec.rb b/spec/lib/open_project/access_control/permission_spec.rb index de9eb7ea7b59..195f5cd71ae7 100644 --- a/spec/lib/open_project/access_control/permission_spec.rb +++ b/spec/lib/open_project/access_control/permission_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::AccessControl::Permission do - describe "#dependencies" do - context "for a permission with a dependency" do + describe '#dependencies' do + context 'for a permission with a dependency' do subject { OpenProject::AccessControl.permission(:edit_work_packages) } - it "denotes the pre-requisites" do + it 'denotes the pre-requisites' do expect(subject.dependencies) .to contain_exactly(:view_work_packages) end end - context "for a permission without a dependency" do + context 'for a permission without a dependency' do subject { OpenProject::AccessControl.permission(:view_work_packages) } - it "is empty" do + it 'is empty' do expect(subject.dependencies) .to be_empty end end end - describe "#work_package?" do - context "when marked as permissible on work package roles" do + describe '#work_package?' do + context 'when marked as permissible on work package roles' do subject(:permission) do described_class.new(:perm, { cont: [:action] }, permissible_on: :work_package) end @@ -59,8 +59,8 @@ end end - describe "#project?" do - context "when marked as permissible on project roles" do + describe '#project?' do + context 'when marked as permissible on project roles' do subject(:permission) do described_class.new(:perm, { cont: [:action] }, permissible_on: :project) end @@ -69,8 +69,8 @@ end end - describe "#global?" do - context "when marked as permissible on global roles" do + describe '#global?' do + context 'when marked as permissible on global roles' do subject(:permission) do described_class.new(:perm, { cont: [:action] }, permissible_on: :global) end @@ -79,7 +79,7 @@ end end - describe "marking it as permissible on multiple role types" do + describe 'marking it as permissible on multiple role types' do subject(:permission) do described_class.new(:perm, { cont: [:action] }, permissible_on: %i[work_package project]) end @@ -88,7 +88,7 @@ it { expect(permission).to be_project } end - context "without :permissible_on as an argument" do + context 'without :permissible_on as an argument' do it do expect do described_class.new(:perm, { cont: [:action] }) @@ -96,8 +96,8 @@ end end - describe "#grant_to_admin?" do - context "when it is marked as grant-able to admin" do + describe '#grant_to_admin?' do + context 'when it is marked as grant-able to admin' do subject(:permission) do described_class.new(:perm, {}, permissible_on: :project, grant_to_admin: true) end @@ -105,7 +105,7 @@ it { expect(permission).to be_grant_to_admin } end - context "when it is marked as non-grant-able to admin" do + context 'when it is marked as non-grant-able to admin' do subject(:permission) do described_class.new(:perm, {}, permissible_on: :project, grant_to_admin: false) end @@ -113,12 +113,12 @@ it { expect(permission).not_to be_grant_to_admin } end - context "without specifying whether the permissions is grant-able to admin or not" do + context 'without specifying whether the permissions is grant-able to admin or not' do subject(:permission) do described_class.new(:perm, {}, permissible_on: :project) end - it "defaults to grant-able to admin" do + it 'defaults to grant-able to admin' do expect(permission).to be_grant_to_admin end end diff --git a/spec/lib/open_project/access_control_spec.rb b/spec/lib/open_project/access_control_spec.rb index f7857bd958da..5c88ade2d34c 100644 --- a/spec/lib/open_project/access_control_spec.rb +++ b/spec/lib/open_project/access_control_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::AccessControl do def setup_permissions @@ -87,8 +87,8 @@ def setup_permissions end end - describe ".disable_modules_permissions" do - include_context "with blank access control state" + describe '.disable_modules_permissions' do + include_context 'with blank access control state' before do setup_permissions @@ -105,126 +105,126 @@ def setup_permissions described_class end - it "removes from permissions" do + it 'removes from permissions' do expect(subject.permissions) .to all(not_belong_to_project_module(:project_module)) end - it "removes from global permissions" do + it 'removes from global permissions' do expect(subject.global_permissions) .to all(not_belong_to_project_module(:project_module)) end - it "removes from public permissions" do + it 'removes from public permissions' do expect(subject.public_permissions) .to all(not_belong_to_project_module(:project_module)) end - it "removes from members-only permissions" do + it 'removes from members-only permissions' do expect(subject.members_only_permissions) .to all(not_belong_to_project_module(:project_module)) end - it "removes from loggedin-only permissions" do + it 'removes from loggedin-only permissions' do expect(subject.loggedin_only_permissions) .to all(not_belong_to_project_module(:project_module)) end - it "disables repository module" do + it 'disables repository module' do expect(subject.available_project_modules) .not_to include(:project_module) end - it "lists the permissions in the disabled_permissions" do + it 'lists the permissions in the disabled_permissions' do expect(subject.disabled_permissions.map(&:name)) .to include :project_module_project_permission_with_contract_actions, :project_module_project_permission end - it "returns true on disabled_permission?" do + it 'returns true on disabled_permission?' do expect(subject.disabled_permission?(:project_module_project_permission)) .to be true end end - describe ".permissions" do + describe '.permissions' do subject(:permissions) { described_class.permissions } - it "returns an array permissions" do + it 'returns an array permissions' do expect(permissions) .to all(be_instance_of(OpenProject::AccessControl::Permission)) end - it "returns only enabled permissions" do + it 'returns only enabled permissions' do expect(permissions) .to all(be_enabled) end end - describe ".permission" do - context "for a project module permission" do + describe '.permission' do + context 'for a project module permission' do subject { described_class.permission(:view_work_packages) } - it "is a permission" do + it 'is a permission' do expect(subject) .to be_a(OpenProject::AccessControl::Permission) end - it "is the permission with the queried-for name" do + it 'is the permission with the queried-for name' do expect(subject.name) .to eq(:view_work_packages) end - it "belongs to a project module" do + it 'belongs to a project module' do expect(subject.project_module) .to eq(:work_package_tracking) end end - context "for a non module permission" do + context 'for a non module permission' do subject { described_class.permission(:edit_project) } - it "is a permission" do + it 'is a permission' do expect(subject) .to be_a(OpenProject::AccessControl::Permission) end - it "is the permission with the queried-for name" do + it 'is the permission with the queried-for name' do expect(subject.name) .to eq(:edit_project) end - it "does not belong to a project module" do + it 'does not belong to a project module' do expect(subject.project_module) .to be_nil end - it "includes actions" do + it 'includes actions' do expect(subject.controller_actions) - .to include("projects/settings/general/show") + .to include('projects/settings/general/show') end end - describe "#dependencies" do - context "for a permission with a pre-requisite" do + describe '#dependencies' do + context 'for a permission with a pre-requisite' do subject(:dependencies) do described_class.permission(:edit_work_packages) .dependencies end - it "denotes the pre-requisites" do + it 'denotes the pre-requisites' do expect(dependencies) .to contain_exactly(:view_work_packages) end end - context "for a permission without a pre-requisite" do + context 'for a permission without a pre-requisite' do subject(:dependencies) do described_class.permission(:view_work_packages) .dependencies end - it "denotes no pre-requisites" do + it 'denotes no pre-requisites' do expect(dependencies) .to be_empty end @@ -232,8 +232,8 @@ def setup_permissions end end - describe ".modules" do - include_context "with blank access control state" + describe '.modules' do + include_context 'with blank access control state' before do setup_permissions @@ -244,14 +244,14 @@ def setup_permissions .find { _1[:name] == :dependent_module }[:dependencies] end - it "can store specified dependencies" do + it 'can store specified dependencies' do expect(dependencies) .to contain_exactly(:project_module) end end - describe ".work_package_permissions" do - include_context "with blank access control state" + describe '.work_package_permissions' do + include_context 'with blank access control state' before do setup_permissions @@ -261,7 +261,7 @@ def setup_permissions described_class.work_package_permissions end - describe "size" do + describe 'size' do it { expect(work_package_permissions.size).to eq(2) } end @@ -272,8 +272,8 @@ def setup_permissions end end - describe ".project_permissions" do - include_context "with blank access control state" + describe '.project_permissions' do + include_context 'with blank access control state' before do setup_permissions @@ -283,7 +283,7 @@ def setup_permissions described_class.project_permissions end - describe "size" do + describe 'size' do it { expect(project_permissions.size).to eq(7) } end @@ -299,8 +299,8 @@ def setup_permissions end end - describe ".global_permissions" do - include_context "with blank access control state" + describe '.global_permissions' do + include_context 'with blank access control state' before do setup_permissions @@ -310,7 +310,7 @@ def setup_permissions described_class.global_permissions end - describe "size" do + describe 'size' do it { expect(global_permissions.size).to eq(3) } end @@ -322,8 +322,8 @@ def setup_permissions end end - describe ".available_project_modules" do - include_context "with blank access control state" + describe '.available_project_modules' do + include_context 'with blank access control state' before do setup_permissions @@ -336,7 +336,7 @@ def setup_permissions it { expect(available_project_modules).to include(:project_module, :mixed_module, :dependent_module) } it { expect(available_project_modules).not_to include(:global_module) } - context "when a module specifies :if" do + context 'when a module specifies :if' do before do described_class.map do |map| map.project_module :dynamic_module, if: if_proc do |mod| @@ -345,27 +345,27 @@ def setup_permissions end end - context "with if: true" do + context 'with if: true' do let(:if_proc) { ->(*) { true } } - it "is considered available" do + it 'is considered available' do expect(available_project_modules).to include(:dynamic_module) end end - context "with if: false" do + context 'with if: false' do let(:if_proc) { ->(*) { false } } - it "is not considered available anymore" do + it 'is not considered available anymore' do expect(available_project_modules).not_to include(:dynamic_module) end end - context "with if: dynamically changing" do + context 'with if: dynamically changing' do let(:if_proc) { ->(*) { if_state[:available] } } let(:if_state) { { available: true } } - it "reevaluates module availability each time", :aggregate_failures do + it 'reevaluates module availability each time', :aggregate_failures do if_state[:available] = true expect(described_class.available_project_modules).to include(:dynamic_module) @@ -376,8 +376,8 @@ def setup_permissions end end - describe ".contract_actions_map" do - include_context "with blank access control state" + describe '.contract_actions_map' do + include_context 'with blank access control state' before do setup_permissions @@ -387,7 +387,7 @@ def setup_permissions described_class.contract_actions_map end - it "contains all contract actions grouped by the permission name" do + it 'contains all contract actions grouped by the permission name' do expect(contract_actions_map) .to eql(mixed_module_global_permission_with_contract_actions: { actions: { baz: [:destroy] }, @@ -413,44 +413,44 @@ def setup_permissions end end - describe ".grant_to_admin?" do - include_context "with blank access control state" + describe '.grant_to_admin?' do + include_context 'with blank access control state' before do setup_permissions end - context "without specifying whether the permission is granted to admins" do - it "is granted" do + context 'without specifying whether the permission is granted to admins' do + it 'is granted' do expect(described_class) .to be_grant_to_admin(:no_module_project_permission_with_contract_actions) end end - context "for an explicitly granted permission" do - it "is granted" do + context 'for an explicitly granted permission' do + it 'is granted' do expect(described_class) .to be_grant_to_admin(:mixed_module_project_permission_granted_to_admin) end end - context "for an explicitly non-granted permission" do - it "is not granted" do + context 'for an explicitly non-granted permission' do + it 'is not granted' do expect(described_class) .not_to be_grant_to_admin(:dependent_module_project_permission_not_granted_to_admin) end end - context "for a non existing permission" do - it "is granted" do + context 'for a non existing permission' do + it 'is granted' do expect(described_class) .to be_grant_to_admin(:not_existing) end end end - describe ".disabled_permission?" do - include_context "with blank access control state" + describe '.disabled_permission?' do + include_context 'with blank access control state' before do described_class.map do |map| @@ -473,27 +473,27 @@ def setup_permissions end end - it "is false for enabled permissions" do + it 'is false for enabled permissions' do expect(subject) .not_to be_disabled_permission(:enabled_permission) end - it "is true for disabled permission" do + it 'is true for disabled permission' do expect(subject) .to be_disabled_permission(:disabled_permission1) end - it "is true for action hash where permissions granting are disabled" do + it 'is true for action hash where permissions granting are disabled' do expect(subject) - .to be_disabled_permission(controller: "some", action: "action") + .to be_disabled_permission(controller: 'some', action: 'action') end - it "is false for action hash where not all permissions granting are disabled (but some can)" do + it 'is false for action hash where not all permissions granting are disabled (but some can)' do expect(subject) - .not_to be_disabled_permission(controller: "another", action: "action") + .not_to be_disabled_permission(controller: 'another', action: 'action') end - it "is false for an unknown permission" do + it 'is false for an unknown permission' do expect(subject) .not_to be_disabled_permission(:unknown_permission) end diff --git a/spec/lib/open_project/authentication/strategies/warden/global_basic_auth_spec.rb b/spec/lib/open_project/authentication/strategies/warden/global_basic_auth_spec.rb index 38e34b095195..1b7c96067370 100644 --- a/spec/lib/open_project/authentication/strategies/warden/global_basic_auth_spec.rb +++ b/spec/lib/open_project/authentication/strategies/warden/global_basic_auth_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' Strategies = OpenProject::Authentication::Strategies::Warden RSpec.describe Strategies::GlobalBasicAuth do - let(:user) { "someuser" } - let(:password) { "somepassword" } + let(:user) { 'someuser' } + let(:password) { 'somepassword' } let(:config) do lambda do @@ -44,23 +44,23 @@ let(:user) { Strategies::UserBasicAuth.user } before do - allow(Strategies::UserBasicAuth).to receive(:user).and_return("schluessel") + allow(Strategies::UserBasicAuth).to receive(:user).and_return('schluessel') end - it "raises an error" do + it 'raises an error' do expect(&config).to raise_error("global user must not be 'schluessel'") end end - context "with an empty pasword" do - let(:password) { "" } + context 'with an empty pasword' do + let(:password) { '' } - it "raises an error" do - expect(&config).to raise_error("password must not be empty") + it 'raises an error' do + expect(&config).to raise_error('password must not be empty') end end - context "with digits-only password" do + context 'with digits-only password' do let(:password) { 1234 } let(:strategy) { Strategies::GlobalBasicAuth.new nil } @@ -68,8 +68,8 @@ config.call end - it "must authenticate successfully" do - expect(strategy.authenticate_user(user, "1234")).to be_truthy + it 'must authenticate successfully' do + expect(strategy.authenticate_user(user, '1234')).to be_truthy end end end diff --git a/spec/lib/open_project/changed_by_system_spec.rb b/spec/lib/open_project/changed_by_system_spec.rb index daa2d3290a17..2cf365d177c0 100644 --- a/spec/lib/open_project/changed_by_system_spec.rb +++ b/spec/lib/open_project/changed_by_system_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::ChangedBySystem do subject(:model) do @@ -35,62 +35,62 @@ model end - describe "#changed_by_user" do - context "when an attribute is changed" do + describe '#changed_by_user' do + context 'when an attribute is changed' do before do - model.title = "abc" + model.title = 'abc' end - it "returns the attribute" do + it 'returns the attribute' do expect(model.changed_by_user) - .to contain_exactly("title") + .to contain_exactly('title') end end - context "when an attribute is changed by the system" do + context 'when an attribute is changed by the system' do before do model.change_by_system do - model.title = "abc" + model.title = 'abc' end end - it "returns no attributes" do + it 'returns no attributes' do expect(model.changed_by_user) .to be_empty end end - context "when an attribute is changed by the system first and then by the user to a different value" do + context 'when an attribute is changed by the system first and then by the user to a different value' do before do model.change_by_system do - model.title = "abc" + model.title = 'abc' end - model.title = "xyz" + model.title = 'xyz' end - it "returns the attribute" do + it 'returns the attribute' do expect(model.changed_by_user) - .to contain_exactly("title") + .to contain_exactly('title') end end - context "when an attribute is changed by the system first and then by the user to the same value" do + context 'when an attribute is changed by the system first and then by the user to the same value' do before do model.change_by_system do - model.title = "abc" + model.title = 'abc' end - model.title = "abc" + model.title = 'abc' end - it "returns no attribute" do + it 'returns no attribute' do expect(model.changed_by_user) .to be_empty end end - context "when the model has the acts_as_customizable plugin included" do + context 'when the model has the acts_as_customizable plugin included' do subject(:model) do create(:work_package, project:).tap do |wp| wp.extend(described_class) @@ -106,8 +106,8 @@ type.custom_fields << cf1 end - it "returns the custom fields too" do - model.custom_field_values = { cf1.id => "test" } + it 'returns the custom fields too' do + model.custom_field_values = { cf1.id => 'test' } expect(model.changed_by_user) .to include(cf1.attribute_name) end diff --git a/spec/lib/open_project/configuration/helpers_spec.rb b/spec/lib/open_project/configuration/helpers_spec.rb index de6d7df72f57..dd9a51529061 100644 --- a/spec/lib/open_project/configuration/helpers_spec.rb +++ b/spec/lib/open_project/configuration/helpers_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "open_project/configuration/helpers" +require 'spec_helper' +require 'open_project/configuration/helpers' RSpec.describe OpenProject::Configuration::Helpers do let(:config) do @@ -36,54 +36,54 @@ end end - describe "#array" do + describe '#array' do def array(value) config.send :array, value end - context "with single string value" do - it "returns an array containing the value" do - arr = array "test" + context 'with single string value' do + it 'returns an array containing the value' do + arr = array 'test' - expect(arr).to eq ["test"] + expect(arr).to eq ['test'] end end - context "with an array" do - it "returns the array" do - arr = ["arrgh"] + context 'with an array' do + it 'returns the array' do + arr = ['arrgh'] expect(array(arr)).to eq arr end end - context "with a space separated string" do - it "returns an array of the values" do - value = "one two three" + context 'with a space separated string' do + it 'returns an array of the values' do + value = 'one two three' - expect(array(value)).to eq ["one", "two", "three"] + expect(array(value)).to eq ['one', 'two', 'three'] end end end - describe "#hidden_menu_items" do + describe '#hidden_menu_items' do before do - items = config["hidden_menu_items"] = {} - items["admin_menu"] = "users colors" - items["project_menu"] = "info" - items["top_menu"] = [] + items = config['hidden_menu_items'] = {} + items['admin_menu'] = 'users colors' + items['project_menu'] = 'info' + items['top_menu'] = [] end - it "works with arrays" do - expect(config.hidden_menu_items["top_menu"]).to eq [] + it 'works with arrays' do + expect(config.hidden_menu_items['top_menu']).to eq [] end - it "works with single string values" do - expect(config.hidden_menu_items["project_menu"]).to eq ["info"] + it 'works with single string values' do + expect(config.hidden_menu_items['project_menu']).to eq ['info'] end - it "work with space separated string values" do - expect(config.hidden_menu_items["admin_menu"]).to eq ["users", "colors"] + it 'work with space separated string values' do + expect(config.hidden_menu_items['admin_menu']).to eq ['users', 'colors'] end end end diff --git a/spec/lib/open_project/configuration_spec.rb b/spec/lib/open_project/configuration_spec.rb index 1d52854c320c..c28b0326588d 100644 --- a/spec/lib/open_project/configuration_spec.rb +++ b/spec/lib/open_project/configuration_spec.rb @@ -26,77 +26,77 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Configuration, :settings_reset do - describe ".[setting]" do - it "fetches the value" do + describe '.[setting]' do + it 'fetches the value' do expect(described_class.app_title) - .to eql("OpenProject") + .to eql('OpenProject') end end - describe ".[setting]?" do - it "fetches the value" do + describe '.[setting]?' do + it 'fetches the value' do expect(described_class.smtp_enable_starttls_auto?) .to be false end - it "works for non boolean settings as well (deprecated)" do + it 'works for non boolean settings as well (deprecated)' do expect(described_class.app_title?) .to be false end end - describe ".[setting]=" do - it "raises an error" do + describe '.[setting]=' do + it 'raises an error' do expect { described_class.smtp_enable_starttls_auto = true } .to raise_error NoMethodError end end - describe ".cache_store_configuration" do + describe '.cache_store_configuration' do subject { described_class.cache_store_configuration } - context "without cache store already set" do - context "with additional cache store configuration", with_config: { "rails_cache_store" => "bar" } do - it "changes the cache store" do + context 'without cache store already set' do + context 'with additional cache store configuration', with_config: { 'rails_cache_store' => 'bar' } do + it 'changes the cache store' do expect(subject).to eq([:bar]) end end - context "without additional cache store configuration", with_config: { "rails_cache_store" => nil } do + context 'without additional cache store configuration', with_config: { 'rails_cache_store' => nil } do before do - described_class["rails_cache_store"] = nil + described_class['rails_cache_store'] = nil end - it "defaults the cache store to :file_store" do + it 'defaults the cache store to :file_store' do expect(subject.first).to eq(:file_store) end end - context "setting rails cache to redis", with_config: { "rails_cache_store" => "redis" } do - context "when setting the URL", with_config: { "cache_redis_url" => "redis://localhost:1234" } do - it "sets the cache to :redis_cache_store" do + context 'setting rails cache to redis', with_config: { 'rails_cache_store' => 'redis' } do + context 'when setting the URL', with_config: { 'cache_redis_url' => 'redis://localhost:1234' } do + it 'sets the cache to :redis_cache_store' do expect(subject.first).to eq(:redis_cache_store) end end - it "raises an error trying to set redis without an URL" do + it 'raises an error trying to set redis without an URL' do expect { subject }.to raise_error(ArgumentError, /CACHE_REDIS_URL is not set/) end end end end - describe "#direct_uploads?" do + describe '#direct_uploads?' do let(:value) { described_class.direct_uploads? } - it "is false by default" do + it 'is false by default' do expect(value).to be false end - context "with remote storage" do + context 'with remote storage' do def self.storage(provider) { attachments_storage: :fog, @@ -108,14 +108,14 @@ def self.storage(provider) } end - context "with AWS", with_config: storage("AWS") do - it "is true" do + context 'with AWS', with_config: storage('AWS') do + it 'is true' do expect(value).to be true end end - context "with Azure", with_config: storage("azure") do - it "is false" do + context 'with Azure', with_config: storage('azure') do + it 'is false' do expect(value).to be false end end diff --git a/spec/lib/open_project/content_type_detector_spec.rb b/spec/lib/open_project/content_type_detector_spec.rb index f6e929f72cb1..98b69faf6764 100644 --- a/spec/lib/open_project/content_type_detector_spec.rb +++ b/spec/lib/open_project/content_type_detector_spec.rb @@ -54,53 +54,53 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::ContentTypeDetector do - it "gives a sensible default when the name is empty" do - expect(OpenProject::ContentTypeDetector.new("").detect).to eq("application/binary") + it 'gives a sensible default when the name is empty' do + expect(OpenProject::ContentTypeDetector.new('').detect).to eq('application/binary') end - it "returns the empty content type when the file is empty" do - tempfile = Tempfile.new("empty") - expect(OpenProject::ContentTypeDetector.new(tempfile.path).detect).to eq("inode/x-empty") + it 'returns the empty content type when the file is empty' do + tempfile = Tempfile.new('empty') + expect(OpenProject::ContentTypeDetector.new(tempfile.path).detect).to eq('inode/x-empty') tempfile.close end - it "returns content type of file if it is an acceptable type" do - allow(MIME::Types).to receive(:type_for).and_return([MIME::Type.new("application/mp4"), MIME::Type.new("video/mp4"), - MIME::Type.new("audio/mp4")]) - allow(Open3).to receive(:capture2).and_return(["video/mp4", 0]) - @filename = "my_file.mp4" - expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq("video/mp4") + it 'returns content type of file if it is an acceptable type' do + allow(MIME::Types).to receive(:type_for).and_return([MIME::Type.new('application/mp4'), MIME::Type.new('video/mp4'), + MIME::Type.new('audio/mp4')]) + allow(Open3).to receive(:capture2).and_return(['video/mp4', 0]) + @filename = 'my_file.mp4' + expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq('video/mp4') end - it "returns the default when exitcode > 0" do - allow(MIME::Types).to receive(:type_for).and_return([MIME::Type.new("application/mp4"), MIME::Type.new("video/mp4"), - MIME::Type.new("audio/mp4")]) - allow(Open3).to receive(:capture2).and_return(["", 1]) - @filename = "my_file.mp4" - expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq("application/binary") + it 'returns the default when exitcode > 0' do + allow(MIME::Types).to receive(:type_for).and_return([MIME::Type.new('application/mp4'), MIME::Type.new('video/mp4'), + MIME::Type.new('audio/mp4')]) + allow(Open3).to receive(:capture2).and_return(['', 1]) + @filename = 'my_file.mp4' + expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq('application/binary') end - it "finds the right type in the list via the file command" do + it 'finds the right type in the list via the file command' do @filename = "#{Dir.tmpdir}/something.hahalolnotreal" - File.open(@filename, "w+") do |file| - file.puts "This is a text file." + File.open(@filename, 'w+') do |file| + file.puts 'This is a text file.' file.rewind - expect(OpenProject::ContentTypeDetector.new(file.path).detect).to eq("text/plain") + expect(OpenProject::ContentTypeDetector.new(file.path).detect).to eq('text/plain') end FileUtils.rm @filename end - it "returns a sensible default if something is wrong, like the file is gone" do - @filename = "/path/to/nothing" - expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq("application/binary") + it 'returns a sensible default if something is wrong, like the file is gone' do + @filename = '/path/to/nothing' + expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq('application/binary') end - it "returns a sensible default when the file command is missing" do - allow(Open3).to receive(:capture2).and_raise "o noes!" - @filename = "/path/to/something" - expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq("application/binary") + it 'returns a sensible default when the file command is missing' do + allow(Open3).to receive(:capture2).and_raise 'o noes!' + @filename = '/path/to/something' + expect(OpenProject::ContentTypeDetector.new(@filename).detect).to eq('application/binary') end end diff --git a/spec/lib/open_project/enterprise_spec.rb b/spec/lib/open_project/enterprise_spec.rb index 6036add8bf58..b47f8d8a71cf 100644 --- a/spec/lib/open_project/enterprise_spec.rb +++ b/spec/lib/open_project/enterprise_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "open_project/passwords" +require 'spec_helper' +require 'open_project/passwords' RSpec.describe OpenProject::Enterprise do # create 3 built-in users, only 2 of which are active diff --git a/spec/lib/open_project/events_spec.rb b/spec/lib/open_project/events_spec.rb index 14d968e6e069..b56d87e5342b 100644 --- a/spec/lib/open_project/events_spec.rb +++ b/spec/lib/open_project/events_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Events do def fire_event(event_constant_name) @@ -37,7 +37,7 @@ def fire_event(event_constant_name) end before do - allow(Storages::ManageNextcloudIntegrationJob).to receive(:debounce) + allow(Storages::ManageNextcloudIntegrationEventsJob).to receive(:debounce) end %w[ @@ -48,27 +48,30 @@ def fire_event(event_constant_name) describe(event) do subject { fire_event(event) } - context "when payload is empty" do + context 'when payload is empty' do let(:payload) { {} } it do subject - expect(Storages::ManageNextcloudIntegrationJob).not_to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).not_to have_received(:debounce) end end - context "when payload contains automatic project_folder_mode" do + context 'when payload contains automatic project_folder_mode' do let(:payload) { { project_folder_mode: :automatic } } it do subject - expect(Storages::ManageNextcloudIntegrationJob).to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).to have_received(:debounce) end it do - allow(Storages::ManageNextcloudIntegrationJob).to receive(:disable_cron_job_if_needed) + # Check for message being called instead of checking the job arrival to the queue + # because it is not simple adding to the queue in ::Storages::ManageNextcloudIntegrationCronJob.ensure_scheduled! + # With this method cron_job can be actually removed if not needed. + allow(Storages::ManageNextcloudIntegrationCronJob).to receive(:ensure_scheduled!) subject - expect(Storages::ManageNextcloudIntegrationJob).to have_received(:disable_cron_job_if_needed) + expect(Storages::ManageNextcloudIntegrationCronJob).to have_received(:ensure_scheduled!) end end end @@ -90,73 +93,73 @@ def fire_event(event_constant_name) it do subject - expect(Storages::ManageNextcloudIntegrationJob).to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).to have_received(:debounce) end end end - describe "OAUTH_CLIENT_TOKEN_CREATED" do - subject { fire_event("OAUTH_CLIENT_TOKEN_CREATED") } + describe 'OAUTH_CLIENT_TOKEN_CREATED' do + subject { fire_event('OAUTH_CLIENT_TOKEN_CREATED') } - context "when payload is empty" do + context 'when payload is empty' do let(:payload) { {} } it do subject - expect(Storages::ManageNextcloudIntegrationJob).not_to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).not_to have_received(:debounce) end end - context "when payload contains storage integration type" do - let(:payload) { { integration_type: "Storages::Storage" } } + context 'when payload contains storage integration type' do + let(:payload) { { integration_type: 'Storages::Storage' } } it do subject - expect(Storages::ManageNextcloudIntegrationJob).to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).to have_received(:debounce) end end end - describe "ROLE_UPDATED" do - subject { fire_event("ROLE_UPDATED") } + describe 'ROLE_UPDATED' do + subject { fire_event('ROLE_UPDATED') } - context "when payload is empty" do + context 'when payload is empty' do let(:payload) { {} } it do subject - expect(Storages::ManageNextcloudIntegrationJob).not_to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).not_to have_received(:debounce) end end - context "when payload contains some nextcloud related permissions as a diff" do + context 'when payload contains some nextcloud related permissions as a diff' do let(:payload) { { permissions_diff: [:read_files] } } it do subject - expect(Storages::ManageNextcloudIntegrationJob).to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).to have_received(:debounce) end end end - describe "ROLE_DESTROYED" do - subject { fire_event("ROLE_DESTROYED") } + describe 'ROLE_DESTROYED' do + subject { fire_event('ROLE_DESTROYED') } - context "when payload is empty" do + context 'when payload is empty' do let(:payload) { {} } it do subject - expect(Storages::ManageNextcloudIntegrationJob).not_to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).not_to have_received(:debounce) end end - context "when payload contains some nextcloud related permissions" do + context 'when payload contains some nextcloud related permissions' do let(:payload) { { permissions: [:read_files] } } it do subject - expect(Storages::ManageNextcloudIntegrationJob).to have_received(:debounce) + expect(Storages::ManageNextcloudIntegrationEventsJob).to have_received(:debounce) end end end diff --git a/spec/lib/open_project/feature_decisions_spec.rb b/spec/lib/open_project/feature_decisions_spec.rb index 308d05d97f82..493cf216b851 100644 --- a/spec/lib/open_project/feature_decisions_spec.rb +++ b/spec/lib/open_project/feature_decisions_spec.rb @@ -25,68 +25,68 @@ # # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::FeatureDecisions, :settings_reset do let(:flag_name) { :example_flag } - include_context "with clean feature decisions" + include_context 'with clean feature decisions' - shared_context "when adding without env variable" do + shared_context 'when adding without env variable' do before do described_class.add flag_name end end - shared_context "when adding the given feature flag" do + shared_context 'when adding the given feature flag' do before do described_class.add flag_name end end - describe "`flag_name`_active?" do - context "without an ENV variable" do - include_context "when adding without env variable" + describe '`flag_name`_active?' do + context 'without an ENV variable' do + include_context 'when adding without env variable' - it "is false by default" do + it 'is false by default' do expect(described_class.send(:"#{flag_name}_active?")) .to be false end end - context "with an ENV variable (set to true)", - with_env: { "OPENPROJECT_FEATURE_EXAMPLE_FLAG_ACTIVE" => "true" } do - include_context "when adding the given feature flag" + context 'with an ENV variable (set to true)', + with_env: { 'OPENPROJECT_FEATURE_EXAMPLE_FLAG_ACTIVE' => 'true' } do + include_context 'when adding the given feature flag' - it "is true" do + it 'is true' do expect(described_class.send(:"#{flag_name}_active?")) .to be true end end end - describe "active" do - context "without any flags defined" do - it "returns an empty array" do + describe 'active' do + context 'without any flags defined' do + it 'returns an empty array' do expect(described_class.active) .to eq [] end end - context "with a flag defined but not enabled" do - include_context "when adding without env variable" + context 'with a flag defined but not enabled' do + include_context 'when adding without env variable' - it "returns an empty array" do + it 'returns an empty array' do expect(described_class.active) .to eq [] end end - context "with a flag defined that is enabled via env", - with_env: { "OPENPROJECT_FEATURE_EXAMPLE_FLAG_ACTIVE" => "true" } do - include_context "when adding the given feature flag" + context 'with a flag defined that is enabled via env', + with_env: { 'OPENPROJECT_FEATURE_EXAMPLE_FLAG_ACTIVE' => 'true' } do + include_context 'when adding the given feature flag' - it "returns an empty array" do + it 'returns an empty array' do expect(described_class.active) .to eq [flag_name.to_s] end diff --git a/spec/lib/open_project/file_command_content_type_detector_spec.rb b/spec/lib/open_project/file_command_content_type_detector_spec.rb index f7407dc0f110..d22cf03f0eec 100644 --- a/spec/lib/open_project/file_command_content_type_detector_spec.rb +++ b/spec/lib/open_project/file_command_content_type_detector_spec.rb @@ -54,27 +54,27 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::FileCommandContentTypeDetector do - it "returns a content type based on the content of the file" do - tempfile = Tempfile.new("something") - tempfile.write("This is a file.") + it 'returns a content type based on the content of the file' do + tempfile = Tempfile.new('something') + tempfile.write('This is a file.') tempfile.rewind - expect(OpenProject::FileCommandContentTypeDetector.new(tempfile.path).detect).to eq("text/plain") + expect(OpenProject::FileCommandContentTypeDetector.new(tempfile.path).detect).to eq('text/plain') tempfile.close end - it "returns a sensible default when the file command is missing" do - allow(Open3).to receive(:capture2).and_raise "o noes!" - @filename = "/path/to/something" - expect(OpenProject::FileCommandContentTypeDetector.new(@filename).detect).to eq("application/binary") + it 'returns a sensible default when the file command is missing' do + allow(Open3).to receive(:capture2).and_raise 'o noes!' + @filename = '/path/to/something' + expect(OpenProject::FileCommandContentTypeDetector.new(@filename).detect).to eq('application/binary') end - it "returns a sensible default on the odd chance that run returns nil" do + it 'returns a sensible default on the odd chance that run returns nil' do allow(Open3).to receive(:capture2).and_return [nil, 0] - expect(OpenProject::FileCommandContentTypeDetector.new("windows").detect).to eq("application/binary") + expect(OpenProject::FileCommandContentTypeDetector.new('windows').detect).to eq('application/binary') end end diff --git a/spec/lib/open_project/files_spec.rb b/spec/lib/open_project/files_spec.rb index 8ef991f0401a..a87233b1ea84 100644 --- a/spec/lib/open_project/files_spec.rb +++ b/spec/lib/open_project/files_spec.rb @@ -54,46 +54,46 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Files do - describe "build_uploaded_file" do - let(:original_filename) { "test.png" } - let(:content_type) { "image/png" } + describe 'build_uploaded_file' do + let(:original_filename) { 'test.png' } + let(:content_type) { 'image/png' } let(:file) do OpenProject::Files.create_temp_file(name: original_filename) end subject { OpenProject::Files.build_uploaded_file(file, content_type) } - it "has the original file name" do + it 'has the original file name' do expect(subject.original_filename).to eql(original_filename) end - it "has the given content type" do + it 'has the given content type' do expect(subject.content_type).to eql(content_type) end - context "with custom file name" do - let(:file_name) { "my-custom-filename.png" } + context 'with custom file name' do + let(:file_name) { 'my-custom-filename.png' } subject { OpenProject::Files.build_uploaded_file(file, content_type, file_name:) } - it "has the custom file name" do + it 'has the custom file name' do expect(subject.original_filename).to eql(file_name) end end end - describe "create_uploaded_file" do - context "without parameters" do + describe 'create_uploaded_file' do + context 'without parameters' do let(:file) { OpenProject::Files.create_uploaded_file } it 'creates a file with the default name "test.txt"' do - expect(file.original_filename).to eq "test.txt" + expect(file.original_filename).to eq 'test.txt' end - it "creates distinct files even with identical names" do + it 'creates distinct files even with identical names' do file_2 = OpenProject::Files.create_uploaded_file expect(file.original_filename).to eq file_2.original_filename @@ -101,18 +101,18 @@ end it 'writes some default content "test content"' do - expect(file.read).to eq "test content" + expect(file.read).to eq 'test content' end it 'set default content type "text/plain"' do - expect(file.content_type).to eq "text/plain" + expect(file.content_type).to eq 'text/plain' end end - context "with a custom name, content and content type" do - let(:name) { "foo.jpg" } - let(:content) { "not-really-a-jpg" } - let(:content_type) { "image/jpeg" } + context 'with a custom name, content and content type' do + let(:name) { 'foo.jpg' } + let(:content) { 'not-really-a-jpg' } + let(:content_type) { 'image/jpeg' } let(:file) do OpenProject::Files.create_uploaded_file name:, @@ -124,7 +124,7 @@ expect(file.original_filename).to eq name end - it "writes the custom content" do + it 'writes the custom content' do expect(file.read).to eq content end @@ -133,19 +133,19 @@ end end - context "with binary content" do + context 'with binary content' do let(:content) { "\xD1\x9B\x86".b } let(:binary) { false } let(:file) { OpenProject::Files.create_uploaded_file content:, binary: } - it "fails when the content is not marked as binary" do + it 'fails when the content is not marked as binary' do expect { file }.to raise_error(Encoding::UndefinedConversionError) end - context "with the file denoted as binary" do + context 'with the file denoted as binary' do let(:binary) { true } - it "succeeds" do + it 'succeeds' do expect(file.read).to eq content end end diff --git a/spec/lib/open_project/footer_spec.rb b/spec/lib/open_project/footer_spec.rb index 392e37793274..2923f6a51ca0 100644 --- a/spec/lib/open_project/footer_spec.rb +++ b/spec/lib/open_project/footer_spec.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "open_project/footer" +require 'spec_helper' +require 'open_project/footer' RSpec.describe OpenProject::Footer do - describe ".add_content" do - context "empty content" do + describe '.add_content' do + context 'empty content' do before do OpenProject::Footer.content = nil - OpenProject::Footer.add_content("OpenProject", "footer") + OpenProject::Footer.add_content('OpenProject', 'footer') end it { expect(OpenProject::Footer.content.class).to eq(Hash) } - it { expect(OpenProject::Footer.content["OpenProject"]).to eq("footer") } + it { expect(OpenProject::Footer.content['OpenProject']).to eq('footer') } end - context "existing content" do + context 'existing content' do before do OpenProject::Footer.content = nil - OpenProject::Footer.add_content("OpenProject", "footer") - OpenProject::Footer.add_content("footer_2", "footer 2") + OpenProject::Footer.add_content('OpenProject', 'footer') + OpenProject::Footer.add_content('footer_2', 'footer 2') end it { expect(OpenProject::Footer.content.count).to eq(2) } - it { expect(OpenProject::Footer.content).to eq("OpenProject" => "footer", "footer_2" => "footer 2") } + it { expect(OpenProject::Footer.content).to eq('OpenProject' => 'footer', 'footer_2' => 'footer 2') } end end end diff --git a/spec/lib/open_project/form_tag_helper_spec.rb b/spec/lib/open_project/form_tag_helper_spec.rb index 706864cd5426..53e0505b5274 100644 --- a/spec/lib/open_project/form_tag_helper_spec.rb +++ b/spec/lib/open_project/form_tag_helper_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::FormTagHelper, type: :helper do let(:options) { {} } - describe "#styled_form_tag" do + describe '#styled_form_tag' do subject(:output) do - helper.styled_form_tag("/feedback", options) do - content_tag(:p, "Form content") + helper.styled_form_tag('/feedback', options) do + content_tag(:p, 'Form content') end end - it_behaves_like "not wrapped in container", "form-container" + it_behaves_like 'not wrapped in container', 'form-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ FUN'.html_safe, options) + helper.styled_select_tag('field', ''.html_safe, options) end - it_behaves_like "wrapped in container", "select-container" + it_behaves_like 'wrapped in container', 'select-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end end - describe "#styled_text_field_tag" do - let(:value) { "Something to be seen" } + describe '#styled_text_field_tag' do + let(:value) { 'Something to be seen' } subject(:output) do - helper.styled_text_field_tag("field", value, options) + helper.styled_text_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_label_tag" do - context "with block" do + describe '#styled_label_tag' do + context 'with block' do subject(:output) do - helper.styled_label_tag("field", nil, options) do - "Label content" + helper.styled_label_tag('field', nil, options) do + 'Label content' end end - it_behaves_like "not wrapped in container", "label-container" + it_behaves_like 'not wrapped in container', 'label-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ }) end end - context "with content arg" do + context 'with content arg' do subject(:output) do - helper.styled_label_tag("field", "Label content", options) + helper.styled_label_tag('field', 'Label content', options) end - it_behaves_like "not wrapped in container", "label-container" + it_behaves_like 'not wrapped in container', 'label-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ }) end end - context "for titles" do - it "uses the title from the options if given" do - label = helper.styled_label_tag "field", "Lautrec", title: "Carim" + context 'for titles' do + it 'uses the title from the options if given' do + label = helper.styled_label_tag 'field', 'Lautrec', title: 'Carim' expect(label).to be_html_eql(%{ }) end - it "prefers the title given in the options over the content" do - label = helper.styled_label_tag("field", nil, title: "Carim") { "Lordvessel" } + it 'prefers the title given in the options over the content' do + label = helper.styled_label_tag('field', nil, title: 'Carim') { 'Lordvessel' } expect(label).to be_html_eql(%{ }) end - it "strips any given inline HTML from the title tag (with block)" do - label = helper.styled_label_tag("field") do - helper.content_tag :span, "Sif" + it 'strips any given inline HTML from the title tag (with block)' do + label = helper.styled_label_tag('field') do + helper.content_tag :span, 'Sif' end expect(label).to be_html_eql(%{ }) end - it "strips any given inline HTML from the title tag (with content arg)" do - label = helper.styled_label_tag("field", helper.content_tag(:span, "Sif")) + it 'strips any given inline HTML from the title tag (with content arg)' do + label = helper.styled_label_tag('field', helper.content_tag(:span, 'Sif')) expect(label).to be_html_eql(%{ }) @@ -145,125 +145,125 @@ end end - describe "#styled_file_field_tag" do + describe '#styled_file_field_tag' do subject(:output) do - helper.styled_file_field_tag("file_field", options) + helper.styled_file_field_tag('file_field', options) end - it_behaves_like "wrapped in container", "file-field-container" + it_behaves_like 'wrapped in container', 'file-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_password_field_tag" do + describe '#styled_password_field_tag' do subject(:output) do - helper.styled_password_field_tag("password", "nopE3king!", options) + helper.styled_password_field_tag('password', 'nopE3king!', options) end - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_text_area_tag" do + describe '#styled_text_area_tag' do subject(:output) do - helper.styled_text_area_tag("field", "Words are important", options) + helper.styled_text_area_tag('field', 'Words are important', options) end - it_behaves_like "wrapped in container", "text-area-container" + it_behaves_like 'wrapped in container', 'text-area-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("textarea") + }).at_path('textarea') end end - describe "#styled_check_box_tag" do + describe '#styled_check_box_tag' do subject(:output) do - helper.styled_check_box_tag("field", "1", false, options) + helper.styled_check_box_tag('field', '1', false, options) end - it_behaves_like "wrapped in container", "check-box-container" + it_behaves_like 'wrapped in container', 'check-box-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_radio_button_tag" do - let(:value) { "good choice" } + describe '#styled_radio_button_tag' do + let(:value) { 'good choice' } subject(:output) do - helper.styled_radio_button_tag("field", value, false, options) + helper.styled_radio_button_tag('field', value, false, options) end - it_behaves_like "wrapped in container", "radio-button-container" + it_behaves_like 'wrapped in container', 'radio-button-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_submit_tag" do + describe '#styled_submit_tag' do let(:output) do - helper.styled_submit_tag("Save it!", options) + helper.styled_submit_tag('Save it!', options) end subject(:html) do Capybara::Node::Simple.new(output) end - it_behaves_like "not wrapped in container", "submit-container" + it_behaves_like 'not wrapped in container', 'submit-container' - it "outputs element" do - expect(html).to have_css("input[type=submit]") + it 'outputs element' do + expect(html).to have_css('input[type=submit]') end end - describe "#styled_button_tag" do + describe '#styled_button_tag' do subject(:output) do helper.styled_button_tag(options) do "Don't save!" end end - it_behaves_like "not wrapped in container", "button-container" + it_behaves_like 'not wrapped in container', 'button-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql %{ } end end - describe "#styled_field_set_tag" do + describe '#styled_field_set_tag' do subject(:output) do - helper.styled_field_set_tag("Fieldset Legend", options) do - content_tag(:p, "Fieldset content") + helper.styled_field_set_tag('Fieldset Legend', options) do + content_tag(:p, 'Fieldset content') end end - it_behaves_like "not wrapped in container", "fieldset-container" + it_behaves_like 'not wrapped in container', 'fieldset-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql %{
    Fieldset Legend @@ -272,103 +272,103 @@ end end - describe "#styled_search_field_tag" do - let(:value) { "Find me" } + describe '#styled_search_field_tag' do + let(:value) { 'Find me' } subject(:output) do - helper.styled_search_field_tag("field", value, options) + helper.styled_search_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "search-field-container" + it_behaves_like 'wrapped in container', 'search-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_telephone_field_tag" do - let(:value) { "+49 555 111 999" } + describe '#styled_telephone_field_tag' do + let(:value) { '+49 555 111 999' } subject(:output) do - helper.styled_telephone_field_tag("field", value, options) + helper.styled_telephone_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_url_field_tag" do - let(:value) { "https://blogger.org/" } + describe '#styled_url_field_tag' do + let(:value) { 'https://blogger.org/' } subject(:output) do - helper.styled_url_field_tag("field", value, options) + helper.styled_url_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_email_field_tag" do - let(:value) { "joe@blogger.com" } + describe '#styled_email_field_tag' do + let(:value) { 'joe@blogger.com' } subject(:output) do - helper.styled_email_field_tag("field", value, options) + helper.styled_email_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_number_field_tag" do + describe '#styled_number_field_tag' do let(:value) { 2 } subject(:output) do - helper.styled_number_field_tag("field", value, options) + helper.styled_number_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#styled_range_field_tag" do + describe '#styled_range_field_tag' do let(:value) { 2 } subject(:output) do - helper.styled_range_field_tag("field", value, options) + helper.styled_range_field_tag('field', value, options) end - it_behaves_like "wrapped in container", "range-field-container" + it_behaves_like 'wrapped in container', 'range-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end end diff --git a/spec/lib/open_project/hook_spec.rb b/spec/lib/open_project/hook_spec.rb index 8d7e3effa2fc..9defc1be2295 100644 --- a/spec/lib/open_project/hook_spec.rb +++ b/spec/lib/open_project/hook_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Hook do let(:test_hook_class) do @@ -34,14 +34,14 @@ let(:test_hook1_class) do Class.new(test_hook_class) do def view_layouts_base_html_head(_context) - "Test hook 1 listener." + 'Test hook 1 listener.' end end end let(:test_hook2_class) do Class.new(test_hook_class) do def view_layouts_base_html_head(_context) - "Test hook 2 listener." + 'Test hook 2 listener.' end end end @@ -63,9 +63,9 @@ def view_layouts_base_html_head(context) described_class.instance_variable_set(:@listener_classes, previous_listener_classes) end - describe "#add_listeners" do - context "when inheriting from the class" do - it "is automatically added" do + describe '#add_listeners' do + context 'when inheriting from the class' do + it 'is automatically added' do expect(described_class.hook_listeners(:view_layouts_base_html_head)) .to be_empty @@ -76,88 +76,88 @@ def view_layouts_base_html_head(context) end end - context "when explicitly adding" do + context 'when explicitly adding' do let(:test_class) do Class.new do include Singleton def view_layouts_base_html_head(_context) - "Test hook listener." + 'Test hook listener.' end end end - it "adds listeners" do + it 'adds listeners' do described_class.add_listener(test_class) expect(described_class.hook_listeners(:view_layouts_base_html_head)) .to contain_exactly(test_class) end end - context "when not having the Singleton module included" do + context 'when not having the Singleton module included' do let(:test_class) do Class.new do def view_layouts_base_html_head(_context) - "Test hook listener." + 'Test hook listener.' end end end - it "adds listeners" do + it 'adds listeners' do expect { described_class.add_listener(test_class) } .to raise_error ArgumentError end end end - describe "#clear_listeners" do + describe '#clear_listeners' do before do # implicitly adding by class creation test_hook1_class end - it "clears the registered listeners" do + it 'clears the registered listeners' do described_class.clear_listeners expect(described_class.hook_listeners(:view_layouts_base_html_head)) .to be_empty end end - describe "#call_hook" do - context "with a class registered for the hook" do + describe '#call_hook' do + context 'with a class registered for the hook' do before do # implicitly adding by class creation test_hook1_class end - it "calls the registered method" do + it 'calls the registered method' do expect(described_class.call_hook(:view_layouts_base_html_head)) .to match_array test_hook1_class.instance.view_layouts_base_html_head(nil) end end - context "without a class registered for the hook" do - it "calls the registered method" do + context 'without a class registered for the hook' do + it 'calls the registered method' do expect(described_class.call_hook(:view_layouts_base_html_head)) .to be_empty end end - context "with multiple listeners" do + context 'with multiple listeners' do before do # implicitly adding by class creation test_hook1_class test_hook2_class end - it "calls all registered methods" do + it 'calls all registered methods' do expect(described_class.call_hook(:view_layouts_base_html_head)) .to contain_exactly(test_hook1_class.instance.view_layouts_base_html_head(nil), test_hook2_class.instance.view_layouts_base_html_head(nil)) end end - context "with a context" do + context 'with a context' do let!(:test_hook_context_class) do # implicitly adding by class creation Class.new(test_hook_class) do @@ -167,31 +167,31 @@ def view_layouts_base_html_head(context) end end - let(:context) { { foo: 1, bar: "a" } } + let(:context) { { foo: 1, bar: 'a' } } - it "passes the context through" do + it 'passes the context through' do expect(described_class.call_hook(:view_layouts_base_html_head, **context)) .to contain_exactly(context) end end - context "with a link rendered in the hooked to method" do + context 'with a link rendered in the hooked to method' do let!(:test_hook_link_class) do # implicitly adding by class creation Class.new(test_hook_class) do def view_layouts_base_html_head(_context) - link_to("Work packages", controller: "/work_packages") + link_to('Work packages', controller: '/work_packages') end end end - it "renders the link" do + it 'renders the link' do expect(described_class.call_hook(:view_layouts_base_html_head)) .to contain_exactly('Work packages') end end - context "when called within a controller" do + context 'when called within a controller' do let(:test_hook_controller_class) do # Also tests that the application controller has the model included Class.new(ApplicationController) @@ -219,19 +219,19 @@ def view_layouts_base_html_head(context) instance_double(ActionDispatch::Request) end - it "adds to the context" do + it 'adds to the context' do expect(instance.call_hook(:view_layouts_base_html_head, {})) .to contain_exactly({ project:, controller: instance, request:, hook_caller: instance }) end end end - context "when called within email rendering" do + context 'when called within email rendering' do let!(:test_hook_link_class) do # implicitly adding by class creation Class.new(test_hook_class) do def view_layouts_base_html_head(_context) - link_to("Work packages", controller: "/work_packages") + link_to('Work packages', controller: '/work_packages') end end end @@ -256,7 +256,7 @@ def view_layouts_base_html_head(_context) ActionMailer::Base.deliveries.last end - it "does not_change_the_default_url_for_email_notifications" do + it 'does not_change_the_default_url_for_email_notifications' do test_hook_controller_class.new.call_hook(:view_layouts_base_html_head) ActionMailer::Base.deliveries.clear diff --git a/spec/lib/open_project/logging/log_extender_spec.rb b/spec/lib/open_project/logging/log_extender_spec.rb index bc994978a84d..4fe1e9027df7 100644 --- a/spec/lib/open_project/logging/log_extender_spec.rb +++ b/spec/lib/open_project/logging/log_extender_spec.rb @@ -26,20 +26,20 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe OpenProject::Logging, "Log extenders" do +RSpec.describe OpenProject::Logging, 'Log extenders' do subject { described_class.extend_payload!(payload, input_context) } let(:payload) do - { method: "GET", action: "something", controller: "SomeController" } + { method: 'GET', action: 'something', controller: 'SomeController' } end let(:input_context) do {} end - context "with an extender returning keys" do + context 'with an extender returning keys' do let(:return_value) do { some_hash: 123 } end @@ -58,7 +58,7 @@ described_class.instance_variable_set(:@payload_extenders, nil) end - it "calls that extender as well as the default one" do + it 'calls that extender as well as the default one' do allow(extender).to receive(:call).and_call_original expect(subject.keys).to contain_exactly :method, :action, :controller, :some_hash, :user @@ -66,7 +66,7 @@ end end - context "with an extender raising an error" do + context 'with an extender raising an error' do let(:return_value) do { some_hash: 123 } end @@ -85,7 +85,7 @@ described_class.instance_variable_set(:@payload_extenders, nil) end - it "does not break the returned payload" do + it 'does not break the returned payload' do allow(extender).to receive(:call).and_call_original expect(subject.keys).to contain_exactly :method, :action, :controller, :user diff --git a/spec/lib/open_project/mime_type_spec.rb b/spec/lib/open_project/mime_type_spec.rb index 5fdcd3d1aad3..2ac536d312c6 100644 --- a/spec/lib/open_project/mime_type_spec.rb +++ b/spec/lib/open_project/mime_type_spec.rb @@ -25,13 +25,13 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::MimeType do - describe "#of" do - to_test = { "test.unk" => nil, - "test.txt" => "text/plain", - "test.c" => "text/x-c" } + describe '#of' do + to_test = { 'test.unk' => nil, + 'test.txt' => 'text/plain', + 'test.c' => 'text/x-c' } to_test.each do |name, expected| it do expect(described_class.of(name)).to eq expected @@ -39,10 +39,10 @@ end end - describe "#css_class_of" do - to_test = { "test.unk" => nil, - "test.txt" => "text-plain", - "test.c" => "text-x-c" } + describe '#css_class_of' do + to_test = { 'test.unk' => nil, + 'test.txt' => 'text-plain', + 'test.c' => 'text-x-c' } to_test.each do |name, expected| it do expect(described_class.css_class_of(name)).to eq expected @@ -50,10 +50,10 @@ end end - describe "#main_mimetype_of" do - to_test = { "test.unk" => nil, - "test.txt" => "text", - "test.c" => "text" } + describe '#main_mimetype_of' do + to_test = { 'test.unk' => nil, + 'test.txt' => 'text', + 'test.c' => 'text' } to_test.each do |name, expected| it do expect(described_class.main_mimetype_of(name)).to eq expected @@ -61,10 +61,10 @@ end end - describe "#is_type?" do - to_test = { ["text", "test.unk"] => false, - ["text", "test.txt"] => true, - ["text", "test.c"] => true } + describe '#is_type?' do + to_test = { ['text', 'test.unk'] => false, + ['text', 'test.txt'] => true, + ['text', 'test.c'] => true } to_test.each do |args, expected| it do @@ -73,11 +73,11 @@ end end - it "equals the main type for the narrow type" do - expect(described_class.narrow_type("rubyfile.rb", "text/plain")).to eq "text/x-ruby" + it 'equals the main type for the narrow type' do + expect(described_class.narrow_type('rubyfile.rb', 'text/plain')).to eq 'text/x-ruby' end - it "uses original type if main type differs" do - expect(described_class.narrow_type("rubyfile.rb", "application/zip")).to eq "application/zip" + it 'uses original type if main type differs' do + expect(described_class.narrow_type('rubyfile.rb', 'application/zip')).to eq 'application/zip' end end diff --git a/spec/lib/open_project/notifications_spec.rb b/spec/lib/open_project/notifications_spec.rb index 02c9fe9006b0..db787549087e 100644 --- a/spec/lib/open_project/notifications_spec.rb +++ b/spec/lib/open_project/notifications_spec.rb @@ -26,23 +26,23 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Notifications do - describe ".send" do + describe '.send' do let(:probe) { lambda { |*_args| } } - let(:payload) { { "test" => "payload" } } + let(:payload) { { 'test' => 'payload' } } before do # We can't clean this up, so we need to use a unique name - described_class.subscribe("notifications_spec_send") do |*args, **kwargs| + described_class.subscribe('notifications_spec_send') do |*args, **kwargs| probe.call(*args, **kwargs) end allow(probe).to receive(:call) end - it "delivers a notification" do + it 'delivers a notification' do described_class.send(:notifications_spec_send, payload) expect(probe).to have_received(:call) do |call_payload| @@ -53,15 +53,15 @@ end end - describe ".subscribe" do - it "throws an error when no callback is given" do + describe '.subscribe' do + it 'throws an error when no callback is given' do expect do - described_class.subscribe("notifications_spec_send") + described_class.subscribe('notifications_spec_send') end.to raise_error ArgumentError, /provide a block as a callback/ end - describe "clear_subscriptions:" do - let(:key) { "test_clear_subs" } + describe 'clear_subscriptions:' do + let(:key) { 'test_clear_subs' } let(:as) { [] } let(:bs) { [] } @@ -77,23 +77,23 @@ def example_with(clear_subscriptions:) described_class.send(key, 2) end - context "when true" do + context 'when true' do before do example_with clear_subscriptions: true end - it "clears previous subscriptions" do + it 'clears previous subscriptions' do expect(as).to eq [1] expect(bs).to eq [2] end end - context "when false" do + context 'when false' do before do example_with clear_subscriptions: false end - it "notifies both subscriptions" do + it 'notifies both subscriptions' do expect(as).to eq [1, 2] expect(bs).to eq [2] end diff --git a/spec/lib/open_project/omni_auth/authorization_spec.rb b/spec/lib/open_project/omni_auth/authorization_spec.rb index 7126d1636ba4..9c6c9253dd06 100644 --- a/spec/lib/open_project/omni_auth/authorization_spec.rb +++ b/spec/lib/open_project/omni_auth/authorization_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::OmniAuth::Authorization do - describe ".after_login!" do - let(:auth_hash) { Struct.new(:uid).new "bar" } - let(:user) { create(:user, mail: "foo@bar.de") } + describe '.after_login!' do + let(:auth_hash) { Struct.new(:uid).new 'bar' } + let(:user) { create(:user, mail: 'foo@bar.de') } let(:state) { Struct.new(:number, :user_email, :uid).new 0, nil, nil } let(:collector) { [] } let!(:existing_callbacks) { OpenProject::OmniAuth::Authorization.after_login_callbacks.dup } @@ -67,11 +67,11 @@ OpenProject::OmniAuth::Authorization.after_login! user, auth_hash expect(state.number).to eq 42 - expect(state.user_email).to eq "foo@bar.de" - expect(state.uid).to eq "bar" + expect(state.user_email).to eq 'foo@bar.de' + expect(state.uid).to eq 'bar' end - it "optionally passes in a context" do + it 'optionally passes in a context' do context = double(:some_context) OpenProject::OmniAuth::Authorization.after_login! user, auth_hash, context expect(collector).to include(context) diff --git a/spec/lib/open_project/passwords_spec.rb b/spec/lib/open_project/passwords_spec.rb index 4efdd4f5b1ca..46914d5db58e 100644 --- a/spec/lib/open_project/passwords_spec.rb +++ b/spec/lib/open_project/passwords_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "open_project/passwords" +require 'spec_helper' +require 'open_project/passwords' RSpec.describe OpenProject::Passwords::Generator do - describe "#random_password", + describe '#random_password', with_settings: { password_active_rules: %w(lowercase uppercase numeric special), password_min_adhered_rules: 3, password_min_length: 4 } do - it "creates a valid password" do + it 'creates a valid password' do pwd = OpenProject::Passwords::Generator.random_password expect(OpenProject::Passwords::Evaluator.conforming?(pwd)).to be(true) end @@ -49,13 +49,13 @@ password_min_adhered_rules: 3, password_min_length: 4 } do - it "evaluates passwords correctly" do - expect(OpenProject::Passwords::Evaluator.conforming?("abCD")).to be(false) - expect(OpenProject::Passwords::Evaluator.conforming?("ab12")).to be(false) - expect(OpenProject::Passwords::Evaluator.conforming?("12CD")).to be(false) - expect(OpenProject::Passwords::Evaluator.conforming?("12CD*")).to be(false) - expect(OpenProject::Passwords::Evaluator.conforming?("aB1")).to be(false) - expect(OpenProject::Passwords::Evaluator.conforming?("abCD12")).to be(true) - expect(OpenProject::Passwords::Evaluator.conforming?("aB123")).to be(true) + it 'evaluates passwords correctly' do + expect(OpenProject::Passwords::Evaluator.conforming?('abCD')).to be(false) + expect(OpenProject::Passwords::Evaluator.conforming?('ab12')).to be(false) + expect(OpenProject::Passwords::Evaluator.conforming?('12CD')).to be(false) + expect(OpenProject::Passwords::Evaluator.conforming?('12CD*')).to be(false) + expect(OpenProject::Passwords::Evaluator.conforming?('aB1')).to be(false) + expect(OpenProject::Passwords::Evaluator.conforming?('abCD12')).to be(true) + expect(OpenProject::Passwords::Evaluator.conforming?('aB123')).to be(true) end end diff --git a/spec/lib/open_project/plugins/acts_as_op_engine_spec.rb b/spec/lib/open_project/plugins/acts_as_op_engine_spec.rb index f007c94a99d2..167a9df5fb73 100644 --- a/spec/lib/open_project/plugins/acts_as_op_engine_spec.rb +++ b/spec/lib/open_project/plugins/acts_as_op_engine_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "roar/decorator" +require 'spec_helper' +require 'roar/decorator' RSpec.describe OpenProject::Plugins::ActsAsOpEngine do class ActsAsOpEngineTestEngine < Rails::Engine @@ -42,9 +42,9 @@ class ActsAsOpEngineTestEngine < Rails::Engine it { is_expected.to respond_to(:additional_permitted_attributes) } it { is_expected.to respond_to(:register) } - describe "#name" do + describe '#name' do subject { engine.name } - it { is_expected.to eq "ActsAsOpEngineTestEngine" } + it { is_expected.to eq 'ActsAsOpEngineTestEngine' } end end diff --git a/spec/lib/open_project/plugins/module_handler_spec.rb b/spec/lib/open_project/plugins/module_handler_spec.rb index 7979acdd2e0f..1a7e0f2c5989 100644 --- a/spec/lib/open_project/plugins/module_handler_spec.rb +++ b/spec/lib/open_project/plugins/module_handler_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Plugins::ModuleHandler do around do |example| old_mapped_permissions = OpenProject::AccessControl.instance_variable_get(:@mapped_permissions).deep_dup - described_class.disable_modules!("repository") + described_class.disable_modules!('repository') example.run ensure @@ -38,8 +38,8 @@ OpenProject::AccessControl.clear_caches end - describe "#disable" do - it "disables repository module" do + describe '#disable' do + it 'disables repository module' do expect(OpenProject::AccessControl.available_project_modules).not_to include(:repository) end end diff --git a/spec/lib/open_project/scm/adapters/git_adapter_spec.rb b/spec/lib/open_project/scm/adapters/git_adapter_spec.rb index f6f427304324..c2fdc4bfc88f 100644 --- a/spec/lib/open_project/scm/adapters/git_adapter_spec.rb +++ b/spec/lib/open_project/scm/adapters/git_adapter_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::SCM::Adapters::Git do shared_examples "git adapter specs" do let(:protocol) { "" } - let(:url) { protocol + Rails.root.join("/tmp/does/not/exist.git").to_s } + let(:url) { protocol + Rails.root.join('/tmp/does/not/exist.git').to_s } let(:config) { {} } let(:encoding) { nil } let(:adapter) do @@ -55,91 +55,91 @@ .and_return(repos_dir) end - describe "client information" do - it "sets the Git client command" do - expect(adapter.client_command).to eq("git") + describe 'client information' do + it 'sets the Git client command' do + expect(adapter.client_command).to eq('git') end - context "with client command from config" do - let(:config) { { client_command: "/usr/local/bin/git" } } + context 'with client command from config' do + let(:config) { { client_command: '/usr/local/bin/git' } } - it "overrides the Git client command from config" do - expect(adapter.client_command).to eq("/usr/local/bin/git") + it 'overrides the Git client command from config' do + expect(adapter.client_command).to eq('/usr/local/bin/git') end end - shared_examples "correct client version" do |git_string, expected_version| - it "sets the correct client version" do + shared_examples 'correct client version' do |git_string, expected_version| + it 'sets the correct client version' do expect(adapter) .to receive(:scm_version_from_command_line) .and_return(git_string) expect(adapter.client_version).to eq(expected_version) expect(adapter.client_available).to be true - expect(adapter.client_version_string).to eq(expected_version.join(".")) + expect(adapter.client_version_string).to eq(expected_version.join('.')) end end - it_behaves_like "correct client version", "git version 1.7.3.4\n", [1, 7, 3, 4] - it_behaves_like "correct client version", "1.6.1\n1.7\n1.8", [1, 6, 1] - it_behaves_like "correct client version", "1.6.2\r\n1.8.1\r\n1.9.1", [1, 6, 2] + it_behaves_like 'correct client version', "git version 1.7.3.4\n", [1, 7, 3, 4] + it_behaves_like 'correct client version', "1.6.1\n1.7\n1.8", [1, 6, 1] + it_behaves_like 'correct client version', "1.6.2\r\n1.8.1\r\n1.9.1", [1, 6, 2] end - describe "invalid repository" do - describe ".check_availability!" do - it "is not available" do + describe 'invalid repository' do + describe '.check_availability!' do + it 'is not available' do expect(Dir.exist?(url)).to be false expect(adapter).not_to be_available expect { adapter.check_availability! } .to raise_error(OpenProject::SCM::Exceptions::SCMUnavailable) end - it "raises a meaningful error if shell output fails" do + it 'raises a meaningful error if shell output fails' do expect { adapter.check_availability! } .to raise_error(OpenProject::SCM::Exceptions::SCMUnavailable) end end end - describe "empty repository" do - include_context "with tmpdir" + describe 'empty repository' do + include_context 'with tmpdir' let(:url) { tmpdir } before do adapter.initialize_bare_git end - describe ".check_availability!" do - shared_examples "check_availibility raises empty" do + describe '.check_availability!' do + shared_examples 'check_availibility raises empty' do it do expect { adapter.check_availability! } .to raise_error(OpenProject::SCM::Exceptions::SCMEmpty) end end - it_behaves_like "check_availibility raises empty" + it_behaves_like 'check_availibility raises empty' - describe "Git version compatibility" do + describe 'Git version compatibility' do before do allow(Open3).to receive(:capture2e).and_return(output, nil) end - context "older Git version" do + context 'older Git version' do let(:output) { "fatal: bad default revision 'HEAD'\n" } - it_behaves_like "check_availibility raises empty" + it_behaves_like 'check_availibility raises empty' end - context "new Git version" do + context 'new Git version' do let(:output) { "fatal: your current branch 'master' does not have any commits yet\n" } - it_behaves_like "check_availibility raises empty" + it_behaves_like 'check_availibility raises empty' end end end end - describe "local repository" do + describe 'local repository' do with_git_repository do |repo_dir| let(:url) { "#{protocol}#{repo_dir}" } @@ -150,19 +150,19 @@ expect { adapter.check_availability! }.not_to raise_error end - it "reads the git version" do + it 'reads the git version' do expect(adapter.client_version.length).to be >= 3 end - it "is a valid repository" do + it 'is a valid repository' do expect(Dir.exist?(repo_dir)).to be true - out, process = Open3.capture2e("git", "--git-dir", repo_dir, "branch") + out, process = Open3.capture2e('git', '--git-dir', repo_dir, 'branch') expect(process.exitstatus).to eq(0) - expect(out).to include("master") + expect(out).to include('master') end - it "is using checkout" do + it 'is using checkout' do if protocol.blank? expect(adapter).not_to be_checkout else @@ -170,218 +170,218 @@ end end - it "is available" do + it 'is available' do expect(adapter).to be_available expect { adapter.check_availability! }.not_to raise_error end - it "reads tags" do + it 'reads tags' do expect(adapter.tags).to match_array(%w[tag00.lightweight tag01.annotated]) end - describe ".branches" do - it "shows the default branch" do - expect(adapter.default_branch).to eq("master") + describe '.branches' do + it 'shows the default branch' do + expect(adapter.default_branch).to eq('master') end - it "reads branches" do + it 'reads branches' do branches = %w[latin-1-path-encoding master test-latin-1 test_branch] expect(adapter.branches).to match_array(branches) end end - describe ".info" do - it "builds the info object" do + describe '.info' do + it 'builds the info object' do info = adapter.info expect(info.root_url).to eq("#{protocol}#{repo_dir}") - expect(info.lastrev.identifier).to eq("71e5c1d3dca6304805b143b9d0e6695fb3895ea4") + expect(info.lastrev.identifier).to eq('71e5c1d3dca6304805b143b9d0e6695fb3895ea4') end end - describe ".lastrev" do + describe '.lastrev' do let(:felix_hex) { "Felix Sch\xC3\xA4fer" } - it "references the last revision for empty path" do - lastrev = adapter.lastrev("", nil) - expect(lastrev.identifier).to eq("71e5c1d3dca6304805b143b9d0e6695fb3895ea4") + it 'references the last revision for empty path' do + lastrev = adapter.lastrev('', nil) + expect(lastrev.identifier).to eq('71e5c1d3dca6304805b143b9d0e6695fb3895ea4') end - it "references the last revision of the given path" do - lastrev = adapter.lastrev("README", nil) - expect(lastrev.identifier).to eq("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8") - expect(lastrev.author).to eq("Adam Soltys ") - expect(lastrev.time).to eq("2009-06-24 07:27:38 +0200") + it 'references the last revision of the given path' do + lastrev = adapter.lastrev('README', nil) + expect(lastrev.identifier).to eq('4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8') + expect(lastrev.author).to eq('Adam Soltys ') + expect(lastrev.time).to eq('2009-06-24 07:27:38 +0200') # Even though that commit has a message, lastrev doesn't parse that deliberately - expect(lastrev.message).to eq("") + expect(lastrev.message).to eq('') expect(lastrev.branch).to be_nil expect(lastrev.paths).to be_nil end - it "references the last revision of the given path and identifier" do - lastrev = adapter.lastrev("README", "4f26664364207fa8b1af9f8722647ab2d4ac5d43") - expect(lastrev.scmid).to eq("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8") - expect(lastrev.identifier).to eq("4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8") - expect(lastrev.author).to eq("Adam Soltys ") - expect(lastrev.time).to eq("2009-06-24 05:27:38") + it 'references the last revision of the given path and identifier' do + lastrev = adapter.lastrev('README', '4f26664364207fa8b1af9f8722647ab2d4ac5d43') + expect(lastrev.scmid).to eq('4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8') + expect(lastrev.identifier).to eq('4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8') + expect(lastrev.author).to eq('Adam Soltys ') + expect(lastrev.time).to eq('2009-06-24 05:27:38') end - it "works with spaces in filename" do - lastrev = adapter.lastrev("filemane with spaces.txt", - "ed5bb786bbda2dee66a2d50faf51429dbc043a7b") - expect(lastrev.identifier).to eq("ed5bb786bbda2dee66a2d50faf51429dbc043a7b") - expect(lastrev.scmid).to eq("ed5bb786bbda2dee66a2d50faf51429dbc043a7b") - expect(lastrev.time).to eq("2010-09-18 19:59:46") + it 'works with spaces in filename' do + lastrev = adapter.lastrev('filemane with spaces.txt', + 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b') + expect(lastrev.identifier).to eq('ed5bb786bbda2dee66a2d50faf51429dbc043a7b') + expect(lastrev.scmid).to eq('ed5bb786bbda2dee66a2d50faf51429dbc043a7b') + expect(lastrev.time).to eq('2010-09-18 19:59:46') end - it "encodes strings correctly" do - lastrev = adapter.lastrev("filemane with spaces.txt", - "ed5bb786bbda2dee66a2d50faf51429dbc043a7b") - expect(lastrev.author).to eq("Felix Schäfer ") + it 'encodes strings correctly' do + lastrev = adapter.lastrev('filemane with spaces.txt', + 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b') + expect(lastrev.author).to eq('Felix Schäfer ') expect(lastrev.author).to eq("#{felix_hex} ") end end - describe ".revisions" do - it "retrieves all revisions" do - rev = adapter.revisions("", nil, nil, all: true) + describe '.revisions' do + it 'retrieves all revisions' do + rev = adapter.revisions('', nil, nil, all: true) expect(rev.length).to eq(22) end - it "retrieves the latest revision" do - rev = adapter.revisions("", nil, nil, all: true) - expect(rev.latest.identifier).to eq("71e5c1d3dca6304805b143b9d0e6695fb3895ea4") - expect(rev.latest.format_identifier).to eq("71e5c1d3") + it 'retrieves the latest revision' do + rev = adapter.revisions('', nil, nil, all: true) + expect(rev.latest.identifier).to eq('71e5c1d3dca6304805b143b9d0e6695fb3895ea4') + expect(rev.latest.format_identifier).to eq('71e5c1d3') end - it "retrieves a certain revisions" do - rev = adapter.revisions("", "899a15d^", "899a15d") + it 'retrieves a certain revisions' do + rev = adapter.revisions('', '899a15d^', '899a15d') expect(rev.length).to eq(1) - expect(rev[0].identifier).to eq("899a15dba03a3b350b89c3f537e4bbe02a03cdc9") - expect(rev[0].author).to eq("jsmith ") + expect(rev[0].identifier).to eq('899a15dba03a3b350b89c3f537e4bbe02a03cdc9') + expect(rev[0].author).to eq('jsmith ') end - it "retrieves revisions in reverse" do - rev = adapter.revisions("", nil, nil, all: true, reverse: true) + it 'retrieves revisions in reverse' do + rev = adapter.revisions('', nil, nil, all: true, reverse: true) expect(rev.length).to eq(22) - expect(rev[0].identifier).to eq("7234cb2750b63f47bff735edc50a1c0a433c2518") - expect(rev[20].identifier).to eq("1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127") + expect(rev[0].identifier).to eq('7234cb2750b63f47bff735edc50a1c0a433c2518') + expect(rev[20].identifier).to eq('1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127') end - it "retrieves revisions in a specific time frame" do + it 'retrieves revisions in a specific time frame' do since = Time.gm(2010, 9, 30, 0, 0, 0) - rev = adapter.revisions("", nil, nil, all: true, since:) + rev = adapter.revisions('', nil, nil, all: true, since:) expect(rev.length).to eq(7) - expect(rev[0].identifier).to eq("71e5c1d3dca6304805b143b9d0e6695fb3895ea4") - expect(rev[1].identifier).to eq("1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127") - expect(rev[5].identifier).to eq("9a6f3b947d16f11b537363a60904d1b1d3bfcd2f") - expect(rev[6].identifier).to eq("67e7792ce20ccae2e4bb73eed09bb397819c8834") + expect(rev[0].identifier).to eq('71e5c1d3dca6304805b143b9d0e6695fb3895ea4') + expect(rev[1].identifier).to eq('1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127') + expect(rev[5].identifier).to eq('9a6f3b947d16f11b537363a60904d1b1d3bfcd2f') + expect(rev[6].identifier).to eq('67e7792ce20ccae2e4bb73eed09bb397819c8834') end - it "retrieves revisions in a specific time frame in reverse" do + it 'retrieves revisions in a specific time frame in reverse' do since = Time.gm(2010, 9, 30, 0, 0, 0) - rev = adapter.revisions("", nil, nil, all: true, since:, reverse: true) + rev = adapter.revisions('', nil, nil, all: true, since:, reverse: true) expect(rev.length).to eq(7) - expect(rev[0].identifier).to eq("67e7792ce20ccae2e4bb73eed09bb397819c8834") - expect(rev[5].identifier).to eq("1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127") - expect(rev[6].identifier).to eq("71e5c1d3dca6304805b143b9d0e6695fb3895ea4") + expect(rev[0].identifier).to eq('67e7792ce20ccae2e4bb73eed09bb397819c8834') + expect(rev[5].identifier).to eq('1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127') + expect(rev[6].identifier).to eq('71e5c1d3dca6304805b143b9d0e6695fb3895ea4') end - it "retrieves revisions by filename" do - rev = adapter.revisions("filemane with spaces.txt", nil, nil, all: true) + it 'retrieves revisions by filename' do + rev = adapter.revisions('filemane with spaces.txt', nil, nil, all: true) expect(rev.length).to eq(1) - expect(rev[0].identifier).to eq("ed5bb786bbda2dee66a2d50faf51429dbc043a7b") + expect(rev[0].identifier).to eq('ed5bb786bbda2dee66a2d50faf51429dbc043a7b') end - it "retrieves revisions with arbitrary whitespace" do - file = " filename with a leading space.txt " + it 'retrieves revisions with arbitrary whitespace' do + file = ' filename with a leading space.txt ' rev = adapter.revisions(file, nil, nil, all: true) expect(rev.length).to eq(1) expect(rev[0].paths[0][:path]).to eq(file) end - it "shows all paths of a revision" do - rev = adapter.revisions("", "899a15d^", "899a15d")[0] + it 'shows all paths of a revision' do + rev = adapter.revisions('', '899a15d^', '899a15d')[0] expect(rev.paths.length).to eq(3) - expect(rev.paths[0]).to eq(action: "M", path: "README") - expect(rev.paths[1]).to eq(action: "A", path: "images/edit.png") - expect(rev.paths[2]).to eq(action: "A", path: "sources/welcome_controller.rb") + expect(rev.paths[0]).to eq(action: 'M', path: 'README') + expect(rev.paths[1]).to eq(action: 'A', path: 'images/edit.png') + expect(rev.paths[2]).to eq(action: 'A', path: 'sources/welcome_controller.rb') end end - describe ".entries" do - shared_examples "retrieve entries" do - it "retrieves entries from an identifier" do - entries = adapter.entries("", "83ca5fd") + describe '.entries' do + shared_examples 'retrieve entries' do + it 'retrieves entries from an identifier' do + entries = adapter.entries('', '83ca5fd') expect(entries.length).to eq(9) - expect(entries[0].name).to eq("images") - expect(entries[0].kind).to eq("dir") + expect(entries[0].name).to eq('images') + expect(entries[0].kind).to eq('dir') expect(entries[0].size).to be_nil expect(entries[0]).to be_dir expect(entries[0]).not_to be_file expect(entries[3]).to be_file expect(entries[3].size).to eq(56) - expect(entries[3].name).to eq(" filename with a leading space.txt ") + expect(entries[3].name).to eq(' filename with a leading space.txt ') end - it "has a related revision" do - entries = adapter.entries("", "83ca5fd") + it 'has a related revision' do + entries = adapter.entries('', '83ca5fd') rev = entries[0].lastrev - expect(rev.identifier).to eq("deff712f05a90d96edbd70facc47d944be5897e3") - expect(rev.author).to eq("Adam Soltys ") + expect(rev.identifier).to eq('deff712f05a90d96edbd70facc47d944be5897e3') + expect(rev.author).to eq('Adam Soltys ') rev = entries[3].lastrev - expect(rev.identifier).to eq("83ca5fd546063a3c7dc2e568ba3355661a9e2b2c") - expect(rev.author).to eq("Felix Schäfer ") + expect(rev.identifier).to eq('83ca5fd546063a3c7dc2e568ba3355661a9e2b2c') + expect(rev.author).to eq('Felix Schäfer ') end - it "can be retrieved by tag" do - entries = adapter.entries(nil, "tag01.annotated") + it 'can be retrieved by tag' do + entries = adapter.entries(nil, 'tag01.annotated') expect(entries.length).to eq(3) sources = entries[1] - expect(sources.name).to eq("sources") - expect(sources.path).to eq("sources") + expect(sources.name).to eq('sources') + expect(sources.path).to eq('sources') expect(sources).to be_dir readme = entries[2] - expect(readme.name).to eq("README") - expect(readme.path).to eq("README") + expect(readme.name).to eq('README') + expect(readme.path).to eq('README') expect(readme).to be_file expect(readme.size).to eq(27) - expect(readme.lastrev.identifier).to eq("899a15dba03a3b350b89c3f537e4bbe02a03cdc9") + expect(readme.lastrev.identifier).to eq('899a15dba03a3b350b89c3f537e4bbe02a03cdc9') expect(readme.lastrev.time).to eq(Time.gm(2007, 12, 14, 9, 24, 1)) end - it "can be retrieved by branch" do - entries = adapter.entries(nil, "test_branch") + it 'can be retrieved by branch' do + entries = adapter.entries(nil, 'test_branch') expect(entries.length).to eq(4) sources = entries[1] - expect(sources.name).to eq("sources") - expect(sources.path).to eq("sources") + expect(sources.name).to eq('sources') + expect(sources.path).to eq('sources') expect(sources).to be_dir readme = entries[2] - expect(readme.name).to eq("README") - expect(readme.path).to eq("README") + expect(readme.name).to eq('README') + expect(readme.path).to eq('README') expect(readme).to be_file expect(readme.size).to eq(159) - expect(readme.lastrev.identifier).to eq("713f4944648826f558cf548222f813dabe7cbb04") + expect(readme.lastrev.identifier).to eq('713f4944648826f558cf548222f813dabe7cbb04') expect(readme.lastrev.time).to eq(Time.gm(2009, 6, 19, 4, 37, 23)) end end - describe "encoding" do - let (:char1_hex) { "\xc3\x9c".force_encoding("UTF-8") } + describe 'encoding' do + let (:char1_hex) { "\xc3\x9c".force_encoding('UTF-8') } - context "with default encoding" do - it_behaves_like "retrieve entries" + context 'with default encoding' do + it_behaves_like 'retrieve entries' - it "can retrieve directories containing entries encoded in latin-1" do - entries = adapter.entries("latin-1-dir", "64f1f3e8") + it 'can retrieve directories containing entries encoded in latin-1' do + entries = adapter.entries('latin-1-dir', '64f1f3e8') f1 = entries[1] expect(f1.name).to eq("test-\xDC-2.txt") @@ -389,22 +389,22 @@ expect(f1).to be_file end - it "cannot retrieve files with latin-1 encoding in their path" do - entries = adapter.entries("latin-1-dir", "64f1f3e8") + it 'cannot retrieve files with latin-1 encoding in their path' do + entries = adapter.entries('latin-1-dir', '64f1f3e8') latin1_path = entries[1].path - expect { adapter.entries(latin1_path, "1ca7f5ed") } + expect { adapter.entries(latin1_path, '1ca7f5ed') } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) end end - context "with latin-1 encoding" do - let (:encoding) { "ISO-8859-1" } + context 'with latin-1 encoding' do + let (:encoding) { 'ISO-8859-1' } - it_behaves_like "retrieve entries" + it_behaves_like 'retrieve entries' - it "can be retrieved with latin-1 encoding" do - entries = adapter.entries("latin-1-dir", "64f1f3e8") + it 'can be retrieved with latin-1 encoding' do + entries = adapter.entries('latin-1-dir', '64f1f3e8') expect(entries.length).to eq(3) f1 = entries[1] @@ -413,9 +413,9 @@ expect(f1).to be_file end - it "can be retrieved with latin-1 directories" do + it 'can be retrieved with latin-1 directories' do entries = adapter.entries("latin-1-dir/test-#{char1_hex}-subdir", - "1ca7f5ed") + '1ca7f5ed') expect(entries.length).to eq(3) f1 = entries[1] @@ -427,72 +427,72 @@ end end - describe ".annotate" do - it "annotates a regular file" do - annotate = adapter.annotate("sources/watchers_controller.rb") + describe '.annotate' do + it 'annotates a regular file' do + annotate = adapter.annotate('sources/watchers_controller.rb') expect(annotate).to be_a(OpenProject::SCM::Adapters::Annotate) expect(annotate.lines.length).to eq(41) - expect(annotate.lines[4].strip).to eq("# This program is free software; " \ - "you can redistribute it and/or") - expect(annotate.revisions[4].identifier).to eq("7234cb2750b63f47bff735edc50a1c0a433c2518") - expect(annotate.revisions[4].author).to eq("jsmith") + expect(annotate.lines[4].strip).to eq('# This program is free software; ' \ + 'you can redistribute it and/or') + expect(annotate.revisions[4].identifier).to eq('7234cb2750b63f47bff735edc50a1c0a433c2518') + expect(annotate.revisions[4].author).to eq('jsmith') end - it "annotates moved file" do - annotate = adapter.annotate("renamed_test.txt") + it 'annotates moved file' do + annotate = adapter.annotate('renamed_test.txt') expect(annotate.lines.length).to eq(2) expect(annotate.content).to eq("This is a test\nLet's pretend I'm adding a new feature!") - expect(annotate.lines).to contain_exactly("This is a test", "Let's pretend I'm adding a new feature!") + expect(annotate.lines).to contain_exactly('This is a test', "Let's pretend I'm adding a new feature!") expect(annotate.revisions.length).to eq(2) - expect(annotate.revisions[0].identifier).to eq("fba357b886984ee71185ad2065e65fc0417d9b92") - expect(annotate.revisions[1].identifier).to eq("7e61ac704deecde634b51e59daa8110435dcb3da") + expect(annotate.revisions[0].identifier).to eq('fba357b886984ee71185ad2065e65fc0417d9b92') + expect(annotate.revisions[1].identifier).to eq('7e61ac704deecde634b51e59daa8110435dcb3da') end - it "annotates with identifier" do - annotate = adapter.annotate("README", "HEAD~10") + it 'annotates with identifier' do + annotate = adapter.annotate('README', 'HEAD~10') expect(annotate.lines.length).to eq(1) expect(annotate.empty?).to be false expect(annotate.content).to eq("Mercurial test repository\r") expect(annotate.revisions.length).to eq(1) - expect(annotate.revisions[0].identifier).to eq("899a15dba03a3b350b89c3f537e4bbe02a03cdc9") - expect(annotate.revisions[0].author).to eq("jsmith") + expect(annotate.revisions[0].identifier).to eq('899a15dba03a3b350b89c3f537e4bbe02a03cdc9') + expect(annotate.revisions[0].author).to eq('jsmith') end - it "raises for an invalid path" do - expect { adapter.annotate("does_not_exist.txt") } + it 'raises for an invalid path' do + expect { adapter.annotate('does_not_exist.txt') } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) - expect { adapter.annotate("/path/outside/repository") } + expect { adapter.annotate('/path/outside/repository') } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) end - it "returns nil for binary path" do - expect(adapter.annotate("images/edit.png")).to be_nil + it 'returns nil for binary path' do + expect(adapter.annotate('images/edit.png')).to be_nil end # We should rethink the output of annotated files for these formats. - it "also returns nil for UTF-16 encoded file" do - expect(adapter.annotate("utf16.txt")).to be_nil + it 'also returns nil for UTF-16 encoded file' do + expect(adapter.annotate('utf16.txt')).to be_nil end end - describe ".cat" do - it "outputs the given file" do - out = adapter.cat("README") - expect(out).to include("Git test repository") + describe '.cat' do + it 'outputs the given file' do + out = adapter.cat('README') + expect(out).to include('Git test repository') end - it "raises an exception for an invalid file" do - expect { adapter.cat("doesnotexiss") } + it 'raises an exception for an invalid file' do + expect { adapter.cat('doesnotexiss') } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) end end - describe ".diff" do - it "provides a full diff of the last commit by default" do - diff = adapter.diff("", "HEAD").map(&:chomp) - expect(diff[0]).to eq("commit 71e5c1d3dca6304805b143b9d0e6695fb3895ea4") + describe '.diff' do + it 'provides a full diff of the last commit by default' do + diff = adapter.diff('', 'HEAD').map(&:chomp) + expect(diff[0]).to eq('commit 71e5c1d3dca6304805b143b9d0e6695fb3895ea4') bare = "Author: Oliver G\xFCnther " cloned = "Author: Oliver Günther " @@ -503,19 +503,19 @@ expect(diff[1] == bare || diff[1] == cloned).to be true end - it "provides a negative diff" do - diff = adapter.diff("", "HEAD~2", "HEAD~1").map(&:chomp) - expect(diff.join("\n")).to include("-And this is a file") + it 'provides a negative diff' do + diff = adapter.diff('', 'HEAD~2', 'HEAD~1').map(&:chomp) + expect(diff.join("\n")).to include('-And this is a file') end - it "provides the complete for the given range" do - diff = adapter.diff("", "61b685f", "2f9c009").map(&:chomp) - expect(diff[1]).to eq("index 6cbd30c..b94e68e 100644") - expect(diff[10]).to eq("index 4eca635..9a541fe 100644") + it 'provides the complete for the given range' do + diff = adapter.diff('', '61b685f', '2f9c009').map(&:chomp) + expect(diff[1]).to eq('index 6cbd30c..b94e68e 100644') + expect(diff[10]).to eq('index 4eca635..9a541fe 100644') end - it "provides the selected diff for the given range" do - diff = adapter.diff("README", "61b685f", "2f9c009").map(&:chomp) + it 'provides the selected diff for the given range' do + diff = adapter.diff('README', '61b685f', '2f9c009').map(&:chomp) expect(diff).to eq(<<~DIFF.split("\n")) diff --git a/README b/README index 6cbd30c..b94e68e 100644 @@ -534,11 +534,11 @@ end context "with a local repository" do - it_behaves_like "git adapter specs" + it_behaves_like 'git adapter specs' end context "with a remote repository" do - it_behaves_like "git adapter specs" do + it_behaves_like 'git adapter specs' do let(:protocol) { "file://" } # make it remote by using a protocol end end diff --git a/spec/lib/open_project/scm/adapters/subversion_adapter_spec.rb b/spec/lib/open_project/scm/adapters/subversion_adapter_spec.rb index 5989f544d43d..2268501d158f 100644 --- a/spec/lib/open_project/scm/adapters/subversion_adapter_spec.rb +++ b/spec/lib/open_project/scm/adapters/subversion_adapter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::SCM::Adapters::Subversion do - let(:root_url) { "/tmp/bar.svn" } + let(:root_url) { '/tmp/bar.svn' } let(:url) { "file://#{root_url}" } let(:config) { {} } let(:adapter) { OpenProject::SCM::Adapters::Subversion.new url, root_url } @@ -38,47 +38,47 @@ allow(adapter.class).to receive(:config).and_return(config) end - describe "client information" do - it "sets the Subversion client command" do - expect(adapter.client_command).to eq("svn") + describe 'client information' do + it 'sets the Subversion client command' do + expect(adapter.client_command).to eq('svn') end - context "with client command from config" do - let(:config) { { client_command: "/usr/local/bin/svn" } } + context 'with client command from config' do + let(:config) { { client_command: '/usr/local/bin/svn' } } - it "overrides the Subversion client command from config" do - expect(adapter.client_command).to eq("/usr/local/bin/svn") + it 'overrides the Subversion client command from config' do + expect(adapter.client_command).to eq('/usr/local/bin/svn') end end - shared_examples "correct client version" do |svn_string, expected_version| - it "sets the correct client version" do + shared_examples 'correct client version' do |svn_string, expected_version| + it 'sets the correct client version' do expect(adapter) .to receive(:scm_version_from_command_line) .and_return(svn_string) expect(adapter.client_version).to eq(expected_version) expect(adapter.client_available).to be true - expect(adapter.client_version_string).to eq(expected_version.join(".")) + expect(adapter.client_version_string).to eq(expected_version.join('.')) end end - it_behaves_like "correct client version", "svn, version 1.6.13 (r1002816)\n", [1, 6, 13] - it_behaves_like "correct client version", "svn, versione 1.6.13 (r1002816)\n", [1, 6, 13] - it_behaves_like "correct client version", "1.6.1\n1.7\n1.8", [1, 6, 1] - it_behaves_like "correct client version", "1.6.2\r\n1.8.1\r\n1.9.1", [1, 6, 2] + it_behaves_like 'correct client version', "svn, version 1.6.13 (r1002816)\n", [1, 6, 13] + it_behaves_like 'correct client version', "svn, versione 1.6.13 (r1002816)\n", [1, 6, 13] + it_behaves_like 'correct client version', "1.6.1\n1.7\n1.8", [1, 6, 1] + it_behaves_like 'correct client version', "1.6.2\r\n1.8.1\r\n1.9.1", [1, 6, 2] end - describe "invalid repository" do - describe ".check_availability!", skip_if_command_unavailable: "svnadmin" do - it "is not available" do + describe 'invalid repository' do + describe '.check_availability!', skip_if_command_unavailable: 'svnadmin' do + it 'is not available' do expect(Dir.exist?(url)).to be false expect(adapter).not_to be_available expect { adapter.check_availability! } .to raise_error(OpenProject::SCM::Exceptions::SCMUnavailable) end - it "raises a meaningful error if shell output fails" do + it 'raises a meaningful error if shell output fails' do error_string = <<~ERR svn: E215004: Authentication failed and interactive prompting is disabled; see the --force-interactive option svn: E215004: Unable to connect to a repository at URL 'file:///tmp/bar.svn' @@ -87,7 +87,7 @@ ERR allow(adapter).to receive(:popen3) - .and_yield(StringIO.new(""), StringIO.new(error_string)) + .and_yield(StringIO.new(''), StringIO.new(error_string)) expect { adapter.check_availability! } .to raise_error(OpenProject::SCM::Exceptions::SCMUnauthorized) @@ -95,44 +95,44 @@ end end - describe "repository with authorization" do + describe 'repository with authorization' do let(:adapter) { OpenProject::SCM::Adapters::Subversion.new url, root_url, login, password } - let(:login) { "whatever@example.org" } - let(:svn_cmd) { adapter.send :build_svn_cmd, ["info"] } + let(:login) { 'whatever@example.org' } + let(:svn_cmd) { adapter.send :build_svn_cmd, ['info'] } - context "without password" do + context 'without password' do let(:password) { nil } - it "creates the subversion command" do - idx = svn_cmd.index("--username") + it 'creates the subversion command' do + idx = svn_cmd.index('--username') expect(idx).not_to be_nil expect(svn_cmd[idx + 1]).to eq(login) - expect(svn_cmd).not_to include("--password") + expect(svn_cmd).not_to include('--password') end end - context "with password" do + context 'with password' do let(:password) { 'VG%\';rm -rf /;},Y^m\+DuE,vJP/9' } - it "creates the subversion command" do - idx = svn_cmd.index("--username") + it 'creates the subversion command' do + idx = svn_cmd.index('--username') expect(idx).not_to be_nil expect(svn_cmd[idx + 1]).to eq(login) - idx = svn_cmd.index("--password") + idx = svn_cmd.index('--password') expect(idx).not_to be_nil expect(password) end end end - describe "empty repository" do - include_context "with tmpdir" + describe 'empty repository' do + include_context 'with tmpdir' let(:root_url) { tmpdir } - describe ".create_empty_svn", skip_if_command_unavailable: "svnadmin" do - context "with valid root_url" do - it "creates the repository" do + describe '.create_empty_svn', skip_if_command_unavailable: 'svnadmin' do + context 'with valid root_url' do + it 'creates the repository' do expect(Dir.exist?(root_url)).to be true expect(Dir.entries(root_url).length).to eq 2 expect { adapter.create_empty_svn }.not_to raise_error @@ -142,10 +142,10 @@ end end - context "with non-existing root_url" do - let(:root_url) { File.join(tmpdir, "foo", "bar") } + context 'with non-existing root_url' do + let(:root_url) { File.join(tmpdir, 'foo', 'bar') } - it "fails" do + it 'fails' do expect { adapter.create_empty_svn } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) @@ -154,8 +154,8 @@ end end - describe ".check_availability!", skip_if_command_unavailable: "svnadmin" do - it "is marked empty" do + describe '.check_availability!', skip_if_command_unavailable: 'svnadmin' do + it 'is marked empty' do adapter.create_empty_svn expect { adapter.check_availability! } .to raise_error(OpenProject::SCM::Exceptions::SCMEmpty) @@ -163,131 +163,131 @@ end end - describe "local repository" do + describe 'local repository' do with_subversion_repository do |repo_dir| let(:root_url) { repo_dir } - it "reads the Subversion version" do + it 'reads the Subversion version' do expect(adapter.client_version.length).to be >= 3 end - it "is a valid repository" do + it 'is a valid repository' do expect(Dir.exist?(repo_dir)).to be true - out, process = Open3.capture2e("svn", "info", url) + out, process = Open3.capture2e('svn', 'info', url) expect(process.exitstatus).to eq(0) - expect(out).to include("Repository UUID") + expect(out).to include('Repository UUID') end - it "is available" do + it 'is available' do expect(adapter).to be_available expect { adapter.check_availability! }.not_to raise_error end - describe ".info" do - it "builds the info object" do + describe '.info' do + it 'builds the info object' do info = adapter.info expect(info.root_url).to eq(url) - expect(info.lastrev.identifier).to eq("14") - expect(info.lastrev.author).to eq("mkahl") - expect(info.lastrev.time.getlocal("+01:00").strftime("%FT%T%:z")).to eq("2017-05-04T14:26:53+01:00") + expect(info.lastrev.identifier).to eq('14') + expect(info.lastrev.author).to eq('mkahl') + expect(info.lastrev.time.getlocal("+01:00").strftime("%FT%T%:z")).to eq('2017-05-04T14:26:53+01:00') end end - describe ".entries" do - it "reads all entries from the current revision" do + describe '.entries' do + it 'reads all entries from the current revision' do entries = adapter.entries expect(entries.length).to eq(10) - expect(entries[0].name).to eq("Föbar") - expect(entries[0].path).to eq("Föbar") - expect(entries[1].name).to eq("folder_a") - expect(entries[1].path).to eq("folder_a") + expect(entries[0].name).to eq('Föbar') + expect(entries[0].path).to eq('Föbar') + expect(entries[1].name).to eq('folder_a') + expect(entries[1].path).to eq('folder_a') end - it "contains a reference to the last revision" do + it 'contains a reference to the last revision' do entries = adapter.entries expect(entries.length).to eq(10) lastrev = entries[0].lastrev - expect(lastrev.identifier).to eq("13") - expect(lastrev.author).to eq("oliver") - expect(lastrev.message).to eq("") - expect(lastrev.time.getlocal("+01:00").strftime("%FT%T%:z")).to eq("2016-04-14T20:23:01+01:00") + expect(lastrev.identifier).to eq('13') + expect(lastrev.author).to eq('oliver') + expect(lastrev.message).to eq('') + expect(lastrev.time.getlocal("+01:00").strftime("%FT%T%:z")).to eq('2016-04-14T20:23:01+01:00') end - it "reads all entries from the given revision" do + it 'reads all entries from the given revision' do entries = adapter.entries(nil, 1) expect(entries.length).to eq(1) lastrev = entries[0].lastrev - expect(lastrev.identifier).to eq("1") - expect(lastrev.author).to eq("jp") - expect(lastrev.message).to eq("") - expect(lastrev.time).to eq("2007-09-10T16:54:38.484000Z") + expect(lastrev.identifier).to eq('1') + expect(lastrev.author).to eq('jp') + expect(lastrev.message).to eq('') + expect(lastrev.time).to eq('2007-09-10T16:54:38.484000Z') end - it "reads all entries from the given path" do - entries = adapter.entries("subversion_test") + it 'reads all entries from the given path' do + entries = adapter.entries('subversion_test') expect(entries.length).to eq(5) - expect(entries[0].name).to eq("[folder_with_brackets]") - expect(entries[0].path).to eq("subversion_test/[folder_with_brackets]") + expect(entries[0].name).to eq('[folder_with_brackets]') + expect(entries[0].path).to eq('subversion_test/[folder_with_brackets]') expect(entries[0]).to be_dir expect(entries[0]).not_to be_file expect(entries[0].size).to be_nil - expect(entries[1].name).to eq("folder") - expect(entries[1].path).to eq("subversion_test/folder") + expect(entries[1].name).to eq('folder') + expect(entries[1].path).to eq('subversion_test/folder') expect(entries[1]).to be_dir expect(entries[1]).not_to be_file expect(entries[1].size).to be_nil - expect(entries[4].name).to eq("textfile.txt") - expect(entries[4].path).to eq("subversion_test/textfile.txt") + expect(entries[4].name).to eq('textfile.txt') + expect(entries[4].path).to eq('subversion_test/textfile.txt') expect(entries[4]).not_to be_dir expect(entries[4]).to be_file expect(entries[4]).not_to be_dir expect(entries[4].size).to eq(756) end - it "reads all entries from the given path and revision" do - entries = adapter.entries("subversion_test", "2") + it 'reads all entries from the given path and revision' do + entries = adapter.entries('subversion_test', '2') expect(entries.length).to eq(4) - expect(entries[0].name).to eq("folder") - expect(entries[0].path).to eq("subversion_test/folder") + expect(entries[0].name).to eq('folder') + expect(entries[0].path).to eq('subversion_test/folder') - expect(entries[1].name).to eq(".project") - expect(entries[1].path).to eq("subversion_test/.project") + expect(entries[1].name).to eq('.project') + expect(entries[1].path).to eq('subversion_test/.project') - expect(entries[2].name).to eq("helloworld.rb") - expect(entries[2].path).to eq("subversion_test/helloworld.rb") + expect(entries[2].name).to eq('helloworld.rb') + expect(entries[2].path).to eq('subversion_test/helloworld.rb') - expect(entries[3].name).to eq("textfile.txt") - expect(entries[3].path).to eq("subversion_test/textfile.txt") + expect(entries[3].name).to eq('textfile.txt') + expect(entries[3].path).to eq('subversion_test/textfile.txt') end end - describe ".properties" do - it "returns an empty hash for no properties" do - expect(adapter.properties("")).to eq({}) + describe '.properties' do + it 'returns an empty hash for no properties' do + expect(adapter.properties('')).to eq({}) end - it "returns the properties when available" do - expect(adapter.properties("subversion_test")).to eq("svn:ignore" => "foo\nbar/\n") + it 'returns the properties when available' do + expect(adapter.properties('subversion_test')).to eq('svn:ignore' => "foo\nbar/\n") end - it "does not return the properties from an older revision on the same path" do - expect(adapter.properties("subversion_test", 11)).to eq({}) + it 'does not return the properties from an older revision on the same path' do + expect(adapter.properties('subversion_test', 11)).to eq({}) end end - describe ".revisions" do - it "returns all revisions by default" do + describe '.revisions' do + it 'returns all revisions by default' do revisions = adapter.revisions expect(revisions.length).to eq(14) - expect(revisions[0].author).to eq("mkahl") + expect(revisions[0].author).to eq('mkahl') expect(revisions[0].message.strip).to eq("added some more files to work with") revisions.each_with_index do |rev, i| @@ -295,98 +295,98 @@ end end - it "returns revisions for a specific path" do - revisions = adapter.revisions("subversion_test/[folder_with_brackets]", nil, nil, + it 'returns revisions for a specific path' do + revisions = adapter.revisions('subversion_test/[folder_with_brackets]', nil, nil, with_paths: true) expect(revisions.length).to eq(1) - expect(revisions[0].identifier).to eq("11") - expect(revisions[0].format_identifier).to eq("11") + expect(revisions[0].identifier).to eq('11') + expect(revisions[0].format_identifier).to eq('11') paths = revisions[0].paths expect(paths.length).to eq(2) - expect(paths[0]).to eq(action: "A", path: "/subversion_test/[folder_with_brackets]", + expect(paths[0]).to eq(action: 'A', path: '/subversion_test/[folder_with_brackets]', from_path: nil, from_revision: nil) end - it "returns revision for a specific path and revision" do + it 'returns revision for a specific path and revision' do # Folder was added in rev 2 - expect { adapter.revisions("subversion_test/folder", 1) } + expect { adapter.revisions('subversion_test/folder', 1) } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) - revisions = adapter.revisions("subversion_test/folder", 2, nil, + revisions = adapter.revisions('subversion_test/folder', 2, nil, with_paths: true) expect(revisions.length).to eq(1) - expect(revisions[0].identifier).to eq("2") + expect(revisions[0].identifier).to eq('2') paths = revisions[0].paths expect(paths.length).to eq(7) end - it "returns revision for a specific range" do - revisions = adapter.revisions("subversion_test/folder", 2, 5, + it 'returns revision for a specific range' do + revisions = adapter.revisions('subversion_test/folder', 2, 5, with_paths: true) expect(revisions.length).to eq(2) - expect(revisions[0].identifier).to eq("2") - expect(revisions[0].message).to eq("Initial import.") - expect(revisions[1].identifier).to eq("5") - expect(revisions[1].message).to eq("Modified one file in the folder.") + expect(revisions[0].identifier).to eq('2') + expect(revisions[0].message).to eq('Initial import.') + expect(revisions[1].identifier).to eq('5') + expect(revisions[1].message).to eq('Modified one file in the folder.') expect(revisions[0].paths.length).to eq(7) expect(revisions[1].paths.length).to eq(1) end end - describe ".blame" do - it "blames an existing file at the given path" do - annotate = adapter.annotate("subversion_test/[folder_with_brackets]/README.txt") + describe '.blame' do + it 'blames an existing file at the given path' do + annotate = adapter.annotate('subversion_test/[folder_with_brackets]/README.txt') expect(annotate.lines.length).to eq(2) expect(annotate.revisions.length).to eq(2) - expect(annotate.revisions[0].identifier).to eq("11") - expect(annotate.revisions[0].author).to eq("schmidt") + expect(annotate.revisions[0].identifier).to eq('11') + expect(annotate.revisions[0].author).to eq('schmidt') end - it "outputs nothing for an invalid blame target" do - annotate = adapter.annotate("subversion_test/[folder_with_brackets]/README.txt", 10) + it 'outputs nothing for an invalid blame target' do + annotate = adapter.annotate('subversion_test/[folder_with_brackets]/README.txt', 10) expect(annotate.lines.length).to eq(0) expect(annotate.revisions.length).to eq(0) end end - describe ".cat" do - it "outputs the given file" do - out = adapter.cat("subversion_test/[folder_with_brackets]/README.txt", 11) - expect(out).to eq("This file should be accessible for Redmine, " \ + describe '.cat' do + it 'outputs the given file' do + out = adapter.cat('subversion_test/[folder_with_brackets]/README.txt', 11) + expect(out).to eq('This file should be accessible for Redmine, ' \ "although its folder contains square\nbrackets.\n") end - it "raises an exception for an invalid file" do - expect { adapter.cat("subversion_test/[folder_with_brackets]/README.txt", 10) } + it 'raises an exception for an invalid file' do + expect { adapter.cat('subversion_test/[folder_with_brackets]/README.txt', 10) } .to raise_error(OpenProject::SCM::Exceptions::CommandFailed) end end - describe ".diff" do - it "provides a full diff against the last revision" do - diff = adapter.diff("", 12).map(&:chomp) - expect(diff.join("\n")).to include("Added: svn:ignore") + describe '.diff' do + it 'provides a full diff against the last revision' do + diff = adapter.diff('', 12).map(&:chomp) + expect(diff.join("\n")).to include('Added: svn:ignore') end - it "provides a negative diff" do - diff = adapter.diff("", 11, 12).map(&:chomp) - expect(diff.join("\n")).to include("Deleted: svn:ignore") + it 'provides a negative diff' do + diff = adapter.diff('', 11, 12).map(&:chomp) + expect(diff.join("\n")).to include('Deleted: svn:ignore') end - it "provides the complete for the given range" do - diff = adapter.diff("", 8, 6).map(&:chomp).join("\n") - expect(diff).to include("Index: subversion_test/folder/greeter.rb") - expect(diff).to include("Index: subversion_test/helloworld.c") + it 'provides the complete for the given range' do + diff = adapter.diff('', 8, 6).map(&:chomp).join("\n") + expect(diff).to include('Index: subversion_test/folder/greeter.rb') + expect(diff).to include('Index: subversion_test/helloworld.c') end - it "provides the selected diff for the given range" do - diff = adapter.diff("subversion_test/helloworld.c", 8, 6).map(&:chomp) + it 'provides the selected diff for the given range' do + diff = adapter.diff('subversion_test/helloworld.c', 8, 6).map(&:chomp) expect(diff).to eq(<<~DIFF.split("\n")) Index: helloworld.c =================================================================== diff --git a/spec/lib/open_project/scm/manager_spec.rb b/spec/lib/open_project/scm/manager_spec.rb index 517510944878..a7291522f9e3 100644 --- a/spec/lib/open_project/scm/manager_spec.rb +++ b/spec/lib/open_project/scm/manager_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::SCM::Manager do - let(:vendor) { "TestScm" } + let(:vendor) { 'TestScm' } let(:scm_class) { Class.new } before do @@ -42,12 +42,12 @@ OpenProject::SCM::Manager.delete :test_scm end - it "is a valid const" do + it 'is a valid const' do expect(OpenProject::SCM::Manager.registered[:test_scm]).to eq(Repository::TestScm) end - context "scm is not known" do - it "is not included" do + context 'scm is not known' do + it 'is not included' do expect(OpenProject::SCM::Manager.registered).not_to have_key(:some_scm) end end diff --git a/spec/lib/open_project/static_routing_spec.rb b/spec/lib/open_project/static_routing_spec.rb index dfcfec9b5582..42c8f515bc2f 100644 --- a/spec/lib/open_project/static_routing_spec.rb +++ b/spec/lib/open_project/static_routing_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::StaticRouting do - describe ".recognize_route" do + describe '.recognize_route' do subject { described_class.recognize_route path } - context "with no relative URL root", with_config: { rails_relative_url_root: nil } do - let(:path) { "/news/1" } + context 'with no relative URL root', with_config: { rails_relative_url_root: nil } do + let(:path) { '/news/1' } - it "detects the route" do + it 'detects the route' do expect(subject).to be_present expect(subject[:controller]).to be_present end end - context "with a relative URL root", with_config: { rails_relative_url_root: "/foobar" } do - let(:path) { "/foobar/news/1" } + context 'with a relative URL root', with_config: { rails_relative_url_root: '/foobar' } do + let(:path) { '/foobar/news/1' } - it "detects the route" do + it 'detects the route' do expect(subject).to be_present expect(subject[:controller]).to be_present end diff --git a/spec/lib/open_project/storage_spec.rb b/spec/lib/open_project/storage_spec.rb index bd9ac2a1b2da..36078d744044 100644 --- a/spec/lib/open_project/storage_spec.rb +++ b/spec/lib/open_project/storage_spec.rb @@ -26,58 +26,58 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OpenProject::Storage do before do allow(Setting).to receive(:enabled_scm).and_return(enabled_scms) allow(OpenProject::Configuration).to receive(:[]).and_call_original - allow(OpenProject::Configuration).to receive(:[]).with("scm").and_return(config) + allow(OpenProject::Configuration).to receive(:[]).with('scm').and_return(config) end - context "with no SCM configuration" do + context 'with no SCM configuration' do let(:config) { {} } let(:enabled_scms) { [] } - describe "#known_storage_paths" do + describe '#known_storage_paths' do subject { OpenProject::Storage.known_storage_paths } - it "contains attachments path" do + it 'contains attachments path' do expect(subject.length).to eq 1 expect(subject[:attachments]) - .to eq(label: I18n.t("attributes.attachments"), + .to eq(label: I18n.t('attributes.attachments'), path: OpenProject::Configuration.attachments_storage_path.to_s) end end - describe "#mount_information" do + describe '#mount_information' do subject { OpenProject::Storage.mount_information } - include_context "with tmpdir" + include_context 'with tmpdir' before do allow(OpenProject::Storage).to receive(:known_storage_paths) - .and_return(foobar: { path: tmpdir, label: "this is foobar" }) + .and_return(foobar: { path: tmpdir, label: 'this is foobar' }) end - it "contains one fs entry" do + it 'contains one fs entry' do expect(File.exist?(tmpdir)).to be true expect(subject.length).to eq 1 entry = subject.values.first - expect(entry[:labels]).to eq(["this is foobar"]) + expect(entry[:labels]).to eq(['this is foobar']) expect(entry[:data]).not_to be_nil expect(entry[:data][:free]).to be_a(Integer) end end end - context "with SCM configuration" do - include_context "with tmpdir" + context 'with SCM configuration' do + include_context 'with tmpdir' let(:config) do { - git: { manages: File.join(tmpdir, "git") } + git: { manages: File.join(tmpdir, 'git') } } end let(:enabled_scms) { %w[git] } @@ -88,38 +88,38 @@ allow(OpenProject::Storage).to receive(:read_fs_info).and_return(*returned_fs_info) end - describe "#known_storage_paths" do + describe '#known_storage_paths' do subject { OpenProject::Storage.known_storage_paths } - it "contains both paths" do + it 'contains both paths' do expect(subject.length).to eq 2 labels = subject.values.pluck(:label) expect(labels) - .to contain_exactly(I18n.t(:label_managed_repositories_vendor, vendor: "Git"), I18n.t("attributes.attachments")) + .to contain_exactly(I18n.t(:label_managed_repositories_vendor, vendor: 'Git'), I18n.t('attributes.attachments')) end end - describe "#mount_information" do + describe '#mount_information' do subject { OpenProject::Storage.mount_information } - it "contains one entry" do + it 'contains one entry' do expect(subject.length).to eq(1) entry = subject.values.first expect(entry[:labels]) - .to contain_exactly(I18n.t(:label_managed_repositories_vendor, vendor: "Git"), I18n.t("attributes.attachments")) + .to contain_exactly(I18n.t(:label_managed_repositories_vendor, vendor: 'Git'), I18n.t('attributes.attachments')) end - context "with multiple filesystem ids" do + context 'with multiple filesystem ids' do let(:returned_fs_info) { [{ id: 1, free: 1234 }, { id: 2, free: 15 }] } - it "contains two entries" do + it 'contains two entries' do expect(subject.length).to eq(2) expect(subject) - .to eq(1 => { labels: [I18n.t(:label_managed_repositories_vendor, vendor: "Git")], + .to eq(1 => { labels: [I18n.t(:label_managed_repositories_vendor, vendor: 'Git')], data: returned_fs_info[0] }, - 2 => { labels: [I18n.t("attributes.attachments")], + 2 => { labels: [I18n.t('attributes.attachments')], data: returned_fs_info[1] }) end end diff --git a/spec/lib/open_project/text_formatting/markdown/attribute_macros_spec.rb b/spec/lib/open_project/text_formatting/markdown/attribute_macros_spec.rb index fe95ba1be738..57ddb87155c1 100644 --- a/spec/lib/open_project/text_formatting/markdown/attribute_macros_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/attribute_macros_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting, - "Attribute macros" do - include_context "expected markdown modules" + 'Attribute macros' do + include_context 'expected markdown modules' - describe "attribute label macros" do - it_behaves_like "format_text produces" do + describe 'attribute label macros' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW # My headline @@ -72,8 +72,8 @@ end end - describe "attribute value macros" do - it_behaves_like "format_text produces" do + describe 'attribute value macros' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW # My headline diff --git a/spec/lib/open_project/text_formatting/markdown/blockquote_spec.rb b/spec/lib/open_project/text_formatting/markdown/blockquote_spec.rb index 62f740f4708a..f06033358b66 100644 --- a/spec/lib/open_project/text_formatting/markdown/blockquote_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/blockquote_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting, - "blockquote" do - include_context "expected markdown modules" + 'blockquote' do + include_context 'expected markdown modules' - it_behaves_like "format_text produces" do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW John said: diff --git a/spec/lib/open_project/text_formatting/markdown/child_pages_macro_spec.rb b/spec/lib/open_project/text_formatting/markdown/child_pages_macro_spec.rb index 5524c83cfce7..2b00a19dfbd1 100644 --- a/spec/lib/open_project/text_formatting/markdown/child_pages_macro_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/child_pages_macro_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "OpenProject child pages macro" do +RSpec.describe 'OpenProject child pages macro' do include ActionView::Helpers::UrlHelper include OpenProject::StaticRouting::UrlHelpers include OpenProject::TextFormatting @@ -44,12 +44,12 @@ def controller let(:input) {} let(:member_project) do create(:valid_project, - identifier: "member-project", + identifier: 'member-project', enabled_module_names: %w[wiki]) end let(:invisible_project) do create(:valid_project, - identifier: "other-project", + identifier: 'other-project', enabled_module_names: %w[wiki]) end let(:role) { create(:project_role, permissions: [:view_wiki_pages]) } @@ -59,47 +59,47 @@ def controller let(:current_page) do create(:wiki_page, - title: "Current page", + title: 'Current page', wiki: project.wiki, text: input) end let(:middle_page) do create(:wiki_page, - title: "Node from same project", + title: 'Node from same project', wiki: project.wiki, parent_id: current_page.id, - text: "# Node Page from same project") + text: '# Node Page from same project') end let(:node_page_invisible_project) do create(:wiki_page, - title: "Node page from invisible project", + title: 'Node page from invisible project', wiki: invisible_project.wiki, - text: "# Page from invisible project") + text: '# Page from invisible project') end let(:leaf_page) do create(:wiki_page, - title: "Leaf page from same project", + title: 'Leaf page from same project', parent_id: middle_page.id, wiki: project.wiki, - text: "# Leaf page from same project") + text: '# Leaf page from same project') end let(:leaf_page_invisible_project) do create(:wiki_page, - title: "Leaf page from invisible project", + title: 'Leaf page from invisible project', parent_id: node_page_invisible_project.id, wiki: invisible_project.wiki, - text: "# Leaf page from invisible project") + text: '# Leaf page from invisible project') end let(:leaf_page_member_project) do create(:wiki_page, - title: "Leaf page from member project", + title: 'Leaf page from member project', wiki: member_project.wiki, - text: "# Leaf page from member project") + text: '# Leaf page from member project') end subject { format_text(current_page, :text) } @@ -108,7 +108,7 @@ def controller login_as user leaf_page leaf_page_invisible_project - allow(Setting).to receive(:text_formatting).and_return("markdown") + allow(Setting).to receive(:text_formatting).and_return('markdown') end def error_html(exception_msg) @@ -116,29 +116,29 @@ def error_html(exception_msg) "Error executing the macro child_pages (#{exception_msg})

    " end - context "with invalid page" do + context 'with invalid page' do let(:input) { '' } it { is_expected.to be_html_eql(error_html("Cannot find the wiki page 'Invalid'.")) } end - context "old macro syntax no longer works" do - let(:input) { "{{child_pages(whatever)}}" } + context 'old macro syntax no longer works' do + let(:input) { '{{child_pages(whatever)}}' } it { is_expected.to be_html_eql("

    #{input}

    ") } end - context "when nothing passed" do + context 'when nothing passed' do let(:input) { '' } it { is_expected.not_to match(current_page.title) } it { is_expected.to match(middle_page.title) } it { is_expected.to match(leaf_page.title) } # Check accessibility - it { is_expected.to include("hidden-for-sighted", "tabindex", "Expanded. Click to collapse") } + it { is_expected.to include('hidden-for-sighted', 'tabindex', 'Expanded. Click to collapse') } end - context "when only include_parent passed" do + context 'when only include_parent passed' do let(:input) { '' } it { is_expected.to match(current_page.title) } @@ -146,7 +146,7 @@ def error_html(exception_msg) it { is_expected.to match(leaf_page.title) } end - context "when page title from same project passed" do + context 'when page title from same project passed' do let(:input) { '' } it { is_expected.not_to match(current_page.title) } @@ -154,7 +154,7 @@ def error_html(exception_msg) it { is_expected.to match(leaf_page.title) } end - context "when page slug from same project passed" do + context 'when page slug from same project passed' do let(:input) { '' } it { is_expected.not_to match(current_page.title) } @@ -162,7 +162,7 @@ def error_html(exception_msg) it { is_expected.to match(leaf_page.title) } end - context "when page title from same project with include_parent passed" do + context 'when page title from same project with include_parent passed' do let(:input) { '' } it { is_expected.not_to match(current_page.title) } @@ -170,13 +170,13 @@ def error_html(exception_msg) it { is_expected.to match(leaf_page.title) } end - context "when page slug from invisible project passed" do + context 'when page slug from invisible project passed' do let(:input) { '' } it { is_expected.to be_html_eql(error_html("Cannot find the wiki page 'other-project:leaf-page-from-other-project'.")) } end - context "when referencing page from a member project" do + context 'when referencing page from a member project' do let(:input) do '' end diff --git a/spec/lib/open_project/text_formatting/markdown/code_spec.rb b/spec/lib/open_project/text_formatting/markdown/code_spec.rb index cf4cd98c2f11..d5a1da389cd1 100644 --- a/spec/lib/open_project/text_formatting/markdown/code_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/code_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting, - "code" do - include_context "expected markdown modules" + 'code' do + include_context 'expected markdown modules' - context "inline code" do - it_behaves_like "format_text produces" do + context 'inline code' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW this is `some code` @@ -50,7 +50,7 @@ end end - it_behaves_like "format_text produces" do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW this is `` some code @@ -67,8 +67,8 @@ end end - context "block code" do - it_behaves_like "format_text produces" do + context 'block code' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW Text before @@ -99,8 +99,8 @@ end end - context "code block with language specified" do - it_behaves_like "format_text produces" do + context 'code block with language specified' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW Text before @@ -135,8 +135,8 @@ def foobar end end - context "blubs" do - it_behaves_like "format_text produces" do + context 'blubs' do + it_behaves_like 'format_text produces' do let(:raw) do "\n\n git clone git@github.com:opf/openproject.git\n\n" end diff --git a/spec/lib/open_project/text_formatting/markdown/embedded_table_macro_spec.rb b/spec/lib/open_project/text_formatting/markdown/embedded_table_macro_spec.rb index 14e3c0a71bfc..881c5ea65e0e 100644 --- a/spec/lib/open_project/text_formatting/markdown/embedded_table_macro_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/embedded_table_macro_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting, - "toc macro" do - include_context "expected markdown modules" + 'toc macro' do + include_context 'expected markdown modules' - it_behaves_like "format_text produces" do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW diff --git a/spec/lib/open_project/text_formatting/markdown/in_tool_links_spec.rb b/spec/lib/open_project/text_formatting/markdown/in_tool_links_spec.rb index 4a9ef7466e16..5b486f880ca7 100644 --- a/spec/lib/open_project/text_formatting/markdown/in_tool_links_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/in_tool_links_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting, - "in tool links" do - include_context "expected markdown modules" + 'in tool links' do + include_context 'expected markdown modules' - describe ".format_text" do + describe '.format_text' do shared_let(:project) { create(:valid_project) } let(:identifier) { project.identifier } @@ -63,7 +63,7 @@ allow(User).to receive(:current).and_return(project_member) end - context "Changeset links" do + context 'Changeset links' do let(:repository) do build_stubbed(:repository_subversion, project:) @@ -71,22 +71,22 @@ let(:changeset1) do build_stubbed(:changeset, repository:, - comments: "My very first commit") + comments: 'My very first commit') end let(:changeset2) do build_stubbed(:changeset, repository:, - comments: "This commit fixes #1, #2 and references #1 & #3") + comments: 'This commit fixes #1, #2 and references #1 & #3') end let(:changeset_link) do link_to("r#{changeset1.revision}", - { controller: "repositories", action: "revision", project_id: identifier, rev: changeset1.revision }, - class: "changeset op-uc-link", title: "My very first commit", target: "_top") + { controller: 'repositories', action: 'revision', project_id: identifier, rev: changeset1.revision }, + class: 'changeset op-uc-link', title: 'My very first commit', target: '_top') end let(:changeset_link2) do link_to("r#{changeset2.revision}", - { controller: "repositories", action: "revision", project_id: identifier, rev: changeset2.revision }, - class: "changeset op-uc-link", title: "This commit fixes #1, #2 and references #1 & #3", target: "_top") + { controller: 'repositories', action: 'revision', project_id: identifier, rev: changeset2.revision }, + class: 'changeset op-uc-link', title: 'This commit fixes #1, #2 and references #1 & #3', target: '_top') end before do @@ -96,138 +96,138 @@ allow(repository).to receive(:find_changeset_by_name).with(changeset2.revision).and_return(changeset2) end - context "Single link" do + context 'Single link' do subject { format_text("r#{changeset1.revision}") } it { is_expected.to be_html_eql("

    #{changeset_link}

    ") } end - context "Single link with dot" do + context 'Single link with dot' do subject { format_text("r#{changeset1.revision}. A word") } it { is_expected.to be_html_eql("

    #{changeset_link}. A word

    ") } end - context "Two links comma separated" do + context 'Two links comma separated' do subject { format_text("r#{changeset1.revision}, r#{changeset2.revision}") } it { is_expected.to be_html_eql("

    #{changeset_link}, #{changeset_link2}

    ") } end - context "Single link comma separated without a space" do + context 'Single link comma separated without a space' do subject { format_text("r#{changeset1.revision},r#{changeset2.revision}") } it { is_expected.to be_html_eql("

    #{changeset_link},#{changeset_link2}

    ") } end - context "Escaping" do + context 'Escaping' do subject { format_text("!r#{changeset1.id}") } it { is_expected.to be_html_eql("

    r#{changeset1.id}

    ") } end end - context "Version link" do + context 'Version link' do let!(:version) do create(:version, - name: "1.0", + name: '1.0', project:) end let(:version_link) do - link_to("1.0", - { controller: "versions", action: "show", id: version.id }, - class: "version op-uc-link", target: "_top") + link_to('1.0', + { controller: 'versions', action: 'show', id: version.id }, + class: 'version op-uc-link', target: '_top') end - context "Link with version id" do + context 'Link with version id' do subject { format_text("version##{version.id}") } it { is_expected.to be_html_eql("

    #{version_link}

    ") } end - context "Link with version" do - subject { format_text("version:1.0") } + context 'Link with version' do + subject { format_text('version:1.0') } it { is_expected.to be_html_eql("

    #{version_link}

    ") } end - context "Link with quoted version" do + context 'Link with quoted version' do subject { format_text('version:"1.0"') } it { is_expected.to be_html_eql("

    #{version_link}

    ") } end - context "Escaping link with version id" do + context 'Escaping link with version id' do subject { format_text("!version##{version.id}") } it { is_expected.to be_html_eql("

    version##{version.id}

    ") } end - context "Escaping link with version" do - subject { format_text("!version:1.0") } + context 'Escaping link with version' do + subject { format_text('!version:1.0') } it { is_expected.to be_html_eql('

    version:1.0

    ') } end - context "Escaping link with quoted version" do + context 'Escaping link with quoted version' do subject { format_text('!version:"1.0"') } it { is_expected.to be_html_eql('

    version:"1.0"

    ') } end end - context "Query link" do + context 'Query link' do let!(:query) do create(:query, - name: "project plan with milestones", + name: 'project plan with milestones', project:) end let(:query_link) do link_to( - "project plan with milestones", + 'project plan with milestones', project_work_packages_path([query.project.id], query_id: query.id), - class: "query op-uc-link", - target: "_top" + class: 'query op-uc-link', + target: '_top' ) end - context "Link with query id" do + context 'Link with query id' do subject { format_text("view##{query.id}") } it { is_expected.to be_html_eql("

    #{query_link}

    ") } end - context "Escaping link with view id" do + context 'Escaping link with view id' do subject { format_text("!view##{query.id}") } it { is_expected.to be_html_eql("

    view##{query.id}

    ") } end end - context "Default work package query link" do + context 'Default work package query link' do let(:default_query_link) do link_to( - "Work packages", + 'Work packages', project_work_packages_path([project.id]), - class: "query op-uc-link", - target: "_top" + class: 'query op-uc-link', + target: '_top' ) end - context "Link to default work package query" do + context 'Link to default work package query' do subject { format_text("view:default") } it { is_expected.to be_html_eql("

    #{default_query_link}

    ") } end - context "Escaping link to default work package query" do + context 'Escaping link to default work package query' do subject { format_text("!view:default") } it { is_expected.to be_html_eql("

    view:default

    ") } end end - context "Message links" do + context 'Message links' do let(:forum) { create(:forum, project:) } let(:message1) { create(:message, forum:) } let(:message2) do @@ -240,7 +240,7 @@ message1.reload end - context "Plain message" do + context 'Plain message' do subject { format_text("message##{message1.id}") } it { @@ -250,28 +250,28 @@ } end - context "Message with parent" do + context 'Message with parent' do subject { format_text("message##{message2.id}") } it { link = link_to(message2.subject, topic_path(message1, anchor: "message-#{message2.id}", r: message2.id), - class: "message op-uc-link", - target: "_top") + class: 'message op-uc-link', + target: '_top') expect(subject).to be_html_eql("

    #{link}

    ") } end end - context "Work package links" do + context 'Work package links' do let(:work_package_link) do link_to("##{work_package.id}", work_package_path(work_package), - class: "issue work_package preview-trigger op-uc-link", - target: "_top") + class: 'issue work_package preview-trigger op-uc-link', + target: '_top') end - context "Plain work_package link" do + context 'Plain work_package link' do subject { format_text("##{work_package.id}, [##{work_package.id}], (##{work_package.id}) and ##{work_package.id}.") } it { @@ -279,25 +279,25 @@ } end - context "Plain work_package link with braces" do + context 'Plain work_package link with braces' do subject { format_text("foo (bar ##{work_package.id})") } it { is_expected.to be_html_eql("

    foo (bar #{work_package_link})

    ") } end - context "Plain work_package link to non-existing element still links" do - subject { format_text("#0123456789") } + context 'Plain work_package link to non-existing element still links' do + subject { format_text('#0123456789') } it { expect(subject).to be_html_eql('

    #0123456789

    ') } end - describe "double hash work_package link" do + describe 'double hash work_package link' do let(:work_package_link) do - content_tag "opce-macro-wp-quickinfo", - "", - data: { id: "1234", detailed: "false" } + content_tag 'opce-macro-wp-quickinfo', + '', + data: { id: '1234', detailed: 'false' } end subject { format_text("foo (bar ##1234)") } @@ -305,11 +305,11 @@ it { is_expected.to be_html_eql("

    foo (bar #{work_package_link})

    ") } end - describe "triple hash work_package link" do + describe 'triple hash work_package link' do let(:work_package_link) do - content_tag "opce-macro-wp-quickinfo", - "", - data: { id: "1234", detailed: "true" } + content_tag 'opce-macro-wp-quickinfo', + '', + data: { id: '1234', detailed: 'true' } end subject { format_text("foo (bar ###1234)") } @@ -317,19 +317,19 @@ it { is_expected.to be_html_eql("

    foo (bar #{work_package_link})

    ") } end - context "Escaping work_package link" do + context 'Escaping work_package link' do subject { format_text("Some leading text. !##{work_package.id}. Some following") } it { is_expected.to be_html_eql("

    Some leading text. ##{work_package.id}. Some following

    ") } end - context "Escaping work_package link" do + context 'Escaping work_package link' do subject { format_text("!##{work_package.id}") } it { is_expected.to be_html_eql("

    ##{work_package.id}

    ") } end - context "WP subject with escapable chars" do + context 'WP subject with escapable chars' do let(:work_package) do create(:work_package, subject: "Title with \"quote\" and 'sòme 'chárs.") end @@ -337,8 +337,8 @@ let(:work_package_link) do link_to("##{work_package.id}", work_package_path(work_package), - class: "issue work_package preview-trigger op-uc-link", - target: "_top") + class: 'issue work_package preview-trigger op-uc-link', + target: '_top') end subject { format_text("##{work_package.id}") } @@ -346,20 +346,20 @@ it { is_expected.to be_html_eql("

    #{work_package_link}

    ") } end - context "Description links" do + context 'Description links' do subject { format_text work_package, :description } - it "replaces the macro with the work_package description" do + it 'replaces the macro with the work_package description' do expect(subject).to be_html_eql("

    #{work_package.description}

    ") end end end - context "Project links" do + context 'Project links' do let(:subproject) { create(:valid_project, parent: project, public: true) } let(:project_url) { project_overview_path(subproject) } - context "Plain project link" do + context 'Plain project link' do subject { format_text("project##{subproject.id}") } it { @@ -369,7 +369,7 @@ } end - context "Plain project link via identifier" do + context 'Plain project link via identifier' do subject { format_text("project:#{subproject.identifier}") } it { @@ -379,7 +379,7 @@ } end - context "Plain project link via name" do + context 'Plain project link via name' do subject { format_text("project:\"#{subproject.name}\"") } it { @@ -390,25 +390,25 @@ end end - context "Wiki links" do + context 'Wiki links' do let(:project_2) do create(:valid_project, - identifier: "onlinestore") + identifier: 'onlinestore') end let(:wiki_1) do create(:wiki, - start_page: "CookBook documentation", + start_page: 'CookBook documentation', project:) end let(:wiki_page_1_1) do create(:wiki_page, wiki: wiki_1, - title: "CookBook documentation") + title: 'CookBook documentation') end let(:wiki_page_1_2) do create(:wiki_page, wiki: wiki_1, - title: "Another page") + title: 'Another page') end let(:wiki_page_1_3) do create(:wiki_page, @@ -421,10 +421,10 @@ wiki_page_2_1 = create(:wiki_page, wiki: project_2.wiki, - title: "Start Page") + title: 'Start Page') project_2.wiki.pages << wiki_page_2_1 - project_2.wiki.start_page = "Start Page" + project_2.wiki.start_page = 'Start Page' project_2.wiki.save! project.wiki = wiki_1 @@ -434,15 +434,15 @@ wiki_1.pages << wiki_page_1_3 end - context "Plain wiki link" do - subject { format_text("[[CookBook documentation]]") } + context 'Plain wiki link' do + subject { format_text('[[CookBook documentation]]') } it { expect(subject).to be_html_eql("

    CookBook documentation

    ") } end - context "Arbitrary wiki link" do + context 'Arbitrary wiki link' do title = '' subject { format_text("[[#{title}]]") } @@ -451,40 +451,40 @@ } end - context "Plain wiki page link" do - subject { format_text("[[Another page|Page]]") } + context 'Plain wiki page link' do + subject { format_text('[[Another page|Page]]') } it { expect(subject).to be_html_eql("

    Page

    ") } end - context "Wiki link with anchor" do - subject { format_text("[[CookBook documentation#One-section]]") } + context 'Wiki link with anchor' do + subject { format_text('[[CookBook documentation#One-section]]') } it { expect(subject).to be_html_eql("

    CookBook documentation

    ") } end - context "Wiki page link with anchor" do - subject { format_text("[[Another page#anchor|Page]]") } + context 'Wiki page link with anchor' do + subject { format_text('[[Another page#anchor|Page]]') } it { expect(subject).to be_html_eql("

    Page

    ") } end - context "Wiki link to an unknown page" do - subject { format_text("[[Unknown page]]") } + context 'Wiki link to an unknown page' do + subject { format_text('[[Unknown page]]') } it { expect(subject).to be_html_eql("

    Unknown page

    ") } end - context "Wiki page link to an unknown page" do - subject { format_text("[[Unknown page|404]]") } + context 'Wiki page link to an unknown page' do + subject { format_text('[[Unknown page|404]]') } it { expect(subject).to be_html_eql("

    404

    ") @@ -492,7 +492,7 @@ end context "Link to another project's wiki" do - subject { format_text("[[onlinestore:]]") } + subject { format_text('[[onlinestore:]]') } it { expect(subject).to be_html_eql("

    onlinestore

    ") @@ -500,7 +500,7 @@ end context "Link to another project's wiki with label" do - subject { format_text("[[onlinestore:|Wiki]]") } + subject { format_text('[[onlinestore:|Wiki]]') } it { expect(subject).to be_html_eql("

    Wiki

    ") @@ -508,7 +508,7 @@ end context "Link to another project's wiki page" do - subject { format_text("[[onlinestore:Start page]]") } + subject { format_text('[[onlinestore:Start page]]') } it { expect(subject).to be_html_eql("

    Start Page

    ") @@ -516,67 +516,67 @@ end context "Link to another project's wiki page with label" do - subject { format_text("[[onlinestore:Start page|Text]]") } + subject { format_text('[[onlinestore:Start page|Text]]') } it { expect(subject).to be_html_eql("

    Text

    ") } end - context "Link to an unknown wiki page in another project" do - subject { format_text("[[onlinestore:Unknown page]]") } + context 'Link to an unknown wiki page in another project' do + subject { format_text('[[onlinestore:Unknown page]]') } it { expect(subject).to be_html_eql("

    Unknown page

    ") } end - context "Struck through link to wiki page" do - subject { format_text("~~[[Another page|Page]]~~") } + context 'Struck through link to wiki page' do + subject { format_text('~~[[Another page|Page]]~~') } it { expect(subject).to be_html_eql("

    Page

    ") } end - context "Named struck through link to wiki page" do - subject { format_text("~~[[Another page|Page]] link~~") } + context 'Named struck through link to wiki page' do + subject { format_text('~~[[Another page|Page]] link~~') } it { expect(subject).to be_html_eql("

    Page link

    ") } end - context "Escaped link to wiki page" do - subject { format_text("![[Another page|Page]]") } + context 'Escaped link to wiki page' do + subject { format_text('![[Another page|Page]]') } it { is_expected.to be_html_eql('

    [[Another page|Page]]

    ') } end - context "Link to wiki of non-existing project" do - subject { format_text("[[unknowproject:Start]]") } + context 'Link to wiki of non-existing project' do + subject { format_text('[[unknowproject:Start]]') } it { is_expected.to be_html_eql('

    [[unknowproject:Start]]

    ') } end - context "Link to wiki page of non-existing project" do - subject { format_text("[[unknowproject:Start|Page title]]") } + context 'Link to wiki page of non-existing project' do + subject { format_text('[[unknowproject:Start|Page title]]') } it { is_expected.to be_html_eql('

    [[unknowproject:Start|Page title]]

    ') } end end - context "Redmine links" do + context 'Redmine links' do let(:repository) do build_stubbed(:repository_subversion, project:) end def source_url(**) - entry_revision_project_repository_path(project_id: identifier, repo_path: "some/file", **) + entry_revision_project_repository_path(project_id: identifier, repo_path: 'some/file', **) end def source_url_with_ext(**) - entry_revision_project_repository_path(project_id: identifier, repo_path: "some/file.ext", **) + entry_revision_project_repository_path(project_id: identifier, repo_path: 'some/file.ext', **) end before do @@ -589,54 +589,54 @@ def source_url_with_ext(**) @to_test = { # source - "source:/some/file" => link_to("source:/some/file", source_url, class: "source op-uc-link", target: "_top"), - "source:/some/file." => link_to("source:/some/file", source_url, class: "source op-uc-link", target: "_top") + ".", - 'source:"/some/file.ext".' => link_to("source:/some/file.ext", source_url_with_ext, class: "source op-uc-link", - target: "_top") + ".", - "source:/some/file. " => link_to("source:/some/file", source_url, class: "source op-uc-link", target: "_top") + ".", - 'source:"/some/file.ext". ' => link_to("source:/some/file.ext", source_url_with_ext, class: "source op-uc-link", - target: "_top") + ".", - "source:/some/file, " => link_to("source:/some/file", source_url, class: "source op-uc-link", target: "_top") + ",", - "source:/some/file@52" => link_to("source:/some/file@52", source_url(rev: 52), class: "source op-uc-link", - target: "_top"), - 'source:"/some/file.ext@52"' => link_to("source:/some/file.ext@52", source_url_with_ext(rev: 52), - class: "source op-uc-link", - target: "_top"), - 'source:"/some/file#L110"' => link_to("source:/some/file#L110", source_url(anchor: "L110"), class: "source op-uc-link", - target: "_top"), - 'source:"/some/file.ext#L110"' => link_to("source:/some/file.ext#L110", source_url_with_ext(anchor: "L110"), - class: "source op-uc-link", - target: "_top"), - 'source:"/some/file@52#L110"' => link_to("source:/some/file@52#L110", source_url(rev: 52, anchor: "L110"), - class: "source op-uc-link", - target: "_top"), - "export:/some/file" => link_to("export:/some/file", source_url(format: "raw"), - class: "source download op-uc-link", - target: "_top"), + 'source:/some/file' => link_to('source:/some/file', source_url, class: 'source op-uc-link', target: '_top'), + 'source:/some/file.' => link_to('source:/some/file', source_url, class: 'source op-uc-link', target: '_top') + '.', + 'source:"/some/file.ext".' => link_to('source:/some/file.ext', source_url_with_ext, class: 'source op-uc-link', + target: '_top') + '.', + 'source:/some/file. ' => link_to('source:/some/file', source_url, class: 'source op-uc-link', target: '_top') + '.', + 'source:"/some/file.ext". ' => link_to('source:/some/file.ext', source_url_with_ext, class: 'source op-uc-link', + target: '_top') + '.', + 'source:/some/file, ' => link_to('source:/some/file', source_url, class: 'source op-uc-link', target: '_top') + ',', + 'source:/some/file@52' => link_to('source:/some/file@52', source_url(rev: 52), class: 'source op-uc-link', + target: '_top'), + 'source:"/some/file.ext@52"' => link_to('source:/some/file.ext@52', source_url_with_ext(rev: 52), + class: 'source op-uc-link', + target: '_top'), + 'source:"/some/file#L110"' => link_to('source:/some/file#L110', source_url(anchor: 'L110'), class: 'source op-uc-link', + target: '_top'), + 'source:"/some/file.ext#L110"' => link_to('source:/some/file.ext#L110', source_url_with_ext(anchor: 'L110'), + class: 'source op-uc-link', + target: '_top'), + 'source:"/some/file@52#L110"' => link_to('source:/some/file@52#L110', source_url(rev: 52, anchor: 'L110'), + class: 'source op-uc-link', + target: '_top'), + 'export:/some/file' => link_to('export:/some/file', source_url(format: 'raw'), + class: 'source download op-uc-link', + target: '_top'), # escaping - "!source:/some/file" => "source:/some/file", + '!source:/some/file' => 'source:/some/file', # invalid expressions - "source:" => "source:" + 'source:' => 'source:' } end - it "" do + it '' do @to_test.each do |text, result| expect(format_text(text)).to be_html_eql("

    #{result}

    ") end end end - context "Pre content should not parse wiki and redmine links" do + context 'Pre content should not parse wiki and redmine links' do let(:wiki) do create(:wiki, - start_page: "CookBook documentation", + start_page: 'CookBook documentation', project:) end let(:wiki_page) do create(:wiki_page, wiki:, - title: "CookBook documentation") + title: 'CookBook documentation') end let(:raw) do <<~RAW diff --git a/spec/lib/open_project/text_formatting/markdown/include_wiki_page_macro_spec.rb b/spec/lib/open_project/text_formatting/markdown/include_wiki_page_macro_spec.rb index f08b9f76ae5c..30040b2f19da 100644 --- a/spec/lib/open_project/text_formatting/markdown/include_wiki_page_macro_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/include_wiki_page_macro_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "OpenProject include wiki page macro" do +RSpec.describe 'OpenProject include wiki page macro' do include ActionView::Helpers::UrlHelper include OpenProject::StaticRouting::UrlHelpers include OpenProject::TextFormatting @@ -50,13 +50,13 @@ def error_html(exception_msg) "Error executing the macro include_wiki_page (#{exception_msg})

    " end - context "old macro syntax no longer works" do - let(:input) { "{{include(whatever)}}" } + context 'old macro syntax no longer works' do + let(:input) { '{{include(whatever)}}' } it { is_expected.to be_html_eql("

    #{input}

    ") } end - context "with the new but also no longer supported syntax" do + context 'with the new but also no longer supported syntax' do let(:input) { '' } it { is_expected.to be_html_eql(error_html("The macro does no longer exist.")) } diff --git a/spec/lib/open_project/text_formatting/markdown/lists_spec.rb b/spec/lib/open_project/text_formatting/markdown/lists_spec.rb index 76cf497ab40a..4d328bc892e7 100644 --- a/spec/lib/open_project/text_formatting/markdown/lists_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/lists_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting, - "lists" do - include_context "expected markdown modules" + 'lists' do + include_context 'expected markdown modules' - context "ordered lists" do - it_behaves_like "format_text produces" do + context 'ordered lists' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW 1. First item @@ -57,8 +57,8 @@ end end - context "unordered lists" do - it_behaves_like "format_text produces" do + context 'unordered lists' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW * First item @@ -84,8 +84,8 @@ end end - context "todo list" do - it_behaves_like "format_text produces" do + context 'todo list' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW * [ ] First ToDo @@ -114,8 +114,8 @@ end end - context "in a table" do - it_behaves_like "format_text produces" do + context 'in a table' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW @@ -267,8 +267,8 @@ end end - context "in a table and with a link on second place" do - it_behaves_like "format_text produces" do + context 'in a table and with a link on second place' do + it_behaves_like 'format_text produces' do let(:raw) do <<~RAW
    diff --git a/spec/lib/open_project/text_formatting/markdown/markdown_formatting_spec.rb b/spec/lib/open_project/text_formatting/markdown/markdown_formatting_spec.rb index 5d42cd378deb..5f7aec204938 100644 --- a/spec/lib/open_project/text_formatting/markdown/markdown_formatting_spec.rb +++ b/spec/lib/open_project/text_formatting/markdown/markdown_formatting_spec.rb @@ -26,38 +26,38 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "expected_markdown" +require 'spec_helper' +require_relative 'expected_markdown' RSpec.describe OpenProject::TextFormatting::Formats::Markdown::Formatter do - it "modifierses" do + it 'modifierses' do assert_html_output( - "**bold**" => "bold", - "before **bold**" => "before bold", - "**bold** after" => "bold after", - "**two words**" => "two words", - "**two*words**" => "two*words", - "**two * words**" => "two * words", - "**two** **words**" => "twowords", - "**(two)** **(words)**" => "(two)(words)" + '**bold**' => 'bold', + 'before **bold**' => 'before bold', + '**bold** after' => 'bold after', + '**two words**' => 'two words', + '**two*words**' => 'two*words', + '**two * words**' => 'two * words', + '**two** **words**' => 'twowords', + '**(two)** **(words)**' => '(two)(words)' ) end - it "escapes script tags" do + it 'escapes script tags' do assert_html_output( - "this is a ") + it 'parses the HTML entities correctly' do + expect(instance.first.first.line_right).to eq('') end - context "with a unified diff with html chars" do + context 'with a unified diff with html chars' do let(:diff) do <<~DIFF diff --git a/asdf b/asdf @@ -211,37 +211,37 @@ def initialize(diff, options={}) instance.first.each_with_object([]) { |l, array| array << [l.html_line_left, l.html_line_right] } end - it "correctly escapes elements" do + it 'correctly escapes elements' do expect(subject[1]).to eq(["Test 2 <_> pouet", ""]) expect(subject[2]).to eq(["", "Test 2 >_> pouet"]) end end - context "with a subversion diff" do + context 'with a subversion diff' do let(:diff) { subversion_diff } - it "has 4 modified files" do + it 'has 4 modified files' do expect(instance.size) .to eq 4 end - it "identifies the file name" do + it 'identifies the file name' do expect(instance[2].file_name) .to match %r{\Aconfig/settings.yml} end end - context "with a subversion diff when truncating" do + context 'with a subversion diff when truncating' do let(:diff) { subversion_diff } let(:diff_options) { { max_lines: 20 } } - it "has only 2 modified files" do + it 'has only 2 modified files' do expect(instance.size) .to eq 2 end end - context "with one line new files" do + context 'with one line new files' do let(:diff) do <<~DIFF diff -r 000000000000 -r ea98b14f75f0 README1 @@ -271,36 +271,36 @@ def initialize(diff, options={}) DIFF end - it "has 4 modified files" do + it 'has 4 modified files' do expect(instance.size) .to eq 4 end end - context "with inline partials" do + context 'with inline partials' do let(:diff) { partials_diff } - it "has 1 modified files" do + it 'has 1 modified files' do expect(instance.size) .to eq 1 end - context "for the file" do + context 'for the file' do subject { instance.first } it { expect(subject.size).to eq 41 } it { expect(subject[0].offsets).to eq [51, -1] } it { expect(subject[1].offsets).to eq [51, -1] } - it { expect(subject[0].html_line).to eq "Lorem ipsum dolor sit amet, consectetur adipiscing elit" } - it { expect(subject[1].html_line).to eq "Lorem ipsum dolor sit amet, consectetur adipiscing xx" } + it { expect(subject[0].html_line).to eq 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' } + it { expect(subject[1].html_line).to eq 'Lorem ipsum dolor sit amet, consectetur adipiscing xx' } it { expect(subject[2].offsets).to be_nil } - it { expect(subject[2].html_line).to eq "Praesent et sagittis dui. Vivamus ac diam diam" } + it { expect(subject[2].html_line).to eq 'Praesent et sagittis dui. Vivamus ac diam diam' } it { expect(subject[3].offsets).to eq [0, -14] } it { expect(subject[4].offsets).to eq [0, -14] } - it { expect(subject[3].html_line).to eq "Ut sed auctor justo" } - it { expect(subject[4].html_line).to eq "xxx auctor justo" } + it { expect(subject[3].html_line).to eq 'Ut sed auctor justo' } + it { expect(subject[4].html_line).to eq 'xxx auctor justo' } it { expect(subject[6].offsets).to eq [13, -19] } it { expect(subject[7].offsets).to eq [13, -19] } @@ -316,31 +316,31 @@ def initialize(diff, options={}) end end - context "with side by side partials" do + context 'with side by side partials' do let(:diff) { partials_diff } - let(:diff_options) { { type: "sbs" } } + let(:diff_options) { { type: 'sbs' } } - it "has 1 modified files" do + it 'has 1 modified files' do expect(instance.size) .to eq 1 end - context "for the file" do + context 'for the file' do subject { instance.first } it { expect(subject.size).to eq 30 } it { expect(subject[0].offsets).to eq [51, -1] } - it { expect(subject[0].html_line_left).to eq "Lorem ipsum dolor sit amet, consectetur adipiscing elit" } - it { expect(subject[0].html_line_right).to eq "Lorem ipsum dolor sit amet, consectetur adipiscing xx" } + it { expect(subject[0].html_line_left).to eq 'Lorem ipsum dolor sit amet, consectetur adipiscing elit' } + it { expect(subject[0].html_line_right).to eq 'Lorem ipsum dolor sit amet, consectetur adipiscing xx' } it { expect(subject[1].offsets).to be_nil } - it { expect(subject[1].html_line_left).to eq "Praesent et sagittis dui. Vivamus ac diam diam" } - it { expect(subject[1].html_line_right).to eq "Praesent et sagittis dui. Vivamus ac diam diam" } + it { expect(subject[1].html_line_left).to eq 'Praesent et sagittis dui. Vivamus ac diam diam' } + it { expect(subject[1].html_line_right).to eq 'Praesent et sagittis dui. Vivamus ac diam diam' } it { expect(subject[2].offsets).to eq [0, -14] } - it { expect(subject[2].html_line_left).to eq "Ut sed auctor justo" } - it { expect(subject[2].html_line_right).to eq "xxx auctor justo" } + it { expect(subject[2].html_line_left).to eq 'Ut sed auctor justo' } + it { expect(subject[2].html_line_right).to eq 'xxx auctor justo' } it { expect(subject[4].offsets).to eq [13, -19] } it { expect(subject[6].offsets).to eq [24, -8] } @@ -349,7 +349,7 @@ def initialize(diff, options={}) end end - context "with lines starting with dashes" do + context 'with lines starting with dashes' do let(:diff) do <<~DIFF --- old.txt Wed Nov 11 14:24:58 2009 @@ -376,7 +376,7 @@ def initialize(diff, options={}) let(:instance) { described_class.new(diff) } - it "has 1 modified file" do + it 'has 1 modified file' do expect(instance.size) .to eq 1 end diff --git a/spec/lib/representable_spec.rb b/spec/lib/representable_spec.rb index 80db83302b32..2c885098ba51 100644 --- a/spec/lib/representable_spec.rb +++ b/spec/lib/representable_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "representable/json" +require 'spec_helper' +require 'representable/json' RSpec.describe Representable do - let(:object) { Struct.new(:title).new("test") } + let(:object) { Struct.new(:title).new('test') } class ReverseNamingStrategy def call(name) @@ -37,7 +37,7 @@ def call(name) end end - describe "as_strategy with lambda" do + describe 'as_strategy with lambda' do class UpcaseRepresenter < Representable::Decorator include Representable::JSON @@ -49,7 +49,7 @@ class UpcaseRepresenter < Representable::Decorator it { expect(UpcaseRepresenter.new(object).to_json).to eql('{"TITLE":"test"}') } end - describe "as_strategy with class responding to #call?" do + describe 'as_strategy with class responding to #call?' do class ReverseRepresenter < Representable::Decorator include Representable::JSON @@ -61,8 +61,8 @@ class ReverseRepresenter < Representable::Decorator it { expect(ReverseRepresenter.new(object).to_json).to eql('{"eltit":"test"}') } end - describe "as_strategy with class not responding to #call?" do - it "raises error" do + describe 'as_strategy with class not responding to #call?' do + it 'raises error' do expect do class FailRepresenter < Representable::Decorator include Representable::JSON diff --git a/spec/lib/rubocop/cop/open_project/no_do_end_block_with_rspec_capybara_matcher_in_expect_spec.rb b/spec/lib/rubocop/cop/open_project/no_do_end_block_with_rspec_capybara_matcher_in_expect_spec.rb index 0086bbbc75a6..3842726ce3a4 100644 --- a/spec/lib/rubocop/cop/open_project/no_do_end_block_with_rspec_capybara_matcher_in_expect_spec.rb +++ b/spec/lib/rubocop/cop/open_project/no_do_end_block_with_rspec_capybara_matcher_in_expect_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rubocop/cop/open_project/no_do_end_block_with_rspec_capybara_matcher_in_expect" +require 'spec_helper' +require 'rubocop/cop/open_project/no_do_end_block_with_rspec_capybara_matcher_in_expect' RSpec.describe RuboCop::Cop::OpenProject::NoDoEndBlockWithRSpecCapybaraMatcherInExpect do include RuboCop::RSpec::ExpectOffense - include_context "config" + include_context 'config' - context "when using `do .. end` syntax with rspec matcher" do - it "registers an offense" do + context 'when using `do .. end` syntax with rspec matcher' do + it 'registers an offense' do expect_offense(<<~RUBY) expect(page).to have_selector("input") do |input| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The `do .. end` block is associated with `to` and not with Capybara matcher `have_selector`. @@ -42,7 +42,7 @@ RUBY end - it "matches only Capybara matchers" do + it 'matches only Capybara matchers' do expect_no_offenses(<<~RUBY) expect(foo).to have_received(:bar) do |value| value == 'hello world' @@ -51,8 +51,8 @@ end end - context "when using `{ .. }` syntax with rspec matcher" do - it "does not register an offense" do + context 'when using `{ .. }` syntax with rspec matcher' do + it 'does not register an offense' do expect_no_offenses(<<~RUBY) expect(page).to have_selector("input") { |input| } RUBY diff --git a/spec/lib/rubocop/cop/open_project/use_service_result_factory_methods_spec.rb b/spec/lib/rubocop/cop/open_project/use_service_result_factory_methods_spec.rb index 86520fc44b44..f723bb289330 100644 --- a/spec/lib/rubocop/cop/open_project/use_service_result_factory_methods_spec.rb +++ b/spec/lib/rubocop/cop/open_project/use_service_result_factory_methods_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rubocop/cop/open_project/use_service_result_factory_methods" +require 'spec_helper' +require 'rubocop/cop/open_project/use_service_result_factory_methods' RSpec.describe RuboCop::Cop::OpenProject::UseServiceResultFactoryMethods do include RuboCop::RSpec::ExpectOffense - include_context "config" + include_context 'config' - it "registers an offense for ServiceResult.new without any success: argument" do + it 'registers an offense for ServiceResult.new without any success: argument' do expect_offense(<<~RUBY) ServiceResult.new ^^^ Use ServiceResult.failure instead of ServiceResult.new. @@ -47,24 +47,24 @@ RUBY end - it "allows ServiceResult.new(success: some_value) (no explicit true/false value)" do - expect_no_offenses("ServiceResult.new(success: some_value)") + it 'allows ServiceResult.new(success: some_value) (no explicit true/false value)' do + expect_no_offenses('ServiceResult.new(success: some_value)') expect_no_offenses('ServiceResult.new(foo: "bar", success: some_value, bar: "baz")') end - it "allows ServiceResult.new(**kw) (no explicit true/false value)" do - expect_no_offenses("ServiceResult.new(**kw)") + it 'allows ServiceResult.new(**kw) (no explicit true/false value)' do + expect_no_offenses('ServiceResult.new(**kw)') expect_no_offenses('ServiceResult.new(foo: "bar", **kw)') expect_no_offenses('ServiceResult.new(**kw, foo: "bar")') end - include_context "ruby 3.1" do - it "allows ServiceResult.new(success:) (no explicit true/false value)" do - expect_no_offenses("ServiceResult.new(success:)") + include_context 'ruby 3.1' do + it 'allows ServiceResult.new(success:) (no explicit true/false value)' do + expect_no_offenses('ServiceResult.new(success:)') expect_no_offenses('ServiceResult.new(foo: "bar", success:, bar: "baz")') end - it "allows ServiceResult.new(...) (no explicit true/false value)" do + it 'allows ServiceResult.new(...) (no explicit true/false value)' do expect_no_offenses(<<~RUBY) def call(...) ServiceResult.new(...) @@ -73,7 +73,7 @@ def call(...) end end - it "registers an offense for ServiceResult.new(success: true) with no additional args" do + it 'registers an offense for ServiceResult.new(success: true) with no additional args' do expect_offense(<<~RUBY) ServiceResult.new(success: true) ^^^^^^^^^^^^^ Use ServiceResult.success(...) instead of ServiceResult.new(success: true, ...). @@ -84,7 +84,7 @@ def call(...) RUBY end - it "registers an offense for ServiceResult.new(success: true) with additional args" do + it 'registers an offense for ServiceResult.new(success: true) with additional args' do expect_offense(<<~RUBY) ServiceResult.new(success: true, ^^^^^^^^^^^^^ Use ServiceResult.success(...) instead of ServiceResult.new(success: true, ...). @@ -100,7 +100,7 @@ def call(...) RUBY end - it "registers an offense for ServiceResult.new(success: false) with no additional args" do + it 'registers an offense for ServiceResult.new(success: false) with no additional args' do expect_offense(<<~RUBY) ServiceResult.new(success: false) ^^^^^^^^^^^^^^ Use ServiceResult.failure(...) instead of ServiceResult.new(success: false, ...). @@ -114,7 +114,7 @@ def call(...) RUBY end - it "registers an offense for ServiceResult.new(success: false) with additional args" do + it 'registers an offense for ServiceResult.new(success: false) with additional args' do expect_offense(<<~RUBY) ServiceResult.new(success: false, ^^^^^^^^^^^^^^ Use ServiceResult.failure(...) instead of ServiceResult.new(success: false, ...). @@ -130,7 +130,7 @@ def call(...) RUBY end - it "registers an offense for ServiceResult.new(success: true/false) with splat kwargs" do + it 'registers an offense for ServiceResult.new(success: true/false) with splat kwargs' do expect_offense(<<~RUBY) ServiceResult.new(success: true, **kw) ^^^^^^^^^^^^^ Use ServiceResult.success(...) instead of ServiceResult.new(success: true, ...). diff --git a/spec/lib/tabular_form_builder_spec.rb b/spec/lib/tabular_form_builder_spec.rb index 4fc11ea52591..46c5921c065e 100644 --- a/spec/lib/tabular_form_builder_spec.rb +++ b/spec/lib/tabular_form_builder_spec.rb @@ -25,47 +25,47 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "ostruct" +require 'spec_helper' +require 'ostruct' RSpec.describe TabularFormBuilder do include Capybara::RSpecMatchers - let(:helper) { ActionView::Base.new(ActionView::LookupContext.new(""), {}, nil) } + let(:helper) { ActionView::Base.new(ActionView::LookupContext.new(''), {}, nil) } let(:resource) do build(:user, - firstname: "JJ", - lastname: "Abrams", - login: "lost", - mail: "jj@lost-mail.com", + firstname: 'JJ', + lastname: 'Abrams', + login: 'lost', + mail: 'jj@lost-mail.com', failed_login_count: 45) end let(:builder) { TabularFormBuilder.new(:user, resource, helper, {}) } - describe "#text_field" do - let(:options) { { title: "Name", class: "custom-class" } } + describe '#text_field' do + let(:options) { { title: 'Name', class: 'custom-class' } } subject(:output) do builder.text_field :name, options end - it_behaves_like "labelled by default" + it_behaves_like 'labelled by default' - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end - context "with help text" do - let(:options) { { title: "Name", class: "custom-class", help_text: { attribute: "foo", "attribute-scope": "bar" } } } + context 'with help text' do + let(:options) { { title: 'Name', class: 'custom-class', help_text: { attribute: 'foo', 'attribute-scope': 'bar' } } } - it "outputs a label with an attribute-help-text tag" do + it 'outputs a label with an attribute-help-text tag' do expect(output).to be_html_eql(%{ - }).at_path("label") + }).at_path('label') end end - context "with affixes" do - let(:random_id) { "random_id" } + context 'with affixes' do + let(:random_id) { 'random_id' } before do allow(SecureRandom) @@ -88,10 +88,10 @@ .and_return(random_id) end - context "with a prefix" do - let(:options) { { title: "Name", prefix: %{Prefix} } } + context 'with a prefix' do + let(:options) { { title: 'Name', prefix: %{Prefix} } } - it "outputs elements" do + it 'outputs elements' do expect(output).to be_html_eql(%{ - }).within_path("span.form--field-container") + }).within_path('span.form--field-container') end - it "includes the prefix hidden in the label" do + it 'includes the prefix hidden in the label' do expect(output).to be_html_eql(%{ Prefix - }).within_path("label.form--label") + }).within_path('label.form--label') end end - context "with a suffix" do - let(:options) { { title: "Name", suffix: %{Suffix} } } + context 'with a suffix' do + let(:options) { { title: 'Name', suffix: %{Suffix} } } - it "outputs elements" do + it 'outputs elements' do expect(output).to be_html_eql(%{ Suffix - }).within_path("span.form--field-container") + }).within_path('span.form--field-container') end end - context "with both prefix and suffix" do + context 'with both prefix and suffix' do let(:options) do { - title: "Name", + title: 'Name', prefix: %{PREFIX}, suffix: %{SUFFIX} } end - it "outputs elements" do + it 'outputs elements' do expect(output).to be_html_eql(%{ SUFFIX - }).within_path("span.form--field-container") + }).within_path('span.form--field-container') end - it "includes the prefix hidden in the label" do + it 'includes the prefix hidden in the label' do expect(output).to be_html_eql(%{ PREFIX - }).within_path("label.form--label") + }).within_path('label.form--label') end end end end - describe "#text_area" do - let(:options) { { title: "Name", class: "custom-class" } } + describe '#text_area' do + let(:options) { { title: 'Name', class: 'custom-class' } } subject(:output) do builder.text_area :name, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-area-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-area-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("textarea") + }).at_path('textarea') end - context "when requesting a text formatting wrapper" do - let(:options) { { title: "Name", class: "custom-class", with_text_formatting: true } } + context 'when requesting a text formatting wrapper' do + let(:options) { { title: 'Name', class: 'custom-class', with_text_formatting: true } } - context "an id is missing" do - it "outputs the wysiwyg wrapper" do - expect(output).to have_css "textarea" - expect(output).to have_css "ckeditor-augmented-textarea" + context 'an id is missing' do + it 'outputs the wysiwyg wrapper' do + expect(output).to have_css 'textarea' + expect(output).to have_css 'ckeditor-augmented-textarea' end end - context "with id present" do - let(:options) { { id: "my-id", title: "Name", class: "custom-class", with_text_formatting: true } } + context 'with id present' do + let(:options) { { id: 'my-id', title: 'Name', class: 'custom-class', with_text_formatting: true } } - it "outputs the wysiwyg wrapper" do - expect(output).to have_css "textarea" - expect(output).to have_css "ckeditor-augmented-textarea" + it 'outputs the wysiwyg wrapper' do + expect(output).to have_css 'textarea' + expect(output).to have_css 'ckeditor-augmented-textarea' end end end end - describe "#select" do - let(:options) { { title: "Name" } } - let(:html_options) { { class: "custom-class" } } + describe '#select' do + let(:options) { { title: 'Name' } } + let(:html_options) { { class: 'custom-class' } } subject(:output) do builder.select :name, ''.html_safe, options, html_options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "select-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'select-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("select") + }).at_path('select') end end - describe "#collection_select" do - let(:options) { { title: "Name" } } - let(:html_options) { { class: "custom-class" } } + describe '#collection_select' do + let(:options) { { title: 'Name' } } + let(:html_options) { { class: 'custom-class' } } subject(:output) do builder.collection_select :name, [ - OpenStruct.new(id: 56, name: "Diana"), - OpenStruct.new(id: 46, name: "Ricky"), - OpenStruct.new(id: 33, name: "Jonas") + OpenStruct.new(id: 56, name: 'Diana'), + OpenStruct.new(id: 46, name: 'Ricky'), + OpenStruct.new(id: 33, name: 'Jonas') ], :id, :name, options, html_options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "select-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'select-container' - it "outputs element" do - expect(output).to have_css "select.custom-class.form--select > option", count: 3 + it 'outputs element' do + expect(output).to have_css 'select.custom-class.form--select > option', count: 3 expect(output).to have_css 'option:first[value="56"]' - expect(output).to have_text "Jonas" + expect(output).to have_text 'Jonas' end end - describe "#date_select" do - let(:options) { { title: "Last logged in on" } } + describe '#date_select' do + let(:options) { { title: 'Last logged in on' } } subject(:output) do builder.date_select :last_login_on, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' - it "outputs element" do - expect(output).to have_css "select", count: 3 - expect(output).to have_css "select:nth-of-type(2) > option", count: 12 - expect(output).to have_css "select:last > option", count: 31 + it 'outputs element' do + expect(output).to have_css 'select', count: 3 + expect(output).to have_css 'select:nth-of-type(2) > option', count: 12 + expect(output).to have_css 'select:last > option', count: 31 end end - describe "#check_box" do - let(:options) { { title: "Name", class: "custom-class" } } + describe '#check_box' do + let(:options) { { title: 'Name', class: 'custom-class' } } subject(:output) do builder.check_box :first_login, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "check-box-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'check-box-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input:nth-of-type(2)") + }).at_path('input:nth-of-type(2)') end end - describe "#collection_check_box" do + describe '#collection_check_box' do let(:options) { {} } subject(:output) do builder.collection_check_box :enabled_module_names, :repositories, true, - "name", + 'name', options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "check-box-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'check-box-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input:nth-of-type(2)") + }).at_path('input:nth-of-type(2)') end end - describe "#radio_button" do - let(:options) { { title: "Name", class: "custom-class" } } + describe '#radio_button' do + let(:options) { { title: 'Name', class: 'custom-class' } } subject(:output) do - builder.radio_button :name, "John", options + builder.radio_button :name, 'John', options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in container" - it_behaves_like "wrapped in container", "radio-button-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in container' + it_behaves_like 'wrapped in container', 'radio-button-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#number_field" do - let(:options) { { title: "Bad logins", class: "custom-class" } } + describe '#number_field' do + let(:options) { { title: 'Bad logins', class: 'custom-class' } } subject(:output) do builder.number_field :failed_login_count, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#range_field" do - let(:options) { { title: "Bad logins", class: "custom-class" } } + describe '#range_field' do + let(:options) { { title: 'Bad logins', class: 'custom-class' } } subject(:output) do builder.range_field :failed_login_count, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "range-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'range-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#search_field" do - let(:options) { { title: "Search name", class: "custom-class" } } + describe '#search_field' do + let(:options) { { title: 'Search name', class: 'custom-class' } } subject(:output) do builder.search_field :name, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "search-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'search-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#email_field" do - let(:options) { { title: "Email", class: "custom-class" } } + describe '#email_field' do + let(:options) { { title: 'Email', class: 'custom-class' } } subject(:output) do builder.email_field :mail, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#telephone_field" do - let(:options) { { title: "Not really email", class: "custom-class" } } + describe '#telephone_field' do + let(:options) { { title: 'Not really email', class: 'custom-class' } } subject(:output) do builder.telephone_field :mail, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#password_field" do - let(:options) { { title: "Not really password", class: "custom-class" } } + describe '#password_field' do + let(:options) { { title: 'Not really password', class: 'custom-class' } } subject(:output) do builder.password_field :login, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#file_field" do - let(:options) { { title: "Not really file", class: "custom-class" } } + describe '#file_field' do + let(:options) { { title: 'Not really file', class: 'custom-class' } } subject(:output) do builder.file_field :name, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "file-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'file-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#url_field" do - let(:options) { { title: "Not really file", class: "custom-class" } } + describe '#url_field' do + let(:options) { { title: 'Not really file', class: 'custom-class' } } subject(:output) do builder.url_field :name, options end - it_behaves_like "labelled by default" - it_behaves_like "wrapped in field-container by default" - it_behaves_like "wrapped in container", "text-field-container" + it_behaves_like 'labelled by default' + it_behaves_like 'wrapped in field-container by default' + it_behaves_like 'wrapped in container', 'text-field-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql(%{ - }).at_path("input") + }).at_path('input') end end - describe "#submit" do + describe '#submit' do subject(:output) do Capybara::Node::Simple.new(builder.submit) end - it_behaves_like "not labelled" - it_behaves_like "not wrapped in container" - it_behaves_like "not wrapped in container", "submit-container" + it_behaves_like 'not labelled' + it_behaves_like 'not wrapped in container' + it_behaves_like 'not wrapped in container', 'submit-container' - it "outputs element" do - expect(output).to have_css("input[name=commit]") + it 'outputs element' do + expect(output).to have_css('input[name=commit]') end end - describe "#button" do + describe '#button' do subject(:output) do builder.button end - it_behaves_like "not labelled" - it_behaves_like "not wrapped in container" - it_behaves_like "not wrapped in container", "button-container" + it_behaves_like 'not labelled' + it_behaves_like 'not wrapped in container' + it_behaves_like 'not wrapped in container', 'button-container' - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql %{} end end - describe "#label" do + describe '#label' do subject(:output) { builder.label :name } - it "outputs element" do + it 'outputs element' do expect(output).to be_html_eql %{ } end end - describe "when using it without ActiveModel" do - let(:resource) { OpenStruct.new name: "Deadpool" } + describe 'when using it without ActiveModel' do + let(:resource) { OpenStruct.new name: 'Deadpool' } - it "falls back to the method name" do + it 'falls back to the method name' do expect(output).to be_html_eql %{ } @@ -577,104 +577,104 @@ end # test the label that is generated for various field types - describe "labels for fields" do + describe 'labels for fields' do let(:options) { {} } - shared_examples_for "generated label" do - def expected_label_like(expected_title, expected_classes = "form--label") + shared_examples_for 'generated label' do + def expected_label_like(expected_title, expected_classes = 'form--label') expect(output).to be_html_eql(%{ - }).at_path("label") + }).at_path('label') end - def expected_form_label_like(expected_title, expected_classes = "form--label") + def expected_form_label_like(expected_title, expected_classes = 'form--label') expect(output).to be_html_eql(%{ - }).at_path("label") + }).at_path('label') end - context "with a label specified as string" do - let(:text) { "My own label" } + context 'with a label specified as string' do + let(:text) { 'My own label' } before do options[:label] = text end - it "uses the label" do + it 'uses the label' do expected_label_like(text) end end - context "with a label specified as symbol" do + context 'with a label specified as symbol' do let(:text) { :label_name } before do options[:label] = text end - it "uses the label" do + it 'uses the label' do expected_label_like(I18n.t(text)) end end - context "without ActiveModel and specified label" do + context 'without ActiveModel and specified label' do # This is a hypotethical resource that does not have an existing translation # key, therefore stubbing the translation is allowed. before do - allow(I18n).to receive(:t).with(:name, scope: "user").and_return("Name") + allow(I18n).to receive(:t).with(:name, scope: 'user').and_return('Name') end - let(:resource) { OpenStruct.new name: "Deadpool" } + let(:resource) { OpenStruct.new name: 'Deadpool' } - it "falls back to the I18n name" do - expected_label_like(I18n.t(:name, scope: "user")) + it 'falls back to the I18n name' do + expected_label_like(I18n.t(:name, scope: 'user')) end end - context "with ActiveModel and without specified label" do + context 'with ActiveModel and without specified label' do let(:resource) do build_stubbed(:user, - firstname: "JJ", - lastname: "Abrams", - login: "lost", - mail: "jj@lost-mail.com", + firstname: 'JJ', + lastname: 'Abrams', + login: 'lost', + mail: 'jj@lost-mail.com', failed_login_count: 45) end - it "uses the human attribute name" do + it 'uses the human attribute name' do expected_label_like(User.human_attribute_name(:name)) end - context "with erroneous field" do + context 'with erroneous field' do before do resource.errors.add(:name, :invalid) resource.errors.add(:name, :inclusion) end - it "shows an appropriate error label" do - expect(output).to have_css "label.-error", + it 'shows an appropriate error label' do + expect(output).to have_css 'label.-error', count: 1, - text: "Name" + text: 'Name' end - it "contains a specific error as a hidden sub-label" do - expect(output).to have_css "label.-error p", + it 'contains a specific error as a hidden sub-label' do + expect(output).to have_css 'label.-error p', count: 1, - text: "This field is invalid: Name is invalid. " \ - "Name is not set to one of the allowed values." + text: 'This field is invalid: Name is invalid. ' \ + 'Name is not set to one of the allowed values.' end end end - context "when required, with a label specified as symbol" do + context 'when required, with a label specified as symbol' do let(:text) { :label_name } before do @@ -682,8 +682,8 @@ def expected_form_label_like(expected_title, expected_classes = "form--label") options[:required] = true end - it "uses the label" do - expected_form_label_like(I18n.t(:label_name), "form--label") + it 'uses the label' do + expected_form_label_like(I18n.t(:label_name), 'form--label') end end end @@ -697,16 +697,16 @@ def expected_form_label_like(expected_title, expected_classes = "form--label") builder.send(input_type, :name, options) end - it_behaves_like "generated label" + it_behaves_like 'generated label' end end - context "for select" do + context 'for select' do subject(:output) do builder.select :name, [], options end - it_behaves_like "generated label" + it_behaves_like 'generated label' end end end diff --git a/spec/mailers/announcement_mailer_spec.rb b/spec/mailers/announcement_mailer_spec.rb index f7deb61a8d22..16bf151bfd01 100644 --- a/spec/mailers/announcement_mailer_spec.rb +++ b/spec/mailers/announcement_mailer_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AnnouncementMailer do - let(:announcement_subject) { "Some subject" } + let(:announcement_subject) { 'Some subject' } let(:recipient) { build_stubbed(:user) } - let(:announcement_body) { "Some body text" } + let(:announcement_body) { 'Some body text' } - describe "#announce" do + describe '#announce' do subject(:mail) do described_class.announce(recipient, subject: announcement_subject, @@ -45,7 +45,7 @@ .to eq announcement_subject end - it "includes the body" do + it 'includes the body' do expect(mail.body.encoded) .to include(announcement_body) end @@ -55,7 +55,7 @@ .to include announcement_subject end - it "sends to the recipient" do + it 'sends to the recipient' do expect(mail.to) .to contain_exactly(recipient.mail) end diff --git a/spec/mailers/digest_mailer_spec.rb b/spec/mailers/digest_mailer_spec.rb index 10c1b341fa9b..a06d7aa834f1 100644 --- a/spec/mailers/digest_mailer_spec.rb +++ b/spec/mailers/digest_mailer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DigestMailer do include OpenProject::ObjectLinking @@ -50,7 +50,7 @@ end let(:journal) do build_stubbed(:work_package_journal, - notes: "Some notes").tap do |j| + notes: 'Some notes').tap do |j| allow(j) .to receive(:details) .and_return({ "subject" => ["old subject", "new subject"] }) @@ -72,22 +72,22 @@ end end - describe "#work_packages" do + describe '#work_packages' do subject(:mail) { described_class.work_packages(recipient.id, notifications.map(&:id)) } - let(:mail_body) { mail.body.parts.detect { |part| part["Content-Type"].value == "text/html" }.body.to_s } + let(:mail_body) { mail.body.parts.detect { |part| part['Content-Type'].value == 'text/html' }.body.to_s } - it "notes the day and the number of notifications in the subject" do + it 'notes the day and the number of notifications in the subject' do expect(mail.subject) .to eql "OpenProject - 1 unread notification" end - it "sends to the recipient" do + it 'sends to the recipient' do expect(mail.to) .to contain_exactly(recipient.mail) end - it "sets the expected message_id header" do + it 'sets the expected message_id header' do allow(Time) .to receive(:current) .and_return(Time.current) @@ -96,13 +96,13 @@ .to eql "op.digest.#{Time.current.strftime('%Y%m%d%H%M%S')}.#{recipient.id}@example.net" end - it "sets the expected openproject headers" do - expect(mail["X-OpenProject-User"]&.value) + it 'sets the expected openproject headers' do + expect(mail['X-OpenProject-User']&.value) .to eql recipient.name end - it "includes the notifications grouped by work package" do - time_stamp = journal.created_at.strftime("%m/%d/%Y, %I:%M %p") + it 'includes the notifications grouped by work package' do + time_stamp = journal.created_at.strftime('%m/%d/%Y, %I:%M %p') expect(mail_body) .to have_text("Hello #{recipient.firstname}") @@ -119,12 +119,12 @@ .to have_text(expected_text, normalize_ws: true) end - context "with only a deleted work package for the digest" do + context 'with only a deleted work package for the digest' do let(:work_package) { nil } it "is a NullMail which isn't sent" do expect(mail.body) - .to eql "" + .to eql '' expect(mail.header) .to eql({}) @@ -136,9 +136,9 @@ let!(:recipient) { create(:user) } let(:notifications) { [notification] } - context "when notification_wp_start_past" do + context 'when notification_wp_start_past' do let(:work_package) do - create(:work_package, subject: "WP start past", project: project1, start_date: 1.day.ago, type: Type.first) + create(:work_package, subject: 'WP start past', project: project1, start_date: 1.day.ago, type: Type.first) end let(:notification) do create(:notification, @@ -148,14 +148,14 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Start date was 1 day ago") + it 'matches generated text' do + expect(mail_body).to have_text('Start date was 1 day ago') end end - context "when notification_wp_start_future" do + context 'when notification_wp_start_future' do let(:work_package) do - create(:work_package, subject: "WP start future", project: project1, start_date: 2.days.from_now, type: Type.first) + create(:work_package, subject: 'WP start future', project: project1, start_date: 2.days.from_now, type: Type.first) end let(:notification) do create(:notification, @@ -165,14 +165,14 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Start date is in 2 days") + it 'matches generated text' do + expect(mail_body).to have_text('Start date is in 2 days') end end - context "when notification_wp_due_past" do + context 'when notification_wp_due_past' do let(:work_package) do - create(:work_package, subject: "WP due past", project: project1, due_date: 3.days.ago, type: Type.first) + create(:work_package, subject: 'WP due past', project: project1, due_date: 3.days.ago, type: Type.first) end let(:notification) do create(:notification, @@ -182,14 +182,14 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Overdue since 3 days") + it 'matches generated text' do + expect(mail_body).to have_text('Overdue since 3 days') end end - context "when notification_wp_due_future" do + context 'when notification_wp_due_future' do let(:work_package) do - create(:work_package, subject: "WP due future", project: project1, due_date: 3.days.from_now, type: Type.first) + create(:work_package, subject: 'WP due future', project: project1, due_date: 3.days.from_now, type: Type.first) end let(:notification) do create(:notification, @@ -199,15 +199,15 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Finish date is in 3 days") + it 'matches generated text' do + expect(mail_body).to have_text('Finish date is in 3 days') end end - context "when notification_milestone_past" do + context 'when notification_milestone_past' do let(:milestone_type) { create(:type_milestone) } let(:work_package) do - create(:work_package, subject: "Milestone WP past", project: project1, type: milestone_type, due_date: 2.days.ago) + create(:work_package, subject: 'Milestone WP past', project: project1, type: milestone_type, due_date: 2.days.ago) end let(:notification) do create(:notification, @@ -217,15 +217,15 @@ project: project1) end - it "matches generated text" do + it 'matches generated text' do expect(mail_body).to include('Overdue since 2 days') end end - context "when notification_milestone_future" do + context 'when notification_milestone_future' do let(:milestone_type) { create(:type_milestone) } let(:work_package) do - create(:work_package, subject: "Milestone WP future", project: project1, type: milestone_type, due_date: 1.day.from_now) + create(:work_package, subject: 'Milestone WP future', project: project1, type: milestone_type, due_date: 1.day.from_now) end let(:notification) do create(:notification, @@ -235,13 +235,13 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Milestone date is in 1 day") + it 'matches generated text' do + expect(mail_body).to have_text('Milestone date is in 1 day') end end - context "when notification_wp_unset_date" do - let(:work_package) { create(:work_package, subject: "Unset date", project: project1, due_date: nil, type: Type.first) } + context 'when notification_wp_unset_date' do + let(:work_package) { create(:work_package, subject: 'Unset date', project: project1, due_date: nil, type: Type.first) } let(:notification) do create(:notification, reason: :date_alert_due_date, @@ -250,14 +250,14 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Finish date is deleted") + it 'matches generated text' do + expect(mail_body).to have_text('Finish date is deleted') end end - context "when notification_wp_due_today" do + context 'when notification_wp_due_today' do let(:work_package) do - create(:work_package, subject: "Due today", project: project1, due_date: Time.zone.today, type: Type.first) + create(:work_package, subject: 'Due today', project: project1, due_date: Time.zone.today, type: Type.first) end let(:notification) do create(:notification, @@ -267,14 +267,14 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Finish date is today") + it 'matches generated text' do + expect(mail_body).to have_text('Finish date is today') end end - context "when notification_wp_double_date_alert" do + context 'when notification_wp_double_date_alert' do let(:work_package) do - create(:work_package, subject: "Alert + Mention", project: project1, due_date: 1.day.from_now, type: Type.first) + create(:work_package, subject: 'Alert + Mention', project: project1, due_date: 1.day.from_now, type: Type.first) end let(:notification) do create(:notification, @@ -284,13 +284,13 @@ project: project1) end - it "matches generated text" do - expect(mail_body).to have_text("Finish date is in 1 day") + it 'matches generated text' do + expect(mail_body).to have_text('Finish date is in 1 day') end end - context "when notification is mentioned and no journal" do - let(:work_package) { create(:work_package, subject: "Unset date", project: project1, due_date: nil, type: Type.first) } + context 'when notification is mentioned and no journal' do + let(:work_package) { create(:work_package, subject: 'Unset date', project: project1, due_date: nil, type: Type.first) } let(:notification) do create(:notification, reason: :mentioned, @@ -300,7 +300,7 @@ journal: nil) end - it "does not send the email" do + it 'does not send the email' do expect(mail.body).to eq("") end end diff --git a/spec/mailers/member_mailer_spec.rb b/spec/mailers/member_mailer_spec.rb index 60cc51651387..bf469294c327 100644 --- a/spec/mailers/member_mailer_spec.rb +++ b/spec/mailers/member_mailer_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MemberMailer do include OpenProject::ObjectLinking @@ -51,7 +51,7 @@ end end - shared_examples_for "has a subject" do |key| + shared_examples_for 'has a subject' do |key| it "has a subject" do if project expect(subject.subject) @@ -63,10 +63,10 @@ end end - shared_examples_for "fails for a group" do + shared_examples_for 'fails for a group' do let(:principal) { build_stubbed(:group) } - it "raises an argument error" do + it 'raises an argument error' do # Calling .to in order to have the mail rendered expect { subject.to } .to raise_error ArgumentError @@ -76,29 +76,29 @@ shared_examples_for "sends a mail to the member's principal" do let(:principal) { build_stubbed(:group) } - it "raises an argument error" do + it 'raises an argument error' do # Calling .to in order to have the mail rendered expect { subject.to } .to raise_error ArgumentError end end - shared_examples_for "sets the expected message_id header" do - it "sets the expected message_id header" do - expect(subject["Message-ID"].value) + shared_examples_for 'sets the expected message_id header' do + it 'sets the expected message_id header' do + expect(subject['Message-ID'].value) .to eql "" end end - shared_examples_for "sets the expected openproject header" do - it "sets the expected openproject header" do - expect(subject["X-OpenProject-Project"].value) + shared_examples_for 'sets the expected openproject header' do + it 'sets the expected openproject header' do + expect(subject['X-OpenProject-Project'].value) .to eql project.identifier end end - shared_examples_for "has the expected body" do - let(:body) { subject.body.parts.detect { |part| part["Content-Type"].value == "text/html" }.body.to_s } + shared_examples_for 'has the expected body' do + let(:body) { subject.body.parts.detect { |part| part['Content-Type'].value == 'text/html' }.body.to_s } let(:i18n_params) do { project: project ? link_to_project(project, only_path: false) : nil, @@ -106,7 +106,7 @@ }.compact end - it "highlights the roles received" do + it 'highlights the roles received' do expected = <<~MSG
    • #{roles.first.name}
    • @@ -116,14 +116,14 @@ expect(body) .to be_html_eql(expected) - .at_path("body/table/tr/td/ul") + .at_path('body/table/tr/td/ul') end - context "when current user and principal have different locales" do - let(:principal) { build_stubbed(:user, language: "fr") } - let(:current_user) { build_stubbed(:user, language: "de") } + context 'when current user and principal have different locales' do + let(:principal) { build_stubbed(:user, language: 'fr') } + let(:current_user) { build_stubbed(:user, language: 'de') } - it "is in the locale of the recipient" do + it 'is in the locale of the recipient' do OpenProject::LocaleHelper.with_locale_for(principal) do i18n_params end @@ -131,71 +131,71 @@ end end - context "with a custom message" do + context 'with a custom message' do let(:message) { "Some **styled** message" } - it "has the expected header" do + it 'has the expected header' do expect(body) .to include(I18n.t(:"#{expected_header}.with_message", **i18n_params)) end - it "includes the custom message" do + it 'includes the custom message' do expect(body) .to include("Some styled message") end end - context "without a custom message" do - it "has the expected header" do + context 'without a custom message' do + it 'has the expected header' do expect(body) .to include(I18n.t(:"#{expected_header}.without_message", **i18n_params)) end end end - describe "#added_project" do + describe '#added_project' do subject { described_class.added_project(current_user, member, message) } it_behaves_like "sends a mail to the member's principal" - it_behaves_like "has a subject", :"mail_member_added_project.subject" - it_behaves_like "sets the expected message_id header" - it_behaves_like "sets the expected openproject header" - it_behaves_like "has the expected body" do + it_behaves_like 'has a subject', :'mail_member_added_project.subject' + it_behaves_like 'sets the expected message_id header' + it_behaves_like 'sets the expected openproject header' + it_behaves_like 'has the expected body' do let(:expected_header) do "mail_member_added_project.body.added_by" end end - it_behaves_like "fails for a group" + it_behaves_like 'fails for a group' end - describe "#updated_project" do + describe '#updated_project' do subject { described_class.updated_project(current_user, member, message) } it_behaves_like "sends a mail to the member's principal" - it_behaves_like "has a subject", :"mail_member_updated_project.subject" - it_behaves_like "sets the expected message_id header" - it_behaves_like "sets the expected openproject header" - it_behaves_like "has the expected body" do + it_behaves_like 'has a subject', :'mail_member_updated_project.subject' + it_behaves_like 'sets the expected message_id header' + it_behaves_like 'sets the expected openproject header' + it_behaves_like 'has the expected body' do let(:expected_header) do "mail_member_updated_project.body.updated_by" end end - it_behaves_like "fails for a group" + it_behaves_like 'fails for a group' end - describe "#updated_global" do + describe '#updated_global' do let(:project) { nil } subject { described_class.updated_global(current_user, member, message) } it_behaves_like "sends a mail to the member's principal" - it_behaves_like "has a subject", :"mail_member_updated_global.subject" - it_behaves_like "sets the expected message_id header" - it_behaves_like "has the expected body" do + it_behaves_like 'has a subject', :'mail_member_updated_global.subject' + it_behaves_like 'sets the expected message_id header' + it_behaves_like 'has the expected body' do let(:expected_header) do "mail_member_updated_global.body.updated_by" end end - it_behaves_like "fails for a group" + it_behaves_like 'fails for a group' end end diff --git a/spec/mailers/previews/digest_mailer_preview.rb b/spec/mailers/previews/digest_mailer_preview.rb index e43ee6ff0b3d..1f731cc62447 100644 --- a/spec/mailers/previews/digest_mailer_preview.rb +++ b/spec/mailers/previews/digest_mailer_preview.rb @@ -30,7 +30,7 @@ class DigestMailerPreview < ActionMailer::Preview # Preview emails at http://localhost:3000/rails/mailers/digest_mailer def work_packages - notifications = Notification.where(resource_type: "WorkPackage") + notifications = Notification.where(resource_type: 'WorkPackage') DigestMailer.work_packages(notifications.first.recipient_id, [notifications.ids]) end end diff --git a/spec/mailers/previews/meeting_mailer_preview.rb b/spec/mailers/previews/meeting_mailer_preview.rb index c398babad5d7..63fc587e4c3d 100644 --- a/spec/mailers/previews/meeting_mailer_preview.rb +++ b/spec/mailers/previews/meeting_mailer_preview.rb @@ -30,8 +30,8 @@ class MeetingMailerPreview < ActionMailer::Preview # Preview emails at http://localhost:3000/rails/mailers/meeting_mailer def rescheduled - language = params["locale"] || I18n.default_locale - actor = FactoryBot.build_stubbed(:user, lastname: "Actor") + language = params['locale'] || I18n.default_locale + actor = FactoryBot.build_stubbed(:user, lastname: 'Actor') user = FactoryBot.build_stubbed(:user, language:) meeting = FactoryBot.build_stubbed(:meeting, start_time: 1.day.from_now, duration: 1.0) @@ -46,8 +46,8 @@ def rescheduled end def invited - language = params["locale"] || I18n.default_locale - actor = FactoryBot.build_stubbed(:user, lastname: "Actor") + language = params['locale'] || I18n.default_locale + actor = FactoryBot.build_stubbed(:user, lastname: 'Actor') user = FactoryBot.build_stubbed(:user, language:) meeting = FactoryBot.build_stubbed(:meeting) diff --git a/spec/mailers/previews/sharing_mailer_preview.rb b/spec/mailers/previews/sharing_mailer_preview.rb index 69ad3e2ecb4c..d1d69b00d216 100644 --- a/spec/mailers/previews/sharing_mailer_preview.rb +++ b/spec/mailers/previews/sharing_mailer_preview.rb @@ -31,7 +31,7 @@ class SharingMailerPreview < ActionMailer::Preview def shared_work_package sharer = User.first - work_package_membership = Member.where(entity_type: "WorkPackage").first + work_package_membership = Member.where(entity_type: 'WorkPackage').first SharingMailer.shared_work_package(sharer, work_package_membership) end @@ -39,7 +39,7 @@ def shared_work_package def shared_work_package_via_group sharer = User.first group = Group.first - user_membership = Member.find_by(entity_type: "WorkPackage", principal: group.users.first) + user_membership = Member.find_by(entity_type: 'WorkPackage', principal: group.users.first) SharingMailer.shared_work_package(sharer, user_membership, group) end @@ -47,7 +47,7 @@ def shared_work_package_via_group def shared_work_package_via_invitation sharer = User.first work_package_membership = Member.includes(:principal) - .where(entity_type: "WorkPackage") + .where(entity_type: 'WorkPackage') .where(principal: { status: :invited }) .first diff --git a/spec/mailers/shared_examples.rb b/spec/mailers/shared_examples.rb index ebcb2eeea36a..389f5af2135f 100644 --- a/spec/mailers/shared_examples.rb +++ b/spec/mailers/shared_examples.rb @@ -1,29 +1,29 @@ -RSpec.shared_examples_for "mail is sent" do +RSpec.shared_examples_for 'mail is sent' do let(:letters_sent_count) { 1 } let(:mail) { deliveries.first } - let(:html_body) { mail.body.parts.detect { |p| p.content_type.include? "text/html" }.body.encoded } + let(:html_body) { mail.body.parts.detect { |p| p.content_type.include? 'text/html' }.body.encoded } - it "actually sends a mail" do + it 'actually sends a mail' do expect(deliveries.size).to eql(letters_sent_count) end - it "is sent to the recipient" do + it 'is sent to the recipient' do expect(deliveries.first.to).to include(recipient.mail) end - it "is sent from the configured address" do + it 'is sent from the configured address' do expect(deliveries.first.from).to contain_exactly(Setting.mail_from) end end -RSpec.shared_examples_for "multiple mails are sent" do |set_letters_sent_count| - it_behaves_like "mail is sent" do +RSpec.shared_examples_for 'multiple mails are sent' do |set_letters_sent_count| + it_behaves_like 'mail is sent' do let(:letters_sent_count) { set_letters_sent_count } end end -RSpec.shared_examples_for "mail is not sent" do - it "sends no mail" do +RSpec.shared_examples_for 'mail is not sent' do + it 'sends no mail' do expect(deliveries).to be_empty end end diff --git a/spec/mailers/sharing_mailer_spec.rb b/spec/mailers/sharing_mailer_spec.rb index fde0d7d4891d..fc4ebecdb9e3 100644 --- a/spec/mailers/sharing_mailer_spec.rb +++ b/spec/mailers/sharing_mailer_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SharingMailer do let(:project) { build_stubbed(:project) } @@ -49,7 +49,7 @@ let(:current_user) { build_stubbed(:user) } - describe "#shared_work_package" do + describe '#shared_work_package' do subject(:mail) do described_class.shared_work_package(current_user, work_package_member) end @@ -61,26 +61,26 @@ it "sets the appropriate subject" do expect(mail.subject) - .to eq(I18n.t("mail.sharing.work_packages.subject", + .to eq(I18n.t('mail.sharing.work_packages.subject', id: work_package.id)) end - it "has a project header" do - expect(mail["X-OpenProject-Project"].value) + it 'has a project header' do + expect(mail['X-OpenProject-Project'].value) .to eq(project.identifier) end - it "has a work package id header" do - expect(mail["X-OpenProject-WorkPackage-Id"].value) + it 'has a work package id header' do + expect(mail['X-OpenProject-WorkPackage-Id'].value) .to eq(work_package.id.to_s) end - it "has a type header" do - expect(mail["X-OpenProject-Type"].value) - .to eq("WorkPackage") + it 'has a type header' do + expect(mail['X-OpenProject-Type'].value) + .to eq('WorkPackage') end - it "has a message id header" do + it 'has a message id header' do Timecop.freeze(Time.current) do expect(mail.message_id) .to eq("op.member-#{work_package_member.id}.#{Time.current.strftime('%Y%m%d%H%M%S')}.#{current_user.id}@example.net") diff --git a/spec/mailers/smtp_settings_spec.rb b/spec/mailers/smtp_settings_spec.rb index fc0c87acce18..56c90b0aa380 100644 --- a/spec/mailers/smtp_settings_spec.rb +++ b/spec/mailers/smtp_settings_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "SMTP settings" do let(:smtp_settings) { {} } @@ -128,11 +128,11 @@ def send_mail context "with SSL enabled and verification disabled" do let(:ssl) { true } - let(:openssl_verify_mode) { "none" } + let(:openssl_verify_mode) { 'none' } before do expect(smtp_settings[:ssl]).to be true - expect(smtp_settings[:openssl_verify_mode]).to eq "none" + expect(smtp_settings[:openssl_verify_mode]).to eq 'none' expect_any_instance_of(Net::SMTP).to receive(:start) do |instance| expect(instance).to be_tls diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb index 43231d9b0914..bed4a396ae6d 100644 --- a/spec/mailers/user_mailer_spec.rb +++ b/spec/mailers/user_mailer_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe UserMailer do subject(:deliveries) { ActionMailer::Base.deliveries } @@ -61,49 +61,49 @@ allow(journal).to receive(:journable).and_return(work_package) allow(journal).to receive(:user).and_return(user) - allow(Setting).to receive(:mail_from).and_return("john@doe.com") - allow(Setting).to receive(:host_name).and_return("mydomain.foo") - allow(Setting).to receive(:protocol).and_return("http") - allow(Setting).to receive(:default_language).and_return("en") + allow(Setting).to receive(:mail_from).and_return('john@doe.com') + allow(Setting).to receive(:host_name).and_return('mydomain.foo') + allow(Setting).to receive(:protocol).and_return('http') + allow(Setting).to receive(:default_language).and_return('en') end - describe "#with_deliveries" do - context "with false" do + describe '#with_deliveries' do + context 'with false' do before do described_class.with_deliveries(false) do described_class.test_mail(recipient).deliver_now end end - it_behaves_like "mail is not sent" + it_behaves_like 'mail is not sent' end - context "with true" do + context 'with true' do before do described_class.with_deliveries(true) do described_class.test_mail(recipient).deliver_now end end - it_behaves_like "mail is sent" + it_behaves_like 'mail is sent' end end - describe "#test_mail" do - let(:test_email) { "bob.bobbi@example.com" } - let(:recipient) { build_stubbed(:user, firstname: "Bob", lastname: "Bobbi", mail: test_email) } + describe '#test_mail' do + let(:test_email) { 'bob.bobbi@example.com' } + let(:recipient) { build_stubbed(:user, firstname: 'Bob', lastname: 'Bobbi', mail: test_email) } before do described_class.test_mail(recipient).deliver_now end - it_behaves_like "mail is sent" do - it "has the expected subject" do + it_behaves_like 'mail is sent' do + it 'has the expected subject' do expect(deliveries.first.subject) - .to eql "OpenProject Test" + .to eql 'OpenProject Test' end - it "includes the url to the instance" do + it 'includes the url to the instance' do expect(deliveries.first.body.encoded) .to match Regexp.new("OpenProject URL: #{Setting.protocol}://#{Setting.host_name}") end @@ -112,30 +112,30 @@ # the name method uses a format setting to determine how to concatenate first name # and last name whereby an unescaped comma will lead to have two email addresses # defined instead of one (['Bobbi', 'bob.bobbi@example.com'] vs. ['bob.bobbi@example.com']) - context "with the user name setting prone to trip up email address separation", + context 'with the user name setting prone to trip up email address separation', with_settings: { user_format: :lastname_coma_firstname } do - it_behaves_like "mail is sent" + it_behaves_like 'mail is sent' end - context "with the recipient being the system user" do + context 'with the recipient being the system user' do let(:recipient) { User.system } - it_behaves_like "mail is not sent" + it_behaves_like 'mail is not sent' end end - describe "#backup_ready" do + describe '#backup_ready' do before do described_class.backup_ready(recipient).deliver_now end - it_behaves_like "mail is sent" do - it "has the expected subject" do + it_behaves_like 'mail is sent' do + it 'has the expected subject' do expect(deliveries.first.subject) .to eql I18n.t("mail_subject_backup_ready") end - it "includes the url to the instance" do + it 'includes the url to the instance' do expect(deliveries.first.body.encoded) .to match Regexp.union( /Your requested backup is ready. You can download it here/, @@ -145,17 +145,17 @@ end end - describe "#wiki_page_added" do + describe '#wiki_page_added' do let(:wiki_page) { create(:wiki_page) } before do described_class.wiki_page_added(recipient, wiki_page).deliver_now end - it_behaves_like "mail is sent" + it_behaves_like 'mail is sent' end - describe "#wiki_page_updated" do + describe '#wiki_page_updated' do let(:wiki_page) { create(:wiki_page) } let(:wiki_page_journal) { build_stubbed(:wiki_page_journal) } @@ -164,23 +164,23 @@ described_class.wiki_page_updated(recipient, wiki_page).deliver_now end - it_behaves_like "mail is sent" + it_behaves_like 'mail is sent' - it "links to the latest version diff page" do + it 'links to the latest version diff page' do expect(deliveries.first.body.encoded).to include "diff/#{wiki_page.version}" end - it "uses the author from the journal" do + it 'uses the author from the journal' do expect(deliveries.first.body.encoded).to include wiki_page_journal.user.name end end - describe "#message_posted" do + describe '#message_posted' do before do described_class.message_posted(recipient, message).deliver_now end - context "for a message without a parent" do + context 'for a message without a parent' do let(:message) do build_stubbed(:message).tap do |msg| allow(msg) @@ -189,18 +189,18 @@ end end - it_behaves_like "mail is sent" do - it "carries a message_id" do + it_behaves_like 'mail is sent' do + it 'carries a message_id' do expect(deliveries.first.message_id) .to eql "op.message-#{message.id}.#{current_time.strftime('%Y%m%d%H%M%S')}.#{recipient.id}@doe.com" end - it "references the message" do + it 'references the message' do expect(deliveries.first.references) .to eql "op.message-#{message.id}@doe.com" end - it "includes a link to the message" do + it 'includes a link to the message' do expect(html_body) .to have_link(message.subject, href: topic_url(message, host: Setting.host_name, r: message.id, anchor: "message-#{message.id}")) @@ -208,7 +208,7 @@ end end - context "for a message with a parent" do + context 'for a message with a parent' do let(:parent) do build_stubbed(:message) end @@ -221,13 +221,13 @@ end end - it_behaves_like "mail is sent" do - it "carries a message_id" do + it_behaves_like 'mail is sent' do + it 'carries a message_id' do expect(deliveries.first.message_id) .to eql "op.message-#{message.id}.#{current_time.strftime('%Y%m%d%H%M%S')}.#{recipient.id}@doe.com" end - it "references the message" do + it 'references the message' do expect(deliveries.first.references) .to eql %W[op.message-#{parent.id}@doe.com op.message-#{message.id}@doe.com] @@ -236,28 +236,28 @@ end end - describe "#account_information" do + describe '#account_information' do let(:pwd) { "pAsswORd" } before do described_class.account_information(recipient, pwd).deliver_now end - it_behaves_like "mail is sent" do - it "includes the password" do + it_behaves_like 'mail is sent' do + it 'includes the password' do expect(html_body) .to have_content(pwd) end end end - describe "#incoming_email_error" do - let(:logs) { ["info: foo", "error: bar"] } + describe '#incoming_email_error' do + let(:logs) { ['info: foo', 'error: bar'] } let(:recipient) { user } let(:current_time) { "2022-11-03 9:15".to_time } - let(:mail_subject) { "New work package 42" } - let(:message_id) { "000501c8d452$a95cd7e0$0a00a8c0@osiris" } - let(:from) { "l.lustig@openproject.com" } + let(:mail_subject) { 'New work package 42' } + let(:message_id) { '000501c8d452$a95cd7e0$0a00a8c0@osiris' } + let(:from) { 'l.lustig@openproject.com' } let(:body) { "Project: demo-project" } let(:incoming_email) do @@ -278,7 +278,7 @@ .deliver_now end - it_behaves_like "mail is sent" do + it_behaves_like 'mail is sent' do it "references the incoming email's subject in its own" do expect(outgoing_email.subject).to eql "Re: #{mail_subject}" end @@ -292,15 +292,15 @@ expect(html_body).to include body end - it "contains the date the mail was received" do + it 'contains the date the mail was received' do expect(html_body).to include "11/03/2022 09:15 AM" end - it "contains the email address from which the email was sent" do + it 'contains the email address from which the email was sent' do expect(html_body).to include from end - it "contains the logs" do + it 'contains the logs' do logs.each do |log| expect(html_body).to include log end @@ -308,27 +308,27 @@ end end - describe "#news_added" do + describe '#news_added' do let(:news) { build_stubbed(:news) } before do described_class.news_added(recipient, news).deliver_now end - it_behaves_like "mail is sent" do - it "carries a message_id" do + it_behaves_like 'mail is sent' do + it 'carries a message_id' do expect(mail.message_id) .to eql "op.news-#{news.id}.#{current_time.strftime('%Y%m%d%H%M%S')}.#{recipient.id}@doe.com" end - it "references the news" do + it 'references the news' do expect(deliveries.first.references) .to eql "op.news-#{news.id}@doe.com" end end end - describe "#news_comment_added" do + describe '#news_comment_added' do let(:news) { build_stubbed(:news) } let(:comment) { build_stubbed(:comment, commented: news) } @@ -336,8 +336,8 @@ described_class.news_comment_added(recipient, comment).deliver_now end - it_behaves_like "mail is sent" do - it "references the news and the comment" do + it_behaves_like 'mail is sent' do + it 'references the news and the comment' do expect(deliveries.first.references) .to eql %W[op.news-#{news.id}@doe.com op.comment-#{comment.id}@doe.com] @@ -345,7 +345,7 @@ end end - describe "#password_lost" do + describe '#password_lost' do let(:token) { build_stubbed(:recovery_token) } let(:recipient) { token.user } @@ -353,8 +353,8 @@ described_class.password_lost(token).deliver_now end - it_behaves_like "mail is sent" do - it "includes a link to reset" do + it_behaves_like 'mail is sent' do + it 'includes a link to reset' do url = account_lost_password_url(host: Setting.host_name, token: token.value) expect(html_body) @@ -364,7 +364,7 @@ end end - describe "#user_signed_up" do + describe '#user_signed_up' do let(:token) { build_stubbed(:invitation_token) } let(:recipient) { token.user } @@ -372,8 +372,8 @@ described_class.user_signed_up(token).deliver_now end - it_behaves_like "mail is sent" do - it "includes a link to activate" do + it_behaves_like 'mail is sent' do + it 'includes a link to activate' do url = account_activate_url(host: Setting.host_name, token: token.value) expect(html_body) @@ -383,66 +383,66 @@ end end - describe "localization" do - context "with the user having a language configured", + describe 'localization' do + context 'with the user having a language configured', with_settings: { available_languages: %w[en de], - default_language: "en", + default_language: 'en', emails_header: { - "de" => "deutscher header", - "en" => "english header" + "de" => 'deutscher header', + "en" => 'english header' } } do let(:recipient) do - build_stubbed(:user, language: "de") + build_stubbed(:user, language: 'de') end before do - described_class.account_information(recipient, "pwd").deliver_now + described_class.account_information(recipient, 'pwd').deliver_now end - it "uses the recipients language" do - expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? "text/html" }.body.encoded) + it 'uses the recipients language' do + expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? 'text/html' }.body.encoded) .to include I18n.t(:mail_body_account_information, locale: :de) end - it "does not alter I18n.locale" do + it 'does not alter I18n.locale' do expect(I18n.locale) .to be :en end - it "include the user language header" do - expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? "text/html" }.body.encoded) - .to include "deutscher header" + it 'include the user language header' do + expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? 'text/html' }.body.encoded) + .to include 'deutscher header' end end - context "with the user having no language configured", + context 'with the user having no language configured', with_settings: { available_languages: %w[en de], - default_language: "en", + default_language: 'en', emails_header: { - "de" => "deutscher header", - "en" => "english header" + "de" => 'deutscher header', + "en" => 'english header' } } do let(:recipient) do - build_stubbed(:user, language: "") + build_stubbed(:user, language: '') end before do I18n.locale = :de - described_class.account_information(recipient, "pwd").deliver_now + described_class.account_information(recipient, 'pwd').deliver_now end - it "uses the default language" do - expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? "text/html" }.body.encoded) + it 'uses the default language' do + expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? 'text/html' }.body.encoded) .to include I18n.t(:mail_body_account_information, locale: :en) end - it "include the default language header" do - expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? "text/html" }.body.encoded) - .to include "english header" + it 'include the default language header' do + expect(ActionMailer::Base.deliveries.last.body.parts.detect { |p| p.content_type.include? 'text/html' }.body.encoded) + .to include 'english header' end - it "does not alter I18n.locale" do + it 'does not alter I18n.locale' do expect(I18n.locale) .to be :de end diff --git a/spec/mailers/work_package_mailer_spec.rb b/spec/mailers/work_package_mailer_spec.rb index 0b23b27c8a29..b334c7f4c6f8 100644 --- a/spec/mailers/work_package_mailer_spec.rb +++ b/spec/mailers/work_package_mailer_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_examples" +require 'spec_helper' +require_relative 'shared_examples' RSpec.describe WorkPackageMailer do include OpenProject::ObjectLinking @@ -50,50 +50,50 @@ user: author) end - describe "#mentioned" do + describe '#mentioned' do subject(:mail) { described_class.mentioned(recipient, journal) } it "has a subject" do expect(mail.subject) - .to eql I18n.t(:"mail.mention.subject", + .to eql I18n.t(:'mail.mention.subject', user_name: author.name, id: work_package.id, subject: work_package.subject) end - it "is sent to the recipient" do + it 'is sent to the recipient' do expect(mail.to) .to contain_exactly(recipient.mail) end - it "has a project header" do - expect(mail["X-OpenProject-Project"].value) + it 'has a project header' do + expect(mail['X-OpenProject-Project'].value) .to eql project.identifier end - it "has a work package id header" do - expect(mail["X-OpenProject-WorkPackage-Id"].value) + it 'has a work package id header' do + expect(mail['X-OpenProject-WorkPackage-Id'].value) .to eql work_package.id.to_s end - it "has a work package author header" do - expect(mail["X-OpenProject-WorkPackage-Author"].value) + it 'has a work package author header' do + expect(mail['X-OpenProject-WorkPackage-Author'].value) .to eql work_package.author.login end - it "has a type header" do - expect(mail["X-OpenProject-Type"].value) - .to eql "WorkPackage" + it 'has a type header' do + expect(mail['X-OpenProject-Type'].value) + .to eql 'WorkPackage' end - it "has a message id header" do + it 'has a message id header' do Timecop.freeze(Time.current) do expect(mail.message_id) .to eql "op.journal-#{journal.id}.#{Time.current.strftime('%Y%m%d%H%M%S')}.#{recipient.id}@example.net" end end - it "has a references header" do + it 'has a references header' do journal_part = "op.journal-#{journal.id}@example.net" work_package_part = "op.work_package-#{work_package.id}@example.net" @@ -101,40 +101,40 @@ .to eql [work_package_part, journal_part] end - it "has a work package assignee header" do - expect(mail["X-OpenProject-WorkPackage-Assignee"].value) + it 'has a work package assignee header' do + expect(mail['X-OpenProject-WorkPackage-Assignee'].value) .to eql work_package.assigned_to.login end end - describe "#watcher_changed" do + describe '#watcher_changed' do subject(:deliveries) { ActionMailer::Base.deliveries } let(:watcher_changer) { author } - context "for an added watcher" do - subject(:mail) { described_class.watcher_changed(work_package, recipient, author, "added") } + context 'for an added watcher' do + subject(:mail) { described_class.watcher_changed(work_package, recipient, author, 'added') } - it "contains the WP subject in the mail subject" do + it 'contains the WP subject in the mail subject' do expect(mail.subject) .to include(work_package.subject) end - it "has a references header" do + it 'has a references header' do expect(mail.references) .to eql "op.work_package-#{work_package.id}@example.net" end end - context "for a removed watcher" do - subject(:mail) { described_class.watcher_changed(work_package, recipient, author, "removed") } + context 'for a removed watcher' do + subject(:mail) { described_class.watcher_changed(work_package, recipient, author, 'removed') } - it "contains the WP subject in the mail subject" do + it 'contains the WP subject in the mail subject' do expect(mail.subject) .to include(work_package.subject) end - it "has a references header" do + it 'has a references header' do expect(mail.references) .to eql "op.work_package-#{work_package.id}@example.net" end diff --git a/spec/migrations/change_default_value_of_alternative_color_spec.rb b/spec/migrations/change_default_value_of_alternative_color_spec.rb index f9a19ec3c1f6..dee6f390e3b5 100644 --- a/spec/migrations/change_default_value_of_alternative_color_spec.rb +++ b/spec/migrations/change_default_value_of_alternative_color_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("db/migrate/20240306083241_change_default_value_of_alternative_color.rb") RSpec.describe ChangeDefaultValueOfAlternativeColor, type: :model do - context "when migrating up" do - context "when there is no custom value set" do + context 'when migrating up' do + context 'when there is no custom value set' do let(:design_color) do DesignColor.new variable: "alternative-color", hexcode: OpenProject::CustomStyles::ColorThemes::DEPRECATED_ALTERNATIVE_COLOR @@ -46,13 +46,13 @@ it "changes the default value" do expect { subject } - .to change { DesignColor.where(variable: "alternative-color").first.hexcode } + .to change { DesignColor.where(variable: 'alternative-color').first.hexcode } .from(OpenProject::CustomStyles::ColorThemes::DEPRECATED_ALTERNATIVE_COLOR) .to(OpenProject::CustomStyles::ColorThemes::PRIMER_PRIMARY_BUTTON_COLOR) end end - context "when there is a custom value set" do + context 'when there is a custom value set' do let(:design_color) do DesignColor.new variable: "alternative-color", hexcode: "#AB1234" end @@ -66,13 +66,13 @@ it "does not change the default value" do expect { subject } - .not_to change { DesignColor.where(variable: "alternative-color").first.hexcode } + .not_to change { DesignColor.where(variable: 'alternative-color').first.hexcode } end end end - context "when migrating down" do - context "when there is no custom value set" do + context 'when migrating down' do + context 'when there is no custom value set' do let(:design_color) do DesignColor.new variable: "alternative-color", hexcode: OpenProject::CustomStyles::ColorThemes::PRIMER_PRIMARY_BUTTON_COLOR @@ -87,13 +87,13 @@ it "changes the default value" do expect { subject } - .to change { DesignColor.where(variable: "alternative-color").first.hexcode } + .to change { DesignColor.where(variable: 'alternative-color').first.hexcode } .from(OpenProject::CustomStyles::ColorThemes::PRIMER_PRIMARY_BUTTON_COLOR) .to(OpenProject::CustomStyles::ColorThemes::DEPRECATED_ALTERNATIVE_COLOR) end end - context "when there is a custom value set" do + context 'when there is a custom value set' do let(:design_color) do DesignColor.new variable: "alternative-color", hexcode: "#AB1234" end @@ -107,7 +107,7 @@ it "does not change the default value" do expect { subject } - .not_to change { DesignColor.where(variable: "alternative-color").first.hexcode } + .not_to change { DesignColor.where(variable: 'alternative-color').first.hexcode } end end end diff --git a/spec/migrations/fix_invalid_journals_spec.rb b/spec/migrations/fix_invalid_journals_spec.rb index e105c3c860fc..5ed59c31acc6 100644 --- a/spec/migrations/fix_invalid_journals_spec.rb +++ b/spec/migrations/fix_invalid_journals_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("db/migrate/20220818074150_fix_invalid_journals.rb") RSpec.describe FixInvalidJournals, type: :model do @@ -100,7 +100,7 @@ run_migration end - it "removes invalid journals and its associations", :aggregate_failures do + it 'removes invalid journals and its associations', :aggregate_failures do expect(Journal.find_by(id: invalid_journal.id)).to be_nil expect(Journal::AttachableJournal.find_by(journal_id: invalid_journal.id)).to be_nil diff --git a/spec/migrations/fix_untranslated_work_package_roles_spec.rb b/spec/migrations/fix_untranslated_work_package_roles_spec.rb index b21e7dca18c0..b28cc5c37cfa 100644 --- a/spec/migrations/fix_untranslated_work_package_roles_spec.rb +++ b/spec/migrations/fix_untranslated_work_package_roles_spec.rb @@ -26,39 +26,39 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("db/migrate/20240206173841_fix_untranslated_work_package_roles.rb") RSpec.describe FixUntranslatedWorkPackageRoles, type: :model do # Silencing migration logs, since we are not interested in that during testing subject(:run_migration) { ActiveRecord::Migration.suppress_messages { described_class.new.up } } - context "when work package roles are already present" do + context 'when work package roles are already present' do before do - create(:work_package_role, builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_EDITOR, name: "foo") - create(:work_package_role, builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_COMMENTER, name: "bar") - create(:work_package_role, builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_VIEWER, name: "baz") + create(:work_package_role, builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_EDITOR, name: 'foo') + create(:work_package_role, builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_COMMENTER, name: 'bar') + create(:work_package_role, builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_VIEWER, name: 'baz') end - it "updates them with correct names" do + it 'updates them with correct names' do expect { run_migration } .not_to change(WorkPackageRole, :count).from(3) expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_EDITOR)) - .to have_attributes(name: "Work package editor") + .to have_attributes(name: 'Work package editor') expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_COMMENTER)) - .to have_attributes(name: "Work package commenter") + .to have_attributes(name: 'Work package commenter') expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_VIEWER)) - .to have_attributes(name: "Work package viewer") + .to have_attributes(name: 'Work package viewer') end [ - "OPENPROJECT_SEED_LOCALE", - "OPENPROJECT_DEFAULT_LANGUAGE" + 'OPENPROJECT_SEED_LOCALE', + 'OPENPROJECT_DEFAULT_LANGUAGE' ].each do |env_var_name| describe "when #{env_var_name} is set with a non-English language", :settings_reset do - it "renames the work package roles in the language specified", :settings_reset do - with_env(env_var_name => "de") do + it 'renames the work package roles in the language specified', :settings_reset do + with_env(env_var_name => 'de') do reset(:default_language) run_migration ensure @@ -66,25 +66,25 @@ end expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_EDITOR)) - .to have_attributes(name: "Arbeitspaket-Bearbeiter") + .to have_attributes(name: 'Arbeitspaket-Bearbeiter') expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_COMMENTER)) - .to have_attributes(name: "Arbeitspaket-Kommentator") + .to have_attributes(name: 'Arbeitspaket-Kommentator') expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_VIEWER)) - .to have_attributes(name: "Arbeitspaket-Betrachter") + .to have_attributes(name: 'Arbeitspaket-Betrachter') end end describe "when #{env_var_name} is set with an unsupported language", :settings_reset do - it "uses the English name", :settings_reset do - allow(Settings).to receive(:default_language).and_return("pt-br") + it 'uses the English name', :settings_reset do + allow(Settings).to receive(:default_language).and_return('pt-br') run_migration expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_EDITOR)) - .to have_attributes(name: "Work package editor") + .to have_attributes(name: 'Work package editor') expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_COMMENTER)) - .to have_attributes(name: "Work package commenter") + .to have_attributes(name: 'Work package commenter') expect(WorkPackageRole.find_by(builtin: WorkPackageRole::BUILTIN_WORK_PACKAGE_VIEWER)) - .to have_attributes(name: "Work package viewer") + .to have_attributes(name: 'Work package viewer') end end end diff --git a/spec/migrations/migrate_team_planner_permissions_spec.rb b/spec/migrations/migrate_team_planner_permissions_spec.rb index ea900fa394a0..1be41a5bd649 100644 --- a/spec/migrations/migrate_team_planner_permissions_spec.rb +++ b/spec/migrations/migrate_team_planner_permissions_spec.rb @@ -26,32 +26,32 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("db/migrate/20220414085531_migrate_team_planner_permissions.rb") RSpec.describe MigrateTeamPlannerPermissions, type: :model do # Silencing migration logs, since we are not interested in that during testing subject { ActiveRecord::Migration.suppress_messages { described_class.new.up } } - shared_examples_for "not changing permissions" do - it "is not changed" do + shared_examples_for 'not changing permissions' do + it 'is not changed' do expect { subject }.not_to change { role.reload.permissions } end - it "does not adds any new permissions" do + it 'does not adds any new permissions' do expect { subject }.not_to change(RolePermission, :count) end end - shared_examples_for "migration is idempotent" do - context "when the migration is ran twice" do + shared_examples_for 'migration is idempotent' do + context 'when the migration is ran twice' do before { subject } - it_behaves_like "not changing permissions" + it_behaves_like 'not changing permissions' end end - shared_examples_for "adding permissions" do |new_permissions| + shared_examples_for 'adding permissions' do |new_permissions| it "adds the #{new_permissions} permissions for the role" do public_permissions = OpenProject::AccessControl.public_permissions.map(&:name) expect { subject }.to change { role.reload.permissions } @@ -64,70 +64,70 @@ end end - context "for a role not eligible to view_team_planner" do + context 'for a role not eligible to view_team_planner' do let!(:role) { create(:project_role, permissions: %i[permission1 permission2]) } - it_behaves_like "not changing permissions" - it_behaves_like "migration is idempotent" + it_behaves_like 'not changing permissions' + it_behaves_like 'migration is idempotent' end - context "for a role eligible to view_team_planner" do + context 'for a role eligible to view_team_planner' do let(:permissions) { %i[view_work_packages permission1 permission2] } let!(:role) { create(:project_role, permissions:) } - it_behaves_like "adding permissions", %i[view_team_planner] - it_behaves_like "migration is idempotent" + it_behaves_like 'adding permissions', %i[view_team_planner] + it_behaves_like 'migration is idempotent' end - context "for a role with view_team_planner" do + context 'for a role with view_team_planner' do let(:permissions) { %i[view_team_planner view_work_packages permission1 permission2] } let!(:role) { create(:project_role, permissions:) } - it_behaves_like "not changing permissions" - it_behaves_like "migration is idempotent" + it_behaves_like 'not changing permissions' + it_behaves_like 'migration is idempotent' end - context "for a role not eligible to manage_team_planner" do + context 'for a role not eligible to manage_team_planner' do let(:permissions) do %i[view_team_planner view_work_packages edit_work_packages save_queries manage_public_queries permission1 permission2] end let!(:role) { create(:project_role, permissions:) } - it_behaves_like "not changing permissions" - it_behaves_like "migration is idempotent" + it_behaves_like 'not changing permissions' + it_behaves_like 'migration is idempotent' end - context "for a role eligible to manage_team_planner having view_team_planner" do + context 'for a role eligible to manage_team_planner having view_team_planner' do let(:permissions) do %i[view_team_planner view_work_packages add_work_packages edit_work_packages save_queries manage_public_queries permission1 permission2] end let!(:role) { create(:project_role, permissions:) } - it_behaves_like "adding permissions", %i[manage_team_planner] - it_behaves_like "migration is idempotent" + it_behaves_like 'adding permissions', %i[manage_team_planner] + it_behaves_like 'migration is idempotent' end - context "for a role eligible to manage_team_planner not having view_team_planner" do + context 'for a role eligible to manage_team_planner not having view_team_planner' do let(:permissions) do %i[view_work_packages add_work_packages edit_work_packages save_queries manage_public_queries permission1 permission2] end let!(:role) { create(:project_role, permissions:) } - it_behaves_like "adding permissions", %i[manage_team_planner view_team_planner] - it_behaves_like "migration is idempotent" + it_behaves_like 'adding permissions', %i[manage_team_planner view_team_planner] + it_behaves_like 'migration is idempotent' end - context "for a role that already has the manage_team_planner and view_team_planner permission" do + context 'for a role that already has the manage_team_planner and view_team_planner permission' do let(:permissions) do %i[manage_team_planner view_team_planner view_work_packages add_work_packages edit_work_packages save_queries manage_public_queries permission1 permission2] end let!(:role) { create(:project_role, permissions:) } - it_behaves_like "not changing permissions" - it_behaves_like "migration is idempotent" + it_behaves_like 'not changing permissions' + it_behaves_like 'migration is idempotent' end end diff --git a/spec/migrations/reduce_configurable_design_variables_spec.rb b/spec/migrations/reduce_configurable_design_variables_spec.rb deleted file mode 100644 index 77e8dc63bee7..000000000000 --- a/spec/migrations/reduce_configurable_design_variables_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -require "spec_helper" -require Rails.root.join("db/migrate/20240307102541_reduce_configurable_design_variables.rb") - -RSpec.describe ReduceConfigurableDesignVariables, type: :model do - context "when migrating up" do - before do - create(:design_color, variable: "alternative-color") - create(:design_color, variable: "primary-color") - create(:design_color, variable: "primary-color-dark") - create(:design_color, variable: "content-link-color") - end - - # Silencing migration logs, since we are not interested in that during testing - subject { ActiveRecord::Migration.suppress_messages { described_class.new.up } } - - it "removes the obsolete variables and renames 'alternative-color'" do - expect { subject } - .to change(DesignColor, :count).from(4).to(2) - - expect(DesignColor.find_by(variable: "primary-button-color")).not_to be_nil - expect(DesignColor.find_by(variable: "accent-color")).not_to be_nil - expect(DesignColor.find_by(variable: "primary-color")).to be_nil - expect(DesignColor.find_by(variable: "primary-color-dark")).to be_nil - expect(DesignColor.find_by(variable: "alternative-color")).to be_nil - expect(DesignColor.find_by(variable: "content-link-color")).to be_nil - end - end - - context "when migrating down" do - before do - create(:design_color, variable: "primary-button-color") - create(:design_color, variable: "accent-color") - end - - # Silencing migration logs, since we are not interested in that during testing - subject { ActiveRecord::Migration.suppress_messages { described_class.new.down } } - - it "re-creates the removed variables and reverts the renaming" do - expect { subject } - .to change(DesignColor, :count).from(2).to(4) - - expect(DesignColor.find_by(variable: "primary-button-color")).to be_nil - expect(DesignColor.find_by(variable: "accent-color")).to be_nil - expect(DesignColor.find_by(variable: "primary-color")).not_to be_nil - expect(DesignColor.find_by(variable: "primary-color-dark")).not_to be_nil - expect(DesignColor.find_by(variable: "alternative-color")).not_to be_nil - expect(DesignColor.find_by(variable: "content-link-color")).not_to be_nil - - end - end -end diff --git a/spec/migrations/restore_defaults_on_empty_settings_spec.rb b/spec/migrations/restore_defaults_on_empty_settings_spec.rb index 90cf1e90453b..025b18024177 100644 --- a/spec/migrations/restore_defaults_on_empty_settings_spec.rb +++ b/spec/migrations/restore_defaults_on_empty_settings_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require Rails.root.join("db/migrate/20220428071221_restore_defaults_on_empty_settings.rb") RSpec.describe RestoreDefaultsOnEmptySettings, type: :model do @@ -42,14 +42,14 @@ Setting.create name: setting_name, value: "" end - it "migrates the value to the expected value" do + it 'migrates the value to the expected value' do expect { run_migration } .to change { Setting.find_by(name: setting_name).value } .from(old_value) .to(expected_value) end - it "does not raise a type error" do + it 'does not raise a type error' do expect { run_migration }.not_to raise_error end end @@ -86,7 +86,7 @@ context "with an empty setting which is not writable" do let(:setting_name) { "smtp_openssl_verify_mode" } - it "deletes the setting from the database" do + it 'deletes the setting from the database' do setting = Setting.new name: setting_name setting.set_value!("", force: true) setting.save! diff --git a/spec/models/actions/scopes/default_spec.rb b/spec/models/actions/scopes/default_spec.rb index f60a1056fa56..5d14b0a50b7a 100644 --- a/spec/models/actions/scopes/default_spec.rb +++ b/spec/models/actions/scopes/default_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Actions::Scopes::Default do subject(:scope) { Action.default } - describe ".default" do + describe '.default' do let(:expected) do # This complicated and programmatic way is chosen so that the test can deal with additional actions being defined format_action = ->(namespace, action, permission, global, module_name) do @@ -59,7 +59,7 @@ end end - it "contains all actions" do + it 'contains all actions' do expect(scope.pluck(:id, :permission, :global, :module)) .to match_array(expected) end diff --git a/spec/models/activities/fetcher_integration_spec.rb b/spec/models/activities/fetcher_integration_spec.rb index 921c4a13662a..2cca6e756b06 100644 --- a/spec/models/activities/fetcher_integration_spec.rb +++ b/spec/models/activities/fetcher_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Activities::Fetcher, "integration" do +RSpec.describe Activities::Fetcher, 'integration' do shared_let(:user) { create(:user) } shared_let(:permissions) { %i[view_work_packages view_time_entries view_changesets view_wiki_edits] } shared_let(:role) { create(:project_role, permissions:) } @@ -39,12 +39,12 @@ let(:instance) { described_class.new(user, options) } let(:options) { {} } - it "does not find budgets in its event_types" do + it 'does not find budgets in its event_types' do expect(instance.event_types) - .not_to include("budgets") + .not_to include('budgets') end - describe "#events" do + describe '#events' do let(:event_user) { user } let(:work_package) { create(:work_package, project:, author: event_user) } let(:forum) { create(:forum, project:) } @@ -55,64 +55,64 @@ let(:changeset) { create(:changeset, committer: event_user.login, repository:) } let(:wiki) { create(:wiki, project:) } let(:wiki_page) do - create(:wiki_page, wiki:, author: event_user, text: "some text") + create(:wiki_page, wiki:, author: event_user, text: 'some text') end subject { instance.events(from: 30.days.ago, to: 1.day.from_now) } - context "for global activities" do + context 'for global activities' do let!(:activities) { [project, work_package, message, news, time_entry, changeset, wiki_page] } - it "finds events of all types" do + it 'finds events of all types' do expect(subject.map(&:journable_id)) .to match_array(activities.map(&:id)) end - context "if lacking permissions" do + context 'if lacking permissions' do before do role.role_permissions.destroy_all end - it "finds only events for which permissions are satisfied" do + it 'finds only events for which permissions are satisfied' do # project attributes, news and message only require the user to be member expect(subject.map(&:journable_id)) .to contain_exactly(project.id, message.id, news.id) end end - context "if project has activity disabled" do + context 'if project has activity disabled' do before do - project.enabled_module_names = project.enabled_module_names - ["activity"] + project.enabled_module_names = project.enabled_module_names - ['activity'] end - it "finds no events" do + it 'finds no events' do expect(subject.map(&:journable_id)) .to be_empty end end - context "if restricting the scope" do + context 'if restricting the scope' do before do options[:scope] = %w(time_entries messages) end - it "finds only events matching the scope" do + it 'finds only events matching the scope' do expect(subject.map(&:journable_id)) .to contain_exactly(message.id, time_entry.id) end end end - context "for activities in a project" do + context 'for activities in a project' do let(:options) { { project: } } let!(:activities) { [project, work_package, message, news, time_entry, changeset, wiki_page] } - it "finds events of all types" do + it 'finds events of all types' do expect(subject.map(&:journable_id)) .to match_array(activities.map(&:id)) end - context "if lacking permissions" do + context 'if lacking permissions' do before do role .role_permissions @@ -122,37 +122,37 @@ .map(&:destroy) end - it "finds only events for which permissions are satisfied" do + it 'finds only events for which permissions are satisfied' do # project attributes, news and message only require the user to be member expect(subject.map(&:journable_id)) .to contain_exactly(project.id, message.id, news.id) end end - context "if project has activity disabled" do + context 'if project has activity disabled' do before do - project.enabled_module_names = project.enabled_module_names - ["activity"] + project.enabled_module_names = project.enabled_module_names - ['activity'] end - it "finds no events" do + it 'finds no events' do expect(subject.map(&:journable_id)) .to be_empty end end - context "if restricting the scope" do + context 'if restricting the scope' do before do options[:scope] = %w(time_entries messages) end - it "finds only events matching the scope" do + it 'finds only events matching the scope' do expect(subject.map(&:journable_id)) .to contain_exactly(message.id, time_entry.id) end end end - context "for activities in a subproject" do + context 'for activities in a subproject' do shared_let(:subproject) do create(:project, parent: project).tap do project.reload @@ -169,40 +169,40 @@ let!(:activities) { [project, subproject, news, subproject_news, work_package, subproject_work_package] } - context "if including subprojects" do + context 'if including subprojects' do before do subproject_member end let(:options) { { project:, with_subprojects: 1 } } - it "finds events in the subproject" do + it 'finds events in the subproject' do expect(subject.map(&:journable_id)) .to match_array(activities.map(&:id)) end end - context "if the subproject has activity disabled" do + context 'if the subproject has activity disabled' do before do - subproject.enabled_module_names -= ["activity"] + subproject.enabled_module_names -= ['activity'] end - it "lacks events from subproject" do + it 'lacks events from subproject' do expect(subject.map(&:journable_id)) .to contain_exactly(project.id, news.id, work_package.id) end end - context "if not member of the subproject" do + context 'if not member of the subproject' do let(:options) { { project:, with_subprojects: 1 } } - it "lacks events from subproject" do + it 'lacks events from subproject' do expect(subject.map(&:journable_id)) .to contain_exactly(project.id, news.id, work_package.id) end end - context "if lacking permissions for the subproject" do + context 'if lacking permissions for the subproject' do let(:options) { { project:, with_subprojects: 1 } } let!(:subproject_member) do create(:member, @@ -211,30 +211,30 @@ roles: [create(:project_role, permissions: [])]) end - it "finds only events for which permissions are satisfied" do + it 'finds only events for which permissions are satisfied' do # project attributes and news only require the user to be member expect(subject.map(&:journable_id)) .to contain_exactly(project.id, subproject.id, news.id, subproject_news.id, work_package.id) - expect(subject.filter { |e| e.event_type.starts_with?("work_package") }.map(&:journable_id)) + expect(subject.filter { |e| e.event_type.starts_with?('work_package') }.map(&:journable_id)) .not_to include(subproject_work_package.id) end end - context "if excluding subprojects" do + context 'if excluding subprojects' do before do subproject_member end let(:options) { { project:, with_subprojects: nil } } - it "lacks events from subproject" do + it 'lacks events from subproject' do expect(subject.map(&:journable_id)) .to contain_exactly(project.id, news.id, work_package.id) end end end - context "for activities of a user" do + context 'for activities of a user' do let(:options) { { author: user } } let!(:activities) do # Login to have all the journals created as the user @@ -242,50 +242,50 @@ [project, work_package, message, news, time_entry, changeset, wiki_page] end - it "finds events of all types" do + it 'finds events of all types' do expect(subject.map(&:journable_id)) .to match_array(activities.map(&:id)) end - context "for a different user" do + context 'for a different user' do let(:other_user) { create(:user) } let(:options) { { author: other_user } } - it "does not return the events made by the non queried for user" do + it 'does not return the events made by the non queried for user' do expect(subject.map(&:journable_id)) .to be_empty end end - context "if project has activity disabled" do + context 'if project has activity disabled' do before do - project.enabled_module_names = project.enabled_module_names - ["activity"] + project.enabled_module_names = project.enabled_module_names - ['activity'] end - it "finds no events" do + it 'finds no events' do expect(subject.map(&:journable_id)) .to be_empty end end - context "if lacking permissions" do + context 'if lacking permissions' do before do role.role_permissions.destroy_all end - it "finds only events for which permissions are satisfied" do + it 'finds only events for which permissions are satisfied' do # project attributes, news and message only require the user to be member expect(subject.map(&:journable_id)) .to contain_exactly(project.id, message.id, news.id) end end - context "if restricting the scope" do + context 'if restricting the scope' do before do options[:scope] = %w(time_entries messages) end - it "finds only events matching the scope" do + it 'finds only events matching the scope' do expect(subject.map(&:journable_id)) .to contain_exactly(message.id, time_entry.id) end diff --git a/spec/models/activities/work_package_activity_provider_spec.rb b/spec/models/activities/work_package_activity_provider_spec.rb index c5c6ee47c401..c3ac9b0dc8a4 100644 --- a/spec/models/activities/work_package_activity_provider_spec.rb +++ b/spec/models/activities/work_package_activity_provider_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Activities::WorkPackageActivityProvider do - let(:event_scope) { "work_packages" } - let(:work_package_edit_event) { "work_package-edit" } - let(:work_package_closed_event) { "work_package-closed" } + let(:event_scope) { 'work_packages' } + let(:work_package_edit_event) { 'work_package-edit' } + let(:work_package_closed_event) { 'work_package-closed' } let(:user) { create(:admin) } let(:role) { create(:project_role) } @@ -43,25 +43,25 @@ end let!(:work_packages) { [work_package] } - describe ".find_events" do - context "when a work package has been created" do + describe '.find_events' do + context 'when a work package has been created' do let(:subject) do Activities::WorkPackageActivityProvider .find_events(event_scope, user, Time.zone.yesterday.to_datetime, Time.zone.tomorrow.to_datetime, {}) end - it "has the edited event type" do + it 'has the edited event type' do expect(subject[0].event_type) .to eql(work_package_edit_event) end - it "has an id to the author stored" do + it 'has an id to the author stored' do expect(subject[0].author_id) .to eql(user.id) end end - context "should be selected and ordered correctly" do + context 'should be selected and ordered correctly' do let!(:work_packages) { (1..5).map { create(:work_package, author: user).id.to_s } } let(:subject) do @@ -73,7 +73,7 @@ it { is_expected.to eq(work_packages.last(3).reverse) } end - context "when a work package has been created and then closed" do + context 'when a work package has been created and then closed' do let(:subject) do Activities::WorkPackageActivityProvider .find_events(event_scope, user, Time.zone.yesterday.to_datetime, Time.zone.tomorrow.to_datetime, limit: 10) @@ -86,18 +86,18 @@ work_package.save(validate: false) end - it "only returns a single event (as it is aggregated)" do + it 'only returns a single event (as it is aggregated)' do expect(subject.count) .to be(1) end - it "has the closed event type" do + it 'has the closed event type' do expect(subject[0].event_type) .to eql(work_package_closed_event) end end - context "for a non admin user" do + context 'for a non admin user' do let(:project) { create(:project) } let(:child_project1) { create(:project, parent: project) } let(:child_project2) { create(:project, parent: project) } @@ -148,7 +148,7 @@ ) end - it "returns only visible work packages" do + it 'returns only visible work packages' do expect(subject.map(&:journable_id)) .to match_array([parent_work_package, child1_work_package, child4_work_package].map(&:id)) end diff --git a/spec/models/announcement_spec.rb b/spec/models/announcement_spec.rb index 2f36fed14b0c..4dcc6e85d561 100644 --- a/spec/models/announcement_spec.rb +++ b/spec/models/announcement_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Announcement do it do @@ -25,11 +25,11 @@ expect(subject).to respond_to :active= end - describe "class methods" do - describe "#only_one" do - context "WHEN no announcement exists" do + describe 'class methods' do + describe '#only_one' do + context 'WHEN no announcement exists' do it do - expect(Announcement.only_one.text).to eql "Announcement" + expect(Announcement.only_one.text).to eql 'Announcement' end it do @@ -39,64 +39,64 @@ it { expect(Announcement.only_one.active).to be false } end - context "WHEN an announcement exists" do + context 'WHEN an announcement exists' do let!(:announcement) { create(:announcement) } - it "returns the true one announcement" do + it 'returns the true one announcement' do expect(Announcement.only_one).to eql announcement end end end - describe "#active_and_current" do - describe "WHEN no announcement is active" do + describe '#active_and_current' do + describe 'WHEN no announcement is active' do let!(:announcement) { create(:inactive_announcement) } - it "returns no announcement" do + it 'returns no announcement' do expect(Announcement.active_and_current).to be_nil end end - describe "WHEN the one announcement is active and today is before show_until" do + describe 'WHEN the one announcement is active and today is before show_until' do let!(:announcement) do create(:active_announcement, show_until: Date.today + 14.days) end - it "returns that announcement" do + it 'returns that announcement' do expect(Announcement.active_and_current).to eql announcement end end - describe "WHEN the one announcement is active and today is after show_until" do + describe 'WHEN the one announcement is active and today is after show_until' do let!(:announcement) do create(:active_announcement, show_until: Date.today - 14.days) end - it "returns no announcement" do + it 'returns no announcement' do expect(Announcement.active_and_current).to be_nil end end - describe "WHEN the one announcement is active and today equals show_until" do + describe 'WHEN the one announcement is active and today equals show_until' do let!(:announcement) do create(:active_announcement, show_until: Date.today) end - it "returns that announcement" do + it 'returns that announcement' do expect(Announcement.active_and_current).to eql announcement end end end - describe "instance methods" do - describe "#active_and_current?" do - describe "WHEN the announcement is not active" do + describe 'instance methods' do + describe '#active_and_current?' do + describe 'WHEN the announcement is not active' do let(:announcement) { build(:inactive_announcement) } it { expect(announcement.active_and_current?).to be_falsey } end - describe "WHEN the announcement is active and today is before show_until" do + describe 'WHEN the announcement is active and today is before show_until' do let(:announcement) do build(:active_announcement, show_until: Date.today + 14.days) end @@ -104,7 +104,7 @@ it { expect(announcement.active_and_current?).to be_truthy } end - describe "WHEN the announcement is active and today is after show_until" do + describe 'WHEN the announcement is active and today is after show_until' do let!(:announcement) do create(:active_announcement, show_until: Date.today - 14.days) end @@ -112,7 +112,7 @@ it { expect(announcement.active_and_current?).to be_falsey } end - describe "WHEN the announcement is active and today equals show_until" do + describe 'WHEN the announcement is active and today equals show_until' do let!(:announcement) do build(:active_announcement, show_until: Date.today) end diff --git a/spec/models/attachment_spec.rb b/spec/models/attachment_spec.rb index fa781fb543df..cc0017451f76 100644 --- a/spec/models/attachment_spec.rb +++ b/spec/models/attachment_spec.rb @@ -25,16 +25,16 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Attachment do let(:stubbed_author) { build_stubbed(:user) } let(:author) { create(:user) } - let(:long_description) { "a" * 300 } + let(:long_description) { 'a' * 300 } let(:work_package) { create(:work_package) } let(:stubbed_work_package) { build_stubbed(:work_package) } - let(:file) { create(:uploaded_jpg, name: "test.jpg") } - let(:second_file) { create(:uploaded_jpg, name: "test2.jpg") } + let(:file) { create(:uploaded_jpg, name: 'test.jpg') } + let(:second_file) { create(:uploaded_jpg, name: 'test2.jpg') } let(:container) { stubbed_work_package } let(:attachment) do @@ -54,52 +54,52 @@ ) end - describe "validations" do - it "is valid" do + describe 'validations' do + it 'is valid' do expect(stubbed_attachment) .to be_valid end - context "with a long description" do + context 'with a long description' do before do stubbed_attachment.description = long_description stubbed_attachment.valid? end - it "raises an error regarding description length" do + it 'raises an error regarding description length' do expect(stubbed_attachment.errors[:description]) - .to contain_exactly(I18n.t("activerecord.errors.messages.too_long", count: 255)) + .to contain_exactly(I18n.t('activerecord.errors.messages.too_long', count: 255)) end end - context "without a container" do + context 'without a container' do let(:container) { nil } - it "is valid" do + it 'is valid' do expect(stubbed_attachment) .to be_valid end end - context "without a container first and then setting a container" do + context 'without a container first and then setting a container' do let(:container) { nil } before do stubbed_attachment.container = work_package end - it "is valid" do + it 'is valid' do expect(stubbed_attachment) .to be_valid end end - context "with a container first and then removing the container" do + context 'with a container first and then removing the container' do before do stubbed_attachment.container = nil end - it "notes the field as unchangeable" do + it 'notes the field as unchangeable' do stubbed_attachment.valid? expect(stubbed_attachment.errors.symbols_for(:container)) @@ -107,12 +107,12 @@ end end - context "with a container first and then changing the container_id" do + context 'with a container first and then changing the container_id' do before do stubbed_attachment.container_id = stubbed_attachment.container_id + 1 end - it "notes the field as unchangeable" do + it 'notes the field as unchangeable' do stubbed_attachment.valid? expect(stubbed_attachment.errors.symbols_for(:container)) @@ -120,12 +120,12 @@ end end - context "with a container first and then changing the container_type" do + context 'with a container first and then changing the container_type' do before do - stubbed_attachment.container_type = "WikiPage" + stubbed_attachment.container_type = 'WikiPage' end - it "notes the field as unchangeable" do + it 'notes the field as unchangeable' do stubbed_attachment.valid? expect(stubbed_attachment.errors.symbols_for(:container)) @@ -134,44 +134,44 @@ end end - describe "#containered?" do - it "is false if the attachment has no container" do + describe '#containered?' do + it 'is false if the attachment has no container' do stubbed_attachment.container = nil expect(stubbed_attachment) .not_to be_containered end - it "is true if the attachment has a container" do + it 'is true if the attachment has a container' do expect(stubbed_attachment) .to be_containered end end - describe "create" do - it("creates a jpg file called test") do + describe 'create' do + it('creates a jpg file called test') do expect(File.exist?(attachment.diskfile.path)).to be true end it('has the content type "image/jpeg"') do - expect(attachment.content_type).to eq "image/jpeg" + expect(attachment.content_type).to eq 'image/jpeg' end - it "has the correct filesize" do + it 'has the correct filesize' do expect(attachment.filesize) .to eql file.size end - it "creates an md5 digest" do + it 'creates an md5 digest' do expect(attachment.digest) .to eql Digest::MD5.file(file.path).hexdigest end end - describe "two attachments with same file name" do + describe 'two attachments with same file name' do let(:second_file) { create(:uploaded_jpg, name: file.original_filename) } - it "does not interfere" do + it 'does not interfere' do a1 = Attachment.create!(container: work_package, file:, author:) @@ -187,7 +187,7 @@ ## # The tests assumes the default, file-based storage is configured and tests against that. # I.e. it does not test fog attachments being deleted from the cloud storage (such as S3). - describe "#destroy" do + describe '#destroy' do before do attachment.save! @@ -204,7 +204,7 @@ end end - include_examples "creates an audit trail on destroy" do + include_examples 'creates an audit trail on destroy' do subject { create(:attachment) } end @@ -238,7 +238,7 @@ end end - context "with expiry time exceeding maximum" do + context 'with expiry time exceeding maximum' do let(:url_options) { { expires_in: 1.year } } it "uses the allowed max" do @@ -250,14 +250,14 @@ shared_examples "it uses content disposition inline" do let(:attachment) { raise "define me!" } - describe "the external url (for remote attachments)" do - it "contains inline content disposition without the filename" do + describe 'the external url (for remote attachments)' do + it 'contains inline content disposition without the filename' do expect(attachment.external_url.to_s).to include "response-content-disposition=inline&" end end - describe "content disposition (for local attachments)" do - it "is inline, including the filename" do + describe 'content disposition (for local attachments)' do + it 'is inline, including the filename' do expect(attachment.content_disposition).to eq "inline; filename=#{attachment.filename}" end end @@ -284,10 +284,10 @@ end end - describe "for a video file" do + describe 'for a video file' do let(:attachment) { described_class.new } - it "assumes it to be inlineable" do + it 'assumes it to be inlineable' do %w[video/webm video/mp4 video/quicktime].each do |content_type| attachment.content_type = content_type expect(attachment).to be_inlineable, "#{content_type} should be inlineable" @@ -305,7 +305,7 @@ end end - describe "virus scan job on commit" do + describe 'virus scan job on commit' do shared_let(:work_package) { create(:work_package) } let(:created_attachment) do create(:attachment, @@ -313,8 +313,8 @@ container: work_package) end - context "with setting disabled", with_settings: { antivirus_scan_mode: :disabled } do - it "does not run" do + context 'with setting disabled', with_settings: { antivirus_scan_mode: :disabled } do + it 'does not run' do attachment.save expect(attachment.pending_virus_scan?).to be false @@ -323,10 +323,10 @@ end end - context "with setting enabled", + context 'with setting enabled', with_ee: %i[virus_scanning], with_settings: { antivirus_scan_mode: :clamav_socket } do - it "runs the job" do + it 'runs the job' do attachment.save expect(attachment.pending_virus_scan?).to be true @@ -336,15 +336,15 @@ end end - describe "full text extraction job on commit" do + describe 'full text extraction job on commit' do let(:created_attachment) do create(:attachment, author:, container:) end - shared_examples_for "runs extraction" do - it "runs extraction" do + shared_examples_for 'runs extraction' do + it 'runs extraction' do extraction_with_id = nil allow(Attachments::ExtractFulltextJob) @@ -358,8 +358,8 @@ end end - shared_examples_for "does not run extraction" do - it "does not run extraction" do + shared_examples_for 'does not run extraction' do + it 'does not run extraction' do created_attachment expect(Attachments::ExtractFulltextJob) @@ -369,41 +369,41 @@ end end - context "for a work package" do + context 'for a work package' do let(:work_package) { create(:work_package) } let(:container) { work_package } - context "on create" do - it_behaves_like "runs extraction" + context 'on create' do + it_behaves_like 'runs extraction' end - context "on update" do - it_behaves_like "does not run extraction" + context 'on update' do + it_behaves_like 'does not run extraction' end end - context "for a wiki page" do + context 'for a wiki page' do let(:wiki_page) { create(:wiki_page) } let(:container) { wiki_page } - context "on create" do - it_behaves_like "does not run extraction" + context 'on create' do + it_behaves_like 'does not run extraction' end - context "on update" do - it_behaves_like "does not run extraction" + context 'on update' do + it_behaves_like 'does not run extraction' end end - context "without a container" do + context 'without a container' do let(:container) { nil } - context "on create" do - it_behaves_like "runs extraction" + context 'on create' do + it_behaves_like 'runs extraction' end - context "on update" do - it_behaves_like "does not run extraction" + context 'on update' do + it_behaves_like 'does not run extraction' end end end diff --git a/spec/models/attribute_help_text/work_package_spec.rb b/spec/models/attribute_help_text/work_package_spec.rb index dd0cc60f1fc9..cc940e65f30e 100644 --- a/spec/models/attribute_help_text/work_package_spec.rb +++ b/spec/models/attribute_help_text/work_package_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AttributeHelpText::WorkPackage do def create_cf_help_text(custom_field) @@ -44,30 +44,30 @@ def create_cf_help_text(custom_field) create_cf_help_text(wp_custom_field) end - it_behaves_like "acts_as_attachable included" do + it_behaves_like 'acts_as_attachable included' do let(:model_instance) { create(:work_package_help_text) } let(:project) { create(:project) } end - describe ".available_attributes" do + describe '.available_attributes' do subject { described_class.available_attributes } - it "returns an array of potential attributes" do + it 'returns an array of potential attributes' do expect(subject).to be_a Hash end end - describe ".used_attributes" do + describe '.used_attributes' do let!(:instance) { create(:work_package_help_text) } subject { described_class.used_attributes instance.type } - it "returns used attributes" do + it 'returns used attributes' do expect(subject).to eq([instance.attribute_name]) end end - describe ".visible" do + describe '.visible' do let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } let(:user) do @@ -75,7 +75,7 @@ def create_cf_help_text(custom_field) member_with_roles: { project => role }) end let(:permission) { [] } - let(:static_instance) { create(:work_package_help_text, attribute_name: "project") } + let(:static_instance) { create(:work_package_help_text, attribute_name: 'project') } before do cf_instance @@ -84,27 +84,27 @@ def create_cf_help_text(custom_field) subject { described_class.visible(user) } - context "user having no permission" do + context 'user having no permission' do let(:user) do create(:user) end - it "returns the help text for the static attribute but not the one for the custom field" do + it 'returns the help text for the static attribute but not the one for the custom field' do expect(subject) .to contain_exactly(static_instance) end end - context "with a user having the `select_custom_fields` permission" do + context 'with a user having the `select_custom_fields` permission' do let(:permissions) { [:select_custom_fields] } - it "returns the help text for the static and cf attribute" do + it 'returns the help text for the static and cf attribute' do expect(subject) .to contain_exactly(static_instance, cf_instance) end end - context "user being member in a project with activated custom fields" do + context 'user being member in a project with activated custom fields' do let(:permissions) { [] } let(:type) do type = create(:type) @@ -144,74 +144,74 @@ def create_cf_help_text(custom_field) cf_instance_for_all end - it "returns the help text for the static and active cf attributes" do + it 'returns the help text for the static and active cf attributes' do expect(subject) .to contain_exactly(static_instance, cf_instance_active, cf_instance_for_all) end end end - describe "validations" do + describe 'validations' do before do - allow(described_class).to receive(:available_attributes).and_return(status: "Status") + allow(described_class).to receive(:available_attributes).and_return(status: 'Status') end - let(:attribute_name) { "status" } - let(:help_text) { "foobar" } + let(:attribute_name) { 'status' } + let(:help_text) { 'foobar' } subject { described_class.new attribute_name:, help_text: } - context "help_text is nil" do + context 'help_text is nil' do let(:help_text) { nil } - it "validates presence of help text" do + it 'validates presence of help text' do expect(subject.valid?).to be_falsey expect(subject.errors[:help_text].count).to be(1) expect(subject.errors[:help_text].first) - .to eql(I18n.t("activerecord.errors.messages.blank")) + .to eql(I18n.t('activerecord.errors.messages.blank')) end end - context "attribute_name is nil" do + context 'attribute_name is nil' do let(:attribute_name) { nil } - it "validates presence of attribute name" do + it 'validates presence of attribute name' do expect(subject.valid?).to be_falsey expect(subject.errors[:attribute_name].count).to be(1) expect(subject.errors[:attribute_name].first) - .to eql(I18n.t("activerecord.errors.messages.inclusion")) + .to eql(I18n.t('activerecord.errors.messages.inclusion')) end end - context "attribute_name is invalid" do - let(:attribute_name) { "foobar" } + context 'attribute_name is invalid' do + let(:attribute_name) { 'foobar' } - it "validates inclusion of attribute name" do + it 'validates inclusion of attribute name' do expect(subject.valid?).to be_falsey expect(subject.errors[:attribute_name].count).to be(1) expect(subject.errors[:attribute_name].first) - .to eql(I18n.t("activerecord.errors.messages.inclusion")) + .to eql(I18n.t('activerecord.errors.messages.inclusion')) end end end - describe "instance" do + describe 'instance' do subject { build(:work_package_help_text) } - it "provides a caption of its type" do - expect(subject.attribute_scope).to eq "WorkPackage" + it 'provides a caption of its type' do + expect(subject.attribute_scope).to eq 'WorkPackage' expect(subject.type_caption).to eq I18n.t(:label_work_package) end end - describe "destroy" do - context "when the custom field is destroyed" do + describe 'destroy' do + context 'when the custom field is destroyed' do before do cf_instance wp_custom_field.destroy end - it "also destroys the instance" do + it 'also destroys the instance' do expect { cf_instance.reload }.to raise_error(ActiveRecord::RecordNotFound) end end diff --git a/spec/models/capabilities/scopes/default_spec.rb b/spec/models/capabilities/scopes/default_spec.rb index 2acb4effbd62..fde8d4508803 100644 --- a/spec/models/capabilities/scopes/default_spec.rb +++ b/spec/models/capabilities/scopes/default_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Capabilities::Scopes::Default do # we focus on the non current user capabilities to make the tests easier to understand @@ -77,151 +77,151 @@ create(:admin) end - shared_examples_for "consists of contract actions" do |with: "the expected actions"| + shared_examples_for 'consists of contract actions' do |with: 'the expected actions'| it "includes #{with} for the scoped to user" do expect(scope.pluck(:action, :principal_id, :context_id)) .to match_array(expected) end end - shared_examples_for "is empty" do - it "is empty for the scoped to user" do + shared_examples_for 'is empty' do + it 'is empty for the scoped to user' do expect(scope) .to be_empty end end - describe ".default" do + describe '.default' do before do members end - context "without any members and non member roles" do - include_examples "is empty" + context 'without any members and non member roles' do + include_examples 'is empty' end - context "with a member without any permissions" do + context 'with a member without any permissions' do let(:members) { [member] } - include_examples "is empty" + include_examples 'is empty' - context "with a module being activated with a public permission" do + context 'with a module being activated with a public permission' do before do - project.enabled_module_names = ["activity"] + project.enabled_module_names = ['activity'] end - include_examples "consists of contract actions", with: "the actions of the public permission" do + include_examples 'consists of contract actions', with: 'the actions of the public permission' do let(:expected) do [ - ["activities/read", user.id, project.id] + ['activities/read', user.id, project.id] ] end end end end - context "with a global member without any permissions" do + context 'with a global member without any permissions' do let(:members) { [global_member] } - include_examples "is empty" + include_examples 'is empty' end - context "with a non member role without any permissions" do + context 'with a non member role without any permissions' do let(:members) { [non_member_role] } - include_examples "is empty" + include_examples 'is empty' - context "with the project being public and having a module activated with a public permission" do + context 'with the project being public and having a module activated with a public permission' do before do project.update(public: true) - project.enabled_module_names = ["activity"] + project.enabled_module_names = ['activity'] end - include_examples "consists of contract actions", with: "the actions of the public permission" do + include_examples 'consists of contract actions', with: 'the actions of the public permission' do let(:expected) do [ - ["activities/read", user.id, project.id] + ['activities/read', user.id, project.id] ] end end end end - context "with a global member with a global permission" do + context 'with a global member with a global permission' do let(:global_permissions) { %i[manage_user] } let(:members) { [global_member] } - include_examples "consists of contract actions", with: "the actions of the global permission" do + include_examples 'consists of contract actions', with: 'the actions of the global permission' do let(:expected) do [ - ["users/read", user.id, nil], - ["users/update", user.id, nil] + ['users/read', user.id, nil], + ['users/update', user.id, nil] ] end end - context "with the user being locked" do + context 'with the user being locked' do before do user.locked! end - include_examples "is empty" + include_examples 'is empty' end end - context "with a member with a project permission" do + context 'with a member with a project permission' do let(:member_permissions) { %i[manage_members] } let(:members) { [member] } - include_examples "consists of contract actions", with: "the actions of the project permission" do + include_examples 'consists of contract actions', with: 'the actions of the project permission' do let(:expected) do - [["memberships/create", user.id, project.id], - ["memberships/destroy", user.id, project.id], - ["memberships/update", user.id, project.id]] + [['memberships/create', user.id, project.id], + ['memberships/destroy', user.id, project.id], + ['memberships/update', user.id, project.id]] end end - context "with the user being locked" do + context 'with the user being locked' do before do user.locked! end - include_examples "is empty" + include_examples 'is empty' end end - context "with the non member role with a project permission" do + context 'with the non member role with a project permission' do let(:non_member_permissions) { %i[view_members] } let(:members) { [non_member_role] } - context "with the project being private" do - include_examples "is empty" + context 'with the project being private' do + include_examples 'is empty' end - context "with the project being public" do + context 'with the project being public' do before do project.update(public: true) end - include_examples "consists of contract actions", with: "the actions of the project permission" do + include_examples 'consists of contract actions', with: 'the actions of the project permission' do let(:expected) do [ - ["memberships/read", user.id, project.id] + ['memberships/read', user.id, project.id] ] end end - context "with the user being locked" do + context 'with the user being locked' do before do user.locked! end - include_examples "is empty" + include_examples 'is empty' end end end - context "with the anonymous role having a project permission in a public project" do + context 'with the anonymous role having a project permission in a public project' do let(:anonymous_permissions) { %i[view_members] } let(:members) { [anonymous_role] } @@ -229,10 +229,10 @@ project.update(public: true) end - include_examples "is empty" + include_examples 'is empty' end - context "with the anonymous user without any permissions with a public project" do + context 'with the anonymous user without any permissions with a public project' do let(:anonymous_permissions) { %i[] } let!(:user) { create(:anonymous) } let(:members) { [anonymous_role] } @@ -241,112 +241,112 @@ project.update(public: true) end - include_examples "is empty" + include_examples 'is empty' - context "with the project having a module activated with a public permission" do + context 'with the project having a module activated with a public permission' do before do - project.enabled_module_names = ["activity"] + project.enabled_module_names = ['activity'] end - include_examples "consists of contract actions", with: "the actions of the public permission" do + include_examples 'consists of contract actions', with: 'the actions of the public permission' do let(:expected) do [ - ["activities/read", user.id, project.id] + ['activities/read', user.id, project.id] ] end end end end - context "with the anonymous user with a project permission" do + context 'with the anonymous user with a project permission' do let(:anonymous_permissions) { %i[view_members] } let!(:user) { create(:anonymous) } let(:members) { [anonymous_role] } - context "with the project being private" do - include_examples "is empty" + context 'with the project being private' do + include_examples 'is empty' end - context "with the project being public" do + context 'with the project being public' do before do project.update(public: true) end - include_examples "consists of contract actions", with: "the actions of the project permission" do + include_examples 'consists of contract actions', with: 'the actions of the project permission' do let(:expected) do [ - ["memberships/read", user.id, project.id] + ['memberships/read', user.id, project.id] ] end end end end - context "with a member without any permissions and with the non member having a project permission" do + context 'with a member without any permissions and with the non member having a project permission' do let(:non_member_permissions) { %i[view_members] } let(:members) { [member, non_member_role] } - context "when the project is private" do - include_examples "is empty" + context 'when the project is private' do + include_examples 'is empty' end - context "when the project is public" do + context 'when the project is public' do before do project.update(public: true) end - include_examples "is empty" + include_examples 'is empty' end end - context "with a member with a project permission and with the non member having another project permission" do + context 'with a member with a project permission and with the non member having another project permission' do # This setup is not possible as having the manage_members permission requires to have view_members via the dependency # but it is convenient to test. let(:non_member_permissions) { %i[view_members] } let(:member_permissions) { %i[manage_members] } let(:members) { [member, non_member_role] } - context "when the project is private" do - include_examples "consists of contract actions", with: "the capabilities granted by the user`s membership" do + context 'when the project is private' do + include_examples 'consists of contract actions', with: 'the capabilities granted by the user`s membership' do let(:expected) do [ - ["memberships/create", user.id, project.id], - ["memberships/update", user.id, project.id], - ["memberships/destroy", user.id, project.id] + ['memberships/create', user.id, project.id], + ['memberships/update', user.id, project.id], + ['memberships/destroy', user.id, project.id] ] end end end - context "when the project is public" do + context 'when the project is public' do before do project.update(public: true) end - include_examples "consists of contract actions", with: "the capabilities granted by the user`s membership" do + include_examples 'consists of contract actions', with: 'the capabilities granted by the user`s membership' do let(:expected) do [ - ["memberships/create", user.id, project.id], - ["memberships/update", user.id, project.id], - ["memberships/destroy", user.id, project.id] + ['memberships/create', user.id, project.id], + ['memberships/update', user.id, project.id], + ['memberships/destroy', user.id, project.id] ] end end end end - context "with an admin" do + context 'with an admin' do before do user.update(admin: true) end - context "with modules activated" do + context 'with modules activated' do before do project.enabled_module_names = OpenProject::AccessControl.available_project_modules end - include_examples "consists of contract actions", - with: "all actions of all permissions (project and global) grantable to admin" do + include_examples 'consists of contract actions', + with: 'all actions of all permissions (project and global) grantable to admin' do let(:expected) do # This complicated and programmatic way is chosen so that the test can deal with additional actions being defined item = ->(namespace, action, global, module_name) { @@ -369,23 +369,23 @@ .uniq { |v| v.join(",") } end - it "does not include actions of permissions non-grantable to admin" do - expect(scope.pluck(:action)).not_to include("work_packages/assigned") + it 'does not include actions of permissions non-grantable to admin' do + expect(scope.pluck(:action)).not_to include('work_packages/assigned') end - it "include actions from public permissions of activated modules" do - expect(scope.pluck(:action)).to include("activities/read") + it 'include actions from public permissions of activated modules' do + expect(scope.pluck(:action)).to include('activities/read') end end end - context "with modules deactivated" do + context 'with modules deactivated' do before do project.enabled_modules = [] end - include_examples "consists of contract actions", - with: "all actions of all core permissions without the ones from modules" do + include_examples 'consists of contract actions', + with: 'all actions of all core permissions without the ones from modules' do let(:expected) do # This complicated and programmatic way is chosen so that the test can deal with additional actions being defined item = ->(namespace, action, global, module_name) { @@ -407,16 +407,16 @@ end end - context "with admin user being locked" do + context 'with admin user being locked' do before do user.locked! end - include_examples "is empty" + include_examples 'is empty' end end - context "without the current user being member in a project" do + context 'without the current user being member in a project' do let(:member_permissions) { %i[manage_members] } let(:global_permissions) { %i[manage_user] } let(:members) { [member, global_member] } @@ -425,10 +425,10 @@ current_user.update(admin: false) end - include_examples "is empty" + include_examples 'is empty' end - context "with the current user being member in a project" do + context 'with the current user being member in a project' do let(:member_permissions) { %i[manage_members] } let(:global_permissions) { %i[manage_user] } let(:own_role) { create(:project_role, permissions: []) } @@ -444,37 +444,37 @@ current_user.update(admin: false) end - include_examples "consists of contract actions" do + include_examples 'consists of contract actions' do let(:expected) do [ - ["memberships/create", user.id, project.id], - ["memberships/destroy", user.id, project.id], - ["memberships/update", user.id, project.id], - ["users/read", user.id, nil], - ["users/update", user.id, nil] + ['memberships/create', user.id, project.id], + ['memberships/destroy', user.id, project.id], + ['memberships/update', user.id, project.id], + ['users/read', user.id, nil], + ['users/update', user.id, nil] ] end end end - context "with a member with an action permission that is not granted to admin" do + context 'with a member with an action permission that is not granted to admin' do let(:member_permissions) { %i[work_package_assigned] } let(:members) { [member] } before do - project.enabled_module_names = ["work_package_tracking"] + project.enabled_module_names = ['work_package_tracking'] end - include_examples "consists of contract actions", with: "the actions of the permission" do + include_examples 'consists of contract actions', with: 'the actions of the permission' do let(:expected) do [ - ["work_packages/assigned", user.id, project.id] + ['work_packages/assigned', user.id, project.id] ] end end end - context "with a member with a project permission and the project being archived" do + context 'with a member with a project permission and the project being archived' do let(:member_permissions) { %i[manage_members] } let(:members) { [member] } @@ -482,29 +482,29 @@ project.update(active: false) end - include_examples "is empty" + include_examples 'is empty' end - context "with a work package membership" do + context 'with a work package membership' do before do - project.enabled_module_names = ["work_package_tracking"] + project.enabled_module_names = ['work_package_tracking'] end let(:members) { [work_package_member] } - context "when no permissions are associated with the role" do - include_examples "is empty" + context 'when no permissions are associated with the role' do + include_examples 'is empty' end # TODO: This is temporary, we do not want the capabilities of the entity specific memberships to # show up in the capabilities API for now. This will change in the future - context "when a permission is granted to the role" do + context 'when a permission is granted to the role' do let(:work_package_permissions) { [:view_work_packages] } - include_examples "is empty" + include_examples 'is empty' end - context "for a public project" do + context 'for a public project' do let(:non_member_permissions) { %i[view_members] } let(:members) { [work_package_member, non_member_role] } @@ -512,10 +512,10 @@ project.update(public: true) end - include_examples "consists of contract actions", with: "the actions of the non member role`s permission" do + include_examples 'consists of contract actions', with: 'the actions of the non member role`s permission' do let(:expected) do [ - ["memberships/read", user.id, project.id] + ['memberships/read', user.id, project.id] ] end end diff --git a/spec/models/category_spec.rb b/spec/models/category_spec.rb index c28dcd51ab6b..a82954227914 100644 --- a/spec/models/category_spec.rb +++ b/spec/models/category_spec.rb @@ -26,46 +26,46 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Category do let(:project) { create(:project) } let(:created_category) { create(:category, project:, assigned_to: assignee) } let(:assignee) { nil } - describe "#create" do - it "is creatable and takes the attributes" do - category = described_class.create project:, name: "New category" + describe '#create' do + it 'is creatable and takes the attributes' do + category = described_class.create project:, name: 'New category' - expect(category.attributes.slice("project_id", "name")) - .to eq("project_id" => project.id, "name" => "New category") + expect(category.attributes.slice('project_id', 'name')) + .to eq('project_id' => project.id, 'name' => 'New category') end - context "with a group assignment" do + context 'with a group assignment' do let(:group) do create(:group, member_with_permissions: { project => [] }) end let(:assignee) { group } - it "allows to assign groups" do + it 'allows to assign groups' do expect(created_category.assigned_to) .to eq group end end end - describe "#destroy" do + describe '#destroy' do let!(:work_package) { create(:work_package, project:, category: created_category) } - it "nullifies existing assignments to a work package" do + it 'nullifies existing assignments to a work package' do created_category.destroy expect(work_package.reload.category_id) .to be_nil end - it "allows reassigning to a different category" do + it 'allows reassigning to a different category' do other_category = create(:category, project:) created_category.destroy(other_category) diff --git a/spec/models/changeset_spec.rb b/spec/models/changeset_spec.rb index b5b51ae5171f..762860fc6e5b 100644 --- a/spec/models/changeset_spec.rb +++ b/spec/models/changeset_spec.rb @@ -26,29 +26,29 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Changeset do - let(:email) { "bob@bobbit.org" } + let(:email) { 'bob@bobbit.org' } with_virtual_subversion_repository do let(:changeset) do build(:changeset, repository:, - revision: "1", + revision: '1', committer: email, - comments: "Initial commit") + comments: 'Initial commit') end end - shared_examples_for "valid changeset" do - it { expect(changeset.revision).to eq("1") } + shared_examples_for 'valid changeset' do + it { expect(changeset.revision).to eq('1') } it { expect(changeset.committer).to eq(email) } - it { expect(changeset.comments).to eq("Initial commit") } + it { expect(changeset.comments).to eq('Initial commit') } - describe "journal" do + describe 'journal' do let(:journal) { changeset.journals.first } it { expect(journal.user).to eq(journal_user) } @@ -57,84 +57,84 @@ end end - describe "empty comment" do - it "commentses empty" do - changeset.comments = "" + describe 'empty comment' do + it 'commentses empty' do + changeset.comments = '' expect(changeset.save).to be true - expect(changeset.comments).to eq "" + expect(changeset.comments).to eq '' if changeset.comments.respond_to?(:force_encoding) - expect(changeset.comments.encoding.to_s).to eq("UTF-8") + expect(changeset.comments.encoding.to_s).to eq('UTF-8') end end - it "commentses nil" do + it 'commentses nil' do changeset.comments = nil expect(changeset.save).to be true - expect(changeset.comments).to eq "" + expect(changeset.comments).to eq '' if changeset.comments.respond_to?(:force_encoding) - expect(changeset.comments.encoding.to_s).to eq("UTF-8") + expect(changeset.comments.encoding.to_s).to eq('UTF-8') end end end - describe "stripping commit" do - let(:comment) { "This is a looooooooooooooong comment" + (((" " * 80) + "\n") * 5) } + describe 'stripping commit' do + let(:comment) { 'This is a looooooooooooooong comment' + (((' ' * 80) + "\n") * 5) } with_virtual_subversion_repository do let(:changeset) do build(:changeset, repository:, - revision: "1", + revision: '1', committer: email, comments: comment) end end - it "fors changeset comments strip" do + it 'fors changeset comments strip' do expect(changeset.save).to be true expect(comment).not_to eq changeset.comments - expect(changeset.comments).to eq "This is a looooooooooooooong comment" + expect(changeset.comments).to eq 'This is a looooooooooooooong comment' end end - describe "mapping" do - let!(:user) { create(:user, login: "jsmith", mail: "jsmith@somenet.foo") } + describe 'mapping' do + let!(:user) { create(:user, login: 'jsmith', mail: 'jsmith@somenet.foo') } let!(:repository) { create(:repository_subversion) } - it "supports manual user mapping with repository.committer_ids" do - c = create(:changeset, repository:, committer: "foo") + it 'supports manual user mapping with repository.committer_ids' do + c = create(:changeset, repository:, committer: 'foo') expect(c.user).to be_nil - repository.committer_ids = { "foo" => user.id } + repository.committer_ids = { 'foo' => user.id } expect(c.reload.user).to eq user # committer is now mapped - c = create(:changeset, repository:, committer: "foo") + c = create(:changeset, repository:, committer: 'foo') expect(c.user).to eq user end - it "maps user automatically when username matches" do + it 'maps user automatically when username matches' do c = create(:changeset, repository:, committer: user.login) expect(c.user).to eq user end - it "maps user automatically when email matches" do + it 'maps user automatically when email matches' do c = create(:changeset, repository:, committer: "john <#{user.mail}>") expect(c.user).to eq user end end - describe "#scan_comment_for_work_package_ids", + describe '#scan_comment_for_work_package_ids', with_settings: { - commit_fix_done_ratio: "90", - commit_ref_keywords: "refs , references, IssueID", - commit_fix_keywords: "fixes , closes", - default_language: "en" + commit_fix_done_ratio: '90', + commit_ref_keywords: 'refs , references, IssueID', + commit_fix_keywords: 'fixes , closes', + default_language: 'en' } do - let!(:user) { create(:admin, login: "dlopper") } + let!(:user) { create(:admin, login: 'dlopper') } let!(:open_status) { create(:status) } let!(:closed_status) { create(:closed_status) } @@ -150,7 +150,7 @@ let(:changeset) do create(:changeset, repository:, - revision: "123", + revision: '123', committer: user.login, comments:) end @@ -161,11 +161,11 @@ allow(Setting).to receive(:commit_fix_status_id).and_return closed_status.id end - describe "with any matching", with_settings: { commit_ref_keywords: "*" } do - describe "reference with brackets" do + describe 'with any matching', with_settings: { commit_ref_keywords: '*' } do + describe 'reference with brackets' do let(:comments) { "[##{work_package.id}] Worked on this work_package" } - it "references" do + it 'references' do changeset.scan_comment_for_work_package_ids work_package.reload @@ -173,10 +173,10 @@ end end - describe "reference at line start" do + describe 'reference at line start' do let(:comments) { "##{work_package.id} Worked on this work_package" } - it "references" do + it 'references' do changeset.scan_comment_for_work_package_ids work_package.reload @@ -185,10 +185,10 @@ end end - describe "non matching ref" do + describe 'non matching ref' do let(:comments) { "Some fix ignores ##{work_package.id}" } - it "references the work package id" do + it 'references the work package id' do changeset.scan_comment_for_work_package_ids work_package.reload @@ -196,39 +196,39 @@ end end - describe "with timelogs" do + describe 'with timelogs' do let!(:activity) { create(:activity, is_default: true) } before do - repository.project.enabled_module_names += ["costs"] + repository.project.enabled_module_names += ['costs'] repository.project.save! end - it "refs keywords any with timelog" do - allow(Setting).to receive(:commit_ref_keywords).and_return "*" + it 'refs keywords any with timelog' do + allow(Setting).to receive(:commit_ref_keywords).and_return '*' allow(Setting).to receive(:commit_logtime_enabled?).and_return true { - "2" => 2.0, - "2h" => 2.0, - "2hours" => 2.0, - "15m" => 0.25, - "15min" => 0.25, - "3h15" => 3.25, - "2h15m" => 2.25, - "2h15min" => 2.25, - "2:15" => 2.25, - "2.25" => 2.25, - "1.25h" => 1.25, - "0,75" => 0.75, - "1,25h" => 1.25 + '2' => 2.0, + '2h' => 2.0, + '2hours' => 2.0, + '15m' => 0.25, + '15min' => 0.25, + '3h15' => 3.25, + '2h15m' => 2.25, + '2h15min' => 2.25, + '2:15' => 2.25, + '2.25' => 2.25, + '1.25h' => 1.25, + '0,75' => 0.75, + '1,25h' => 1.25 }.each do |syntax, expected_hours| c = build(:changeset, repository:, committed_on: 24.hours.ago, commit_date: Date.yesterday, comments: "Worked on this work_package ##{work_package.id} @#{syntax}", - revision: "520", + revision: '520', user:) expect { c.scan_comment_for_work_package_ids } @@ -236,7 +236,7 @@ expect(c.work_package_ids).to eq [work_package.id] - time = TimeEntry.order(Arel.sql("id DESC")).first + time = TimeEntry.order(Arel.sql('id DESC')).first expect(work_package.id).to eq(time.work_package_id) expect(work_package.project_id).to eq(time.project_id) expect(user.id).to eq(time.user_id) @@ -245,23 +245,23 @@ expect(time.spent_on).to eq Date.yesterday expect(time.activity.is_default).to be true - expect(time.comments).to include "r520" + expect(time.comments).to include 'r520' end end - context "with a second work package" do + context 'with a second work package' do let!(:work_package2) { create(:work_package, project: repository.project, status: open_status) } - it "refs keywords closing with timelog" do + it 'refs keywords closing with timelog' do allow(Setting).to receive(:commit_fix_status_id).and_return closed_status.id - allow(Setting).to receive(:commit_ref_keywords).and_return "*" - allow(Setting).to receive(:commit_fix_keywords).and_return "fixes , closes" + allow(Setting).to receive(:commit_ref_keywords).and_return '*' + allow(Setting).to receive(:commit_fix_keywords).and_return 'fixes , closes' allow(Setting).to receive(:commit_logtime_enabled?).and_return true c = build(:changeset, repository:, comments: "This is a comment. Fixes ##{work_package.id} @4.5, ##{work_package2.id} @1", - revision: "520", + revision: '520', user:) expect { c.scan_comment_for_work_package_ids } @@ -274,13 +274,13 @@ expect(work_package).to be_closed expect(work_package2).to be_closed - times = TimeEntry.order(Arel.sql("id desc")).limit(2) + times = TimeEntry.order(Arel.sql('id desc')).limit(2) expect(times.map(&:work_package_id)).to contain_exactly(work_package.id, work_package2.id) end end end - it "references the work package id" do + it 'references the work package id' do # make sure work package 1 is not already closed expect(work_package.status.is_closed?).to be false @@ -296,7 +296,7 @@ journal = work_package.journals.last expect(journal.user).to eq user - expect(journal.notes).to eq "Applied in changeset r123." + expect(journal.notes).to eq 'Applied in changeset r123.' # Expect other work package to be unchanged # due to other project @@ -304,7 +304,7 @@ expect(other_work_package.changesets).to eq [] end - describe "with work package in parent project" do + describe 'with work package in parent project' do let(:parent) { create(:project) } let!(:work_package) { create(:work_package, project: parent, status: open_status) } @@ -313,7 +313,7 @@ repository.project.save! end - it "can reference it" do + it 'can reference it' do # make sure work package 1 is not already closed expect(work_package.status.is_closed?).to be false @@ -329,7 +329,7 @@ end end - describe "with work package in sub project" do + describe 'with work package in sub project' do let(:sub) { create(:project) } let!(:work_package) { create(:work_package, project: sub, status: open_status) } @@ -341,7 +341,7 @@ sub.reload end - it "can reference it" do + it 'can reference it' do # make sure work package 1 is not already closed expect(work_package.status.is_closed?).to be false @@ -358,30 +358,30 @@ end end - describe "assign_openproject user" do - describe "w/o user" do + describe 'assign_openproject user' do + describe 'w/o user' do before do changeset.save! end - it_behaves_like "valid changeset" do + it_behaves_like 'valid changeset' do let(:journal_user) { User.anonymous } end end - describe "with user is committer" do + describe 'with user is committer' do let!(:committer) { create(:user, login: email) } before do changeset.save! end - it_behaves_like "valid changeset" do + it_behaves_like 'valid changeset' do let(:journal_user) { committer } end end - describe "current user is not committer" do + describe 'current user is not committer' do let(:current_user) { create(:user) } let!(:committer) { create(:user, login: email) } @@ -391,7 +391,7 @@ changeset.save! end - it_behaves_like "valid changeset" do + it_behaves_like 'valid changeset' do let(:journal_user) { committer } end end diff --git a/spec/models/color_spec.rb b/spec/models/color_spec.rb index 8b6d426ab5d4..d9862b4e30f4 100644 --- a/spec/models/color_spec.rb +++ b/spec/models/color_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Color do - describe "- Relations" do - describe "#planning_element_types" do - it "can read planning_element_types w/ the help of the has_many association" do + describe '- Relations' do + describe '#planning_element_types' do + it 'can read planning_element_types w/ the help of the has_many association' do color = create(:color) planning_element_type = create(:type, color_id: color.id) @@ -42,7 +42,7 @@ expect(color.planning_element_types.first).to eq(planning_element_type) end - it "nullifies dependent planning_element_types" do + it 'nullifies dependent planning_element_types' do color = create(:color) planning_element_type = create(:type, color_id: color.id) @@ -56,14 +56,14 @@ end end - describe "- Validations" do + describe '- Validations' do let(:attributes) do - { name: "Color No. 1", - hexcode: "#FFFFFF" } + { name: 'Color No. 1', + hexcode: '#FFFFFF' } end - describe "name" do - it "is invalid w/o a name" do + describe 'name' do + it 'is invalid w/o a name' do attributes[:name] = nil color = Color.new(attributes) @@ -73,19 +73,19 @@ expect(color.errors[:name]).to eq(["can't be blank."]) end - it "is invalid w/ a name longer than 255 characters" do - attributes[:name] = "A" * 500 + it 'is invalid w/ a name longer than 255 characters' do + attributes[:name] = 'A' * 500 color = Color.new(attributes) expect(color).not_to be_valid expect(color.errors[:name]).to be_present - expect(color.errors[:name]).to eq(["is too long (maximum is 255 characters)."]) + expect(color.errors[:name]).to eq(['is too long (maximum is 255 characters).']) end end - describe "hexcode" do - it "is invalid w/o a hexcode" do + describe 'hexcode' do + it 'is invalid w/o a hexcode' do attributes[:hexcode] = nil color = Color.new(attributes) @@ -95,33 +95,33 @@ expect(color.errors[:hexcode]).to eq(["can't be blank."]) end - it "is invalid w/ malformed hexcodes" do - expect(Color.new(attributes.merge(hexcode: "0#FFFFFF"))).not_to be_valid - expect(Color.new(attributes.merge(hexcode: "#FFFFFF0"))).not_to be_valid - expect(Color.new(attributes.merge(hexcode: "white"))).not_to be_valid + it 'is invalid w/ malformed hexcodes' do + expect(Color.new(attributes.merge(hexcode: '0#FFFFFF'))).not_to be_valid + expect(Color.new(attributes.merge(hexcode: '#FFFFFF0'))).not_to be_valid + expect(Color.new(attributes.merge(hexcode: 'white'))).not_to be_valid end - it "fixes some wrong formats of hexcode automatically" do - color = Color.new(attributes.merge(hexcode: "FFCC33")) + it 'fixes some wrong formats of hexcode automatically' do + color = Color.new(attributes.merge(hexcode: 'FFCC33')) expect(color).to be_valid - expect(color.hexcode).to eq("#FFCC33") + expect(color.hexcode).to eq('#FFCC33') - color = Color.new(attributes.merge(hexcode: "#ffcc33")) + color = Color.new(attributes.merge(hexcode: '#ffcc33')) expect(color).to be_valid - expect(color.hexcode).to eq("#FFCC33") + expect(color.hexcode).to eq('#FFCC33') - color = Color.new(attributes.merge(hexcode: "fc3")) + color = Color.new(attributes.merge(hexcode: 'fc3')) expect(color).to be_valid - expect(color.hexcode).to eq("#FFCC33") + expect(color.hexcode).to eq('#FFCC33') - color = Color.new(attributes.merge(hexcode: "#fc3")) + color = Color.new(attributes.merge(hexcode: '#fc3')) expect(color).to be_valid - expect(color.hexcode).to eq("#FFCC33") + expect(color.hexcode).to eq('#FFCC33') end - it "is valid w/ proper hexcodes" do - expect(Color.new(attributes.merge(hexcode: "#FFFFFF"))).to be_valid - expect(Color.new(attributes.merge(hexcode: "#FF00FF"))).to be_valid + it 'is valid w/ proper hexcodes' do + expect(Color.new(attributes.merge(hexcode: '#FFFFFF'))).to be_valid + expect(Color.new(attributes.merge(hexcode: '#FF00FF'))).to be_valid end end end diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index eaaa6474e29a..20c3028f3157 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -25,48 +25,48 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe Comment do shared_let(:user) { create(:user) } shared_let(:news) { create(:news) } - let(:comment) { described_class.new(author: user, comments: "some important words", commented: news) } + let(:comment) { described_class.new(author: user, comments: 'some important words', commented: news) } - describe "#create" do - it "creates the comment" do - expect(described_class.create(commented: news, author: user, comments: "some important words")) + describe '#create' do + it 'creates the comment' do + expect(described_class.create(commented: news, author: user, comments: 'some important words')) .to be_truthy end end - describe "#texts" do - it "reads the comments" do - expect(described_class.new(comments: "some important words").text) - .to eql "some important words" + describe '#texts' do + it 'reads the comments' do + expect(described_class.new(comments: 'some important words').text) + .to eql 'some important words' end end - describe "#valid?" do - it "is valid" do + describe '#valid?' do + it 'is valid' do expect(comment) .to be_valid end - it "is invalid on an empty comments" do - comment.comments = "" + it 'is invalid on an empty comments' do + comment.comments = '' expect(comment) .not_to be_valid end - it "is invalid without comments" do + it 'is invalid without comments' do comment.comments = nil expect(comment) .not_to be_valid end - it "is invalid without author" do + it 'is invalid without author' do comment.author = nil expect(comment) diff --git a/spec/models/custom_action_spec.rb b/spec/models/custom_action_spec.rb index 6c59e0bc777a..63cd20e197b2 100644 --- a/spec/models/custom_action_spec.rb +++ b/spec/models/custom_action_spec.rb @@ -26,80 +26,80 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomAction do let(:stubbed_instance) { build_stubbed(:custom_action) } - let(:instance) { create(:custom_action, name: "zzzzzzzzz") } - let(:other_instance) { create(:custom_action, name: "aaaaa") } + let(:instance) { create(:custom_action, name: 'zzzzzzzzz') } + let(:other_instance) { create(:custom_action, name: 'aaaaa') } - describe "#name" do - it "can be set and read" do - stubbed_instance.name = "blubs" + describe '#name' do + it 'can be set and read' do + stubbed_instance.name = 'blubs' expect(stubbed_instance.name) - .to eql "blubs" + .to eql 'blubs' end end - describe "#description" do - it "can be set and read" do - stubbed_instance.description = "blubs" + describe '#description' do + it 'can be set and read' do + stubbed_instance.description = 'blubs' expect(stubbed_instance.description) - .to eql "blubs" + .to eql 'blubs' end end - describe "validations" do - it "is invalid with a name longer than 255 chars" do - stubbed_instance.name = "a" * 256 + describe 'validations' do + it 'is invalid with a name longer than 255 chars' do + stubbed_instance.name = 'a' * 256 expect(stubbed_instance) .to be_invalid end - it "is invalid with a nil name" do + it 'is invalid with a nil name' do stubbed_instance.name = nil expect(stubbed_instance) .to be_invalid end - it "is invalid with an empty name" do - stubbed_instance.name = "" + it 'is invalid with an empty name' do + stubbed_instance.name = '' expect(stubbed_instance) .to be_invalid end end - describe ".order_by_name" do + describe '.order_by_name' do before do instance other_instance end - it "returns the actions ordered by name" do + it 'returns the actions ordered by name' do expect(described_class.order_by_name.to_a) .to eql [other_instance, instance] end end - describe ".actions" do - it "is empty initially" do + describe '.actions' do + it 'is empty initially' do expect(stubbed_instance.actions) .to be_empty end - it "can be set and read" do + it 'can be set and read' do stubbed_instance.actions = [CustomActions::Actions::AssignedTo.new(1)] expect(stubbed_instance.actions.map { |a| [a.key, a.values] }) .to contain_exactly([:assigned_to, [1]]) end - it "can be persisted" do + it 'can be persisted' do instance.actions = [CustomActions::Actions::AssignedTo.new(1)] instance.save! @@ -109,13 +109,13 @@ end end - describe ".all_actions" do - it "returns all available actions with the default value initialized" do + describe '.all_actions' do + it 'returns all available actions with the default value initialized' do expect(stubbed_instance.all_actions.map { |a| [a.key, a.values] }) .to include([:assigned_to, []], [:status, []]) end - it "returns the activated actions with their selected value and all other with the default value" do + it 'returns the activated actions with their selected value and all other with the default value' do stubbed_instance.actions = [CustomActions::Actions::AssignedTo.new(1)] expect(stubbed_instance.all_actions.map { |a| [a.key, a.values] }) @@ -123,17 +123,17 @@ end end - describe ".conditions" do + describe '.conditions' do let(:status) { create(:status) } let(:role) { create(:project_role) } let(:project) { create(:project) } - it "is empty initially" do + it 'is empty initially' do expect(stubbed_instance.conditions) .to be_empty end - it "can be set and read" do + it 'can be set and read' do stubbed_instance.conditions = [CustomActions::Conditions::Status.new(status.id), CustomActions::Conditions::Role.new(role.id)] @@ -141,7 +141,7 @@ .to contain_exactly([:status, [status.id]], [:role, [role.id]]) end - it "can be persisted" do + it 'can be persisted' do instance.conditions = [CustomActions::Conditions::Status.new(status.id), CustomActions::Conditions::Role.new(role.id)] @@ -151,7 +151,7 @@ .to contain_exactly([:status, [status.id]], [:role, [role.id]]) end - it "existing permissions can be removed" do + it 'existing permissions can be removed' do instance.conditions = [CustomActions::Conditions::Project.new(project.id)] instance.save! @@ -165,12 +165,12 @@ end end - describe "#conditions_fulfilled?" do - let(:work_package) { double("work_package") } - let(:user) { double("user") } + describe '#conditions_fulfilled?' do + let(:work_package) { double('work_package') } + let(:user) { double('user') } let(:stubbed_condition1) do - condition = double("condition1") + condition = double('condition1') allow(condition) .to receive(:fulfilled_by?) .with(work_package, user) @@ -178,7 +178,7 @@ condition end let(:stubbed_condition2) do - condition = double("condition2") + condition = double('condition2') allow(condition) .to receive(:fulfilled_by?) .with(work_package, user) @@ -194,25 +194,25 @@ .and_return [stubbed_condition1, stubbed_condition2] end - context "all conditions fulfilled" do - it "is true" do + context 'all conditions fulfilled' do + it 'is true' do expect(stubbed_instance.conditions_fulfilled?(work_package, user)) .to be_truthy end end - context "but one condition not fulfilled" do + context 'but one condition not fulfilled' do let(:condition1_fulfilled) { false } - it "is false" do + it 'is false' do expect(stubbed_instance.conditions_fulfilled?(work_package, user)) .to be_falsey end end end - describe ".all_conditions" do - it "returns all available conditions with the default value initialized" do + describe '.all_conditions' do + it 'returns all available conditions with the default value initialized' do expect(stubbed_instance.all_conditions.map { |a| [a.key, a.values] }) .to contain_exactly([:status, []], [:role, []], [:type, []], [:project, []]) end diff --git a/spec/models/custom_actions/actions/assigned_to_spec.rb b/spec/models/custom_actions/actions/assigned_to_spec.rb index 126cc00d0c0a..0ee7fa34c350 100644 --- a/spec/models/custom_actions/actions/assigned_to_spec.rb +++ b/spec/models/custom_actions/actions/assigned_to_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::AssignedTo do let(:key) { :assigned_to } @@ -38,16 +38,16 @@ .to receive_message_chain(:not_locked, :select, :ordered_by_name) .and_return(users) - [{ value: nil, label: "-" }, - { value: "current_user", label: "(Assign to executing user)" }, + [{ value: nil, label: '-' }, + { value: 'current_user', label: '(Assign to executing user)' }, { value: users.first.id, label: users.first.name }, { value: users.last.id, label: users.last.name }] end - it_behaves_like "base custom action" - it_behaves_like "associated custom action" do - describe "#allowed_values" do - it "is the list of all users" do + it_behaves_like 'base custom action' + it_behaves_like 'associated custom action' do + describe '#allowed_values' do + it 'is the list of all users' do allowed_values expect(instance.allowed_values) @@ -56,49 +56,49 @@ end end - describe "current_user special value" do + describe 'current_user special value' do let(:work_package) { build_stubbed(:work_package) } let(:user) { build_stubbed(:user) } subject { described_class.new } before do - subject.values = ["current_user"] + subject.values = ['current_user'] end - it "can set the value" do + it 'can set the value' do expect(subject).to have_me_value end - it "includes the value in available_values" do + it 'includes the value in available_values' do expect(subject.associated) - .to include([subject.current_user_value_key, I18n.t("custom_actions.actions.assigned_to.executing_user_value")]) + .to include([subject.current_user_value_key, I18n.t('custom_actions.actions.assigned_to.executing_user_value')]) end - context "when logged in" do + context 'when logged in' do before do login_as user end - it "returns nil for the current user id" do + it 'returns nil for the current user id' do subject.apply work_package expect(work_package.assigned_to_id).to eq(user.id) end - it "validates the me value when executing" do + it 'validates the me value when executing' do errors = ActiveModel::Errors.new(CustomAction.new) subject.validate errors expect(errors.symbols_for(:actions)).to be_empty end end - context "when not logged in" do - it "returns nil for the current user id" do + context 'when not logged in' do + it 'returns nil for the current user id' do subject.apply work_package expect(work_package.assigned_to_id).to be_nil end - it "validates the me value when executing" do + it 'validates the me value when executing' do errors = ActiveModel::Errors.new(CustomAction.new) subject.validate errors expect(errors.symbols_for(:actions)).to include :not_logged_in diff --git a/spec/models/custom_actions/actions/custom_field_spec.rb b/spec/models/custom_actions/actions/custom_field_spec.rb index 41299c1e7d13..7dacd3d0b305 100644 --- a/spec/models/custom_actions/actions/custom_field_spec.rb +++ b/spec/models/custom_actions/actions/custom_field_spec.rb @@ -25,19 +25,19 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::CustomField do let(:list_custom_field) do build_stubbed(:list_wp_custom_field, - custom_options: [build_stubbed(:custom_option, value: "A"), - build_stubbed(:custom_option, value: "B")]) + custom_options: [build_stubbed(:custom_option, value: 'A'), + build_stubbed(:custom_option, value: 'B')]) end let(:list_multi_custom_field) do build_stubbed(:list_wp_custom_field, - custom_options: [build_stubbed(:custom_option, value: "A"), - build_stubbed(:custom_option, value: "B")], + custom_options: [build_stubbed(:custom_option, value: 'A'), + build_stubbed(:custom_option, value: 'B')], multi_value: true) end let(:version_custom_field) do @@ -91,14 +91,14 @@ klass.new end - describe ".all" do + describe '.all' do before do allow(WorkPackageCustomField) .to receive(:order) .and_return(custom_fields) end - it "is an array with a list of subclasses for every custom_field" do + it 'is an array with a list of subclasses for every custom_field' do expect(described_class.all.length) .to eql custom_fields.length @@ -111,186 +111,186 @@ end end - describe ".key" do - it "is the custom field accessor" do + describe '.key' do + it 'is the custom field accessor' do expect(klass.key) .to eql(custom_field.attribute_getter) end end - describe "#key" do - it "is the custom field accessor" do + describe '#key' do + it 'is the custom field accessor' do expect(instance.key) .to eql(custom_field.attribute_getter) end end - describe "#value" do - it "can be provided on initialization" do + describe '#value' do + it 'can be provided on initialization' do i = klass.new(1) expect(i.values) .to eql [1] end - it "can be set and read" do + it 'can be set and read' do instance.values = [1] expect(instance.values) .to eql [1] end - context "for an list custom field" do + context 'for an list custom field' do let(:custom_field) { list_custom_field } - it_behaves_like "associated values transformation" + it_behaves_like 'associated values transformation' end - context "for an int custom field" do + context 'for an int custom field' do let(:custom_field) { int_custom_field } - it_behaves_like "int values transformation" + it_behaves_like 'int values transformation' end - context "for a float custom field" do + context 'for a float custom field' do let(:custom_field) { float_custom_field } - it_behaves_like "float values transformation" + it_behaves_like 'float values transformation' end - context "for a string custom field" do + context 'for a string custom field' do let(:custom_field) { string_custom_field } - it_behaves_like "string values transformation" + it_behaves_like 'string values transformation' end - context "for a text custom field" do + context 'for a text custom field' do let(:custom_field) { text_custom_field } - it_behaves_like "text values transformation" + it_behaves_like 'text values transformation' end - context "for a date custom field" do + context 'for a date custom field' do let(:custom_field) { date_custom_field } - it_behaves_like "date values transformation" + it_behaves_like 'date values transformation' end end - describe "#human_name" do - it "is the name of the custom field" do + describe '#human_name' do + it 'is the name of the custom field' do expect(instance.human_name) .to eql(custom_field.name) end end - describe "#type" do - context "for a list custom field" do - it "is :associated_property" do + describe '#type' do + context 'for a list custom field' do + it 'is :associated_property' do expect(instance.type) .to be(:associated_property) end end - context "for a list custom field allowing multiple values" do + context 'for a list custom field allowing multiple values' do let(:custom_field) { list_multi_custom_field } - it "is :associated_property" do + it 'is :associated_property' do expect(instance.type) .to be(:associated_property) end end - context "for a text custom field" do + context 'for a text custom field' do let(:custom_field) { text_custom_field } - it "is :text_property" do + it 'is :text_property' do expect(instance.type) .to be(:text_property) end end - context "for a string custom field" do + context 'for a string custom field' do let(:custom_field) { string_custom_field } - it "is :string_property" do + it 'is :string_property' do expect(instance.type) .to be(:string_property) end end - context "for a version custom field" do + context 'for a version custom field' do let(:custom_field) { version_custom_field } - it "is :associated_property" do + it 'is :associated_property' do expect(instance.type) .to be(:associated_property) end end - context "for a bool custom field" do + context 'for a bool custom field' do let(:custom_field) { bool_custom_field } - it "is :boolean" do + it 'is :boolean' do expect(instance.type) .to be(:boolean) end end - context "for a user custom field" do + context 'for a user custom field' do let(:custom_field) { user_custom_field } - it "is :associated_property" do + it 'is :associated_property' do expect(instance.type) .to be(:associated_property) end - describe "current_user special value" do + describe 'current_user special value' do let(:work_package) { build_stubbed(:work_package) } let(:user) { build_stubbed(:user) } before do allow(work_package).to receive(:available_custom_fields).and_return([custom_field]) - instance.values = ["current_user"] + instance.values = ['current_user'] end - it "can set the value" do + it 'can set the value' do expect(instance).to have_me_value end - it "includes the value in available_values" do + it 'includes the value in available_values' do expect(instance.associated) - .to include([instance.current_user_value_key, I18n.t("custom_actions.actions.assigned_to.executing_user_value")]) + .to include([instance.current_user_value_key, I18n.t('custom_actions.actions.assigned_to.executing_user_value')]) end - context "when logged in" do + context 'when logged in' do before do login_as user end - it "sets the current user" do + it 'sets the current user' do instance.apply work_package expect(work_package.custom_value_for(custom_field).value).to eq(user.id.to_s) end - it "validates the me value when executing" do + it 'validates the me value when executing' do errors = ActiveModel::Errors.new(CustomAction.new) instance.validate errors expect(errors.symbols_for(:actions)).to be_empty end end - context "when not logged in" do + context 'when not logged in' do before do login_as User.anonymous end - it "returns nil for the current user id" do + it 'returns nil for the current user id' do instance.apply work_package expect(work_package.custom_value_for(custom_field).value).to be_nil end - it "validates the me value when executing" do + it 'validates the me value when executing' do errors = ActiveModel::Errors.new(CustomAction.new) instance.validate errors expect(errors.symbols_for(:actions)).to include :not_logged_in @@ -299,80 +299,80 @@ end end - context "for an int custom field" do + context 'for an int custom field' do let(:custom_field) { int_custom_field } - it "is :integer_property" do + it 'is :integer_property' do expect(instance.type) .to be(:integer_property) end end - context "for a float custom field" do + context 'for a float custom field' do let(:custom_field) { float_custom_field } - it "is :float_property" do + it 'is :float_property' do expect(instance.type) .to be(:float_property) end end - context "for a date custom field" do + context 'for a date custom field' do let(:custom_field) { date_custom_field } - it "is :date_property" do + it 'is :date_property' do expect(instance.type) .to be(:date_property) end end end - describe "#multi_value?" do - context "for a non multi value field" do - it "is false" do + describe '#multi_value?' do + context 'for a non multi value field' do + it 'is false' do expect(instance) .not_to be_multi_value end end - context "for a multi value field" do + context 'for a multi value field' do let(:custom_field) { list_multi_custom_field } - it "is true" do + it 'is true' do expect(instance) .to be_multi_value end end end - describe "#allowed_values" do - context "for a list custom field" do + describe '#allowed_values' do + context 'for a list custom field' do let(:expected) do custom_field .custom_options .map { |o| { value: o.id, label: o.value } } end - context "for a non required field" do - it "is the list of options and an empty placeholder" do + context 'for a non required field' do + it 'is the list of options and an empty placeholder' do expect(instance.allowed_values) - .to eql(expected.unshift(value: nil, label: "-")) + .to eql(expected.unshift(value: nil, label: '-')) end end - context "for a required field" do + context 'for a required field' do before do custom_field.is_required = true end - it "is the list of options" do + it 'is the list of options' do expect(instance.allowed_values) .to eql(expected) end end end - context "for a version custom field" do + context 'for a version custom field' do let(:custom_field) { version_custom_field } let(:expected) do # the versions will be sorted which by their name (and the project but that is the same for all of them) @@ -381,9 +381,9 @@ .map { |o| { value: o.id, label: o.name } } end let(:project) { build_stubbed(:project) } - let(:a_version) { build_stubbed(:version, name: "aaaaa", project:) } - let(:m_version) { build_stubbed(:version, name: "mmmmm", project:) } - let(:z_version) { build_stubbed(:version, name: "zzzzz", project:) } + let(:a_version) { build_stubbed(:version, name: 'aaaaa', project:) } + let(:m_version) { build_stubbed(:version, name: 'mmmmm', project:) } + let(:z_version) { build_stubbed(:version, name: 'zzzzz', project:) } let(:versions) { [z_version, a_version, m_version] } before do @@ -392,26 +392,26 @@ .and_return(versions) end - context "for a non required field" do - it "is the list of options and an empty placeholder" do + context 'for a non required field' do + it 'is the list of options and an empty placeholder' do expect(instance.allowed_values) - .to eql(expected.unshift(value: nil, label: "-")) + .to eql(expected.unshift(value: nil, label: '-')) end end - context "for a required field" do + context 'for a required field' do before do custom_field.is_required = true end - it "is the list of options" do + it 'is the list of options' do expect(instance.allowed_values) .to eql(expected) end end end - context "for a user custom field" do + context 'for a user custom field' do let(:custom_field) { user_custom_field } let(:expected) do values = [{ label: "(Assign to executing user)", value: "current_user" }] @@ -430,26 +430,26 @@ .and_return(users) end - context "for a non required field" do - it "is the list of options and an empty placeholder" do + context 'for a non required field' do + it 'is the list of options and an empty placeholder' do expect(instance.allowed_values) - .to eql(expected.unshift(value: nil, label: "-")) + .to eql(expected.unshift(value: nil, label: '-')) end end - context "for a required field" do + context 'for a required field' do before do custom_field.is_required = true end - it "is the list of options" do + it 'is the list of options' do expect(instance.allowed_values) .to eql(expected) end end end - context "for a bool custom field" do + context 'for a bool custom field' do let(:custom_field) { bool_custom_field } let(:expected) do @@ -459,16 +459,16 @@ ] end - it "is the list of options" do + it 'is the list of options' do expect(instance.allowed_values) .to eql(expected) end end end - describe "#validate" do - context "for a list custom field" do - it_behaves_like "associated custom action validations" do + describe '#validate' do + context 'for a list custom field' do + it_behaves_like 'associated custom action validations' do let(:allowed_values) do custom_field .custom_options @@ -477,10 +477,10 @@ end end - context "for a multi list custom field" do + context 'for a multi list custom field' do let(:custom_field) { list_multi_custom_field } - it_behaves_like "associated custom action validations" do + it_behaves_like 'associated custom action validations' do let(:allowed_values) do custom_field .custom_options @@ -489,7 +489,7 @@ end end - context "for a user custom field" do + context 'for a user custom field' do let(:custom_field) { user_custom_field } let(:users) do [build_stubbed(:user), @@ -504,7 +504,7 @@ .and_return(users) end - it_behaves_like "associated custom action validations" do + it_behaves_like 'associated custom action validations' do let(:allowed_values) do users .map { |u| { value: u.id, label: u.name } } @@ -512,7 +512,7 @@ end end - context "for a version custom field" do + context 'for a version custom field' do let(:custom_field) { version_custom_field } let(:project) { build_stubbed(:project) } let(:versions) do @@ -527,7 +527,7 @@ .and_return(versions) end - it_behaves_like "associated custom action validations" do + it_behaves_like 'associated custom action validations' do let(:allowed_values) do versions .map { |o| { value: o.id, label: o.name } } @@ -535,10 +535,10 @@ end end - context "for a bool custom field" do + context 'for a bool custom field' do let(:custom_field) { bool_custom_field } - it_behaves_like "bool custom action validations" do + it_behaves_like 'bool custom action validations' do let(:allowed_values) do [ { true: OpenProject::Database::DB_VALUE_TRUE }, @@ -548,32 +548,32 @@ end end - context "for an int custom field" do + context 'for an int custom field' do let(:custom_field) { int_custom_field } - it_behaves_like "int custom action validations" + it_behaves_like 'int custom action validations' end - context "for a float custom field" do + context 'for a float custom field' do let(:custom_field) { float_custom_field } - it_behaves_like "float custom action validations" + it_behaves_like 'float custom action validations' end - context "for a string custom field" do + context 'for a string custom field' do let(:custom_field) { string_custom_field } - it_behaves_like "string custom action validations" + it_behaves_like 'string custom action validations' end - context "for a date custom field" do + context 'for a date custom field' do let(:custom_field) { date_custom_field } - it_behaves_like "date custom action validations" + it_behaves_like 'date custom action validations' end end - describe "#apply" do + describe '#apply' do let(:work_package) { build(:work_package) } %i[list @@ -601,14 +601,14 @@ end end - context "for a date custom field" do + context 'for a date custom field' do let(:custom_field) { date_custom_field } it "sets the value to today for a dynamic value" do allow(work_package) .to receive(custom_field.attribute_setter) - instance.values = "%CURRENT_DATE%" + instance.values = '%CURRENT_DATE%' instance.apply(work_package) expect(work_package) diff --git a/spec/models/custom_actions/actions/date_spec.rb b/spec/models/custom_actions/actions/date_spec.rb index 0e1e6d68a60d..dbcba63f66ac 100644 --- a/spec/models/custom_actions/actions/date_spec.rb +++ b/spec/models/custom_actions/actions/date_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Date do let(:key) { :date } let(:type) { :date_property } let(:value) { Date.today } - it_behaves_like "base custom action" do - describe "#apply" do + it_behaves_like 'base custom action' do + describe '#apply' do let(:work_package) { build_stubbed(:work_package) } - it "sets both start and finish date to the action's value" do + it 'sets both start and finish date to the action\'s value' do instance.values = [Date.today + 5] instance.apply(work_package) @@ -49,8 +49,8 @@ .to eql Date.today + 5 end - it "sets both start and finish date to the current date if so specified" do - instance.values = ["%CURRENT_DATE%"] + it 'sets both start and finish date to the current date if so specified' do + instance.values = ['%CURRENT_DATE%'] instance.apply(work_package) @@ -61,8 +61,8 @@ end end - describe "#multi_value?" do - it "is false" do + describe '#multi_value?' do + it 'is false' do expect(instance) .not_to be_multi_value end diff --git a/spec/models/custom_actions/actions/done_ratio_spec.rb b/spec/models/custom_actions/actions/done_ratio_spec.rb index 320ac891804f..e874fbc28b36 100644 --- a/spec/models/custom_actions/actions/done_ratio_spec.rb +++ b/spec/models/custom_actions/actions/done_ratio_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::DoneRatio do let(:key) { :done_ratio } let(:type) { :integer_property } - it_behaves_like "base custom action" do - describe "#apply" do + it_behaves_like 'base custom action' do + describe '#apply' do let(:work_package) { build_stubbed(:work_package) } - it "sets the done_ratio to the action's value" do + it 'sets the done_ratio to the action\'s value' do instance.values = [95] instance.apply(work_package) @@ -47,19 +47,19 @@ end end - describe "#multi_value?" do - it "is false" do + describe '#multi_value?' do + it 'is false' do expect(instance) .not_to be_multi_value end end - describe "validate" do + describe 'validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "is valid for values between 0 and 100" do + it 'is valid for values between 0 and 100' do instance.values = [50] instance.validate(errors) @@ -68,7 +68,7 @@ .to be_empty end - it "is invalid for values larger than 100" do + it 'is invalid for values larger than 100' do instance.values = [101] instance.validate(errors) @@ -77,7 +77,7 @@ .to include(:smaller_than_or_equal_to) end - it "is invalid for values smaller than 0" do + it 'is invalid for values smaller than 0' do instance.values = [-1] instance.validate(errors) @@ -87,16 +87,16 @@ end end - describe ".all" do - context "with field disabled", with_settings: { work_package_done_ratio: "disabled" } do - it "is empty" do + describe '.all' do + context 'with field disabled', with_settings: { work_package_done_ratio: 'disabled' } do + it 'is empty' do expect(described_class.all) .to be_empty end end - context "with field derived", with_settings: { work_package_done_ratio: "status" } do - it "is empty" do + context 'with field derived', with_settings: { work_package_done_ratio: 'status' } do + it 'is empty' do expect(described_class.all) .to be_empty end diff --git a/spec/models/custom_actions/actions/due_date_spec.rb b/spec/models/custom_actions/actions/due_date_spec.rb index 6a54a5521130..8db81583c6a7 100644 --- a/spec/models/custom_actions/actions/due_date_spec.rb +++ b/spec/models/custom_actions/actions/due_date_spec.rb @@ -26,24 +26,24 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::DueDate do let(:key) { :due_date } let(:type) { :date_property } let(:value) { Date.today } - it_behaves_like "base custom action" do - describe "#multi_value?" do - it "is false" do + it_behaves_like 'base custom action' do + describe '#multi_value?' do + it 'is false' do expect(instance) .not_to be_multi_value end end - it_behaves_like "date custom action validations" - it_behaves_like "date values transformation" - it_behaves_like "date custom action apply" + it_behaves_like 'date custom action validations' + it_behaves_like 'date values transformation' + it_behaves_like 'date custom action apply' end end diff --git a/spec/models/custom_actions/actions/estimated_hours_spec.rb b/spec/models/custom_actions/actions/estimated_hours_spec.rb index 1e7eaac355b9..5394fca1a63f 100644 --- a/spec/models/custom_actions/actions/estimated_hours_spec.rb +++ b/spec/models/custom_actions/actions/estimated_hours_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::EstimatedHours do let(:key) { :estimated_hours } let(:type) { :float_property } let(:value) { 1.0 } - it_behaves_like "base custom action" do - describe "#apply" do + it_behaves_like 'base custom action' do + describe '#apply' do let(:work_package) { build_stubbed(:work_package) } - it "sets the done_ratio to the action's value" do + it 'sets the done_ratio to the action\'s value' do instance.values = [95.56] instance.apply(work_package) @@ -48,19 +48,19 @@ end end - describe "#multi_value?" do - it "is false" do + describe '#multi_value?' do + it 'is false' do expect(instance) .not_to be_multi_value end end - describe "validate" do + describe 'validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "is valid for values equal to or greater than 0" do + it 'is valid for values equal to or greater than 0' do instance.values = [50] instance.validate(errors) @@ -69,7 +69,7 @@ .to be_empty end - it "is invalid for values smaller than 0" do + it 'is invalid for values smaller than 0' do instance.values = [-0.00001] instance.validate(errors) diff --git a/spec/models/custom_actions/actions/notify_spec.rb b/spec/models/custom_actions/actions/notify_spec.rb index 47afed140f06..8afb9c976bf0 100644 --- a/spec/models/custom_actions/actions/notify_spec.rb +++ b/spec/models/custom_actions/actions/notify_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Notify do let(:key) { :notify } @@ -39,14 +39,14 @@ .to receive_message_chain(:not_locked, :select, :ordered_by_name) .and_return(users) - [{ value: nil, label: "-" }, + [{ value: nil, label: '-' }, { value: users.first.id, label: users.first.name }, { value: users.last.id, label: users.last.name }] end - it_behaves_like "base custom action" do - describe "#allowed_values" do - it "is the list of all users" do + it_behaves_like 'base custom action' do + describe '#allowed_values' do + it 'is the list of all users' do allowed_values expect(instance.allowed_values) @@ -54,12 +54,12 @@ end end - it_behaves_like "associated custom action validations" + it_behaves_like 'associated custom action validations' - describe "#apply" do + describe '#apply' do let(:work_package) { build_stubbed(:work_package) } - it "adds a note with all values distinguished by type" do + it 'adds a note with all values distinguished by type' do principals = [build_stubbed(:user), build_stubbed(:group), build_stubbed(:user)] @@ -78,8 +78,8 @@ end end - describe "#multi_value?" do - it "is true" do + describe '#multi_value?' do + it 'is true' do expect(instance) .to be_multi_value end diff --git a/spec/models/custom_actions/actions/priority_spec.rb b/spec/models/custom_actions/actions/priority_spec.rb index 5801b70024a7..c8adea790915 100644 --- a/spec/models/custom_actions/actions/priority_spec.rb +++ b/spec/models/custom_actions/actions/priority_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Priority do let(:key) { :priority } @@ -42,10 +42,10 @@ { value: priorities.last.id, label: priorities.last.name }] end - it_behaves_like "base custom action" - it_behaves_like "associated custom action" do - describe "#allowed_values" do - it "is the list of all priorities" do + it_behaves_like 'base custom action' + it_behaves_like 'associated custom action' do + describe '#allowed_values' do + it 'is the list of all priorities' do allowed_values expect(instance.allowed_values) diff --git a/spec/models/custom_actions/actions/project_spec.rb b/spec/models/custom_actions/actions/project_spec.rb index c8506428688e..a844a55c8089 100644 --- a/spec/models/custom_actions/actions/project_spec.rb +++ b/spec/models/custom_actions/actions/project_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Project do let(:key) { :project } @@ -44,10 +44,10 @@ { value: projects.last.id, label: projects.last.name }] end - it_behaves_like "base custom action" - it_behaves_like "associated custom action" do - describe "#allowed_values" do - it "is the list of all project" do + it_behaves_like 'base custom action' + it_behaves_like 'associated custom action' do + describe '#allowed_values' do + it 'is the list of all project' do allowed_values expect(instance.allowed_values) diff --git a/spec/models/custom_actions/actions/responsible_spec.rb b/spec/models/custom_actions/actions/responsible_spec.rb index a13062b1e7e7..a442fff08be8 100644 --- a/spec/models/custom_actions/actions/responsible_spec.rb +++ b/spec/models/custom_actions/actions/responsible_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Responsible do let(:key) { :responsible } @@ -39,16 +39,15 @@ .to receive_message_chain(:not_locked, :select, :ordered_by_name) .and_return(principals) - [{ value: nil, label: "-" }, - { value: "current_user", label: "(Assign to executing user)" }, + [{ value: nil, label: '-' }, { value: principals.first.id, label: principals.first.name }, { value: principals.last.id, label: principals.last.name }] end - it_behaves_like "base custom action" - it_behaves_like "associated custom action" do - describe "#allowed_values" do - it "is the list of all users and groups" do + it_behaves_like 'base custom action' + it_behaves_like 'associated custom action' do + describe '#allowed_values' do + it 'is the list of all users and groups' do allowed_values expect(instance.allowed_values) @@ -56,54 +55,4 @@ end end end - - describe "current_user special value" do - let(:work_package) { build_stubbed(:work_package) } - let(:user) { build_stubbed(:user) } - - subject { described_class.new } - - before do - subject.values = ["current_user"] - end - - it "can set the value" do - expect(subject).to have_me_value - end - - it "includes the value in available_values" do - expect(subject.associated) - .to include([subject.current_user_value_key, I18n.t("custom_actions.actions.assigned_to.executing_user_value")]) - end - - context "when logged in" do - before do - login_as user - end - - it "returns nil for the current user id" do - subject.apply work_package - expect(work_package.responsible_id).to eq(user.id) - end - - it "validates the me value when executing" do - errors = ActiveModel::Errors.new(CustomAction.new) - subject.validate errors - expect(errors.symbols_for(:actions)).to be_empty - end - end - - context "when not logged in" do - it "returns nil for the current user id" do - subject.apply work_package - expect(work_package.responsible_id).to be_nil - end - - it "validates the me value when executing" do - errors = ActiveModel::Errors.new(CustomAction.new) - subject.validate errors - expect(errors.symbols_for(:actions)).to include :not_logged_in - end - end - end end diff --git a/spec/models/custom_actions/actions/start_date_spec.rb b/spec/models/custom_actions/actions/start_date_spec.rb index cda913a890c3..0a798e895a28 100644 --- a/spec/models/custom_actions/actions/start_date_spec.rb +++ b/spec/models/custom_actions/actions/start_date_spec.rb @@ -26,24 +26,24 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::StartDate do let(:key) { :start_date } let(:type) { :date_property } let(:value) { Date.today } - it_behaves_like "base custom action" do - describe "#multi_value?" do - it "is false" do + it_behaves_like 'base custom action' do + describe '#multi_value?' do + it 'is false' do expect(instance) .not_to be_multi_value end end - it_behaves_like "date custom action validations" - it_behaves_like "date values transformation" - it_behaves_like "date custom action apply" + it_behaves_like 'date custom action validations' + it_behaves_like 'date values transformation' + it_behaves_like 'date custom action apply' end end diff --git a/spec/models/custom_actions/actions/status_spec.rb b/spec/models/custom_actions/actions/status_spec.rb index dbb69e272d4f..e92fbfd8581e 100644 --- a/spec/models/custom_actions/actions/status_spec.rb +++ b/spec/models/custom_actions/actions/status_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Status do let(:key) { :status } @@ -42,10 +42,10 @@ { value: statuses.last.id, label: statuses.last.name }] end - it_behaves_like "base custom action" - it_behaves_like "associated custom action" do - describe "#allowed_values" do - it "is the list of all status" do + it_behaves_like 'base custom action' + it_behaves_like 'associated custom action' do + describe '#allowed_values' do + it 'is the list of all status' do allowed_values expect(instance.allowed_values) diff --git a/spec/models/custom_actions/actions/type_spec.rb b/spec/models/custom_actions/actions/type_spec.rb index 0f4543a70b3b..8af04638cf46 100644 --- a/spec/models/custom_actions/actions/type_spec.rb +++ b/spec/models/custom_actions/actions/type_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Actions::Type do let(:key) { :type } @@ -43,10 +43,10 @@ { value: types.last.id, label: types.last.name }] end - it_behaves_like "base custom action" - it_behaves_like "associated custom action" do - describe "#allowed_values" do - it "is the list of all type" do + it_behaves_like 'base custom action' + it_behaves_like 'associated custom action' do + describe '#allowed_values' do + it 'is the list of all type' do allowed_values expect(instance.allowed_values) diff --git a/spec/models/custom_actions/conditions/project_spec.rb b/spec/models/custom_actions/conditions/project_spec.rb index dde25154ff31..b54207cff4d0 100644 --- a/spec/models/custom_actions/conditions/project_spec.rb +++ b/spec/models/custom_actions/conditions/project_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Conditions::Project do - it_behaves_like "associated custom condition" do + it_behaves_like 'associated custom condition' do let(:key) { :project } - describe "#allowed_values" do - it "is the list of all projects" do + describe '#allowed_values' do + it 'is the list of all projects' do projects = [build_stubbed(:project), build_stubbed(:project)] allow(Project) @@ -46,11 +46,11 @@ end end - describe "#fulfilled_by?" do - let(:work_package) { double("work_package", project_id: 1) } - let(:user) { double("not relevant") } + describe '#fulfilled_by?' do + let(:work_package) { double('work_package', project_id: 1) } + let(:user) { double('not relevant') } - it "is true if values are empty" do + it 'is true if values are empty' do instance.values = [] expect(instance.fulfilled_by?(work_package, user)) diff --git a/spec/models/custom_actions/conditions/role_spec.rb b/spec/models/custom_actions/conditions/role_spec.rb index b3abd459c610..822791583a40 100644 --- a/spec/models/custom_actions/conditions/role_spec.rb +++ b/spec/models/custom_actions/conditions/role_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Conditions::Role do - it_behaves_like "associated custom condition" do + it_behaves_like 'associated custom condition' do let(:key) { :role } - describe "#allowed_values" do - it "is the list of all roles" do + describe '#allowed_values' do + it 'is the list of all roles' do roles = [build_stubbed(:project_role), build_stubbed(:project_role)] @@ -47,22 +47,22 @@ end end - describe "#fulfilled_by?" do - let(:project) { double("project", id: 1) } - let(:work_package) { double("work_package", project:, project_id: 1) } + describe '#fulfilled_by?' do + let(:project) { double('project', id: 1) } + let(:work_package) { double('work_package', project:, project_id: 1) } let(:user) do - double("user", id: 3).tap do |user| + double('user', id: 3).tap do |user| allow(user) .to receive(:roles_for_project) .with(project) .and_return(roles) end end - let(:role1) { double("role", id: 1) } - let(:role2) { double("role", id: 2) } + let(:role1) { double('role', id: 1) } + let(:role2) { double('role', id: 2) } let(:roles) { [role1, role2] } - it "is true if values are empty" do + it 'is true if values are empty' do instance.values = [] expect(instance.fulfilled_by?(work_package, user)) diff --git a/spec/models/custom_actions/conditions/status_spec.rb b/spec/models/custom_actions/conditions/status_spec.rb index 3239d8fe25a5..2a6030cc81dd 100644 --- a/spec/models/custom_actions/conditions/status_spec.rb +++ b/spec/models/custom_actions/conditions/status_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Conditions::Status do - it_behaves_like "associated custom condition" do + it_behaves_like 'associated custom condition' do let(:key) { :status } - describe "#allowed_values" do - it "is the list of all status" do + describe '#allowed_values' do + it 'is the list of all status' do statuses = [build_stubbed(:status), build_stubbed(:status)] allow(Status) @@ -46,11 +46,11 @@ end end - describe "#fulfilled_by?" do - let(:work_package) { double("work_package", status_id: 1) } - let(:user) { double("not relevant") } + describe '#fulfilled_by?' do + let(:work_package) { double('work_package', status_id: 1) } + let(:user) { double('not relevant') } - it "is true if values are empty" do + it 'is true if values are empty' do instance.values = [] expect(instance.fulfilled_by?(work_package, user)) diff --git a/spec/models/custom_actions/conditions/type_spec.rb b/spec/models/custom_actions/conditions/type_spec.rb index 0b235bf3bb73..11c27aaa2c5e 100644 --- a/spec/models/custom_actions/conditions/type_spec.rb +++ b/spec/models/custom_actions/conditions/type_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../shared_expectations" +require 'spec_helper' +require_relative '../shared_expectations' RSpec.describe CustomActions::Conditions::Type do - it_behaves_like "associated custom condition" do + it_behaves_like 'associated custom condition' do let(:key) { :type } - describe "#allowed_values" do - it "is the list of all types" do + describe '#allowed_values' do + it 'is the list of all types' do types = [build_stubbed(:type), build_stubbed(:type)] allow(Type) @@ -46,11 +46,11 @@ end end - describe "#fulfilled_by?" do - let(:work_package) { double("work_package", type_id: 1) } - let(:user) { double("not relevant") } + describe '#fulfilled_by?' do + let(:work_package) { double('work_package', type_id: 1) } + let(:user) { double('not relevant') } - it "is true if values are empty" do + it 'is true if values are empty' do instance.values = [] expect(instance.fulfilled_by?(work_package, user)) diff --git a/spec/models/custom_actions/shared_expectations.rb b/spec/models/custom_actions/shared_expectations.rb index 72ea7193ff27..db3203e3f461 100644 --- a/spec/models/custom_actions/shared_expectations.rb +++ b/spec/models/custom_actions/shared_expectations.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "custom actions action" do +RSpec.shared_context 'custom actions action' do let(:instance) do described_class.new end @@ -46,8 +46,8 @@ end end -RSpec.shared_examples_for "base custom action" do - include_context "custom actions action" +RSpec.shared_examples_for 'base custom action' do + include_context 'custom actions action' let(:expected_priority) do if defined?(priority) priority @@ -63,36 +63,36 @@ end end - describe ".all" do - it "is an array with the class itself" do + describe '.all' do + it 'is an array with the class itself' do expect(described_class.all) .to contain_exactly(described_class) end end - describe ".key" do - it "is the expected key" do + describe '.key' do + it 'is the expected key' do expect(described_class.key) .to eql(expected_key) end end - describe "#key" do - it "is the expected key" do + describe '#key' do + it 'is the expected key' do expect(instance.key) .to eql(expected_key) end end - describe "#values" do - it "can be provided on initialization" do + describe '#values' do + it 'can be provided on initialization' do i = described_class.new(expected_value) expect(i.values) .to eql [expected_value] end - it "can be set and read" do + it 'can be set and read' do instance.values = expected_value expect(instance.values) @@ -100,34 +100,34 @@ end end - describe "#human_name" do - it "is the human_attribute_name" do + describe '#human_name' do + it 'is the human_attribute_name' do expect(instance.human_name) .to eql(WorkPackage.human_attribute_name(expected_key)) end end - describe "#type" do - it "is the expected type" do + describe '#type' do + it 'is the expected type' do expect(instance.type) .to eql(expected_type) end end - describe "#priority" do - it "is the expected level" do + describe '#priority' do + it 'is the expected level' do expect(instance.priority) .to eql(expected_priority) end end end -RSpec.shared_examples_for "associated custom action" do - include_context "custom actions action" do - describe "#apply" do +RSpec.shared_examples_for 'associated custom action' do + include_context 'custom actions action' do + describe '#apply' do let(:work_package) { build_stubbed(:work_package) } - it "sets the associated_id in the work package to the action's value" do + it 'sets the associated_id in the work package to the action\'s value' do expect(work_package) .to receive(:"#{key}_id=") .with(42) @@ -138,17 +138,17 @@ end end - it_behaves_like "associated custom action validations" + it_behaves_like 'associated custom action validations' end end -RSpec.shared_examples_for "associated custom action validations" do - describe "#validate" do +RSpec.shared_examples_for 'associated custom action validations' do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on actions if values is blank (depending on required?)" do + it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) @@ -162,7 +162,7 @@ end end - it "adds an error on actions if values not from list of allowed values" do + it 'adds an error on actions if values not from list of allowed values' do instance.values = [0] instance.validate(errors) @@ -171,7 +171,7 @@ .to eql [:inclusion] end - it "adds an error on actions if there are more values than one (depending on multi_value?)" do + it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = allowed_values.pluck(:value) instance.validate(errors) @@ -189,13 +189,13 @@ end end -RSpec.shared_examples_for "bool custom action validations" do - describe "#validate" do +RSpec.shared_examples_for 'bool custom action validations' do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on actions if values is blank (depending on required?)" do + it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) @@ -209,8 +209,8 @@ end end - it "adds an error on actions if values not true or false" do - instance.values = ["some bogus"] + it 'adds an error on actions if values not true or false' do + instance.values = ['some bogus'] instance.validate(errors) @@ -218,7 +218,7 @@ .to eql [:inclusion] end - it "adds an error on actions if there are more values than one (depending on multi_value?)" do + it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = allowed_values.map(&:values).flatten instance.validate(errors) @@ -234,13 +234,13 @@ end end -RSpec.shared_examples_for "int custom action validations" do - describe "#validate" do +RSpec.shared_examples_for 'int custom action validations' do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on actions if values is blank (depending on required?)" do + it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) @@ -254,7 +254,7 @@ end end - it "adds an error on actions if there are more values than one (depending on multi_value?)" do + it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = [1, 2] instance.validate(errors) @@ -270,13 +270,13 @@ end end -RSpec.shared_examples_for "float custom action validations" do - describe "#validate" do +RSpec.shared_examples_for 'float custom action validations' do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on actions if values is blank (depending on required?)" do + it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) @@ -290,7 +290,7 @@ end end - it "adds an error on actions if there are more values than one (depending on multi_value?)" do + it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = [1.252, 2.123] instance.validate(errors) @@ -306,13 +306,13 @@ end end -RSpec.shared_examples_for "string custom action validations" do - describe "#validate" do +RSpec.shared_examples_for 'string custom action validations' do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on actions if values is blank (depending on required?)" do + it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) @@ -326,7 +326,7 @@ end end - it "adds an error on actions if there are more values than one (depending on multi_value?)" do + it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = %w(some values) instance.validate(errors) @@ -342,17 +342,17 @@ end end -RSpec.shared_examples_for "text custom action validations" do - it_behaves_like "string custom action validations" +RSpec.shared_examples_for 'text custom action validations' do + it_behaves_like 'string custom action validations' end -RSpec.shared_examples_for "date custom action validations" do - describe "#validate" do +RSpec.shared_examples_for 'date custom action validations' do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on actions if values is blank (depending on required?)" do + it 'adds an error on actions if values is blank (depending on required?)' do instance.values = [] instance.validate(errors) @@ -366,7 +366,7 @@ end end - it "adds an error on actions if there are more values than one (depending on multi_value?)" do + it 'adds an error on actions if there are more values than one (depending on multi_value?)' do instance.values = [Date.today + 4.days, Date.today - 5.days] instance.validate(errors) @@ -382,14 +382,14 @@ end end -RSpec.shared_examples_for "associated values transformation" do - it_behaves_like "int values transformation" +RSpec.shared_examples_for 'associated values transformation' do + it_behaves_like 'int values transformation' end -RSpec.shared_examples_for "int values transformation" do - describe "#values" do - it "transforms the values to integers" do - instance.values = [42, nil, "23", "some bogus", "12.34234", "42a34e324r32"] +RSpec.shared_examples_for 'int values transformation' do + describe '#values' do + it 'transforms the values to integers' do + instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) .to contain_exactly(42, nil, 23) @@ -397,10 +397,10 @@ end end -RSpec.shared_examples_for "float values transformation" do - describe "#values" do - it "transforms the values to integers" do - instance.values = [42, nil, "23", "some bogus", "12.34234", "42a34e324r32"] +RSpec.shared_examples_for 'float values transformation' do + describe '#values' do + it 'transforms the values to integers' do + instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) .to contain_exactly(42, nil, 23, 12.34234) @@ -408,40 +408,40 @@ end end -RSpec.shared_examples_for "string values transformation" do - describe "#values" do - it "transforms the values to integers" do - instance.values = [42, nil, "23", "some bogus", "12.34234", "42a34e324r32"] +RSpec.shared_examples_for 'string values transformation' do + describe '#values' do + it 'transforms the values to integers' do + instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) - .to contain_exactly("42", nil, "23", "some bogus", "12.34234", "42a34e324r32") + .to contain_exactly('42', nil, '23', 'some bogus', '12.34234', '42a34e324r32') end end end -RSpec.shared_examples_for "text values transformation" do - describe "#values" do - it "transforms the values to integers" do - instance.values = [42, nil, "23", "some bogus", "12.34234", "42a34e324r32"] +RSpec.shared_examples_for 'text values transformation' do + describe '#values' do + it 'transforms the values to integers' do + instance.values = [42, nil, '23', 'some bogus', '12.34234', '42a34e324r32'] expect(instance.values) - .to contain_exactly("42", nil, "23", "some bogus", "12.34234", "42a34e324r32") + .to contain_exactly('42', nil, '23', 'some bogus', '12.34234', '42a34e324r32') end end end -RSpec.shared_examples_for "date values transformation" do - describe "#values" do - it "transforms the values to integers" do - instance.values = ["2015-03-29", Date.today, nil, (Date.today - 1.day).to_datetime, "bogus", "%CURRENT_DATE%"] +RSpec.shared_examples_for 'date values transformation' do + describe '#values' do + it 'transforms the values to integers' do + instance.values = ["2015-03-29", Date.today, nil, (Date.today - 1.day).to_datetime, 'bogus', '%CURRENT_DATE%'] expect(instance.values) - .to contain_exactly(Date.parse("2015-03-29"), Date.today, nil, Date.today - 1.day, "%CURRENT_DATE%") + .to contain_exactly(Date.parse("2015-03-29"), Date.today, nil, Date.today - 1.day, '%CURRENT_DATE%') end end end -RSpec.shared_examples_for "associated custom condition" do +RSpec.shared_examples_for 'associated custom condition' do let(:instance) do described_class.new end @@ -453,51 +453,51 @@ end end - describe ".key" do - it "is the expected key" do + describe '.key' do + it 'is the expected key' do expect(described_class.key) .to eql(expected_key) end end - describe "#key" do - it "is the expected key" do + describe '#key' do + it 'is the expected key' do expect(instance.key) .to eql(expected_key) end end - describe "#values" do - it "can be provided on initialization" do + describe '#values' do + it 'can be provided on initialization' do i = described_class.new(1) expect(i.values) .to eql [1] end - it "can be set and read" do + it 'can be set and read' do instance.values = 1 expect(instance.values) .to eql [1] end - it_behaves_like "associated values transformation" + it_behaves_like 'associated values transformation' end - describe "#human_name" do - it "is the human_attribute_name" do + describe '#human_name' do + it 'is the human_attribute_name' do expect(instance.human_name) .to eql(WorkPackage.human_attribute_name(expected_key)) end end - describe "#validate" do + describe '#validate' do let(:errors) do build_stubbed(:custom_action).errors end - it "adds an error on conditions if values not from list of allowed values" do + it 'adds an error on conditions if values not from list of allowed values' do instance.values = [0] instance.validate(errors) @@ -508,11 +508,11 @@ end end -RSpec.shared_examples_for "date custom action apply" do - describe "#apply" do +RSpec.shared_examples_for 'date custom action apply' do + describe '#apply' do let(:work_package) { build_stubbed(:work_package) } - it "sets the daate to the action's value" do + it 'sets the daate to the action\'s value' do instance.values = [Date.today + 5.days] instance.apply(work_package) @@ -521,8 +521,8 @@ .to eql Date.today + 5.days end - it "sets the date to the current date if so specified" do - instance.values = ["%CURRENT_DATE%"] + it 'sets the date to the current date if so specified' do + instance.values = ['%CURRENT_DATE%'] instance.apply(work_package) diff --git a/spec/models/custom_field_spec.rb b/spec/models/custom_field_spec.rb index bd0f403b65e5..e8176eef13ed 100644 --- a/spec/models/custom_field_spec.rb +++ b/spec/models/custom_field_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomField do before do @@ -36,34 +36,34 @@ let(:field) { build(:custom_field) } let(:field2) { build(:custom_field) } - describe "#name" do + describe '#name' do it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_length_of(:name).is_at_most(256) } - describe "uniqueness" do - describe "WHEN value, locale and type are identical" do + describe 'uniqueness' do + describe 'WHEN value, locale and type are identical' do before do - field.name = field2.name = "taken name" + field.name = field2.name = 'taken name' field2.save! end it { expect(field).not_to be_valid } end - describe "WHEN value and locale are identical and type is different" do + describe 'WHEN value and locale are identical and type is different' do before do - field.name = field2.name = "taken name" + field.name = field2.name = 'taken name' field2.save! - field.type = "TestCustomField" + field.type = 'TestCustomField' end it { expect(field).to be_valid } end - describe "WHEN type and locale are identical and value is different" do + describe 'WHEN type and locale are identical and value is different' do before do - field.name = "new name" - field2.name = "taken name" + field.name = 'new name' + field2.name = 'taken name' field2.save! end @@ -72,11 +72,11 @@ end end - describe "#valid?" do + describe '#valid?' do describe "WITH a text field WITH minimum length blank" do before do - field.field_format = "text" + field.field_format = 'text' field.min_length = nil end @@ -86,7 +86,7 @@ describe "WITH a text field WITH maximum length blank" do before do - field.field_format = "text" + field.field_format = 'text' field.max_length = nil end @@ -96,8 +96,8 @@ describe "WITH a text field WITH minimum length not an integer" do before do - field.field_format = "text" - field.min_length = "a" + field.field_format = 'text' + field.min_length = 'a' end it { expect(field).not_to be_valid } @@ -106,8 +106,8 @@ describe "WITH a text field WITH maximum length not an integer" do before do - field.field_format = "text" - field.max_length = "a" + field.field_format = 'text' + field.max_length = 'a' end it { expect(field).not_to be_valid } @@ -116,7 +116,7 @@ describe "WITH a text field WITH minimum length greater than maximum length" do before do - field.field_format = "text" + field.field_format = 'text' field.min_length = 2 field.max_length = 1 end @@ -127,7 +127,7 @@ describe "WITH a text field WITH negative minimum length" do before do - field.field_format = "text" + field.field_format = 'text' field.min_length = -2 end @@ -137,7 +137,7 @@ describe "WITH a text field WITH negative maximum length" do before do - field.field_format = "text" + field.field_format = 'text' field.max_length = -2 end @@ -147,11 +147,11 @@ describe "WITH a text field WITH an invalid regexp" do before do - field.field_format = "text" - field.regexp = "[0-9}" + field.field_format = 'text' + field.regexp = '[0-9}' end - it "is not valid" do + it 'is not valid' do expect(field).not_to be_valid expect(field.errors[:regexp].size).to eq(1) end @@ -160,10 +160,10 @@ describe "WITH a list field WITHOUT a custom option" do before do - field.field_format = "list" + field.field_format = 'list' end - it "is not valid" do + it 'is not valid' do expect(field) .to be_invalid end @@ -172,32 +172,32 @@ describe "WITH a list field WITH a custom option" do before do - field.field_format = "list" - field.custom_options.build(value: "some value") + field.field_format = 'list' + field.custom_options.build(value: 'some value') end - it "is valid" do + it 'is valid' do expect(field) .to be_valid end end end - describe "#attribute_name" do + describe '#attribute_name' do let(:field) { build_stubbed(:custom_field) } subject { field.attribute_name } it { is_expected.to eq("custom_field_#{field.id}") } - context "when a format is provided" do + context 'when a format is provided' do subject { field.attribute_name(:camel_case) } it { is_expected.to eq("customField#{field.id}") } end end - describe "#attribute_getter" do + describe '#attribute_getter' do let(:field) { build_stubbed(:custom_field) } subject { field.attribute_getter } @@ -205,7 +205,7 @@ it { is_expected.to eq(:"custom_field_#{field.id}") } end - describe "#attribute_setter" do + describe '#attribute_setter' do let(:field) { build_stubbed(:custom_field) } subject { field.attribute_setter } @@ -213,7 +213,7 @@ it { is_expected.to eq(:"custom_field_#{field.id}=") } end - describe "#column_name" do + describe '#column_name' do let(:field) { build_stubbed(:custom_field) } subject { field.column_name } @@ -221,14 +221,14 @@ it { is_expected.to eq("cf_#{field.id}") } end - describe "#possible_values_options" do + describe '#possible_values_options' do let(:project) { build_stubbed(:project) } let(:user1) { build_stubbed(:user) } let(:user2) { build_stubbed(:user) } - context "for a user custom field" do + context 'for a user custom field' do before do - field.field_format = "user" + field.field_format = 'user' allow(project) .to receive(:principals) .and_return([user1, user2]) @@ -238,15 +238,15 @@ .and_return([user2]) end - context "for a project" do - it "is a list of name, id pairs" do + context 'for a project' do + it 'is a list of name, id pairs' do expect(field.possible_values_options(project)) .to contain_exactly([user1.name, user1.id.to_s], [user2.name, user2.id.to_s]) end end - context "for something that responds to project" do - it "is a list of name, id pairs" do + context 'for something that responds to project' do + it 'is a list of name, id pairs' do object = OpenStruct.new(project:) # rubocop:disable Style/OpenStructUse expect(field.possible_values_options(object)) @@ -254,39 +254,39 @@ end end - context "for nil" do - it "returns all principles visible to me" do + context 'for nil' do + it 'returns all principles visible to me' do expect(field.possible_values_options) .to contain_exactly([user2.name, user2.id.to_s]) end end end - context "for a list custom field" do + context 'for a list custom field' do let(:option1) { build_stubbed(:custom_option) } let(:option2) { build_stubbed(:custom_option) } before do - field.field_format = "list" + field.field_format = 'list' field.custom_options = [option1, option2] end - it "is a list of name, id pairs" do + it 'is a list of name, id pairs' do expect(field.possible_values_options) .to contain_exactly([option1.value, option1.id.to_s], [option2.value, option2.id.to_s]) end end - context "for a version custom field" do + context 'for a version custom field' do let(:versions) { [build_stubbed(:version), build_stubbed(:version)] } before do - field.field_format = "version" + field.field_format = 'version' end - context "with a project provided" do - it "returns the project's shared_versions" do + context 'with a project provided' do + it 'returns the project\'s shared_versions' do allow(project) .to receive(:shared_versions) .and_return(versions) @@ -296,10 +296,10 @@ end end - context "with a time entry provided" do + context 'with a time entry provided' do let(:time_entry) { build_stubbed(:time_entry, project:) } - it "returns the project's shared_versions" do + it 'returns the project\'s shared_versions' do allow(project) .to receive(:shared_versions) .and_return(versions) @@ -309,8 +309,8 @@ end end - context "with nothing provided" do - it "returns the systemwide versions" do + context 'with nothing provided' do + it 'returns the systemwide versions' do allow(Version) .to receive(:systemwide) .and_return(versions) @@ -322,56 +322,56 @@ end end - describe "#possible_values" do - context "on a list custom field" do + describe '#possible_values' do + context 'on a list custom field' do let(:field) { described_class.new field_format: "list" } - context "on providing an array" do + context 'on providing an array' do before do - field.possible_values = ["One value", "Two values", ""] + field.possible_values = ['One value', 'Two values', ''] end - it "accepts the values" do + it 'accepts the values' do expect(field.possible_values.map(&:value)) - .to contain_exactly("One value", "Two values") + .to contain_exactly('One value', 'Two values') end end - context "on providing a string" do + context 'on providing a string' do before do - field.possible_values = "One value" + field.possible_values = 'One value' end - it "accepts the values" do + it 'accepts the values' do expect(field.possible_values.map(&:value)) - .to contain_exactly("One value") + .to contain_exactly('One value') end end - context "on providing a multiline string" do + context 'on providing a multiline string' do before do field.possible_values = "One value\nTwo values \r\n \n" end - it "accepts the values" do + it 'accepts the values' do expect(field.possible_values.map(&:value)) - .to contain_exactly("One value", "Two values") + .to contain_exactly('One value', 'Two values') end end end end - describe "nested attributes for custom options" do + describe 'nested attributes for custom options' do let(:option) { build(:custom_option) } let(:options) { [option] } - let(:field) { build(:custom_field, field_format: "list", custom_options: options) } + let(:field) { build(:custom_field, field_format: 'list', custom_options: options) } before do field.save! end - shared_examples_for "saving updates field's updated_at" do - it "updates updated_at" do + shared_examples_for 'saving updates field\'s updated_at' do + it 'updates updated_at' do timestamp_before = field.updated_at sleep 0.001 field.save @@ -379,176 +379,176 @@ end end - context "after adding a custom option" do + context 'after adding a custom option' do before do - field.attributes = { "custom_options_attributes" => { "0" => option.attributes, - "1" => { value: "blubs" } } } + field.attributes = { 'custom_options_attributes' => { '0' => option.attributes, + '1' => { value: 'blubs' } } } end - it_behaves_like "saving updates field's updated_at" + it_behaves_like 'saving updates field\'s updated_at' end - context "after changing a custom option" do + context 'after changing a custom option' do before do - attributes = option.attributes.merge(value: "new_value") + attributes = option.attributes.merge(value: 'new_value') - field.attributes = { "custom_options_attributes" => { "0" => attributes } } + field.attributes = { 'custom_options_attributes' => { '0' => attributes } } end - it_behaves_like "saving updates field's updated_at" + it_behaves_like 'saving updates field\'s updated_at' end end - describe "#multi_value_possible?" do - context "with a wp list cf" do + describe '#multi_value_possible?' do + context 'with a wp list cf' do let(:field) { build_stubbed(:list_wp_custom_field) } - it "is true" do + it 'is true' do expect(field) .to be_multi_value_possible end end - context "with a wp user cf" do + context 'with a wp user cf' do let(:field) { build_stubbed(:user_wp_custom_field) } - it "is true" do + it 'is true' do expect(field) .to be_multi_value_possible end end - context "with a wp int cf" do + context 'with a wp int cf' do let(:field) { build_stubbed(:integer_wp_custom_field) } - it "is false" do + it 'is false' do expect(field) .not_to be_multi_value_possible end end - context "with a project list cf" do + context 'with a project list cf' do let(:field) { build_stubbed(:list_project_custom_field) } - it "is true" do + it 'is true' do expect(field) .to be_multi_value_possible end end - context "with a project user cf" do + context 'with a project user cf' do let(:field) { build_stubbed(:user_project_custom_field) } - it "is true" do + it 'is true' do expect(field) .to be_multi_value_possible end end - context "with a project int cf" do + context 'with a project int cf' do let(:field) { build_stubbed(:integer_project_custom_field) } - it "is false" do + it 'is false' do expect(field) .not_to be_multi_value_possible end end - context "with a time_entry user cf" do + context 'with a time_entry user cf' do let(:field) { build_stubbed(:time_entry_custom_field, :user) } - it "is true" do + it 'is true' do expect(field) .to be_multi_value_possible end end - context "with a time_entry list cf" do + context 'with a time_entry list cf' do let(:field) { build_stubbed(:time_entry_custom_field, :list) } - it "is true" do + it 'is true' do expect(field) .to be_multi_value_possible end end end - describe "#allow_non_open_versions?" do - context "with a wp list cf" do + describe '#allow_non_open_versions?' do + context 'with a wp list cf' do let(:field) { build_stubbed(:list_wp_custom_field) } - it "is false" do + it 'is false' do expect(field) .not_to be_allow_non_open_versions_possible end end - context "with a wp user cf" do + context 'with a wp user cf' do let(:field) { build_stubbed(:user_wp_custom_field) } - it "is false" do + it 'is false' do expect(field) .not_to be_allow_non_open_versions_possible end end - context "with a wp int cf" do + context 'with a wp int cf' do let(:field) { build_stubbed(:integer_wp_custom_field) } - it "is false" do + it 'is false' do expect(field) .not_to be_allow_non_open_versions_possible end end - context "with a work package user cf" do + context 'with a work package user cf' do let(:field) { build_stubbed(:wp_custom_field, :user) } - it "is false" do + it 'is false' do expect(field) .not_to be_allow_non_open_versions_possible end end - context "with a work package version cf" do + context 'with a work package version cf' do let(:field) { build_stubbed(:wp_custom_field, :version) } - it "is true" do + it 'is true' do expect(field) .to be_allow_non_open_versions_possible end end - context "with a version cf for version" do + context 'with a version cf for version' do let(:field) { build_stubbed(:version_custom_field, :version) } - it "is true" do + it 'is true' do expect(field) .to be_allow_non_open_versions_possible end end - context "with a project version cf" do + context 'with a project version cf' do let(:field) { build_stubbed(:project_custom_field, :version) } - it "is true" do + it 'is true' do expect(field) .to be_allow_non_open_versions_possible end end - context "with a time entry version cf" do + context 'with a time entry version cf' do let(:field) { build_stubbed(:time_entry_custom_field, :version) } - it "is true" do + it 'is true' do expect(field) .to be_allow_non_open_versions_possible end end end - describe "#destroy" do - it "removes the cf" do + describe '#destroy' do + it 'removes the cf' do field.save! field.destroy diff --git a/spec/models/custom_option_spec.rb b/spec/models/custom_option_spec.rb index 524876a536e7..d5bbbe3583ee 100644 --- a/spec/models/custom_option_spec.rb +++ b/spec/models/custom_option_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomOption do let(:custom_field) do - cf = build(:wp_custom_field, field_format: "list") - cf.custom_options.build(value: "some value") + cf = build(:wp_custom_field, field_format: 'list') + cf.custom_options.build(value: 'some value') cf end @@ -42,7 +42,7 @@ custom_field.save! end - describe "saving" do + describe 'saving' do it "updates the custom_field's timestamp" do timestamp_before = custom_field.updated_at sleep 1 @@ -51,13 +51,13 @@ end end - describe ".destroy" do - context "with more than one option for the cf" do + describe '.destroy' do + context 'with more than one option for the cf' do before do create(:custom_option, custom_field:) end - it "removes the option" do + it 'removes the option' do custom_option.destroy expect(CustomOption.where(id: custom_option.id).count) @@ -72,17 +72,17 @@ end end - context "with only one option for the cf" do + context 'with only one option for the cf' do before do custom_option.destroy end - it "reports an error" do + it 'reports an error' do expect(custom_option.errors[:base]) - .to contain_exactly(I18n.t(:"activerecord.errors.models.custom_field.at_least_one_custom_option")) + .to contain_exactly(I18n.t(:'activerecord.errors.models.custom_field.at_least_one_custom_option')) end - it "does not remove the custom option" do + it 'does not remove the custom option' do expect(CustomOption.where(id: custom_option.id).count) .to be 1 end diff --git a/spec/models/custom_style_spec.rb b/spec/models/custom_style_spec.rb index 0e945f87beaa..153277621a36 100644 --- a/spec/models/custom_style_spec.rb +++ b/spec/models/custom_style_spec.rb @@ -1,16 +1,16 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomStyle do describe "#current" do subject { CustomStyle.current } context "there is one in DB" do - it "returns an instance" do + it 'returns an instance' do CustomStyle.create expect(subject).to be_a CustomStyle end - it "returns the same instance for subsequent calls" do + it 'returns the same instance for subsequent calls' do CustomStyle.create first_instance = CustomStyle.current expect(subject).to be first_instance @@ -22,7 +22,7 @@ RequestStore.delete(:current_custom_style) end - it "returns nil" do + it 'returns nil' do expect(subject).to be_nil end end @@ -37,11 +37,11 @@ custom_style.send :"remove_#{image}" end - it "deletes the file" do + it 'deletes the file' do expect(File.exist?(file_path)).to be false end - it "clears the file mount column" do + it 'clears the file mount column' do expect(custom_style.reload.send(image).file).to be_nil end end diff --git a/spec/models/custom_value/bool_strategy_spec.rb b/spec/models/custom_value/bool_strategy_spec.rb index 670d2fed20af..0d0a770e5684 100644 --- a/spec/models/custom_value/bool_strategy_spec.rb +++ b/spec/models/custom_value/bool_strategy_spec.rb @@ -26,178 +26,178 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::BoolStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:) end - describe "#value_present?" do + describe '#value_present?' do subject { described_class.new(custom_value).value_present? } - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be false } end - context "value is empty string" do - let(:value) { "" } + context 'value is empty string' do + let(:value) { '' } it { is_expected.to be false } end - context "value is present string" do - let(:value) { "1" } + context 'value is present string' do + let(:value) { '1' } it { is_expected.to be true } end - context "value is true" do + context 'value is true' do let(:value) { true } it { is_expected.to be true } end - context "value is false" do + context 'value is false' do let(:value) { false } it { is_expected.to be true } end end - describe "#typed_value" do + describe '#typed_value' do subject { instance.typed_value } - context "value corresponds to true" do - let(:value) { "1" } + context 'value corresponds to true' do + let(:value) { '1' } it { is_expected.to be true } end - context "value corresponds to false" do - let(:value) { "0" } + context 'value corresponds to false' do + let(:value) { '0' } it { is_expected.to be false } end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } it { is_expected.to be_nil } end - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be_nil } end - context "value is true" do + context 'value is true' do let(:value) { true } it { is_expected.to be true } end - context "value is false" do + context 'value is false' do let(:value) { false } it { is_expected.to be false } end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "value is present string" do - let(:value) { "1" } + context 'value is present string' do + let(:value) { '1' } - it "is the true string" do + it 'is the true string' do expect(subject).to eql I18n.t(:general_text_Yes) end end - context "value is zero string" do - let(:value) { "0" } + context 'value is zero string' do + let(:value) { '0' } - it "is the false string" do + it 'is the false string' do expect(subject).to eql I18n.t(:general_text_No) end end - context "value is true" do + context 'value is true' do let(:value) { true } - it "is the true string" do + it 'is the true string' do expect(subject).to eql I18n.t(:general_text_Yes) end end - context "value is false" do + context 'value is false' do let(:value) { false } - it "is the false string" do + it 'is the false string' do expect(subject).to eql I18n.t(:general_text_No) end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is the false string" do + it 'is the false string' do expect(subject).to eql I18n.t(:general_text_No) end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is the false string" do + it 'is the false string' do expect(subject).to eql I18n.t(:general_text_No) end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } - context "value corresponds to true" do - let(:value) { "1" } + context 'value corresponds to true' do + let(:value) { '1' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value corresponds to false" do - let(:value) { "0" } + context 'value corresponds to false' do + let(:value) { '0' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is true" do + context 'value is true' do let(:value) { true } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is false" do + context 'value is false' do let(:value) { false } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end end - describe "#parse_value" do + describe '#parse_value' do subject { instance.parse_value(value) } ActiveRecord::Type::Boolean::FALSE_VALUES.each do |falsey_value| @@ -205,12 +205,12 @@ let(:value) { falsey_value } it "is 'f'" do - expect(subject).to eql "f" + expect(subject).to eql 'f' end end end - context "for nil" do + context 'for nil' do let(:value) { nil } it "is nil" do @@ -219,19 +219,19 @@ end context "for ''" do - let(:value) { "" } + let(:value) { '' } it "is nil" do expect(subject).to be_nil end end - [true, "1", 1, "t", 42, "true"].each do |truthy_value| + [true, '1', 1, 't', 42, 'true'].each do |truthy_value| context "for #{truthy_value}" do let(:value) { truthy_value } it "is 't'" do - expect(subject).to eql "t" + expect(subject).to eql 't' end end end diff --git a/spec/models/custom_value/date_strategy_spec.rb b/spec/models/custom_value/date_strategy_spec.rb index 967cedc77bcc..d24cfb345159 100644 --- a/spec/models/custom_value/date_strategy_spec.rb +++ b/spec/models/custom_value/date_strategy_spec.rb @@ -26,106 +26,106 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::DateStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:) end - describe "#typed_value" do + describe '#typed_value' do subject { instance.typed_value } - context "value is some date string" do - let(:value) { "2015-01-03" } + context 'value is some date string' do + let(:value) { '2015-01-03' } it { is_expected.to eql(Date.iso8601(value)) } end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } it { is_expected.to be_nil } end - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be_nil } end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "value is some date string" do - let(:value) { "2015-01-03" } + context 'value is some date string' do + let(:value) { '2015-01-03' } - context "date format", with_settings: { date_format: "%Y-%m-%d" } do - it "is the date" do + context 'date format', with_settings: { date_format: '%Y-%m-%d' } do + it 'is the date' do expect(subject).to eql value end end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is a blank string" do + it 'is a blank string' do expect(subject).to be_nil end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is a blank string" do - expect(subject).to eql "" + it 'is a blank string' do + expect(subject).to eql '' end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } - context "value is valid date string" do - let(:value) { "2015-01-03" } + context 'value is valid date string' do + let(:value) { '2015-01-03' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is invalid date string in good format" do - let(:value) { "2015-02-30" } + context 'value is invalid date string in good format' do + let(:value) { '2015-02-30' } - it "rejects" do + it 'rejects' do expect(subject).to be(:not_a_date) end end - context "value is date string in bad format" do - let(:value) { "03.01.2015" } + context 'value is date string in bad format' do + let(:value) { '03.01.2015' } - it "rejects" do + it 'rejects' do expect(subject).to be(:not_a_date) end end - context "value is not a date string at all" do - let(:value) { "chicken" } + context 'value is not a date string at all' do + let(:value) { 'chicken' } - it "rejects" do + it 'rejects' do expect(subject).to be(:not_a_date) end end - context "value is valid date" do - let(:value) { Date.iso8601("2015-01-03") } + context 'value is valid date' do + let(:value) { Date.iso8601('2015-01-03') } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end diff --git a/spec/models/custom_value/float_strategy_spec.rb b/spec/models/custom_value/float_strategy_spec.rb index 4a8cc301d2a5..aa130e1f8f15 100644 --- a/spec/models/custom_value/float_strategy_spec.rb +++ b/spec/models/custom_value/float_strategy_spec.rb @@ -26,110 +26,110 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::FloatStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:) end - describe "#typed_value" do + describe '#typed_value' do subject { instance.typed_value } - context "value is some float string" do - let(:value) { "3.14" } + context 'value is some float string' do + let(:value) { '3.14' } it { is_expected.to be(3.14) } end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } it { is_expected.to be_nil } end - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be_nil } end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "value is some float string" do - let(:value) { "3.14" } + context 'value is some float string' do + let(:value) { '3.14' } - it "is the float string" do + it 'is the float string' do expect(subject).to eql value end - it "is localized" do + it 'is localized' do I18n.with_locale(:de) do - expect(subject).to eql "3,14" + expect(subject).to eql '3,14' end end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is a blank string" do + it 'is a blank string' do expect(subject).to eql value end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is a blank string" do - expect(subject).to eql "" + it 'is a blank string' do + expect(subject).to eql '' end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } - context "value is float string in decimal notation" do - let(:value) { "3.14" } + context 'value is float string in decimal notation' do + let(:value) { '3.14' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is float string in exp. notation" do - let(:value) { "5.0e-14" } + context 'value is float string in exp. notation' do + let(:value) { '5.0e-14' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is not a float string" do - let(:value) { "banana" } + context 'value is not a float string' do + let(:value) { 'banana' } - it "rejects" do + it 'rejects' do expect(subject).to be(:not_a_number) end end - context "value is float" do + context 'value is float' do let(:value) { 3.14 } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is int" do + context 'value is int' do let(:value) { 3 } - it "accepts" do + it 'accepts' do # accepting here, as we can "losslessly" convert expect(subject).to be_nil end diff --git a/spec/models/custom_value/format_strategy_spec.rb b/spec/models/custom_value/format_strategy_spec.rb index 622950ed1776..afca083b0f2d 100644 --- a/spec/models/custom_value/format_strategy_spec.rb +++ b/spec/models/custom_value/format_strategy_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::FormatStrategy do let(:custom_value) do - double("CustomValue", + double('CustomValue', value:) end - describe "#value_present?" do + describe '#value_present?' do subject { described_class.new(custom_value).value_present? } - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be(false) } end - context "value is empty string" do - let(:value) { "" } + context 'value is empty string' do + let(:value) { '' } it { is_expected.to be(false) } end - context "value is present string" do - let(:value) { "foo" } + context 'value is present string' do + let(:value) { 'foo' } it { is_expected.to be(true) } end - context "value is present integer" do + context 'value is present integer' do let(:value) { 42 } it { is_expected.to be(true) } diff --git a/spec/models/custom_value/int_strategy_spec.rb b/spec/models/custom_value/int_strategy_spec.rb index 9b912c7878d3..b2ffc3708833 100644 --- a/spec/models/custom_value/int_strategy_spec.rb +++ b/spec/models/custom_value/int_strategy_spec.rb @@ -26,98 +26,98 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::IntStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:) end - describe "#typed_value" do + describe '#typed_value' do subject { instance.typed_value } - context "value is some float string" do - let(:value) { "10" } + context 'value is some float string' do + let(:value) { '10' } it { is_expected.to be(10) } end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } it { is_expected.to be_nil } end - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be_nil } end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.typed_value } - context "value is some int string" do - let(:value) { "10" } + context 'value is some int string' do + let(:value) { '10' } it { is_expected.to be(10) } end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } it { is_expected.to be_nil } end - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be_nil } end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } - context "value is positive int string" do - let(:value) { "10" } + context 'value is positive int string' do + let(:value) { '10' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is negative int string" do - let(:value) { "-10" } + context 'value is negative int string' do + let(:value) { '-10' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is not an int string" do - let(:value) { "unicorn" } + context 'value is not an int string' do + let(:value) { 'unicorn' } - it "rejects" do + it 'rejects' do expect(subject).to be(:not_an_integer) end end - context "value is an actual int" do + context 'value is an actual int' do let(:value) { 10 } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is a float" do + context 'value is a float' do let(:value) { 2.3 } - it "rejects" do + it 'rejects' do expect(subject).to be(:not_an_integer) end end diff --git a/spec/models/custom_value/list_strategy_integration_spec.rb b/spec/models/custom_value/list_strategy_integration_spec.rb index bf07a96d46bf..49e736592742 100644 --- a/spec/models/custom_value/list_strategy_integration_spec.rb +++ b/spec/models/custom_value/list_strategy_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe CustomValue::ListStrategy, "integration tests" do +RSpec.describe CustomValue::ListStrategy, 'integration tests' do let(:type) { create(:type) } let(:project) { create(:project, types: [type]) } let!(:custom_field) do @@ -38,7 +38,7 @@ multi_value: true, types: [type], projects: [project], - possible_values: ["A", "B"] + possible_values: ['A', 'B'] ) end @@ -46,17 +46,17 @@ create(:work_package, project:, type:, - custom_values: { custom_field.id => custom_field.custom_options.find_by(value: "A") }) + custom_values: { custom_field.id => custom_field.custom_options.find_by(value: 'A') }) end - it "can handle invalid CustomOptions (Regression test)" do + it 'can handle invalid CustomOptions (Regression test)' do expect(work_package.public_send(custom_field.attribute_getter)).to eq(%w(A)) # Remove the custom value without replacement - CustomValue.find_by(customized_id: work_package.id).update_columns(value: "invalid") + CustomValue.find_by(customized_id: work_package.id).update_columns(value: 'invalid') work_package.reload work_package.reset_custom_values! - expect(work_package.public_send(custom_field.attribute_getter)).to eq(["invalid not found"]) + expect(work_package.public_send(custom_field.attribute_getter)).to eq(['invalid not found']) end end diff --git a/spec/models/custom_value/list_strategy_spec.rb b/spec/models/custom_value/list_strategy_spec.rb index 1942d1b9d79a..5bcf2b98c883 100644 --- a/spec/models/custom_value/list_strategy_spec.rb +++ b/spec/models/custom_value/list_strategy_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::ListStrategy do let(:instance) { described_class.new(custom_value) } @@ -35,15 +35,15 @@ double("CustomField", value:, custom_field:, customized:) end - let(:customized) { double("customized") } + let(:customized) { double('customized') } - describe "#parse_value/#typed_value" do + describe '#parse_value/#typed_value' do subject { instance } - context "with a CustomOption" do + context 'with a CustomOption' do let(:value) { custom_field.custom_options.first } - it "returns the CustomOption and sets it for later retrieval" do + it 'returns the CustomOption and sets it for later retrieval' do expect(CustomOption) .not_to receive(:where) @@ -53,20 +53,20 @@ end end - context "with an id string" do + context 'with an id string' do let(:value) { custom_field.custom_options.first.id.to_s } - it "returns the string and has to later find the CustoOption" do + it 'returns the string and has to later find the CustoOption' do expect(subject.parse_value(value)).to eql value expect(subject.typed_value).to eql custom_field.custom_options.first.value end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is nil and does not look for the CustomOption" do + it 'is nil and does not look for the CustomOption' do expect(CustomOption) .not_to receive(:where) @@ -76,10 +76,10 @@ end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is nil and does not look for the CustomOption" do + it 'is nil and does not look for the CustomOption' do expect(CustomOption) .not_to receive(:where) @@ -90,13 +90,13 @@ end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "with a CustomOption" do + context 'with a CustomOption' do let(:value) { custom_field.custom_options.first } - it "is the custom option to_s (without db access)" do + it 'is the custom option to_s (without db access)' do instance.parse_value(value) expect(CustomOption) @@ -106,46 +106,46 @@ end end - context "with an id string" do + context 'with an id string' do let(:value) { custom_field.custom_options.first.id.to_s } - it "is the custom option to_s (with db access)" do + it 'is the custom option to_s (with db access)' do expect(subject).to eql custom_field.custom_options.first.to_s end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is blank" do + it 'is blank' do expect(subject).to eql value end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is blank" do - expect(subject).to eql "" + it 'is blank' do + expect(subject).to eql '' end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } - context "value is included" do + context 'value is included' do let(:value) { custom_field.custom_options.first.id.to_s } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is not included" do - let(:value) { "cat" } + context 'value is not included' do + let(:value) { 'cat' } - it "rejects" do + it 'rejects' do expect(subject).to be(:inclusion) end end diff --git a/spec/models/custom_value/string_strategy_spec.rb b/spec/models/custom_value/string_strategy_spec.rb index c8b305ab37e2..71cffa027b5a 100644 --- a/spec/models/custom_value/string_strategy_spec.rb +++ b/spec/models/custom_value/string_strategy_spec.rb @@ -26,80 +26,80 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::StringStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:) end - describe "#typed_value" do + describe '#typed_value' do subject { instance.typed_value } - context "value is some string" do - let(:value) { "foo bar!" } + context 'value is some string' do + let(:value) { 'foo bar!' } it { is_expected.to eql(value) } end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } it { is_expected.to eql(value) } end - context "value is nil" do + context 'value is nil' do let(:value) { nil } it { is_expected.to be_nil } end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "value is some string" do - let(:value) { "foo bar!" } + context 'value is some string' do + let(:value) { 'foo bar!' } - it "is the string" do + it 'is the string' do expect(subject).to eql value end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is a blank string" do + it 'is a blank string' do expect(subject).to eql value end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is a blank string" do - expect(subject).to eql "" + it 'is a blank string' do + expect(subject).to eql '' end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } - context "value is some string" do - let(:value) { "foo bar!" } + context 'value is some string' do + let(:value) { 'foo bar!' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is empty string" do - let(:value) { "" } + context 'value is empty string' do + let(:value) { '' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end diff --git a/spec/models/custom_value/user_strategy_spec.rb b/spec/models/custom_value/user_strategy_spec.rb index 7db11e26061b..cdda80583eff 100644 --- a/spec/models/custom_value/user_strategy_spec.rb +++ b/spec/models/custom_value/user_strategy_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::UserStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:, custom_field:, customized:) end - let(:customized) { double("customized") } + let(:customized) { double('customized') } let(:custom_field) { build(:custom_field) } let(:user) { build_stubbed(:user) } - describe "#parse_value/#typed_value" do + describe '#parse_value/#typed_value' do subject { instance } - context "with a user" do + context 'with a user' do let(:value) { user } - it "returns the user and sets it for later retrieval" do + it 'returns the user and sets it for later retrieval' do expect(Principal) .not_to receive(:find_by) @@ -56,10 +56,10 @@ end end - context "with an id string" do + context 'with an id string' do let(:value) { user.id.to_s } - it "returns the string and has to later find the user" do + it 'returns the string and has to later find the user' do allow(Principal) .to receive(:find_by) .with(id: user.id.to_s) @@ -71,10 +71,10 @@ end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is nil and does not look for the user" do + it 'is nil and does not look for the user' do expect(Principal) .not_to receive(:find_by) @@ -84,10 +84,10 @@ end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is nil and does not look for the user" do + it 'is nil and does not look for the user' do expect(Principal) .not_to receive(:find_by) @@ -98,13 +98,13 @@ end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "with a User" do + context 'with a User' do let(:value) { user } - it "is the user to_s (without db access)" do + it 'is the user to_s (without db access)' do instance.parse_value(value) expect(Principal) @@ -114,10 +114,10 @@ end end - context "with an id string" do + context 'with an id string' do let(:value) { user.id.to_s } - it "is the user to_s (with db access)" do + it 'is the user to_s (with db access)' do allow(Principal) .to receive(:find_by) .with(id: user.id.to_s) @@ -127,24 +127,24 @@ end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is blank and does not look for the user" do - expect(subject).to eql "" + it 'is blank and does not look for the user' do + expect(subject).to eql '' end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is blank and does not look for the user" do - expect(subject).to eql "" + it 'is blank and does not look for the user' do + expect(subject).to eql '' end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } let(:allowed_ids) { %w(12 13) } @@ -153,18 +153,18 @@ allow(custom_field).to receive(:possible_values).with(customized).and_return(allowed_ids) end - context "value is id of included element" do - let(:value) { "12" } + context 'value is id of included element' do + let(:value) { '12' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is id of non included element" do - let(:value) { "10" } + context 'value is id of non included element' do + let(:value) { '10' } - it "rejects" do + it 'rejects' do expect(subject).to be(:inclusion) end end diff --git a/spec/models/custom_value/version_strategy_spec.rb b/spec/models/custom_value/version_strategy_spec.rb index 3098e1820ad4..3b868d556197 100644 --- a/spec/models/custom_value/version_strategy_spec.rb +++ b/spec/models/custom_value/version_strategy_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomValue::VersionStrategy do let(:instance) { described_class.new(custom_value) } let(:custom_value) do - double("CustomValue", + double('CustomValue', value:, custom_field:, customized:) end - let(:customized) { double("customized") } + let(:customized) { double('customized') } let(:custom_field) { build(:custom_field) } let(:version) { build_stubbed(:version) } - describe "#parse_value/#typed_value" do + describe '#parse_value/#typed_value' do subject { instance } - context "with a version" do + context 'with a version' do let(:value) { version } - it "returns the version and sets it for later retrieval" do + it 'returns the version and sets it for later retrieval' do expect(Version) .not_to receive(:find_by) @@ -56,10 +56,10 @@ end end - context "with an id string" do + context 'with an id string' do let(:value) { version.id.to_s } - it "returns the string and has to later find the version" do + it 'returns the string and has to later find the version' do allow(Version) .to receive(:find_by) .with(id: version.id.to_s) @@ -71,10 +71,10 @@ end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is nil and does not look for the version" do + it 'is nil and does not look for the version' do expect(Version) .not_to receive(:find_by) @@ -84,10 +84,10 @@ end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is nil and does not look for the version" do + it 'is nil and does not look for the version' do expect(Version) .not_to receive(:find_by) @@ -98,13 +98,13 @@ end end - describe "#formatted_value" do + describe '#formatted_value' do subject { instance.formatted_value } - context "with a version" do + context 'with a version' do let(:value) { version } - it "is the version to_s (without db access)" do + it 'is the version to_s (without db access)' do expect(Version) .not_to receive(:find_by) @@ -114,10 +114,10 @@ end end - context "with an id string" do + context 'with an id string' do let(:value) { version.id.to_s } - it "is the version to_s (with db access)" do + it 'is the version to_s (with db access)' do allow(Version) .to receive(:find_by) .with(id: version.id.to_s) @@ -127,30 +127,30 @@ end end - context "value is blank" do - let(:value) { "" } + context 'value is blank' do + let(:value) { '' } - it "is blank and does not look for the version" do + it 'is blank and does not look for the version' do expect(Version) .not_to receive(:find_by) - expect(subject).to eql "" + expect(subject).to eql '' end end - context "value is nil" do + context 'value is nil' do let(:value) { nil } - it "is blank and does not look for the version" do + it 'is blank and does not look for the version' do expect(Version) .not_to receive(:find_by) - expect(subject).to eql "" + expect(subject).to eql '' end end end - describe "#validate_type_of_value" do + describe '#validate_type_of_value' do subject { instance.validate_type_of_value } let(:allowed_ids) { %w(12 13) } @@ -159,18 +159,18 @@ allow(custom_field).to receive(:possible_values).with(customized).and_return(allowed_ids) end - context "value is id of included element" do - let(:value) { "12" } + context 'value is id of included element' do + let(:value) { '12' } - it "accepts" do + it 'accepts' do expect(subject).to be_nil end end - context "value is id of non included element" do - let(:value) { "10" } + context 'value is id of non included element' do + let(:value) { '10' } - it "rejects" do + it 'rejects' do expect(subject).to be(:inclusion) end end diff --git a/spec/models/day_spec.rb b/spec/models/day_spec.rb index 6599c7f68424..7a3eec7a45bf 100644 --- a/spec/models/day_spec.rb +++ b/spec/models/day_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Day do shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } @@ -15,144 +15,144 @@ it { is_expected.to respond_to :day_of_week } it { is_expected.to respond_to :name } - context "with default_scope" do + context 'with default_scope' do let(:days) { described_class.default_scope } - it "returns a default date range" do + it 'returns a default date range' do expect(days.minmax.pluck(:date)).to eq( [today.at_beginning_of_month, today.next_month.at_end_of_month] ) end - it "loads week_day method" do + it 'loads week_day method' do expect(days).to(be_all { |d| d.week_day.present? }) end - it "eager loads non_working_days relation" do + it 'eager loads non_working_days relation' do expect(days).to(be_all { |d| d.association(:non_working_days).loaded? }) end - it "loads the id attribute" do - expect(days.first.id).to eq(today.at_beginning_of_month.strftime("%Y%m%d").to_i) + it 'loads the id attribute' do + expect(days.first.id).to eq(today.at_beginning_of_month.strftime('%Y%m%d').to_i) end - it "loads the date attribute" do + it 'loads the date attribute' do expect(days.first.date).to eq(today.at_beginning_of_month) end - it "loads the day_of_week attribute" do + it 'loads the day_of_week attribute' do expect(days.first.day_of_week % 7).to eq(today.at_beginning_of_month.wday) # wday is from 0-6 end - it "loads the name attribute" do + it 'loads the name attribute' do expect(days.first.name).to eq(today.at_beginning_of_month.strftime("%A")) end end - context "for collection with multiple non-working days" do + context 'for collection with multiple non-working days' do let(:non_working_dates) { [date_range.begin, date_range.begin + 1.day] } before do non_working_dates.each { |date| create(:non_working_day, date:) } end - it "returns the correct number of days" do + it 'returns the correct number of days' do expect(days.count).to eq(date_range.count) end - it "returns the dates included in the date_range" do + it 'returns the dates included in the date_range' do expect(days.collect(&:date)).to eq(date_range.to_a) end - it "returns working false for weekends and non_working_days" do + it 'returns working false for weekends and non_working_days' do expected_working_states = date_range.map do |day| !(day.saturday? || day.sunday? || day.in?(non_working_dates)) end expect(days.pluck(:working)).to eq(expected_working_states) end - it "returns the correct day_of_week" do + it 'returns the correct day_of_week' do expected_days_of_week = date_range.map { |day| Array(1..7)[day.wday - 1] } expect(days.pluck(:day_of_week)).to eq(expected_days_of_week) end end - context "with the weekday present" do - it "loads the name attribute" do - expect(subject.name).to eq("Saturday") + context 'with the weekday present' do + it 'loads the name attribute' do + expect(subject.name).to eq('Saturday') end end - describe ".last_working" do + describe '.last_working' do subject { described_class.last_working } around do |ex| Timecop.travel(current_time, &ex) end - context "when today is Monday" do + context 'when today is Monday' do let(:current_time) { Time.current.monday } - context "when yesterday is a weekend day" do - it "returns last Friday" do + context 'when yesterday is a weekend day' do + it 'returns last Friday' do expect(subject.date).to eq(current_time.prev_occurring(:friday)) end end end - context "when today is Tuesday" do + context 'when today is Tuesday' do let(:current_time) { Time.current.monday + 1.day } - context "when yesterday is working" do - it "returns Monday" do + context 'when yesterday is working' do + it 'returns Monday' do expect(subject.date).to eq(current_time.yesterday) end end - context "when yesterday is non-working" do + context 'when yesterday is non-working' do before do create(:non_working_day, date: current_time.yesterday) end - it "returns last Friday" do + it 'returns last Friday' do expect(subject.date).to eq(current_time.prev_occurring(:friday)) end end end end - describe "#working" do - context "when the week day is non-working" do + describe '#working' do + context 'when the week day is non-working' do shared_let(:working_days) { week_with_no_working_days } - it "is false" do + it 'is false' do expect(subject.working).to be_falsy end - context "with a non-working day" do + context 'with a non-working day' do before do create(:non_working_day, date: first_of_year) end - it "is false" do + it 'is false' do expect(subject.working).to be_falsy end end end - context "when the week day is working" do - shared_let(:working_days) { set_work_week("saturday") } + context 'when the week day is working' do + shared_let(:working_days) { set_work_week('saturday') } - it "is true" do + it 'is true' do expect(subject.working).to be_truthy end - context "with a non working day" do + context 'with a non working day' do before do create(:non_working_day, date: first_of_year) end - it "is false" do + it 'is false' do expect(subject.working).to be_falsy end end diff --git a/spec/models/db_and_ar_length_constraints_spec.rb b/spec/models/db_and_ar_length_constraints_spec.rb index 82a1732f4a25..50c3b0be6f62 100644 --- a/spec/models/db_and_ar_length_constraints_spec.rb +++ b/spec/models/db_and_ar_length_constraints_spec.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "DB and ActiveRecord constraints" do # rubocop:disable RSpec/DescribeClass +RSpec.describe 'DB and ActiveRecord constraints' do # rubocop:disable RSpec/DescribeClass def self.has_max_length_validator?(model) max_length_validators(model).any? end @@ -50,7 +50,7 @@ def self.db_maximum_length(table_name, column_name) ] ) rows = ActiveRecord::Base.connection.execute(query) - rows.first["character_maximum_length"] + rows.first['character_maximum_length'] end ApplicationRecord.descendants diff --git a/spec/models/deleted_user_spec.rb b/spec/models/deleted_user_spec.rb index c2bf340221a3..72f49d32559c 100644 --- a/spec/models/deleted_user_spec.rb +++ b/spec/models/deleted_user_spec.rb @@ -26,40 +26,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DeletedUser do let(:user) { DeletedUser.new } - describe "#admin" do + describe '#admin' do it { expect(user.admin).to be_falsey } end - describe "#logged?" do + describe '#logged?' do it { expect(user).not_to be_logged } end - describe "#name" do - it { expect(user.name).to eq(I18n.t("user.deleted")) } + describe '#name' do + it { expect(user.name).to eq(I18n.t('user.deleted')) } end - describe "#mail" do + describe '#mail' do it { expect(user.mail).to be_nil } end - describe "#time_zone" do + describe '#time_zone' do it { expect(user.time_zone).to be_nil } end - describe "#rss_key" do + describe '#rss_key' do it { expect(user.rss_key).to be_nil } end - describe "#destroy" do + describe '#destroy' do it { expect(user.destroy).to be_falsey } end - describe "#available_custom_fields" do + describe '#available_custom_fields' do before do create(:user_custom_field) end @@ -67,8 +67,8 @@ it { expect(user.available_custom_fields).to eq([]) } end - describe "#create" do - describe "WHEN creating a second deleted user" do + describe '#create' do + describe 'WHEN creating a second deleted user' do let(:u1) { build(:deleted_user) } let(:u2) { build(:deleted_user) } @@ -79,20 +79,20 @@ it { expect(u1).not_to be_new_record } it { expect(u2).to be_new_record } - it { expect(u2.errors[:base]).to include "A DeletedUser already exists." } + it { expect(u2.errors[:base]).to include 'A DeletedUser already exists.' } end end - describe "#valid" do - describe "WHEN no login, first-, lastname and mail is provided" do + describe '#valid' do + describe 'WHEN no login, first-, lastname and mail is provided' do let(:user) { DeletedUser.new } it { expect(user).to be_valid } end end - describe "#first" do - describe "WHEN a deleted user already exists" do + describe '#first' do + describe 'WHEN a deleted user already exists' do let(:user) { build(:deleted_user) } before do @@ -102,7 +102,7 @@ it { expect(DeletedUser.first).to eq(user) } end - describe "WHEN no deleted user exists" do + describe 'WHEN no deleted user exists' do it { expect(DeletedUser.first.is_a?(DeletedUser)).to be_truthy } it { expect(DeletedUser.first).not_to be_new_record } end diff --git a/spec/models/design_color_spec.rb b/spec/models/design_color_spec.rb index 2411ce5fe3f0..355eb5caa4a0 100644 --- a/spec/models/design_color_spec.rb +++ b/spec/models/design_color_spec.rb @@ -1,8 +1,8 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe DesignColor do - let(:default_primary) { OpenProject::CustomStyles::Design.variables["primary-button-color"] } - let(:primary_color) { create(:"design_color_primary-button-color") } + let(:default_primary) { OpenProject::CustomStyles::Design.variables['primary-color'] } + let(:primary_color) { create(:'design_color_primary-color') } describe "#setables" do it "returns an Array of instances" do @@ -10,7 +10,7 @@ expect(described_class.setables.first).to be_a(described_class) end - it "not overwritten defaults do not have a color set" do + it 'not overwritten defaults do not have a color set' do expect(described_class.setables.first.hexcode).to be_nil end @@ -28,7 +28,7 @@ end it "returns nil hexcode if hexcode not present" do - expect(described_class.new(variable: "primary-button-color").hexcode) + expect(described_class.new(variable: "primary-color").hexcode) .to be_nil end end @@ -43,7 +43,7 @@ design_color.save end - it "fails validation for another design_color with same name" do + it 'fails validation for another design_color with same name' do second_color_variable = DesignColor.new variable: "foo", hexcode: "#888888" expect(second_color_variable.valid?).to be_falsey end @@ -71,7 +71,7 @@ context "no CustomStyle.current exists yet" do subject { DesignColor.new variable: "foo", hexcode: "#111111" } - it "creates a CustomStyle.current" do + it 'creates a CustomStyle.current' do expect(CustomStyle.current).to be_nil subject.save expect(CustomStyle.current).to be_present diff --git a/spec/models/enabled_module_spec.rb b/spec/models/enabled_module_spec.rb index 86f4ebeeb0ec..06da6d0bffce 100644 --- a/spec/models/enabled_module_spec.rb +++ b/spec/models/enabled_module_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe EnabledModule do # Force reload, as association is not always(?) showing let(:project) { create(:project, enabled_module_names: modules).reload } - describe "#wiki" do + describe '#wiki' do let(:modules) { %w[wiki] } - it "creates a wiki" do + it 'creates a wiki' do expect(project.wiki).not_to be_nil - expect(project.wiki.start_page).to eq("Wiki") + expect(project.wiki.start_page).to eq('Wiki') end - it "does not create a separate wiki when one exists already" do + it 'does not create a separate wiki when one exists already' do expect(project.wiki).not_to be_nil expect do @@ -49,40 +49,40 @@ end.not_to change { Wiki.count } expect do - project.enabled_module_names = ["wiki"] + project.enabled_module_names = ['wiki'] end.not_to change { Wiki.count } expect(project.wiki).not_to be_nil end - context "with disabled module" do + context 'with disabled module' do let(:modules) { [] } - it "does not create a wiki" do + it 'does not create a wiki' do expect(project.wiki).to be_nil end - it "creates a wiki when the module is enabled at a later time" do - project.enabled_module_names = ["wiki"] + it 'creates a wiki when the module is enabled at a later time' do + project.enabled_module_names = ['wiki'] project.reload expect(project.wiki).not_to be_nil - expect(project.wiki.start_page).to eq("Wiki") + expect(project.wiki.start_page).to eq('Wiki') end end end - describe "#repository" do + describe '#repository' do let(:modules) { %w[repository] } before do allow(Setting).to receive(:repositories_automatic_managed_vendor).and_return(vendor) end - shared_examples "does not create a repository when one exists" do + shared_examples 'does not create a repository when one exists' do let!(:repository) { create(:repository_git, project:) } - it "does not create a separate repository when one exists already" do + it 'does not create a separate repository when one exists already' do project.reload expect(project.repository).not_to be_nil @@ -92,40 +92,40 @@ end.not_to change { Repository.count } expect do - project.enabled_module_names = ["repository"] + project.enabled_module_names = ['repository'] end.not_to change { Repository.count } expect(project.repository).not_to be_nil end end - context "with disabled setting" do + context 'with disabled setting' do let(:vendor) { nil } - it "does not create a repository" do + it 'does not create a repository' do expect(project.repository).to be_nil end - it_behaves_like "does not create a repository when one exists" + it_behaves_like 'does not create a repository when one exists' end - context "with enabled setting" do - let(:vendor) { "git" } + context 'with enabled setting' do + let(:vendor) { 'git' } let(:config) do { - git: { manages: File.join(tmpdir, "git") } + git: { manages: File.join(tmpdir, 'git') } } end - include_context "with tmpdir" + include_context 'with tmpdir' before do - allow(Setting).to receive(:enabled_scm).and_return(["git"]) + allow(Setting).to receive(:enabled_scm).and_return(['git']) allow(OpenProject::Configuration).to receive(:[]).and_call_original - allow(OpenProject::Configuration).to receive(:[]).with("scm").and_return(config) + allow(OpenProject::Configuration).to receive(:[]).with('scm').and_return(config) end - it "creates a repository of the given vendor" do + it 'creates a repository of the given vendor' do project.reload expect(project.repository).not_to be_nil @@ -133,20 +133,20 @@ expect(project.repository.managed?).to be true end - it "does not remove the repository when setting is removed" do + it 'does not remove the repository when setting is removed' do project.enabled_module_names = [] project.reload expect(project.repository).not_to be_nil end - it_behaves_like "does not create a repository when one exists" + it_behaves_like 'does not create a repository when one exists' end - context "with invalid setting" do - let(:vendor) { "some weird vendor" } + context 'with invalid setting' do + let(:vendor) { 'some weird vendor' } - it "does not create a repository" do + it 'does not create a repository' do expect(project.repository).to be_nil end end diff --git a/spec/models/enterprise_token_spec.rb b/spec/models/enterprise_token_spec.rb index 850a9dc4205b..e3caccc4b739 100644 --- a/spec/models/enterprise_token_spec.rb +++ b/spec/models/enterprise_token_spec.rb @@ -1,55 +1,55 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe EnterpriseToken do let(:object) { OpenProject::Token.new domain: Setting.host_name } - subject { EnterpriseToken.new(encoded_token: "foo") } + subject { EnterpriseToken.new(encoded_token: 'foo') } before do RequestStore.delete :current_ee_token allow(OpenProject::Configuration).to receive(:ee_manager_visible?).and_return(true) end - describe ".active?" do + describe '.active?' do before do allow(described_class).to receive(:current).and_return(subject) allow(described_class.current).to receive(:token_object).and_return(object) subject.save!(validate: false) end - context "with a non expired token" do + context 'with a non expired token' do before do allow(object).to receive(:expired?).and_return(false) end - it "returns true" do + it 'returns true' do expect(described_class.active?).to be(true) end end - context "with an expired token" do + context 'with an expired token' do before do allow(object).to receive(:expired?).and_return(true) end - it "returns false" do + it 'returns false' do expect(described_class.active?).to be(false) end end end - describe "existing token" do + describe 'existing token' do before do allow_any_instance_of(EnterpriseToken).to receive(:token_object).and_return(object) subject.save!(validate: false) end - context "when inner token is active" do - it "has an active token" do + context 'when inner token is active' do + it 'has an active token' do expect(object).to receive(:expired?).and_return(false) expect(EnterpriseToken.count).to eq(1) expect(EnterpriseToken.current).to eq(subject) - expect(EnterpriseToken.current.encoded_token).to eq("foo") + expect(EnterpriseToken.current.encoded_token).to eq('foo') expect(EnterpriseToken.show_banners?).to be(false) # Deleting it updates the current token @@ -59,25 +59,25 @@ expect(EnterpriseToken.current).to be_nil end - it "delegates to the token object" do + it 'delegates to the token object' do allow(object).to receive_messages( - subscriber: "foo", - mail: "bar", + subscriber: 'foo', + mail: 'bar', starts_at: Date.today, issued_at: Date.today, - expires_at: "never", + expires_at: 'never', restrictions: { foo: :bar } ) - expect(subject.subscriber).to eq("foo") - expect(subject.mail).to eq("bar") + expect(subject.subscriber).to eq('foo') + expect(subject.mail).to eq('bar') expect(subject.starts_at).to eq(Date.today) expect(subject.issued_at).to eq(Date.today) - expect(subject.expires_at).to eq("never") + expect(subject.expires_at).to eq('never') expect(subject.restrictions).to eq(foo: :bar) end - describe "#allows_to?" do + describe '#allows_to?' do let(:service_double) { Authorization::EnterpriseService.new(subject) } before do @@ -85,15 +85,15 @@ .to receive(:new).twice.with(subject).and_return(service_double) end - it "forwards to EnterpriseTokenService for checks" do + it 'forwards to EnterpriseTokenService for checks' do expect(service_double) .to receive(:call) .with(:forbidden_action) - .and_return double("ServiceResult", result: false) + .and_return double('ServiceResult', result: false) expect(service_double) .to receive(:call) .with(:allowed_action) - .and_return double("ServiceResult", result: true) + .and_return double('ServiceResult', result: true) expect(EnterpriseToken.allows_to?(:forbidden_action)).to be false expect(EnterpriseToken.allows_to?(:allowed_action)).to be true @@ -101,41 +101,41 @@ end end - context "when inner token is expired" do + context 'when inner token is expired' do before do expect(object).to receive(:expired?).and_return(true) end - it "has an expired token" do + it 'has an expired token' do expect(EnterpriseToken.current).to eq(subject) expect(EnterpriseToken.show_banners?).to be(true) end end - context "updating it with an invalid token" do - it "fails validations" do + context 'updating it with an invalid token' do + it 'fails validations' do subject.encoded_token = "bar" expect(subject.save).to be_falsey end end end - describe "no token" do + describe 'no token' do it do expect(EnterpriseToken.current).to be_nil expect(EnterpriseToken.show_banners?).to be(true) end end - describe "invalid token" do - it "appears as if no token is shown" do + describe 'invalid token' do + it 'appears as if no token is shown' do expect(EnterpriseToken.current).to be_nil expect(EnterpriseToken.show_banners?).to be(true) end end describe "Configuration file has `ee_manager_visible` set to false" do - it "does not show banners promoting EE" do + it 'does not show banners promoting EE' do expect(OpenProject::Configuration).to receive(:ee_manager_visible?).and_return(false) expect(EnterpriseToken.show_banners?).to be_falsey end diff --git a/spec/models/forum_spec.rb b/spec/models/forum_spec.rb index 45cfef36f4ff..974b07c668f2 100644 --- a/spec/models/forum_spec.rb +++ b/spec/models/forum_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require "support/shared/acts_as_watchable" +require 'support/shared/acts_as_watchable' RSpec.describe Forum do - it_behaves_like "acts_as_watchable included" do + it_behaves_like 'acts_as_watchable included' do let(:model_instance) { create(:forum) } let(:watch_permission) { :view_messages } # view_messages is a public permission let(:project) { model_instance.project } end - describe "with forum present" do - let(:forum) { build(:forum, name: "Test forum", description: "Whatever") } + describe 'with forum present' do + let(:forum) { build(:forum, name: 'Test forum', description: 'Whatever') } - it "creates" do + it 'creates' do expect(forum.save).to be_truthy forum.reload - expect(forum.name).to eq "Test forum" - expect(forum.description).to eq "Whatever" + expect(forum.name).to eq 'Test forum' + expect(forum.description).to eq 'Whatever' expect(forum.topics_count).to eq 0 expect(forum.messages_count).to eq 0 expect(forum.last_message).to be_nil diff --git a/spec/models/global_role_spec.rb b/spec/models/global_role_spec.rb index ff4805c39dbd..21b3bf9b206f 100644 --- a/spec/models/global_role_spec.rb +++ b/spec/models/global_role_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe GlobalRole do - before { GlobalRole.create name: "globalrole", permissions: ["permissions"] } + before { GlobalRole.create name: 'globalrole', permissions: ['permissions'] } it { is_expected.to validate_presence_of :name } it { is_expected.to validate_uniqueness_of :name } it { is_expected.to validate_length_of(:name).is_at_most(256) } - describe "attributes" do + describe 'attributes' do before { @role = GlobalRole.new } subject { @role } @@ -45,59 +45,59 @@ it { is_expected.to respond_to :position } end - describe "instance methods" do + describe 'instance methods' do before do @role = GlobalRole.new end - describe "WITH no attributes set" do + describe 'WITH no attributes set' do before do @role = GlobalRole.new end - describe "#permissions" do + describe '#permissions' do subject { @role.permissions } it { is_expected.to be_an_instance_of(Array) } - it "has no items" do + it 'has no items' do expect(subject.size).to eq(0) end end - describe "#has_permission?" do + describe '#has_permission?' do it { expect(@role.has_permission?(:perm)).to be_falsey } end - describe "#allowed_to?" do - describe "WITH requested permission" do + describe '#allowed_to?' do + describe 'WITH requested permission' do it { expect(@role.allowed_to?(:perm1)).to be_falsey } end end end - describe "WITH set permissions" do + describe 'WITH set permissions' do before { @role = GlobalRole.new permissions: %i[perm1 perm2 perm3] } - describe "#has_permission?" do + describe '#has_permission?' do it { expect(@role.has_permission?(:perm1)).to be_truthy } - it { expect(@role.has_permission?("perm1")).to be_truthy } + it { expect(@role.has_permission?('perm1')).to be_truthy } it { expect(@role.has_permission?(:perm5)).to be_falsey } end - describe "#allowed_to?" do - describe "WITH requested permission" do + describe '#allowed_to?' do + describe 'WITH requested permission' do it { expect(@role.allowed_to?(:perm1)).to be_truthy } it { expect(@role.allowed_to?(:perm5)).to be_falsey } end end end - describe "WITH set name" do - before { @role = GlobalRole.new name: "name" } + describe 'WITH set name' do + before { @role = GlobalRole.new name: 'name' } - describe "#to_s" do - it { expect(@role.to_s).to eql("name") } + describe '#to_s' do + it { expect(@role.to_s).to eql('name') } end end end diff --git a/spec/models/group_performance_spec.rb b/spec/models/group_performance_spec.rb index c1001e54c68f..82e7e50d3309 100644 --- a/spec/models/group_performance_spec.rb +++ b/spec/models/group_performance_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/shared/become_member" +require 'spec_helper' +require_relative '../support/shared/become_member' RSpec.describe Group do include BecomeMember @@ -67,8 +67,8 @@ let(:users) { create_list(:user, 100) } let(:group) { build(:group, members: users) } - describe "#destroy" do - describe "work packages assigned to the group" do + describe '#destroy' do + describe 'work packages assigned to the group' do let(:deleted_user) { DeletedUser.first } before do @@ -88,7 +88,7 @@ expect(@seconds < 10).to be true end - it "reassigns the work package to nobody and cleans up the journals" do + it 'reassigns the work package to nobody and cleans up the journals' do expect(OpenProject::Notifications) .to have_received(:send) .with(OpenProject::Events::MEMBER_DESTROYED, any_args) diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 7477d3bf6f42..05918248348f 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/shared/become_member" +require 'spec_helper' +require_relative '../support/shared/become_member' RSpec.describe Group do let(:group) { create(:group) } @@ -42,39 +42,39 @@ status:) end - it "creates" do - g = described_class.new(lastname: "New group") + it 'creates' do + g = described_class.new(lastname: 'New group') expect(g.save).to be true end - describe "with long but allowed attributes" do - it "is valid" do - group.name = "a" * 256 + describe 'with long but allowed attributes' do + it 'is valid' do + group.name = 'a' * 256 expect(group).to be_valid expect(group.save).to be_truthy end end - describe "with a name too long" do - it "is invalid" do - group.name = "a" * 257 + describe 'with a name too long' do + it 'is invalid' do + group.name = 'a' * 257 expect(group).not_to be_valid expect(group.save).to be_falsey end end - describe "a user with and overly long firstname (> 256 chars)" do - it "is invalid" do - user.firstname = "a" * 257 + describe 'a user with and overly long firstname (> 256 chars)' do + it 'is invalid' do + user.firstname = 'a' * 257 expect(user).not_to be_valid expect(user.save).to be_falsey end end - describe "#group_users" do - context "when adding a user" do - context "if it does not exist" do - it "does not create a group user" do + describe '#group_users' do + context 'when adding a user' do + context 'if it does not exist' do + it 'does not create a group user' do count = group.group_users.count gu = group.group_users.create user_id: User.maximum(:id).to_i + 1 @@ -83,7 +83,7 @@ end end - it "updates the timestamp" do + it 'updates the timestamp' do updated_at = group.updated_at group.group_users.create(user:) @@ -92,8 +92,8 @@ end end - context "when removing a user" do - it "updates the timestamp" do + context 'when removing a user' do + it 'updates the timestamp' do group.group_users.create(user:) updated_at = group.reload.updated_at @@ -105,23 +105,23 @@ end end - describe "#create" do - describe "group with empty group name" do - let(:group) { build(:group, lastname: "") } + describe '#create' do + describe 'group with empty group name' do + let(:group) { build(:group, lastname: '') } it { expect(group).not_to be_valid } - describe "error message" do + describe 'error message' do before do group.valid? end - it { expect(group.errors.full_messages[0]).to include I18n.t("attributes.name") } + it { expect(group.errors.full_messages[0]).to include I18n.t('attributes.name') } end end end - describe "preference" do + describe 'preference' do %w{preference preference= build_preference @@ -133,16 +133,16 @@ end end - describe "#name" do + describe '#name' do it { expect(group).to validate_presence_of :name } it { expect(group).to validate_uniqueness_of :name } end - include_examples "creates an audit trail on destroy" do + include_examples 'creates an audit trail on destroy' do subject { create(:attachment) } end - it_behaves_like "acts_as_customizable included" do + it_behaves_like 'acts_as_customizable included' do let(:model_instance) { group } let(:custom_field) { create(:group_custom_field, :string) } end diff --git a/spec/models/issue_priority_spec.rb b/spec/models/issue_priority_spec.rb index e849dfa5d0ea..0a711708da6e 100644 --- a/spec/models/issue_priority_spec.rb +++ b/spec/models/issue_priority_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe IssuePriority do shared_let(:priority) { create(:priority) } @@ -33,18 +33,18 @@ let(:stubbed_priority) { build_stubbed(:priority) } - describe ".ancestors" do - it "is an enumeration" do + describe '.ancestors' do + it 'is an enumeration' do expect(IssuePriority.ancestors) .to include(Enumeration) end end - describe "#objects_count" do + describe '#objects_count' do let(:work_package1) { create(:work_package, priority:) } let(:work_package2) { create(:work_package) } - it "counts the work packages having the priority" do + it 'counts the work packages having the priority' do expect(priority.objects_count) .to be 0 @@ -57,15 +57,15 @@ end end - describe "#option_name" do - it "is a symbol" do + describe '#option_name' do + it 'is a symbol' do expect(stubbed_priority.option_name) .to be :enumeration_work_package_priorities end end - describe "#cache_key" do - it "updates when the updated_at field changes" do + describe '#cache_key' do + it 'updates when the updated_at field changes' do old_cache_key = stubbed_priority.cache_key stubbed_priority.updated_at = Time.now @@ -75,13 +75,13 @@ end end - describe "#transer_to" do + describe '#transer_to' do let(:new_priority) { create(:priority) } let(:work_package1) { create(:work_package, priority:) } let(:work_package2) { create(:work_package) } let(:work_package3) { create(:work_package, priority: new_priority) } - it "moves all work_packages to the designated priority" do + it 'moves all work_packages to the designated priority' do work_package1 work_package2 work_package3 @@ -93,45 +93,45 @@ end end - describe "#in_use?" do - context "with a work package that uses the priority" do + describe '#in_use?' do + context 'with a work package that uses the priority' do let!(:work_package) { create(:work_package, priority:) } - it "is true" do + it 'is true' do expect(priority) .to be_in_use end end - context "without a work package that uses the priority" do - it "is false" do + context 'without a work package that uses the priority' do + it 'is false' do expect(priority) .not_to be_in_use end end end - describe ".default" do - it "returns the default priority" do + describe '.default' do + it 'returns the default priority' do expect(described_class.default) .to eq default_priority end - it "changes if a new default priority is created" do - new_default = described_class.create(name: "New default", is_default: true) + it 'changes if a new default priority is created' do + new_default = described_class.create(name: 'New default', is_default: true) expect(described_class.default) .to eq new_default end - it "does not change if a new non default priority is created" do - described_class.create(name: "New default", is_default: false) + it 'does not change if a new non default priority is created' do + described_class.create(name: 'New default', is_default: false) expect(described_class.default) .to eq default_priority end - it "is nil if the default priority looses the default flag" do + it 'is nil if the default priority looses the default flag' do default_priority.update(is_default: false) expect(described_class.default) @@ -139,25 +139,25 @@ end end - describe "#default?" do - it "is true for a default priority" do + describe '#default?' do + it 'is true for a default priority' do expect(default_priority) .to be_is_default end - it "is false for a non default priority" do + it 'is false for a non default priority' do expect(priority) .not_to be_is_default end - it "changes if a new default priority is created" do - described_class.create(name: "New default", is_default: true) + it 'changes if a new default priority is created' do + described_class.create(name: 'New default', is_default: true) expect(default_priority.reload) .not_to be_is_default end - it "changes if an existing priority is assigned default" do + it 'changes if an existing priority is assigned default' do new_default_priority = create(:priority) new_default_priority.update(is_default: true) @@ -166,11 +166,11 @@ end end - describe ".destroy" do + describe '.destroy' do let!(:work_package) { create(:work_package, priority:) } - context "with reassign" do - it "reassigns the work packages" do + context 'with reassign' do + it 'reassigns the work packages' do priority.destroy(default_priority) expect(WorkPackage.where(priority: default_priority)) @@ -178,8 +178,8 @@ end end - context "without reassign" do - it "raises an error as it is in use" do + context 'without reassign' do + it 'raises an error as it is in use' do expect { priority.destroy } .to raise_error RuntimeError end diff --git a/spec/models/journable/historic_active_record_relation_spec.rb b/spec/models/journable/historic_active_record_relation_spec.rb index d0d7853ce547..0d98338a5af1 100644 --- a/spec/models/journable/historic_active_record_relation_spec.rb +++ b/spec/models/journable/historic_active_record_relation_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journable::HistoricActiveRecordRelation do # See: https://github.com/opf/openproject/pull/11243 @@ -223,31 +223,31 @@ describe "when searching for custom fields" do let(:custom_field) do create(:text_wp_custom_field, - name: "Text CF", + name: 'Text CF', types: project.types, projects: [project]) end let!(:monday_cf_journal) do - create(:journal_customizable_journal, journal: monday_journal, custom_field:, value: "Monday_CV") + create(:journal_customizable_journal, journal: monday_journal, custom_field:, value: 'Monday_CV') end let!(:wednesday_cf_journal) do - create(:journal_customizable_journal, journal: wednesday_journal, custom_field:, value: "Wednesday_CV") + create(:journal_customizable_journal, journal: wednesday_journal, custom_field:, value: 'Wednesday_CV') end let!(:friday_cf_journal) do - create(:journal_customizable_journal, journal: friday_journal, custom_field:, value: "Friday_CV") + create(:journal_customizable_journal, journal: friday_journal, custom_field:, value: 'Friday_CV') end - let(:work_package_attributes) { { custom_values: { custom_field.id => "Friday_CV" } } } + let(:work_package_attributes) { { custom_values: { custom_field.id => 'Friday_CV' } } } let(:filter) do Queries::WorkPackages::Filter::CustomFieldFilter.create!( name: custom_field.column_name, context: build_stubbed(:query, project:), - operator: "~", + operator: '~', values: ) end let(:relation) { WorkPackage.where(filter.where) } - context "with the current value at the current time" do + context 'with the current value at the current time' do let(:values) { %w(Friday_CV) } let(:historic_relation) { relation.at_timestamp(Timestamp.new("PT0S")) } @@ -256,7 +256,7 @@ end end - context "with the matching historic value" do + context 'with the matching historic value' do let(:values) { %w(Wednesday_CV) } it "transforms the expression to join the customizable_journals" do @@ -276,7 +276,7 @@ end end - context "with a different historic value" do + context 'with a different historic value' do let(:values) { %w(Monday_CV) } it "does not return the requested work package" do @@ -490,7 +490,7 @@ end it "joins the projects table" do - sql = subject.to_sql.tr('"', "") + sql = subject.to_sql.tr('"', '') expect(sql).to include \ "LEFT OUTER JOIN projects ON projects.id = work_package_journals.project_id" expect(sql).to include \ diff --git a/spec/models/journable/timestamps_spec.rb b/spec/models/journable/timestamps_spec.rb index 6db86df45c97..7356bcf0d209 100644 --- a/spec/models/journable/timestamps_spec.rb +++ b/spec/models/journable/timestamps_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journable::Timestamps do # See: https://github.com/opf/openproject/pull/11243 @@ -86,7 +86,7 @@ expect(subject.first.readonly?).to be true end - it "adds a `timestamp` property to the returned work packages" do + it 'adds a `timestamp` property to the returned work packages' do expect(subject.first.timestamp).to eq timestamp.iso8601 end @@ -173,7 +173,7 @@ expect(subject.find { |wp| wp.timestamp == monday.iso8601 }.description) .to eq "The work package as it has been on Monday" - expect(subject.find { |wp| wp.timestamp == "PT0S" }.description) + expect(subject.find { |wp| wp.timestamp == 'PT0S' }.description) .to eq "The work package as it is since Friday" end end @@ -397,7 +397,7 @@ describe "when using a GROUP BY COUNT HAVING query" do describe "without at_timestamp" do - subject { WorkPackage.group(:estimated_hours).having("estimated_hours > 3").count } + subject { WorkPackage.group(:estimated_hours).having('estimated_hours > 3').count } it "returns the correct result for today" do expect(subject).to eq({ 10.0 => 1 }) @@ -405,7 +405,7 @@ end describe "after at_timestamp" do - subject { WorkPackage.at_timestamp(monday).group(:estimated_hours).having("estimated_hours > 3").count } + subject { WorkPackage.at_timestamp(monday).group(:estimated_hours).having('estimated_hours > 3').count } it "returns the correct result for that timestamp" do expect(subject).to eq({ 5.0 => 1 }) @@ -609,10 +609,10 @@ end end - context "with a custom field present" do + context 'with a custom field present' do let!(:custom_field) do create(:string_wp_custom_field, - name: "String CF", + name: 'String CF', types: project.types, projects: [project]) end @@ -621,12 +621,12 @@ create(:journal_customizable_journal, journal: monday_journal, custom_field:, - value: "The custom field as it has been on Monday") + value: 'The custom field as it has been on Monday') end - it "loads the custom_values relation with the historic values" do + it 'loads the custom_values relation with the historic values' do expect(subject.send(:"custom_field_#{custom_field.id}")) - .to eq "The custom field as it has been on Monday" + .to eq 'The custom field as it has been on Monday' end end end diff --git a/spec/models/journable/with_historic_attributes_spec.rb b/spec/models/journable/with_historic_attributes_spec.rb index d5fd106b9b9c..836c6954ae9f 100644 --- a/spec/models/journable/with_historic_attributes_spec.rb +++ b/spec/models/journable/with_historic_attributes_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journable::WithHistoricAttributes, with_ee: %i[baseline_comparison] do @@ -62,14 +62,14 @@ let(:user1) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project => %i[view_work_packages view_file_links] }) end let(:build_query) do build(:query, user: nil, project: nil).tap do |query| query.filters.clear - query.add_filter "subject", "~", search_term + query.add_filter 'subject', '~', search_term end end @@ -165,7 +165,7 @@ end end - describe "#attributes_by_timestamp" do + describe '#attributes_by_timestamp' do let(:work_packages) { work_package1 } context "with a single work package" do @@ -279,7 +279,7 @@ end end - describe "#exists_at_timestamps" do + describe '#exists_at_timestamps' do context "with a single work package" do let(:work_packages) { work_package1 } @@ -288,7 +288,7 @@ expect(subject.exists_at_timestamps).to include Timestamp.parse("PT0S") end - context "with the work package not being visible currently" do + context 'with the work package not being visible currently' do let(:other_project) { create(:project) } before do @@ -302,7 +302,7 @@ end end - context "with the work package not having been visible before but being visible now" do + context 'with the work package not having been visible before but being visible now' do let(:other_project) { create(:project) } before do @@ -366,20 +366,20 @@ end end - describe "#at_timestamp" do + describe '#at_timestamp' do context "with a single work package" do let(:work_packages) { work_package1 } it "returns the journable at a former time it existed with the attributes set to the former values" do - expect(subject.at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z")).attributes.slice("subject", "id")) - .to eq("subject" => "The original work package 1", - "id" => work_package1.id) + expect(subject.at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z")).attributes.slice('subject', 'id')) + .to eq('subject' => "The original work package 1", + 'id' => work_package1.id) end it "returns the journable at the current time" do - expect(subject.at_timestamp(Timestamp.parse("PT0S")).attributes.slice("subject", "id")) - .to eq("subject" => "The current work package 1", - "id" => work_package1.id) + expect(subject.at_timestamp(Timestamp.parse("PT0S")).attributes.slice('subject', 'id')) + .to eq('subject' => "The current work package 1", + 'id' => work_package1.id) end it "returns nil for a time it did not exist yet" do @@ -387,7 +387,7 @@ .to be_nil end - context "with the work package not being visible currently" do + context 'with the work package not being visible currently' do let(:other_project) { create(:project) } before do @@ -396,9 +396,9 @@ end it "returns the journable at a former time it existed with the attributes set to the former values" do - expect(subject.at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z")).attributes.slice("subject", "id")) - .to eq("subject" => "The original work package 1", - "id" => work_package1.id) + expect(subject.at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z")).attributes.slice('subject', 'id')) + .to eq('subject' => "The original work package 1", + 'id' => work_package1.id) end it "returns nil at the current time" do @@ -407,7 +407,7 @@ end end - context "with the work package not having been visible before but being visible now" do + context 'with the work package not having been visible before but being visible now' do let(:other_project) { create(:project) } before do @@ -415,21 +415,21 @@ end it "returns the journable at a former time it existed (and was invisible) with the attributes set to the former values" do - expect(subject.at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z")).attributes.slice("subject", "id")) - .to eq("subject" => "The original work package 1", - "id" => work_package1.id) + expect(subject.at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z")).attributes.slice('subject', 'id')) + .to eq('subject' => "The original work package 1", + 'id' => work_package1.id) end it "returns the journable at the current time" do - expect(subject.at_timestamp(Timestamp.parse("PT0S")).attributes.slice("subject", "id")) - .to eq("subject" => "The current work package 1", - "id" => work_package1.id) + expect(subject.at_timestamp(Timestamp.parse("PT0S")).attributes.slice('subject', 'id')) + .to eq('subject' => "The current work package 1", + 'id' => work_package1.id) end end end end - describe "#historic?" do + describe '#historic?' do context "with a single work package" do let(:work_packages) { work_package1 } @@ -471,7 +471,7 @@ end end - describe "#matches_query_filters_at_timestamps" do + describe '#matches_query_filters_at_timestamps' do let(:query) { build_query } let(:search_term) { "original" } @@ -592,19 +592,19 @@ end end - describe "#changed_at_timestamp" do + describe '#changed_at_timestamp' do subject { described_class.wrap(work_package1, timestamps:) } - context "for a timestamp where the work package did exist" do - it "returns the changed attributes at the timestamp compared to the current attribute values" do + context 'for a timestamp where the work package did exist' do + it 'returns the changed attributes at the timestamp compared to the current attribute values' do expect(subject.changed_at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z"))) - .to contain_exactly("subject") + .to contain_exactly('subject') end - context "when the work package includes custom field changes" do + context 'when the work package includes custom field changes' do let!(:custom_field) do create(:string_wp_custom_field, - name: "String CF", + name: 'String CF', types: project.types, projects: [project]) end @@ -613,18 +613,18 @@ create(:custom_value, custom_field:, customized: work_package1, - value: "This is a string value") + value: 'This is a string value') end - it "returns the changed attributes including custom fields at the timestamp compared to the current attribute values" do + it 'returns the changed attributes including custom fields at the timestamp compared to the current attribute values' do expect(subject.changed_at_timestamp(Timestamp.parse("2022-01-01T00:00:00Z"))) - .to contain_exactly "subject", "custom_field_#{custom_field.id}" + .to contain_exactly 'subject', "custom_field_#{custom_field.id}" end end end - context "for a timestamp where the work package did not exist" do - it "returns no changes" do + context 'for a timestamp where the work package did not exist' do + it 'returns no changes' do expect(subject.changed_at_timestamp(Timestamp.parse("2021-01-01T00:00:00Z"))) .to be_empty end diff --git a/spec/models/journal/notification_configuration_spec.rb b/spec/models/journal/notification_configuration_spec.rb index 66f8c7690011..b0a4a99177a0 100644 --- a/spec/models/journal/notification_configuration_spec.rb +++ b/spec/models/journal/notification_configuration_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journal::NotificationConfiguration do - describe ".with" do + describe '.with' do let!(:send_notification_before) { described_class.active? } let!(:proc_called_counter) { OpenStruct.new called: false, send_notifications: send_notification_before } let(:proc) do @@ -39,36 +39,36 @@ end end - it "executes the block" do + it 'executes the block' do described_class.with !send_notification_before, &proc expect(proc_called_counter.called) .to be_truthy end - it "uses the provided send_notifications value within the proc" do + it 'uses the provided send_notifications value within the proc' do described_class.with !send_notification_before, &proc expect(proc_called_counter.send_notifications) .to eql !send_notification_before end - it "resets the send_notifications to the value before" do + it 'resets the send_notifications to the value before' do described_class.with !send_notification_before, &proc expect(described_class.active?) .to eql send_notification_before end - context "when called with nil" do - it "defaults to true for send_notifications" do + context 'when called with nil' do + it 'defaults to true for send_notifications' do described_class.with nil, &proc expect(described_class.active?) .to be(true) end end - context "with nested calls" do + context 'with nested calls' do before do allow(Rails.logger).to receive(:debug) @@ -77,76 +77,76 @@ end end - context "when send_notifications value of inner call is different from outer call" do + context 'when send_notifications value of inner call is different from outer call' do let(:outer_call_value) { !send_notification_before } let(:inner_call_value) { send_notification_before } - it "executes the block" do + it 'executes the block' do expect(proc_called_counter.called) .to be_truthy end - it "lets the outer block call dominate further block calls" do + it 'lets the outer block call dominate further block calls' do expect(proc_called_counter.send_notifications) .to eq(outer_call_value) end - it "logs a debug message" do + it 'logs a debug message' do expect(Rails.logger).to have_received(:debug) .with("Ignoring setting journal notifications to '#{inner_call_value}' " \ "as a parent block already set it to #{outer_call_value}") end end - context "when send_notifications value of inner call is the same as for outer call" do + context 'when send_notifications value of inner call is the same as for outer call' do let(:outer_call_value) { !send_notification_before } let(:inner_call_value) { outer_call_value } - it "does not log any debug messages" do + it 'does not log any debug messages' do expect(Rails.logger).not_to have_received(:debug) end end - context "when send_notifications value of inner call is nil" do + context 'when send_notifications value of inner call is nil' do let(:outer_call_value) { !send_notification_before } let(:inner_call_value) { nil } - it "executes the block" do + it 'executes the block' do expect(proc_called_counter.called) .to be_truthy end - it "keeps the value of the outer block call" do + it 'keeps the value of the outer block call' do expect(proc_called_counter.send_notifications) .to eq(outer_call_value) end - it "does not log any debug messages" do + it 'does not log any debug messages' do expect(Rails.logger).not_to have_received(:debug) end end - context "when send_notifications value of outer call is nil" do + context 'when send_notifications value of outer call is nil' do let(:outer_call_value) { nil } let(:inner_call_value) { !send_notification_before } - it "executes the block" do + it 'executes the block' do expect(proc_called_counter.called) .to be_truthy end - it "sets the value to the inner block call value" do + it 'sets the value to the inner block call value' do expect(proc_called_counter.send_notifications) .to eq(inner_call_value) end - it "does not log any debug messages" do + it 'does not log any debug messages' do expect(Rails.logger).not_to have_received(:debug) end end end - it "is thread safe" do + it 'is thread safe' do thread = Thread.new do described_class.with true do inner = Thread.new do @@ -163,8 +163,8 @@ .to eql [true, false] end - context "with an exception being raised within the block" do - it "raises the exception but always resets the notification value" do + context 'with an exception being raised within the block' do + it 'raises the exception but always resets the notification value' do expect { described_class.with(!send_notification_before) { raise ArgumentError } } .to raise_error ArgumentError diff --git a/spec/models/journal/project_journal_spec.rb b/spec/models/journal/project_journal_spec.rb index 1f757a168e55..3b7db53f9369 100644 --- a/spec/models/journal/project_journal_spec.rb +++ b/spec/models/journal/project_journal_spec.rb @@ -26,67 +26,67 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journal::ProjectJournal do - describe "#render_detail" do + describe '#render_detail' do let(:project) { build(:project) } let(:journal) { build(:project_journal, journable: project) } - it "renders identifier field correctly" do - html = journal.render_detail(["identifier", [nil, "my-project"]], html: true) - expect(html).to eq("Identifier set to " \ - "my-project") + it 'renders identifier field correctly' do + html = journal.render_detail(['identifier', [nil, 'my-project']], html: true) + expect(html).to eq('Identifier set to ' \ + 'my-project') - html = journal.render_detail(["identifier", [nil, "my-project"]], html: false) - expect(html).to eq("Identifier set to my-project") + html = journal.render_detail(['identifier', [nil, 'my-project']], html: false) + expect(html).to eq('Identifier set to my-project') - html = journal.render_detail(["identifier", ["my-project", "my-beautiful-project"]], html: true) - expect(html).to eq("Identifier changed from my-project " \ - "to my-beautiful-project") + html = journal.render_detail(['identifier', ['my-project', 'my-beautiful-project']], html: true) + expect(html).to eq('Identifier changed from my-project ' \ + 'to my-beautiful-project') - html = journal.render_detail(["identifier", ["my-project", "my-beautiful-project"]], html: false) - expect(html).to eq("Identifier changed from my-project to my-beautiful-project") + html = journal.render_detail(['identifier', ['my-project', 'my-beautiful-project']], html: false) + expect(html).to eq('Identifier changed from my-project to my-beautiful-project') end - it "renders name field correctly" do - html = journal.render_detail(["name", [nil, "Test Project 123"]], html: true) - expect(html).to eq("Name set to " \ - "Test Project 123") + it 'renders name field correctly' do + html = journal.render_detail(['name', [nil, 'Test Project 123']], html: true) + expect(html).to eq('Name set to ' \ + 'Test Project 123') - html = journal.render_detail(["name", [nil, "Test Project 123"]], html: false) - expect(html).to eq("Name set to Test Project 123") + html = journal.render_detail(['name', [nil, 'Test Project 123']], html: false) + expect(html).to eq('Name set to Test Project 123') - html = journal.render_detail(["name", ["Old Project Name", "New Project Name"]], html: true) - expect(html).to eq("Name changed from Old Project Name " \ - "to New Project Name") + html = journal.render_detail(['name', ['Old Project Name', 'New Project Name']], html: true) + expect(html).to eq('Name changed from Old Project Name ' \ + 'to New Project Name') - html = journal.render_detail(["name", ["Old Project Name", "New Project Name"]], html: false) - expect(html).to eq("Name changed from Old Project Name to New Project Name") + html = journal.render_detail(['name', ['Old Project Name', 'New Project Name']], html: false) + expect(html).to eq('Name changed from Old Project Name to New Project Name') end - it "renders parent field correctly" do + it 'renders parent field correctly' do parent = create(:project) # Set - expect(journal.render_detail(["parent_id", [nil, parent.id]], html: true)) + expect(journal.render_detail(['parent_id', [nil, parent.id]], html: true)) .to eq("Subproject of #{parent.name}") - expect(journal.render_detail(["parent_id", [nil, parent.id]], html: false)) + expect(journal.render_detail(['parent_id', [nil, parent.id]], html: false)) .to eq("Subproject of #{parent.name}") previous_parent = create(:project) # Change - expect(journal.render_detail(["parent_id", [previous_parent.id, parent.id]], html: true)) - .to eq("Subproject changed " \ + expect(journal.render_detail(['parent_id', [previous_parent.id, parent.id]], html: true)) + .to eq('Subproject changed ' \ "from #{previous_parent.name} to #{parent.name}") - expect(journal.render_detail(["parent_id", [previous_parent.id, parent.id]], html: false)) + expect(journal.render_detail(['parent_id', [previous_parent.id, parent.id]], html: false)) .to eq("Subproject changed from #{previous_parent.name} to #{parent.name}") # Delete - expect(journal.render_detail(["parent_id", [parent.id, nil]], html: true)) + expect(journal.render_detail(['parent_id', [parent.id, nil]], html: true)) .to eq("No longer subproject of #{parent.name}") - expect(journal.render_detail(["parent_id", [parent.id, nil]], html: false)) + expect(journal.render_detail(['parent_id', [parent.id, nil]], html: false)) .to eq("No longer subproject of #{parent.name}") end end diff --git a/spec/models/journal/timestamps_spec.rb b/spec/models/journal/timestamps_spec.rb index dba79b00fc12..96158bcaa017 100644 --- a/spec/models/journal/timestamps_spec.rb +++ b/spec/models/journal/timestamps_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journal::Timestamps do # See: https://github.com/opf/openproject/pull/11243 diff --git a/spec/models/journal_spec.rb b/spec/models/journal_spec.rb index e2db69c24703..1083c843a93a 100644 --- a/spec/models/journal_spec.rb +++ b/spec/models/journal_spec.rb @@ -25,17 +25,17 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journal do - describe "#journable" do - it "raises no error on a new journal without a journable" do + describe '#journable' do + it 'raises no error on a new journal without a journable' do expect(Journal.new.journable) .to be_nil end end - describe "#notifications" do + describe '#notifications' do let(:work_package) { create(:work_package) } let(:journal) { work_package.journals.first } let!(:notification) do @@ -45,22 +45,22 @@ project: work_package.project) end - it "has a notifications association" do + it 'has a notifications association' do expect(journal.notifications) .to contain_exactly(notification) end - it "destroys the associated notifications upon journal destruction" do + it 'destroys the associated notifications upon journal destruction' do expect { journal.destroy } .to change(Notification, :count).from(1).to(0) end end - describe "#create" do - context "without a data foreign key" do + describe '#create' do + context 'without a data foreign key' do subject { create(:work_package_journal, data: nil) } - it "raises an error and does not create a database record" do + it 'raises an error and does not create a database record' do expect { subject } .to raise_error(ActiveRecord::NotNullViolation) diff --git a/spec/models/ldap_auth_source_spec.rb b/spec/models/ldap_auth_source_spec.rb index b372b0a3fdeb..3c581cc6e091 100644 --- a/spec/models/ldap_auth_source_spec.rb +++ b/spec/models/ldap_auth_source_spec.rb @@ -26,65 +26,65 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe LdapAuthSource do - it "creates" do - a = described_class.new(name: "My LDAP", host: "ldap.example.net", port: 389, base_dn: "dc=example,dc=net", - attr_login: "sAMAccountName") + it 'creates' do + a = described_class.new(name: 'My LDAP', host: 'ldap.example.net', port: 389, base_dn: 'dc=example,dc=net', + attr_login: 'sAMAccountName') expect(a.save).to be true end - it "strips ldap attributes" do - a = described_class.new(name: "My LDAP", host: "ldap.example.net", port: 389, - base_dn: "dc=example,dc=net", attr_login: "sAMAccountName", - attr_firstname: "givenName ") + it 'strips ldap attributes' do + a = described_class.new(name: 'My LDAP', host: 'ldap.example.net', port: 389, + base_dn: 'dc=example,dc=net', attr_login: 'sAMAccountName', + attr_firstname: 'givenName ') expect(a.save).to be true - expect(a.reload.attr_firstname).to eq "givenName" + expect(a.reload.attr_firstname).to eq 'givenName' end - describe "verify_peer" do + describe 'verify_peer' do let(:tls_mode) { :start_tls } let(:ldap) { described_class.new tls_mode:, verify_peer: } subject { ldap.ldap_connection_options[:encryption] } - context "when set" do + context 'when set' do let(:verify_peer) { true } - it "reflects in tls_options" do + it 'reflects in tls_options' do expect(subject).to have_key :tls_options expect(subject[:tls_options]).to match(hash_including(verify_mode: OpenSSL::SSL::VERIFY_PEER)) end end - context "when set, but tls_mode differs" do + context 'when set, but tls_mode differs' do let(:tls_mode) { :plain_ldap } let(:verify_peer) { true } - it "does nothing" do + it 'does nothing' do expect(subject).to be_nil end end - context "when unset" do + context 'when unset' do let(:verify_peer) { false } - it "reflects in tls_options" do + it 'reflects in tls_options' do expect(subject).to have_key :tls_options expect(subject[:tls_options]).to match(hash_including(verify_mode: OpenSSL::SSL::VERIFY_NONE)) end end end - describe "cert_store" do - let(:fixture) { Rails.root.join("spec/fixtures/ldap/snakeoil.pem") } + describe 'cert_store' do + let(:fixture) { Rails.root.join('spec/fixtures/ldap/snakeoil.pem') } let(:ldap) { build(:ldap_auth_source, tls_mode: :start_tls, tls_certificate_string: File.read(fixture)) } let(:store_double) { instance_double(OpenSSL::X509::Store) } subject { ldap.ldap_connection_options.dig(:encryption, :tls_options) } - it "adds the certificates to the store" do + it 'adds the certificates to the store' do allow(OpenSSL::X509::Store).to receive(:new).and_return(store_double) allow(store_double).to receive(:set_default_paths) allow(store_double).to receive(:add_cert) @@ -96,16 +96,16 @@ end end - describe "tls_certificate_string" do + describe 'tls_certificate_string' do let(:ldap) { build(:ldap_auth_source, tls_certificate_string:) } subject { ldap.read_ldap_certificates } - context "when single certificate" do - let(:fixture) { Rails.root.join("spec/fixtures/ldap/snakeoil.pem") } + context 'when single certificate' do + let(:fixture) { Rails.root.join('spec/fixtures/ldap/snakeoil.pem') } let(:tls_certificate_string) { File.read(fixture).split(/^$/)[0] } - it "is valid" do + it 'is valid' do expect(ldap).to be_valid expect(subject).to be_a Array expect(subject.length).to eq 1 @@ -113,11 +113,11 @@ end end - context "when multiple certificates" do - let(:fixture) { Rails.root.join("spec/fixtures/ldap/snakeoil.pem") } + context 'when multiple certificates' do + let(:fixture) { Rails.root.join('spec/fixtures/ldap/snakeoil.pem') } let(:tls_certificate_string) { File.read(fixture) } - it "is valid" do + it 'is valid' do expect(ldap).to be_valid expect(subject).to be_a Array expect(subject.length).to eq 2 @@ -125,101 +125,101 @@ end end - context "when bogus content" do - let(:tls_certificate_string) { "foo" } + context 'when bogus content' do + let(:tls_certificate_string) { 'foo' } - it "is invalid" do + it 'is invalid' do expect(ldap).not_to be_valid expect { subject }.to raise_error(OpenSSL::X509::CertificateError) end end end - describe "admin attribute mapping" do + describe 'admin attribute mapping' do let(:auth_source) do build(:ldap_auth_source, - attr_login: "uid", - attr_firstname: "givenName", - attr_lastname: "sn", - attr_mail: "mail", + attr_login: 'uid', + attr_firstname: 'givenName', + attr_lastname: 'sn', + attr_mail: 'mail', attr_admin:) end let(:entry) do - Net::LDAP::Entry.new("uid=login,foo=bar").tap do |entry| - entry["uid"] = "login" - entry["givenName"] = "abc" - entry["sn"] = "lastname" - entry["mail"] = "some@example.org" - entry["admin"] = admin_value + Net::LDAP::Entry.new('uid=login,foo=bar').tap do |entry| + entry['uid'] = 'login' + entry['givenName'] = 'abc' + entry['sn'] = 'lastname' + entry['mail'] = 'some@example.org' + entry['admin'] = admin_value end end subject { auth_source.get_user_attributes_from_ldap_entry(entry) } - context "when attribute defined and not present" do - let(:attr_admin) { "admin" } + context 'when attribute defined and not present' do + let(:attr_admin) { 'admin' } let(:admin_value) { nil } - it "returns it as false" do + it 'returns it as false' do expect(subject).to have_key(:admin) expect(subject[:admin]).to be false end end - context "when attribute defined and castable number" do - let(:attr_admin) { "admin" } - let(:admin_value) { "1" } + context 'when attribute defined and castable number' do + let(:attr_admin) { 'admin' } + let(:admin_value) { '1' } - it "does return the mapping" do + it 'does return the mapping' do expect(subject).to have_key(:admin) expect(subject[:admin]).to be true end end - context "when attribute defined and boolean" do - let(:attr_admin) { "admin" } + context 'when attribute defined and boolean' do + let(:attr_admin) { 'admin' } let(:admin_value) { false } - it "does return the mapping" do + it 'does return the mapping' do expect(subject).to have_key(:admin) expect(subject[:admin]).to be false end end - context "when attribute defined and true string" do - let(:attr_admin) { "admin" } - let(:admin_value) { "true" } + context 'when attribute defined and true string' do + let(:attr_admin) { 'admin' } + let(:admin_value) { 'true' } - it "does return the mapping" do + it 'does return the mapping' do expect(subject).to have_key(:admin) expect(subject[:admin]).to be true end end - context "when attribute defined and false string" do - let(:attr_admin) { "admin" } - let(:admin_value) { "false" } + context 'when attribute defined and false string' do + let(:attr_admin) { 'admin' } + let(:admin_value) { 'false' } - it "does return the mapping" do + it 'does return the mapping' do expect(subject).to have_key(:admin) expect(subject[:admin]).to be false end end - context "when attribute not defined and set" do + context 'when attribute not defined and set' do let(:attr_admin) { nil } let(:admin_value) { true } - it "does not return an admin mapping" do + it 'does not return an admin mapping' do expect(subject).not_to have_key(:admin) end end end - describe "with live LDAP", skip_if_command_unavailable: "java" do + describe 'with live LDAP', skip_if_command_unavailable: 'java' do before(:all) do - ldif = Rails.root.join("spec/fixtures/ldap/users.ldif") - @ldap_server = Ladle::Server.new(quiet: false, port: ParallelHelper.port_for_ldap.to_s, domain: "dc=example,dc=com", + ldif = Rails.root.join('spec/fixtures/ldap/users.ldif') + @ldap_server = Ladle::Server.new(quiet: false, port: ParallelHelper.port_for_ldap.to_s, domain: 'dc=example,dc=com', ldif:).start end @@ -232,15 +232,15 @@ create(:ldap_auth_source, port: ParallelHelper.port_for_ldap.to_s, tls_mode: :plain_ldap, - account: "uid=admin,ou=system", - account_password: "secret", - base_dn: "ou=people,dc=example,dc=com", + account: 'uid=admin,ou=system', + account_password: 'secret', + base_dn: 'ou=people,dc=example,dc=com', filter_string:, onthefly_register:, - attr_login: "uid", - attr_firstname: "givenName", - attr_lastname: "sn", - attr_mail: "mail", + attr_login: 'uid', + attr_firstname: 'givenName', + attr_lastname: 'sn', + attr_mail: 'mail', attr_admin:) end @@ -248,36 +248,36 @@ let(:filter_string) { nil } let(:attr_admin) { nil } - describe "attr_admin" do - context "when set" do - let(:attr_admin) { "isAdmin" } + describe 'attr_admin' do + context 'when set' do + let(:attr_admin) { 'isAdmin' } - it "maps for the admin user in ldap", :aggregate_failures do - admin = ldap.find_user("ldap_admin") + it 'maps for the admin user in ldap', :aggregate_failures do + admin = ldap.find_user('ldap_admin') expect(admin).to be_a User - expect(admin.firstname).to eq "LDAP" - expect(admin.lastname).to eq "Adminuser" + expect(admin.firstname).to eq 'LDAP' + expect(admin.lastname).to eq 'Adminuser' expect(admin.admin).to eq true - user = ldap.find_user("bb459") + user = ldap.find_user('bb459') expect(user).to be_a User - expect(user.firstname).to eq "Belle" - expect(user.lastname).to eq "Baldwin" + expect(user.firstname).to eq 'Belle' + expect(user.lastname).to eq 'Baldwin' expect(user.admin).to eq false end - context "with an existing user and different attributes" do - let!(:user) { create(:user, ldap_auth_source: ldap, login: "ldap_admin") } + context 'with an existing user and different attributes' do + let!(:user) { create(:user, ldap_auth_source: ldap, login: 'ldap_admin') } - it "updates the user" do - expect(user.firstname).to eq "Bob" + it 'updates the user' do + expect(user.firstname).to eq 'Bob' expect(user).not_to be_admin - ldap.find_user("ldap_admin") + ldap.find_user('ldap_admin') user.reload expect(user).to be_a User - expect(user.firstname).to eq "LDAP" - expect(user.lastname).to eq "Adminuser" + expect(user.firstname).to eq 'LDAP' + expect(user.lastname).to eq 'Adminuser' expect(user).to be_admin expect(user.ldap_auth_source_id).to eq ldap.id end @@ -285,143 +285,143 @@ end end - describe "looking up and authenticating users" do - context "with a valid LDAP user" do - it "authenticates the user" do - user = ldap.authenticate("bb459", "niwdlab") + describe 'looking up and authenticating users' do + context 'with a valid LDAP user' do + it 'authenticates the user' do + user = ldap.authenticate('bb459', 'niwdlab') expect(user).to be_a User - expect(user.firstname).to eq "Belle" - expect(user.lastname).to eq "Baldwin" - expect(user.mail).to eq "belle@example.org" + expect(user.firstname).to eq 'Belle' + expect(user.lastname).to eq 'Baldwin' + expect(user.mail).to eq 'belle@example.org' expect(user.ldap_auth_source_id).to eq ldap.id end - it "finds the user" do - user = ldap.find_user("bb459") + it 'finds the user' do + user = ldap.find_user('bb459') expect(user).to be_a User - expect(user.firstname).to eq "Belle" - expect(user.lastname).to eq "Baldwin" - expect(user.mail).to eq "belle@example.org" + expect(user.firstname).to eq 'Belle' + expect(user.lastname).to eq 'Baldwin' + expect(user.mail).to eq 'belle@example.org' expect(user.ldap_auth_source_id).to eq ldap.id end end - context "with an existing user and different attributes" do - let!(:user) { create(:user, ldap_auth_source: ldap, login: "bb459") } + context 'with an existing user and different attributes' do + let!(:user) { create(:user, ldap_auth_source: ldap, login: 'bb459') } - it "updates the user" do - expect(user.firstname).to eq "Bob" + it 'updates the user' do + expect(user.firstname).to eq 'Bob' - ldap.find_user("bb459") + ldap.find_user('bb459') user.reload expect(user).to be_a User - expect(user.firstname).to eq "Belle" - expect(user.lastname).to eq "Baldwin" - expect(user.mail).to eq "belle@example.org" + expect(user.firstname).to eq 'Belle' + expect(user.lastname).to eq 'Baldwin' + expect(user.mail).to eq 'belle@example.org' expect(user.ldap_auth_source_id).to eq ldap.id end end - context "with a valid LDAP user that exists, but not for the ldap connection" do - let!(:other_ldap) { create(:ldap_auth_source, name: "other") } - let!(:user) { create(:user, ldap_auth_source: other_ldap, login: "bb459") } + context 'with a valid LDAP user that exists, but not for the ldap connection' do + let!(:other_ldap) { create(:ldap_auth_source, name: 'other') } + let!(:user) { create(:user, ldap_auth_source: other_ldap, login: 'bb459') } - it "does not authenticate as the user does not exist for the ldap" do - user = ldap.authenticate("bb459", "niwdlab") + it 'does not authenticate as the user does not exist for the ldap' do + user = ldap.authenticate('bb459', 'niwdlab') expect(user).to be_nil end - it "does not find as the user does not exist for the ldap" do - user = ldap.find_user("bb459") + it 'does not find as the user does not exist for the ldap' do + user = ldap.find_user('bb459') expect(user).to be_nil end end - context "when the LDAP is not onthefly_register" do + context 'when the LDAP is not onthefly_register' do let(:onthefly_register) { false } - context "with a valid LDAP user that does not exist" do - it "does not authenticate as the user does not exist" do - user = ldap.authenticate("bb459", "niwdlab") + context 'with a valid LDAP user that does not exist' do + it 'does not authenticate as the user does not exist' do + user = ldap.authenticate('bb459', 'niwdlab') expect(user).to be_nil end - it "does not find as the user does not exist" do - user = ldap.find_user("bb459") + it 'does not find as the user does not exist' do + user = ldap.find_user('bb459') expect(user).to be_nil end end - context "with a valid LDAP user that exists, but not for the ldap connection" do - let!(:other_ldap) { create(:ldap_auth_source, name: "other") } - let!(:user) { create(:user, ldap_auth_source: other_ldap, login: "bb459") } + context 'with a valid LDAP user that exists, but not for the ldap connection' do + let!(:other_ldap) { create(:ldap_auth_source, name: 'other') } + let!(:user) { create(:user, ldap_auth_source: other_ldap, login: 'bb459') } - it "does not authenticate as the user does not exist for the ldap" do - user = ldap.authenticate("bb459", "niwdlab") + it 'does not authenticate as the user does not exist for the ldap' do + user = ldap.authenticate('bb459', 'niwdlab') expect(user).to be_nil end - it "does not find as the user does not exist for the ldap" do - user = ldap.find_user("bb459") + it 'does not find as the user does not exist for the ldap' do + user = ldap.find_user('bb459') expect(user).to be_nil end end end - context "with the wrong LDAP user password" do - it "does not authenticate" do - user = ldap.authenticate("bb459", "asdf") + context 'with the wrong LDAP user password' do + it 'does not authenticate' do + user = ldap.authenticate('bb459', 'asdf') expect(user).to be_nil end end - context "with an invalid LDAP user" do - it "returns nil for authenticate" do - expect(ldap.authenticate("nouser", "whatever")).to be_nil + context 'with an invalid LDAP user' do + it 'returns nil for authenticate' do + expect(ldap.authenticate('nouser', 'whatever')).to be_nil end - it "returns nil for find_user" do - expect(ldap.find_user("nouser")).to be_nil + it 'returns nil for find_user' do + expect(ldap.find_user('nouser')).to be_nil end end - context "without a login" do - it "returns nil for authenticate" do - expect(ldap.authenticate("", "whatever")).to be_nil + context 'without a login' do + it 'returns nil for authenticate' do + expect(ldap.authenticate('', 'whatever')).to be_nil end - it "returns nil for find_user" do - expect(ldap.find_user("")).to be_nil + it 'returns nil for find_user' do + expect(ldap.find_user('')).to be_nil end end - context "without a password" do - it "returns nil" do - expect(ldap.authenticate("whatever", "nil")).to be_nil + context 'without a password' do + it 'returns nil' do + expect(ldap.authenticate('whatever', 'nil')).to be_nil end end - context "with a filter string returning only users with a*" do - let(:filter_string) { "(uid=a*)" } + context 'with a filter string returning only users with a*' do + let(:filter_string) { '(uid=a*)' } - it "no longer authenticates bb459" do - expect(ldap.authenticate("bb459", "niwdlab")).to be_nil + it 'no longer authenticates bb459' do + expect(ldap.authenticate('bb459', 'niwdlab')).to be_nil end - it "no longer finds bb254" do - expect(ldap.find_user("bb459")).to be_nil + it 'no longer finds bb254' do + expect(ldap.find_user('bb459')).to be_nil end - it "still finds aa729" do - user = ldap.find_user("aa729") + it 'still finds aa729' do + user = ldap.find_user('aa729') expect(user).to be_a User - expect(user.firstname).to eq "Alexandra" + expect(user.firstname).to eq 'Alexandra' end - it "still authenticates aa729" do - user = ldap.authenticate("aa729", "smada") + it 'still authenticates aa729' do + user = ldap.authenticate('aa729', 'smada') expect(user).to be_a User - expect(user.firstname).to eq "Alexandra" + expect(user.firstname).to eq 'Alexandra' end end end diff --git a/spec/models/mail_handler/user_creator_spec.rb b/spec/models/mail_handler/user_creator_spec.rb index 8363dfdab958..7479b2b9fff5 100644 --- a/spec/models/mail_handler/user_creator_spec.rb +++ b/spec/models/mail_handler/user_creator_spec.rb @@ -24,23 +24,23 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe MailHandler::UserCreator do - describe ".new_user_from_attributes" do - context "with sufficient information" do + describe '.new_user_from_attributes' do + context 'with sufficient information' do # [address, name] => [login, firstname, lastname] { - ["jsmith@example.net", nil] => %w[jsmith@example.net jsmith -], + ['jsmith@example.net', nil] => %w[jsmith@example.net jsmith -], %w[jsmith@example.net John] => %w[jsmith@example.net John -], - ["jsmith@example.net", "John Smith"] => %w[jsmith@example.net John Smith], - ["jsmith@example.net", "John Paul Smith"] => ["jsmith@example.net", "John", "Paul Smith"], - ["jsmith@example.net", "AVeryLongFirstnameThatNoLongerExceedsTheMaximumLength Smith"] => + ['jsmith@example.net', 'John Smith'] => %w[jsmith@example.net John Smith], + ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'], + ['jsmith@example.net', 'AVeryLongFirstnameThatNoLongerExceedsTheMaximumLength Smith'] => %w[jsmith@example.net AVeryLongFirstnameThatNoLongerExceedsTheMaximumLength Smith], - ["jsmith@example.net", "John AVeryLongLastnameThatNoLongerExceedsTheMaximumLength"] => + ['jsmith@example.net', 'John AVeryLongLastnameThatNoLongerExceedsTheMaximumLength'] => %w[jsmith@example.net John AVeryLongLastnameThatNoLongerExceedsTheMaximumLength] }.each do |(provided_mail, provided_fullname), (expected_login, expected_firstname, expected_lastname)| - it "returns a valid user" do + it 'returns a valid user' do user = described_class.send(:new_user_from_attributes, provided_mail, provided_fullname) expect(user) @@ -57,10 +57,10 @@ end end - context "with min password length", + context 'with min password length', with_legacy_settings: { password_min_length: 15 } do - it "respects minimum password length" do - user = described_class.send(:new_user_from_attributes, "jsmith@example.net") + it 'respects minimum password length' do + user = described_class.send(:new_user_from_attributes, 'jsmith@example.net') expect(user) .to be_valid @@ -70,10 +70,10 @@ end end - context "when the attributes are invalid", + context 'when the attributes are invalid', with_legacy_settings: { password_min_length: 15 } do - it "respects minimum password length" do - user = described_class.send(:new_user_from_attributes, "foo&bar@example.net") + it 'respects minimum password length' do + user = described_class.send(:new_user_from_attributes, 'foo&bar@example.net') expect(user) .to be_valid @@ -82,7 +82,7 @@ .to match /^user[a-f0-9]+$/ expect(user.mail) - .to eq "foo&bar@example.net" + .to eq 'foo&bar@example.net' end end end diff --git a/spec/models/members/roles_diff_spec.rb b/spec/models/members/roles_diff_spec.rb index 0f634c597631..08b07c7d90c1 100644 --- a/spec/models/members/roles_diff_spec.rb +++ b/spec/models/members/roles_diff_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::RolesDiff do let(:project) { build_stubbed(:project) } @@ -37,7 +37,7 @@ let(:group_member_role) { build_stubbed(:member_role, role:) } let(:group_member_role_other) { build_stubbed(:member_role, role: role_other) } - let(:group_member_roles) { raise NotImplementedError("please set group_member_roles") } + let(:group_member_roles) { raise NotImplementedError('please set group_member_roles') } let(:group_member) do build_stubbed(:member, principal: group, project:, member_roles: group_member_roles) end @@ -54,7 +54,7 @@ let(:user_member_role_other_inherited) do build_stubbed(:member_role, role: role_other, inherited_from: group_member_role_other.id) end - let(:user_member_roles) { raise NotImplementedError("please set user_member_roles") } + let(:user_member_roles) { raise NotImplementedError('please set user_member_roles') } let(:user_member) do build_stubbed(:member, principal: user, project:, member_roles: user_member_roles) end @@ -63,25 +63,25 @@ described_class.new(user_member, group_member) end - shared_examples "roles created" do - it "results in roles created" do + shared_examples 'roles created' do + it 'results in roles created' do expect(difference.result).to eq(:roles_created) end end - shared_examples "roles updated" do - it "results in roles updated" do + shared_examples 'roles updated' do + it 'results in roles updated' do expect(difference.result).to eq(:roles_updated) end end - shared_examples "roles unchanged" do - it "results in roles unchanged" do + shared_examples 'roles unchanged' do + it 'results in roles unchanged' do expect(difference.result).to eq(:roles_unchanged) end end - context "when group has added all its roles to a user" do + context 'when group has added all its roles to a user' do let(:group_member_roles) { [group_member_role, group_member_role_other] } let(:user_member_roles) do [ @@ -90,10 +90,10 @@ ] end - include_examples "roles created" + include_examples 'roles created' end - context "when group has added all its roles to a user who already had some preexisting other roles" do + context 'when group has added all its roles to a user who already had some preexisting other roles' do let(:group_member_roles) { [group_member_role] } let(:user_member_roles) do [ @@ -102,10 +102,10 @@ ] end - include_examples "roles updated" + include_examples 'roles updated' end - context "when group has added a new role and an existing role to a user" do + context 'when group has added a new role and an existing role to a user' do let(:group_member_roles) { [group_member_role, group_member_role_other] } let(:user_member_roles) do [ @@ -115,10 +115,10 @@ ] end - include_examples "roles updated" + include_examples 'roles updated' end - context "when group has added already existing roles to a user" do + context 'when group has added already existing roles to a user' do let(:group_member_roles) { [group_member_role, group_member_role_other] } let(:user_member_roles) do [ @@ -129,10 +129,10 @@ ] end - include_examples "roles unchanged" + include_examples 'roles unchanged' end - context "when group did not add any roles" do + context 'when group did not add any roles' do let(:group_member_roles) { [group_member_role, group_member_role_other] } let(:user_member_roles) do [ @@ -141,10 +141,10 @@ ] end - include_examples "roles unchanged" + include_examples 'roles unchanged' end - context "when the projects are different between members" do + context 'when the projects are different between members' do let(:group_member) do build_stubbed( :member, @@ -160,12 +160,12 @@ ) end - it "raises ArgumentError" do + it 'raises ArgumentError' do expect { difference.result }.to raise_error(ArgumentError) end end - context "with another group defined" do + context 'with another group defined' do let(:other_group_member_role) { build_stubbed(:member_role, role:) } let(:other_group_member_role_other) { build_stubbed(:member_role, role: role_other) } let(:user_member_role_inherited_from_other_group) do @@ -175,7 +175,7 @@ build_stubbed(:member_role, role: role_other, inherited_from: other_group_member_role_other.id) end - context "when group has added to a user a new role and a role that already existed from another group membership" do + context 'when group has added to a user a new role and a role that already existed from another group membership' do let(:group_member_roles) { [group_member_role, group_member_role_other] } let(:user_member_roles) do [ @@ -185,10 +185,10 @@ ] end - include_examples "roles updated" + include_examples 'roles updated' end - context "when group has added to a user some roles that already existed from another group membership" do + context 'when group has added to a user some roles that already existed from another group membership' do let(:group_member_roles) { [group_member_role, group_member_role_other] } let(:user_member_roles) do [ @@ -199,7 +199,7 @@ ] end - include_examples "roles unchanged" + include_examples 'roles unchanged' end end end diff --git a/spec/models/members/scopes/global_spec.rb b/spec/models/members/scopes/global_spec.rb index b179887e8263..5862951a6213 100644 --- a/spec/models/members/scopes/global_spec.rb +++ b/spec/models/members/scopes/global_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::Global do let(:project) { create(:project) } @@ -54,10 +54,10 @@ principal: user) end - describe ".global" do + describe '.global' do subject { Member.global } - it "returns global memberships" do + it 'returns global memberships' do expect(subject) .to contain_exactly(global_member) end diff --git a/spec/models/members/scopes/not_locked_spec.rb b/spec/models/members/scopes/not_locked_spec.rb index dd11a5fdf0d7..41911e9fd2e9 100644 --- a/spec/models/members/scopes/not_locked_spec.rb +++ b/spec/models/members/scopes/not_locked_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::NotLocked do let(:project) { create(:project) } @@ -63,10 +63,10 @@ principal: create(:group)) end - describe ".fetch" do + describe '.fetch' do subject { Member.not_locked } - it "returns only actual users and groups" do + it 'returns only actual users and groups' do expect(subject) .to contain_exactly(active_user_member, invited_user_member, registered_user_member, group_member) end diff --git a/spec/models/members/scopes/of_any_entity_spec.rb b/spec/models/members/scopes/of_any_entity_spec.rb index 7000add2fa9e..36ec1f15eab3 100644 --- a/spec/models/members/scopes/of_any_entity_spec.rb +++ b/spec/models/members/scopes/of_any_entity_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::OfAnyEntity do let(:project) { create(:project) } @@ -52,10 +52,10 @@ principal: user) end - describe ".of_any_entity" do + describe '.of_any_entity' do subject { Member.of_any_entity } - it "returns all memberships on entities" do + it 'returns all memberships on entities' do expect(subject) .to contain_exactly(work_package_member) end diff --git a/spec/models/members/scopes/of_any_project_spec.rb b/spec/models/members/scopes/of_any_project_spec.rb index cfae1b066c24..196d1071bd20 100644 --- a/spec/models/members/scopes/of_any_project_spec.rb +++ b/spec/models/members/scopes/of_any_project_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::OfAnyProject do let(:project) { create(:project) } @@ -82,10 +82,10 @@ principal: create(:user, status: Principal.statuses[:active])) end - describe ".of_any_project" do + describe '.of_any_project' do subject { Member.of_any_project } - it "returns all members in any project but neither global nor entity memberships" do + it 'returns all members in any project but neither global nor entity memberships' do expect(subject) .to contain_exactly(active_user_member, invited_user_member, registered_user_member, group_member, locked_user_member, active_user_member_in_other_project) diff --git a/spec/models/members/scopes/of_any_work_package_spec.rb b/spec/models/members/scopes/of_any_work_package_spec.rb index 78ca28dc0af6..822b973a9ec3 100644 --- a/spec/models/members/scopes/of_any_work_package_spec.rb +++ b/spec/models/members/scopes/of_any_work_package_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::OfAnyWorkPackage do let(:project) { create(:project) } @@ -61,10 +61,10 @@ principal: user) end - describe ".of_any_work_package" do + describe '.of_any_work_package' do subject { Member.of_any_work_package } - it "returns all memberships on work package entities" do + it 'returns all memberships on work package entities' do expect(subject) .to contain_exactly(work_package_member, work_package_in_other_project_member) end diff --git a/spec/models/members/scopes/of_anything_in_project_spec.rb b/spec/models/members/scopes/of_anything_in_project_spec.rb index 18c54c8908de..c649e78e19f4 100644 --- a/spec/models/members/scopes/of_anything_in_project_spec.rb +++ b/spec/models/members/scopes/of_anything_in_project_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::OfAnythingInProject do let(:project) { create(:project) } @@ -82,10 +82,10 @@ principal: create(:user, status: Principal.statuses[:active])) end - describe ".of_anything_in_project" do + describe '.of_anything_in_project' do subject { Member.of_anything_in_project(project) } - it "returns all members including those of entities in the project" do + it 'returns all members including those of entities in the project' do expect(subject) .to contain_exactly(active_user_member, invited_user_member, diff --git a/spec/models/members/scopes/of_project_spec.rb b/spec/models/members/scopes/of_project_spec.rb index 778bc54b4913..13394e0a6b4f 100644 --- a/spec/models/members/scopes/of_project_spec.rb +++ b/spec/models/members/scopes/of_project_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::OfProject do let(:project) { create(:project) } @@ -82,10 +82,10 @@ principal: create(:user, status: Principal.statuses[:active])) end - describe ".of_project" do + describe '.of_project' do subject { Member.of_project(project) } - it "returns all members but not those of entities in the project" do + it 'returns all members but not those of entities in the project' do expect(subject) .to contain_exactly(active_user_member, invited_user_member, registered_user_member, group_member, locked_user_member) end diff --git a/spec/models/members/scopes/of_work_package_spec.rb b/spec/models/members/scopes/of_work_package_spec.rb index 643064d4b280..47d4e81c72b1 100644 --- a/spec/models/members/scopes/of_work_package_spec.rb +++ b/spec/models/members/scopes/of_work_package_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::OfWorkPackage do let(:project) { create(:project) } @@ -62,10 +62,10 @@ principal: user) end - describe ".of_work_package" do + describe '.of_work_package' do subject { Member.of_work_package(work_package) } - it "returns memberships on the specific work package" do + it 'returns memberships on the specific work package' do expect(subject) .to contain_exactly(work_package_member) end diff --git a/spec/models/members/scopes/visible_spec.rb b/spec/models/members/scopes/visible_spec.rb index 4304fde45178..29871395ac90 100644 --- a/spec/models/members/scopes/visible_spec.rb +++ b/spec/models/members/scopes/visible_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::Visible do def create_member(project:, permissions:) @@ -72,13 +72,13 @@ def create_work_package_share(project:) create_work_package_share(project: view_shared_work_packages_project) end - describe ".visible" do + describe '.visible' do subject { Member.visible(user) } - context "for admin" do + context 'for admin' do let(:admin) { true } - it "returns all members" do + it 'returns all members' do expect(subject).to contain_exactly view_members_member, manage_members_member, view_shared_work_packages_member, @@ -88,10 +88,10 @@ def create_work_package_share(project:) end end - context "for non admin" do + context 'for non admin' do let(:admin) { false } - it "returns only members allowed by permissions" do + it 'returns only members allowed by permissions' do expect(subject).to contain_exactly view_members_member, manage_members_member, view_shared_work_packages_work_package_share diff --git a/spec/models/members/scopes/without_inherited_roles_spec.rb b/spec/models/members/scopes/without_inherited_roles_spec.rb index e1a8f058257a..c263eeb4e623 100644 --- a/spec/models/members/scopes/without_inherited_roles_spec.rb +++ b/spec/models/members/scopes/without_inherited_roles_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::Scopes::WithoutInheritedRoles do let(:project) { create(:project) } @@ -53,10 +53,10 @@ end end - describe ".without_inherited_roles" do + describe '.without_inherited_roles' do subject { Member.without_inherited_roles } - it "returns all that are not inherited" do + it 'returns all that are not inherited' do expect(subject).to contain_exactly(work_package_member) end end diff --git a/spec/models/menu_item_spec.rb b/spec/models/menu_item_spec.rb index 23e7eb736f58..1435ea1f28ba 100644 --- a/spec/models/menu_item_spec.rb +++ b/spec/models/menu_item_spec.rb @@ -26,45 +26,45 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MenuItem do - describe "validations" do + describe 'validations' do let(:item) { build(:menu_item) } - it "requires a title" do + it 'requires a title' do item.title = nil expect(item).not_to be_valid expect(item.errors).to have_key :title end - it "requires a name" do + it 'requires a name' do item.name = nil expect(item).not_to be_valid expect(item.errors).to have_key :name end - describe "scoped uniqueness of title" do + describe 'scoped uniqueness of title' do let!(:item) { create(:menu_item) } let(:another_item) { build(:menu_item, title: item.title) } let(:wiki_menu_item) { build(:wiki_menu_item, title: item.title) } - it "does not allow for duplicate titles" do + it 'does not allow for duplicate titles' do expect(another_item).not_to be_valid expect(another_item.errors).to have_key :title end - it "allows for creating a menu item with the same title if it has a different type" do + it 'allows for creating a menu item with the same title if it has a different type' do expect(wiki_menu_item).to be_valid end end end - context "it should destroy" do + context 'it should destroy' do let!(:menu_item) { create(:menu_item) } let!(:child_item) { create(:menu_item, parent_id: menu_item.id) } - example "all children when deleting the parent" do + example 'all children when deleting the parent' do menu_item.destroy expect(MenuItem.exists?(child_item.id)).to be_falsey end diff --git a/spec/models/menu_items/wiki_menu_item_spec.rb b/spec/models/menu_items/wiki_menu_item_spec.rb index a6f6a315eced..9b53446507b1 100644 --- a/spec/models/menu_items/wiki_menu_item_spec.rb +++ b/spec/models/menu_items/wiki_menu_item_spec.rb @@ -26,49 +26,49 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MenuItems::WikiMenuItem do before do @project = create(:project, enabled_module_names: %w[activity]) - @current = create(:user, login: "user1", mail: "user1@users.com") + @current = create(:user, login: 'user1', mail: 'user1@users.com') allow(User).to receive(:current).and_return(@current) end - it "creates a default wiki menu item when enabling the wiki" do + it 'creates a default wiki menu item when enabling the wiki' do expect(MenuItems::WikiMenuItem.all).not_to be_any - @project.enabled_modules << EnabledModule.new(name: "wiki") + @project.enabled_modules << EnabledModule.new(name: 'wiki') @project.reload wiki_item = @project.wiki.wiki_menu_items.first - expect(wiki_item.name).to eql "wiki" - expect(wiki_item.title).to eql "Wiki" - expect(wiki_item.slug).to eql "wiki" + expect(wiki_item.name).to eql 'wiki' + expect(wiki_item.title).to eql 'Wiki' + expect(wiki_item.slug).to eql 'wiki' expect(wiki_item.options[:index_page]).to be true expect(wiki_item.options[:new_wiki_page]).to be true end - it "changes title when a wikipage is renamed" do - wikipage = create(:wiki_page, title: "Oldtitle") + it 'changes title when a wikipage is renamed' do + wikipage = create(:wiki_page, title: 'Oldtitle') menu_item_1 = create(:wiki_menu_item, navigatable_id: wikipage.wiki.id, - title: "Item 1", + title: 'Item 1', name: wikipage.slug) - wikipage.title = "Newtitle" + wikipage.title = 'Newtitle' wikipage.save! menu_item_1.reload expect(menu_item_1.title).to eq(wikipage.title) end - it "does not allow duplicate sibling entries" do - wikipage = create(:wiki_page, title: "Parent Page") + it 'does not allow duplicate sibling entries' do + wikipage = create(:wiki_page, title: 'Parent Page') parent = create( - :wiki_menu_item, navigatable_id: wikipage.wiki.id, title: "Item 1", name: wikipage.slug + :wiki_menu_item, navigatable_id: wikipage.wiki.id, title: 'Item 1', name: wikipage.slug ) child_1 = parent.children.create name: "child-1", title: "Child 1" @@ -77,35 +77,35 @@ expect { child_2.save! }.to raise_error /Name has already been taken/ end - describe "it should destroy" do + describe 'it should destroy' do before do - @project.enabled_modules << EnabledModule.new(name: "wiki") + @project.enabled_modules << EnabledModule.new(name: 'wiki') @project.reload @menu_item_1 = create(:wiki_menu_item, wiki: @project.wiki, - name: "Item 1", - title: "Item 1") + name: 'Item 1', + title: 'Item 1') @menu_item_2 = create(:wiki_menu_item, wiki: @project.wiki, - name: "Item 2", + name: 'Item 2', parent_id: @menu_item_1.id, - title: "Item 2") + title: 'Item 2') end - it "all children when deleting the parent" do + it 'all children when deleting the parent' do @menu_item_1.destroy expect { MenuItems::WikiMenuItem.find(@menu_item_1.id) }.to raise_error(ActiveRecord::RecordNotFound) expect { MenuItems::WikiMenuItem.find(@menu_item_2.id) }.to raise_error(ActiveRecord::RecordNotFound) end - describe "all items when destroying" do - it "the associated project" do + describe 'all items when destroying' do + it 'the associated project' do @project.destroy expect(MenuItems::WikiMenuItem.all).not_to be_any end - it "the associated wiki" do + it 'the associated wiki' do @project.wiki.destroy expect(MenuItems::WikiMenuItem.all).not_to be_any end diff --git a/spec/models/messages/acts_as_journalized_spec.rb b/spec/models/messages/acts_as_journalized_spec.rb index db9d30b03167..41a260fe26da 100644 --- a/spec/models/messages/acts_as_journalized_spec.rb +++ b/spec/models/messages/acts_as_journalized_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Message, "acts_as_journalized" do +RSpec.describe Message, 'acts_as_journalized' do let(:user) { create(:user) } let(:project) { create(:project) } let!(:forum) do @@ -37,10 +37,10 @@ end let(:attachment) { create(:attachment, container: nil, author: user) } - context "on creation" do - context "attachments" do + context 'on creation' do + context 'attachments' do before do - Message.create! forum:, subject: "Test message", content: "Message body", attachments: [attachment] + Message.create! forum:, subject: 'Test message', content: 'Message body', attachments: [attachment] end let(:attachment_id) { "attachments_#{attachment.id}" } diff --git a/spec/models/messages_spec.rb b/spec/models/messages_spec.rb index cd8fa1424112..6967d877188d 100644 --- a/spec/models/messages_spec.rb +++ b/spec/models/messages_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require "support/shared/acts_as_watchable" +require 'support/shared/acts_as_watchable' RSpec.describe Message do let(:message) { create(:message) } - it_behaves_like "acts_as_watchable included" do + it_behaves_like 'acts_as_watchable included' do let(:model_instance) { message } let(:watch_permission) { :view_messages } # view_messages is a public permission let(:project) { model_instance.forum.project } end - it_behaves_like "acts_as_attachable included" do + it_behaves_like 'acts_as_attachable included' do let(:model_instance) { create(:message) } end - describe "#project" do - it "is the same as the project on wiki" do + describe '#project' do + it 'is the same as the project on wiki' do expect(message.project).to eql(message.forum.project) end end - describe "with forum" do + describe 'with forum' do shared_let(:forum) { create(:forum) } let(:message) do - build(:message, forum:, subject: "Test message", content: "Test message content") + build(:message, forum:, subject: 'Test message', content: 'Test message content') end - it "creates" do + it 'creates' do topics_count = forum.topics_count messages_count = forum.messages_count @@ -70,13 +70,13 @@ message.reload end - context "with previous message" do + context 'with previous message' do let(:topic) { create(:message) } let(:reply) do - create(:message, forum:, subject: "Test reply", parent: topic) + create(:message, forum:, subject: 'Test reply', parent: topic) end - it "replies" do + it 'replies' do topics_count = forum.topics_count messages_count = forum.messages_count replies_count = topic.replies_count @@ -96,12 +96,12 @@ end end - describe "moving" do + describe 'moving' do let!(:forum1) { create(:forum) } let!(:forum2) { create(:forum) } let!(:message) { create(:message, forum: forum1) } - it "movings message should update counters" do + it 'movings message should update counters' do expect do forum1.reload expect(forum1.topics_count).to eq 1 @@ -119,7 +119,7 @@ end end - it "sets sticky" do + it 'sets sticky' do message = Message.new expect(message.sticky).to eq 0 message.sticky = nil @@ -128,18 +128,18 @@ expect(message.sticky).to eq 0 message.sticky = true expect(message.sticky).to eq 1 - message.sticky = "0" + message.sticky = '0' expect(message.sticky).to eq 0 - message.sticky = "1" + message.sticky = '1' expect(message.sticky).to eq 1 end - describe "with reply set" do + describe 'with reply set' do let!(:reply) do create(:message, forum: message.forum, parent: message) end - it "destroys topic" do + it 'destroys topic' do forum = message.forum.reload expect(forum.topics_count).to eq 1 expect(forum.messages_count).to eq 2 @@ -151,7 +151,7 @@ expect(forum.messages_count).to eq 0 end - it "destroys reply" do + it 'destroys reply' do forum = message.forum expect(forum.topics_count).to eq 1 expect(forum.messages_count).to eq 2 diff --git a/spec/models/news_spec.rb b/spec/models/news_spec.rb index 5da9f7f360bc..7a19b664c00a 100644 --- a/spec/models/news_spec.rb +++ b/spec/models/news_spec.rb @@ -25,17 +25,17 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/shared/become_member", __dir__) +require 'spec_helper' +require File.expand_path('../support/shared/become_member', __dir__) -require "support/shared/acts_as_watchable" +require 'support/shared/acts_as_watchable' RSpec.describe News do include BecomeMember let(:project) do project = create(:public_project) - project.enabled_modules << EnabledModule.new(name: "news") + project.enabled_modules << EnabledModule.new(name: 'news') project.reload end @@ -43,30 +43,30 @@ let(:permissions) { [] } let(:role) { build(:project_role, permissions:) } - it_behaves_like "acts_as_watchable included" do + it_behaves_like 'acts_as_watchable included' do let(:model_instance) { create(:news) } let(:watch_permission) { :view_news } let(:project) { model_instance.project } end - describe ".latest" do + describe '.latest' do let(:project_news) { described_class.where(project:) } before do ProjectRole.anonymous end - it "includes news elements from projects where news module is enabled" do + it 'includes news elements from projects where news module is enabled' do expect(described_class.latest).to contain_exactly(news) end it "doesn't include news elements from projects where news module is not enabled" do - EnabledModule.where(project_id: project.id, name: "news").delete_all + EnabledModule.where(project_id: project.id, name: 'news').delete_all expect(described_class.latest).to be_empty end - it "only includes news elements from projects that are visible to the user" do + it 'only includes news elements from projects that are visible to the user' do private_project = create(:project, public: false) create(:news, project: private_project) @@ -74,7 +74,7 @@ expect(latest_news).to contain_exactly(news) end - it "limits the number of returned news elements" do + it 'limits the number of returned news elements' do project_news.delete_all create_list(:news, 10, project:) @@ -84,7 +84,7 @@ expect(project_news.latest(user: User.current, count: 15).size).to eq(10) end - it "returns five news elements by default" do + it 'returns five news elements by default' do project_news.delete_all create_list(:news, 2, project:) @@ -99,8 +99,8 @@ end end - describe "#save" do - it "sends email notifications when created" do + describe '#save' do + it 'sends email notifications when created' do create(:user, member_with_roles: { project => role }, notification_settings: [ @@ -116,45 +116,45 @@ end end - describe "#to_param" do - it "includes includes id and title for a nicer url" do - title = "OpenProject now has a Twitter Account" + describe '#to_param' do + it 'includes includes id and title for a nicer url' do + title = 'OpenProject now has a Twitter Account' news = create(:news, title:) slug = "#{news.id}-openproject-now-has-a-twitter-account" expect(news.to_param).to eq slug end - it "returns nil for unsaved news" do + it 'returns nil for unsaved news' do news = described_class.new expect(news.to_param).to be_nil end end - describe "#new_comment" do - subject(:comment) { news.new_comment(author: news.author, comments: "some important words") } + describe '#new_comment' do + subject(:comment) { news.new_comment(author: news.author, comments: 'some important words') } - it "sets the comment`s news" do + it 'sets the comment`s news' do expect(comment.commented) .to eq news end - it "is saveable" do + it 'is saveable' do expect(comment.save) .to be_truthy end end - describe "#comments_count" do - it "counts the comments on the news when adding" do - expect { news.comments.create(author: news.author, comments: "some important words") } + describe '#comments_count' do + it 'counts the comments on the news when adding' do + expect { news.comments.create(author: news.author, comments: 'some important words') } .to change { news.reload.comments_count } .from(0) .to(1) end - it "counts the comments on the news when destroying a comment" do - comment = news.comments.build(author: news.author, comments: "some important words") + it 'counts the comments on the news when destroying a comment' do + comment = news.comments.build(author: news.author, comments: 'some important words') comment.save expect { comment.destroy } diff --git a/spec/models/non_working_day_spec.rb b/spec/models/non_working_day_spec.rb index b20dd727db3d..608feae5a151 100644 --- a/spec/models/non_working_day_spec.rb +++ b/spec/models/non_working_day_spec.rb @@ -1,26 +1,26 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe NonWorkingDay do subject { build(:non_working_day) } - describe "validations" do - it "is valid when all attributes are present" do + describe 'validations' do + it 'is valid when all attributes are present' do expect(subject).to be_valid end - it "is invalid without name" do + it 'is invalid without name' do subject.name = nil expect(subject).to be_invalid expect(subject.errors[:name]).to be_present end - it "is invalid without date" do + it 'is invalid without date' do subject.date = nil expect(subject).to be_invalid expect(subject.errors[:date]).to be_present end - it "is invalid with an already existing date" do + it 'is invalid with an already existing date' do existing = create(:non_working_day) subject.date = existing.date expect(subject).to be_invalid diff --git a/spec/models/notification_settings/scopes/applicable_spec.rb b/spec/models/notification_settings/scopes/applicable_spec.rb index e3438f9c270c..24ef4cf74db5 100644 --- a/spec/models/notification_settings/scopes/applicable_spec.rb +++ b/spec/models/notification_settings/scopes/applicable_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe NotificationSettings::Scopes::Applicable do - describe ".applicable" do + describe '.applicable' do subject(:scope) { NotificationSetting.applicable(project) } let!(:user) do @@ -40,20 +40,20 @@ create(:project) end - context "when only global settings exist" do + context 'when only global settings exist' do let(:notification_settings) do [ build(:notification_setting, project: nil) ] end - it "returns the global settings" do + it 'returns the global settings' do expect(scope) .to match_array(notification_settings) end end - context "when global and project settings exist" do + context 'when global and project settings exist' do let(:project_notification_settings) do [ build(:notification_setting, project:) @@ -66,13 +66,13 @@ end let(:notification_settings) { project_notification_settings + global_notification_settings } - it "returns the project settings" do + it 'returns the project settings' do expect(scope) .to match_array(project_notification_settings) end end - context "when global and project settings exist but for a different project" do + context 'when global and project settings exist but for a different project' do let(:other_project) { create(:project) } let(:project_notification_settings) do [ @@ -86,7 +86,7 @@ end let(:notification_settings) { project_notification_settings + global_notification_settings } - it "returns the project settings" do + it 'returns the project settings' do expect(scope) .to match_array(global_notification_settings) end diff --git a/spec/models/notification_spec.rb b/spec/models/notification_spec.rb index 660527358197..a11e868bda3a 100644 --- a/spec/models/notification_spec.rb +++ b/spec/models/notification_spec.rb @@ -25,14 +25,14 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notification do - describe ".save" do - context "for a non existing journal (e.g. because it has been deleted)" do + describe '.save' do + context 'for a non existing journal (e.g. because it has been deleted)' do let(:notification) { build(:notification) } - it "raises an error" do + it 'raises an error' do notification.journal_id = 99999 expect { notification.save } .to raise_error ActiveRecord::InvalidForeignKey diff --git a/spec/models/notifications/scopes/reminder_mail_unsent_spec.rb b/spec/models/notifications/scopes/reminder_mail_unsent_spec.rb index 6c1b7cf55cfe..2036b1ffb948 100644 --- a/spec/models/notifications/scopes/reminder_mail_unsent_spec.rb +++ b/spec/models/notifications/scopes/reminder_mail_unsent_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::Scopes::MailReminderUnsent do - describe ".unread_digest_mail" do + describe '.unread_digest_mail' do subject(:scope) { Notification.mail_reminder_unsent } let(:no_mail_notification) { create(:notification, mail_reminder_sent: nil) } @@ -42,7 +42,7 @@ read_mail_notification end - it "contains the notifications with read_mail: false" do + it 'contains the notifications with read_mail: false' do expect(scope) .to contain_exactly(unread_mail_notification) end diff --git a/spec/models/notifications/scopes/unsent_reminders_before_spec.rb b/spec/models/notifications/scopes/unsent_reminders_before_spec.rb index c739b814ec49..d700cde8548c 100644 --- a/spec/models/notifications/scopes/unsent_reminders_before_spec.rb +++ b/spec/models/notifications/scopes/unsent_reminders_before_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::Scopes::UnsentRemindersBefore do - describe ".unsent_reminders_before" do + describe '.unsent_reminders_before' do subject(:scope) { Notification.unsent_reminders_before(recipient:, time:) } let(:recipient) do @@ -53,48 +53,48 @@ let!(:notifications) { notification } - shared_examples_for "is empty" do - it "is empty" do + shared_examples_for 'is empty' do + it 'is empty' do expect(scope) .to be_empty end end - context "with a unread and not reminded notification that was created before the time and for the user" do - it "returns the notification" do + context 'with a unread and not reminded notification that was created before the time and for the user' do + it 'returns the notification' do expect(scope) .to contain_exactly(notification) end end - context "with a unread and not reminded notification that was created after the time and for the user" do + context 'with a unread and not reminded notification that was created after the time and for the user' do let(:notification_created_at) { 10.minutes.from_now } - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with a unread and not reminded notification that was created before the time and for different user" do + context 'with a unread and not reminded notification that was created before the time and for different user' do let(:notification_recipient) { create(:user) } - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with a unread and not reminded notification created before the time and for the user" do + context 'with a unread and not reminded notification created before the time and for the user' do let(:notification_mail_reminder_sent) { nil } - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with a unread but reminded notification created before the time and for the user" do + context 'with a unread but reminded notification created before the time and for the user' do let(:notification_mail_reminder_sent) { true } - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with a read notification that was created before the time" do + context 'with a read notification that was created before the time' do let(:notification_read_ian) { true } - it_behaves_like "is empty" + it_behaves_like 'is empty' end end end diff --git a/spec/models/notifications/scopes/visible_spec.rb b/spec/models/notifications/scopes/visible_spec.rb index 56cb6aec5f20..5bf28505535f 100644 --- a/spec/models/notifications/scopes/visible_spec.rb +++ b/spec/models/notifications/scopes/visible_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::Scopes::Visible do - describe ".visible" do + describe '.visible' do subject(:scope) { Notification.visible(user) } let(:user) do @@ -50,30 +50,30 @@ let!(:notifications) { notification } - shared_examples_for "is empty" do - it "is empty" do + shared_examples_for 'is empty' do + it 'is empty' do expect(scope) .to be_empty end end - context "with the user being recipient and being allowed to see the work package" do - it "returns the notification" do + context 'with the user being recipient and being allowed to see the work package' do + it 'returns the notification' do expect(scope) .to contain_exactly(notification) end end - context "with the user being recipient and not being allowed to see the work package" do + context 'with the user being recipient and not being allowed to see the work package' do let(:permissions) { [] } - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with the user not being recipient but being allowed to see the work package" do + context 'with the user not being recipient but being allowed to see the work package' do let(:notification_recipient) { create(:user) } - it_behaves_like "is empty" + it_behaves_like 'is empty' end end end diff --git a/spec/models/oauth_client_token_spec.rb b/spec/models/oauth_client_token_spec.rb index 385198730745..8f72a4ccbee4 100644 --- a/spec/models/oauth_client_token_spec.rb +++ b/spec/models/oauth_client_token_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OAuthClientToken do let(:access_token) { "x" } @@ -37,59 +37,59 @@ let(:oauth_client) { create(:oauth_client) } let(:instance) { described_class.new(access_token:, refresh_token:, user:, oauth_client:) } - describe "#valid?" do + describe '#valid?' do subject { instance.valid? } - context "with default arguments" do - it "succeeds" do + context 'with default arguments' do + it 'succeeds' do expect(subject).to be_truthy end end - context "with access_token too short" do + context 'with access_token too short' do let(:access_token) { "" } - it "fails with access_token too short" do + it 'fails with access_token too short' do expect(subject).to be_falsey end end - context "with refresh_token too short" do + context 'with refresh_token too short' do let(:refresh_token) { "" } - it "fails with refresh_token too short" do + it 'fails with refresh_token too short' do expect(subject).to be_falsey end end - context "without access_token" do + context 'without access_token' do let(:access_token) { nil } - it "fails with access_token is nil" do + it 'fails with access_token is nil' do expect(subject).to be_falsey end end - context "without refresh_token" do + context 'without refresh_token' do let(:refresh_token) { nil } - it "fails with refresh_token is nil" do + it 'fails with refresh_token is nil' do expect(subject).to be_falsey end end - context "with invalid user" do + context 'with invalid user' do let(:user) { nil } - it "fails with invalid user" do + it 'fails with invalid user' do expect(subject).to be_falsey end end - context "with invalid oauth_client" do + context 'with invalid oauth_client' do let(:oauth_client) { nil } - it "fails with invalid oauth_client" do + it 'fails with invalid oauth_client' do expect(subject).to be_falsey end end diff --git a/spec/models/placeholder_users/placeholder_user_spec.rb b/spec/models/placeholder_users/placeholder_user_spec.rb index 72b2e970844e..72c678993fb4 100644 --- a/spec/models/placeholder_users/placeholder_user_spec.rb +++ b/spec/models/placeholder_users/placeholder_user_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe PlaceholderUser do let(:placeholder_user) { build(:placeholder_user) } subject { placeholder_user } - describe "#name" do - it "updates the name" do + describe '#name' do + it 'updates the name' do subject.name = "Foo" expect(subject.name).to eq("Foo") end - it "updates the lastname attribute" do + it 'updates the lastname attribute' do subject.name = "Foo" expect(subject.lastname).to eq("Foo") end @@ -49,7 +49,7 @@ end describe "#to_s" do - it "returns the lastname" do + it 'returns the lastname' do expect(subject.to_s).to eq(subject.lastname) end end diff --git a/spec/models/placeholder_users/scopes/visible_spec.rb b/spec/models/placeholder_users/scopes/visible_spec.rb index 0bd980bded47..e0cab80c6046 100644 --- a/spec/models/placeholder_users/scopes/visible_spec.rb +++ b/spec/models/placeholder_users/scopes/visible_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe PlaceholderUsers::Scopes::Visible do - describe ".visible" do + describe '.visible' do shared_let(:project) { create(:project) } shared_let(:other_project) { create(:project) } shared_let(:role) { create(:project_role, permissions: %i[manage_members]) } @@ -41,26 +41,26 @@ subject { PlaceholderUser.visible.to_a } - context "when user has manage_members permission" do + context 'when user has manage_members permission' do current_user { create(:user, member_with_roles: { project => role }) } - it "sees all users" do + it 'sees all users' do expect(subject).to contain_exactly(other_project_placeholder, global_placeholder) end end - context "when user has no manage_members permission, but it is in other project" do + context 'when user has no manage_members permission, but it is in other project' do current_user { create(:user, member_with_permissions: { other_project => %i[view_work_packages] }) } - it "sees the other user in the same project" do + it 'sees the other user in the same project' do expect(subject).to contain_exactly(other_project_placeholder) end end - context "when user has no permission" do + context 'when user has no permission' do current_user { create(:user) } - it "sees nothing" do + it 'sees nothing' do expect(subject).to be_empty end end diff --git a/spec/models/principal_spec.rb b/spec/models/principal_spec.rb index 76bab20a405b..0ef56c5aa799 100644 --- a/spec/models/principal_spec.rb +++ b/spec/models/principal_spec.rb @@ -28,32 +28,32 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principal do let(:user) { build(:user) } let(:group) { build(:group) } def self.should_return_groups_and_users_if_active(method, *) - it "returns a user" do + it 'returns a user' do user.save! expect(described_class.send(method, *).where(id: user.id)).to eq([user]) end - it "returns a group" do + it 'returns a group' do group.save! expect(described_class.send(method, *).where(id: group.id)).to eq([group]) end - it "does not return the anonymous user" do + it 'does not return the anonymous user' do User.anonymous expect(described_class.send(method, *).where(id: user.id)).to eq([]) end - it "does not return an inactive user" do + it 'does not return an inactive user' do user.status = User.statuses[:locked] user.save! @@ -62,16 +62,16 @@ def self.should_return_groups_and_users_if_active(method, *) end end - describe "associations" do + describe 'associations' do subject { described_class.new } it { is_expected.to have_many(:work_package_shares).conditions(entity_type: WorkPackage.name) } end - describe "active" do + describe 'active' do should_return_groups_and_users_if_active(:active) - it "does not return a registered user" do + it 'does not return a registered user' do user.status = User.statuses[:registered] user.save! @@ -80,10 +80,10 @@ def self.should_return_groups_and_users_if_active(method, *) end end - describe "not_locked" do + describe 'not_locked' do should_return_groups_and_users_if_active(:not_locked) - it "returns a registered user" do + it 'returns a registered user' do user.status = User.statuses[:registered] user.save! @@ -92,7 +92,7 @@ def self.should_return_groups_and_users_if_active(method, *) end end - describe ".memberships" do + describe '.memberships' do let(:project_role) { create(:project_role) } let(:global_role) { create(:global_role) } let(:work_package_role) { create(:view_work_package_role) } @@ -123,7 +123,7 @@ def self.should_return_groups_and_users_if_active(method, *) roles: [work_package_role]) end - it "returns all active projects and global members" do + it 'returns all active projects and global members' do expect(user.memberships) .to contain_exactly(active_project_member, global_member) end diff --git a/spec/models/principals/scopes/having_entity_membership_spec.rb b/spec/models/principals/scopes/having_entity_membership_spec.rb index 544930fcd093..9ea3c02d7251 100644 --- a/spec/models/principals/scopes/having_entity_membership_spec.rb +++ b/spec/models/principals/scopes/having_entity_membership_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::HavingEntityMembership do shared_association_default(:status) { create(:status) } shared_association_default(:priority) { create(:priority) } shared_association_default(:author, factory_name: :user) { create(:user) } - describe ".having_entity_membership" do + describe '.having_entity_membership' do subject { Principal.having_entity_membership(work_package) } - context "with some sharing" do + context 'with some sharing' do let(:project_role) { create(:project_role) } let(:view_work_package_role) { create(:view_work_package_role) } let(:comment_work_package_role) { create(:comment_work_package_role) } @@ -63,7 +63,7 @@ let!(:non_shared_project_user) { create(:user) } let!(:shared_project_user) { create(:user) } - it "returns all those users having an entity membership" do + it 'returns all those users having an entity membership' do expect(subject) .to contain_exactly(view_user, comment_user, @@ -73,13 +73,13 @@ end end - context "without any sharing" do + context 'without any sharing' do let(:project) { create(:project) } let(:work_package) { create(:work_package, project:) } let!(:user) { create(:user) } - it "is empty" do + it 'is empty' do expect(subject).to be_empty end end diff --git a/spec/models/principals/scopes/human_spec.rb b/spec/models/principals/scopes/human_spec.rb index 0c4e88e0bc42..00d0c1d39aa2 100644 --- a/spec/models/principals/scopes/human_spec.rb +++ b/spec/models/principals/scopes/human_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::Human do - describe ".human" do + describe '.human' do let!(:anonymous_user) { create(:anonymous) } let!(:system_user) { create(:system) } let!(:deleted_user) { create(:deleted_user) } @@ -39,7 +39,7 @@ subject { Principal.human } - it "returns only actual users and groups" do + it 'returns only actual users and groups' do expect(subject) .to contain_exactly(user, group) end diff --git a/spec/models/principals/scopes/like_spec.rb b/spec/models/principals/scopes/like_spec.rb index f1238bcfe982..df9f3f223f4e 100644 --- a/spec/models/principals/scopes/like_spec.rb +++ b/spec/models/principals/scopes/like_spec.rb @@ -26,52 +26,52 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::Like do - describe ".like" do + describe '.like' do let!(:login) do - create(:principal, login: "login") + create(:principal, login: 'login') end let!(:login2) do - create(:principal, login: "login2") + create(:principal, login: 'login2') end let!(:firstname) do - create(:principal, firstname: "firstname") + create(:principal, firstname: 'firstname') end let!(:firstname2) do - create(:principal, firstname: "firstname2") + create(:principal, firstname: 'firstname2') end let!(:lastname) do - create(:principal, lastname: "lastname") + create(:principal, lastname: 'lastname') end let!(:lastname2) do - create(:principal, lastname: "lastname2") + create(:principal, lastname: 'lastname2') end let!(:mail) do - create(:principal, mail: "mail@example.com") + create(:principal, mail: 'mail@example.com') end let!(:mail2) do - create(:principal, mail: "mail2@example.com") + create(:principal, mail: 'mail2@example.com') end - it "finds by login" do - expect(Principal.like("login")) + it 'finds by login' do + expect(Principal.like('login')) .to contain_exactly(login, login2) end - it "finds by firstname" do - expect(Principal.like("firstname")) + it 'finds by firstname' do + expect(Principal.like('firstname')) .to contain_exactly(firstname, firstname2) end - it "finds by lastname" do - expect(Principal.like("lastname")) + it 'finds by lastname' do + expect(Principal.like('lastname')) .to contain_exactly(lastname, lastname2) end - it "finds by mail" do - expect(Principal.like("mail")) + it 'finds by mail' do + expect(Principal.like('mail')) .to contain_exactly(mail, mail2) end end diff --git a/spec/models/principals/scopes/not_builtin_spec.rb b/spec/models/principals/scopes/not_builtin_spec.rb index 97923657f7f9..21d07462be96 100644 --- a/spec/models/principals/scopes/not_builtin_spec.rb +++ b/spec/models/principals/scopes/not_builtin_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::NotBuiltin do - describe ".not_builtin" do + describe '.not_builtin' do let!(:anonymous_user) { create(:anonymous) } let!(:system_user) { create(:system) } let!(:deleted_user) { create(:deleted_user) } @@ -39,7 +39,7 @@ subject { Principal.not_builtin } - it "returns only actual users and groups" do + it 'returns only actual users and groups' do expect(subject) .to contain_exactly(user, group, placeholder_user) end diff --git a/spec/models/principals/scopes/ordered_by_name_spec.rb b/spec/models/principals/scopes/ordered_by_name_spec.rb index 966e6d781752..87cb99b90b4b 100644 --- a/spec/models/principals/scopes/ordered_by_name_spec.rb +++ b/spec/models/principals/scopes/ordered_by_name_spec.rb @@ -26,66 +26,66 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::OrderedByName do - describe ".ordered_by_name" do - shared_let(:alice) { create(:user, login: "alice", firstname: "Alice", lastname: "Zetop") } - shared_let(:eve) { create(:user, login: "eve", firstname: "Eve", lastname: "Baddie") } + describe '.ordered_by_name' do + shared_let(:alice) { create(:user, login: 'alice', firstname: 'Alice', lastname: 'Zetop') } + shared_let(:eve) { create(:user, login: 'eve', firstname: 'Eve', lastname: 'Baddie') } - shared_let(:group) { create(:group, name: "Core Team") } - shared_let(:placeholder_user) { create(:placeholder_user, name: "Developers") } + shared_let(:group) { create(:group, name: 'Core Team') } + shared_let(:placeholder_user) { create(:placeholder_user, name: 'Developers') } subject { Principal.ordered_by_name(desc: descending).pluck(:id) } let(:descending) { false } - shared_examples "sorted results" do - it "returns the correct ascending sort" do + shared_examples 'sorted results' do + it 'returns the correct ascending sort' do expect(subject).to eq order end - context "reversed" do + context 'reversed' do let(:descending) { true } - it "returns the correct descending sort" do + it 'returns the correct descending sort' do expect(subject).to eq order.reverse end end end - context "with default user sort", with_settings: { user_format: :firstname_lastname } do - it_behaves_like "sorted results" do + context 'with default user sort', with_settings: { user_format: :firstname_lastname } do + it_behaves_like 'sorted results' do let(:order) { [alice.id, group.id, placeholder_user.id, eve.id] } end end - context "with lastname_firstname user sort", with_settings: { user_format: :lastname_firstname } do - it_behaves_like "sorted results" do + context 'with lastname_firstname user sort', with_settings: { user_format: :lastname_firstname } do + it_behaves_like 'sorted results' do let(:order) { [eve.id, group.id, placeholder_user.id, alice.id] } end end - context "with lastname_n_firstname user sort", with_settings: { user_format: :lastname_n_firstname } do - it_behaves_like "sorted results" do + context 'with lastname_n_firstname user sort', with_settings: { user_format: :lastname_n_firstname } do + it_behaves_like 'sorted results' do let(:order) { [eve.id, group.id, placeholder_user.id, alice.id] } end end - context "with lastname_coma_firstname user sort", with_settings: { user_format: :lastname_coma_firstname } do - it_behaves_like "sorted results" do + context 'with lastname_coma_firstname user sort', with_settings: { user_format: :lastname_coma_firstname } do + it_behaves_like 'sorted results' do let(:order) { [eve.id, group.id, placeholder_user.id, alice.id] } end end - context "with firstname user sort", with_settings: { user_format: :firstname } do - it_behaves_like "sorted results" do + context 'with firstname user sort', with_settings: { user_format: :firstname } do + it_behaves_like 'sorted results' do let(:order) { [alice.id, group.id, placeholder_user.id, eve.id] } end end - context "with login user sort", with_settings: { user_format: :username } do - it_behaves_like "sorted results" do + context 'with login user sort', with_settings: { user_format: :username } do + it_behaves_like 'sorted results' do let(:order) { [alice.id, group.id, placeholder_user.id, eve.id] } end end diff --git a/spec/models/principals/scopes/possible_assignee_spec.rb b/spec/models/principals/scopes/possible_assignee_spec.rb index 1a6cedcd5b3f..ce25a6b60e2f 100644 --- a/spec/models/principals/scopes/possible_assignee_spec.rb +++ b/spec/models/principals/scopes/possible_assignee_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::PossibleAssignee do shared_let(:project) { create(:project) } @@ -41,8 +41,8 @@ shared_let(:assignable_work_package_role) { create(:comment_work_package_role) } shared_let(:non_assignable_work_package_role) { create(:view_work_package_role) } - describe ".possible_assignee" do - context "when providing Project resources" do + describe '.possible_assignee' do + context 'when providing Project resources' do subject { Principal.possible_assignee(project) } let(:user_status) { :active } @@ -61,54 +61,54 @@ create(:group, member_with_roles: { other_project => role }) end - context "with the role being assignable" do + context 'with the role being assignable' do let(:role) { assignable_project_role } - context "with the user status being active" do - it "returns non locked users, groups and placeholder users that are members" do + context 'with the user status being active' do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_user, member_placeholder_user, member_group) end end - context "with the user status being registered" do + context 'with the user status being registered' do let(:user_status) { :registered } - it "returns non locked users, groups and placeholder users that are members" do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_user, member_placeholder_user, member_group) end end - context "with the user status being invited" do + context 'with the user status being invited' do let(:user_status) { :invited } - it "returns non locked users, groups and placeholder users that are members" do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_user, member_placeholder_user, member_group) end end - context "with the user status being locked" do + context 'with the user status being locked' do let(:user_status) { :locked } - it "returns non locked users, groups and placeholder users that are members" do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_placeholder_user, member_group) end end end - context "with the role not being assignable" do + context 'with the role not being assignable' do let(:role) { non_assignable_project_role } - it "returns nothing" do + it 'returns nothing' do expect(subject) .to be_empty end end - context "when asking for multiple projects" do + context 'when asking for multiple projects' do subject { Principal.possible_assignee([project, other_project]) } before do @@ -120,14 +120,14 @@ let(:role) { assignable_project_role } - it "returns users assignable in all of the provided projects (intersection)" do + it 'returns users assignable in all of the provided projects (intersection)' do expect(subject) .to contain_exactly(member_user) end end end - context "when providing WorkPackage resources" do + context 'when providing WorkPackage resources' do subject { Principal.possible_assignee(work_package) } let!(:member_user) do @@ -142,48 +142,48 @@ create(:group, member_with_roles: { work_package => role }) end - context "with the role being assignable" do + context 'with the role being assignable' do let(:role) { assignable_work_package_role } - context "and the user status being active" do + context 'and the user status being active' do let(:user_status) { :active } - it "returns non locked users, groups and placeholder users that are members" do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_user, member_placeholder_user, member_group) end end - context "with the user status being invited" do + context 'with the user status being invited' do let(:user_status) { :invited } - it "returns non locked users, groups and placeholder users that are members" do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_user, member_placeholder_user, member_group) end end - context "with the user status being locked" do + context 'with the user status being locked' do let(:user_status) { :locked } - it "returns non locked users, groups and placeholder users that are members" do + it 'returns non locked users, groups and placeholder users that are members' do expect(subject) .to contain_exactly(member_placeholder_user, member_group) end end end - context "with the role not being assignable" do + context 'with the role not being assignable' do let(:role) { non_assignable_work_package_role } let(:user_status) { :active } - it "returns nothing" do + it 'returns nothing' do expect(subject) .to be_empty end end - context "when asking for multiple Work Packages (intersection)" do + context 'when asking for multiple Work Packages (intersection)' do subject { Principal.possible_assignee([work_package, other_work_package]) } before do @@ -196,7 +196,7 @@ let(:role) { assignable_work_package_role } let(:user_status) { :active } - it "returns users assignable in all of the provided work packages (intersection)" do + it 'returns users assignable in all of the provided work packages (intersection)' do expect(subject) .to contain_exactly(member_user) end diff --git a/spec/models/principals/scopes/possible_member_spec.rb b/spec/models/principals/scopes/possible_member_spec.rb index 7fa9bbfad4d4..a19a46dedc1d 100644 --- a/spec/models/principals/scopes/possible_member_spec.rb +++ b/spec/models/principals/scopes/possible_member_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::PossibleMember do let(:project) { create(:project) } @@ -76,21 +76,21 @@ end end - describe ".possible_member" do + describe '.possible_member' do subject { Principal.possible_member(project) } - context "as a simple user" do + context 'as a simple user' do current_user { active_user } - it "returns non locked users, groups and placeholder users not part of the project yet" do + it 'returns non locked users, groups and placeholder users not part of the project yet' do expect(subject).to contain_exactly(active_user, member_in_public_project) end end - context "as a user with global permission to manage users" do + context 'as a user with global permission to manage users' do current_user { global_manager } - it "returns non locked users, groups and placeholder users not part of the project yet" do + it 'returns non locked users, groups and placeholder users not part of the project yet' do expect(subject).to contain_exactly(admin_user, global_manager, active_user, registered_user, invited_user, placeholder_user, group, member_in_public_project, shared_work_package_with_user, @@ -98,10 +98,10 @@ end end - context "as an admin" do + context 'as an admin' do current_user { admin_user } - it "returns non locked users, groups and placeholder users not part of the project yet" do + it 'returns non locked users, groups and placeholder users not part of the project yet' do expect(subject).to contain_exactly(admin_user, global_manager, active_user, registered_user, invited_user, placeholder_user, group, member_in_public_project, shared_work_package_with_user, diff --git a/spec/models/principals/scopes/user_spec.rb b/spec/models/principals/scopes/user_spec.rb index 68c4df67cb94..fc3f5afc9dd5 100644 --- a/spec/models/principals/scopes/user_spec.rb +++ b/spec/models/principals/scopes/user_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::User do - describe ".user" do + describe '.user' do let!(:anonymous_user) { create(:anonymous) } let!(:system_user) { create(:system) } let!(:deleted_user) { create(:deleted_user) } @@ -39,7 +39,7 @@ subject { Principal.user } - it "returns only actual users and groups" do + it 'returns only actual users and groups' do expect(subject) .to contain_exactly(user) end diff --git a/spec/models/principals/scopes/visible_spec.rb b/spec/models/principals/scopes/visible_spec.rb index 4e5d590ce6e0..398a819019b2 100644 --- a/spec/models/principals/scopes/visible_spec.rb +++ b/spec/models/principals/scopes/visible_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::Scopes::Visible do - describe ".visible" do + describe '.visible' do shared_let(:role) { create(:project_role, permissions: %i[manage_members]) } shared_let(:anonymous_user) { User.anonymous } @@ -37,15 +37,15 @@ shared_let(:project) { create(:project) } shared_let(:project_user) do - create(:user, firstname: "project user", + create(:user, firstname: 'project user', member_with_roles: { project => role }) end shared_let(:project_group) do - create(:group, firstname: "project group", + create(:group, firstname: 'project group', member_with_roles: { project => role }) end shared_let(:project_placeholder_user) do - create(:placeholder_user, firstname: "project placeholder user", + create(:placeholder_user, firstname: 'project placeholder user', member_with_roles: { project => role }) end @@ -53,61 +53,61 @@ # the outside for people lacking manage_members or manage_user permissions shared_let(:other_project) { create(:project) } shared_let(:other_project_user) do - create(:user, firstname: "other project user", + create(:user, firstname: 'other project user', member_with_roles: { other_project => role }) end shared_let(:other_project_group) do - create(:group, firstname: "other project group", + create(:group, firstname: 'other project group', member_with_roles: { other_project => role }) end shared_let(:other_placeholder_user) do - create(:placeholder_user, firstname: "other project placeholder user", + create(:placeholder_user, firstname: 'other project placeholder user', member_with_roles: { other_project => role }) end - shared_let(:global_user) { create(:user, firstname: "global user") } - shared_let(:global_group) { create(:group, firstname: "global group") } - shared_let(:global_placeholder_user) { create(:placeholder_user, firstname: "global placeholder") } + shared_let(:global_user) { create(:user, firstname: 'global user') } + shared_let(:global_group) { create(:group, firstname: 'global group') } + shared_let(:global_placeholder_user) { create(:placeholder_user, firstname: 'global placeholder') } subject { Principal.visible.to_a } - shared_examples "sees all principals" do - it "sees all users, groups, and placeholder users" do + shared_examples 'sees all principals' do + it 'sees all users, groups, and placeholder users' do expect(subject).to contain_exactly(anonymous_user, system_user, current_user, project_user, other_project_user, global_user, project_group, other_project_group, global_group, project_placeholder_user, other_placeholder_user, global_placeholder_user) end end - context "when user has manage_members project permission" do + context 'when user has manage_members project permission' do current_user do - create(:user, firstname: "current user", + create(:user, firstname: 'current user', member_with_roles: { project => role }) end - include_examples "sees all principals" + include_examples 'sees all principals' end - context "when user has no manage_members project permission, and is member of a project" do + context 'when user has no manage_members project permission, and is member of a project' do current_user do - create(:user, firstname: "current user", + create(:user, firstname: 'current user', member_with_permissions: { project => %i[view_work_packages] }) end - it "sees only the users, groups, and placeholder users in the same project" do + it 'sees only the users, groups, and placeholder users in the same project' do expect(subject).to contain_exactly(current_user, project_user, project_group, project_placeholder_user) end end - context "when user has manage_user global permission" do - current_user { create(:user, firstname: "current user", global_permissions: %i[manage_user]) } + context 'when user has manage_user global permission' do + current_user { create(:user, firstname: 'current user', global_permissions: %i[manage_user]) } - include_examples "sees all principals" + include_examples 'sees all principals' end - context "when user has no permission" do - current_user { create(:user, firstname: "current user") } + context 'when user has no permission' do + current_user { create(:user, firstname: 'current user') } - it "sees only themself" do + it 'sees only themself' do expect(subject).to contain_exactly(current_user) end end diff --git a/spec/models/project_role_spec.rb b/spec/models/project_role_spec.rb index 6a95a15eaeaf..706854f9d357 100644 --- a/spec/models/project_role_spec.rb +++ b/spec/models/project_role_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe ProjectRole do let(:permissions) { %i[permission1 permission2] } let(:build_role) { build(:project_role, permissions:) } let(:created_role) { create(:project_role, permissions:) } - describe ".givable" do + describe '.givable' do let!(:project_role) { create(:project_role) } let!(:builtin_role) { create(:non_member) } it { expect(described_class.givable).to contain_exactly project_role } end - describe ".in_new_project" do + describe '.in_new_project' do let!(:ungivable_role) { create(:non_member) } let!(:second_role) do create(:project_role).tap do |r| @@ -53,83 +53,83 @@ end end - context "without a specified role" do - it "returns the first role (by position)" do + context 'without a specified role' do + it 'returns the first role (by position)' do expect(described_class.in_new_project) .to eql first_role end end - context "with a specified role" do + context 'with a specified role' do before do allow(Setting) .to receive(:new_project_user_role_id) .and_return(second_role.id.to_s) end - it "returns that role" do + it 'returns that role' do expect(described_class.in_new_project) .to eql second_role end end - context "with a specified role but that one is faulty (e.g. does not exist any more)" do + context 'with a specified role but that one is faulty (e.g. does not exist any more)' do before do allow(Setting) .to receive(:new_project_user_role_id) .and_return("-1") end - it "returns the first role (by position)" do + it 'returns the first role (by position)' do expect(described_class.in_new_project) .to eql first_role end end end - describe ".anonymous" do + describe '.anonymous' do subject { described_class.anonymous } - it "has the constant's builtin value" do + it 'has the constant\'s builtin value' do expect(subject.builtin) .to eql(Role::BUILTIN_ANONYMOUS) end - it "is builtin" do + it 'is builtin' do expect(subject) .to be_builtin end - context "with a missing anonymous role" do + context 'with a missing anonymous role' do before do described_class.where(builtin: Role::BUILTIN_ANONYMOUS).delete_all end - it "creates a new anonymous role" do + it 'creates a new anonymous role' do expect { subject }.to change(described_class, :count).by(1) end end end - describe ".non_member" do + describe '.non_member' do subject { described_class.non_member } - it "has the constant's builtin value" do + it 'has the constant\'s builtin value' do expect(subject.builtin) .to eql(Role::BUILTIN_NON_MEMBER) end - it "is builtin" do + it 'is builtin' do expect(subject) .to be_builtin end - context "with a missing non_member role" do + context 'with a missing non_member role' do before do described_class.where(builtin: Role::BUILTIN_NON_MEMBER).delete_all end - it "creates a new non_member role" do + it 'creates a new non_member role' do expect { subject }.to change(described_class, :count).by(1) end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d8d336a9a0e4..1cc598ffe391 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/shared/become_member", __dir__) +require 'spec_helper' +require File.expand_path('../support/shared/become_member', __dir__) RSpec.describe Project do include BecomeMember @@ -38,48 +38,48 @@ let(:build_project) { build_stubbed(:project, active:) } let(:user) { create(:user) } - describe "#active?" do - context "if active" do - it "is true" do + describe '#active?' do + context 'if active' do + it 'is true' do expect(project).to be_active end end - context "if not active" do + context 'if not active' do let(:active) { false } - it "is false" do + it 'is false' do expect(project).not_to be_active end end end - describe "#archived?" do + describe '#archived?' do subject { project.archived? } - context "if active is true" do + context 'if active is true' do let(:active) { true } it { is_expected.to be false } end - context "if active is false" do + context 'if active is false' do let(:active) { false } it { is_expected.to be true } end end - describe "#being_archived?" do + describe '#being_archived?' do subject { project.being_archived? } - context "if active is true" do + context 'if active is true' do let(:active) { true } it { is_expected.to be false } end - context "if active was true and changes to false (marking as archived)" do + context 'if active was true and changes to false (marking as archived)' do let(:active) { true } before do @@ -89,13 +89,13 @@ it { is_expected.to be true } end - context "if active is false" do + context 'if active is false' do let(:active) { false } it { is_expected.to be false } end - context "if active was false and changes to true (marking as active)" do + context 'if active was false and changes to true (marking as active)' do let(:active) { false } before do @@ -106,26 +106,26 @@ end end - context "when the wiki module is enabled" do - let(:project) { create(:project, disable_modules: "wiki") } + context 'when the wiki module is enabled' do + let(:project) { create(:project, disable_modules: 'wiki') } before do - project.enabled_module_names = project.enabled_module_names | ["wiki"] + project.enabled_module_names = project.enabled_module_names | ['wiki'] project.save project.reload end - it "creates a wiki" do + it 'creates a wiki' do expect(project.wiki).to be_present end - it "creates a wiki menu item named like the default start page" do + it 'creates a wiki menu item named like the default start page' do expect(project.wiki.wiki_menu_items).to be_one expect(project.wiki.wiki_menu_items.first.title).to eq(project.wiki.start_page) end end - describe "#copy_allowed?" do + describe '#copy_allowed?' do let(:user) { build_stubbed(:user) } let(:project) { build_stubbed(:project) } let(:permission_granted) { true } @@ -138,45 +138,45 @@ login_as(user) end - context "with copy project permission" do - it "is true" do + context 'with copy project permission' do + it 'is true' do expect(project).to be_copy_allowed end end - context "without copy project permission" do + context 'without copy project permission' do before { mock_permissions_for(user, &:forbid_everything) } - it "is false" do + it 'is false' do expect(project).not_to be_copy_allowed end end end - describe "name" do - let(:name) { " Hello World " } + describe 'name' do + let(:name) { ' Hello World ' } let(:project) { described_class.new attributes_for(:project, name:) } - context "with white spaces in the name" do - it "trims the name" do + context 'with white spaces in the name' do + it 'trims the name' do project.save - expect(project.name).to eql("Hello World") + expect(project.name).to eql('Hello World') end end - context "when updating the name" do - it "persists the update" do + context 'when updating the name' do + it 'persists the update' do project.save - project.name = "A new name" + project.name = 'A new name' project.save project.reload - expect(project.name).to eql("A new name") + expect(project.name).to eql('A new name') end end end - describe "#types_used_by_work_packages" do + describe '#types_used_by_work_packages' do let(:project) { create(:project_with_types) } let(:type) { project.types.first } let(:other_type) { create(:type) } @@ -184,7 +184,7 @@ let(:other_project) { create(:project, types: [other_type, type]) } let(:other_project_work_package) { create(:work_package, type: other_type, project: other_project) } - it "returns the type used by a work package of the project" do + it 'returns the type used by a work package of the project' do project_work_package other_project_work_package @@ -192,11 +192,11 @@ end end - describe "Views belonging to queries that belong to the project" do + describe 'Views belonging to queries that belong to the project' do let(:query) { create(:query, project:) } let(:view) { create(:view, query:) } - it "destroys the views and queries when project gets destroyed" do + it 'destroys the views and queries when project gets destroyed' do view project.destroy @@ -205,7 +205,7 @@ end end - describe "#members" do + describe '#members' do let(:role) { create(:project_role) } let(:active_user) { create(:user) } let!(:active_member) { create(:member, project:, user: active_user, roles: [role]) } @@ -213,17 +213,17 @@ let(:inactive_user) { create(:user, status: Principal.statuses[:locked]) } let!(:inactive_member) { create(:member, project:, user: inactive_user, roles: [role]) } - it "only includes active members" do + it 'only includes active members' do expect(project.members) .to eq [active_member] end end - include_examples "creates an audit trail on destroy" do + include_examples 'creates an audit trail on destroy' do subject { create(:attachment) } end - describe "#users" do + describe '#users' do let(:role) { create(:project_role) } let(:active_user) { create(:user) } let!(:active_member) { create(:member, project:, user: active_user, roles: [role]) } @@ -231,19 +231,19 @@ let(:inactive_user) { create(:user, status: Principal.statuses[:locked]) } let!(:inactive_member) { create(:member, project:, user: inactive_user, roles: [role]) } - it "only includes active users" do + it 'only includes active users' do expect(project.users) .to eq [active_user] end end - include_examples "creates an audit trail on destroy" do + include_examples 'creates an audit trail on destroy' do subject { create(:attachment) } end - describe "#close_completed_versions" do + describe '#close_completed_versions' do let!(:completed_version) do - create(:version, project:, effective_date: Date.parse("2000-01-01")).tap do |v| + create(:version, project:, effective_date: Date.parse('2000-01-01')).tap do |v| create(:work_package, version: v, status: create(:closed_status)) end end @@ -253,7 +253,7 @@ end end let!(:version_with_open_wps) do - create(:version, project:, effective_date: Date.parse("2000-01-01")).tap do |v| + create(:version, project:, effective_date: Date.parse('2000-01-01')).tap do |v| create(:work_package, version: v) end end @@ -262,87 +262,87 @@ project.close_completed_versions end - it "closes the completed version" do + it 'closes the completed version' do expect(completed_version.reload.status) - .to eq "closed" + .to eq 'closed' end - it "keeps the version with the not yet reached date open" do + it 'keeps the version with the not yet reached date open' do expect(ineffective_version.reload.status) - .to eq "open" + .to eq 'open' end - it "keeps the version with open work packages open" do + it 'keeps the version with open work packages open' do expect(version_with_open_wps.reload.status) - .to eq "open" + .to eq 'open' end end - describe "hierarchy methods" do + describe 'hierarchy methods' do shared_let(:root_project) { create(:project) } shared_let(:parent_project) { create(:project, parent: root_project) } shared_let(:child_project1) { create(:project, parent: parent_project) } shared_let(:child_project2) { create(:project, parent: parent_project) } - describe "#parent" do - it "returns the parent" do + describe '#parent' do + it 'returns the parent' do expect(parent_project.parent) .to eq root_project end end - describe "#root" do - it "returns the root of the hierarchy" do + describe '#root' do + it 'returns the root of the hierarchy' do expect(child_project1.root) .to eq root_project end end - describe "#ancestors" do - it "returns the ancestors of the work package" do + describe '#ancestors' do + it 'returns the ancestors of the work package' do expect(child_project1.ancestors) .to eq [root_project, parent_project] end - it "returns empty array if there are no ancestors" do + it 'returns empty array if there are no ancestors' do expect(root_project.ancestors) .to be_empty end end - describe "#descendants" do - it "returns the descendants of the work package" do + describe '#descendants' do + it 'returns the descendants of the work package' do expect(root_project.descendants) .to contain_exactly(parent_project, child_project1, child_project2) end - it "returns empty array if there are no descendants" do + it 'returns empty array if there are no descendants' do expect(child_project2.descendants) .to be_empty end end - describe "#children" do - it "returns the children of the work package" do + describe '#children' do + it 'returns the children of the work package' do expect(parent_project.children) .to contain_exactly(child_project1, child_project2) end - it "returns empty array if there are no descendants" do + it 'returns empty array if there are no descendants' do expect(child_project2.children) .to be_empty end end end - describe "#active_subprojects" do + describe '#active_subprojects' do subject { root_project.active_subprojects } shared_let(:root_project) { create(:project) } shared_let(:parent_project) { create(:project, parent: root_project) } shared_let(:child_project1) { create(:project, parent: parent_project) } - context "with an archived subproject" do + context 'with an archived subproject' do before do child_project1.active = false child_project1.save @@ -351,12 +351,12 @@ it { is_expected.to eq [parent_project] } end - context "with all active subprojects" do + context 'with all active subprojects' do it { is_expected.to eq [parent_project, child_project1] } end end - describe "#rolled_up_types" do + describe '#rolled_up_types' do let!(:parent) do create(:project, types: [parent_type]).tap do |p| project.update_attribute(:parent, p) @@ -377,7 +377,7 @@ end end - it "includes all types of active projects starting from receiver down to the leaves" do + it 'includes all types of active projects starting from receiver down to the leaves' do project.reload expect(project.rolled_up_types) @@ -385,29 +385,29 @@ end end - describe "#enabled_module_names=", with_settings: { default_projects_modules: %w(work_package_tracking repository) } do - context "when assigning a new value" do + describe '#enabled_module_names=', with_settings: { default_projects_modules: %w(work_package_tracking repository) } do + context 'when assigning a new value' do let(:new_value) { %w(work_package_tracking news) } subject do project.enabled_module_names = new_value end - it "sets the value" do + it 'sets the value' do subject expect(project.reload.enabled_module_names.sort) .to eql new_value.sort end - it "keeps already assigned modules intact (same id)" do + it 'keeps already assigned modules intact (same id)' do expect { subject } - .not_to change { project.reload.enabled_modules.find { |em| em.name == "work_package_tracking" }.id } + .not_to change { project.reload.enabled_modules.find { |em| em.name == 'work_package_tracking' }.id } end end end - it_behaves_like "acts_as_customizable included" do + it_behaves_like 'acts_as_customizable included' do let(:model_instance) { project } let(:custom_field) { create(:string_project_custom_field) } end diff --git a/spec/models/projects/activity_spec.rb b/spec/models/projects/activity_spec.rb index 94f6ede2d3dc..57ff7ca81d26 100644 --- a/spec/models/projects/activity_spec.rb +++ b/spec/models/projects/activity_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::Activity, "core" do +RSpec.describe Projects::Activity, 'core' do shared_let(:project) do create(:project, :updated_a_long_time_ago) end @@ -115,8 +115,8 @@ def latest_activity Project.with_latest_activity.find(project.id).latest_activity_at end - describe ".with_latest_activity" do - it "is the latest work_package update" do + describe '.with_latest_activity' do + it 'is the latest work_package update' do work_package.update(updated_at: initial_time - 10.seconds) work_package2.update(updated_at: initial_time - 20.seconds) work_package.reload @@ -126,7 +126,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(work_package.updated_at) end - it "is the latest wiki_pages update" do + it 'is the latest wiki_pages update' do wiki_page.update(updated_at: initial_time - 10.seconds) wiki_page2.update(updated_at: initial_time - 20.seconds) wiki_page.reload @@ -135,7 +135,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(wiki_page.updated_at) end - it "is the latest news update" do + it 'is the latest news update' do news.update(updated_at: initial_time - 10.seconds) news2.update(updated_at: initial_time - 20.seconds) news.reload @@ -144,7 +144,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(news.updated_at) end - it "is the latest changeset update" do + it 'is the latest changeset update' do changeset.update(committed_on: initial_time - 10.seconds) changeset2.update(committed_on: initial_time - 20.seconds) changeset.reload @@ -153,7 +153,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(changeset.committed_on) end - it "is the latest message update" do + it 'is the latest message update' do message.update(updated_at: initial_time - 10.seconds) message2.update(updated_at: initial_time - 20.seconds) message.reload @@ -162,7 +162,7 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(message.updated_at) end - it "is the latest time_entry update" do + it 'is the latest time_entry update' do work_package.update(updated_at: initial_time - 60.seconds) time_entry.update(updated_at: initial_time - 10.seconds) time_entry2.update(updated_at: initial_time - 20.seconds) @@ -172,14 +172,14 @@ def latest_activity expect(latest_activity).to be_within(0.00001).of(time_entry.updated_at) end - it "is the latest project update" do + it 'is the latest project update' do work_package.update(updated_at: initial_time - 60.seconds) project.update(updated_at: initial_time - 10.seconds) expect(latest_activity).to be_within(0.00001).of(project.updated_at) end - it "takes the time stamp of the latest activity across models" do + it 'takes the time stamp of the latest activity across models' do work_package.update(updated_at: initial_time - 10.seconds) wiki_page.update(updated_at: initial_time - 20.seconds) news.update(updated_at: initial_time - 30.seconds) diff --git a/spec/models/projects/allowed_to_scope_spec.rb b/spec/models/projects/allowed_to_scope_spec.rb index 38e5f3173abb..a330971a25fd 100644 --- a/spec/models/projects/allowed_to_scope_spec.rb +++ b/spec/models/projects/allowed_to_scope_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Project, "allowed to" do +RSpec.describe Project, 'allowed to' do let(:user) { build(:user) } let(:anonymous) { build(:anonymous) } let(:admin) { build(:admin) } @@ -71,19 +71,19 @@ project:) end - shared_examples_for "includes the project" do - it "includes the project" do + shared_examples_for 'includes the project' do + it 'includes the project' do expect(described_class.allowed_to(user, action)).to contain_exactly(project) end end - shared_examples_for "is empty" do - it "is empty" do + shared_examples_for 'is empty' do + it 'is empty' do expect(described_class.allowed_to(user, action)).to be_empty end end - shared_examples_for "member based allowed to check" do + shared_examples_for 'member based allowed to check' do before do project.save! user.save! @@ -96,7 +96,7 @@ member.save! end - it_behaves_like "includes the project" + it_behaves_like 'includes the project' end context 'with the user being member @@ -108,7 +108,7 @@ member.save! end - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the user being member @@ -119,12 +119,12 @@ member.save! end - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'without the user being member with the role having the permission' do - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the user being member @@ -135,7 +135,7 @@ project.enabled_modules = [] end - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the user being member @@ -144,7 +144,7 @@ member.save! end - it "includes the project" do + it 'includes the project' do expect(described_class.allowed_to(user, public_action)).to contain_exactly(project) end end @@ -157,7 +157,7 @@ project.enabled_modules = [] end - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(user, public_action)).to be_empty end end @@ -170,7 +170,7 @@ project.enabled_modules = [] end - it "includes the project" do + it 'includes the project' do expect(described_class.allowed_to(user, public_non_module_action)).to contain_exactly(project) end end @@ -185,7 +185,7 @@ member.save! end - it "includes the project" do + it 'includes the project' do expect(described_class.allowed_to(user, non_module_action)).to contain_exactly(project) end end @@ -200,13 +200,13 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(user, non_module_action)).to be_empty end end end - shared_examples_for "with an admin user" do + shared_examples_for 'with an admin user' do let(:user) { admin } before do @@ -214,95 +214,95 @@ user.save! end - context "without the user being a member" do - it_behaves_like "includes the project" + context 'without the user being a member' do + it_behaves_like 'includes the project' end - context "without the project being active" do + context 'without the project being active' do let(:project_status) { false } - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'without the project being active with the permission being public' do let(:project_status) { false } - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(user, public_action)).to be_empty end end - context "with the project being active with the permission being public" do - it "includes the project" do + context 'with the project being active with the permission being public' do + it 'includes the project' do expect(described_class.allowed_to(user, public_action)).to contain_exactly(project) end end - context "without the project module being active" do + context 'without the project module being active' do before do project.enabled_modules = [] end - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with the user being locked" do + context 'with the user being locked' do before do user.update!(status: Principal.statuses[:locked]) end - it_behaves_like "is empty" + it_behaves_like 'is empty' end end - context "with the project being private" do + context 'with the project being private' do let(:project) { private_project } - it_behaves_like "member based allowed to check" - it_behaves_like "with an admin user" + it_behaves_like 'member based allowed to check' + it_behaves_like 'with an admin user' - context "with the user not being logged in" do + context 'with the user not being logged in' do before do project.save! anonymous.save! anonymous_role.save! end - context "with the anonymous role having the permission" do - it "is empty" do + context 'with the anonymous role having the permission' do + it 'is empty' do expect(described_class.allowed_to(anonymous, action)).to be_empty end end - context "with the permission being public" do - it "is empty" do + context 'with the permission being public' do + it 'is empty' do expect(described_class.allowed_to(anonymous, public_action)).to be_empty end end end end - context "with the project being public" do + context 'with the project being public' do let(:project) { public_project } - it_behaves_like "member based allowed to check" - it_behaves_like "with an admin user" + it_behaves_like 'member based allowed to check' + it_behaves_like 'with an admin user' - context "with the user not being logged in" do + context 'with the user not being logged in' do before do project.save! anonymous.save! anonymous_role.save! end - context "with the anonymous role having the permission" do - it "includes the project" do + context 'with the anonymous role having the permission' do + it 'includes the project' do expect(described_class.allowed_to(anonymous, action)).to contain_exactly(project) end end - context "with the permission being disabled" do + context 'with the permission being disabled' do let(:permission) { OpenProject::AccessControl.permission(action) } around do |example| @@ -314,7 +314,7 @@ OpenProject::AccessControl.clear_caches end - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(anonymous, action)).to be_empty end end @@ -323,21 +323,21 @@ without the project being active' do let(:project_status) { false } - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(anonymous, action)).to be_empty end end - context "without the anonymous role having the permission" do + context 'without the anonymous role having the permission' do let(:anonymous_permissions) { [] } - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(anonymous, action)).to be_empty end end - context "with the permission being public" do - it "includes the project" do + context 'with the permission being public' do + it 'includes the project' do expect(described_class.allowed_to(anonymous, public_action)).to contain_exactly(project) end end @@ -348,7 +348,7 @@ project.enabled_modules = [] end - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(anonymous, public_action)).to be_empty end end @@ -359,13 +359,13 @@ project.enabled_modules = [] end - it "includes the project" do + it 'includes the project' do expect(described_class.allowed_to(anonymous, public_non_module_action)).to contain_exactly(project) end end end - context "with the user being member" do + context 'with the user being member' do before do project.save! user.save! @@ -378,45 +378,45 @@ let(:permissions) { [] } let(:non_member_permissions) { [action] } - it_behaves_like "is empty" + it_behaves_like 'is empty' end end - context "without the user being member" do + context 'without the user being member' do before do project.save! user.save! non_member_role.save! end - context "with the non member role having the permission" do - it_behaves_like "includes the project" + context 'with the non member role having the permission' do + it_behaves_like 'includes the project' end context 'with the non member role having the permission without the project being active' do let(:project_status) { false } - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the permission being public and not module bound without the project being active' do let(:project_status) { false } - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(user, public_non_module_action)).to be_empty end end - context "without the non member role having the permission" do + context 'without the non member role having the permission' do let(:non_member_permissions) { [] } - it_behaves_like "is empty" + it_behaves_like 'is empty' end - context "with the permission being public" do - it "includes the project" do + context 'with the permission being public' do + it 'includes the project' do expect(described_class.allowed_to(user, public_action)).to contain_exactly(project) end end @@ -427,7 +427,7 @@ project.enabled_modules = [] end - it "is empty" do + it 'is empty' do expect(described_class.allowed_to(user, public_action)).to be_empty end end @@ -438,7 +438,7 @@ project.enabled_modules = [] end - it "includes the project" do + it 'includes the project' do expect(described_class.allowed_to(user, public_non_module_action)).to contain_exactly(project) end end diff --git a/spec/models/projects/project_acts_as_journalized_spec.rb b/spec/models/projects/project_acts_as_journalized_spec.rb index 6649fb3b098b..f8650063c0c6 100644 --- a/spec/models/projects/project_acts_as_journalized_spec.rb +++ b/spec/models/projects/project_acts_as_journalized_spec.rb @@ -26,86 +26,86 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Project, "acts_as_journalized" do +RSpec.describe Project, 'acts_as_journalized' do shared_let(:user) { create(:user) } let!(:project) do User.execute_as user do create(:project, - description: "project description") + description: 'project description') end end - context "on project creation" do - it "has one journal entry" do + context 'on project creation' do + it 'has one journal entry' do expect(Journal.all.count).to eq(1) expect(Journal.first.journable).to eq(project) end - it "notes the changes to name" do + it 'notes the changes to name' do expect(Journal.first.details[:name]) .to contain_exactly(nil, project.name) end - it "notes the changes to description" do + it 'notes the changes to description' do expect(Journal.first.details[:description]) .to contain_exactly(nil, project.description) end - it "notes the changes to public flag" do + it 'notes the changes to public flag' do expect(Journal.first.details[:public]) .to contain_exactly(nil, project.public) end - it "notes the changes to identifier" do + it 'notes the changes to identifier' do expect(Journal.first.details[:identifier]) .to contain_exactly(nil, project.identifier) end - it "notes the changes to active flag" do + it 'notes the changes to active flag' do expect(Journal.first.details[:active]) .to contain_exactly(nil, project.active) end - it "notes the changes to template flag" do + it 'notes the changes to template flag' do expect(Journal.first.details[:templated]) .to contain_exactly(nil, project.templated) end - it "has the timestamp of the project update time for created_at" do + it 'has the timestamp of the project update time for created_at' do expect(Journal.first.created_at) .to eql(project.reload.updated_at) end end - context "when nothing is changed" do + context 'when nothing is changed' do it { expect { project.save! }.not_to change(Journal, :count) } end - describe "on project update", with_settings: { journal_aggregation_time_minutes: 0 } do + describe 'on project update', with_settings: { journal_aggregation_time_minutes: 0 } do shared_let(:parent_project) { create(:project) } before do - project.name = "changed project name" - project.description = "changed project description" + project.name = 'changed project name' + project.description = 'changed project description' project.public = !project.public project.parent = parent_project - project.identifier = "changed-identifier" + project.identifier = 'changed-identifier' project.active = !project.active project.templated = !project.templated project.save! end - context "for last created journal" do - it "has the timestamp of the project update time for created_at" do + context 'for last created journal' do + it 'has the timestamp of the project update time for created_at' do expect(project.last_journal.created_at) .to eql(project.reload.updated_at) end - it "contains last changes" do + it 'contains last changes' do %i[name description public parent_id identifier active templated].each do |prop| expect(project.last_journal.details).to have_key(prop.to_s), "Missing change for #{prop}" end @@ -113,36 +113,36 @@ end end - describe "custom values", with_settings: { journal_aggregation_time_minutes: 0 } do + describe 'custom values', with_settings: { journal_aggregation_time_minutes: 0 } do shared_let(:custom_field) { create(:string_project_custom_field) } let(:custom_value) do build(:custom_value, - value: "some string value for project custom field", + value: 'some string value for project custom field', custom_field:) end let(:custom_field_id) { "custom_fields_#{custom_value.custom_field_id}" } - shared_context "for project with new custom value" do + shared_context 'for project with new custom value' do before do project.update(custom_values: [custom_value]) end end - context "for new custom value" do - include_context "for project with new custom value" + context 'for new custom value' do + include_context 'for project with new custom value' - it "contains the new custom value change" do + it 'contains the new custom value change' do expect(project.last_journal.details) .to include(custom_field_id => [nil, custom_value.value]) end end - context "for updated custom value" do - include_context "for project with new custom value" + context 'for updated custom value' do + include_context 'for project with new custom value' let(:modified_custom_value) do build(:custom_value, - value: "some modified value for project custom field", + value: 'some modified value for project custom field', custom_field:) end @@ -150,14 +150,14 @@ project.update(custom_values: [modified_custom_value]) end - it "contains the change from previous value to updated value" do + it 'contains the change from previous value to updated value' do expect(project.last_journal.details) .to include(custom_field_id => [custom_value.value, modified_custom_value.value]) end end - context "when project saved without any changes" do - include_context "for project with new custom value" + context 'when project saved without any changes' do + include_context 'for project with new custom value' let(:unmodified_custom_value) do build(:custom_value, @@ -172,25 +172,25 @@ it { expect { project.save! }.not_to change(Journal, :count) } end - context "when custom value removed" do - include_context "for project with new custom value" + context 'when custom value removed' do + include_context 'for project with new custom value' before do project.update(custom_values: []) end - it "contains the change from previous value to nil" do + it 'contains the change from previous value to nil' do expect(project.last_journal.details) .to include(custom_field_id => [custom_value.value, nil]) end end end - describe "on project deletion" do + describe 'on project deletion' do shared_let(:custom_field) { create(:string_project_custom_field) } let(:custom_value) do build(:custom_value, - value: "some string value for project custom field", + value: 'some string value for project custom field', custom_field:) end let!(:project) do @@ -205,17 +205,17 @@ project.destroy end - it "removes the journal" do + it 'removes the journal' do expect(Journal.find_by(id: journal.id)) .to be_nil end - it "removes the journal data" do + it 'removes the journal data' do expect(Journal::ProjectJournal.find_by(id: journal.data_id)) .to be_nil end - it "removes the customizable journals" do + it 'removes the customizable journals' do expect(Journal::CustomizableJournal.find_by(id: customizable_journals.map(&:id))) .to be_nil end diff --git a/spec/models/projects/reorder_nested_set_spec.rb b/spec/models/projects/reorder_nested_set_spec.rb index 685c30207a9f..2cc9108d6501 100644 --- a/spec/models/projects/reorder_nested_set_spec.rb +++ b/spec/models/projects/reorder_nested_set_spec.rb @@ -26,42 +26,42 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Project, "reordering of nested set" do +RSpec.describe Project, 'reordering of nested set' do # Create some parents in non-alphabetical order - shared_let(:parent_project_b) { create(:project, name: "ParentB") } - shared_let(:parent_project_a) { create(:project, name: "ParentA") } + shared_let(:parent_project_b) { create(:project, name: 'ParentB') } + shared_let(:parent_project_a) { create(:project, name: 'ParentA') } # Create some children in non-alphabetical order # including lower case to test case insensitivity - shared_let(:child_e) { create(:project, name: "e", parent: parent_project_a) } - shared_let(:child_c) { create(:project, name: "C", parent: parent_project_a) } - shared_let(:child_f) { create(:project, name: "F", parent: parent_project_a) } - shared_let(:child_d) { create(:project, name: "D", parent: parent_project_b) } - shared_let(:child_b) { create(:project, name: "B", parent: parent_project_b) } + shared_let(:child_e) { create(:project, name: 'e', parent: parent_project_a) } + shared_let(:child_c) { create(:project, name: 'C', parent: parent_project_a) } + shared_let(:child_f) { create(:project, name: 'F', parent: parent_project_a) } + shared_let(:child_d) { create(:project, name: 'D', parent: parent_project_b) } + shared_let(:child_b) { create(:project, name: 'B', parent: parent_project_b) } subject { described_class.all.reorder(:lft) } - it "has the correct sort" do + it 'has the correct sort' do expect(subject.reload.pluck(:name)).to eq %w[ParentA C e F ParentB B D] end - context "when renaming a child" do + context 'when renaming a child' do before do - child_b.update! name: "Z" + child_b.update! name: 'Z' end - it "updates that order" do + it 'updates that order' do expect(subject.reload.pluck(:name)).to eq %w[ParentA C e F ParentB D Z] end end - context "when adding a new first child to the parent (Regression #40930)" do - it "still resorts them" do + context 'when adding a new first child to the parent (Regression #40930)' do + it 'still resorts them' do expect(subject.reload.pluck(:name)).to eq %w[ParentA C e F ParentB B D] - described_class.create!(parent: parent_project_a, name: "A") + described_class.create!(parent: parent_project_a, name: 'A') expect(subject.reload.pluck(:name)).to eq %w[ParentA A C e F ParentB B D] end diff --git a/spec/models/projects/scopes/visible_spec.rb b/spec/models/projects/scopes/visible_spec.rb index 2f2a28ff46f1..8b25872b08f0 100644 --- a/spec/models/projects/scopes/visible_spec.rb +++ b/spec/models/projects/scopes/visible_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::Scopes::Visible do shared_let(:activity) { create(:time_entry_activity) } @@ -74,50 +74,50 @@ subject { Project.visible(current_user) } - context "for an admin user" do + context 'for an admin user' do let(:current_user) { admin_user } - it "list all projects" do + it 'list all projects' do expect(subject).to contain_exactly(shared_in_project, project, public_project) end end - context "for a user a work package is shared with and who has a memberships" do + context 'for a user a work package is shared with and who has a memberships' do let(:current_user) { shared_user } - it "list all projects" do + it 'list all projects' do expect(subject).to contain_exactly(shared_in_project, project, public_project) end end - context "for a user having only a project membership" do + context 'for a user having only a project membership' do let(:current_user) { only_project_user } - it "list only the project in which the user has the membership and the public project" do + it 'list only the project in which the user has the membership and the public project' do expect(subject).to contain_exactly(project, public_project) end end - context "for a user only having a share" do + context 'for a user only having a share' do let(:current_user) { only_shared_user } - it "list only the project in which the shared work package is and the public project" do + it 'list only the project in which the shared work package is and the public project' do expect(subject).to contain_exactly(shared_in_project, public_project) end end - context "for a user without any permission" do + context 'for a user without any permission' do let(:current_user) { no_membership_user } - it "list only the public project" do + it 'list only the public project' do expect(subject).to contain_exactly(public_project) end end - context "for an anonymous user" do + context 'for an anonymous user' do let(:current_user) { create(:anonymous) } - it "list only the public project" do + it 'list only the public project' do expect(subject).to contain_exactly(public_project) end end diff --git a/spec/models/projects/storage_spec.rb b/spec/models/projects/storage_spec.rb index 4610867d26db..95762c1048bf 100644 --- a/spec/models/projects/storage_spec.rb +++ b/spec/models/projects/storage_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::Storage do let(:project1) do @@ -36,7 +36,7 @@ let(:project2) { create(:project) } before do - allow(Setting).to receive(:enabled_scm).and_return(["git"]) + allow(Setting).to receive(:enabled_scm).and_return(['git']) wp = create(:work_package, project: project1) create(:work_package, project: project1) @@ -49,8 +49,8 @@ repo.update(required_storage_bytes: 1234) end - describe "#with_required_storage" do - it "counts projects correctly" do + describe '#with_required_storage' do + it 'counts projects correctly' do # TODO Using storage.find(project1.id) here causes work_package_required_space # to be nil or "2500" (Postgres only) occasionally with no definitive solution found. # The returned "2500" were pre-Rails4 behavior, thus this might be a Rails bug. @@ -71,18 +71,18 @@ expect(p2.required_disk_space).to eq(1234) end - it "outputs the correct total amount" do + it 'outputs the correct total amount' do expect(Project.total_projects_size).to eq(13734) end - context "with a project with all modules" do + context 'with a project with all modules' do let(:repository1) { create(:repository_git, project: project1) } before do repository1.update(required_storage_bytes: 543211234) end - it "counts all projects correctly" do + it 'counts all projects correctly' do project = Project.with_required_storage.find(project1.id) expect(project.wiki_required_space).to eq(10000) @@ -92,28 +92,28 @@ expect(project.required_disk_space).to eq(543223734) end - it "outputs the correct total amount" do + it 'outputs the correct total amount' do expect(Project.total_projects_size).to eq(543224968) end end end - describe "#count_required_storage" do - it "provides a hash of the storage information" do + describe '#count_required_storage' do + it 'provides a hash of the storage information' do storage = project1.count_required_storage - expect(storage["total"]).to eq(12500) - expect(storage["modules"].length).to eq(2) - expect(storage["modules"]["project_module_wiki"]).to eq(10000) - expect(storage["modules"]["label_work_package_plural"]).to eq(2500) + expect(storage['total']).to eq(12500) + expect(storage['modules'].length).to eq(2) + expect(storage['modules']['project_module_wiki']).to eq(10000) + expect(storage['modules']['label_work_package_plural']).to eq(2500) end - it "works with partially available information" do + it 'works with partially available information' do storage = project2.count_required_storage - expect(storage["total"]).to eq(1234) - expect(storage["modules"].length).to eq(1) - expect(storage["modules"]["label_repository"]).to eq(1234) + expect(storage['total']).to eq(1234) + expect(storage['modules'].length).to eq(1) + expect(storage['modules']['label_repository']).to eq(1234) end end end diff --git a/spec/models/queries/capabilities/capability_query_spec.rb b/spec/models/queries/capabilities/capability_query_spec.rb index 51b127c3c40e..4dc042e91991 100644 --- a/spec/models/queries/capabilities/capability_query_spec.rb +++ b/spec/models/queries/capabilities/capability_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Capabilities::CapabilityQuery do let(:instance) { described_class.new } @@ -35,87 +35,87 @@ build_stubbed(:user) end - describe "#valid?" do - context "without filters" do - it "is invalid" do + describe '#valid?' do + context 'without filters' do + it 'is invalid' do expect(instance) .not_to be_valid end end - context "with a principal filter having the `=` operator" do + context 'with a principal filter having the `=` operator' do before do - instance.where("principal_id", "=", ["1"]) + instance.where('principal_id', '=', ['1']) end - it "is valid" do + it 'is valid' do expect(instance) .to be_valid end end - context "with a principal filter having the `!` operator" do + context 'with a principal filter having the `!` operator' do before do - instance.where("principal_id", "!", ["1"]) + instance.where('principal_id', '!', ['1']) end - it "is invalid" do + it 'is invalid' do expect(instance) .not_to be_valid end end - context "with a principal filter having the `=` operator but without values" do + context 'with a principal filter having the `=` operator but without values' do before do - instance.where("principal_id", "=", []) + instance.where('principal_id', '=', []) end - it "is invalid" do + it 'is invalid' do expect(instance) .not_to be_valid end end - context "with a context filter having the `=` operator" do + context 'with a context filter having the `=` operator' do before do - instance.where("context", "=", ["p1"]) + instance.where('context', '=', ['p1']) end - it "is valid" do + it 'is valid' do expect(instance) .to be_valid end end - context "with a context filter having the `=` operator but without values" do + context 'with a context filter having the `=` operator but without values' do before do - instance.where("context", "=", []) + instance.where('context', '=', []) end - it "is invalid" do + it 'is invalid' do expect(instance) .not_to be_valid end end - context "with a context filter having the `!` operator" do + context 'with a context filter having the `!` operator' do before do - instance.where("context", "!", ["g"]) + instance.where('context', '!', ['g']) end - it "is invalid" do + it 'is invalid' do expect(instance) .not_to be_valid end end - context "with a context filter having the `!` operator and also with a principal filter having the `=` operator" do + context 'with a context filter having the `!` operator and also with a principal filter having the `=` operator' do before do - instance.where("context", "!", ["g"]) - instance.where("principal_id", "=", ["1"]) + instance.where('context', '!', ['g']) + instance.where('principal_id', '=', ['1']) end - it "is valid" do + it 'is valid' do expect(instance) .to be_valid end diff --git a/spec/models/queries/capabilities/filters/action_filter_spec.rb b/spec/models/queries/capabilities/filters/action_filter_spec.rb index 7f7ffb79bd65..72d7a0d49104 100644 --- a/spec/models/queries/capabilities/filters/action_filter_spec.rb +++ b/spec/models/queries/capabilities/filters/action_filter_spec.rb @@ -26,53 +26,53 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Capabilities::Filters::ActionFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :action } let(:type) { :string } let(:model) { Capability } let(:attribute) { :action } - let(:values) { ["memberships/create"] } + let(:values) { ['memberships/create'] } - describe "#available_operators" do - it "supports = and !" do + describe '#available_operators' do + it 'supports = and !' do expect(instance.available_operators) .to eql [Queries::Operators::Equals, Queries::Operators::NotEquals] end end - describe "#valid?" do - context "without values" do + describe '#valid?' do + context 'without values' do let(:values) { [] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end end - context "with valid value" do - it "is valid" do + context 'with valid value' do + it 'is valid' do expect(instance) .to be_valid end end - context "with multiple valid values" do + context 'with multiple valid values' do let(:values) { %w[memberships/create users/create] } - it "is valid" do + it 'is valid' do expect(instance) .to be_valid end end - context "with malfomed values" do + context 'with malfomed values' do let(:values) { ["foo/5"] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end diff --git a/spec/models/queries/capabilities/filters/context_filter_spec.rb b/spec/models/queries/capabilities/filters/context_filter_spec.rb index 139c175e53f9..0f58aa66bc2d 100644 --- a/spec/models/queries/capabilities/filters/context_filter_spec.rb +++ b/spec/models/queries/capabilities/filters/context_filter_spec.rb @@ -26,53 +26,53 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Capabilities::Filters::ContextFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :context } let(:type) { :string } let(:model) { Capability } let(:attribute) { :context } - let(:values) { ["p3"] } + let(:values) { ['p3'] } - describe "#available_operators" do - it "supports = and !" do + describe '#available_operators' do + it 'supports = and !' do expect(instance.available_operators) .to eql [Queries::Operators::Equals, Queries::Operators::NotEquals] end end - describe "#valid?" do - context "without values" do + describe '#valid?' do + context 'without values' do let(:values) { [] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end end - context "with valid value" do - it "is valid" do + context 'with valid value' do + it 'is valid' do expect(instance) .to be_valid end end - context "with multiple valid values" do - let(:values) { ["p3", "g"] } + context 'with multiple valid values' do + let(:values) { ['p3', 'g'] } - it "is valid" do + it 'is valid' do expect(instance) .to be_valid end end - context "with malfomed values" do + context 'with malfomed values' do let(:values) { ["a5"] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end diff --git a/spec/models/queries/capabilities/filters/id_filter_spec.rb b/spec/models/queries/capabilities/filters/id_filter_spec.rb index 333a51aced08..298c9d6718eb 100644 --- a/spec/models/queries/capabilities/filters/id_filter_spec.rb +++ b/spec/models/queries/capabilities/filters/id_filter_spec.rb @@ -26,53 +26,53 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Capabilities::Filters::IdFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :id } let(:type) { :string } let(:model) { Capability } let(:attribute) { :id } - let(:values) { ["memberships/create/p3-5"] } + let(:values) { ['memberships/create/p3-5'] } - describe "#available_operators" do - it "supports = and !" do + describe '#available_operators' do + it 'supports = and !' do expect(instance.available_operators) .to eql [Queries::Operators::Equals, Queries::Operators::NotEquals] end end - describe "#valid?" do - context "without values" do + describe '#valid?' do + context 'without values' do let(:values) { [] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end end - context "with valid value" do - it "is valid" do + context 'with valid value' do + it 'is valid' do expect(instance) .to be_valid end end - context "with multiple valid values" do - let(:values) { ["memberships/create/p3-5", "users/create/g-5"] } + context 'with multiple valid values' do + let(:values) { ['memberships/create/p3-5', 'users/create/g-5'] } - it "is valid" do + it 'is valid' do expect(instance) .to be_valid end end - context "with malfomed values" do + context 'with malfomed values' do let(:values) { ["foo/bar/baz-5"] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end diff --git a/spec/models/queries/capabilities/filters/principal_id_filter_spec.rb b/spec/models/queries/capabilities/filters/principal_id_filter_spec.rb index 99ff3506dc17..3159be31953c 100644 --- a/spec/models/queries/capabilities/filters/principal_id_filter_spec.rb +++ b/spec/models/queries/capabilities/filters/principal_id_filter_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Capabilities::Filters::PrincipalIdFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :principal_id } let(:type) { :integer } let(:model) { Capability } let(:attribute) { :principal_id } - let(:values) { ["5"] } + let(:values) { ['5'] } end end diff --git a/spec/models/queries/days/day_query_spec.rb b/spec/models/queries/days/day_query_spec.rb index ec29bac53995..79ff52009167 100644 --- a/spec/models/queries/days/day_query_spec.rb +++ b/spec/models/queries/days/day_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Days::DayQuery do let(:instance) { described_class.new } @@ -37,17 +37,17 @@ login_as(current_user) end - context "without a filter" do - context "as an admin" do - it "is the same as getting all days" do + context 'without a filter' do + context 'as an admin' do + it 'is the same as getting all days' do expect(instance.results.to_sql).to eql base_scope.to_sql end end - context "as a non admin" do + context 'as a non admin' do let(:current_user) { build_stubbed(:user) } - it "is the same as getting all days" do + it 'is the same as getting all days' do expect(instance.results.to_sql).to eql base_scope.to_sql end end @@ -57,14 +57,14 @@ let(:date_range) { [from.iso8601, to.iso8601] } before do - instance.where("date", "<>d", date_range) + instance.where('date', '<>d', date_range) end - shared_examples_for "dates within the default range" do |working: nil| + shared_examples_for 'dates within the default range' do |working: nil| let(:from) { Time.zone.today } let(:to) { 5.days.from_now.to_date } let(:base_scope) { Day.from_range(from:, to:).reorder(date: :asc) } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do # Expectation has to be weirdly specific to the logic of Queries::Operators::DateRangeClauses expected_scope = base_scope.where("days.date > ? AND days.date <= ?", (from - 1.day).end_of_day, @@ -78,43 +78,43 @@ end end - shared_examples_for "dates out of the default range" do + shared_examples_for 'dates out of the default range' do let(:from) { 5.days.from_now.to_date } let(:to) { 153.days.from_now.to_date } - it "returns all the days" do + it 'returns all the days' do expect(instance.results.size).to eq 149 end - context "with dates missing the to date" do + context 'with dates missing the to date' do let(:date_range) { [from.iso8601, ""] } - it "returns days until the end of next month" do + it 'returns days until the end of next month' do expected_size = (from.next_month.at_end_of_month - from).to_i + 1 expect(instance.results.size).to be expected_size end end - context "with dates missing the from date" do + context 'with dates missing the from date' do let(:date_range) { ["", to.iso8601] } - it "returns days from the beginning of the month" do + it 'returns days from the beginning of the month' do expected_size = (to - to.at_beginning_of_month).to_i + 1 expect(instance.results.size).to be expected_size end end end - include_examples "dates within the default range" - include_examples "dates out of the default range" + include_examples 'dates within the default range' + include_examples 'dates out of the default range' - context "when having a working filter too" do + context 'when having a working filter too' do before do - instance.where("working", "=", "t") + instance.where('working', '=', 't') end - include_examples "dates within the default range", working: "t" - include_examples "dates out of the default range" + include_examples 'dates within the default range', working: 't' + include_examples 'dates out of the default range' end end end diff --git a/spec/models/queries/days/filters/dates_interval_filter_spec.rb b/spec/models/queries/days/filters/dates_interval_filter_spec.rb index 6e60dd00dfc6..76ddd495586b 100644 --- a/spec/models/queries/days/filters/dates_interval_filter_spec.rb +++ b/spec/models/queries/days/filters/dates_interval_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Days::Filters::DatesIntervalFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :date } let(:class_key) { :date } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/days/filters/working_filter_spec.rb b/spec/models/queries/days/filters/working_filter_spec.rb index fe86efc44884..8d4f1df5ef02 100644 --- a/spec/models/queries/days/filters/working_filter_spec.rb +++ b/spec/models/queries/days/filters/working_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Days::Filters::WorkingFilter do - it_behaves_like "boolean query filter" do + it_behaves_like 'boolean query filter' do let(:model) { Day } let(:attribute) { :working } end diff --git a/spec/models/queries/filters/available_filters_spec.rb b/spec/models/queries/filters/available_filters_spec.rb index a8a1ebe620ad..0b60b893d042 100644 --- a/spec/models/queries/filters/available_filters_spec.rb +++ b/spec/models/queries/filters/available_filters_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Filters::AvailableFilters do let(:context) { build_stubbed(:project) } @@ -50,7 +50,7 @@ def initialize(context) includer end - describe "#filter_for" do + describe '#filter_for' do let(:registered_filters) { [filter1, filter2] } let(:filter1_available) { true } @@ -84,27 +84,27 @@ def initialize(context) all_for: filter2_instance) end - context "for a filter identified by a symbol" do + context 'for a filter identified by a symbol' do let(:registered_filters) { [filter1, filter2] } - context "if available" do - it "returns an instance of the matching filter" do + context 'if available' do + it 'returns an instance of the matching filter' do expect(includer.filter_for(:filter1)).to eql filter1_instance end - it "returns the NotExistingFilter if the name is not matched" do + it 'returns the NotExistingFilter if the name is not matched' do expect(includer.filter_for(:not_a_filter_name)).to be_a Queries::Filters::NotExistingFilter end end - context "if not available" do + context 'if not available' do let(:filter1_available) { false } - it "returns the NotExistingFilter if the name is not matched" do + it 'returns the NotExistingFilter if the name is not matched' do expect(includer.filter_for(:not_a_filter_name)).to be_a Queries::Filters::NotExistingFilter end - it "is ignored and returns the filter if the name is matched" do + it 'is ignored and returns the filter if the name is matched' do expect(includer.filter_for(:filter1)).to eq(filter1_instance) expect(includer.filter_for(:filter1, no_memoization: true)).to eq(filter1_instance) expect(includer.filter_for(:filter1, no_memoization: false)).to eq(filter1_instance) @@ -112,25 +112,25 @@ def initialize(context) end end - context "for a filter identified by a regexp" do - context "if available" do - it "returns an instance of the matching filter" do + context 'for a filter identified by a regexp' do + context 'if available' do + it 'returns an instance of the matching filter' do expect(includer.filter_for(:f2)).to eq(filter2_instance) end - it "returns the NotExistingFilter if the key is not matched" do + it 'returns the NotExistingFilter if the key is not matched' do expect(includer.filter_for(:fi1)).to be_a Queries::Filters::NotExistingFilter end - it "returns the NotExistingFilter if the key is matched but the name is not" do + it 'returns the NotExistingFilter if the key is matched but the name is not' do expect(includer.filter_for(:f42)).to be_a Queries::Filters::NotExistingFilter end end - context "if unavailable" do + context 'if unavailable' do let(:filter2_available) { false } - it "is ignored and returns the matching filter" do + it 'is ignored and returns the matching filter' do expect(includer.filter_for(:f2)).to eq(filter2_instance) end end diff --git a/spec/models/queries/filters/base_spec.rb b/spec/models/queries/filters/base_spec.rb index 4696e1e1e498..cd00ecde7262 100644 --- a/spec/models/queries/filters/base_spec.rb +++ b/spec/models/queries/filters/base_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Filters::Base do let(:integer_filter) do @@ -71,45 +71,45 @@ def self.name filter_class.create! name: :test_datetime end - shared_examples_for "validity checked" do - describe "#valid?" do - context "when the operator does not require values" do + shared_examples_for 'validity checked' do + describe '#valid?' do + context 'when the operator does not require values' do before do filter.operator = operator_without_value end - it "is valid if no values are given" do + it 'is valid if no values are given' do expect(filter).to be_valid end end - context "when the operator requires values" do + context 'when the operator requires values' do before do filter.operator = valid_operator end - context "and no value is given" do - it "is invalid" do + context 'and no value is given' do + it 'is invalid' do expect(filter).to be_invalid end end - context "and only an empty string is given as value" do + context 'and only an empty string is given as value' do before do - filter.values = [""] + filter.values = [''] end - it "is invalid" do + it 'is invalid' do expect(filter).to be_invalid end end - context "and values are given" do + context 'and values are given' do before do filter.values = valid_values end - it "is valid" do + it 'is valid' do expect(filter).to be_valid end end @@ -117,49 +117,49 @@ def self.name end end - shared_examples_for "date validity checked" do - describe "#valid?" do + shared_examples_for 'date validity checked' do + describe '#valid?' do context "and the operator is 't' (today)" do before do - filter.operator = "t" + filter.operator = 't' end - it "is valid" do + it 'is valid' do expect(filter).to be_valid end end context "and the operator is 'w' (this week)" do before do - filter.operator = "w" + filter.operator = 'w' end - it "is valid" do + it 'is valid' do expect(filter).to be_valid end end - context "and the operator compares the current day" do + context 'and the operator compares the current day' do before do - filter.operator = ">t-" + filter.operator = '>t-' end - context "and the value is an integer" do + context 'and the value is an integer' do before do - filter.values = ["4"] + filter.values = ['4'] end - it "is valid" do + it 'is valid' do expect(filter).to be_valid end end - context "and the value is not an integer" do + context 'and the value is not an integer' do before do - filter.values = ["four"] + filter.values = ['four'] end - it "is invalid" do + it 'is invalid' do expect(filter).to be_invalid end end @@ -167,45 +167,45 @@ def self.name end end - context "for an integer filter" do + context 'for an integer filter' do let(:filter) { integer_filter } let(:valid_values) { [5] } - let(:valid_operator) { "=" } - let(:operator_without_value) { "*" } + let(:valid_operator) { '=' } + let(:operator_without_value) { '*' } - it_behaves_like "validity checked" + it_behaves_like 'validity checked' - describe "#valid?" do - context "when the filter values is not an integer" do + describe '#valid?' do + context 'when the filter values is not an integer' do before do - filter.operator = "=" - filter.values == [1, "asdf"] + filter.operator = '=' + filter.values == [1, 'asdf'] end - it "is invalid" do + it 'is invalid' do expect(filter).to be_invalid end end end end - context "for a date filter" do + context 'for a date filter' do let(:filter) { date_filter } let(:valid_values) { [5] } - let(:valid_operator) { " role }, members: [user]) } - let!(:group2) { create(:group, name: "B", member_with_roles: { project => role }, members: [user]) } + let!(:group1) { create(:group, name: 'A', member_with_roles: { project => role }, members: [user]) } + let!(:group2) { create(:group, name: 'B', member_with_roles: { project => role }, members: [user]) } - it "only returns one user when filtering for one group (Regression #45331)" do - instance.where "project_id", "=", [project.id.to_s] - instance.where "group", "=", [group1.id.to_s] + it 'only returns one user when filtering for one group (Regression #45331)' do + instance.where 'project_id', '=', [project.id.to_s] + instance.where 'group', '=', [group1.id.to_s] expect(subject.count).to eq 1 expect(subject.first.user_id).to eq user.id end end - context "with a project and a work package membership" do + context 'with a project and a work package membership' do let(:project) { create(:project) } let(:work_package) { create(:work_package, project:) } let(:user) { create(:user) } @@ -60,7 +60,7 @@ let!(:project_membership) { create(:member, principal: user, project:, roles: [role]) } let!(:wp_membership) { create(:member, principal: user, project:, entity: work_package, roles: [wp_role]) } - it "returns both, the project membership and the workPackage membership" do + it 'returns both, the project membership and the workPackage membership' do expect(subject.count).to eq(2) expect(subject.first).to have_attributes( project:, diff --git a/spec/models/queries/news/filters/project_filter_spec.rb b/spec/models/queries/news/filters/project_filter_spec.rb index a4406f25bd60..41dccceadfec 100644 --- a/spec/models/queries/news/filters/project_filter_spec.rb +++ b/spec/models/queries/news/filters/project_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::News::Filters::ProjectFilter do let(:project1) { build_stubbed(:project) } @@ -39,13 +39,13 @@ .and_return([project1.id, project2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :project_id } let(:type) { :list_optional } let(:name) { News.human_attribute_name(:project) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[project1.id, project1.id.to_s], [project2.id, project2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :project_id } let(:model) { News } let(:valid_values) { [project1.id.to_s] } diff --git a/spec/models/queries/news/news_query_spec.rb b/spec/models/queries/news/news_query_spec.rb index cb1b72db6757..3e9276f8f7c8 100644 --- a/spec/models/queries/news/news_query_spec.rb +++ b/spec/models/queries/news/news_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::News::NewsQuery do let(:user) { build_stubbed(:user) } @@ -37,47 +37,47 @@ login_as(user) end - context "without a filter" do - describe "#results" do - it "is the same as getting all the visible news" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the visible news' do expect(instance.results.to_sql).to eql base_scope.to_sql end end end - context "with a project filter" do + context 'with a project filter' do before do allow(Project) .to receive_message_chain(:visible, :pluck) .with(:id) .and_return([1]) - instance.where("project_id", "=", ["1"]) + instance.where('project_id', '=', ['1']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope - .where(["news.project_id IN (?)", ["1"]]) + .where(["news.project_id IN (?)", ['1']]) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("project_id", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('project_id', '=', ['']) expect(instance).to be_invalid end end end - context "with an order by id asc" do - describe "#results" do - it "returns all visible news ordered by id asc" do + context 'with an order by id asc' do + describe '#results' do + it 'returns all visible news ordered by id asc' do expect(instance.order(id: :asc).results.to_sql) .to eql base_scope.except(:order).order(id: :asc).to_sql end diff --git a/spec/models/queries/non_working_days/filters/dates_interval_filter_spec.rb b/spec/models/queries/non_working_days/filters/dates_interval_filter_spec.rb index aa9038df0eec..394932b77bbe 100644 --- a/spec/models/queries/non_working_days/filters/dates_interval_filter_spec.rb +++ b/spec/models/queries/non_working_days/filters/dates_interval_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::NonWorkingDays::Filters::DatesIntervalFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :date } let(:class_key) { :date } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/non_working_days/non_working_day_query_spec.rb b/spec/models/queries/non_working_days/non_working_day_query_spec.rb index 21e9c36578ca..9b00b31fbdb8 100644 --- a/spec/models/queries/non_working_days/non_working_day_query_spec.rb +++ b/spec/models/queries/non_working_days/non_working_day_query_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/work_packages/shared/shared_examples_days" +require 'spec_helper' +require 'services/work_packages/shared/shared_examples_days' RSpec.describe Queries::NonWorkingDays::NonWorkingDayQuery do shared_let(:first_of_may) { create(:non_working_day, date: Date.new(Date.current.year, 5, 1)) } @@ -57,12 +57,12 @@ end end - context "without a filter" do - context "as an admin" do + context 'without a filter' do + context 'as an admin' do include_examples "returns this year's non working days" end - context "as a non admin" do + context 'as a non admin' do let(:current_user) { build_stubbed(:user) } include_examples "returns this year's non working days" @@ -73,39 +73,39 @@ let(:date_range) { [from.iso8601, to.iso8601] } before do - instance.where("date", "<>d", date_range) + instance.where('date', '<>d', date_range) end - context "with dates from this year" do + context 'with dates from this year' do let(:from) { Date.new(Date.current.year, 12, 1) } let(:to) { from.end_of_year } - it "returns days from the December" do + it 'returns days from the December' do expect(instance.results).to eq [christmas] end - context "with dates missing the to date" do + context 'with dates missing the to date' do let(:date_range) { [from.iso8601, ""] } - it "returns days from December until the end of year" do + it 'returns days from December until the end of year' do expect(instance.results).to eq [christmas] end end - context "with dates missing the from date" do + context 'with dates missing the from date' do let(:date_range) { ["", from.iso8601] } - it "returns days from the beginning of the year until December" do + it 'returns days from the beginning of the year until December' do expect(instance.results).to eq [first_of_may] end end end - context "with dates from multiple years" do + context 'with dates from multiple years' do let(:from) { Date.current.beginning_of_year } let(:to) { Date.current.next_year.end_of_year } - it "returns days from this year and next year" do + it 'returns days from this year and next year' do expect(instance.results).to eq [first_of_may, christmas, new_year_day] end end diff --git a/spec/models/queries/notifications/filters/id_filter_spec.rb b/spec/models/queries/notifications/filters/id_filter_spec.rb index a6e5763341ed..b5dc9a42b8e0 100644 --- a/spec/models/queries/notifications/filters/id_filter_spec.rb +++ b/spec/models/queries/notifications/filters/id_filter_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Notifications::Filters::IdFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :id } let(:type) { :list } let(:model) { Notification } let(:attribute) { :id } - let(:values) { ["5"] } + let(:values) { ['5'] } end end diff --git a/spec/models/queries/notifications/filters/read_ian_filter_spec.rb b/spec/models/queries/notifications/filters/read_ian_filter_spec.rb index 5b8284520b1c..288b605e3c37 100644 --- a/spec/models/queries/notifications/filters/read_ian_filter_spec.rb +++ b/spec/models/queries/notifications/filters/read_ian_filter_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Notifications::Filters::ReadIanFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :read_ian } - describe "#available_operators" do - it "supports = and !" do + describe '#available_operators' do + it 'supports = and !' do expect(instance.available_operators) .to eql [Queries::Operators::BooleanEqualsStrict, Queries::Operators::BooleanNotEquals] end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/notifications/filters/reason_filter_spec.rb b/spec/models/queries/notifications/filters/reason_filter_spec.rb index e9d7ea0c5e8f..f12e87167fa5 100644 --- a/spec/models/queries/notifications/filters/reason_filter_spec.rb +++ b/spec/models/queries/notifications/filters/reason_filter_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Notifications::Filters::ReasonFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :reason } let(:type) { :list } let(:model) { Notification } let(:attribute) { :reason } - let(:values) { ["mentioned"] } + let(:values) { ['mentioned'] } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' - describe "#allowed_values" do - context "with enterprise", with_ee: %i[date_alerts] do - it "contains all the REASONS" do + describe '#allowed_values' do + context 'with enterprise', with_ee: %i[date_alerts] do + it 'contains all the REASONS' do expect(instance.allowed_values).to eq(described_class::REASONS.keys.map { |r| [r, r] }) end end - context "without enterprise", with_ee: false do - it "does not contains date alerts" do + context 'without enterprise', with_ee: false do + it 'does not contains date alerts' do expect(instance.allowed_values) .to eq(described_class::REASONS.keys.without("dateAlert").map { |r| [r, r] }) end diff --git a/spec/models/queries/notifications/notification_query_spec.rb b/spec/models/queries/notifications/notification_query_spec.rb index 9e6248679219..375518ad8583 100644 --- a/spec/models/queries/notifications/notification_query_spec.rb +++ b/spec/models/queries/notifications/notification_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Notifications::NotificationQuery do shared_let(:project) { create(:project) } @@ -41,58 +41,58 @@ current_user { recipient } - context "without a filter" do - describe "#results" do - it "is the same as getting all the users" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the users' do expect(instance.results.to_sql).to eql base_scope.order(id: :desc).to_sql end end end - context "with a read_ian filter" do + context 'with a read_ian filter' do before do - instance.where("read_ian", "=", ["t"]) + instance.where('read_ian', '=', ['t']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope.merge(Notification.where("notifications.read_ian IN ('t')").order(id: :desc)).to_sql expect(instance.results.to_sql).to eql expected end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("read_ian", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('read_ian', '=', ['']) expect(instance).to be_invalid end end end - context "with a non existent filter" do + context 'with a non existent filter' do before do - instance.where("not_supposed_to_exist", "=", ["bogus"]) + instance.where('not_supposed_to_exist', '=', ['bogus']) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = Notification.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end - it "returns the error on the filter" do + it 'returns the error on the filter' do instance.valid? expect(instance.errors[:filters]).to eql ["Not supposed to exist filter does not exist."] @@ -100,13 +100,13 @@ end end - context "with an id sortation" do + context 'with an id sortation' do before do instance.order(id: :asc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope.merge(Notification.order(id: :asc)) expect(instance.results.to_sql).to eql expected.to_sql @@ -114,13 +114,13 @@ end end - context "with a read_ian sortation" do + context 'with a read_ian sortation' do before do instance.order(read_ian: :desc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope.merge(Notification.order(read_ian: :desc, id: :desc)).to_sql expect(instance.results.to_sql).to eql expected @@ -128,13 +128,13 @@ end end - context "with a reason sortation" do + context 'with a reason sortation' do before do instance.order(reason: :desc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope.merge(Notification.order(reason: :desc, id: :desc)).to_sql expect(instance.results.to_sql).to eql expected @@ -142,37 +142,37 @@ end end - context "with a non existing sortation" do + context 'with a non existing sortation' do before do instance.order(non_existing: :desc) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = Notification.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end end end - context "with a reason group_by" do + context 'with a reason group_by' do before do instance.group(:reason) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do scope = Notification .group(:reason) .order(reason: :asc) - .select(:reason, Arel.sql("COUNT(*)")) + .select(:reason, Arel.sql('COUNT(*)')) expected = base_scope.merge(scope).to_sql expect(instance.groups.to_sql).to eql expected @@ -180,17 +180,17 @@ end end - context "with a project group_by" do + context 'with a project group_by' do before do instance.group(:project) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do scope = Notification .group(:project_id) .order(project_id: :asc) - .select(:project_id, Arel.sql("COUNT(*)")) + .select(:project_id, Arel.sql('COUNT(*)')) expected = base_scope.merge(scope).to_sql expect(instance.groups.to_sql).to eql expected @@ -198,21 +198,21 @@ end end - context "with a non existing group_by" do + context 'with a non existing group_by' do before do instance.group(:does_not_exist) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = Notification.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end end diff --git a/spec/models/queries/placeholder_users/placeholder_user_query_spec.rb b/spec/models/queries/placeholder_users/placeholder_user_query_spec.rb index 7203128d65fc..8ad381e3e892 100644 --- a/spec/models/queries/placeholder_users/placeholder_user_query_spec.rb +++ b/spec/models/queries/placeholder_users/placeholder_user_query_spec.rb @@ -26,49 +26,49 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::PlaceholderUsers::PlaceholderUserQuery do let(:instance) { described_class.new } let(:base_scope) { PlaceholderUser.order(id: :desc) } - context "without a filter" do - describe "#results" do - it "is the same as getting all the users" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the users' do expect(instance.results.to_sql).to eql base_scope.to_sql end end end - context "with a name filter" do + context 'with a name filter' do before do - instance.where("name", "~", ["a user"]) + instance.where('name', '~', ['a user']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope .merge(PlaceholderUser - .where(["unaccent(LOWER(CONCAT(users.firstname, ' ', users.lastname))) LIKE unaccent(?)", + .where(["LOWER(CONCAT(users.firstname, CONCAT(' ', users.lastname))) LIKE ?", "%a user%"])) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("name", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('name', '=', ['']) expect(instance).to be_invalid end end end - context "with a group filter" do + context 'with a group filter' do let(:group_1) { build_stubbed(:group) } before do @@ -80,11 +80,11 @@ .to receive(:all) .and_return([group_1]) - instance.where("group", "=", [group_1.id]) + instance.where('group', '=', [group_1.id]) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope .merge(PlaceholderUser .where(["users.id IN (#{PlaceholderUser.in_group([group_1.id.to_s]).select(:id).to_sql})"])) @@ -93,37 +93,37 @@ end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("group", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('group', '=', ['']) expect(instance).to be_invalid end end end - context "with a non existent filter" do + context 'with a non existent filter' do before do - instance.where("not_supposed_to_exist", "=", ["bogus"]) + instance.where('not_supposed_to_exist', '=', ['bogus']) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = PlaceholderUser.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end - it "returns the error on the filter" do + it 'returns the error on the filter' do instance.valid? expect(instance.errors[:filters]).to eql ["Not supposed to exist filter does not exist."] @@ -131,13 +131,13 @@ end end - context "with an id sortation" do + context 'with an id sortation' do before do instance.order(id: :asc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = PlaceholderUser.merge(PlaceholderUser.order(id: :asc)) expect(instance.results.to_sql).to eql expected.to_sql @@ -145,13 +145,13 @@ end end - context "with a name sortation" do + context 'with a name sortation' do before do instance.order(name: :desc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"type\" = 'PlaceholderUser' ORDER BY \"users\".\"lastname\" DESC, \"users\".\"id\" DESC" expect(instance.results.to_sql).to eql expected @@ -159,13 +159,13 @@ end end - context "with a group sortation" do + context 'with a group sortation' do before do instance.order(group: :desc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = PlaceholderUser.merge(PlaceholderUser.joins(:groups).order("groups_users.lastname DESC")).order(id: :desc) expect(instance.results.to_sql).to eql expected.to_sql @@ -173,22 +173,22 @@ end end - context "with a non existing sortation" do + context 'with a non existing sortation' do # this is a field protected from sortation before do instance.order(password: :desc) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = PlaceholderUser.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end end diff --git a/spec/models/queries/principals/filters/mentionable_on_work_package_filter_spec.rb b/spec/models/queries/principals/filters/mentionable_on_work_package_filter_spec.rb index d2b8c5b1c653..8773a0274c70 100644 --- a/spec/models/queries/principals/filters/mentionable_on_work_package_filter_spec.rb +++ b/spec/models/queries/principals/filters/mentionable_on_work_package_filter_spec.rb @@ -28,14 +28,14 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Principals::Filters::MentionableOnWorkPackageFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :mentionable_on_work_package } let(:type) { :list_optional } - describe "#scope" do + describe '#scope' do subject { instance.scope } shared_let(:project) { create(:project) } @@ -67,10 +67,10 @@ .and_return(user) end - context "with an = operator" do - let(:operator) { "=" } + context 'with an = operator' do + let(:operator) { '=' } - it "returns all mentionable principals on the work package and its project" do + it 'returns all mentionable principals on the work package and its project' do expect(subject) .to contain_exactly(user, mentionable_shared_with_user, @@ -78,10 +78,10 @@ end end - context "with a ! operator" do - let(:operator) { "!" } + context 'with a ! operator' do + let(:operator) { '!' } - it "returns all non-mentionable users on the work package and its project" do + it 'returns all non-mentionable users on the work package and its project' do expect(subject) .to contain_exactly(non_mentionable_shared_with_user) end diff --git a/spec/models/queries/principals/principal_query_integrations_spec.rb b/spec/models/queries/principals/principal_query_integrations_spec.rb index f7804032c89e..efdcabf81c06 100644 --- a/spec/models/queries/principals/principal_query_integrations_spec.rb +++ b/spec/models/queries/principals/principal_query_integrations_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Queries::Principals::PrincipalQuery, "integration" do +RSpec.describe Queries::Principals::PrincipalQuery, 'integration' do let(:current_user) { create(:user) } let(:instance) { described_class.new } let!(:non_member_role) { create(:non_member) } @@ -37,7 +37,7 @@ login_as(current_user) end - context "with a member filter" do + context 'with a member filter' do let(:project) { create(:project, public: true) } let(:role) { create(:project_role) } let(:project_user) do @@ -62,23 +62,23 @@ users end - context "with the = operator" do + context 'with the = operator' do before do - instance.where("member", "=", [project.id.to_s]) + instance.where('member', '=', [project.id.to_s]) end - it "returns all principals being member" do + it 'returns all principals being member' do expect(instance.results) .to contain_exactly(project_user) end end - context "with the ! operator" do + context 'with the ! operator' do before do - instance.where("member", "!", [project.id.to_s]) + instance.where('member', '!', [project.id.to_s]) end - it "returns all principals not being member" do + it 'returns all principals not being member' do expect(instance.results) .to contain_exactly(current_user, other_project_user) end diff --git a/spec/models/queries/projects/factory_spec.rb b/spec/models/queries/projects/factory_spec.rb index bea1ddad631a..58b1a159d1fe 100644 --- a/spec/models/queries/projects/factory_spec.rb +++ b/spec/models/queries/projects/factory_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Queries::Projects::Factory, with_settings: { enabled_projects_columns: %w[name project_status] } do let!(:query_finder) do @@ -46,7 +46,7 @@ let(:persisted_query) do build_stubbed(:project_query) do |query| query.order(id: :asc) - query.where(:project_status, "=", [Project.status_codes[:on_track].to_s]) + query.where(:project_status, '=', [Project.status_codes[:on_track].to_s]) query.select(:project_status, :name, :created_at) end end @@ -56,385 +56,385 @@ current_user { build_stubbed(:user) } - describe ".find" do + describe '.find' do subject(:find) { described_class.find(id, params:, user: current_user) } - context "without id" do - it "returns a project query" do + context 'without id' do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.active")) + .to eql(I18n.t('projects.lists.active')) end - it "has a filter for active projects" do + it 'has a filter for active projects' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["t"]]]) + .to eq([[:active, '=', ['t']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "without id and with ee and admin privileges", + context 'without id and with ee and admin privileges', with_ee: %i[custom_fields_in_projects_list], with_settings: { enabled_projects_columns: %w[name created_at cf_1] } do current_user { build_stubbed(:admin) } - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'active' id" do - let(:id) { "active" } + context 'with the \'active\' id' do + let(:id) { 'active' } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.active")) + .to eql(I18n.t('projects.lists.active')) end - it "has a filter for active projects" do + it 'has a filter for active projects' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["t"]]]) + .to eq([[:active, '=', ['t']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'my' id" do - let(:id) { "my" } + context 'with the \'my\' id' do + let(:id) { 'my' } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.my")) + .to eql(I18n.t('projects.lists.my')) end - it "has a filter for projects the user is a member of" do + it 'has a filter for projects the user is a member of' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:member_of, "=", ["t"]]]) + .to eq([[:member_of, '=', ['t']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'archived' id" do - let(:id) { "archived" } + context 'with the \'archived\' id' do + let(:id) { 'archived' } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.archived")) + .to eql(I18n.t('projects.lists.archived')) end - it "has a filter for archived projects" do + it 'has a filter for archived projects' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["f"]]]) + .to eq([[:active, '=', ['f']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'on_track' id" do - let(:id) { "on_track" } + context 'with the \'on_track\' id' do + let(:id) { 'on_track' } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("activerecord.attributes.project.status_codes.on_track")) + .to eql(I18n.t('activerecord.attributes.project.status_codes.on_track')) end it 'has a filter for projects that are "on track"' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:project_status_code, "=", [Project.status_codes[:on_track].to_s]]]) + .to eq([[:project_status_code, '=', [Project.status_codes[:on_track].to_s]]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'off_track' id" do - let(:id) { "off_track" } + context 'with the \'off_track\' id' do + let(:id) { 'off_track' } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("activerecord.attributes.project.status_codes.off_track")) + .to eql(I18n.t('activerecord.attributes.project.status_codes.off_track')) end it 'has a filter for projects that are "off track"' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:project_status_code, "=", [Project.status_codes[:off_track].to_s]]]) + .to eq([[:project_status_code, '=', [Project.status_codes[:off_track].to_s]]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'at_risk' id" do - let(:id) { "at_risk" } + context 'with the \'at_risk\' id' do + let(:id) { 'at_risk' } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("activerecord.attributes.project.status_codes.at_risk")) + .to eql(I18n.t('activerecord.attributes.project.status_codes.at_risk')) end it 'has a filter for projects that are "at risk"' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:project_status_code, "=", [Project.status_codes[:at_risk].to_s]]]) + .to eq([[:project_status_code, '=', [Project.status_codes[:at_risk].to_s]]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with an integer id for which the user has a query" do + context 'with an integer id for which the user has a query' do let(:id) { 42 } - it "returns the persisted query" do + it 'returns the persisted query' do expect(find) .to eql(persisted_query) end end - context "with an integer id for which the user does not have a persisted query" do + context 'with an integer id for which the user does not have a persisted query' do let(:id) { 42 } let(:persisted_query) { nil } - it "returns nil" do + it 'returns nil' do expect(find) .to be_nil end end - context "without an id and with params" do + context 'without an id and with params' do let(:id) { nil } let(:params) do { filters: [ { - attribute: "active", - operator: "=", - values: ["f"] + attribute: 'active', + operator: '=', + values: ['f'] }, { - attribute: "member_of", - operator: "=", - values: ["t"] + attribute: 'member_of', + operator: '=', + values: ['t'] } ], orders: [ { - attribute: "id", - direction: "asc" + attribute: 'id', + direction: 'asc' }, { - attribute: "name", - direction: "desc" + attribute: 'name', + direction: 'desc' } ], selects: %w[created_at name] } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has no name" do + it 'has no name' do expect(find.name) .to be_nil end - it "has the filters applied" do + it 'has the filters applied' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["f"]], [:member_of, "=", ["t"]]]) + .to eq([[:active, '=', ['f']], [:member_of, '=', ['t']]]) end - it "has the orders applied" do + it 'has the orders applied' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["id", :asc], ["name", :desc]]) + .to eq([['id', :asc], ['name', :desc]]) end - it "has the selects" do + it 'has the selects' do expect(find.selects.map(&:attribute)) .to eq(%i[created_at name]) end end - context "with the 'active' id and with order params" do - let(:id) { "active" } + context 'with the \'active\' id and with order params' do + let(:id) { 'active' } let(:params) do { orders: [ { - attribute: "id", - direction: "asc" + attribute: 'id', + direction: 'asc' }, { - attribute: "name", - direction: "desc" + attribute: 'name', + direction: 'desc' } ] } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has no name" do + it 'has no name' do expect(find.name) .to be_nil end - it "has the filters of the default 'active' query applied" do + it 'has the filters of the default \'active\' query applied' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["t"]]]) + .to eq([[:active, '=', ['t']]]) end - it "has the orders overwritten" do + it 'has the orders overwritten' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["id", :asc], ["name", :desc]]) + .to eq([['id', :asc], ['name', :desc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'active' id and with filter params" do + context 'with the \'active\' id and with filter params' do let(:id) { nil } let(:params) do { filters: [ { - attribute: "active", - operator: "=", - values: ["f"] + attribute: 'active', + operator: '=', + values: ['f'] }, { - attribute: "member_of", - operator: "=", - values: ["t"] + attribute: 'member_of', + operator: '=', + values: ['t'] } ] } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has no name" do + it 'has no name' do expect(find.name) .to be_nil end - it "has the filters overwritten" do + it 'has the filters overwritten' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["f"]], [:member_of, "=", ["t"]]]) + .to eq([[:active, '=', ['f']], [:member_of, '=', ['t']]]) end - it "has the orders of the default 'active' query applied" do + it 'has the orders of the default \'active\' query applied' do expect(find.orders.map { |order| [order.attribute, order.direction] }) .to eq([%i[lft asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - context "with the 'active' id and with select params" do + context 'with the \'active\' id and with select params' do let(:id) { nil } let(:params) do { @@ -442,121 +442,121 @@ } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has no name" do + it 'has no name' do expect(find.name) .to be_nil end - it "has the filters of the default 'active' query applied" do + it 'has the filters of the default \'active\' query applied' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["t"]]]) + .to eq([[:active, '=', ['t']]]) end - it "has the orders of the default 'active' query applied" do + it 'has the orders of the default \'active\' query applied' do expect(find.orders.map { |order| [order.attribute, order.direction] }) .to eq([%i[lft asc]]) end - it "has the selects overwritten" do + it 'has the selects overwritten' do expect(find.selects.map(&:attribute)) .to eq(%i[created_at project_status]) end end - context "with an integer id for which the user has a query and with filter params" do + context 'with an integer id for which the user has a query and with filter params' do let(:id) { 42 } let(:params) do { filters: [ { - attribute: "active", - operator: "=", - values: ["f"] + attribute: 'active', + operator: '=', + values: ['f'] }, { - attribute: "member_of", - operator: "=", - values: ["t"] + attribute: 'member_of', + operator: '=', + values: ['t'] } ] } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "keeps the name" do + it 'keeps the name' do expect(find.name) .to eql(persisted_query.name) end - it "has the filters overwritten" do + it 'has the filters overwritten' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["f"]], [:member_of, "=", ["t"]]]) + .to eq([[:active, '=', ['f']], [:member_of, '=', ['t']]]) end - it "has the orders of the persisted query" do + it 'has the orders of the persisted query' do expect(find.orders.map { |order| [order.attribute, order.direction] }) .to eq(persisted_query.orders.map { |order| [order.attribute, order.direction] }) end - it "has the selects of the persisted query" do + it 'has the selects of the persisted query' do expect(find.selects.map(&:attribute)) .to eq(persisted_query.selects.map(&:attribute)) end end - context "with an integer id for which the user has a query and with order params" do + context 'with an integer id for which the user has a query and with order params' do let(:id) { 42 } let(:params) do { orders: [ { - attribute: "id", - direction: "asc" + attribute: 'id', + direction: 'asc' }, { - attribute: "name", - direction: "desc" + attribute: 'name', + direction: 'desc' } ] } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "keeps the name" do + it 'keeps the name' do expect(find.name) .to eql(persisted_query.name) end - it "has the filters of the persisted query" do + it 'has the filters of the persisted query' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) .to eq(persisted_query.filters.map { |filter| [filter.field, filter.operator, filter.values] }) end - it "has the orders overwritten" do + it 'has the orders overwritten' do expect(find.orders.map { |order| [order.attribute, order.direction] }) .to eq [["id", :asc], ["name", :desc]] end - it "has the selects of the persisted query" do + it 'has the selects of the persisted query' do expect(find.selects.map(&:attribute)) .to eq(persisted_query.selects.map(&:attribute)) end end - context "with an integer id for which the user has a query and with select params" do + context 'with an integer id for which the user has a query and with select params' do let(:id) { 42 } let(:params) do { @@ -564,238 +564,238 @@ } end - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "keeps the name" do + it 'keeps the name' do expect(find.name) .to eql(persisted_query.name) end - it "has the filters of the persisted query" do + it 'has the filters of the persisted query' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) .to eq(persisted_query.filters.map { |filter| [filter.field, filter.operator, filter.values] }) end - it "has the orders of the persisted query" do + it 'has the orders of the persisted query' do expect(find.orders.map { |order| [order.attribute, order.direction] }) .to eq(persisted_query.orders.map { |order| [order.attribute, order.direction] }) end - it "has the selects specified by the params" do + it 'has the selects specified by the params' do expect(find.selects.map(&:attribute)) .to eq(%i[created_at project_status]) end end - context "with an integer id for which the user does not have a query and with params" do + context 'with an integer id for which the user does not have a query and with params' do let(:id) { 42 } let(:persisted_query) { nil } let(:params) do { filters: [ { - attribute: "active", - operator: "=", - values: ["f"] + attribute: 'active', + operator: '=', + values: ['f'] }, { - attribute: "member_of", - operator: "=", - values: ["t"] + attribute: 'member_of', + operator: '=', + values: ['t'] } ], orders: [ { - attribute: "id", - direction: "asc" + attribute: 'id', + direction: 'asc' }, { - attribute: "name", - direction: "desc" + attribute: 'name', + direction: 'desc' } ] } end - it "returns nil" do + it 'returns nil' do expect(find) .to be_nil end end end - describe ".static_query_active" do + describe '.static_query_active' do subject(:find) { described_class.static_query_active } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.active")) + .to eql(I18n.t('projects.lists.active')) end - it "has a filter for active projects" do + it 'has a filter for active projects' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["t"]]]) + .to eq([[:active, '=', ['t']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - describe ".static_query_my" do + describe '.static_query_my' do subject(:find) { described_class.static_query_my } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.my")) + .to eql(I18n.t('projects.lists.my')) end - it "has a filter for projects the user is a member of" do + it 'has a filter for projects the user is a member of' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:member_of, "=", ["t"]]]) + .to eq([[:member_of, '=', ['t']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - describe ".static_query_archived" do + describe '.static_query_archived' do subject(:find) { described_class.static_query_archived } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("projects.lists.archived")) + .to eql(I18n.t('projects.lists.archived')) end - it "has a filter for archived projects" do + it 'has a filter for archived projects' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:active, "=", ["f"]]]) + .to eq([[:active, '=', ['f']]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - describe ".static_query_status_on_track" do + describe '.static_query_status_on_track' do subject(:find) { described_class.static_query_status_on_track } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("activerecord.attributes.project.status_codes.on_track")) + .to eql(I18n.t('activerecord.attributes.project.status_codes.on_track')) end it 'has a filter for project that are "on track"' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:project_status_code, "=", [Project.status_codes[:on_track].to_s]]]) + .to eq([[:project_status_code, '=', [Project.status_codes[:on_track].to_s]]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - describe ".static_query_status_off_track" do + describe '.static_query_status_off_track' do subject(:find) { described_class.static_query_status_off_track } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("activerecord.attributes.project.status_codes.off_track")) + .to eql(I18n.t('activerecord.attributes.project.status_codes.off_track')) end it 'has a filter for projects that are "off track"' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:project_status_code, "=", [Project.status_codes[:off_track].to_s]]]) + .to eq([[:project_status_code, '=', [Project.status_codes[:off_track].to_s]]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end end - describe ".static_query_status_at_risk" do + describe '.static_query_status_at_risk' do subject(:find) { described_class.static_query_status_at_risk } - it "returns a project query" do + it 'returns a project query' do expect(find) .to be_a(Queries::Projects::ProjectQuery) end - it "has a name" do + it 'has a name' do expect(find.name) - .to eql(I18n.t("activerecord.attributes.project.status_codes.at_risk")) + .to eql(I18n.t('activerecord.attributes.project.status_codes.at_risk')) end it 'has a filter for projects that are "at risk"' do expect(find.filters.map { |filter| [filter.field, filter.operator, filter.values] }) - .to eq([[:project_status_code, "=", [Project.status_codes[:at_risk].to_s]]]) + .to eq([[:project_status_code, '=', [Project.status_codes[:at_risk].to_s]]]) end - it "is ordered by lft asc" do + it 'is ordered by lft asc' do expect(find.orders.map { |order| [order.attribute, order.direction] }) - .to eq([["lft", :asc]]) + .to eq([['lft', :asc]]) end - it "has the enabled project columns columns as selects" do + it 'has the enabled project columns columns as selects' do expect(find.selects.map(&:attribute)) .to eq(Setting.enabled_projects_columns.map(&:to_sym)) end diff --git a/spec/models/queries/projects/filters/active_filter_spec.rb b/spec/models/queries/projects/filters/active_filter_spec.rb index 1bae71388bd6..2507c5d9d5e2 100644 --- a/spec/models/queries/projects/filters/active_filter_spec.rb +++ b/spec/models/queries/projects/filters/active_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::ActiveFilter do - it_behaves_like "boolean query filter" do + it_behaves_like 'boolean query filter' do let(:model) { Project } let(:attribute) { :active } end diff --git a/spec/models/queries/projects/filters/created_at_filter_spec.rb b/spec/models/queries/projects/filters/created_at_filter_spec.rb index 0e3a6068b241..49b58b7ffc45 100644 --- a/spec/models/queries/projects/filters/created_at_filter_spec.rb +++ b/spec/models/queries/projects/filters/created_at_filter_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::CreatedAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :created_at } let(:type) { :datetime_past } let(:model) { Project } let(:attribute) { :created_at } - let(:values) { ["3"] } + let(:values) { ['3'] } let(:admin) { build_stubbed(:admin) } let(:user) { build_stubbed(:user) } - describe "#available?" do - context "for an admin" do + describe '#available?' do + context 'for an admin' do before do login_as admin end - it "is true" do + it 'is true' do expect(instance) .to be_available end end - context "for non admin" do + context 'for non admin' do before do login_as user end - it "is true" do + it 'is true' do expect(instance) .to be_available end diff --git a/spec/models/queries/projects/filters/custom_field_filter_spec.rb b/spec/models/queries/projects/filters/custom_field_filter_spec.rb index 2bae736f5a42..8cdb6433b174 100644 --- a/spec/models/queries/projects/filters/custom_field_filter_spec.rb +++ b/spec/models/queries/projects/filters/custom_field_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::CustomFieldFilter do let(:query) { Queries::Projects::ProjectQuery.new } @@ -52,7 +52,7 @@ end let(:cf_accessor) { custom_field.column_name } let(:instance) do - described_class.create!(name: cf_accessor, operator: "=", context: query) + described_class.create!(name: cf_accessor, operator: '=', context: query) end let(:instance_key) { nil } @@ -64,64 +64,64 @@ .and_return(all_custom_fields) end - describe "invalid custom field" do - let(:cf_accessor) { "cf_100" } + describe 'invalid custom field' do + let(:cf_accessor) { 'cf_100' } let(:all_custom_fields) { [] } - it "raises exception" do + it 'raises exception' do expect { instance }.to raise_error(Queries::Filters::InvalidError) end end - describe ".valid?" do + describe '.valid?' do let(:custom_field) { string_project_custom_field } before do - instance.values = ["bogus"] + instance.values = ['bogus'] allow(ProjectCustomField) .to receive_message_chain(:visible, :exists?) # rubocop:disable RSpec/MessageChain .and_return(true) end - shared_examples_for "custom field type dependent validity" do - context "with a string custom field" do - it "is valid" do + shared_examples_for 'custom field type dependent validity' do + context 'with a string custom field' do + it 'is valid' do expect(instance).to be_valid end end - context "with a list custom field" do + context 'with a list custom field' do let(:custom_field) { list_project_custom_field } before do instance.values = [list_project_custom_field.possible_values.first.id] end - it "is valid" do + it 'is valid' do expect(instance).to be_valid end it "is invalid if the value is not one of the custom field's possible values" do - instance.values = ["bogus"] + instance.values = ['bogus'] expect(instance).not_to be_valid end end end - context "without a project" do - it_behaves_like "custom field type dependent validity" + context 'without a project' do + it_behaves_like 'custom field type dependent validity' end end - describe ".key" do - it "is a regular expression" do + describe '.key' do + it 'is a regular expression' do expect(described_class.key).to eql(/cf_(\d+)/) end end - describe "instance attributes" do - it "are valid" do + describe 'instance attributes' do + it 'are valid' do all_custom_fields.each do |cf| name = "cf_#{cf.id}" filter = described_class.create!(name:) @@ -131,138 +131,138 @@ end end - describe "#type" do - context "integer" do + describe '#type' do + context 'integer' do let(:cf_accessor) { int_project_custom_field.column_name } - it "is integer for an integer" do + it 'is integer for an integer' do expect(instance.type) .to be(:integer) end end - context "float" do + context 'float' do let(:cf_accessor) { float_project_custom_field.column_name } - it "is integer for a float" do + it 'is integer for a float' do expect(instance.type) .to be(:float) end end - context "text" do + context 'text' do let(:cf_accessor) { text_project_custom_field.column_name } - it "is text for a text" do + it 'is text for a text' do expect(instance.type) .to be(:text) end end - context "list optional" do + context 'list optional' do let(:cf_accessor) { list_project_custom_field.column_name } - it "is list_optional for a list" do + it 'is list_optional for a list' do expect(instance.type) .to be(:list_optional) end end - context "user" do + context 'user' do let(:cf_accessor) { user_project_custom_field.column_name } - it "is list_optional for a user" do + it 'is list_optional for a user' do expect(instance.type) .to be(:list_optional) end end - context "version" do + context 'version' do let(:cf_accessor) { version_project_custom_field.column_name } - it "is list_optional for a version" do + it 'is list_optional for a version' do expect(instance.type) .to be(:list_optional) end end - context "version" do + context 'version' do let(:cf_accessor) { date_project_custom_field.column_name } - it "is date for a date" do + it 'is date for a date' do expect(instance.type) .to be(:date) end end - context "bool" do + context 'bool' do let(:cf_accessor) { bool_project_custom_field.column_name } - it "is list for a bool" do + it 'is list for a bool' do expect(instance.type) .to be(:list) end end - context "string" do + context 'string' do let(:cf_accessor) { string_project_custom_field.column_name } - it "is string for a string" do + it 'is string for a string' do expect(instance.type) .to be(:string) end end end - describe "#human_name" do - it "is the field name" do + describe '#human_name' do + it 'is the field name' do expect(instance.human_name) .to eql(list_project_custom_field.name) end end - describe "#allowed_values" do - context "integer" do + describe '#allowed_values' do + context 'integer' do let(:cf_accessor) { int_project_custom_field.column_name } - it "is nil for an integer" do + it 'is nil for an integer' do expect(instance.allowed_values) .to be_nil end end - context "float" do + context 'float' do let(:cf_accessor) { float_project_custom_field.column_name } - it "is integer for a float" do + it 'is integer for a float' do expect(instance.allowed_values) .to be_nil end end - context "text" do + context 'text' do let(:cf_accessor) { text_project_custom_field.column_name } - it "is text for a text" do + it 'is text for a text' do expect(instance.allowed_values) .to be_nil end end - context "list" do + context 'list' do let(:cf_accessor) { list_project_custom_field.column_name } - it "is list_optional for a list" do + it 'is list_optional for a list' do expect(instance.allowed_values) .to match_array(list_project_custom_field.custom_options.map { |co| [co.value, co.id.to_s] }) end end - context "user" do + context 'user' do let(:cf_accessor) { user_project_custom_field.column_name } - it "is list_optional for a user" do - bogus_return_value = ["user1", "user2"] + it 'is list_optional for a user' do + bogus_return_value = ['user1', 'user2'] allow(user_project_custom_field) .to receive(:possible_values_options) .and_return(bogus_return_value) @@ -272,11 +272,11 @@ end end - context "version" do + context 'version' do let(:cf_accessor) { version_project_custom_field.column_name } - it "is list_optional for a version" do - bogus_return_value = ["version1", "version2"] + it 'is list_optional for a version' do + bogus_return_value = ['version1', 'version2'] allow(version_project_custom_field) .to receive(:possible_values_options) .and_return(bogus_return_value) @@ -286,36 +286,36 @@ end end - context "date" do + context 'date' do let(:cf_accessor) { date_project_custom_field.column_name } - it "is nil for a date" do + it 'is nil for a date' do expect(instance.allowed_values) .to be_nil end end - context "bool" do + context 'bool' do let(:cf_accessor) { bool_project_custom_field.column_name } - it "is list for a bool" do + it 'is list for a bool' do expect(instance.allowed_values) .to contain_exactly([I18n.t(:general_text_yes), OpenProject::Database::DB_VALUE_TRUE], [I18n.t(:general_text_no), OpenProject::Database::DB_VALUE_FALSE]) end end - context "string" do + context 'string' do let(:cf_accessor) { string_project_custom_field.column_name } - it "is nil for a string" do + it 'is nil for a string' do expect(instance.allowed_values) .to be_nil end end end - describe ".all_for" do + describe '.all_for' do before do allow(ProjectCustomField) .to receive(:visible) @@ -328,7 +328,7 @@ string_project_custom_field]) end - it "returns a list with a filter for every custom field" do + it 'returns a list with a filter for every custom field' do filters = described_class.all_for [list_project_custom_field, @@ -348,30 +348,30 @@ end end - context "list cf" do - describe "#ar_object_filter? / #value_objects" do + context 'list cf' do + describe '#ar_object_filter? / #value_objects' do let(:custom_field) { list_project_custom_field } - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do before do instance.values = [custom_field.custom_options.last.id, custom_field.custom_options.first.id] end - it "returns an array with custom classes" do + it 'returns an array with custom classes' do expect(instance.value_objects) .to contain_exactly(custom_field.custom_options.last, custom_field.custom_options.first) end - it "ignores invalid values" do - instance.values = ["invalid", + it 'ignores invalid values' do + instance.values = ['invalid', custom_field.custom_options.last.id] expect(instance.value_objects) @@ -380,41 +380,41 @@ end end - context "bool cf" do + context 'bool cf' do let(:custom_field) { bool_project_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "int cf" do + context 'int cf' do let(:custom_field) { int_project_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "float cf" do + context 'float cf' do let(:custom_field) { float_project_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "text cf" do + context 'text cf' do let(:custom_field) { text_project_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "user cf" do + context 'user cf' do let(:custom_field) { user_project_custom_field } - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:user1) { build_stubbed(:user) } let(:user2) { build_stubbed(:user) } @@ -426,24 +426,24 @@ instance.values = [user1.id.to_s, user2.id.to_s] end - it "returns an array with users" do + it 'returns an array with users' do expect(instance.value_objects) .to contain_exactly(user1, user2) end end end - context "version cf" do + context 'version cf' do let(:custom_field) { version_project_custom_field } - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:version1) { build_stubbed(:version) } let(:version2) { build_stubbed(:version) } @@ -456,23 +456,23 @@ instance.values = [version1.id.to_s, version2.id.to_s] end - it "returns an array with users" do + it 'returns an array with users' do expect(instance.value_objects) .to contain_exactly(version1, version2) end end end - context "date cf" do + context 'date cf' do let(:custom_field) { date_project_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "string cf" do + context 'string cf' do let(:custom_field) { string_project_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end end diff --git a/spec/models/queries/projects/filters/latest_activity_at_filter_spec.rb b/spec/models/queries/projects/filters/latest_activity_at_filter_spec.rb index 826544053a8b..1d89ad6a4f07 100644 --- a/spec/models/queries/projects/filters/latest_activity_at_filter_spec.rb +++ b/spec/models/queries/projects/filters/latest_activity_at_filter_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::LatestActivityAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :latest_activity_at } let(:type) { :datetime_past } let(:model) { Project.with_latest_activity } let(:attribute) { :activity } - let(:values) { ["3"] } + let(:values) { ['3'] } let(:admin) { build_stubbed(:admin) } let(:user) { build_stubbed(:user) } - describe "#available?" do - context "for an admin" do + describe '#available?' do + context 'for an admin' do before do login_as admin end - it "is true" do + it 'is true' do expect(instance) .to be_available end end - context "for non admin" do + context 'for non admin' do before do login_as user end - it "is false" do + it 'is false' do expect(instance) .not_to be_available end diff --git a/spec/models/queries/projects/filters/member_of_filter_spec.rb b/spec/models/queries/projects/filters/member_of_filter_spec.rb index 95d44d19c2f6..22617c5eec77 100644 --- a/spec/models/queries/projects/filters/member_of_filter_spec.rb +++ b/spec/models/queries/projects/filters/member_of_filter_spec.rb @@ -29,20 +29,20 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::MemberOfFilter do - it_behaves_like "boolean query filter", scope: false do + it_behaves_like 'boolean query filter', scope: false do let(:model) { Project } let(:attribute) { :member_of } - describe "#scope" do - let(:operator) { "=" } + describe '#scope' do + let(:operator) { '=' } context 'for "t"' do let(:values) { [OpenProject::Database::DB_VALUE_TRUE] } - it "queries for projects where current user is a member" do + it 'queries for projects where current user is a member' do expected = expected_base_scope.visible.with_member expect(instance.scope.to_sql).to eql expected.to_sql @@ -52,7 +52,7 @@ context 'for "f"' do let(:values) { [OpenProject::Database::DB_VALUE_FALSE] } - it "queries for projects where current user is not a member" do + it 'queries for projects where current user is not a member' do expected = expected_base_scope.visible.without_member expect(instance.scope.to_sql).to eql expected.to_sql @@ -60,11 +60,11 @@ end end - describe "invalid operators" do + describe 'invalid operators' do context 'when using "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end diff --git a/spec/models/queries/projects/filters/name_and_identifier_filter_spec.rb b/spec/models/queries/projects/filters/name_and_identifier_filter_spec.rb index 49a96c34989e..9ce8fc14cefa 100644 --- a/spec/models/queries/projects/filters/name_and_identifier_filter_spec.rb +++ b/spec/models/queries/projects/filters/name_and_identifier_filter_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::NameAndIdentifierFilter do - include_context "filter tests" - let(:values) { ["A name"] } + include_context 'filter tests' + let(:values) { ['A name'] } let(:model) { Project } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :name_and_identifier } - let(:human_name) { "Name or identifier" } + let(:human_name) { 'Name or identifier' } let(:type) { :string } let(:model) { Project } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end diff --git a/spec/models/queries/projects/filters/name_filter_spec.rb b/spec/models/queries/projects/filters/name_filter_spec.rb index c46e71e8c4dc..2dec4850b501 100644 --- a/spec/models/queries/projects/filters/name_filter_spec.rb +++ b/spec/models/queries/projects/filters/name_filter_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::NameFilter do - include_context "filter tests" - let(:values) { ["A name"] } + include_context 'filter tests' + let(:values) { ['A name'] } let(:model) { Project } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :name } - let(:human_name) { "Name" } + let(:human_name) { 'Name' } let(:type) { :string } let(:model) { Project } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end diff --git a/spec/models/queries/projects/filters/parent_filter_spec.rb b/spec/models/queries/projects/filters/parent_filter_spec.rb index 5db0e79c2365..252317c2037e 100644 --- a/spec/models/queries/projects/filters/parent_filter_spec.rb +++ b/spec/models/queries/projects/filters/parent_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::ParentFilter do let(:project1) { build_stubbed(:project) } @@ -39,13 +39,13 @@ .and_return([project1.id, project2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :parent_id } let(:type) { :list_optional } let(:name) { Project.human_attribute_name(:parent) } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[project1.id, project1.id.to_s], [project2.id, project2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :parent_id } let(:model) { Project } let(:valid_values) { [project1.id.to_s] } diff --git a/spec/models/queries/projects/filters/principal_filter_spec.rb b/spec/models/queries/projects/filters/principal_filter_spec.rb index b9759cb0276e..7c283da63a2b 100644 --- a/spec/models/queries/projects/filters/principal_filter_spec.rb +++ b/spec/models/queries/projects/filters/principal_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::PrincipalFilter do let(:group1) { build_stubbed(:group) } @@ -44,13 +44,13 @@ user2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :principal } let(:type) { :list_optional } let(:name) { Principal.model_name.human } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[group1.id, group1.id.to_s], [group2.id, group2.id.to_s], [user1.id, user1.id.to_s], diff --git a/spec/models/queries/projects/filters/project_status_filter_spec.rb b/spec/models/queries/projects/filters/project_status_filter_spec.rb index f27310f8253b..2750e85630a4 100644 --- a/spec/models/queries/projects/filters/project_status_filter_spec.rb +++ b/spec/models/queries/projects/filters/project_status_filter_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::ProjectStatusFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :project_status_code } let(:type) { :list_optional } let(:model) { Project } let(:attribute) { :status_code } - let(:values) { ["On track"] } - let(:human_name) { "Project status" } + let(:values) { ['On track'] } + let(:human_name) { 'Project status' } let(:admin) { build_stubbed(:admin) } let(:user) { build_stubbed(:user) } let(:expected) do @@ -49,8 +49,8 @@ ] end - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expect(instance.allowed_values).to match_array(expected) end end diff --git a/spec/models/queries/projects/filters/public_filter_spec.rb b/spec/models/queries/projects/filters/public_filter_spec.rb index 97730b75497e..b6313056ce93 100644 --- a/spec/models/queries/projects/filters/public_filter_spec.rb +++ b/spec/models/queries/projects/filters/public_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::PublicFilter do - it_behaves_like "boolean query filter" do + it_behaves_like 'boolean query filter' do let(:model) { Project } let(:attribute) { :public } end diff --git a/spec/models/queries/projects/filters/type_filter_spec.rb b/spec/models/queries/projects/filters/type_filter_spec.rb index be84d1d3deff..33c81fe3d5d6 100644 --- a/spec/models/queries/projects/filters/type_filter_spec.rb +++ b/spec/models/queries/projects/filters/type_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::TypeFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :type_id } let(:type) { :list } let(:model) { Project } let(:attribute) { :type_id } - let(:values) { ["3"] } + let(:values) { ['3'] } let(:admin) { build_stubbed(:admin) } let(:user) { build_stubbed(:user) } before do - allow(Type).to receive(:pluck).with(:name, :id).and_return([["Foo", "1234"]]) + allow(Type).to receive(:pluck).with(:name, :id).and_return([['Foo', '1234']]) end - describe "#allowed_values" do - it "is a list of the possible values" do - expect(instance.allowed_values).to contain_exactly(["Foo", "1234"]) + describe '#allowed_values' do + it 'is a list of the possible values' do + expect(instance.allowed_values).to contain_exactly(['Foo', '1234']) end end end diff --git a/spec/models/queries/projects/filters/user_action_filter_spec.rb b/spec/models/queries/projects/filters/user_action_filter_spec.rb index a8820bd8d4df..67d4d13cd8f3 100644 --- a/spec/models/queries/projects/filters/user_action_filter_spec.rb +++ b/spec/models/queries/projects/filters/user_action_filter_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::UserActionFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :user_action } let(:type) { :list_all } let(:model) { Project } let(:attribute) { :user_action } - let(:values) { ["projects/view"] } + let(:values) { ['projects/view'] } end end diff --git a/spec/models/queries/projects/filters/visible_filter_spec.rb b/spec/models/queries/projects/filters/visible_filter_spec.rb index b81945bf5005..b738e8fc3833 100644 --- a/spec/models/queries/projects/filters/visible_filter_spec.rb +++ b/spec/models/queries/projects/filters/visible_filter_spec.rb @@ -26,50 +26,50 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Filters::VisibleFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :visible } let(:type) { :list } let(:model) { Project } let(:attribute) { :visible } - let(:values) { ["5"] } + let(:values) { ['5'] } - describe "#available_operators" do - it "supports only =" do + describe '#available_operators' do + it 'supports only =' do expect(instance.available_operators) .to eql [Queries::Operators::Equals] end end - describe "#valid?" do + describe '#valid?' do before do allow(User) .to receive(:pluck) .and_return([[5, 5], [8, 8]]) end - context "without values" do + context 'without values' do let(:values) { [] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end end - context "with valid value" do - it "is valid" do + context 'with valid value' do + it 'is valid' do expect(instance) .to be_valid end end - context "with multiple valid values" do + context 'with multiple valid values' do let(:values) { %w[5 8] } - it "is invalid" do + it 'is invalid' do expect(instance) .to be_invalid end diff --git a/spec/models/queries/projects/orders/latest_activity_at_order_spec.rb b/spec/models/queries/projects/orders/latest_activity_at_order_spec.rb index 841079f34f85..1ff643331ccd 100644 --- a/spec/models/queries/projects/orders/latest_activity_at_order_spec.rb +++ b/spec/models/queries/projects/orders/latest_activity_at_order_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Orders::LatestActivityAtOrder do let(:instance) do - described_class.new("").tap do |i| + described_class.new('').tap do |i| i.direction = direction end end let(:direction) { :asc } - describe "#scope" do - context "with a valid direction" do - it "orders by the disk space" do + describe '#scope' do + context 'with a valid direction' do + it 'orders by the disk space' do expect(instance.scope.to_sql) .to eql(Project.order(Arel.sql("activity.latest_activity_at").asc).to_sql) end end - context "with an invalid direction" do - let(:direction) { "bogus" } + context 'with an invalid direction' do + let(:direction) { 'bogus' } - it "raises an error" do + it 'raises an error' do expect { instance.scope } .to raise_error(ArgumentError) end diff --git a/spec/models/queries/projects/orders/required_disk_space_order_spec.rb b/spec/models/queries/projects/orders/required_disk_space_order_spec.rb index c6507423d03b..f53345d5bba4 100644 --- a/spec/models/queries/projects/orders/required_disk_space_order_spec.rb +++ b/spec/models/queries/projects/orders/required_disk_space_order_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::Orders::RequiredDiskSpaceOrder do let(:instance) do - described_class.new("").tap do |i| + described_class.new('').tap do |i| i.direction = direction end end let(:direction) { :asc } - describe "#scope" do - context "with a valid direction" do - it "orders by the disk space" do + describe '#scope' do + context 'with a valid direction' do + it 'orders by the disk space' do expect(instance.scope.to_sql) .to eql(Project.order(Arel.sql(Project.required_disk_space_sum).asc).to_sql) end end - context "with an invalid direction" do - let(:direction) { "bogus" } + context 'with an invalid direction' do + let(:direction) { 'bogus' } - it "raises an error" do + it 'raises an error' do expect { instance.scope } .to raise_error(ArgumentError) end diff --git a/spec/models/queries/projects/project_query_results_spec.rb b/spec/models/queries/projects/project_query_results_spec.rb index ecbb349d9258..9bf2b010a17e 100644 --- a/spec/models/queries/projects/project_query_results_spec.rb +++ b/spec/models/queries/projects/project_query_results_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Queries::Projects::ProjectQuery, "results" do +RSpec.describe Queries::Projects::ProjectQuery, 'results' do let(:instance) { described_class.new } let(:base_scope) { Project.order(id: :desc) } shared_let(:view_role) { create(:project_role, permissions: %i[view_project]) } shared_let(:non_member_role) { create(:non_member, permissions: %i[view_project]) } - shared_let(:grandparent) { create(:project, name: "Grandparent") } - shared_let(:parent) { create(:project, parent: grandparent, name: "Parent") } - shared_let(:child) { create(:project, parent:, name: "Child") } - shared_let(:grandchild) { create(:project, parent: child, name: "Grandchild") } - shared_let(:sibling) { create(:project, parent:, name: "Sibling") } - shared_let(:not_member) { create(:project, name: "Not member") } - shared_let(:public) { create(:public_project, name: "Public") } - shared_let(:no_hierarchy) { create(:project, name: "No Hierarchy") } + shared_let(:grandparent) { create(:project, name: 'Grandparent') } + shared_let(:parent) { create(:project, parent: grandparent, name: 'Parent') } + shared_let(:child) { create(:project, parent:, name: 'Child') } + shared_let(:grandchild) { create(:project, parent: child, name: 'Grandchild') } + shared_let(:sibling) { create(:project, parent:, name: 'Sibling') } + shared_let(:not_member) { create(:project, name: 'Not member') } + shared_let(:public) { create(:public_project, name: 'Public') } + shared_let(:no_hierarchy) { create(:project, name: 'No Hierarchy') } shared_let(:user) do create(:user, member_with_roles: { @@ -56,33 +56,33 @@ current_user { user } - context "without a filter" do - it "gets all visible projects" do + context 'without a filter' do + it 'gets all visible projects' do expect(instance.results) .to contain_exactly(grandparent, parent, child, sibling, grandchild, public, no_hierarchy) end end - context "with a parent filter" do + context 'with a parent filter' do context 'with a "=" operator' do before do - instance.where("parent_id", "=", [parent.id]) + instance.where('parent_id', '=', [parent.id]) end - it "returns all children of the specified parent" do + it 'returns all children of the specified parent' do expect(instance.results) .to contain_exactly(child, sibling) end end end - context "with an ancestor filter" do + context 'with an ancestor filter' do context 'with a "=" operator' do before do - instance.where("ancestor", "=", [grandparent.id]) + instance.where('ancestor', '=', [grandparent.id]) end - it "gets all projects that are descendants" do + it 'gets all projects that are descendants' do expect(instance.results) .to contain_exactly(parent, child, sibling, grandchild) end @@ -90,29 +90,29 @@ context 'with a "!" operator' do before do - instance.where("ancestor", "!", [grandparent.id]) + instance.where('ancestor', '!', [grandparent.id]) end - it "gets all projects that are not descendants" do + it 'gets all projects that are not descendants' do expect(instance.results) .to contain_exactly(grandparent, public, no_hierarchy) end end end - context "with an order by id asc" do - it "returns all visible projects ordered by id asc" do + context 'with an order by id asc' do + it 'returns all visible projects ordered by id asc' do expect(instance.order(id: :asc).results.to_a) .to eql [grandparent, parent, child, sibling, grandchild, public, no_hierarchy].sort_by(&:id) end end - context "with an order by typeahead asc" do + context 'with an order by typeahead asc' do before do instance.order(typeahead: :asc) end - it "returns all visible projects ordered by lft asc" do + it 'returns all visible projects ordered by lft asc' do expect(instance.results.to_a) .to eql [grandparent, parent, child, grandchild, sibling, no_hierarchy, public] end diff --git a/spec/models/queries/projects/project_query_spec.rb b/spec/models/queries/projects/project_query_spec.rb index 513a00c52ddc..47bcd25832de 100644 --- a/spec/models/queries/projects/project_query_spec.rb +++ b/spec/models/queries/projects/project_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::ProjectQuery do let(:instance) { described_class.new } @@ -34,40 +34,40 @@ shared_let(:user) { create(:user) } shared_let(:admin) { create(:admin) } - context "when persisting" do + context 'when persisting' do let(:properties) do { - name: "some name", + name: 'some name', user: } end - it "takes a name property" do + it 'takes a name property' do instance = described_class.create(**properties) expect(described_class.find(instance.id).name) .to eql properties[:name] end - it "takes a user property" do + it 'takes a user property' do instance = described_class.create(**properties) expect(described_class.find(instance.id).user) .to eql properties[:user] end - it "takes filters" do + it 'takes filters' do instance = described_class.new(**properties) - instance.where("active", "=", OpenProject::Database::DB_VALUE_TRUE) + instance.where('active', '=', OpenProject::Database::DB_VALUE_TRUE) instance.save! expect(described_class.find(instance.id).filters.map { |f| { field: f.field, operator: f.operator, values: f.values } }) - .to eql [{ field: :active, operator: "=", values: [OpenProject::Database::DB_VALUE_TRUE] }] + .to eql [{ field: :active, operator: '=', values: [OpenProject::Database::DB_VALUE_TRUE] }] end - it "takes sort order" do + it 'takes sort order' do instance = described_class.new(**properties) instance.order(id: :desc) @@ -78,7 +78,7 @@ .to eql [{ id: :desc }] end - it "takes selects" do + it 'takes selects' do instance = described_class.new(**properties) instance.select(:name, :public) @@ -90,7 +90,7 @@ end end - describe ".available_selects" do + describe '.available_selects' do current_user { user } before do @@ -105,7 +105,7 @@ .and_return([23, 42]) end - it "lists registered selects" do + it 'lists registered selects' do expect(instance.available_selects.map(&:attribute)) .to contain_exactly(:name, :public, @@ -115,10 +115,10 @@ :status_explanation) end - context "with the user being admin" do + context 'with the user being admin' do current_user { admin } - it "includes admin columns" do + it 'includes admin columns' do expect(instance.available_selects.map(&:attribute)) .to contain_exactly(:name, :public, @@ -132,10 +132,10 @@ end end - context "with an enterprise token", + context 'with an enterprise token', with_ee: %i[custom_fields_in_projects_list] do # rubocop:disable Naming/VariableNumber - it "includes custom field columns" do + it 'includes custom field columns' do expect(instance.available_selects.map(&:attribute)) .to contain_exactly(:name, :public, diff --git a/spec/models/queries/queries/filters/project_filter_spec.rb b/spec/models/queries/queries/filters/project_filter_spec.rb index 8b81c83a4058..fc78b4eea218 100644 --- a/spec/models/queries/queries/filters/project_filter_spec.rb +++ b/spec/models/queries/queries/filters/project_filter_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Queries::Filters::ProjectFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :project_id } let(:type) { :list_optional } end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :project_id } let(:model) { Query } - let(:valid_values) { ["1"] } + let(:valid_values) { ['1'] } end end diff --git a/spec/models/queries/queries/filters/updated_at_filter_spec.rb b/spec/models/queries/queries/filters/updated_at_filter_spec.rb index eb0136da4e0c..6fe449d4c2e0 100644 --- a/spec/models/queries/queries/filters/updated_at_filter_spec.rb +++ b/spec/models/queries/queries/filters/updated_at_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Queries::Filters::UpdatedAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :datetime_past } let(:class_key) { :updated_at } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/queries/query_query_spec.rb b/spec/models/queries/queries/query_query_spec.rb index 8766835375a6..578485fd5a4e 100644 --- a/spec/models/queries/queries/query_query_spec.rb +++ b/spec/models/queries/queries/query_query_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Queries::QueryQuery do let(:user) { build_stubbed(:user) } let(:instance) { described_class.new(user:) } let(:base_scope) { Query.visible(user).order(id: :desc) } - context "without a filter" do - describe "#results" do - it "is the same as getting all visible queries" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all visible queries' do expect(instance.results.to_sql).to eql base_scope.to_sql end end end - context "with an updated_at filter" do + context 'with an updated_at filter' do before do - instance.where("updated_at", "<>d", ["2018-03-22 20:00:00"]) + instance.where('updated_at', '<>d', ['2018-03-22 20:00:00']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope.merge(Query.where("queries.updated_at >= '2018-03-22 20:00:00'")) expect(instance.results.to_sql).to eql expected.to_sql @@ -55,13 +55,13 @@ end end - context "with a project filter" do + context 'with a project filter' do before do - instance.where("project_id", "=", ["1", "2"]) + instance.where('project_id', '=', ['1', '2']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do # apparently, strings are accepted to be compared to # integers in the postgresql expected = base_scope @@ -71,13 +71,13 @@ end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("name", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('name', '=', ['']) expect(instance).to be_invalid end end diff --git a/spec/models/queries/relations/filters/from_filter_spec.rb b/spec/models/queries/relations/filters/from_filter_spec.rb index afd2393ace78..1414e52a7959 100644 --- a/spec/models/queries/relations/filters/from_filter_spec.rb +++ b/spec/models/queries/relations/filters/from_filter_spec.rb @@ -26,34 +26,34 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Relations::Filters::FromFilter do - include_context "filter tests" - let(:values) { ["1"] } + include_context 'filter tests' + let(:values) { ['1'] } let(:model) { Relation } let(:current_user) { build_stubbed(:user) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :from_id } let(:type) { :integer } # The name is not very good but as long as the filter is not displayed in the UI ... - let(:human_name) { "Work package" } + let(:human_name) { 'Work package' } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end end - describe "#visibility_checked?" do - it "is true" do + describe '#visibility_checked?' do + it 'is true' do expect(instance).to be_visibility_checked end end - describe "#scope" do + describe '#scope' do before do login_as(current_user) end @@ -61,9 +61,9 @@ let(:visible_sql) { WorkPackage.visible(current_user).select(:id).to_sql } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where("from_id IN ('1') AND to_id IN (#{visible_sql})") expect(instance.scope.to_sql).to eql expected.to_sql @@ -71,9 +71,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where("from_id NOT IN ('1') AND to_id IN (#{visible_sql})") expect(instance.scope.to_sql).to eql expected.to_sql diff --git a/spec/models/queries/relations/filters/involved_filter_spec.rb b/spec/models/queries/relations/filters/involved_filter_spec.rb index 336489ea7faf..11e7db1df46a 100644 --- a/spec/models/queries/relations/filters/involved_filter_spec.rb +++ b/spec/models/queries/relations/filters/involved_filter_spec.rb @@ -26,32 +26,32 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Relations::Filters::InvolvedFilter do - include_context "filter tests" - let(:values) { ["1"] } + include_context 'filter tests' + let(:values) { ['1'] } let(:model) { Relation } let(:current_user) { build_stubbed(:user) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :involved } let(:type) { :integer } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end end - describe "#visibility_checked?" do - it "is true" do + describe '#visibility_checked?' do + it 'is true' do expect(instance).to be_visibility_checked end end - describe "#scope" do + describe '#scope' do before do login_as(current_user) end @@ -59,9 +59,9 @@ let(:visible_sql) { WorkPackage.visible(current_user).select(:id).to_sql } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "(from_id IN ('1') AND to_id IN (#{visible_sql})) OR (to_id IN ('1') AND from_id IN (#{visible_sql}))" expected = model.where(sql) @@ -70,9 +70,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "(from_id NOT IN ('1') AND to_id IN (#{visible_sql})) AND (to_id NOT IN ('1') AND from_id IN (#{visible_sql}))" expected = model.where(sql) diff --git a/spec/models/queries/relations/filters/to_filter_spec.rb b/spec/models/queries/relations/filters/to_filter_spec.rb index 0fa757bb3e62..5d9e2d2791ac 100644 --- a/spec/models/queries/relations/filters/to_filter_spec.rb +++ b/spec/models/queries/relations/filters/to_filter_spec.rb @@ -26,34 +26,34 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Relations::Filters::ToFilter do - include_context "filter tests" - let(:values) { ["1"] } + include_context 'filter tests' + let(:values) { ['1'] } let(:model) { Relation } let(:current_user) { build_stubbed(:user) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :to_id } let(:type) { :integer } # The name is not very good but as long as the filter is not displayed in the UI ... - let(:human_name) { "Related work package" } + let(:human_name) { 'Related work package' } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end end - describe "#visibility_checked?" do - it "is true" do + describe '#visibility_checked?' do + it 'is true' do expect(instance).to be_visibility_checked end end - describe "#scope" do + describe '#scope' do before do login_as(current_user) end @@ -61,9 +61,9 @@ let(:visible_sql) { WorkPackage.visible(current_user).select(:id).to_sql } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where("to_id IN ('1') AND from_id IN (#{visible_sql})") expect(instance.scope.to_sql).to eql expected.to_sql @@ -71,9 +71,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where("to_id NOT IN ('1') AND from_id IN (#{visible_sql})") expect(instance.scope.to_sql).to eql expected.to_sql diff --git a/spec/models/queries/relations/relation_query_spec.rb b/spec/models/queries/relations/relation_query_spec.rb index 4cc2c587edbd..863156888fe3 100644 --- a/spec/models/queries/relations/relation_query_spec.rb +++ b/spec/models/queries/relations/relation_query_spec.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Relations::RelationQuery do let(:instance) { described_class.new } let(:base_scope) { Relation.order(id: :desc) } - context "without a filter" do - describe "#results" do - it "is the same as getting all the relations" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the relations' do expect(instance.results.to_sql).to eql base_scope.visible.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end end end - context "with a type filter" do + context 'with a type filter' do before do - instance.where("type", "=", ["follows", "blocks"]) + instance.where('type', '=', ['follows', 'blocks']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope .merge(Relation .where("relations.relation_type IN ('follows','blocks')")) @@ -62,29 +62,29 @@ end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("type", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('type', '=', ['']) expect(instance).to be_invalid end end end - context "with a from filter" do + context 'with a from filter' do let(:current_user) { build_stubbed(:user) } before do login_as(current_user) - instance.where("from_id", "=", ["1"]) + instance.where('from_id', '=', ['1']) end - describe "#results" do - it "is the same as handwriting the query (with visibility checked within the filter query)" do + describe '#results' do + it 'is the same as handwriting the query (with visibility checked within the filter query)' do visible_sql = WorkPackage.visible(current_user).select(:id).to_sql expected = base_scope @@ -96,9 +96,9 @@ end end - context "with an order by id asc" do - describe "#results" do - it "returns all visible relations ordered by id asc" do + context 'with an order by id asc' do + describe '#results' do + it 'returns all visible relations ordered by id asc' do expect(instance.order(id: :asc).results.to_sql) .to eql base_scope.visible.except(:order).order(id: :asc).to_sql end diff --git a/spec/models/queries/roles/filters/allows_becoming_assignee_filter_spec.rb b/spec/models/queries/roles/filters/allows_becoming_assignee_filter_spec.rb index 1db42e8f813a..fcfac8b60580 100644 --- a/spec/models/queries/roles/filters/allows_becoming_assignee_filter_spec.rb +++ b/spec/models/queries/roles/filters/allows_becoming_assignee_filter_spec.rb @@ -28,31 +28,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Roles::Filters::AllowsBecomingAssigneeFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :allows_becoming_assignee } let(:type) { :list } let(:model) { Role } end - it_behaves_like "boolean query filter", scope: false do + it_behaves_like 'boolean query filter', scope: false do let(:model) { Role } let(:attribute) { :type } - let(:permission_name) { "work_package_assigned" } + let(:permission_name) { 'work_package_assigned' } end - describe "#scope" do + describe '#scope' do shared_let(:assignable_role) do create(:project_role, - name: "assignable_role", + name: 'assignable_role', permissions: %i[work_package_assigned], add_public_permissions: false) end shared_let(:unassignable_role) do create(:project_role, - name: "unassignable_role", + name: 'unassignable_role', permissions: %i[wrong], add_public_permissions: false) end @@ -67,7 +67,7 @@ subject { instance.scope.map(&:name) } context 'with a "=" operator' do - let(:operator) { "=" } + let(:operator) { '=' } context 'with a "true" value' do let(:values) { [OpenProject::Database::DB_VALUE_TRUE] } @@ -83,7 +83,7 @@ end context 'with a "!" operator' do - let(:operator) { "!" } + let(:operator) { '!' } context 'with a "true" value' do let(:values) { [OpenProject::Database::DB_VALUE_TRUE] } diff --git a/spec/models/queries/roles/filters/grantable_filter_spec.rb b/spec/models/queries/roles/filters/grantable_filter_spec.rb index ccc45dabfc59..e67c86469591 100644 --- a/spec/models/queries/roles/filters/grantable_filter_spec.rb +++ b/spec/models/queries/roles/filters/grantable_filter_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Roles::Filters::GrantableFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :grantable } let(:type) { :list } let(:model) { Role } end - it_behaves_like "boolean query filter", scope: false do + it_behaves_like 'boolean query filter', scope: false do let(:model) { Role } let(:attribute) { :type } - describe "#scope" do - context "for the true value" do + describe '#scope' do + context 'for the true value' do let(:values) { [OpenProject::Database::DB_VALUE_TRUE] } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.builtin IN (?)", Role::NON_BUILTIN]) @@ -55,9 +55,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.builtin NOT IN (?)", Role::NON_BUILTIN]) @@ -66,13 +66,13 @@ end end - context "for the false value" do + context 'for the false value' do let(:values) { [OpenProject::Database::DB_VALUE_FALSE] } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.builtin IN (?)", [Role::BUILTIN_ANONYMOUS, Role::BUILTIN_NON_MEMBER]]) @@ -81,9 +81,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.builtin NOT IN (?)", [Role::BUILTIN_ANONYMOUS, Role::BUILTIN_NON_MEMBER]]) diff --git a/spec/models/queries/roles/filters/unit_filter_spec.rb b/spec/models/queries/roles/filters/unit_filter_spec.rb index d4b27b40f810..3d4509c1ca99 100644 --- a/spec/models/queries/roles/filters/unit_filter_spec.rb +++ b/spec/models/queries/roles/filters/unit_filter_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Roles::Filters::UnitFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :unit } let(:type) { :list } let(:model) { Role } end - it_behaves_like "list query filter", scope: false do + it_behaves_like 'list query filter', scope: false do let(:attribute) { :type } let(:model) { Role } - let(:valid_values) { ["project"] } + let(:valid_values) { ['project'] } - describe "#scope" do - context "for the system value" do - let(:values) { ["system"] } + describe '#scope' do + context 'for the system value' do + let(:values) { ['system'] } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model .where(["roles.type = ?", GlobalRole.name]) # rubocop:disable Rails/WhereEquals @@ -56,9 +56,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model .where(["roles.type != ?", GlobalRole.name]) # rubocop:disable Rails/WhereNot @@ -67,13 +67,13 @@ end end - context "for the project value" do - let(:values) { ["project"] } + context 'for the project value' do + let(:values) { ['project'] } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model .where(["roles.type = ? AND roles.builtin = ?", ProjectRole.name, Role::NON_BUILTIN]) @@ -82,9 +82,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model .where(["roles.type != ?", ProjectRole.name]) # rubocop:disable Rails/WhereNot diff --git a/spec/models/queries/scopes/visible_spec.rb b/spec/models/queries/scopes/visible_spec.rb index db5f3f0e64cd..06ca67c0b059 100644 --- a/spec/models/queries/scopes/visible_spec.rb +++ b/spec/models/queries/scopes/visible_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Scopes::Visible do - describe ".visible" do + describe '.visible' do subject(:scope) { Query.visible(user) } let(:user) do @@ -39,66 +39,66 @@ let(:permissions) { %i[view_work_packages] } let!(:private_user_query) do create(:query, - name: "Private user query", + name: 'Private user query', project:, user:) end let!(:private_other_user_query) do create(:query, - name: "Private other user query", + name: 'Private other user query', project:) end let!(:private_user_query_lacking_permissions) do create(:query, - name: "Private user query lacking permission", + name: 'Private user query lacking permission', project: create(:project, members: { user => create(:project_role, permissions: []) }), user:) end let!(:public_query) do create(:query, - name: "Public query", + name: 'Public query', project:, public: true) end let!(:public_query_lacking_permissions) do create(:query, - name: "Public query lacking permission", + name: 'Public query lacking permission', project: create(:project, members: { user => create(:project_role, permissions: []) }), public: true) end let!(:global_user_query) do create(:query, - name: "Global user query", + name: 'Global user query', project: nil, user:) end let!(:global_other_user_query) do create(:query, - name: "Global other user query", + name: 'Global other user query', project: nil) end let!(:global_other_user_public_query) do create(:query, - name: "Global other user public query", + name: 'Global other user public query', project: nil, public: true) end let(:project) { create(:project) } let(:public_project) { create(:public_project) } - context "with the user having the :view_work_packages permission" do - it "returns the queries that are public or that are the user`s" do + context 'with the user having the :view_work_packages permission' do + it 'returns the queries that are public or that are the user`s' do expect(scope) .to contain_exactly(private_user_query, public_query, global_user_query, global_other_user_public_query) end end - context "without the user having the :view_work_packages permission" do + context 'without the user having the :view_work_packages permission' do let(:permissions) { [] } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end diff --git a/spec/models/queries/users/filters/any_name_attribute_filter_spec.rb b/spec/models/queries/users/filters/any_name_attribute_filter_spec.rb index 3a973ac15c72..945c82c5c141 100644 --- a/spec/models/queries/users/filters/any_name_attribute_filter_spec.rb +++ b/spec/models/queries/users/filters/any_name_attribute_filter_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Users::Filters::AnyNameAttributeFilter do - include_context "filter tests" - let(:values) { ["A name"] } + include_context 'filter tests' + let(:values) { ['A name'] } let(:model) { User.user } let(:filter_str) { instance.send :sql_concat_name } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :any_name_attribute } let(:type) { :string } let(:model) { User.user } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#available_operators" do - it "supports = and !" do + describe '#available_operators' do + it 'supports = and !' do expect(instance.available_operators) .to contain_exactly Queries::Operators::Contains, Queries::Operators::NotContains, @@ -55,22 +55,22 @@ end end - describe "#scope" do + describe '#scope' do context 'for "~"' do - let(:operator) { "~" } + let(:operator) { '~' } - it "is the same as handwriting the query" do - expected = model.where("unaccent(#{filter_str}) LIKE unaccent('%#{values.first.downcase}%')") + it 'is the same as handwriting the query' do + expected = model.where("#{filter_str} LIKE '%#{values.first.downcase}%'") expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "!~"' do - let(:operator) { "!~" } + let(:operator) { '!~' } - it "is the same as handwriting the query" do - expected = model.where("unaccent(#{filter_str}) NOT LIKE unaccent('%#{values.first.downcase}%')") + it 'is the same as handwriting the query' do + expected = model.where("#{filter_str} NOT LIKE '%#{values.first.downcase}%'") expect(instance.scope.to_sql).to eql expected.to_sql end diff --git a/spec/models/queries/users/filters/group_filter_spec.rb b/spec/models/queries/users/filters/group_filter_spec.rb index 65c4f5f311cd..8fed0fb5e102 100644 --- a/spec/models/queries/users/filters/group_filter_spec.rb +++ b/spec/models/queries/users/filters/group_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Users::Filters::GroupFilter do let(:group1) { build_stubbed(:group) } @@ -39,13 +39,13 @@ .and_return([group1.id, group2.id]) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :group } let(:type) { :list_optional } - let(:name) { I18n.t("query_fields.member_of_group") } + let(:name) { I18n.t('query_fields.member_of_group') } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = [[group1.id, group1.id.to_s], [group2.id, group2.id.to_s]] expect(instance.allowed_values).to match_array(expected) @@ -53,7 +53,7 @@ end end - it_behaves_like "list_optional group query filter" do + it_behaves_like 'list_optional group query filter' do let(:model) { User.user } let(:valid_values) { [group1.id.to_s] } end diff --git a/spec/models/queries/users/filters/name_filter_spec.rb b/spec/models/queries/users/filters/name_filter_spec.rb index 4f922d34c634..c3c894413180 100644 --- a/spec/models/queries/users/filters/name_filter_spec.rb +++ b/spec/models/queries/users/filters/name_filter_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Users::Filters::NameFilter do - include_context "filter tests" - let(:values) { ["A name"] } + include_context 'filter tests' + let(:values) { ['A name'] } let(:model) { User.user } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :name } let(:type) { :string } let(:model) { User.user } - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end end - describe "#scope" do + describe '#scope' do before do allow(Setting) .to receive(:user_format) @@ -53,40 +53,40 @@ end context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do - expected = model.where("LOWER(users.firstname) IN ('#{values.first.downcase}') OR unaccent(LOWER(users.firstname)) IN ('#{values.first.downcase}')") + it 'is the same as handwriting the query' do + expected = model.where("LOWER(users.firstname) IN ('#{values.first.downcase}')") expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do - expected = model.where("LOWER(users.firstname) NOT IN ('a name') AND unaccent(LOWER(users.firstname)) NOT IN ('a name')") + it 'is the same as handwriting the query' do + expected = model.where("LOWER(users.firstname) NOT IN ('#{values.first.downcase}')") expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "~"' do - let(:operator) { "~" } + let(:operator) { '~' } - it "is the same as handwriting the query" do - expected = model.where("unaccent(LOWER(users.firstname)) LIKE unaccent('%#{values.first.downcase}%')") + it 'is the same as handwriting the query' do + expected = model.where("LOWER(users.firstname) LIKE '%#{values.first.downcase}%'") expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "!~"' do - let(:operator) { "!~" } + let(:operator) { '!~' } - it "is the same as handwriting the query" do - expected = model.where("unaccent(LOWER(users.firstname)) NOT LIKE unaccent('%#{values.first.downcase}%')") + it 'is the same as handwriting the query' do + expected = model.where("LOWER(users.firstname) NOT LIKE '%#{values.first.downcase}%'") expect(instance.scope.to_sql).to eql expected.to_sql end diff --git a/spec/models/queries/users/filters/status_filter_spec.rb b/spec/models/queries/users/filters/status_filter_spec.rb index d19bb7c5b0c3..d3b4bf42aa81 100644 --- a/spec/models/queries/users/filters/status_filter_spec.rb +++ b/spec/models/queries/users/filters/status_filter_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Users::Filters::StatusFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :status } let(:type) { :list } - describe "#allowed_values" do - it "is a list of the possible values" do + describe '#allowed_values' do + it 'is a list of the possible values' do expected = Principal.statuses.keys.map do |key| [I18n.t(:"status_#{key}"), key] end @@ -44,15 +44,15 @@ end end - describe "#scope" do - include_context "filter tests" + describe '#scope' do + include_context 'filter tests' let(:values) { %w[active invited] } let(:model) { User.user } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where("users.status IN (1,4)") expect(instance.scope.to_sql).to eql expected.to_sql diff --git a/spec/models/queries/users/user_query_spec.rb b/spec/models/queries/users/user_query_spec.rb index e7ea71b79365..12e546ded43b 100644 --- a/spec/models/queries/users/user_query_spec.rb +++ b/spec/models/queries/users/user_query_spec.rb @@ -26,75 +26,75 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Users::UserQuery do let(:instance) { described_class.new } let(:base_scope) { User.user.order(id: :desc) } - context "without a filter" do - describe "#results" do - it "is the same as getting all the users" do + context 'without a filter' do + describe '#results' do + it 'is the same as getting all the users' do expect(instance.results.to_sql).to eql base_scope.to_sql end end end - context "with a name filter" do + context 'with a name filter' do before do - instance.where("name", "~", ["a user"]) + instance.where('name', '~', ['a user']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope .merge(User .user - .where(["unaccent(LOWER(CONCAT(users.firstname, ' ', users.lastname))) LIKE unaccent(?)", + .where(["LOWER(CONCAT(users.firstname, CONCAT(' ', users.lastname))) LIKE ?", "%a user%"])) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("name", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('name', '=', ['']) expect(instance).to be_invalid end end end - context "with a status filter" do + context 'with a status filter' do before do - instance.where("status", "=", ["active"]) + instance.where('status', '=', ['active']) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope.merge(User.user.where("users.status IN (1)")) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("status", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('status', '=', ['']) expect(instance).to be_invalid end end end - context "with a group filter" do + context 'with a group filter' do let(:group_1) { build_stubbed(:group) } before do @@ -106,11 +106,11 @@ .to receive(:all) .and_return([group_1]) - instance.where("group", "=", [group_1.id]) + instance.where('group', '=', [group_1.id]) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = base_scope .merge(User .user @@ -120,37 +120,37 @@ end end - describe "#valid?" do - it "is true" do + describe '#valid?' do + it 'is true' do expect(instance).to be_valid end - it "is invalid if the filter is invalid" do - instance.where("group", "=", [""]) + it 'is invalid if the filter is invalid' do + instance.where('group', '=', ['']) expect(instance).to be_invalid end end end - context "with a non existent filter" do + context 'with a non existent filter' do before do - instance.where("not_supposed_to_exist", "=", ["bogus"]) + instance.where('not_supposed_to_exist', '=', ['bogus']) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = User.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end - it "returns the error on the filter" do + it 'returns the error on the filter' do instance.valid? expect(instance.errors[:filters]).to eql ["Not supposed to exist filter does not exist."] @@ -158,13 +158,13 @@ end end - context "with an id sortation" do + context 'with an id sortation' do before do instance.order(id: :asc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = User.user.merge(User.order(id: :asc)) expect(instance.results.to_sql).to eql expected.to_sql @@ -172,12 +172,12 @@ end end - context "with a name sortation" do + context 'with a name sortation' do before do instance.order(name: :desc) end - describe "#results", with_settings: { user_format: :firstname_lastname } do + describe '#results', with_settings: { user_format: :firstname_lastname } do let(:order_sql) do <<~SQL CASE @@ -187,7 +187,7 @@ SQL end - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = User .user .order(Arel.sql(order_sql)) @@ -198,13 +198,13 @@ end end - context "with a group sortation" do + context 'with a group sortation' do before do instance.order(group: :desc) end - describe "#results" do - it "is the same as handwriting the query" do + describe '#results' do + it 'is the same as handwriting the query' do expected = User.user.merge(User.joins(:groups).order("groups_users.lastname DESC")).order(id: :desc) expect(instance.results.to_sql).to eql expected.to_sql @@ -212,22 +212,22 @@ end end - context "with a non existing sortation" do + context 'with a non existing sortation' do # this is a field protected from sortation before do instance.order(password: :desc) end - describe "#results" do - it "returns a query not returning anything" do + describe '#results' do + it 'returns a query not returning anything' do expected = User.where(Arel::Nodes::Equality.new(1, 0)) expect(instance.results.to_sql).to eql expected.to_sql end end - describe "valid?" do - it "is false" do + describe 'valid?' do + it 'is false' do expect(instance).to be_invalid end end diff --git a/spec/models/queries/views/filters/type_filter_spec.rb b/spec/models/queries/views/filters/type_filter_spec.rb index 32af090d4fea..fcfd7f4d8871 100644 --- a/spec/models/queries/views/filters/type_filter_spec.rb +++ b/spec/models/queries/views/filters/type_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Views::Filters::TypeFilter do let(:current_user) { create(:user) } @@ -35,12 +35,12 @@ login_as(current_user) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :type } let(:type) { :list_optional } - describe "#allowed_values" do - it "includes the core views" do + describe '#allowed_values' do + it 'includes the core views' do expected_core_views = [ %w[Views::TeamPlanner Views::TeamPlanner], %w[Views::WorkPackagesTable Views::WorkPackagesTable] @@ -51,7 +51,7 @@ end end - it_behaves_like "list_optional query filter" do + it_behaves_like 'list_optional query filter' do let(:attribute) { :type } let(:model) { View } let(:valid_values) { %w[Views::TeamPlanner Views::WorkPackagesTable] } diff --git a/spec/models/queries/work_packages/filter/assigned_to_filter_spec.rb b/spec/models/queries/work_packages/filter/assigned_to_filter_spec.rb index 49c545b134dd..ab4d5dcb6088 100644 --- a/spec/models/queries/work_packages/filter/assigned_to_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/assigned_to_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::AssignedToFilter do let(:instance) do @@ -36,27 +36,27 @@ filter end - let(:operator) { "=" } + let(:operator) { '=' } let(:values) { [] } - describe "where filter results" do + describe 'where filter results' do let(:work_package) { create(:work_package, assigned_to: assignee) } let(:assignee) { create(:user) } let(:group) { create(:group) } subject { WorkPackage.where(instance.where) } - context "for the user value" do + context 'for the user value' do let(:values) { [assignee.id.to_s] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for the me value with the user being logged in" do - let(:values) { ["me"] } + context 'for the me value with the user being logged in' do + let(:values) { ['me'] } before do allow(User) @@ -64,22 +64,22 @@ .and_return(assignee) end - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end - it "returns the corrected value object" do + it 'returns the corrected value object' do objects = instance.value_objects expect(objects.size).to eq(1) - expect(objects.first.id).to eq "me" - expect(objects.first.name).to eq "me" + expect(objects.first.id).to eq 'me' + expect(objects.first.name).to eq 'me' end end - context "for the me value with another user being logged in" do - let(:values) { ["me"] } + context 'for the me value with another user being logged in' do + let(:values) { ['me'] } before do allow(User) @@ -87,16 +87,16 @@ .and_return(create(:user)) end - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for me and user values" do + context 'for me and user values' do let(:user) { create(:user) } let(:assignee2) { create(:user) } - let(:values) { [assignee.id, user.id, "me", assignee2.id] } + let(:values) { [assignee.id, user.id, 'me', assignee2.id] } before do assignee @@ -109,39 +109,39 @@ .and_return(user) end - it "returns the mapped value" do + it 'returns the mapped value' do objects = instance.value_objects # As no order is defined in the filter, we use the same method of fetching the values # from the DB as the object under test expecting it to return the values in the same order - expect(objects.map(&:id)).to eql ["me"] + Principal.where(id: [assignee.id, assignee2.id]).pluck(:id) + expect(objects.map(&:id)).to eql ['me'] + Principal.where(id: [assignee.id, assignee2.id]).pluck(:id) end end - context "for a group value with the group being assignee" do + context 'for a group value with the group being assignee' do let(:assignee) { group } let(:values) { [group.id.to_s] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for a group value with a group member being assignee" do + context 'for a group value with a group member being assignee' do let(:values) { [group.id.to_s] } let(:group) { create(:group, members: assignee) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for a group value with no group member being assignee" do + context 'for a group value with no group member being assignee' do let(:values) { [group.id.to_s] } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end @@ -153,7 +153,7 @@ let(:user) { create(:user) } let(:group) { create(:group, members: user) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end @@ -164,23 +164,23 @@ let(:assignee) { group } let(:user) { create(:user) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for an unmatched value" do - let(:values) { ["0"] } + context 'for an unmatched value' do + let(:values) { ['0'] } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :assigned_to_id } @@ -189,18 +189,18 @@ let(:placeholder_user) { build_stubbed(:group) } let(:principal_loader) do - double("principal_loader", principal_values:) + double('principal_loader', principal_values:) end let(:principal_values) { [] } - describe "#valid_values!" do + describe '#valid_values!' do let(:principal_values) { [[nil, user.id.to_s]] } before do - instance.values = [user.id.to_s, "99999"] + instance.values = [user.id.to_s, '99999'] end - it "remove the invalid value" do + it 'remove the invalid value' do instance.valid_values! expect(instance.values).to contain_exactly(user.id.to_s) @@ -214,7 +214,7 @@ .and_return(principal_loader) end - describe "#available?" do + describe '#available?' do let(:logged_in) { true } before do @@ -223,78 +223,78 @@ .and_return(logged_in) end - context "when being logged in" do - context "if no value is available" do + context 'when being logged in' do + context 'if no value is available' do let(:principal_values) { [] } - it "is true" do + it 'is true' do expect(instance).to be_available end end - context "if a user is available" do + context 'if a user is available' do let(:principal_values) { [[nil, user.id.to_s]] } - it "is true" do + it 'is true' do expect(instance).to be_available end end - context "if a placeholder user is available" do + context 'if a placeholder user is available' do let(:principal_values) { [[nil, placeholder_user.id.to_s]] } - it "is true" do + it 'is true' do expect(instance).to be_available end end - context "if another group selectable" do + context 'if another group selectable' do let(:principal_values) { [[nil, group.id.to_s]] } - it "is true" do + it 'is true' do expect(instance).to be_available end end end - context "when not being logged in" do + context 'when not being logged in' do let(:logged_in) { false } - context "if no value is available" do + context 'if no value is available' do let(:principal_values) { [] } - it "is false" do + it 'is false' do expect(instance).not_to be_available end end - context "if a user is available" do + context 'if a user is available' do let(:principal_values) { [[nil, user.id.to_s]] } - it "is true" do + it 'is true' do expect(instance).to be_available end end - context "if a placeholder user is available" do + context 'if a placeholder user is available' do let(:principal_values) { [[nil, placeholder_user.id.to_s]] } - it "is true" do + it 'is true' do expect(instance).to be_available end end - context "if another group selectable" do + context 'if another group selectable' do let(:principal_values) { [[nil, group.id.to_s]] } - it "is true" do + it 'is true' do expect(instance).to be_available end end end end - describe "#allowed_values" do + describe '#allowed_values' do let(:logged_in) { true } before do @@ -307,17 +307,17 @@ .and_return([[nil, user.id.to_s], [nil, group.id.to_s]]) end - context "when being logged in" do - it "returns the me value and the available users and groups" do + context 'when being logged in' do + it 'returns the me value and the available users and groups' do expect(instance.allowed_values) - .to contain_exactly([I18n.t(:label_me), "me"], [nil, user.id.to_s], [nil, group.id.to_s]) + .to contain_exactly([I18n.t(:label_me), 'me'], [nil, user.id.to_s], [nil, group.id.to_s]) end end - context "when not being logged in" do + context 'when not being logged in' do let(:logged_in) { false } - it "returns the available users" do + it 'returns the available users' do expect(instance.allowed_values) .to contain_exactly([nil, user.id.to_s], [nil, group.id.to_s]) end diff --git a/spec/models/queries/work_packages/filter/assignee_or_group_filter_spec.rb b/spec/models/queries/work_packages/filter/assignee_or_group_filter_spec.rb index b25d3f9983c1..97f1ebed0b54 100644 --- a/spec/models/queries/work_packages/filter/assignee_or_group_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/assignee_or_group_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::AssigneeOrGroupFilter do let(:instance) do @@ -36,10 +36,10 @@ filter end - let(:operator) { "=" } + let(:operator) { '=' } let(:values) { [] } - describe "where filter results" do + describe 'where filter results' do let(:work_package) { create(:work_package, assigned_to: assignee) } let(:assignee) { create(:user) } let(:group) { create(:group, members: group_members) } @@ -47,17 +47,17 @@ subject { WorkPackage.where(instance.where) } - context "for the user value" do + context 'for the user value' do let(:values) { [assignee.id.to_s] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for the me value with the user being logged in" do - let(:values) { ["me"] } + context 'for the me value with the user being logged in' do + let(:values) { ['me'] } before do allow(User) @@ -65,14 +65,14 @@ .and_return(assignee) end - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for the me value with another user being logged in" do - let(:values) { ["me"] } + context 'for the me value with another user being logged in' do + let(:values) { ['me'] } before do allow(User) @@ -80,36 +80,36 @@ .and_return(create(:user)) end - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for a group value with the group being assignee" do + context 'for a group value with the group being assignee' do let(:assignee) { group } let(:values) { [group.id.to_s] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for a group value with a group member being assignee" do + context 'for a group value with a group member being assignee' do let(:values) { [group.id.to_s] } let(:group_members) { [assignee] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for a group value with no group member being assignee" do + context 'for a group value with no group member being assignee' do let(:values) { [group.id.to_s] } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end @@ -121,7 +121,7 @@ let(:user) { create(:user) } let!(:group) { create(:group, members: user) } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end @@ -132,31 +132,31 @@ let(:assignee) { group } let(:user) { create(:user) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for an unmatched value" do - let(:values) { ["0"] } + context 'for an unmatched value' do + let(:values) { ['0'] } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :assignee_or_group } - let(:human_name) { I18n.t("query_fields.assignee_or_group") } + let(:human_name) { I18n.t('query_fields.assignee_or_group') } - describe "#valid_values!" do + describe '#valid_values!' do let(:user) { build_stubbed(:user) } let(:loader) do - loader = double("loader") + loader = double('loader') allow(loader) .to receive(:user_values) @@ -173,10 +173,10 @@ .to receive(:new) .and_return(loader) - instance.values = [user.id.to_s, "99999"] + instance.values = [user.id.to_s, '99999'] end - it "remove the invalid value" do + it 'remove the invalid value' do instance.valid_values! expect(instance.values).to contain_exactly(user.id.to_s) diff --git a/spec/models/queries/work_packages/filter/attachment_content_filter_spec.rb b/spec/models/queries/work_packages/filter/attachment_content_filter_spec.rb index 332d2513ac74..167bd8592f67 100644 --- a/spec/models/queries/work_packages/filter/attachment_content_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/attachment_content_filter_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::AttachmentContentFilter do if OpenProject::Database.allows_tsv? - context "WP with attachment" do + context 'WP with attachment' do let(:context) { nil } - let(:value) { "ipsum" } - let(:operator) { "~" } + let(:value) { 'ipsum' } + let(:operator) { '~' } let(:instance) do described_class.create!(name: :search, context:, operator:, values: [value]) end let(:work_package) { create(:work_package) } - let(:text) { "lorem ipsum" } + let(:text) { 'lorem ipsum' } let(:attachment) { create(:attachment, container: work_package) } before do @@ -48,7 +48,7 @@ attachment.reload end - it "finds WP through attachment content" do + it 'finds WP through attachment content' do perform_enqueued_jobs expect(WorkPackage.joins(instance.joins).where(instance.where)) @@ -56,41 +56,41 @@ end end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :text } let(:class_key) { :attachment_content } - describe "#available?" do - it "is available" do + describe '#available?' do + it 'is available' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#valid_values!" do - it "is a noop" do - instance.values = ["none", "is", "changed"] + describe '#valid_values!' do + it 'is a noop' do + instance.values = ['none', 'is', 'changed'] instance.valid_values! expect(instance.values) - .to contain_exactly("none", "is", "changed") + .to contain_exactly('none', 'is', 'changed') end end - describe "#available_operators" do - it "supports ~ and !~" do + describe '#available_operators' do + it 'supports ~ and !~' do expect(instance.available_operators) .to eql [Queries::Operators::Contains, Queries::Operators::NotContains] end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end end diff --git a/spec/models/queries/work_packages/filter/attachment_file_name_filter_spec.rb b/spec/models/queries/work_packages/filter/attachment_file_name_filter_spec.rb index 433020b19db9..be4b7acced06 100644 --- a/spec/models/queries/work_packages/filter/attachment_file_name_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/attachment_file_name_filter_spec.rb @@ -26,45 +26,45 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::AttachmentFileNameFilter do if OpenProject::Database.allows_tsv? - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :text } let(:class_key) { :attachment_file_name } - describe "#available?" do - it "is available" do + describe '#available?' do + it 'is available' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#valid_values!" do - it "is a noop" do - instance.values = ["none", "is", "changed"] + describe '#valid_values!' do + it 'is a noop' do + instance.values = ['none', 'is', 'changed'] instance.valid_values! expect(instance.values) - .to contain_exactly("none", "is", "changed") + .to contain_exactly('none', 'is', 'changed') end end - describe "#available_operators" do - it "supports ~ and !~" do + describe '#available_operators' do + it 'supports ~ and !~' do expect(instance.available_operators) .to eql [Queries::Operators::Contains, Queries::Operators::NotContains] end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end end diff --git a/spec/models/queries/work_packages/filter/author_filter_spec.rb b/spec/models/queries/work_packages/filter/author_filter_spec.rb index d9b3d37a879b..b31a4f6b2683 100644 --- a/spec/models/queries/work_packages/filter/author_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/author_filter_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::AuthorFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :author_id } let(:user_1) { build_stubbed(:user) } let(:principal_loader) do - loader = double("principal_loader") + loader = double('principal_loader') allow(loader) .to receive(:user_values) .and_return([]) @@ -51,7 +51,7 @@ .and_return(principal_loader) end - describe "#available?" do + describe '#available?' do let(:logged_in) { true } before do @@ -60,12 +60,12 @@ .and_return(logged_in) end - context "when being logged in" do - it "is true if no other user is available" do + context 'when being logged in' do + it 'is true if no other user is available' do expect(instance).to be_available end - it "is true if there is another user selectable" do + it 'is true if there is another user selectable' do allow(principal_loader) .to receive(:user_values) .and_return([[nil, user_1.id.to_s]]) @@ -74,14 +74,14 @@ end end - context "when not being logged in" do + context 'when not being logged in' do let(:logged_in) { false } - it "is false if no other user is available" do + it 'is false if no other user is available' do expect(instance).not_to be_available end - it "is true if there is another user selectable" do + it 'is true if there is another user selectable' do allow(principal_loader) .to receive(:user_values) .and_return([[nil, user_1.id.to_s]]) @@ -91,7 +91,7 @@ end end - describe "#allowed_values" do + describe '#allowed_values' do let(:logged_in) { true } before do @@ -100,21 +100,21 @@ .and_return(logged_in) end - context "when being logged in" do - it "returns the me value and the available users" do + context 'when being logged in' do + it 'returns the me value and the available users' do allow(principal_loader) .to receive(:user_values) .and_return([[nil, user_1.id.to_s]]) expect(instance.allowed_values) - .to contain_exactly([I18n.t(:label_me), "me"], [nil, user_1.id.to_s]) + .to contain_exactly([I18n.t(:label_me), 'me'], [nil, user_1.id.to_s]) end end - context "when not being logged in" do + context 'when not being logged in' do let(:logged_in) { false } - it "returns the available users" do + it 'returns the available users' do allow(principal_loader) .to receive(:user_values) .and_return([[nil, user_1.id.to_s]]) diff --git a/spec/models/queries/work_packages/filter/blocked_filter_spec.rb b/spec/models/queries/work_packages/filter/blocked_filter_spec.rb index a98aad0f3586..9641d7630206 100644 --- a/spec/models/queries/work_packages/filter/blocked_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/blocked_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::BlockedFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :blocked } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :blocked } end end diff --git a/spec/models/queries/work_packages/filter/blocks_filter_spec.rb b/spec/models/queries/work_packages/filter/blocks_filter_spec.rb index 911a492ddded..d0540a195a85 100644 --- a/spec/models/queries/work_packages/filter/blocks_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/blocks_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::BlocksFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :blocks } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { class_key } end end diff --git a/spec/models/queries/work_packages/filter/category_filter_spec.rb b/spec/models/queries/work_packages/filter/category_filter_spec.rb index 30fab48cb68a..f1e83ad435cc 100644 --- a/spec/models/queries/work_packages/filter/category_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/category_filter_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::CategoryFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :category_id } - describe "#available?" do - context "within a project" do + describe '#available?' do + context 'within a project' do before do allow(project) .to receive_message_chain(:categories, :exists?) .and_return true end - it "is true" do + it 'is true' do expect(instance).to be_available end - it "is false without a type" do + it 'is false without a type' do allow(project) .to receive_message_chain(:categories, :exists?) .and_return false @@ -54,16 +54,16 @@ end end - context "without a project" do + context 'without a project' do let(:project) { nil } - it "is false" do + it 'is false' do expect(instance).not_to be_available end end end - describe "#allowed_values" do + describe '#allowed_values' do let(:category) { build_stubbed(:category) } before do @@ -72,13 +72,13 @@ .and_return [category] end - it "returns an array of type options" do + it 'returns an array of type options' do expect(instance.allowed_values) .to contain_exactly([category.name, category.id.to_s]) end end - describe "#value_objects" do + describe '#value_objects' do let(:category1) { build_stubbed(:category) } let(:category2) { build_stubbed(:category) } @@ -90,14 +90,14 @@ instance.values = [category2.id.to_s] end - it "returns an array of category" do + it 'returns an array of category' do expect(instance.value_objects) .to contain_exactly(category2) end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end diff --git a/spec/models/queries/work_packages/filter/comment_filter_spec.rb b/spec/models/queries/work_packages/filter/comment_filter_spec.rb index c2c5570323be..fb1bdcdd184b 100644 --- a/spec/models/queries/work_packages/filter/comment_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/comment_filter_spec.rb @@ -26,43 +26,43 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::CommentFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :text } let(:class_key) { :comment } - describe "#available?" do - it "is available" do + describe '#available?' do + it 'is available' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#valid_values!" do - it "is a noop" do - instance.values = ["none", "is", "changed"] + describe '#valid_values!' do + it 'is a noop' do + instance.values = ['none', 'is', 'changed'] instance.valid_values! expect(instance.values) - .to contain_exactly("none", "is", "changed") + .to contain_exactly('none', 'is', 'changed') end end - describe "#available_operators" do - it "supports ~ and !~" do + describe '#available_operators' do + it 'supports ~ and !~' do expect(instance.available_operators) .to eql [Queries::Operators::Contains, Queries::Operators::NotContains] end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/created_at_filter_spec.rb b/spec/models/queries/work_packages/filter/created_at_filter_spec.rb index 3d46c7248449..87fbccfc3cfd 100644 --- a/spec/models/queries/work_packages/filter/created_at_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/created_at_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::CreatedAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :datetime_past } let(:class_key) { :created_at } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/custom_fields/contains_text_custom_field_filter_spec.rb b/spec/models/queries/work_packages/filter/custom_fields/contains_text_custom_field_filter_spec.rb index 4b2ac70f775e..ecd7b85ca73e 100644 --- a/spec/models/queries/work_packages/filter/custom_fields/contains_text_custom_field_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/custom_fields/contains_text_custom_field_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::CustomFieldFilter, - "with contains filter (Regression test #28348)" do + 'with contains filter (Regression test #28348)' do let(:cf_accessor) { custom_field.column_name } let(:query) { build_stubbed(:query, project:) } let(:instance) do @@ -42,7 +42,7 @@ work_package_custom_fields: [custom_field]) end let(:custom_field) do - create(:issue_custom_field, :text, name: "LongText") + create(:issue_custom_field, :text, name: 'LongText') end let(:type) { create(:type_standard, custom_fields: [custom_field]) } @@ -50,20 +50,20 @@ create(:work_package, type:, project:, - custom_values: { custom_field.id => "foo" }) + custom_values: { custom_field.id => 'foo' }) end let!(:wp_not_contains) do create(:work_package, type:, project:, - custom_values: { custom_field.id => "bar" }) + custom_values: { custom_field.id => 'bar' }) end let!(:wp_empty) do create(:work_package, type:, project:, - custom_values: { custom_field.id => "" }) + custom_values: { custom_field.id => '' }) end let!(:wp_nil) do @@ -75,19 +75,19 @@ subject { WorkPackage.where(instance.where) } - describe "contains" do - let(:operator) { "~" } + describe 'contains' do + let(:operator) { '~' } - it "returns the one matching work package" do + it 'returns the one matching work package' do expect(subject) .to contain_exactly(wp_contains) end end - describe "not contains" do - let(:operator) { "!~" } + describe 'not contains' do + let(:operator) { '!~' } - it "returns the three non-matching work package" do + it 'returns the three non-matching work package' do expect(subject) .to contain_exactly(wp_not_contains, wp_empty, wp_nil) end diff --git a/spec/models/queries/work_packages/filter/custom_fields/custom_field_filter_spec.rb b/spec/models/queries/work_packages/filter/custom_fields/custom_field_filter_spec.rb index 60e8b4b3a53a..6ca7debe36bd 100644 --- a/spec/models/queries/work_packages/filter/custom_fields/custom_field_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/custom_fields/custom_field_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::CustomFieldFilter do let(:project) { build_stubbed(:project) } @@ -53,7 +53,7 @@ let(:query) { build_stubbed(:query, project:) } let(:cf_accessor) { custom_field.column_name } let(:instance) do - described_class.create!(name: cf_accessor, operator: "=", context: query) + described_class.create!(name: cf_accessor, operator: '=', context: query) end let(:instance_key) { nil } @@ -65,67 +65,67 @@ .and_return(all_custom_fields) end - describe "invalid custom field" do - let(:cf_accessor) { "cf_100" } + describe 'invalid custom field' do + let(:cf_accessor) { 'cf_100' } let(:all_custom_fields) { [] } - it "raises exception" do + it 'raises exception' do expect { instance }.to raise_error(Queries::Filters::InvalidError) end end - describe ".valid?" do + describe '.valid?' do let(:custom_field) { string_wp_custom_field } before do - instance.values = ["bogus"] + instance.values = ['bogus'] end - shared_examples_for "custom field type dependent validity" do - context "with a string custom field" do - it "is valid" do + shared_examples_for 'custom field type dependent validity' do + context 'with a string custom field' do + it 'is valid' do expect(instance).to be_valid end end - context "with a list custom field" do + context 'with a list custom field' do let(:custom_field) { list_wp_custom_field } before do instance.values = [list_wp_custom_field.possible_values.first.id] end - it "is valid" do + it 'is valid' do expect(instance).to be_valid end it "is invalid if the value is not one of the custom field's possible values" do - instance.values = ["bogus"] + instance.values = ['bogus'] expect(instance).not_to be_valid end end end - context "within a project" do - it_behaves_like "custom field type dependent validity" + context 'within a project' do + it_behaves_like 'custom field type dependent validity' end - context "without a project" do + context 'without a project' do let(:project) { nil } - it_behaves_like "custom field type dependent validity" + it_behaves_like 'custom field type dependent validity' end end - describe ".key" do - it "is a regular expression" do + describe '.key' do + it 'is a regular expression' do expect(described_class.key).to eql(/cf_(\d+)/) end end - describe "instance attributes" do - it "are valid" do + describe 'instance attributes' do + it 'are valid' do all_custom_fields.each do |cf| filter = described_class.create!(name: cf.column_name) expect(filter.name).to eql(cf.column_name.to_sym) @@ -133,138 +133,138 @@ end end - describe "#type" do - context "integer" do + describe '#type' do + context 'integer' do let(:cf_accessor) { int_wp_custom_field.column_name } - it "is integer for an integer" do + it 'is integer for an integer' do expect(instance.type) .to be(:integer) end end - context "float" do + context 'float' do let(:cf_accessor) { float_wp_custom_field.column_name } - it "is integer for a float" do + it 'is integer for a float' do expect(instance.type) .to be(:float) end end - context "text" do + context 'text' do let(:cf_accessor) { text_wp_custom_field.column_name } - it "is text for a text" do + it 'is text for a text' do expect(instance.type) .to be(:text) end end - context "list optional" do + context 'list optional' do let(:cf_accessor) { list_wp_custom_field.column_name } - it "is list_optional for a list" do + it 'is list_optional for a list' do expect(instance.type) .to be(:list_optional) end end - context "user" do + context 'user' do let(:cf_accessor) { user_wp_custom_field.column_name } - it "is list_optional for a user" do + it 'is list_optional for a user' do expect(instance.type) .to be(:list_optional) end end - context "version" do + context 'version' do let(:cf_accessor) { version_wp_custom_field.column_name } - it "is list_optional for a version" do + it 'is list_optional for a version' do expect(instance.type) .to be(:list_optional) end end - context "version" do + context 'version' do let(:cf_accessor) { date_wp_custom_field.column_name } - it "is date for a date" do + it 'is date for a date' do expect(instance.type) .to be(:date) end end - context "bool" do + context 'bool' do let(:cf_accessor) { bool_wp_custom_field.column_name } - it "is list for a bool" do + it 'is list for a bool' do expect(instance.type) .to be(:list) end end - context "string" do + context 'string' do let(:cf_accessor) { string_wp_custom_field.column_name } - it "is string for a string" do + it 'is string for a string' do expect(instance.type) .to be(:string) end end end - describe "#human_name" do - it "is the field name" do + describe '#human_name' do + it 'is the field name' do expect(instance.human_name) .to eql(list_wp_custom_field.name) end end - describe "#allowed_values" do - context "integer" do + describe '#allowed_values' do + context 'integer' do let(:cf_accessor) { int_wp_custom_field.column_name } - it "is nil for an integer" do + it 'is nil for an integer' do expect(instance.allowed_values) .to be_nil end end - context "float" do + context 'float' do let(:cf_accessor) { float_wp_custom_field.column_name } - it "is integer for a float" do + it 'is integer for a float' do expect(instance.allowed_values) .to be_nil end end - context "text" do + context 'text' do let(:cf_accessor) { text_wp_custom_field.column_name } - it "is text for a text" do + it 'is text for a text' do expect(instance.allowed_values) .to be_nil end end - context "list" do + context 'list' do let(:cf_accessor) { list_wp_custom_field.column_name } - it "is list_optional for a list" do + it 'is list_optional for a list' do expect(instance.allowed_values) .to match_array(list_wp_custom_field.custom_options.map { |co| [co.value, co.id.to_s] }) end end - context "user" do + context 'user' do let(:cf_accessor) { user_wp_custom_field.column_name } - it "is list_optional for a user" do - bogus_return_value = ["user1", "user2"] + it 'is list_optional for a user' do + bogus_return_value = ['user1', 'user2'] allow(user_wp_custom_field) .to receive(:possible_values_options) .with(project) @@ -276,11 +276,11 @@ end end - context "version" do + context 'version' do let(:cf_accessor) { version_wp_custom_field.column_name } - it "is list_optional for a version" do - bogus_return_value = ["version1", "version2"] + it 'is list_optional for a version' do + bogus_return_value = ['version1', 'version2'] allow(version_wp_custom_field) .to receive(:possible_values_options) .with(project) @@ -292,37 +292,37 @@ end end - context "date" do + context 'date' do let(:cf_accessor) { date_wp_custom_field.column_name } - it "is nil for a date" do + it 'is nil for a date' do expect(instance.allowed_values) .to be_nil end end - context "bool" do + context 'bool' do let(:cf_accessor) { bool_wp_custom_field.column_name } - it "is list for a bool" do + it 'is list for a bool' do expect(instance.allowed_values) .to contain_exactly([I18n.t(:general_text_yes), OpenProject::Database::DB_VALUE_TRUE], [I18n.t(:general_text_no), OpenProject::Database::DB_VALUE_FALSE]) end end - context "string" do + context 'string' do let(:cf_accessor) { string_wp_custom_field.column_name } - it "is nil for a string" do + it 'is nil for a string' do expect(instance.allowed_values) .to be_nil end end end - describe ".all_for" do - context "with a project" do + describe '.all_for' do + context 'with a project' do before do filter_scope = instance_double(ActiveRecord::Relation) @@ -342,7 +342,7 @@ .and_return(all_custom_fields) end - it "returns a list with a filter for every custom field" do + it 'returns a list with a filter for every custom field' do filters = described_class.all_for(query) all_custom_fields.each do |cf| @@ -350,7 +350,7 @@ end end - it "sets the project as context for every created cf filter" do + it 'sets the project as context for every created cf filter' do filters = described_class.all_for(query) all_custom_fields.each do |cf| @@ -360,7 +360,7 @@ end end - context "without a project" do + context 'without a project' do before do query.project = nil @@ -375,7 +375,7 @@ string_wp_custom_field]) end - it "returns a list with a filter for every custom field" do + it 'returns a list with a filter for every custom field' do filters = described_class.all_for(query) [list_wp_custom_field, @@ -396,30 +396,30 @@ end end - context "list cf" do - describe "#ar_object_filter? / #value_objects" do + context 'list cf' do + describe '#ar_object_filter? / #value_objects' do let(:custom_field) { list_wp_custom_field } - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do before do instance.values = [custom_field.custom_options.last.id, custom_field.custom_options.first.id] end - it "returns an array with custom classes" do + it 'returns an array with custom classes' do expect(instance.value_objects) .to contain_exactly(custom_field.custom_options.last, custom_field.custom_options.first) end - it "ignores invalid values" do - instance.values = ["invalid", + it 'ignores invalid values' do + instance.values = ['invalid', custom_field.custom_options.last.id] expect(instance.value_objects) @@ -428,41 +428,41 @@ end end - context "bool cf" do + context 'bool cf' do let(:custom_field) { bool_wp_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "int cf" do + context 'int cf' do let(:custom_field) { int_wp_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "float cf" do + context 'float cf' do let(:custom_field) { float_wp_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "text cf" do + context 'text cf' do let(:custom_field) { text_wp_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "user cf" do + context 'user cf' do let(:custom_field) { user_wp_custom_field } - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:user1) { build_stubbed(:user) } let(:user2) { build_stubbed(:user) } @@ -475,24 +475,24 @@ instance.values = [user1.id.to_s, user2.id.to_s] end - it "returns an array with users" do + it 'returns an array with users' do expect(instance.value_objects) .to contain_exactly(user1, user2) end end end - context "version cf" do + context 'version cf' do let(:custom_field) { version_wp_custom_field } - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:version1) { build_stubbed(:version) } let(:version2) { build_stubbed(:version) } @@ -505,23 +505,23 @@ instance.values = [version1.id.to_s, version2.id.to_s] end - it "returns an array with users" do + it 'returns an array with users' do expect(instance.value_objects) .to contain_exactly(version1, version2) end end end - context "date cf" do + context 'date cf' do let(:custom_field) { date_wp_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end - context "string cf" do + context 'string cf' do let(:custom_field) { string_wp_custom_field } - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end end diff --git a/spec/models/queries/work_packages/filter/dates_interval_filter_spec.rb b/spec/models/queries/work_packages/filter/dates_interval_filter_spec.rb index ac5a03c2b1bc..44b7554828a8 100644 --- a/spec/models/queries/work_packages/filter/dates_interval_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/dates_interval_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DatesIntervalFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :date } let(:class_key) { :dates_interval } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/description_filter_spec.rb b/spec/models/queries/work_packages/filter/description_filter_spec.rb index cfe4f94e3509..e3b2bfdb2619 100644 --- a/spec/models/queries/work_packages/filter/description_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/description_filter_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DescriptionFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :text } let(:class_key) { :description } - describe "#available?" do - it "is available" do + describe '#available?' do + it 'is available' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#valid_values!" do - it "is a noop" do - instance.values = ["none", "is", "changed"] + describe '#valid_values!' do + it 'is a noop' do + instance.values = ['none', 'is', 'changed'] instance.valid_values! expect(instance.values) - .to contain_exactly("none", "is", "changed") + .to contain_exactly('none', 'is', 'changed') end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/done_ratio_filter_spec.rb b/spec/models/queries/work_packages/filter/done_ratio_filter_spec.rb index 47b1a3d935a5..cf5c50faf614 100644 --- a/spec/models/queries/work_packages/filter/done_ratio_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/done_ratio_filter_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DoneRatioFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :integer } let(:class_key) { :done_ratio } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end diff --git a/spec/models/queries/work_packages/filter/due_date_filter_spec.rb b/spec/models/queries/work_packages/filter/due_date_filter_spec.rb index cc1e5bec6017..c011f9bfb4bb 100644 --- a/spec/models/queries/work_packages/filter/due_date_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/due_date_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DueDateFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :date } let(:class_key) { :due_date } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/duplicated_filter_spec.rb b/spec/models/queries/work_packages/filter/duplicated_filter_spec.rb index 3df4458a01a3..4efd9fe0679d 100644 --- a/spec/models/queries/work_packages/filter/duplicated_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/duplicated_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DuplicatedFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :duplicated } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :duplicated } end end diff --git a/spec/models/queries/work_packages/filter/duplicates_filter_spec.rb b/spec/models/queries/work_packages/filter/duplicates_filter_spec.rb index d9d021459773..6124cef7a5a1 100644 --- a/spec/models/queries/work_packages/filter/duplicates_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/duplicates_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DuplicatesFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :duplicates } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :duplicates } end end diff --git a/spec/models/queries/work_packages/filter/duration_filter_spec.rb b/spec/models/queries/work_packages/filter/duration_filter_spec.rb index 5f63c90d4123..fda515ab51a0 100644 --- a/spec/models/queries/work_packages/filter/duration_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/duration_filter_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::DurationFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :integer } let(:class_key) { :duration } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' - describe "#where" do + describe '#where' do # TODO: 0 duration should not happen in 12.x. Should we remove it? let!(:work_package_zero_duration) { create(:work_package, duration: 0) } let!(:work_package_no_duration) { create(:work_package, duration: nil) } @@ -62,12 +62,12 @@ instance.operator = Queries::Operators::None.to_sym.to_s end - it "finds zero and none values also including milestones" do + it 'finds zero and none values also including milestones' do expect(subject).to contain_exactly(work_package_zero_duration, work_package_no_duration, work_package_with_milestone) end end - it "does not returns milestone work packages" do + it 'does not returns milestone work packages' do expect(subject).to contain_exactly(work_package_with_duration) end end diff --git a/spec/models/queries/work_packages/filter/estimated_hours_filter_spec.rb b/spec/models/queries/work_packages/filter/estimated_hours_filter_spec.rb index c8539c034d40..6cf763e9f85a 100644 --- a/spec/models/queries/work_packages/filter/estimated_hours_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/estimated_hours_filter_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::EstimatedHoursFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :integer } let(:class_key) { :estimated_hours } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' - describe "#where" do + describe '#where' do let!(:work_package_zero_hour) { create(:work_package, estimated_hours: 0) } let!(:work_package_no_hours) { create(:work_package, estimated_hours: nil) } let!(:work_package_with_hours) { create(:work_package, estimated_hours: 1) } @@ -57,7 +57,7 @@ instance.operator = Queries::Operators::None.to_sym.to_s end - it "finds zero and none values" do + it 'finds zero and none values' do expect(WorkPackage.where(instance.where)).to contain_exactly(work_package_zero_hour, work_package_no_hours) end end diff --git a/spec/models/queries/work_packages/filter/follows_filter_spec.rb b/spec/models/queries/work_packages/filter/follows_filter_spec.rb index e9a0fd704477..789a36fdfb7b 100644 --- a/spec/models/queries/work_packages/filter/follows_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/follows_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::FollowsFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :follows } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :follows } end end diff --git a/spec/models/queries/work_packages/filter/group_filter_spec.rb b/spec/models/queries/work_packages/filter/group_filter_spec.rb index 8868861fa551..5be366010b34 100644 --- a/spec/models/queries/work_packages/filter/group_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/group_filter_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::GroupFilter do let(:group) { build_stubbed(:group) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :member_of_group } - let(:name) { I18n.t("query_fields.member_of_group") } + let(:name) { I18n.t('query_fields.member_of_group') } - describe "#available?" do - it "is true if any group exists" do + describe '#available?' do + it 'is true if any group exists' do allow(Group) .to receive(:exists?) .and_return true @@ -45,7 +45,7 @@ expect(instance).to be_available end - it "is false if no group exists" do + it 'is false if no group exists' do allow(Group) .to receive(:exists?) .and_return false @@ -54,27 +54,27 @@ end end - describe "#allowed_values" do + describe '#allowed_values' do before do allow(Group) .to receive(:all) .and_return [group] end - it "is an array of group values" do + it 'is an array of group values' do expect(instance.allowed_values) .to contain_exactly([group.name, group.id.to_s]) end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:group2) { build_stubbed(:group) } before do @@ -85,7 +85,7 @@ instance.values = [group2.id.to_s] end - it "returns an array of groups" do + it 'returns an array of groups' do expect(instance.value_objects) .to contain_exactly(group2) end diff --git a/spec/models/queries/work_packages/filter/id_filter_spec.rb b/spec/models/queries/work_packages/filter/id_filter_spec.rb index bfece6f4c3f0..4ebcc8e0d044 100644 --- a/spec/models/queries/work_packages/filter/id_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/id_filter_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::IdFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :id } - describe "#where" do + describe '#where' do let!(:visible_wp) { create(:work_package) } let!(:other_wp) { create(:work_package) } before do instance.values = [visible_wp.id.to_s] - instance.operator = "=" + instance.operator = '=' end - it "filters" do + it 'filters' do expect(WorkPackage.where(instance.where)) .to contain_exactly(visible_wp) end diff --git a/spec/models/queries/work_packages/filter/includes_filter_spec.rb b/spec/models/queries/work_packages/filter/includes_filter_spec.rb index a4a1ed88790b..65109f8aa88f 100644 --- a/spec/models/queries/work_packages/filter/includes_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/includes_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::IncludesFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :includes } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :includes } end end diff --git a/spec/models/queries/work_packages/filter/manual_sort_filter_spec.rb b/spec/models/queries/work_packages/filter/manual_sort_filter_spec.rb index ed2561d687d0..6b5079f7605b 100644 --- a/spec/models/queries/work_packages/filter/manual_sort_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/manual_sort_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::ManualSortFilter do let!(:in_order) { create(:work_package) } @@ -37,11 +37,11 @@ let(:query_double) { double(Query, ordered_work_packages: ar_double) } let(:instance) do - described_class.create!(name: :manual_sort, context: query_double, operator: "ow", values: []) + described_class.create!(name: :manual_sort, context: query_double, operator: 'ow', values: []) end - describe "#where" do - it "filters based on the manual sort order" do + describe '#where' do + it 'filters based on the manual sort order' do expect(WorkPackage.where(instance.where)) .to contain_exactly(in_order2, in_order) end diff --git a/spec/models/queries/work_packages/filter/milestone_filter_spec.rb b/spec/models/queries/work_packages/filter/milestone_filter_spec.rb index 172644af9463..b2461b98b4d2 100644 --- a/spec/models/queries/work_packages/filter/milestone_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/milestone_filter_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::MilestoneFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :is_milestone } - describe "#available?" do - context "within a project" do + describe '#available?' do + context 'within a project' do before do allow(project) .to receive_message_chain(:rolled_up_types, :exists?) .and_return true end - it "is true" do + it 'is true' do expect(instance).to be_available end - it "is false without a type" do + it 'is false without a type' do allow(project) .to receive_message_chain(:rolled_up_types, :exists?) .and_return false @@ -54,7 +54,7 @@ end end - context "without a project" do + context 'without a project' do let(:project) { nil } before do @@ -63,11 +63,11 @@ .and_return true end - it "is true" do + it 'is true' do expect(instance).to be_available end - it "is false without a type" do + it 'is false without a type' do allow(Type) .to receive_message_chain(:order, :exists?) .and_return false @@ -78,18 +78,18 @@ end end - it_behaves_like "boolean query filter", scope: false do + it_behaves_like 'boolean query filter', scope: false do let(:model) { WorkPackage.unscoped } let(:attribute) { :id } - describe "#scope" do - context "for the true value" do + describe '#scope' do + context 'for the true value' do let(:values) { [OpenProject::Database::DB_VALUE_TRUE] } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = 'type_id IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' expect(instance.where).to eql expected @@ -97,9 +97,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = 'type_id NOT IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' expect(instance.where).to eql expected @@ -107,13 +107,13 @@ end end - context "for the false value" do + context 'for the false value' do let(:values) { [OpenProject::Database::DB_VALUE_FALSE] } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = 'type_id NOT IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' expect(instance.where).to eql expected @@ -121,9 +121,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = 'type_id IN (SELECT "types"."id" FROM "types" WHERE "types"."is_milestone" = TRUE ORDER BY position ASC)' expect(instance.where).to eql expected diff --git a/spec/models/queries/work_packages/filter/parent_filter_spec.rb b/spec/models/queries/work_packages/filter/parent_filter_spec.rb index c94216430f2f..58c294a323ad 100644 --- a/spec/models/queries/work_packages/filter/parent_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/parent_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::ParentFilter do let(:project) { build_stubbed(:project) } @@ -34,7 +34,7 @@ build_stubbed(:query, project:) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:class_key) { :parent } let(:type) { :list } @@ -42,9 +42,9 @@ instance.context = query end - describe "#available?" do - context "within a project" do - it "is true if any work package exists and is visible" do + describe '#available?' do + context 'within a project' do + it 'is true if any work package exists and is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :exists?) .with(no_args) @@ -55,7 +55,7 @@ expect(instance).to be_available end - it "is false if no work package exists/ is visible" do + it 'is false if no work package exists/ is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :exists?) .with(no_args) @@ -67,10 +67,10 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "is true if any work package exists and is visible" do + it 'is true if any work package exists and is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :exists?) .with(no_args) @@ -79,7 +79,7 @@ expect(instance).to be_available end - it "is false if no work package exists/ is visible" do + it 'is false if no work package exists/ is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :exists?) .with(no_args) @@ -90,22 +90,22 @@ end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance).to be_ar_object_filter end end - describe "#allowed_values" do - it "raises an error" do + describe '#allowed_values' do + it 'raises an error' do expect { instance.allowed_values }.to raise_error NotImplementedError end end - describe "#value_object" do + describe '#value_object' do let(:visible_wp) { build_stubbed(:work_package) } - it "returns the work package for the values" do + it 'returns the work package for the values' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :find) .with(no_args) @@ -119,7 +119,7 @@ context "with the 'templated' value" do before do - instance.values = ["templated"] + instance.values = ['templated'] allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :find) @@ -129,26 +129,26 @@ .and_return([]) end - it "returns a TemplatedValue object" do + it 'returns a TemplatedValue object' do expect(instance.value_objects.length).to be 1 - expect(instance.value_objects[0].id).to eql "{id}" + expect(instance.value_objects[0].id).to eql '{id}' end end end - describe "#allowed_objects" do - it "raises an error" do + describe '#allowed_objects' do + it 'raises an error' do expect { instance.allowed_objects }.to raise_error NotImplementedError end end - describe "#valid_values!" do + describe '#valid_values!' do let(:visible_wp) { build_stubbed(:work_package) } let(:invisible_wp) { build_stubbed(:work_package) } - context "within a project" do - it "removes all non existing/non visible ids" do - instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, "999999"] + context 'within a project' do + it 'removes all non existing/non visible ids' do + instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999'] allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :where, :pluck) @@ -165,11 +165,11 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "removes all non existing/non visible ids" do - instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, "999999"] + it 'removes all non existing/non visible ids' do + instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999'] allow(WorkPackage) .to receive_message_chain(:visible, :where, :pluck) @@ -186,26 +186,26 @@ end end - describe "#validate" do + describe '#validate' do let(:visible_wp) { build_stubbed(:work_package) } let(:invisible_wp) { build_stubbed(:work_package) } - context "with old templated value" do - it "is still valid" do + context 'with old templated value' do + it 'is still valid' do instance.values = %w[templated] expect(instance).to be_valid end end - context "with new templated value" do - it "is still valid" do + context 'with new templated value' do + it 'is still valid' do instance.values = %w[{id}] expect(instance).to be_valid end end - context "within a project" do - it "is valid if only visible wps are values" do + context 'within a project' do + it 'is valid if only visible wps are values' do instance.values = [visible_wp.id.to_s] allow(WorkPackage) @@ -219,7 +219,7 @@ expect(instance).to be_valid end - it "is invalid if invisible wps are values" do + it 'is invalid if invisible wps are values' do instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s] allow(WorkPackage) @@ -234,10 +234,10 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "is valid if only visible wps are values" do + it 'is valid if only visible wps are values' do instance.values = [visible_wp.id.to_s] allow(WorkPackage) @@ -250,7 +250,7 @@ expect(instance).to be_valid end - it "is invalid if invisible wps are values" do + it 'is invalid if invisible wps are values' do instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s] allow(WorkPackage) @@ -265,17 +265,17 @@ end end - describe "#where and #includes" do + describe '#where and #includes' do let(:parent) { create(:work_package) } let(:visible_wp) { create(:work_package, parent:) } before do visible_wp instance.values = [parent.id.to_s] - instance.operator = "=" + instance.operator = '=' end - it "filters" do + it 'filters' do scope = WorkPackage .references(instance.includes) .includes(instance.includes) diff --git a/spec/models/queries/work_packages/filter/partof_filter_spec.rb b/spec/models/queries/work_packages/filter/partof_filter_spec.rb index 5a136f65c0b1..95a61eda313a 100644 --- a/spec/models/queries/work_packages/filter/partof_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/partof_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::PartofFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :partof } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :partof } end end diff --git a/spec/models/queries/work_packages/filter/precedes_filter_spec.rb b/spec/models/queries/work_packages/filter/precedes_filter_spec.rb index 79a674c7d6dd..b4edfbc3fd86 100644 --- a/spec/models/queries/work_packages/filter/precedes_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/precedes_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::PrecedesFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :precedes } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :precedes } end end diff --git a/spec/models/queries/work_packages/filter/principal_loader_spec.rb b/spec/models/queries/work_packages/filter/principal_loader_spec.rb index 4436d36ee3e2..029f4a6bdf56 100644 --- a/spec/models/queries/work_packages/filter/principal_loader_spec.rb +++ b/spec/models/queries/work_packages/filter/principal_loader_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::PrincipalLoader do let(:user) { build_stubbed(:user) } @@ -35,19 +35,19 @@ let(:project) { build_stubbed(:project) } let(:instance) { described_class.new(project) } - context "with a project" do + context 'with a project' do before do allow(project) .to receive(:principals) .and_return([user, group, placeholder_user]) end - describe "#user_values" do - it "returns a user array" do + describe '#user_values' do + it 'returns a user array' do expect(instance.user_values).to contain_exactly([nil, user.id.to_s]) end - it "is empty if no user exists" do + it 'is empty if no user exists' do allow(project) .to receive(:principals) .and_return([]) @@ -56,12 +56,12 @@ end end - describe "#group_values" do - it "returns a group array" do + describe '#group_values' do + it 'returns a group array' do expect(instance.group_values).to contain_exactly([nil, group.id.to_s]) end - it "is empty if no group exists" do + it 'is empty if no group exists' do allow(project) .to receive(:principals) .and_return([]) @@ -70,13 +70,13 @@ end end - describe "#principal_values" do - it "returns an array of principals as [name, id]" do + describe '#principal_values' do + it 'returns an array of principals as [name, id]' do expect(instance.principal_values) .to contain_exactly([nil, group.id.to_s], [nil, user.id.to_s], [nil, placeholder_user.id.to_s]) end - it "is empty if no principal exists" do + it 'is empty if no principal exists' do allow(project) .to receive(:principals) .and_return([]) @@ -86,7 +86,7 @@ end end - context "without a project" do + context 'without a project' do let(:project) { nil } let(:visible_projects) { [build_stubbed(:project)] } let(:matching_principals) { [user, group, placeholder_user] } @@ -101,44 +101,44 @@ .and_return(matching_principals) end - describe "#user_values" do - it "returns a user array" do + describe '#user_values' do + it 'returns a user array' do expect(instance.user_values).to contain_exactly([nil, user.id.to_s]) end - context "if no user exists" do + context 'if no user exists' do let(:matching_principals) { [group] } - it "is empty" do + it 'is empty' do expect(instance.user_values).to be_empty end end end - describe "#group_values" do - it "returns a group array" do + describe '#group_values' do + it 'returns a group array' do expect(instance.group_values).to contain_exactly([nil, group.id.to_s]) end - context "if no group exists" do + context 'if no group exists' do let(:matching_principals) { [user] } - it "is empty" do + it 'is empty' do expect(instance.group_values).to be_empty end end end - describe "#principal_values" do - it "returns an array of principals as [name, id]" do + describe '#principal_values' do + it 'returns an array of principals as [name, id]' do expect(instance.principal_values) .to contain_exactly([nil, group.id.to_s], [nil, user.id.to_s], [nil, placeholder_user.id.to_s]) end - context "if no principals exist" do + context 'if no principals exist' do let(:matching_principals) { [] } - it "is empty" do + it 'is empty' do expect(instance.principal_values).to be_empty end end diff --git a/spec/models/queries/work_packages/filter/priority_filter_spec.rb b/spec/models/queries/work_packages/filter/priority_filter_spec.rb index b8ba9f080ed5..ee3e02d0abe5 100644 --- a/spec/models/queries/work_packages/filter/priority_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/priority_filter_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::PriorityFilter do let(:priority) { build_stubbed(:priority) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :priority_id } - describe "#available?" do - it "is true if any group exists" do + describe '#available?' do + it 'is true if any group exists' do allow(IssuePriority) .to receive_message_chain(:active, :exists?) .and_return true @@ -44,7 +44,7 @@ expect(instance).to be_available end - it "is false if no group exists" do + it 'is false if no group exists' do allow(IssuePriority) .to receive_message_chain(:active, :exists?) .and_return false @@ -53,27 +53,27 @@ end end - describe "#allowed_values" do + describe '#allowed_values' do before do allow(IssuePriority) .to receive(:active) .and_return [priority] end - it "is an array of group values" do + it 'is an array of group values' do expect(instance.allowed_values) .to contain_exactly([priority.name, priority.id.to_s]) end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:priority2) { build_stubbed(:priority) } before do @@ -84,7 +84,7 @@ instance.values = [priority2.id.to_s] end - it "returns an array of priorities" do + it 'returns an array of priorities' do expect(instance.value_objects) .to contain_exactly(priority2) end diff --git a/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb b/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb index b8d9c8b18764..8625fd359199 100644 --- a/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb +++ b/spec/models/queries/work_packages/filter/project_filter_instance_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::ProjectFilter do let(:query) { build(:query) } let(:instance) do - described_class.create!(name: "project", context: query, operator: "=", values: []) + described_class.create!(name: 'project', context: query, operator: '=', values: []) end - describe "#allowed_values" do + describe '#allowed_values' do let!(:project) { create(:project) } let!(:archived_project) { create(:project, active: false) } @@ -45,7 +45,7 @@ login_as user end - it "does not include the archived project (Regression #36026)" do + it 'does not include the archived project (Regression #36026)' do expect(instance.allowed_values) .to contain_exactly([project.name, project.id.to_s]) end diff --git a/spec/models/queries/work_packages/filter/project_filter_spec.rb b/spec/models/queries/work_packages/filter/project_filter_spec.rb index 99de249d65f5..8f9946ef221f 100644 --- a/spec/models/queries/work_packages/filter/project_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/project_filter_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::ProjectFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :project_id } let(:visible_projects) { build_stubbed_list(:project, 2) } @@ -56,42 +56,42 @@ end end - describe "#available?" do - shared_examples_for "filter availability" do - context "when able to see projects" do - it "is true" do + describe '#available?' do + shared_examples_for 'filter availability' do + context 'when able to see projects' do + it 'is true' do expect(instance).to be_available end end - context "when not able to see projects" do + context 'when not able to see projects' do let(:visible_projects) { [] } - it "is true" do + it 'is true' do expect(instance).not_to be_available end end end - context "when inside a project" do + context 'when inside a project' do # Used to be always false hence still checking. - it_behaves_like "filter availability" + it_behaves_like 'filter availability' end - context "when outside of a project" do + context 'when outside of a project' do let(:project) { nil } - it_behaves_like "filter availability" + it_behaves_like 'filter availability' end end - describe "#allowed_values" do + describe '#allowed_values' do let(:project) { nil } let(:parent) { build_stubbed(:project, id: 1) } let(:child) { build_stubbed(:project, parent:, id: 2) } let(:visible_projects) { [parent, child] } - it "is an array of group values" do + it 'is an array of group values' do allow(Project) .to receive(:project_tree) .with(visible_projects) @@ -103,17 +103,17 @@ end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:selected) { visible_projects.first } let(:visible_descendants) { [] } - let(:descendants) { double("Project", visible: visible_descendants) } # rubocop:disable RSpec/VerifiedDoubles + let(:descendants) { double('Project', visible: visible_descendants) } # rubocop:disable RSpec/VerifiedDoubles before do allow(selected).to receive(:descendants).and_return(descendants) @@ -121,16 +121,16 @@ instance.values = [selected.id.to_s] end - it "returns an array of projects" do + it 'returns an array of projects' do expect(instance.value_objects) .to contain_exactly(selected) end - context "with a visible child" do + context 'with a visible child' do let(:child) { build_stubbed(:project, parent: selected, id: 2134) } let(:visible_descendants) { [child] } - it "still only returns the parent object" do + it 'still only returns the parent object' do expect(instance.value_objects) .to contain_exactly(selected) end diff --git a/spec/models/queries/work_packages/filter/relates_filter_spec.rb b/spec/models/queries/work_packages/filter/relates_filter_spec.rb index 4c85e533ace7..76f43e8bb13b 100644 --- a/spec/models/queries/work_packages/filter/relates_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/relates_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::RelatesFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :relates } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :relates } end end diff --git a/spec/models/queries/work_packages/filter/required_filter_spec.rb b/spec/models/queries/work_packages/filter/required_filter_spec.rb index 4c57d1bfef9d..ffd55989516c 100644 --- a/spec/models/queries/work_packages/filter/required_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/required_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::RequiredFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :required } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :required } end end diff --git a/spec/models/queries/work_packages/filter/requires_filter_spec.rb b/spec/models/queries/work_packages/filter/requires_filter_spec.rb index c071bce2c5d5..39e54409e840 100644 --- a/spec/models/queries/work_packages/filter/requires_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/requires_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::RequiresFilter do - it_behaves_like "filter by work package id" do + it_behaves_like 'filter by work package id' do let(:class_key) { :requires } - it_behaves_like "filter for relation" do + it_behaves_like 'filter for relation' do let(:relation_type) { :requires } end end diff --git a/spec/models/queries/work_packages/filter/responsible_filter_spec.rb b/spec/models/queries/work_packages/filter/responsible_filter_spec.rb index 5233fd9eb5aa..7d57d1a175d3 100644 --- a/spec/models/queries/work_packages/filter/responsible_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/responsible_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::ResponsibleFilter do let(:instance) do @@ -36,27 +36,27 @@ filter end - let(:operator) { "=" } + let(:operator) { '=' } let(:values) { [] } - describe "where filter results" do + describe 'where filter results' do let(:work_package) { create(:work_package, responsible:) } let(:responsible) { create(:user) } let(:group) { create(:group) } subject { WorkPackage.where(instance.where) } - context "for the user value" do + context 'for the user value' do let(:values) { [responsible.id.to_s] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for the me value with the user being logged in" do - let(:values) { ["me"] } + context 'for the me value with the user being logged in' do + let(:values) { ['me'] } before do allow(User) @@ -64,22 +64,22 @@ .and_return(responsible) end - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end - it "returns the corrected value object" do + it 'returns the corrected value object' do objects = instance.value_objects expect(objects.size).to eq(1) - expect(objects.first.id).to eq "me" - expect(objects.first.name).to eq "me" + expect(objects.first.id).to eq 'me' + expect(objects.first.name).to eq 'me' end end - context "for the me value with another user being logged in" do - let(:values) { ["me"] } + context 'for the me value with another user being logged in' do + let(:values) { ['me'] } before do allow(User) @@ -87,16 +87,16 @@ .and_return(create(:user)) end - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for me and user values" do + context 'for me and user values' do let(:user) { create(:user) } let(:responsible2) { create(:user) } - let(:values) { [responsible.id, user.id, "me", responsible2.id] } + let(:values) { [responsible.id, user.id, 'me', responsible2.id] } before do # Order is important here for ids, @@ -111,40 +111,40 @@ .and_return(user) end - it "returns the mapped value" do + it 'returns the mapped value' do objects = instance.value_objects # The first value is guaranteed to be 'me'. # There is no order on the other values. - expect(objects.map(&:id)[0]).to eql "me" + expect(objects.map(&:id)[0]).to eql 'me' expect(objects.map(&:id)[1..-1]).to contain_exactly(responsible.id, responsible2.id) end end - context "for a group value with the group being assignee" do + context 'for a group value with the group being assignee' do let(:responsible) { group } let(:values) { [group.id.to_s] } - it "returns the work package" do + it 'returns the work package' do expect(subject) .to contain_exactly(work_package) end end - context "for a group value with a group member being assignee" do + context 'for a group value with a group member being assignee' do let(:values) { [group.id.to_s] } let(:group) { create(:group, members: responsible) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for a group value with no group member being assignee" do + context 'for a group value with no group member being assignee' do let(:values) { [group.id.to_s] } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end @@ -156,7 +156,7 @@ let(:user) { create(:user) } let(:group) { create(:group, members: user) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end @@ -167,30 +167,30 @@ let(:responsible) { group } let(:user) { create(:user) } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end - context "for an unmatched value" do - let(:values) { ["0"] } + context 'for an unmatched value' do + let(:values) { ['0'] } - it "does not return the work package" do + it 'does not return the work package' do expect(subject) .to be_empty end end end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :responsible_id } let(:user_1) { build_stubbed(:user) } let(:principal_loader) do - loader = double("principal_loader") + loader = double('principal_loader') allow(loader) .to receive(:principal_values) .and_return([]) @@ -205,7 +205,7 @@ .and_return(principal_loader) end - describe "#available?" do + describe '#available?' do let(:logged_in) { true } before do @@ -214,12 +214,12 @@ .and_return(logged_in) end - context "when being logged in" do - it "is true if no other user is available" do + context 'when being logged in' do + it 'is true if no other user is available' do expect(instance).to be_available end - it "is true if there is another user selectable" do + it 'is true if there is another user selectable' do allow(principal_loader) .to receive(:principal_values) .and_return([nil, user_1.id.to_s]) @@ -228,14 +228,14 @@ end end - context "when not being logged in" do + context 'when not being logged in' do let(:logged_in) { false } - it "is false if no other user is available" do + it 'is false if no other user is available' do expect(instance).not_to be_available end - it "is true if there is another user selectable" do + it 'is true if there is another user selectable' do allow(principal_loader) .to receive(:principal_values) .and_return([[nil, user_1.id.to_s]]) @@ -245,7 +245,7 @@ end end - describe "#allowed_values" do + describe '#allowed_values' do let(:logged_in) { true } let(:group) { build_stubbed(:group) } @@ -260,31 +260,31 @@ [nil, group.id.to_s]]) end - context "when being logged in" do - it "returns the me value, the available users, and groups" do + context 'when being logged in' do + it 'returns the me value, the available users, and groups' do expect(instance.allowed_values) - .to contain_exactly([I18n.t(:label_me), "me"], [nil, user_1.id.to_s], [nil, group.id.to_s]) + .to contain_exactly([I18n.t(:label_me), 'me'], [nil, user_1.id.to_s], [nil, group.id.to_s]) end end - context "when not being logged in" do + context 'when not being logged in' do let(:logged_in) { false } - it "returns the available users" do + it 'returns the available users' do expect(instance.allowed_values) .to contain_exactly([nil, user_1.id.to_s], [nil, group.id.to_s]) end end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:user) { build_stubbed(:user) } let(:user2) { build_stubbed(:user) } @@ -297,7 +297,7 @@ instance.values = [user.id.to_s, user2.id.to_s] end - it "returns an array of objects" do + it 'returns an array of objects' do expect(instance.value_objects) .to contain_exactly(user, user2) end diff --git a/spec/models/queries/work_packages/filter/role_filter_spec.rb b/spec/models/queries/work_packages/filter/role_filter_spec.rb index c075251f8ed1..5b4e269705a6 100644 --- a/spec/models/queries/work_packages/filter/role_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/role_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::RoleFilter do let(:role) { build_stubbed(:project_role) } @@ -40,13 +40,13 @@ def mock_roles_query_chain(return_value) return_value end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :assigned_to_role } - let(:name) { I18n.t("query_fields.assigned_to_role") } + let(:name) { I18n.t('query_fields.assigned_to_role') } - describe "#available?" do - context "when any givable role exists" do + describe '#available?' do + context 'when any givable role exists' do before do givable_roles_relation = instance_double(ActiveRecord::Relation) allow(givable_roles_relation) @@ -59,7 +59,7 @@ def mock_roles_query_chain(return_value) it { expect(instance).to be_available } end - context "when no givable role exists" do + context 'when no givable role exists' do before do givable_roles_relation = instance_double(ActiveRecord::Relation) allow(givable_roles_relation) @@ -73,25 +73,25 @@ def mock_roles_query_chain(return_value) end end - describe "#allowed_values" do + describe '#allowed_values' do before do mock_roles_query_chain([role]) end - it "is an array of role values" do + it 'is an array of role values' do expect(instance.allowed_values) .to contain_exactly [role.name, role.id.to_s] end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:other_role) { build_stubbed(:project_role) } before do @@ -99,7 +99,7 @@ def mock_roles_query_chain(return_value) instance.values = [role.id.to_s, other_role.id.to_s] end - it "returns an array of projects" do + it 'returns an array of projects' do expect(instance.value_objects) .to contain_exactly(role, other_role) end diff --git a/spec/models/queries/work_packages/filter/search_filter_spec.rb b/spec/models/queries/work_packages/filter/search_filter_spec.rb index f51b46ffb383..ed57245284b5 100644 --- a/spec/models/queries/work_packages/filter/search_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/search_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::SearchFilter do let(:context) { nil } - let(:value) { "bogus" } - let(:operator) { "**" } - let(:subject) { "Some subject" } + let(:value) { 'bogus' } + let(:operator) { '**' } + let(:subject) { 'Some subject' } let(:work_package) { create(:work_package, subject:) } let(:journal) { work_package.journals.last } let(:instance) do @@ -42,22 +42,22 @@ shared_examples "subject, description, and comment filter" do subject { WorkPackage.joins(instance.joins).where(instance.where) } - context "" do + context '' do let!(:work_package) { create(:work_package, subject: "A bogus subject", description: "And a short description") } - it "finds in subject" do - instance.values = ["bogus subject"] + it 'finds in subject' do + instance.values = ['bogus subject'] expect(subject) .to contain_exactly(work_package) end - it "finds in description" do - instance.values = ["short description"] + it 'finds in description' do + instance.values = ['short description'] expect(subject) .to contain_exactly(work_package) end - it "finds in comments" do + it 'finds in comments' do journal.notes = "bogus comment" journal.save @@ -68,51 +68,51 @@ end end - describe "escaping underscores for the filter (Regression #33574)" do + describe 'escaping underscores for the filter (Regression #33574)' do subject { WorkPackage.joins(instance.joins).where(instance.where) } let!(:work_package) { create(:work_package, description: "Some text c_tree_h more text") } let!(:no_match) { create(:work_package, description: "Some cotreeoh text") } - it "finds in description" do - instance.values = ["c_tree_h"] + it 'finds in description' do + instance.values = ['c_tree_h'] expect(subject) .to contain_exactly(work_package) end end - describe "partial (not fuzzy) match of string in subject (#29832)" do + describe 'partial (not fuzzy) match of string in subject (#29832)' do subject { WorkPackage.joins(instance.joins).where(instance.where) } let!(:work_package) { create(:work_package, subject: "big old cat") } - it "finds in subject" do - instance.values = ["big cat"] + it 'finds in subject' do + instance.values = ['big cat'] expect(subject) .to contain_exactly(work_package) end end - describe "partial match of string in subject and description (#29832)" do + describe 'partial match of string in subject and description (#29832)' do subject { WorkPackage.joins(instance.joins).where(instance.where) } let!(:work_package) { create(:work_package, subject: "big", description: "cat") } - it "does not match a partial result currently" do - instance.values = ["big cat"] + it 'does not match a partial result currently' do + instance.values = ['big cat'] expect(subject) .to be_empty end end if OpenProject::Database.allows_tsv? - context "DB allows tsv" do - context "with EE" do - it_behaves_like "subject, description, and comment filter" + context 'DB allows tsv' do + context 'with EE' do + it_behaves_like 'subject, description, and comment filter' - context "WP with attachment" do - let(:text) { "lorem ipsum" } - let(:filename) { "plaintext-file.txt" } + context 'WP with attachment' do + let(:text) { 'lorem ipsum' } + let(:filename) { 'plaintext-file.txt' } let(:attachment) { create(:attachment, container: work_package, filename:) } before do @@ -125,7 +125,7 @@ it "finds in attachment content" do perform_enqueued_jobs - instance.values = ["ipsum"] + instance.values = ['ipsum'] expect(WorkPackage.joins(instance.joins).where(instance.where)) .to contain_exactly(work_package) end @@ -139,9 +139,9 @@ end end - context "with two attachments" do - let(:text) { "lorem ipsum" } - let(:filename) { "plaintext-file.txt" } + context 'with two attachments' do + let(:text) { 'lorem ipsum' } + let(:filename) { 'plaintext-file.txt' } let(:attachment) { create(:attachment, container: work_package, filename:) } let(:attachment2) { create(:attachment, container: work_package, filename:) } @@ -152,13 +152,13 @@ work_package.reload end - context "with the search string in both attachments" do - let(:text) { "plaintext lorem ipsum" } + context 'with the search string in both attachments' do + let(:text) { 'plaintext lorem ipsum' } it "only finds work package once" do perform_enqueued_jobs - instance.values = ["plaintext"] + instance.values = ['plaintext'] expect(WorkPackage.joins(instance.joins).where(instance.where).pluck(:id)) .to contain_exactly(work_package.id) @@ -167,47 +167,47 @@ end end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :search } let(:class_key) { :search } - describe "#available?" do - it "is available" do + describe '#available?' do + it 'is available' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#valid_values!" do - it "is a noop" do - instance.values = ["none", "is", "changed"] + describe '#valid_values!' do + it 'is a noop' do + instance.values = ['none', 'is', 'changed'] instance.valid_values! expect(instance.values) - .to contain_exactly("none", "is", "changed") + .to contain_exactly('none', 'is', 'changed') end end - describe "#available_operators" do - it "supports **" do + describe '#available_operators' do + it 'supports **' do expect(instance.available_operators) .to eql [Queries::Operators::Everywhere] end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end else - context "DB does not support TSV" do - context "WP without attachment" do - it_behaves_like "subject, description, and comment filter" + context 'DB does not support TSV' do + context 'WP without attachment' do + it_behaves_like 'subject, description, and comment filter' end end end diff --git a/spec/models/queries/work_packages/filter/shared_with_me_filter_spec.rb b/spec/models/queries/work_packages/filter/shared_with_me_filter_spec.rb index 53504d89b5f8..b1ba3f158521 100644 --- a/spec/models/queries/work_packages/filter/shared_with_me_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/shared_with_me_filter_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::SharedWithMeFilter do create_shared_association_defaults_for_work_package_factory @@ -44,33 +44,33 @@ let(:query) { Query.new } - let(:instance) { described_class.create!(context: query, values: ["t"], operator: "=") } + let(:instance) { described_class.create!(context: query, values: ['t'], operator: '=') } subject { instance } - describe "#available?" do - context "when the query is not scoped to a project" do - context "when the user has work packages shared with them" do + describe '#available?' do + context 'when the query is not scoped to a project' do + context 'when the user has work packages shared with them' do current_user { shared_with_user } it { is_expected.to be_available } end - context "when the user does not have work packages shared with them" do + context 'when the user does not have work packages shared with them' do current_user { non_shared_with_user } it { is_expected.not_to be_available } end end - context "when the query is scoped to a project" do + context 'when the query is scoped to a project' do current_user { shared_with_user } - context "and the user has work packages shared with them in the project" do + context 'and the user has work packages shared with them in the project' do before { query.project = project_with_types } it { is_expected.to be_available } end - context "and the user does not have work packages shared with them in the project" do + context 'and the user does not have work packages shared with them in the project' do before { query.project = create(:project) } it { is_expected.not_to be_available } @@ -78,10 +78,10 @@ end end - describe "#where" do + describe '#where' do subject { WorkPackage.where(instance.where) } - context "when the user has work packages shared with them" do + context 'when the user has work packages shared with them' do current_user { shared_with_user } let!(:other_work_package) do @@ -91,7 +91,7 @@ it { is_expected.to contain_exactly(shared_work_package) } end - context "when the user has no work packages shared with them" do + context 'when the user has no work packages shared with them' do current_user { non_shared_with_user } it { is_expected.to be_empty } diff --git a/spec/models/queries/work_packages/filter/shared_with_user_filter_spec.rb b/spec/models/queries/work_packages/filter/shared_with_user_filter_spec.rb index 9a12480849d8..925acfbbb4cc 100644 --- a/spec/models/queries/work_packages/filter/shared_with_user_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/shared_with_user_filter_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::SharedWithUserFilter do create_shared_association_defaults_for_work_package_factory - describe "#scope" do + describe '#scope' do shared_let(:work_package_role) { create(:work_package_role, permissions: %i[blurgh]) } shared_let(:shared_with_user) { create(:user) } @@ -78,27 +78,27 @@ def grant_viewing_permissions current_user { user } context 'with a "=" operator' do - let(:operator) { "=" } + let(:operator) { '=' } - context "for a list of users when none were shared a work package" do + context 'for a list of users when none were shared a work package' do let(:values) { [non_shared_with_user.id.to_s, user.id.to_s] } - it "does not return any work package" do + it 'does not return any work package' do expect(subject) .to be_empty end end - context "for a list of users where at least one was shared a work package" do + context 'for a list of users where at least one was shared a work package' do let(:values) { [shared_with_user.id.to_s, non_shared_with_user.id.to_s] } - it "returns the shared work package" do + it 'returns the shared work package' do expect(subject) .to contain_exactly(shared_work_package) end end - context "for a list of users where all were shared the same work package" do + context 'for a list of users where all were shared the same work package' do before do user.memberships << create(:member, user:, @@ -110,13 +110,13 @@ def grant_viewing_permissions let(:values) { [shared_with_user.id.to_s, user.id.to_s] } - it "returns the shared work package" do + it 'returns the shared work package' do expect(subject) .to contain_exactly(shared_work_package) end end - context "for a list of users where each was shared a different work package" do + context 'for a list of users where each was shared a different work package' do shared_let(:other_shared_work_package) do create(:work_package) do |wp| create(:member, @@ -129,13 +129,13 @@ def grant_viewing_permissions let(:values) { [shared_with_user.id.to_s, user.id.to_s] } - it "returns each shared work package" do + it 'returns each shared work package' do expect(subject) .to contain_exactly(shared_work_package, other_shared_work_package) end end - context "when the user does not have the :view_shared_work_packages permission" do + context 'when the user does not have the :view_shared_work_packages permission' do before do # Remove all permissions user.members.destroy_all @@ -148,18 +148,18 @@ def grant_viewing_permissions user.save! end - context "and using `me` as the filter value" do - let(:values) { ["me"] } + context 'and using `me` as the filter value' do + let(:values) { ['me'] } - it "returns the work package shared with me" do + it 'returns the work package shared with me' do expect(subject).to contain_exactly(shared_work_package) end end - context "and filtering for other users" do + context 'and filtering for other users' do let(:values) { [non_shared_with_user.id, shared_with_user.id] } - it "returns the work package shared with me" do + it 'returns the work package shared with me' do expect(subject).to be_empty end end @@ -167,27 +167,27 @@ def grant_viewing_permissions end context 'with a "&=" operator' do - let(:operator) { "&=" } + let(:operator) { '&=' } - context "for a list of users where none were shared the work package" do + context 'for a list of users where none were shared the work package' do let(:values) { [non_shared_with_user.id.to_s, user.id.to_s] } - it "does not return any work package" do + it 'does not return any work package' do expect(subject) .to be_empty end end - context "for a list of users where some were shared the work package" do + context 'for a list of users where some were shared the work package' do let(:values) { [shared_with_user.id.to_s, non_shared_with_user.id.to_s] } - it "does not return any work package" do + it 'does not return any work package' do expect(subject) .to be_empty end end - context "for a list of users where all were shared the work package" do + context 'for a list of users where all were shared the work package' do before do other_shared_with_user.memberships << create(:member, user: other_shared_with_user, @@ -199,7 +199,7 @@ def grant_viewing_permissions let(:values) { [shared_with_user.id.to_s, other_shared_with_user.id.to_s] } - it "returns the commonly shared work package" do + it 'returns the commonly shared work package' do expect(subject) .to contain_exactly(shared_work_package) end @@ -207,22 +207,22 @@ def grant_viewing_permissions end context 'with a "*" operator' do - let(:operator) { "*" } + let(:operator) { '*' } let(:values) { [] } - it "returns the shared work package" do + it 'returns the shared work package' do expect(subject) .to contain_exactly(shared_work_package, other_shared_work_package) end end end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :shared_with_user_list_optional } let(:class_key) { :shared_with_user } - let(:human_name) { I18n.t("query_fields.shared_with_user") } + let(:human_name) { I18n.t('query_fields.shared_with_user') } - describe "#available?" do + describe '#available?' do context "when I'm logged in" do before do login_as user diff --git a/spec/models/queries/work_packages/filter/start_date_filter_spec.rb b/spec/models/queries/work_packages/filter/start_date_filter_spec.rb index fe0c05c7687e..070ff2aa40da 100644 --- a/spec/models/queries/work_packages/filter/start_date_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/start_date_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::StartDateFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :date } let(:class_key) { :start_date } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/status_filter_spec.rb b/spec/models/queries/work_packages/filter/status_filter_spec.rb index 3e57c8ab8dc1..d198b2b61ed1 100644 --- a/spec/models/queries/work_packages/filter/status_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/status_filter_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::StatusFilter do let(:status) { build_stubbed(:status) } let(:status2) { build_stubbed(:status) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :status_id } - describe "#available?" do - it "is true if any status exists" do + describe '#available?' do + it 'is true if any status exists' do allow(Status) .to receive(:all) .and_return [status] @@ -45,7 +45,7 @@ expect(instance).to be_available end - it "is false if no status exists" do + it 'is false if no status exists' do allow(Status) .to receive(:exists?) .and_return false @@ -54,43 +54,43 @@ end end - describe "#allowed_values" do + describe '#allowed_values' do before do allow(Status) .to receive(:all) .and_return [status] end - it "is an array of status values" do + it 'is an array of status values' do expect(instance.allowed_values) .to contain_exactly([status.name, status.id.to_s]) end end - describe "#valid_values!" do + describe '#valid_values!' do before do allow(Status) .to receive(:all) .and_return [status] - instance.values = [status.id.to_s, "99999"] + instance.values = [status.id.to_s, '99999'] end - it "remove the invalid value" do + it 'remove the invalid value' do instance.valid_values! expect(instance.values).to contain_exactly(status.id.to_s) end end - describe "#value_objects" do + describe '#value_objects' do before do allow(Status) .to receive(:all) .and_return [status, status2] end - it "is an array of statuses" do + it 'is an array of statuses' do instance.values = [status.id.to_s] expect(instance.value_objects) @@ -98,8 +98,8 @@ end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end diff --git a/spec/models/queries/work_packages/filter/subject_filter_spec.rb b/spec/models/queries/work_packages/filter/subject_filter_spec.rb index 41208e31d64f..1c04a6e72e23 100644 --- a/spec/models/queries/work_packages/filter/subject_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/subject_filter_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::SubjectFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :text } let(:class_key) { :subject } - describe "#available?" do - it "is available" do + describe '#available?' do + it 'is available' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - describe "#valid_values!" do - it "is a noop" do - instance.values = ["none", "is", "changed"] + describe '#valid_values!' do + it 'is a noop' do + instance.values = ['none', 'is', 'changed'] instance.valid_values! expect(instance.values) - .to contain_exactly("none", "is", "changed") + .to contain_exactly('none', 'is', 'changed') end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/subject_or_id_filter_spec.rb b/spec/models/queries/work_packages/filter/subject_or_id_filter_spec.rb index 6c5ad463d4a7..3f0030731700 100644 --- a/spec/models/queries/work_packages/filter/subject_or_id_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/subject_or_id_filter_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::SubjectOrIdFilter do - let(:value) { "bogus" } - let(:operator) { "**" } - let(:subject) { "Some subject" } + let(:value) { 'bogus' } + let(:operator) { '**' } + let(:subject) { 'Some subject' } let(:work_package) { create(:work_package, subject:) } let(:current_user) do create(:user, member_with_permissions: { work_package.project => %i[view_work_packages edit_work_packages] }) @@ -45,13 +45,13 @@ login_as current_user end - it "finds in subject" do - instance.values = ["Some subject"] + it 'finds in subject' do + instance.values = ['Some subject'] expect(WorkPackage.eager_load(instance.includes).where(instance.where)) .to contain_exactly(work_package) end - it "finds in ID" do + it 'finds in ID' do instance.values = [work_package.id.to_s] expect(WorkPackage.eager_load(instance.includes).where(instance.where)) .to contain_exactly(work_package) diff --git a/spec/models/queries/work_packages/filter/subproject_filter_spec.rb b/spec/models/queries/work_packages/filter/subproject_filter_spec.rb index d70052fdadfc..f79d42576f62 100644 --- a/spec/models/queries/work_packages/filter/subproject_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/subproject_filter_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::SubprojectFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :subproject_id } - let(:name) { I18n.t("query_fields.subproject_id") } + let(:name) { I18n.t('query_fields.subproject_id') } let(:project) { build_stubbed(:project) } let(:relation) { double(ActiveRecord::Relation) } let(:projects) { [] } @@ -51,7 +51,7 @@ .and_return plucked end - describe "#available?" do + describe '#available?' do context 'with a project and that project not being a leaf and the project having visible descendants' do let(:subproject) { build_stubbed(:project) } @@ -66,27 +66,27 @@ .and_return false end - it "is available" do + it 'is available' do expect(instance).to be_available end end - context "without a project" do + context 'without a project' do let(:project) { nil } - it "is unavailable" do + it 'is unavailable' do expect(instance).not_to be_available end end - context "with a project and that project is a leaf" do + context 'with a project and that project is a leaf' do before do allow(project) .to receive(:leaf?) .and_return true end - it "is unavailable" do + it 'is unavailable' do expect(instance).not_to be_available end end @@ -102,77 +102,77 @@ .and_return false end - it "is unavailable" do + it 'is unavailable' do expect(instance).not_to be_available end end end - describe "#allowed_values" do + describe '#allowed_values' do let(:subproject1) { build_stubbed(:project) } let(:subproject2) { build_stubbed(:project) } let(:projects) { [subproject1, subproject2] } - it "returns a list of all visible descendants" do + it 'returns a list of all visible descendants' do expect(instance.allowed_values).to contain_exactly([subproject1.name, subproject1.id.to_s], [subproject2.name, subproject2.id.to_s]) end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#default_operator" do - it "is the `all` operator" do + describe '#default_operator' do + it 'is the `all` operator' do expect(instance.default_operator) .to eql(Queries::Operators::All) end end - describe "#where" do + describe '#where' do let(:subproject1) { build_stubbed(:project) } let(:subproject2) { build_stubbed(:project) } let(:projects) { [subproject1, subproject2] } - context "for the equals operator" do - let(:operator) { "=" } + context 'for the equals operator' do + let(:operator) { '=' } let(:values) { [subproject1.id.to_s] } - it "returns an sql filtering for project id eql self or specified values" do + it 'returns an sql filtering for project id eql self or specified values' do expect(instance.where) .to eql("projects.id IN (#{project.id},#{subproject1.id})") end end - context "for the not equals operator" do - let(:operator) { "!" } + context 'for the not equals operator' do + let(:operator) { '!' } let(:values) { [subproject1.id.to_s] } - it "returns an sql filtering for project id eql self and all subprojects excluding specified values" do + it 'returns an sql filtering for project id eql self and all subprojects excluding specified values' do expect(instance.where) .to eql("projects.id IN (#{project.id},#{subproject2.id})") end end - context "for the all operator" do - let(:operator) { "*" } + context 'for the all operator' do + let(:operator) { '*' } let(:values) { [] } - it "returns an sql filtering for project id eql self and all subprojects" do + it 'returns an sql filtering for project id eql self and all subprojects' do expect(instance.where) .to eql("projects.id IN (#{project.id},#{subproject1.id},#{subproject2.id})") end end - context "for the none operator" do - let(:operator) { "!*" } + context 'for the none operator' do + let(:operator) { '!*' } let(:values) { [] } - it "returns an sql filtering for only the project id (and by that excluding all subprojects)" do + it 'returns an sql filtering for only the project id (and by that excluding all subprojects)' do expect(instance.where) .to eql("projects.id IN (#{project.id})") end diff --git a/spec/models/queries/work_packages/filter/type_filter_spec.rb b/spec/models/queries/work_packages/filter/type_filter_spec.rb index 711a541b3ee5..4d87c724c890 100644 --- a/spec/models/queries/work_packages/filter/type_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/type_filter_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::TypeFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :type_id } - describe "#available?" do - context "within a project" do + describe '#available?' do + context 'within a project' do before do allow(project) .to receive_message_chain(:rolled_up_types, :exists?) .and_return true end - it "is true" do + it 'is true' do expect(instance).to be_available end - it "is false without a type" do + it 'is false without a type' do allow(project) .to receive_message_chain(:rolled_up_types, :exists?) .and_return false @@ -54,7 +54,7 @@ end end - context "without a project" do + context 'without a project' do let(:project) { nil } before do @@ -63,11 +63,11 @@ .and_return true end - it "is true" do + it 'is true' do expect(instance).to be_available end - it "is false without a type" do + it 'is false without a type' do allow(Type) .to receive_message_chain(:order, :exists?) .and_return false @@ -77,23 +77,23 @@ end end - describe "#allowed_values" do + describe '#allowed_values' do let(:type) { build_stubbed(:type) } - context "within a project" do + context 'within a project' do before do allow(project) .to receive(:rolled_up_types) .and_return [type] end - it "returns an array of type options" do + it 'returns an array of type options' do expect(instance.allowed_values) .to contain_exactly([type.name, type.id.to_s]) end end - context "without a project" do + context 'without a project' do let(:project) { nil } before do @@ -102,21 +102,21 @@ .and_return [type] end - it "returns an array of type options" do + it 'returns an array of type options' do expect(instance.allowed_values) .to contain_exactly([type.name, type.id.to_s]) end end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:type1) { build_stubbed(:type) } let(:type2) { build_stubbed(:type) } @@ -128,7 +128,7 @@ instance.values = [type1.id.to_s, type2.id.to_s] end - it "returns an array of types" do + it 'returns an array of types' do expect(instance.value_objects) .to contain_exactly(type1, type2) end diff --git a/spec/models/queries/work_packages/filter/updated_at_filter_spec.rb b/spec/models/queries/work_packages/filter/updated_at_filter_spec.rb index de2a80d50ad1..fbbe6f42e2c7 100644 --- a/spec/models/queries/work_packages/filter/updated_at_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/updated_at_filter_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::UpdatedAtFilter do - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :datetime_past } let(:class_key) { :updated_at } - describe "#available?" do - it "is true" do + describe '#available?' do + it 'is true' do expect(instance).to be_available end end - describe "#allowed_values" do - it "is nil" do + describe '#allowed_values' do + it 'is nil' do expect(instance.allowed_values).to be_nil end end - it_behaves_like "non ar filter" + it_behaves_like 'non ar filter' end end diff --git a/spec/models/queries/work_packages/filter/version_filter_spec.rb b/spec/models/queries/work_packages/filter/version_filter_spec.rb index da04fdefdbd7..e9e4eff6b58f 100644 --- a/spec/models/queries/work_packages/filter/version_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/version_filter_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::VersionFilter do let(:version) { build_stubbed(:version) } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list_optional } let(:class_key) { :version_id } let(:values) { [version.id.to_s] } - let(:name) { WorkPackage.human_attribute_name("version") } + let(:name) { WorkPackage.human_attribute_name('version') } before do if project @@ -49,13 +49,13 @@ end end - describe "#valid?" do - context "within a project" do - it "is true if the value exists as a version" do + describe '#valid?' do + context 'within a project' do + it 'is true if the value exists as a version' do expect(instance).to be_valid end - it "is false if the value does not exist as a version" do + it 'is false if the value does not exist as a version' do allow(project) .to receive_message_chain(:shared_versions, :pluck) .and_return [] @@ -64,14 +64,14 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "is true if the value exists as a version" do + it 'is true if the value exists as a version' do expect(instance).to be_valid end - it "is false if the value does not exist as a version" do + it 'is false if the value does not exist as a version' do allow(Version) .to receive_message_chain(:visible, :systemwide, :pluck) .and_return [] @@ -81,15 +81,15 @@ end end - describe "#allowed_values" do - context "within a project" do + describe '#allowed_values' do + context 'within a project' do before do expect(instance.allowed_values) .to contain_exactly([version.id.to_s, version.id.to_s]) end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } before do @@ -99,14 +99,14 @@ end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:version1) { build_stubbed(:version) } let(:version2) { build_stubbed(:version) } @@ -118,7 +118,7 @@ instance.values = [version1.id.to_s] end - it "returns an array of versions" do + it 'returns an array of versions' do expect(instance.value_objects) .to contain_exactly(version1) end diff --git a/spec/models/queries/work_packages/filter/watcher_filter_spec.rb b/spec/models/queries/work_packages/filter/watcher_filter_spec.rb index a0479c2d4591..ad539638d89f 100644 --- a/spec/models/queries/work_packages/filter/watcher_filter_spec.rb +++ b/spec/models/queries/work_packages/filter/watcher_filter_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Filter::WatcherFilter do let(:user) { build_stubbed(:user) } let(:pemissions) { [:view_work_package_watchers] } - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } let(:class_key) { :watcher_id } let(:principal_loader) do - loader = double("principal_loader") + loader = double('principal_loader') allow(loader) .to receive(:user_values) .and_return([]) @@ -52,14 +52,14 @@ .and_return(principal_loader) end - describe "#available?" do - it "is true if the user is logged in" do + describe '#available?' do + it 'is true if the user is logged in' do allow(User.current).to receive(:logged?).and_return true expect(instance).to be_available end - it "is true if the user is allowed to see watchers and if there are users" do + it 'is true if the user is allowed to see watchers and if there are users' do allow(User.current).to receive(:logged?).and_return true allow(principal_loader) @@ -69,7 +69,7 @@ expect(instance).to be_available end - it "is false if the user is allowed to see watchers but there are no users" do + it 'is false if the user is allowed to see watchers but there are no users' do allow(User.current).to receive(:logged?).and_return false allow(principal_loader) @@ -79,7 +79,7 @@ expect(instance).not_to be_available end - it "is false if the user is not allowed to see watchers but there are users" do + it 'is false if the user is not allowed to see watchers but there are users' do allow(User.current).to receive(:logged?).and_return false mock_permissions_for(User.current, &:forbid_everything) @@ -91,17 +91,17 @@ end end - describe "#allowed_values" do - context "contains the me value if the user is logged in" do + describe '#allowed_values' do + context 'contains the me value if the user is logged in' do before do allow(User.current).to receive(:logged?).and_return true expect(instance.allowed_values) - .to contain_exactly([I18n.t(:label_me), "me"]) + .to contain_exactly([I18n.t(:label_me), 'me']) end end - context "contains the user values loaded if the user is allowed to see them" do + context 'contains the user values loaded if the user is allowed to see them' do before do allow(User.current).to receive(:logged?).and_return true @@ -110,19 +110,19 @@ .and_return([nil, user.id.to_s]) expect(instance.allowed_values) - .to contain_exactly([I18n.t(:label_me), "me"], [nil, user.id.to_s]) + .to contain_exactly([I18n.t(:label_me), 'me'], [nil, user.id.to_s]) end end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance) .to be_ar_object_filter end end - describe "#value_objects" do + describe '#value_objects' do let(:user1) { build_stubbed(:user) } before do @@ -134,7 +134,7 @@ instance.values = [user1.id.to_s] end - it "returns an array of users" do + it 'returns an array of users' do expect(instance.value_objects) .to contain_exactly(user1) end diff --git a/spec/models/queries/work_packages/manual_sorting_spec.rb b/spec/models/queries/work_packages/manual_sorting_spec.rb index 758b4f62ccd6..7a37df801540 100644 --- a/spec/models/queries/work_packages/manual_sorting_spec.rb +++ b/spec/models/queries/work_packages/manual_sorting_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Query, "manual sorting " do shared_let(:user) { create(:admin) } @@ -47,8 +47,8 @@ login_as user end - describe "#ordered_work_packages" do - it "keeps the current set of ordered work packages" do + describe '#ordered_work_packages' do + it 'keeps the current set of ordered work packages' do expect(query.ordered_work_packages).to eq [] expect(OrderedWorkPackage.where(query_id: query.id).count).to eq 0 @@ -65,7 +65,7 @@ end end - describe "with a second query on the same work package" do + describe 'with a second query on the same work package' do let(:query2) { create(:query, user:, project:) } before do @@ -76,12 +76,12 @@ OrderedWorkPackage.create(query: query2, work_package: wp_2, position: 3) end - it "returns the correct number of work packages" do - query.add_filter("manual_sort", "ow", []) - query2.add_filter("manual_sort", "ow", []) + it 'returns the correct number of work packages' do + query.add_filter('manual_sort', 'ow', []) + query2.add_filter('manual_sort', 'ow', []) - query.sort_criteria = [[:manual_sorting, "asc"]] - query2.sort_criteria = [[:manual_sorting, "asc"]] + query.sort_criteria = [[:manual_sorting, 'asc']] + query2.sort_criteria = [[:manual_sorting, 'asc']] expect(query.results.work_packages.pluck(:id)).to eq [wp_1.id, wp_2.id] expect(query2.results.work_packages.pluck(:id)).to eq [wp_2.id, wp_1.id] diff --git a/spec/models/queries/work_packages/selects/custom_field_select_spec.rb b/spec/models/queries/work_packages/selects/custom_field_select_spec.rb index 9dbcb8389e89..618ada5177a6 100644 --- a/spec/models/queries/work_packages/selects/custom_field_select_spec.rb +++ b/spec/models/queries/work_packages/selects/custom_field_select_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_query_select_specs" +require 'spec_helper' +require_relative 'shared_query_select_specs' RSpec.describe Queries::WorkPackages::Selects::CustomFieldSelect do let(:project) { build_stubbed(:project) } let(:custom_field) { build_stubbed(:string_wp_custom_field) } let(:instance) { described_class.new(custom_field) } - it_behaves_like "query column", sortable_by_default: true + it_behaves_like 'query column', sortable_by_default: true - describe "instances" do + describe 'instances' do let(:text_custom_field) do create(:text_wp_custom_field) end @@ -45,7 +45,7 @@ create(:list_wp_custom_field) end - context "within project" do + context 'within project' do before do allow(project) .to receive(:all_work_package_custom_fields) @@ -53,7 +53,7 @@ list_custom_field]) end - it "contains only non text cf columns" do + it 'contains only non text cf columns' do expect(described_class.instances(project).length) .to eq 1 @@ -62,7 +62,7 @@ end end - context "global" do + context 'global' do before do allow(WorkPackageCustomField) .to receive(:all) @@ -70,7 +70,7 @@ list_custom_field]) end - it "contains only non text cf columns" do + it 'contains only non text cf columns' do expect(described_class.instances.length) .to eq 1 @@ -80,10 +80,10 @@ end end - describe "#value" do + describe '#value' do let(:mock) { instance_double(WorkPackage) } - it "delegates to formatted_custom_value_for" do + it 'delegates to formatted_custom_value_for' do expect(mock).to receive(:formatted_custom_value_for).with(custom_field.id) instance.value(mock) end diff --git a/spec/models/queries/work_packages/selects/property_select_spec.rb b/spec/models/queries/work_packages/selects/property_select_spec.rb index e7b0f40e582c..bd22e08b3e39 100644 --- a/spec/models/queries/work_packages/selects/property_select_spec.rb +++ b/spec/models/queries/work_packages/selects/property_select_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_query_select_specs" +require 'spec_helper' +require_relative 'shared_query_select_specs' RSpec.describe Queries::WorkPackages::Selects::PropertySelect do let(:instance) { described_class.new(:query_column) } - it_behaves_like "query column" + it_behaves_like 'query column' - describe "instances" do - context "when done_ratio disabled" do - it "the done ratio column does not exist" do + describe 'instances' do + context 'when done_ratio disabled' do + it 'the done ratio column does not exist' do allow(WorkPackage) .to receive(:done_ratio_disabled?) .and_return(true) @@ -45,8 +45,8 @@ end end - context "when done_ratio enabled" do - it "the done ratio column exists" do + context 'when done_ratio enabled' do + it 'the done ratio column exists' do allow(WorkPackage) .to receive(:done_ratio_disabled?) .and_return(false) @@ -55,8 +55,8 @@ end end - context "when duration feature flag enabled" do - it "column exists" do + context 'when duration feature flag enabled' do + it 'column exists' do expect(described_class.instances.map(&:name)).to include :duration end end diff --git a/spec/models/queries/work_packages/selects/relation_of_type_select_spec.rb b/spec/models/queries/work_packages/selects/relation_of_type_select_spec.rb index 6382085c3cdb..c31b53e4dcc9 100644 --- a/spec/models/queries/work_packages/selects/relation_of_type_select_spec.rb +++ b/spec/models/queries/work_packages/selects/relation_of_type_select_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_query_select_specs" +require 'spec_helper' +require_relative 'shared_query_select_specs' RSpec.describe Queries::WorkPackages::Selects::RelationOfTypeSelect do let(:project) { build_stubbed(:project) } @@ -35,11 +35,11 @@ let(:instance) { described_class.new(type) } let(:enterprise_token_allows) { true } - it_behaves_like "query column" + it_behaves_like 'query column' - describe "instances" do + describe 'instances' do before do - stub_const("Relation::TYPES", + stub_const('Relation::TYPES', relation1: { name: :label_relates_to, sym_name: :label_relates_to, order: 1, sym: :relation1 }, relation2: { name: :label_duplicates, sym_name: :label_duplicated_by, order: 2, sym: :relation2 }) @@ -49,8 +49,8 @@ .and_return(enterprise_token_allows) end - context "with a valid enterprise token" do - it "contains the type columns" do + context 'with a valid enterprise token' do + it 'contains the type columns' do expect(described_class.instances.length) .to eq 2 @@ -62,10 +62,10 @@ end end - context "without a valid enterprise token" do + context 'without a valid enterprise token' do let(:enterprise_token_allows) { false } - it "is empty" do + it 'is empty' do expect(described_class.instances) .to be_empty end diff --git a/spec/models/queries/work_packages/selects/relation_to_type_select_spec.rb b/spec/models/queries/work_packages/selects/relation_to_type_select_spec.rb index c24671eb1988..c96454b53b54 100644 --- a/spec/models/queries/work_packages/selects/relation_to_type_select_spec.rb +++ b/spec/models/queries/work_packages/selects/relation_to_type_select_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared_query_select_specs" +require 'spec_helper' +require_relative 'shared_query_select_specs' RSpec.describe Queries::WorkPackages::Selects::RelationToTypeSelect do let(:project) { build_stubbed(:project) } @@ -35,9 +35,9 @@ let(:instance) { described_class.new(type) } let(:enterprise_token_allows) { true } - it_behaves_like "query column" + it_behaves_like 'query column' - describe "instances" do + describe 'instances' do before do allow(EnterpriseToken) .to receive(:allows_to?) @@ -45,15 +45,15 @@ .and_return(enterprise_token_allows) end - context "within project" do + context 'within project' do before do allow(project) .to receive(:types) .and_return([type]) end - context "with a valid enterprise token" do - it "contains the type columns" do + context 'with a valid enterprise token' do + it 'contains the type columns' do expect(described_class.instances(project).length) .to eq 1 @@ -62,25 +62,25 @@ end end - context "without a valid enterprise token" do + context 'without a valid enterprise token' do let(:enterprise_token_allows) { false } - it "is empty" do + it 'is empty' do expect(described_class.instances) .to be_empty end end end - context "global" do + context 'global' do before do allow(Type) .to receive(:all) .and_return([type]) end - context "with a valid enterprise token" do - it "contains the type columns" do + context 'with a valid enterprise token' do + it 'contains the type columns' do expect(described_class.instances.length) .to eq 1 @@ -89,10 +89,10 @@ end end - context "without a valid enterprise token" do + context 'without a valid enterprise token' do let(:enterprise_token_allows) { false } - it "is empty" do + it 'is empty' do expect(described_class.instances) .to be_empty end diff --git a/spec/models/queries/work_packages/selects/shared_query_select_specs.rb b/spec/models/queries/work_packages/selects/shared_query_select_specs.rb index 693b63999592..7de43252608e 100644 --- a/spec/models/queries/work_packages/selects/shared_query_select_specs.rb +++ b/spec/models/queries/work_packages/selects/shared_query_select_specs.rb @@ -26,78 +26,78 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "query column" do |sortable_by_default: false| - describe "#groupable" do - it "is the name if true is provided" do +RSpec.shared_examples_for 'query column' do |sortable_by_default: false| + describe '#groupable' do + it 'is the name if true is provided' do instance.groupable = true expect(instance.groupable).to eql(instance.name.to_s) end - it "is the value if something truthy is provided" do - instance.groupable = "lorem ipsum" + it 'is the value if something truthy is provided' do + instance.groupable = 'lorem ipsum' - expect(instance.groupable).to eql("lorem ipsum") + expect(instance.groupable).to eql('lorem ipsum') end - it "is false if false is provided" do + it 'is false if false is provided' do instance.groupable = false expect(instance.groupable).to be_falsey end - it "is false if nothing is provided" do + it 'is false if nothing is provided' do instance.groupable = nil expect(instance.groupable).to be_falsey end end - describe "#sortable" do - it "is the name if true is provided" do + describe '#sortable' do + it 'is the name if true is provided' do instance.sortable = true expect(instance.sortable).to eql(instance.name.to_s) end - it "is the value if something truthy is provided" do - instance.sortable = "lorem ipsum" + it 'is the value if something truthy is provided' do + instance.sortable = 'lorem ipsum' - expect(instance.sortable).to eql("lorem ipsum") + expect(instance.sortable).to eql('lorem ipsum') end - it "is false if false is provided" do + it 'is false if false is provided' do instance.sortable = false expect(instance.sortable).to be_falsey end - it "is false if nothing is provided" do + it 'is false if nothing is provided' do instance.sortable = nil expect(instance.sortable).to be_falsey end end - describe "#groupable?" do - it "is false by default" do + describe '#groupable?' do + it 'is false by default' do expect(instance).not_to be_groupable end - it "is true if told so" do + it 'is true if told so' do instance.groupable = true expect(instance).to be_groupable end - it "is true if a value is provided (e.g. for specifying sql code)" do - instance.groupable = "COALESCE(null, 1)" + it 'is true if a value is provided (e.g. for specifying sql code)' do + instance.groupable = 'COALESCE(null, 1)' expect(instance).to be_groupable end end - describe "#sortable?" do + describe '#sortable?' do it "is #{sortable_by_default} by default" do if sortable_by_default expect(instance).to be_sortable @@ -106,14 +106,14 @@ end end - it "is true if told so" do + it 'is true if told so' do instance.sortable = true expect(instance).to be_sortable end - it "is true if a value is provided (e.g. for specifying sql code)" do - instance.sortable = "COALESCE(null, 1)" + it 'is true if a value is provided (e.g. for specifying sql code)' do + instance.sortable = 'COALESCE(null, 1)' expect(instance).to be_sortable end diff --git a/spec/models/queries/work_packages/selects/work_package_select_spec.rb b/spec/models/queries/work_packages/selects/work_package_select_spec.rb index ad93df023c36..57d8eb4dd33a 100644 --- a/spec/models/queries/work_packages/selects/work_package_select_spec.rb +++ b/spec/models/queries/work_packages/selects/work_package_select_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::WorkPackages::Selects::WorkPackageSelect do it "allows to be constructed with attribute highlightable" do - expect(described_class.new("foo", highlightable: true).highlightable?).to be(true) + expect(described_class.new('foo', highlightable: true).highlightable?).to be(true) end it "allows to be constructed without attribute highlightable" do - expect(described_class.new("foo").highlightable?).to be(false) + expect(described_class.new('foo').highlightable?).to be(false) end end diff --git a/spec/models/query/default_query_spec.rb b/spec/models/query/default_query_spec.rb index 9691d2939801..0550b354580c 100644 --- a/spec/models/query/default_query_spec.rb +++ b/spec/models/query/default_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "default query" do let(:query) { Query.new_default } diff --git a/spec/models/query/results_cf_sorting_integration_spec.rb b/spec/models/query/results_cf_sorting_integration_spec.rb index 6c429bbd12f3..848d1a61b566 100644 --- a/spec/models/query/results_cf_sorting_integration_spec.rb +++ b/spec/models/query/results_cf_sorting_integration_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "Sorting of custom field floats" do +RSpec.describe Query::Results, 'Sorting of custom field floats' do let(:query_results) do Query::Results.new query end let(:user) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project => [:view_work_packages] }) end @@ -59,7 +59,7 @@ end let(:custom_field) do - create(:float_wp_custom_field, name: "MyFloat") + create(:float_wp_custom_field, name: 'MyFloat') end let(:query) do @@ -78,19 +78,19 @@ work_package_without_float end - describe "sorting ASC by float cf" do - let(:sort_criteria) { [[custom_field.column_name, "asc"]] } + describe 'sorting ASC by float cf' do + let(:sort_criteria) { [[custom_field.column_name, 'asc']] } - it "returns the correctly sorted result" do + it 'returns the correctly sorted result' do expect(query_results.work_packages.pluck(:id)) .to match [work_package_without_float, work_package_with_float].map(&:id) end end - describe "sorting DESC by float cf" do - let(:sort_criteria) { [[custom_field.column_name, "desc"]] } + describe 'sorting DESC by float cf' do + let(:sort_criteria) { [[custom_field.column_name, 'desc']] } - it "returns the correctly sorted result" do + it 'returns the correctly sorted result' do expect(query_results.work_packages.pluck(:id)) .to match [work_package_with_float, work_package_without_float].map(&:id) end diff --git a/spec/models/query/results_custom_field_filter_integration_spec.rb b/spec/models/query/results_custom_field_filter_integration_spec.rb index b2bb05fb9671..12036608c500 100644 --- a/spec/models/query/results_custom_field_filter_integration_spec.rb +++ b/spec/models/query/results_custom_field_filter_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "Filtering custom fields" do +RSpec.describe Query::Results, 'Filtering custom fields' do shared_let(:user) { create(:admin) } shared_let(:custom_field) do create( @@ -57,27 +57,27 @@ def custom_values_for(*names) end shared_let(:wp_a) do - create(:work_package, subject: "A", type:, project:, custom_values: custom_values_for("A")) + create(:work_package, subject: 'A', type:, project:, custom_values: custom_values_for('A')) end shared_let(:wp_b) do - create(:work_package, subject: "B", type:, project:, custom_values: custom_values_for("B")) + create(:work_package, subject: 'B', type:, project:, custom_values: custom_values_for('B')) end shared_let(:wp_c) do - create(:work_package, subject: "C", type:, project:, custom_values: custom_values_for("C")) + create(:work_package, subject: 'C', type:, project:, custom_values: custom_values_for('C')) end shared_let(:wp_a_b) do - create(:work_package, subject: "A and B", type:, project:, custom_values: custom_values_for("A", "B")) + create(:work_package, subject: 'A and B', type:, project:, custom_values: custom_values_for('A', 'B')) end shared_let(:wp_b_c) do - create(:work_package, subject: "B and C", type:, project:, custom_values: custom_values_for("B", "C")) + create(:work_package, subject: 'B and C', type:, project:, custom_values: custom_values_for('B', 'C')) end shared_let(:wp_a_b_c) do - create(:work_package, subject: "A B C", type:, project:, custom_values: custom_values_for("A", "B", "C")) + create(:work_package, subject: 'A B C', type:, project:, custom_values: custom_values_for('A', 'B', 'C')) end let(:query) do @@ -101,91 +101,91 @@ def custom_values_for(*names) login_as(user) end - shared_examples "filtered work packages" do + shared_examples 'filtered work packages' do it do expect(query_results).to match_array expected.map(&:id) end end - describe "filter for is(OR)" do - let(:operator) { "=" } + describe 'filter for is(OR)' do + let(:operator) { '=' } - context "when filtering for A" do - let(:values) { ["A"] } + context 'when filtering for A' do + let(:values) { ['A'] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_a, wp_a_b, wp_a_b_c] } end end - context "when filtering for A OR B" do + context 'when filtering for A OR B' do let(:values) { %w[A B] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_a, wp_a_b, wp_a_b_c, wp_b, wp_b_c] } end end - context "when filtering for A OR B OR C" do + context 'when filtering for A OR B OR C' do let(:values) { %w[A B C] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_a, wp_a_b, wp_a_b_c, wp_b, wp_b_c, wp_c] } end end end - describe "filter for is(AND)" do - let(:operator) { "&=" } + describe 'filter for is(AND)' do + let(:operator) { '&=' } - context "when filtering for A" do - let(:values) { ["A"] } + context 'when filtering for A' do + let(:values) { ['A'] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_a, wp_a_b, wp_a_b_c] } end end - context "when filtering for A AND B" do + context 'when filtering for A AND B' do let(:values) { %w[A B] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_a_b, wp_a_b_c] } end end - context "when filtering for A AND B AND C" do + context 'when filtering for A AND B AND C' do let(:values) { %w[A B C] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_a_b_c] } end end end - describe "filter for is not" do - let(:operator) { "!" } + describe 'filter for is not' do + let(:operator) { '!' } - context "when filtering for A" do - let(:values) { ["A"] } + context 'when filtering for A' do + let(:values) { ['A'] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_b, wp_b_c, wp_c] } end end - context "when filtering for A AND B" do + context 'when filtering for A AND B' do let(:values) { %w[A B] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [wp_c] } end end - context "when filtering for A AND B AND C" do + context 'when filtering for A AND B AND C' do let(:values) { %w[A B C] } - it_behaves_like "filtered work packages" do + it_behaves_like 'filtered work packages' do let(:expected) { [] } end end diff --git a/spec/models/query/results_filter_on_historic_data_spec.rb b/spec/models/query/results_filter_on_historic_data_spec.rb index 895844540435..ce52738c8e1a 100644 --- a/spec/models/query/results_filter_on_historic_data_spec.rb +++ b/spec/models/query/results_filter_on_historic_data_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Query::Results, - "Filter on historic data", + 'Filter on historic data', with_ee: %i[baseline_comparison] do let(:historic_time) { "2022-08-01".to_datetime } let(:pre_historic_time) { historic_time - 1.day } @@ -59,8 +59,8 @@ let(:user1) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project_with_member => %i[view_work_packages view_file_links] }) end @@ -86,7 +86,7 @@ def move_work_package_to_project(work_package, project, time) login_as(user1) build(:query, user: user1, project: nil).tap do |query| query.filters.clear - query.add_filter "description", "~", search_term + query.add_filter 'description', '~', search_term end end let(:results) { query.results } @@ -94,7 +94,7 @@ def move_work_package_to_project(work_package, project, time) subject { results.work_packages } describe "filter for description containing 'current'" do - let(:search_term) { "current" } + let(:search_term) { 'current' } it "includes the work package matching today" do expect(subject).to eq [work_package] @@ -102,7 +102,7 @@ def move_work_package_to_project(work_package, project, time) end describe "filter for description containing 'original'" do - let(:search_term) { "original" } + let(:search_term) { 'original' } it "does not include the work package matching only in the past" do expect(subject).not_to eq [work_package] @@ -113,7 +113,7 @@ def move_work_package_to_project(work_package, project, time) before { query.timestamps = [historic_time, Time.zone.now] } describe "filter for description containing 'current'" do - let(:search_term) { "current" } + let(:search_term) { 'current' } it "includes the work package matching today" do expect(subject).to eq [work_package] @@ -121,7 +121,7 @@ def move_work_package_to_project(work_package, project, time) end describe "filter for description containing 'original'" do - let(:search_term) { "original" } + let(:search_term) { 'original' } it "includes the work package matching in the past" do expect(subject).to eq [work_package] @@ -132,7 +132,7 @@ def move_work_package_to_project(work_package, project, time) describe "when the search matches several work packages" do before { query.timestamps = [historic_time, Time.zone.now] } - let(:search_term) { "re" } + let(:search_term) { 're' } it "includes all matching work packages" do expect(subject).to include work_package, work_package2 @@ -143,7 +143,7 @@ def move_work_package_to_project(work_package, project, time) before { query.timestamps = [historic_time] } describe "filter for description containing 'current'" do - let(:search_term) { "current" } + let(:search_term) { 'current' } it "does not include the work package matching only in the past" do expect(subject).not_to include work_package @@ -151,7 +151,7 @@ def move_work_package_to_project(work_package, project, time) end describe "filter for description containing 'original'" do - let(:search_term) { "original" } + let(:search_term) { 'original' } it "includes the work package matching in the past" do expect(subject).to include work_package @@ -195,7 +195,7 @@ def move_work_package_to_project(work_package, project, time) before { query.timestamps = [pre_historic_time] } describe "filter for description containing 'current'" do - let(:search_term) { "current" } + let(:search_term) { 'current' } it "does not include the work package matching only in the past" do expect(subject).not_to include work_package @@ -203,7 +203,7 @@ def move_work_package_to_project(work_package, project, time) end describe "filter for description containing 'original'" do - let(:search_term) { "original" } + let(:search_term) { 'original' } it "does not include the work package because it does not exist yet at that time" do expect(subject).not_to include work_package @@ -219,7 +219,7 @@ def move_work_package_to_project(work_package, project, time) login_as(user1) build(:query, user: user1, project: nil).tap do |query| query.filters.clear - query.add_filter "file_link_origin_id", "=", [file_link1.origin_id.to_s] + query.add_filter 'file_link_origin_id', '=', [file_link1.origin_id.to_s] end end let(:file_link1) { create(:file_link, creator: user1, container: work_package, storage: storage1) } @@ -260,7 +260,7 @@ def move_work_package_to_project(work_package, project, time) end end - context "when the work package is moved to a project the user has no permissions in" do + context 'when the work package is moved to a project the user has no permissions in' do current_user { user1 } let(:query) do @@ -279,8 +279,8 @@ def move_work_package_to_project(work_package, project, time) end end - context "when the work package is moved to a project the user has no permissions in " \ - "and also has no permission in the old project" do + context 'when the work package is moved to a project the user has no permissions in ' \ + 'and also has no permission in the old project' do current_user { user1 } let(:query) do @@ -300,8 +300,8 @@ def move_work_package_to_project(work_package, project, time) end end - context "when the work package is moved to a project the user has permissions in " \ - "and looses permission in the former project" do + context 'when the work package is moved to a project the user has permissions in ' \ + 'and looses permission in the former project' do current_user { user1 } let(:query) do @@ -325,8 +325,8 @@ def move_work_package_to_project(work_package, project, time) end end - context "when the work package is moved to a project the user has no permissions in" \ - "and the comparison time is after the move" do + context 'when the work package is moved to a project the user has no permissions in' \ + 'and the comparison time is after the move' do current_user { user1 } let(:query) do diff --git a/spec/models/query/results_project_filter_integration_spec.rb b/spec/models/query/results_project_filter_integration_spec.rb index 9e9ec395deac..b99054b21958 100644 --- a/spec/models/query/results_project_filter_integration_spec.rb +++ b/spec/models/query/results_project_filter_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "Project filter integration" do +RSpec.describe Query::Results, 'Project filter integration' do let(:query) do build(:query, user:, @@ -48,8 +48,8 @@ shared_let(:user) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { parent_project => [:view_work_packages], child_project => [:view_work_packages], @@ -68,85 +68,85 @@ login_as user end - describe "both parent projects selected" do + describe 'both parent projects selected' do before do - query.add_filter "project_id", "=", [parent_project.id, second_parent_project.id] + query.add_filter 'project_id', '=', [parent_project.id, second_parent_project.id] end - context "when subprojects included", with_settings: { display_subprojects_work_packages: true } do - it "shows the sub work packages" do + context 'when subprojects included', with_settings: { display_subprojects_work_packages: true } do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp, second_parent_wp, second_child_wp) end end - context "when subprojects not included", with_settings: { display_subprojects_work_packages: false } do - it "does not show the sub work packages" do + context 'when subprojects not included', with_settings: { display_subprojects_work_packages: false } do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, second_parent_wp) end end - context "when subprojects explicitly disabled" do + context 'when subprojects explicitly disabled' do before do query.include_subprojects = false end - it "does not show the sub work packages" do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, second_parent_wp) end end end - describe "one parent projects selected" do + describe 'one parent projects selected' do before do - query.add_filter "project_id", "=", [second_parent_project.id] + query.add_filter 'project_id', '=', [second_parent_project.id] end - context "when subprojects included", with_settings: { display_subprojects_work_packages: true } do - it "shows the sub work packages" do + context 'when subprojects included', with_settings: { display_subprojects_work_packages: true } do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(second_parent_wp, second_child_wp) end end - context "when subprojects not included", with_settings: { display_subprojects_work_packages: false } do - it "does not show the sub work packages" do + context 'when subprojects not included', with_settings: { display_subprojects_work_packages: false } do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(second_parent_wp) end end - context "when subprojects explicitly disabled" do + context 'when subprojects explicitly disabled' do before do query.include_subprojects = false end - it "does not show the sub work packages" do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(second_parent_wp) end end end - describe "one parent and one other child selected" do + describe 'one parent and one other child selected' do before do - query.add_filter "project_id", "=", [child_project.id, second_parent_project.id] + query.add_filter 'project_id', '=', [child_project.id, second_parent_project.id] end - context "when subprojects included", with_settings: { display_subprojects_work_packages: true } do - it "shows the sub work packages" do + context 'when subprojects included', with_settings: { display_subprojects_work_packages: true } do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(child_wp, second_parent_wp, second_child_wp) end end - context "when subprojects not included", with_settings: { display_subprojects_work_packages: false } do - it "does not show the sub work packages" do + context 'when subprojects not included', with_settings: { display_subprojects_work_packages: false } do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(child_wp, second_parent_wp) end end - context "when subprojects explicitly disabled" do + context 'when subprojects explicitly disabled' do before do query.include_subprojects = false end - it "does not show the sub work packages" do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(child_wp, second_parent_wp) end end diff --git a/spec/models/query/results_sort_intergration_spec.rb b/spec/models/query/results_sort_intergration_spec.rb index ace50a7a5687..9f7c5869867f 100644 --- a/spec/models/query/results_sort_intergration_spec.rb +++ b/spec/models/query/results_sort_intergration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "sorting and grouping" do +RSpec.describe Query::Results, 'sorting and grouping' do create_shared_association_defaults_for_work_package_factory let(:query) do @@ -46,25 +46,25 @@ let(:project1) { create(:project) } let(:user1) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project1 => [:view_work_packages] }) end - let(:user_a) { create(:user, firstname: "AAA", lastname: "AAA") } - let(:user_m) { create(:user, firstname: "mmm", lastname: "mmm") } - let(:user_z) { create(:user, firstname: "ZZZ", lastname: "ZZZ") } + let(:user_a) { create(:user, firstname: 'AAA', lastname: 'AAA') } + let(:user_m) { create(:user, firstname: 'mmm', lastname: 'mmm') } + let(:user_z) { create(:user, firstname: 'ZZZ', lastname: 'ZZZ') } let(:work_package1) { create(:work_package, project: project1, id: 1) } let(:work_package2) { create(:work_package, project: project1, id: 2) } let(:work_package3) { create(:work_package, project: project1, id: 3) } let(:sort_by) { [%w[id asc]] } let(:columns) { %i(id subject) } - let(:group_by) { "" } + let(:group_by) { '' } current_user { user1 } - context "when grouping by assigned_to, having the author column selected" do - let(:group_by) { "assigned_to" } + context 'when grouping by assigned_to, having the author column selected' do + let(:group_by) { 'assigned_to' } let(:columns) { %i(id subject author) } before do @@ -84,7 +84,7 @@ work_package3.save(validate: false) end - it "sorts case insensitive first by assigned_to (group by), then by sort criteria" do + it 'sorts case insensitive first by assigned_to (group by), then by sort criteria' do # Would look like this in the table # # user_m @@ -97,9 +97,9 @@ end end - context "when sorting by author, grouping by assigned_to" do - let(:group_by) { "assigned_to" } - let(:sort_by) { [["author", "asc"]] } + context 'when sorting by author, grouping by assigned_to' do + let(:group_by) { 'assigned_to' } + let(:sort_by) { [['author', 'asc']] } before do work_package1.assigned_to = user_m @@ -118,7 +118,7 @@ work_package3.save(validate: false) end - it "sorts case insensitive first by group by, then by assigned_to" do + it 'sorts case insensitive first by group by, then by assigned_to' do # Would look like this in the table # # user_m @@ -129,7 +129,7 @@ expect(query_results.work_packages) .to match [work_package3, work_package1, work_package2] - query.sort_criteria = [["author", "desc"]] + query.sort_criteria = [['author', 'desc']] # Would look like this in the table # @@ -143,10 +143,10 @@ end end - context "when sorting and grouping by priority" do + context 'when sorting and grouping by priority' do let(:prio_low) { create(:issue_priority, position: 1) } let(:prio_high) { create(:issue_priority, position: 0) } - let(:group_by) { "priority" } + let(:group_by) { 'priority' } before do work_package1.priority = prio_low @@ -156,23 +156,23 @@ work_package2.save(validate: false) end - it "respects the sorting (Regression #29689)" do - query.sort_criteria = [["priority", "asc"]] + it 'respects the sorting (Regression #29689)' do + query.sort_criteria = [['priority', 'asc']] expect(query_results.work_packages) .to match [work_package1, work_package2] - query.sort_criteria = [["priority", "desc"]] + query.sort_criteria = [['priority', 'desc']] expect(query_results.work_packages) .to match [work_package2, work_package1] end end - context "when sorting by priority, grouping by project" do + context 'when sorting by priority, grouping by project' do let(:prio_low) { create(:issue_priority, position: 1) } let(:prio_high) { create(:issue_priority, position: 0) } - let(:group_by) { "project" } + let(:group_by) { 'project' } before do work_package1.priority = prio_low @@ -182,13 +182,13 @@ work_package2.save(validate: false) end - it "properly selects project_id (Regression #31667)" do - query.sort_criteria = [["priority", "asc"]] + it 'properly selects project_id (Regression #31667)' do + query.sort_criteria = [['priority', 'asc']] expect(query_results.work_packages) .to match [work_package1, work_package2] - query.sort_criteria = [["priority", "desc"]] + query.sort_criteria = [['priority', 'desc']] expect(query_results.work_packages) .to match [work_package2, work_package1] @@ -199,9 +199,9 @@ end end - context "when sorting by author and responsible, grouping by assigned_to" do - let(:group_by) { "assigned_to" } - let(:sort_by) { [["author", "asc"], ["responsible", "desc"]] } + context 'when sorting by author and responsible, grouping by assigned_to' do + let(:group_by) { 'assigned_to' } + let(:sort_by) { [['author', 'asc'], ['responsible', 'desc']] } before do work_package1.assigned_to = user_m @@ -223,7 +223,7 @@ work_package3.save(validate: false) end - it "sorts case insensitive first by group by, then by assigned_to (neutral as equal), then by responsible" do + it 'sorts case insensitive first by group by, then by assigned_to (neutral as equal), then by responsible' do # Would look like this in the table # # user_m @@ -248,7 +248,7 @@ end end - context "when sorting by project" do + context 'when sorting by project' do let(:user1) { create(:admin) } let(:query) do build_stubbed(:query, @@ -257,54 +257,54 @@ sort_criteria: sort_by) end - let(:project1) { create(:project, name: "Project A") } - let(:project2) { create(:project, name: "Project b") } - let(:project3) { create(:project, name: "Project C") } + let(:project1) { create(:project, name: 'Project A') } + let(:project2) { create(:project, name: 'Project b') } + let(:project3) { create(:project, name: 'Project C') } let(:work_package1) { create(:work_package, project: project1) } let(:work_package2) { create(:work_package, project: project2) } let(:work_package3) { create(:work_package, project: project3) } before { [work_package1, work_package2, work_package3] } - context "when ascending" do + context 'when ascending' do let(:sort_by) { [%w[project asc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package1, work_package2, work_package3] end end - context "when descending" do + context 'when descending' do let(:sort_by) { [%w[project desc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package3, work_package2, work_package1] end end end - context "when sorting by category" do + context 'when sorting by category' do let(:query) do build_stubbed(:query, show_hierarchies: false, project: nil, sort_criteria: sort_by) end - let(:category1) { create(:category, project: project1, name: "Category A") } - let(:category2) { create(:category, project: project1, name: "Category b") } - let(:category3) { create(:category, project: project1, name: "Category C") } + let(:category1) { create(:category, project: project1, name: 'Category A') } + let(:category2) { create(:category, project: project1, name: 'Category b') } + let(:category3) { create(:category, project: project1, name: 'Category C') } let(:work_package1) { create(:work_package, project: project1, category: category1) } let(:work_package2) { create(:work_package, project: project1, category: category2) } let(:work_package3) { create(:work_package, project: project1, category: category3) } before { [work_package1, work_package2, work_package3] } - context "when ascending" do + context 'when ascending' do let(:sort_by) { [%w[category asc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do query_results.work_packages [work_package1, work_package2, work_package3] @@ -313,33 +313,33 @@ end end - context "when descending" do + context 'when descending' do let(:sort_by) { [%w[category desc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package3, work_package2, work_package1] end end end - context "when sorting by subject" do + context 'when sorting by subject' do let(:query) do build_stubbed(:query, show_hierarchies: false, project: nil, sort_criteria: sort_by) end - let(:work_package1) { create(:work_package, project: project1, subject: "WorkPackage A") } - let(:work_package2) { create(:work_package, project: project1, subject: "WorkPackage b") } - let(:work_package3) { create(:work_package, project: project1, subject: "WorkPackage C") } + let(:work_package1) { create(:work_package, project: project1, subject: 'WorkPackage A') } + let(:work_package2) { create(:work_package, project: project1, subject: 'WorkPackage b') } + let(:work_package3) { create(:work_package, project: project1, subject: 'WorkPackage C') } before { [work_package1, work_package2, work_package3] } - context "when ascending" do + context 'when ascending' do let(:sort_by) { [%w[subject asc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do query_results.work_packages [work_package1, work_package2, work_package3] @@ -348,17 +348,17 @@ end end - context "when descending" do + context 'when descending' do let(:sort_by) { [%w[subject desc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package3, work_package2, work_package1] end end end - context "when sorting by finish date" do + context 'when sorting by finish date' do let(:query) do build_stubbed(:query, show_hierarchies: false, @@ -371,26 +371,26 @@ before { [work_package1, work_package2, work_package3] } - context "when ascending" do + context 'when ascending' do let(:sort_by) { [%w[due_date asc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package1, work_package2, work_package3] end end - context "when descending" do + context 'when descending' do let(:sort_by) { [%w[due_date desc]] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package3, work_package2, work_package1] end end end - context "when sorting by string custom field" do + context 'when sorting by string custom field' do let(:query) do build_stubbed(:query, show_hierarchies: false, @@ -406,20 +406,20 @@ create(:custom_value, custom_field: string_cf, customized: work_package1, - value: "String A") + value: 'String A') end let!(:custom_value2) do create(:custom_value, custom_field: string_cf, customized: work_package2, - value: "String b") + value: 'String b') end let!(:custom_value3) do create(:custom_value, custom_field: string_cf, customized: work_package3, - value: "String C") + value: 'String C') end before do @@ -432,26 +432,26 @@ project1.reload end - context "when ascending" do - let(:sort_by) { [[string_cf.column_name, "asc"]] } + context 'when ascending' do + let(:sort_by) { [[string_cf.column_name, 'asc']] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package1, work_package2, work_package3] end end - context "when descending" do - let(:sort_by) { [["assigned_to", "desc"]] } + context 'when descending' do + let(:sort_by) { [["assigned_to", 'desc']] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package3, work_package2, work_package1] end end end - context "when sorting by integer custom field" do + context 'when sorting by integer custom field' do let(:query) do build_stubbed(:query, show_hierarchies: false, @@ -493,26 +493,26 @@ project1.reload end - context "when ascending" do - let(:sort_by) { [[int_cf.column_name, "asc"]] } + context 'when ascending' do + let(:sort_by) { [[int_cf.column_name, 'asc']] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package1, work_package2, work_package3] end end - context "when descending" do - let(:sort_by) { [[int_cf.column_name, "desc"]] } + context 'when descending' do + let(:sort_by) { [[int_cf.column_name, 'desc']] } - it "sorts case insensitive" do + it 'sorts case insensitive' do expect(query_results.work_packages) .to match [work_package3, work_package2, work_package1] end end end - context "when sorting by typeahead" do + context 'when sorting by typeahead' do before do work_package1.update_column(:updated_at, 5.days.ago) work_package2.update_column(:updated_at, Time.current) @@ -523,7 +523,7 @@ current_user { user1 } - it "sorts by updated_at desc" do + it 'sorts by updated_at desc' do expect(query_results.work_packages) .to match [work_package2, work_package1, work_package3] end diff --git a/spec/models/query/results_spec.rb b/spec/models/query/results_spec.rb index 97bff215992d..9aee68ece0dc 100644 --- a/spec/models/query/results_spec.rb +++ b/spec/models/query/results_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Query::Results do let(:query) do @@ -52,8 +52,8 @@ end let(:user1) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_roles: { project1 => [role_dev, role_pm] }) end let(:wp_p1) do @@ -64,7 +64,7 @@ end end - describe "#work_package_count_by_group" do + describe '#work_package_count_by_group' do let(:query) do build(:query, show_hierarchies: false, @@ -88,28 +88,28 @@ project: project1) end - context "when grouping by responsible" do - let(:group_by) { "responsible" } + context 'when grouping by responsible' do + let(:group_by) { 'responsible' } - it "produces a valid SQL statement" do + it 'produces a valid SQL statement' do expect { query_results.work_package_count_by_group }.not_to raise_error end end - context "when grouping and filtering by text" do - let(:group_by) { "responsible" } + context 'when grouping and filtering by text' do + let(:group_by) { 'responsible' } before do - query.add_filter("search", "**", ["asdf"]) + query.add_filter('search', '**', ['asdf']) end - it "produces a valid SQL statement (Regression #29598)" do + it 'produces a valid SQL statement (Regression #29598)' do expect { query_results.work_package_count_by_group }.not_to raise_error end end - context "when grouping by assigned_to" do - let(:group_by) { "assigned_to" } + context 'when grouping by assigned_to' do + let(:group_by) { 'assigned_to' } before do work_package1 @@ -118,13 +118,13 @@ login_as(user1) end - it "returns a hash of counts by value" do + it 'returns a hash of counts by value' do expect(query_results.work_package_count_by_group).to eql(nil => 1, user1 => 1) end end - context "when grouping by assigned_to with only a nil group" do - let(:group_by) { "assigned_to" } + context 'when grouping by assigned_to with only a nil group' do + let(:group_by) { 'assigned_to' } before do work_package1 @@ -132,13 +132,13 @@ login_as(user1) end - it "returns a hash of counts by value" do + it 'returns a hash of counts by value' do expect(query_results.work_package_count_by_group).to eql(nil => 1) end end - context "when grouping by type" do - let(:group_by) { "type" } + context 'when grouping by type' do + let(:group_by) { 'type' } before do work_package1 @@ -147,7 +147,7 @@ login_as(user1) end - it "returns the groups sorted by type`s position" do + it 'returns the groups sorted by type`s position' do type1.update_column(:position, 1) type2.update_column(:position, 2) @@ -174,7 +174,7 @@ end end - context "when grouping by list custom field and filtering for it at the same time" do + context 'when grouping by list custom field and filtering for it at the same time' do let!(:custom_field) do create(:list_wp_custom_field, is_for_all: true, @@ -200,7 +200,7 @@ work_package2.save! end - it "yields no error but rather returns the result" do + it 'yields no error but rather returns the result' do expect { query_results.work_package_count_by_group }.not_to raise_error group_count = query_results.work_package_count_by_group @@ -213,7 +213,7 @@ end end - context "when grouping by int custom field" do + context 'when grouping by int custom field' do let!(:custom_field) do create(:integer_wp_custom_field, is_for_all: true, @@ -233,12 +233,12 @@ wp_p1[1].save end - it "returns a hash of counts by value" do + it 'returns a hash of counts by value' do expect(query_results.work_package_count_by_group).to eql(42 => 2, nil => 1) end end - context "when grouping by user custom field" do + context 'when grouping by user custom field' do let!(:custom_field) do create(:user_wp_custom_field, is_for_all: true, is_filter: true) end @@ -252,12 +252,12 @@ project1.work_package_custom_fields << custom_field end - it "returns nil as user custom fields are not groupable" do + it 'returns nil as user custom fields are not groupable' do expect(query_results.work_package_count_by_group).to be_nil end end - context "when grouping by bool custom field" do + context 'when grouping by bool custom field' do let!(:custom_field) do create(:boolean_wp_custom_field, is_for_all: true, @@ -277,12 +277,12 @@ wp_p1[1].save end - it "returns a hash of counts by value" do + it 'returns a hash of counts by value' do expect(query_results.work_package_count_by_group).to eql(true => 2, nil => 1) end end - context "when grouping by date custom field" do + context 'when grouping by date custom field' do let!(:custom_field) do create(:date_wp_custom_field, is_for_all: true, @@ -302,13 +302,13 @@ wp_p1[1].save end - it "returns a hash of counts by value" do + it 'returns a hash of counts by value' do expect(query_results.work_package_count_by_group).to eql(Time.zone.today => 2, nil => 1) end end end - describe "filtering" do + describe 'filtering' do let!(:project1) { create(:project) } let!(:project2) { create(:project) } let!(:member) do @@ -319,8 +319,8 @@ end let!(:user2) do create(:user, - firstname: "user", - lastname: "2", + firstname: 'user', + lastname: '2', member_with_roles: { project2 => role_dev }) end @@ -339,26 +339,26 @@ wp_p1 end - context "when filtering for assigned_to_role" do + context 'when filtering for assigned_to_role' do before do allow(User).to receive(:current).and_return(user2) allow(project2.descendants).to receive(:active).and_return([]) - query.add_filter("assigned_to_role", "=", [role_dev.id.to_s]) + query.add_filter('assigned_to_role', '=', [role_dev.id.to_s]) end - context "when a project is set" do + context 'when a project is set' do let(:query) { build(:query, project: project2) } - it "displays only wp for selected project and selected role" do + it 'displays only wp for selected project and selected role' do expect(query_results.work_packages).to contain_exactly(wp_p2) end end - context "when no project is set" do + context 'when no project is set' do let(:query) { build(:query, project: nil) } - it "displays all wp from projects where User.current has access" do + it 'displays all wp from projects where User.current has access' do expect(query_results.work_packages).to contain_exactly(wp_p2, wp2_p2) end end @@ -366,7 +366,7 @@ # this tests some unfortunate combination of filters where wrong # sql statements where produced. - context "with a custom field being returned and paginating" do + context 'with a custom field being returned and paginating' do let(:group_by) { nil } let(:query) do build_stubbed(:query, @@ -385,13 +385,13 @@ query.project = Project.find(query.project.id) end - context "when grouping by assignees" do + context 'when grouping by assignees' do before do query.column_names = [:assigned_to, custom_field.column_name.to_sym] - query.group_by = "assigned_to" + query.group_by = 'assigned_to' end - it "returns all work packages of project 2" do + it 'returns all work packages of project 2' do work_packages = query .results .work_packages @@ -402,14 +402,14 @@ end end - context "when grouping by responsibles" do - let(:group_by) { "responsible" } + context 'when grouping by responsibles' do + let(:group_by) { 'responsible' } before do query.column_names = [:responsible, custom_field.column_name.to_sym] end - it "returns all work packages of project 2" do + it 'returns all work packages of project 2' do work_packages = query .results .work_packages @@ -421,14 +421,14 @@ end end - context "when grouping by responsible" do + context 'when grouping by responsible' do let(:query) do build(:query, show_hierarchies: false, group_by:, project: project1) end - let(:group_by) { "responsible" } + let(:group_by) { 'responsible' } before do allow(User).to receive(:current).and_return(user1) @@ -437,13 +437,13 @@ wp_p1[1].update_attribute(:responsible, user2) end - it "outputs the work package count in the schema { => count }" do + it 'outputs the work package count in the schema { => count }' do expect(query_results.work_package_count_by_group) .to eql(user1 => 1, user2 => 1, nil => 1) end end - context "when filtering by precedes and ordering by id" do + context 'when filtering by precedes and ordering by id' do let(:query) do build(:query, project: project1) @@ -454,9 +454,9 @@ create(:follows_relation, to: wp_p1[1], from: wp_p1[0]) - query.add_filter("precedes", "=", [wp_p1[0].id.to_s]) + query.add_filter('precedes', '=', [wp_p1[0].id.to_s]) - query.sort_criteria = [["id", "asc"]] + query.sort_criteria = [['id', 'asc']] # Reload is necessary as it fixes the lft/rgt columns of nested set # that on some runs end up being the same as project2 (reason unknown), @@ -465,14 +465,14 @@ project1.reload end - it "returns the work packages preceding the filtered for work package" do + it 'returns the work packages preceding the filtered for work package' do expect(query.results.work_packages) .to match_array(wp_p1[1]) end end end - context "when filtering by bool cf" do + context 'when filtering by bool cf' do let(:query) do build_stubbed(:query, show_hierarchies: false, @@ -494,32 +494,32 @@ customized: work_package1, value:) end - let(:value) { "t" } - let(:filter_value) { "t" } + let(:value) { 't' } + let(:filter_value) { 't' } let(:work_package1) { create(:work_package, project: project1) } let(:work_package2) { create(:work_package, project: project1, id: 2) } let(:work_package3) { create(:work_package, project: project1, id: 3) } let(:sort_by) { [%w[id asc]] } let(:columns) { %i(id subject) } - let(:group_by) { "" } + let(:group_by) { '' } before do allow(User).to receive(:current).and_return(user1) custom_value - query.add_filter(bool_cf.column_name.to_sym, "=", [filter_value]) + query.add_filter(bool_cf.column_name.to_sym, '=', [filter_value]) end - shared_examples_for "is empty" do - it "is empty" do + shared_examples_for 'is empty' do + it 'is empty' do expect(query.results.work_packages) .to be_empty end end - shared_examples_for "returns the wp" do - it "returns the wp" do + shared_examples_for 'returns the wp' do + it 'returns the wp' do expect(query.results.work_packages) .to match_array(work_package1) end @@ -527,58 +527,58 @@ context 'with the wp having true for the cf and filtering for true' do - it_behaves_like "returns the wp" + it_behaves_like 'returns the wp' end context 'with the wp having true for the cf and filtering for false' do - let(:filter_value) { "f" } + let(:filter_value) { 'f' } - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the wp having false for the cf and filtering for false' do - let(:value) { "f" } - let(:filter_value) { "f" } + let(:value) { 'f' } + let(:filter_value) { 'f' } - it_behaves_like "returns the wp" + it_behaves_like 'returns the wp' end context 'with the wp having false for the cf and filtering for true' do - let(:value) { "f" } + let(:value) { 'f' } - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the wp having no value for the cf and filtering for true' do let(:custom_value) { nil } - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the wp having no value for the cf and filtering for false' do let(:custom_value) { nil } - let(:filter_value) { "f" } + let(:filter_value) { 'f' } - it_behaves_like "returns the wp" + it_behaves_like 'returns the wp' end context 'with the wp having no value for the cf and filtering for false and the cf not being active for the type' do let(:custom_value) { nil } - let(:filter_value) { "f" } + let(:filter_value) { 'f' } let(:bool_cf) do create(:boolean_wp_custom_field, is_filter: true, types: [work_package1.type]) end - it_behaves_like "is empty" + it_behaves_like 'is empty' end context 'with the wp having no value for the cf @@ -586,7 +586,7 @@ and the cf not being active in the project and the cf being for all' do let(:custom_value) { nil } - let(:filter_value) { "f" } + let(:filter_value) { 'f' } let(:bool_cf) do create(:boolean_wp_custom_field, is_filter: true, @@ -594,7 +594,7 @@ projects: [work_package1.project]) end - it_behaves_like "is empty" + it_behaves_like 'is empty' end end end diff --git a/spec/models/query/results_subject_filter_integration_spec.rb b/spec/models/query/results_subject_filter_integration_spec.rb index a1f27eff451a..6a5817d8fc11 100644 --- a/spec/models/query/results_subject_filter_integration_spec.rb +++ b/spec/models/query/results_subject_filter_integration_spec.rb @@ -26,38 +26,38 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "Subject filter integration" do +RSpec.describe Query::Results, 'Subject filter integration' do let(:query_results) do described_class.new query end let(:project) { create(:project) } let(:user) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project => [:view_work_packages] }) end let!(:contains_wp) do create(:work_package, - subject: "The quick brown fox jumped", + subject: 'The quick brown fox jumped', project:) end let!(:contains_reversed_wp) do create(:work_package, - subject: "The quick brown fox jumped", + subject: 'The quick brown fox jumped', project:) end let!(:partially_contains_wp) do create(:work_package, - subject: "The quick brown goose jumped", + subject: 'The quick brown goose jumped', project:) end let!(:not_contains_wp) do create(:work_package, - subject: "Something completely different", + subject: 'Something completely different', project:) end @@ -71,26 +71,26 @@ end before do - query.add_filter("subject", operator, values) + query.add_filter('subject', operator, values) login_as(user) end - describe "searching for contains" do - let(:operator) { "~" } - let(:values) { ["quick fox"] } + describe 'searching for contains' do + let(:operator) { '~' } + let(:values) { ['quick fox'] } - it "returns the work packages containing the string regardless of order" do + it 'returns the work packages containing the string regardless of order' do expect(query_results.work_packages) .to contain_exactly(contains_wp, contains_reversed_wp) end end - describe "searching for not contains" do - let(:operator) { "!~" } - let(:values) { ["quick fox"] } + describe 'searching for not contains' do + let(:operator) { '!~' } + let(:values) { ['quick fox'] } - it "returns the work packages not containing the string regardless of order" do + it 'returns the work packages not containing the string regardless of order' do expect(query_results.work_packages) .to contain_exactly(not_contains_wp, partially_contains_wp) end diff --git a/spec/models/query/results_subproject_filter_integration_spec.rb b/spec/models/query/results_subproject_filter_integration_spec.rb index e380f54c50ff..8edd78fff447 100644 --- a/spec/models/query/results_subproject_filter_integration_spec.rb +++ b/spec/models/query/results_subproject_filter_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "Subproject filter integration" do +RSpec.describe Query::Results, 'Subproject filter integration' do let(:query) do build(:query, user:, @@ -45,8 +45,8 @@ shared_let(:user) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { parent_project => [:view_work_packages], child_project => [:view_work_packages] @@ -60,110 +60,110 @@ login_as user end - describe "new default query" do - context "when subprojects included", with_settings: { display_subprojects_work_packages: true } do - it "shows the sub work packages" do + describe 'new default query' do + context 'when subprojects included', with_settings: { display_subprojects_work_packages: true } do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp) end end - context "when subprojects not included", with_settings: { display_subprojects_work_packages: false } do - it "does not show the sub work packages" do + context 'when subprojects not included', with_settings: { display_subprojects_work_packages: false } do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp) end - context "when subproject filter added manually" do + context 'when subproject filter added manually' do before do - query.add_filter("subproject_id", "=", [child_project.id]) + query.add_filter('subproject_id', '=', [child_project.id]) end - it "shows the sub work packages" do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp) end end - context "when only subproject filter added manually" do + context 'when only subproject filter added manually' do before do - query.add_filter("only_subproject_id", "=", [child_project.id]) + query.add_filter('only_subproject_id', '=', [child_project.id]) end - it "shows only the sub work packages" do + it 'shows only the sub work packages' do expect(query_results.work_packages).to contain_exactly(child_wp) end end end end - describe "query with overridden include_subprojects = true" do + describe 'query with overridden include_subprojects = true' do before do query.include_subprojects = true end - context "when subprojects included", with_settings: { display_subprojects_work_packages: true } do - it "shows the sub work packages" do + context 'when subprojects included', with_settings: { display_subprojects_work_packages: true } do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp) end end - context "when subprojects not included", with_settings: { display_subprojects_work_packages: false } do - it "shows the sub work packages" do + context 'when subprojects not included', with_settings: { display_subprojects_work_packages: false } do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp) end - context "when subproject filter added manually" do + context 'when subproject filter added manually' do before do - query.add_filter("subproject_id", "=", [child_project.id]) + query.add_filter('subproject_id', '=', [child_project.id]) end - it "shows the sub work packages" do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp) end end - context "when only subproject filter added manually" do + context 'when only subproject filter added manually' do before do - query.add_filter("only_subproject_id", "=", [child_project.id]) + query.add_filter('only_subproject_id', '=', [child_project.id]) end - it "shows only the sub work packages" do + it 'shows only the sub work packages' do expect(query_results.work_packages).to contain_exactly(child_wp) end end end end - describe "query with overridden include_subprojects = false" do + describe 'query with overridden include_subprojects = false' do before do query.include_subprojects = false end - context "when subprojects included", with_settings: { display_subprojects_work_packages: true } do - it "does not show the sub work packages" do + context 'when subprojects included', with_settings: { display_subprojects_work_packages: true } do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp) end end - context "when subprojects not included", with_settings: { display_subprojects_work_packages: false } do - it "does not show the sub work packages" do + context 'when subprojects not included', with_settings: { display_subprojects_work_packages: false } do + it 'does not show the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp) end - context "when subproject filter added manually" do + context 'when subproject filter added manually' do before do - query.add_filter("subproject_id", "=", [child_project.id]) + query.add_filter('subproject_id', '=', [child_project.id]) end - it "shows the sub work packages" do + it 'shows the sub work packages' do expect(query_results.work_packages).to contain_exactly(parent_wp, child_wp) end end - context "when only subproject filter added manually" do + context 'when only subproject filter added manually' do before do - query.add_filter("only_subproject_id", "=", [child_project.id]) + query.add_filter('only_subproject_id', '=', [child_project.id]) end - it "shows only the sub work packages" do + it 'shows only the sub work packages' do expect(query_results.work_packages).to contain_exactly(child_wp) end end diff --git a/spec/models/query/results_version_integration_spec.rb b/spec/models/query/results_version_integration_spec.rb index 7c3df21a57f0..3b4b0a7aa3ea 100644 --- a/spec/models/query/results_version_integration_spec.rb +++ b/spec/models/query/results_version_integration_spec.rb @@ -26,39 +26,39 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Query::Results, "Grouping and sorting for version" do +RSpec.describe Query::Results, 'Grouping and sorting for version' do let(:query_results) do Query::Results.new query end let(:project) { create(:project) } let(:user) do create(:user, - firstname: "user", - lastname: "1", + firstname: 'user', + lastname: '1', member_with_permissions: { project => [:view_work_packages] }) end let(:old_version) do create(:version, - name: "1. Old version", + name: '1. Old version', project:, - start_date: "2019-02-02", - effective_date: "2019-02-03") + start_date: '2019-02-02', + effective_date: '2019-02-03') end let(:new_version) do create(:version, - name: "1.2 New version", + name: '1.2 New version', project:, - start_date: "2020-02-02", - effective_date: "2020-02-03") + start_date: '2020-02-02', + effective_date: '2020-02-03') end let(:no_date_version) do create(:version, - name: "1.1 No date version", + name: '1.1 No date version', project:, start_date: nil, effective_date: nil) @@ -66,30 +66,30 @@ let!(:no_version_wp) do create(:work_package, - subject: "No version wp", + subject: 'No version wp', project:) end let!(:newest_version_wp) do create(:work_package, - subject: "Newest version wp", + subject: 'Newest version wp', version: new_version, project:) end let!(:oldest_version_wp) do create(:work_package, - subject: "Oldest version wp", + subject: 'Oldest version wp', version: old_version, project:) end let!(:no_date_version_wp) do create(:work_package, - subject: "No date version wp", + subject: 'No date version wp', version: no_date_version, project:) end let(:group_by) { nil } - let(:sort_criteria) { [["version", "asc"]] } + let(:sort_criteria) { [['version', 'asc']] } let(:query) do build(:query, @@ -107,10 +107,10 @@ login_as(user) end - describe "grouping by version" do - let(:group_by) { "version" } + describe 'grouping by version' do + let(:group_by) { 'version' } - it "returns the correctly sorted grouped result" do + it 'returns the correctly sorted grouped result' do # Keys are also sorted by the version expect(query_results.work_package_count_by_group.keys) .to eql work_packages_asc.map(&:version) @@ -123,19 +123,19 @@ end end - describe "sorting ASC by version" do - let(:sort_criteria) { [["version", "asc"]] } + describe 'sorting ASC by version' do + let(:sort_criteria) { [['version', 'asc']] } - it "returns the correctly sorted result" do + it 'returns the correctly sorted result' do expect(query_results.work_packages.pluck(:id)) .to match work_packages_asc.map(&:id) end end - describe "sorting DESC by version" do - let(:sort_criteria) { [["version", "desc"]] } + describe 'sorting DESC by version' do + let(:sort_criteria) { [['version', 'desc']] } - it "returns the correctly sorted result" do + it 'returns the correctly sorted result' do # null values are still sorted last work_packages_order = [newest_version_wp, no_date_version_wp, oldest_version_wp, no_version_wp] diff --git a/spec/models/query/sort_criteria_spec.rb b/spec/models/query/sort_criteria_spec.rb index 4bc7100aec66..8cf5d81105a8 100644 --- a/spec/models/query/sort_criteria_spec.rb +++ b/spec/models/query/sort_criteria_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Query::SortCriteria do let(:query) do @@ -45,82 +45,82 @@ instance.available_criteria = available_criteria end - describe "ordered handling" do - context "with an empty sort_criteria" do + describe 'ordered handling' do + context 'with an empty sort_criteria' do let(:sort_criteria) { [] } - it "returns the default order by id" do + it 'returns the default order by id' do expect(subject) - .to eq [["work_packages.id DESC"]] + .to eq [['work_packages.id DESC']] end end - context "with a sort_criteria for id" do - let(:sort_criteria) { [["id"]] } + context 'with a sort_criteria for id' do + let(:sort_criteria) { [['id']] } - it "returns the default order by id only once" do + it 'returns the default order by id only once' do expect(subject) - .to eq [["work_packages.id"]] + .to eq [['work_packages.id']] end end - context "with a sort_criteria for id ASC" do + context 'with a sort_criteria for id ASC' do let(:sort_criteria) { [%w[id asc]] } - it "returns the custom order by id asc" do + it 'returns the custom order by id asc' do expect(subject) - .to eq [["work_packages.id"]] + .to eq [['work_packages.id']] end end - context "with a sort_criteria for typeahead ASC" do + context 'with a sort_criteria for typeahead ASC' do let(:sort_criteria) { [%w[typeahead asc]] } - it "returns the custom order by id asc" do + it 'returns the custom order by id asc' do expect(subject) - .to eq [["work_packages.updated_at DESC, work_packages.updated_at"], ["work_packages.id DESC"]] + .to eq [['work_packages.updated_at DESC, work_packages.updated_at'], ['work_packages.id DESC']] end end - context "with sort_criteria with order handling and no order statement" do - let(:sort_criteria) { [["start_date"]] } + context 'with sort_criteria with order handling and no order statement' do + let(:sort_criteria) { [['start_date']] } - it "adds the order handling (and the default order by id)" do + it 'adds the order handling (and the default order by id)' do expect(subject) - .to eq [["work_packages.start_date NULLS LAST"], ["work_packages.id DESC"]] + .to eq [['work_packages.start_date NULLS LAST'], ['work_packages.id DESC']] end end - context "with sort_criteria with order handling and ASC order statement" do + context 'with sort_criteria with order handling and ASC order statement' do let(:sort_criteria) { [%w[start_date asc]] } - it "adds the order handling (and the default order by id)" do + it 'adds the order handling (and the default order by id)' do expect(subject) - .to eq [["work_packages.start_date NULLS LAST"], ["work_packages.id DESC"]] + .to eq [['work_packages.start_date NULLS LAST'], ['work_packages.id DESC']] end end - context "with sort_criteria with order handling and DESC order statement" do + context 'with sort_criteria with order handling and DESC order statement' do let(:sort_criteria) { [%w[start_date desc]] } - it "adds the order handling (and the default order by id)" do + it 'adds the order handling (and the default order by id)' do expect(subject) - .to eq [["work_packages.start_date DESC NULLS LAST"], ["work_packages.id DESC"]] + .to eq [['work_packages.start_date DESC NULLS LAST'], ['work_packages.id DESC']] end end - context "with multiple sort_criteria with order handling and misc order statement" do + context 'with multiple sort_criteria with order handling and misc order statement' do let(:sort_criteria) { [%w[version desc], %w[start_date asc]] } - it "adds the order handling (and the default order by id)" do + it 'adds the order handling (and the default order by id)' do sort_sql = <<~SQL array_remove(regexp_split_to_array(regexp_replace(substring(versions.name from '^[^a-zA-Z]+'), '\\D+', ' ', 'g'), ' '), '')::int[] SQL expect(subject) - .to eq [["#{sort_sql} DESC NULLS LAST", "name DESC NULLS LAST"], - ["work_packages.start_date NULLS LAST"], - ["work_packages.id DESC"]] + .to eq [["#{sort_sql} DESC NULLS LAST", 'name DESC NULLS LAST'], + ['work_packages.start_date NULLS LAST'], + ['work_packages.id DESC']] end end end diff --git a/spec/models/query/timestamps_spec.rb b/spec/models/query/timestamps_spec.rb index f175adf08c0c..ab876ae5fdac 100644 --- a/spec/models/query/timestamps_spec.rb +++ b/spec/models/query/timestamps_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Query::Timestamps, with_ee: %i[baseline_comparison] do diff --git a/spec/models/query_spec.rb b/spec/models/query_spec.rb index f1e7855090ad..5039fc106a7b 100644 --- a/spec/models/query_spec.rb +++ b/spec/models/query_spec.rb @@ -26,92 +26,92 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Query, with_ee: %i[baseline_comparison conditional_highlighting work_package_query_relation_columns] do let(:query) { build(:query) } let(:project) { create(:project) } - describe ".new_default" do - it "set the default sortation" do + describe '.new_default' do + it 'set the default sortation' do query = described_class.new_default expect(query.sort_criteria) - .to contain_exactly(["id", "asc"]) + .to contain_exactly(['id', 'asc']) end - it "does not use the default sortation if an order is provided" do - query = described_class.new_default(sort_criteria: [["id", "asc"]]) + it 'does not use the default sortation if an order is provided' do + query = described_class.new_default(sort_criteria: [['id', 'asc']]) expect(query.sort_criteria) - .to contain_exactly(["id", "asc"]) + .to contain_exactly(['id', 'asc']) end - context "with global subprojects include", with_settings: { display_subprojects_work_packages: true } do - it "sets the include subprojects" do + context 'with global subprojects include', with_settings: { display_subprojects_work_packages: true } do + it 'sets the include subprojects' do expect(query.include_subprojects).to be true end end - context "with global subprojects include", with_settings: { display_subprojects_work_packages: false } do - it "sets the include subprojects" do + context 'with global subprojects include', with_settings: { display_subprojects_work_packages: false } do + it 'sets the include subprojects' do expect(query.include_subprojects).to be false end end end - describe "include_subprojects" do - let(:query) { described_class.new name: "foo" } + describe 'include_subprojects' do + let(:query) { described_class.new name: 'foo' } - it "is required" do + it 'is required' do expect(query).not_to be_valid - expect(query.errors[:include_subprojects]).to include "is not set to one of the allowed values." + expect(query.errors[:include_subprojects]).to include 'is not set to one of the allowed values.' end end - describe "hidden" do - context "with a view" do + describe 'hidden' do + context 'with a view' do before do create(:view_work_packages_table, query:) end - it "is false" do + it 'is false' do expect(query.hidden).to be(false) end end - context "without a view" do - it "is true" do + context 'without a view' do + it 'is true' do expect(query.hidden).to be(true) end end end - describe "timeline" do - it "has a property for timeline visible" do + describe 'timeline' do + it 'has a property for timeline visible' do expect(query.timeline_visible).to be_falsey query.timeline_visible = true expect(query.timeline_visible).to be_truthy end - it "validates the timeline labels hash keys" do + it 'validates the timeline labels hash keys' do expect(query.timeline_labels).to eq({}) expect(query).to be_valid - query.timeline_labels = { "left" => "foobar", "xyz" => "bar" } + query.timeline_labels = { 'left' => 'foobar', 'xyz' => 'bar' } expect(query).not_to be_valid - query.timeline_labels = { "left" => "foobar", "right" => "bar", "farRight" => "blub" } + query.timeline_labels = { 'left' => 'foobar', 'right' => 'bar', 'farRight' => 'blub' } expect(query).to be_valid end end - describe "timestamps" do + describe 'timestamps' do subject { build(:query, timestamps:) } - context "with EE", with_ee: %i[baseline_comparison] do + context 'with EE', with_ee: %i[baseline_comparison] do Timestamp::ALLOWED_DATE_KEYWORDS.each do |timestamp_date_keyword| context "when the '#{timestamp_date_keyword}' value is provided" do let(:timestamps) { ["#{timestamp_date_keyword}@12:00+00:00"] } @@ -139,7 +139,7 @@ end end - context "without EE", with_ee: false do + context 'without EE', with_ee: false do context "when the 'oneDayAgo' value is provided" do let(:timestamps) { ["oneDayAgo@12:00+00:00"] } @@ -186,7 +186,7 @@ context "when the '#{timestamp_date_keyword}' value is provided" do let(:timestamps) { ["#{timestamp_date_keyword}@12:00+00:00"] } - it "is invalid" do + it 'is invalid' do expect(subject).not_to be_valid expect(subject.errors.symbols_for(:timestamps)).to eq [:forbidden] end @@ -200,7 +200,7 @@ allow(Day).to receive(:last_working) { Day.new(date: 7.days.ago) } end - it "is invalid" do + it 'is invalid' do expect(subject).not_to be_valid expect(subject.errors.symbols_for(:timestamps)).to eq [:forbidden] end @@ -209,7 +209,7 @@ context "when a duration value older than yesterday is provided" do let(:timestamps) { ["P-2D"] } - it "is invalid" do + it 'is invalid' do expect(subject).not_to be_valid expect(subject.errors.symbols_for(:timestamps)).to eq [:forbidden] end @@ -218,7 +218,7 @@ context "when an iso8601 datetime value older than yesterday is provided" do let(:timestamps) { [2.days.ago.end_of_day.iso8601] } - it "is invalid" do + it 'is invalid' do expect(subject).not_to be_valid expect(subject.errors.symbols_for(:timestamps)).to eq [:forbidden] end @@ -226,32 +226,32 @@ end end - describe "highlighting" do - context "with EE" do - it "#highlighted_attributes accepts valid values" do + describe 'highlighting' do + context 'with EE' do + it '#highlighted_attributes accepts valid values' do query.highlighted_attributes = %w(status priority due_date) expect(query).to be_valid end - it "#highlighted_attributes rejects invalid values" do + it '#highlighted_attributes rejects invalid values' do query.highlighted_attributes = %w(status bogus) expect(query).not_to be_valid end - it "#hightlighting_mode accepts non-present values" do + it '#hightlighting_mode accepts non-present values' do query.highlighting_mode = nil expect(query).to be_valid - query.highlighting_mode = "" + query.highlighting_mode = '' expect(query).to be_valid end - it "#hightlighting_mode rejects invalid values" do - query.highlighting_mode = "bogus" + it '#hightlighting_mode rejects invalid values' do + query.highlighting_mode = 'bogus' expect(query).not_to be_valid end - it "#available_highlighting_columns returns highlightable columns" do + it '#available_highlighting_columns returns highlightable columns' do available_columns = { highlightable1: { highlightable: true @@ -268,14 +268,14 @@ expect(query.available_highlighting_columns.map(&:name)).to eq(%i{highlightable1 highlightable2}) end - describe "#highlighted_columns returns a valid subset of Columns" do + describe '#highlighted_columns returns a valid subset of Columns' do let(:highlighted_attributes) { %i{status priority due_date foo} } before do query.highlighted_attributes = highlighted_attributes end - it "removes the offending values" do + it 'removes the offending values' do query.valid_subset! expect(query.highlighted_columns.map(&:name)) @@ -284,29 +284,29 @@ end end - context "without EE", with_ee: false do - it "always returns :none as highlighting_mode" do - query.highlighting_mode = "status" + context 'without EE', with_ee: false do + it 'always returns :none as highlighting_mode' do + query.highlighting_mode = 'status' expect(query.highlighting_mode).to eq(:none) end - it "always returns nil as highlighted_attributes" do - query.highlighting_mode = "inline" - query.highlighted_attributes = ["status"] + it 'always returns nil as highlighted_attributes' do + query.highlighting_mode = 'inline' + query.highlighted_attributes = ['status'] expect(query.highlighted_attributes).to be_empty end end end - describe "hierarchies" do - it "is enabled in default queries" do + describe 'hierarchies' do + it 'is enabled in default queries' do query = described_class.new_default expect(query.show_hierarchies).to be_truthy query.show_hierarchies = false expect(query.show_hierarchies).to be_falsey end - it "is mutually exclusive with group_by" do + it 'is mutually exclusive with group_by' do query = described_class.new_default expect(query.show_hierarchies).to be_truthy query.group_by = :assignee @@ -314,31 +314,31 @@ expect(query.save).to be_falsey expect(query).not_to be_valid expect(query.errors[:show_hierarchies].first) - .to include(I18n.t("activerecord.errors.models.query.group_by_hierarchies_exclusive", group_by: "assignee")) + .to include(I18n.t('activerecord.errors.models.query.group_by_hierarchies_exclusive', group_by: 'assignee')) end end - describe "#available_columns" do - context "with work_package_done_ratio NOT disabled" do - it "includes the done_ratio column" do + describe '#available_columns' do + context 'with work_package_done_ratio NOT disabled' do + it 'includes the done_ratio column' do expect(query.displayable_columns.map(&:name)).to include :done_ratio end end - context "with work_package_done_ratio disabled" do + context 'with work_package_done_ratio disabled' do before do allow(WorkPackage).to receive(:done_ratio_disabled?).and_return(true) end - it "does not include the done_ratio column" do + it 'does not include the done_ratio column' do expect(query.displayable_columns.map(&:name)).not_to include :done_ratio end end - context "results caching" do + context 'results caching' do let(:project2) { create(:project) } - it "does not call the db twice" do + it 'does not call the db twice' do query.project = project query.displayable_columns @@ -352,7 +352,7 @@ query.displayable_columns end - it "does call the db if the project changes" do + it 'does call the db if the project changes' do query.project = project query.displayable_columns @@ -370,7 +370,7 @@ query.displayable_columns end - it "does call the db if the project changes to nil" do + it 'does call the db if the project changes to nil' do query.project = project query.displayable_columns @@ -389,7 +389,7 @@ end end - context "relation_to_type columns" do + context 'relation_to_type columns' do let(:type_in_project) do type = create(:type) project.types << type @@ -406,38 +406,38 @@ type_not_in_project end - context "when in project" do + context 'when in project' do before do query.project = project end - it "includes the relation columns for project types" do + it 'includes the relation columns for project types' do expect(query.displayable_columns.map(&:name)).to include :"relations_to_type_#{type_in_project.id}" end - it "does not include the relation columns for types not in project" do + it 'does not include the relation columns for types not in project' do expect(query.displayable_columns.map(&:name)).not_to include :"relations_to_type_#{type_not_in_project.id}" end - context "with the enterprise token disallowing relation columns", with_ee: false do - it "excludes the relation columns" do + context 'with the enterprise token disallowing relation columns', with_ee: false do + it 'excludes the relation columns' do expect(query.displayable_columns.map(&:name)).not_to include :"relations_to_type_#{type_in_project.id}" end end end - context "when global" do + context 'when global' do before do query.project = nil end - it "includes the relation columns for all types" do + it 'includes the relation columns for all types' do expect(query.displayable_columns.map(&:name)).to include(:"relations_to_type_#{type_in_project.id}", :"relations_to_type_#{type_not_in_project.id}") end - context "with the enterprise token disallowing relation columns", with_ee: false do - it "excludes the relation columns" do + context 'with the enterprise token disallowing relation columns', with_ee: false do + it 'excludes the relation columns' do expect(query.displayable_columns.map(&:name)).not_to include(:"relations_to_type_#{type_in_project.id}", :"relations_to_type_#{type_not_in_project.id}") end @@ -445,20 +445,20 @@ end end - context "with relation_of_type columns" do + context 'with relation_of_type columns' do before do - stub_const("Relation::TYPES", + stub_const('Relation::TYPES', relation1: { name: :label_relates_to, sym_name: :label_relates_to, order: 1, sym: :relation1 }, relation2: { name: :label_duplicates, sym_name: :label_duplicated_by, order: 2, sym: :relation2 }) end - it "includes the relation columns for every relation type" do + it 'includes the relation columns for every relation type' do expect(query.displayable_columns.map(&:name)).to include(:relations_of_type_relation1, :relations_of_type_relation2) end - context "with the enterprise token disallowing relation columns", with_ee: false do - it "excludes the relation columns" do + context 'with the enterprise token disallowing relation columns', with_ee: false do + it 'excludes the relation columns' do expect(query.displayable_columns.map(&:name)).not_to include(:relations_of_type_relation1, :relations_of_type_relation2) end @@ -466,35 +466,35 @@ end end - describe ".displayable_columns" do - it "includes the id column" do + describe '.displayable_columns' do + it 'includes the id column' do expect(query.displayable_columns.detect { |c| c.name == :id }) .not_to be_nil end - it "excludes the manual sorting column" do + it 'excludes the manual sorting column' do expect(query.displayable_columns.detect { |c| c.name == :manual_sorting }) .to be_nil end - it "excludes the typeahead column" do + it 'excludes the typeahead column' do expect(query.displayable_columns.detect { |c| c.name == :typeahead }) .to be_nil end end - describe ".available_columns" do + describe '.available_columns' do let(:custom_field) { create(:list_wp_custom_field) } let(:type) { create(:type) } before do - stub_const("Relation::TYPES", + stub_const('Relation::TYPES', relation1: { name: :label_relates_to, sym_name: :label_relates_to, order: 1, sym: :relation1 }, relation2: { name: :label_duplicates, sym_name: :label_duplicated_by, order: 2, sym: :relation2 }) end - context "with the enterprise token allowing relation columns" do - it "has all static columns, cf columns and relation columns" do + context 'with the enterprise token allowing relation columns' do + it 'has all static columns, cf columns and relation columns' do expected_columns = %i(id project assigned_to author category created_at due_date estimated_hours parent done_ratio priority responsible @@ -508,8 +508,8 @@ end end - context "with the enterprise token disallowing relation columns", with_ee: false do - it "has all static columns, cf columns but no relation columns" do + context 'with the enterprise token disallowing relation columns', with_ee: false do + it 'has all static columns, cf columns but no relation columns' do expected_columns = %i(id project assigned_to author category created_at due_date estimated_hours parent done_ratio priority responsible @@ -526,58 +526,58 @@ end end - describe "#valid?" do - context "with a missing value and an operator that requires values" do + describe '#valid?' do + context 'with a missing value and an operator that requires values' do before do - query.add_filter("due_date", "t-", [""]) + query.add_filter('due_date', 't-', ['']) end - it "is not valid and creates an error" do + it 'is not valid and creates an error' do expect(query).not_to be_valid - expect(query.errors[:base].first).to include(I18n.t("activerecord.errors.messages.blank")) + expect(query.errors[:base].first).to include(I18n.t('activerecord.errors.messages.blank')) end end - context "when filters are blank" do + context 'when filters are blank' do let(:status) { create(:status) } let(:query) { build(:query).tap { |q| q.filters = [] } } - it "is valid" do + it 'is valid' do expect(query) .to be_valid end end - context "with a missing value for a custom field" do + context 'with a missing value for a custom field' do let(:custom_field) do create(:issue_custom_field, :text, is_filter: true, is_for_all: true) end before do - query.add_filter(custom_field.column_name, "=", [""]) + query.add_filter(custom_field.column_name, '=', ['']) end - it "has the name of the custom field in the error message" do + it 'has the name of the custom field in the error message' do expect(query).not_to be_valid expect(query.errors.messages[:base].to_s).to include(custom_field.name) end end - context "with a filter for a non existing custom field" do + context 'with a filter for a non existing custom field' do before do - query.add_filter("cf_0", "=", ["1"]) + query.add_filter('cf_0', '=', ['1']) end - it "is not valid" do + it 'is not valid' do expect(query).not_to be_valid end end end - describe "#valid_subset!" do + describe '#valid_subset!' do let(:valid_status) { build_stubbed(:status) } - context "with filters" do + context 'with filters' do before do allow(Status) .to receive(:all) @@ -588,67 +588,67 @@ .and_return(true) query.filters.clear - query.add_filter("status_id", "=", values) + query.add_filter('status_id', '=', values) query.valid_subset! end - context "for a status filter having valid and invalid values" do - let(:values) { [valid_status.id.to_s, "99999"] } + context 'for a status filter having valid and invalid values' do + let(:values) { [valid_status.id.to_s, '99999'] } - it "leaves the filter" do + it 'leaves the filter' do expect(query.filters.length).to eq 1 end - it "leaves only the valid value" do + it 'leaves only the valid value' do expect(query.filters[0].values) .to contain_exactly(valid_status.id.to_s) end end - context "for a status filter having only invalid values" do - let(:values) { ["99999"] } + context 'for a status filter having only invalid values' do + let(:values) { ['99999'] } - it "removes the filter" do + it 'removes the filter' do expect(query.filters.length).to eq 0 end end - context "for an unavailable filter" do + context 'for an unavailable filter' do let(:values) { [valid_status.id.to_s] } before do - query.add_filter("cf_0815", "=", ["1"]) + query.add_filter('cf_0815', '=', ['1']) query.valid_subset! end - it "removes the invalid filter" do + it 'removes the invalid filter' do expect(query.filters.length).to eq 1 expect(query.filters[0].name).to eq :status_id end end end - context "with group_by" do + context 'with group_by' do before do query.group_by = group_by end - context "valid" do - let(:group_by) { "project" } + context 'valid' do + let(:group_by) { 'project' } - it "leaves the value untouched" do + it 'leaves the value untouched' do query.valid_subset! expect(query.group_by).to eql group_by end end - context "invalid" do - let(:group_by) { "cf_0815" } + context 'invalid' do + let(:group_by) { 'cf_0815' } - it "removes the group by" do + it 'removes the group by' do query.valid_subset! expect(query.group_by).to be_nil @@ -656,60 +656,60 @@ end end - context "with sort_criteria" do + context 'with sort_criteria' do before do query.sort_criteria = sort_by end - context "valid" do - let(:sort_by) { [["project", "desc"]] } + context 'valid' do + let(:sort_by) { [['project', 'desc']] } - it "leaves the value untouched" do + it 'leaves the value untouched' do query.valid_subset! expect(query.sort_criteria).to eql sort_by end end - context "invalid" do - let(:sort_by) { [["cf_0815", "desc"]] } + context 'invalid' do + let(:sort_by) { [['cf_0815', 'desc']] } - it "removes the sorting" do + it 'removes the sorting' do query.valid_subset! expect(query.sort_criteria).to be_empty end end - context "parent" do - let(:sort_by) { [["parent", "asc"], ["start_date", "asc"]] } + context 'parent' do + let(:sort_by) { [['parent', 'asc'], ['start_date', 'asc']] } - it "is valid" do + it 'is valid' do expect(query).to be_valid - expect(query.sort_criteria).to contain_exactly(["id", "asc"], ["start_date", "asc"]) + expect(query.sort_criteria).to contain_exactly(['id', 'asc'], ['start_date', 'asc']) end end - context "partially invalid" do - let(:sort_by) { [["cf_0815", "desc"], ["project", "desc"]] } + context 'partially invalid' do + let(:sort_by) { [['cf_0815', 'desc'], ['project', 'desc']] } - it "removes the offending values from sort" do + it 'removes the offending values from sort' do query.valid_subset! - expect(query.sort_criteria).to contain_exactly(["project", "desc"]) + expect(query.sort_criteria).to contain_exactly(['project', 'desc']) end end end - context "with columns" do + context 'with columns' do before do query.column_names = columns end - context "valid" do + context 'valid' do let(:columns) { %i(status project) } - it "leaves the values untouched" do + it 'leaves the values untouched' do query.valid_subset! expect(query.column_names) @@ -717,10 +717,10 @@ end end - context "invalid" do + context 'invalid' do let(:columns) { %i(bogus cf_0815) } - it "removes the values" do + it 'removes the values' do query.valid_subset! expect(query.column_names) @@ -728,10 +728,10 @@ end end - context "partially invalid" do + context 'partially invalid' do let(:columns) { %i(status cf_0815) } - it "removes the offending values" do + it 'removes the offending values' do query.valid_subset! expect(query.column_names) @@ -740,14 +740,14 @@ end end - context "with highlighted_attributes" do + context 'with highlighted_attributes' do let(:highlighted_attributes) { %i{status priority due_date foo} } before do query.highlighted_attributes = highlighted_attributes end - it "removes the offending values" do + it 'removes the offending values' do query.valid_subset! expect(query.highlighted_attributes) @@ -755,9 +755,9 @@ end end - context "with timestamps" do + context 'with timestamps' do let(:timestamps) do - [3.weeks.ago.iso8601, "oneWeekAgo@12:00+00:00", "oneDayAgo@12:00+00:00", "PT0S"] + [3.weeks.ago.iso8601, 'oneWeekAgo@12:00+00:00', 'oneDayAgo@12:00+00:00', 'PT0S'] end before do @@ -765,15 +765,15 @@ query.valid_subset! end - context "without EE", with_ee: false do - it "removes the forbidden values" do + context 'without EE', with_ee: false do + it 'removes the forbidden values' do expect(query.timestamps) .to match_array %w{oneDayAgo@12:00+00:00 PT0S} end end - context "with EE", with_ee: %i[baseline_comparison] do - it "allows all valid values" do + context 'with EE', with_ee: %i[baseline_comparison] do + it 'allows all valid values' do expect(query.timestamps) .to match_array timestamps end @@ -781,26 +781,26 @@ end end - describe "#filter_for" do - context "for a status_id filter" do - subject { query.filter_for("status_id") } + describe '#filter_for' do + context 'for a status_id filter' do + subject { query.filter_for('status_id') } - it "exists" do + it 'exists' do expect(subject).not_to be_nil end - it "has the context set" do + it 'has the context set' do expect(subject.context).to eql query end - it "reuses an existing filter" do - expect(subject.object_id).to eql query.filter_for("status_id").object_id + it 'reuses an existing filter' do + expect(subject.object_id).to eql query.filter_for('status_id').object_id end end end - describe "filters after deserialization" do - it "sets the context (project) on deserialization" do + describe 'filters after deserialization' do + it 'sets the context (project) on deserialization' do query.save! query.reload @@ -810,24 +810,24 @@ end end - describe "#remove_filter" do - context "if the filter exists" do - it "removes the filter" do + describe '#remove_filter' do + context 'if the filter exists' do + it 'removes the filter' do # Works because status_id is there by default - expect { query.remove_filter("status_id") } + expect { query.remove_filter('status_id') } .to change { query.filters.count }.by(-1) end end - context "if the filter does not exist" do - it "is a noop" do - expect { query.remove_filter("assigned_to_id") } + context 'if the filter does not exist' do + it 'is a noop' do + expect { query.remove_filter('assigned_to_id') } .not_to change { query.filters.count } end end end - describe "filters and statement_filters (private method)" do + describe 'filters and statement_filters (private method)' do def subproject_filter?(filter) filter.is_a?(Queries::WorkPackages::Filter::SubprojectFilter) end @@ -836,7 +836,7 @@ def detect_subproject_filter(filters) filters.detect { |filter| subproject_filter?(filter) } end - shared_examples_for "adds a subproject id filter" do |operator| + shared_examples_for 'adds a subproject id filter' do |operator| it "does not add a visible subproject filter" do expect(detect_subproject_filter(query.filters)).to be_nil end @@ -848,8 +848,8 @@ def detect_subproject_filter(filters) end end - shared_examples_for "does not add a subproject id filter" do - it "does not add a second subproject id filter" do + shared_examples_for 'does not add a subproject id filter' do + it 'does not add a second subproject id filter' do expect(query.filters.count).to eq(query.send(:statement_filters).count) expect(query.filters.select { |filter| subproject_filter?(filter) }) @@ -857,51 +857,51 @@ def detect_subproject_filter(filters) end end - context "when subprojects included settings active", with_settings: { display_subprojects_work_packages: true } do - it_behaves_like "adds a subproject id filter", "*" + context 'when subprojects included settings active', with_settings: { display_subprojects_work_packages: true } do + it_behaves_like 'adds a subproject id filter', '*' end - context "when subprojects included settings inactive", with_settings: { display_subprojects_work_packages: false } do - it_behaves_like "adds a subproject id filter", "!*" + context 'when subprojects included settings inactive', with_settings: { display_subprojects_work_packages: false } do + it_behaves_like 'adds a subproject id filter', '!*' end - context "with a subproject filter added manually" do + context 'with a subproject filter added manually' do before do - query.add_filter("subproject_id", "=", ["1234"]) + query.add_filter('subproject_id', '=', ['1234']) end - it_behaves_like "does not add a subproject id filter" + it_behaves_like 'does not add a subproject id filter' end - context "with a only_subproject filter added manually" do + context 'with a only_subproject filter added manually' do before do - query.add_filter("only_subproject_id", "=", ["1234"]) + query.add_filter('only_subproject_id', '=', ['1234']) end - it_behaves_like "does not add a subproject id filter" + it_behaves_like 'does not add a subproject id filter' end - context "with a project filter added manually" do + context 'with a project filter added manually' do before do - query.add_filter("project_id", "=", ["1234"]) + query.add_filter('project_id', '=', ['1234']) end - it_behaves_like "does not add a subproject id filter" + it_behaves_like 'does not add a subproject id filter' end end - describe "ical tokens" do + describe 'ical tokens' do let(:user) { create(:user) } let(:query) { create(:query, user:) } - context "when present" do + context 'when present' do let(:ical_token) { create(:ical_token, user:, query:, name: "Some Token") } - it "can be accessed via relation" do + it 'can be accessed via relation' do expect(query.ical_tokens).to contain_exactly(ical_token) end - it "are destroyed when query is destroyed" do + it 'are destroyed when query is destroyed' do expect do query.destroy! end.to change { Token::ICal.where(id: ical_token.id).count }.by(-1) @@ -909,8 +909,8 @@ def detect_subproject_filter(filters) end end - context "when not present" do - it "do not cause errors on query.destroy" do + context 'when not present' do + it 'do not cause errors on query.destroy' do expect do query.destroy! end.not_to raise_error diff --git a/spec/models/relation_spec.rb b/spec/models/relation_spec.rb index 312e9a2ae05e..2539e89eabf7 100644 --- a/spec/models/relation_spec.rb +++ b/spec/models/relation_spec.rb @@ -25,17 +25,17 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Relation do create_shared_association_defaults_for_work_package_factory let(:from) { create(:work_package) } let(:to) { create(:work_package) } - let(:type) { "relates" } + let(:type) { 'relates' } let(:relation) { build(:relation, from:, to:, relation_type: type) } - describe "all relation types" do + describe 'all relation types' do Relation::TYPES.each do |key, type_hash| let(:type) { key } let(:reversed) { type_hash[:reverse] } @@ -54,20 +54,20 @@ end end - describe "#relation_type= / #relation_type" do + describe '#relation_type= / #relation_type' do let(:type) { Relation::TYPE_RELATES } - it "sets the type" do + it 'sets the type' do relation.relation_type = Relation::TYPE_BLOCKS expect(relation.relation_type).to eq(Relation::TYPE_BLOCKS) end end - describe "follows / precedes" do - context "for FOLLOWS" do + describe 'follows / precedes' do + context 'for FOLLOWS' do let(:type) { Relation::TYPE_FOLLOWS } - it "is not reversed" do + it 'is not reversed' do expect(relation.save).to be(true) relation.reload @@ -76,8 +76,8 @@ expect(relation.from).to eq(from) end - it "fails validation with invalid date and reverses" do - relation.delay = "xx" + it 'fails validation with invalid date and reverses' do + relation.delay = 'xx' expect(relation).not_to be_valid expect(relation.save).to be(false) @@ -87,10 +87,10 @@ end end - context "for PRECEDES" do + context 'for PRECEDES' do let(:type) { Relation::TYPE_PRECEDES } - it "is reversed" do + it 'is reversed' do expect(relation.save).to be(true) relation.reload @@ -101,63 +101,63 @@ end end - describe "#follows?" do - context "for a follows relation" do + describe '#follows?' do + context 'for a follows relation' do let(:type) { Relation::TYPE_FOLLOWS } - it "is truthy" do + it 'is truthy' do expect(relation) .to be_follows end end - context "for a precedes relation" do + context 'for a precedes relation' do let(:type) { Relation::TYPE_PRECEDES } - it "is truthy" do + it 'is truthy' do expect(relation) .to be_follows end end - context "for a blocks relation" do + context 'for a blocks relation' do let(:type) { Relation::TYPE_BLOCKS } - it "is falsey" do + it 'is falsey' do expect(relation) .not_to be_follows end end end - describe "#successor_soonest_start" do - context "with a follows relation" do + describe '#successor_soonest_start' do + context 'with a follows relation' do let_schedule(<<~CHART) days | MTWTFSS | main | ] | follower | | follows main CHART - it "returns predecessor due_date + 1" do - relation = schedule.follows_relation(from: "follower", to: "main") + it 'returns predecessor due_date + 1' do + relation = schedule.follows_relation(from: 'follower', to: 'main') expect(relation.successor_soonest_start).to eq(schedule.tuesday) end end - context "with a follows relation with predecessor having only start date" do + context 'with a follows relation with predecessor having only start date' do let_schedule(<<~CHART) days | MTWTFSS | main | [ | follower | | follows main CHART - it "returns predecessor start_date + 1" do - relation = schedule.follows_relation(from: "follower", to: "main") + it 'returns predecessor start_date + 1' do + relation = schedule.follows_relation(from: 'follower', to: 'main') expect(relation.successor_soonest_start).to eq(schedule.tuesday) end end - context "with a non-follows relation" do + context 'with a non-follows relation' do let_schedule(<<~CHART) days | MTWTFSS | main | X | @@ -165,12 +165,12 @@ CHART let(:relation) { create(:relation, from: main, to: related) } - it "returns nil" do + it 'returns nil' do expect(relation.successor_soonest_start).to be_nil end end - context "with a follows relation with a delay" do + context 'with a follows relation with a delay' do let_schedule(<<~CHART) days | MTWTFSS | main | X | @@ -179,19 +179,19 @@ follower_c | | follows main with delay 3 CHART - it "returns predecessor due_date + delay + 1" do - relation_a = schedule.follows_relation(from: "follower_a", to: "main") + it 'returns predecessor due_date + delay + 1' do + relation_a = schedule.follows_relation(from: 'follower_a', to: 'main') expect(relation_a.successor_soonest_start).to eq(schedule.tuesday) - relation_b = schedule.follows_relation(from: "follower_b", to: "main") + relation_b = schedule.follows_relation(from: 'follower_b', to: 'main') expect(relation_b.successor_soonest_start).to eq(schedule.wednesday) - relation_c = schedule.follows_relation(from: "follower_c", to: "main") + relation_c = schedule.follows_relation(from: 'follower_c', to: 'main') expect(relation_c.successor_soonest_start).to eq(schedule.friday) end end - context "with a follows relation with a delay and with non-working days in the delay period" do + context 'with a follows relation with a delay and with non-working days in the delay period' do let_schedule(<<~CHART) days | MTWTFSSmtw | main | X░ ░ ░░ ░ | @@ -201,24 +201,24 @@ follower_delay3 | ░ ░ ░░ ░ | follows main with delay 3 CHART - it "returns a date such as the number of working days between both work package is equal to the delay" do - set_work_week("monday", "wednesday", "friday") + it 'returns a date such as the number of working days between both work package is equal to the delay' do + set_work_week('monday', 'wednesday', 'friday') - relation_delay0 = schedule.follows_relation(from: "follower_delay0", to: "main") + relation_delay0 = schedule.follows_relation(from: 'follower_delay0', to: 'main') expect(relation_delay0.successor_soonest_start).to eq(schedule.wednesday) - relation_delay1 = schedule.follows_relation(from: "follower_delay1", to: "main") + relation_delay1 = schedule.follows_relation(from: 'follower_delay1', to: 'main') expect(relation_delay1.successor_soonest_start).to eq(schedule.friday) - relation_delay2 = schedule.follows_relation(from: "follower_delay2", to: "main") + relation_delay2 = schedule.follows_relation(from: 'follower_delay2', to: 'main') expect(relation_delay2.successor_soonest_start).to eq(schedule.monday + 7.days) - relation_delay3 = schedule.follows_relation(from: "follower_delay3", to: "main") + relation_delay3 = schedule.follows_relation(from: 'follower_delay3', to: 'main') expect(relation_delay3.successor_soonest_start).to eq(schedule.wednesday + 7.days) end end - context "with a follows relation with a delay, non-working days, and follower ignoring non-working days" do + context 'with a follows relation with a delay, non-working days, and follower ignoring non-working days' do let_schedule(<<~CHART) days | MTWTFSSmtw | main | X░ ░ ░░ ░ | @@ -228,19 +228,19 @@ follower_delay3 | ░ ░ ░░ ░ | follows main with delay 3, working days include weekends CHART - it "returns predecessor due_date + delay + 1 (like without non-working days)" do - set_work_week("monday", "wednesday", "friday") + it 'returns predecessor due_date + delay + 1 (like without non-working days)' do + set_work_week('monday', 'wednesday', 'friday') - relation_delay0 = schedule.follows_relation(from: "follower_delay0", to: "main") + relation_delay0 = schedule.follows_relation(from: 'follower_delay0', to: 'main') expect(relation_delay0.successor_soonest_start).to eq(schedule.tuesday) - relation_delay1 = schedule.follows_relation(from: "follower_delay1", to: "main") + relation_delay1 = schedule.follows_relation(from: 'follower_delay1', to: 'main') expect(relation_delay1.successor_soonest_start).to eq(schedule.wednesday) - relation_delay2 = schedule.follows_relation(from: "follower_delay2", to: "main") + relation_delay2 = schedule.follows_relation(from: 'follower_delay2', to: 'main') expect(relation_delay2.successor_soonest_start).to eq(schedule.thursday) - relation_delay3 = schedule.follows_relation(from: "follower_delay3", to: "main") + relation_delay3 = schedule.follows_relation(from: 'follower_delay3', to: 'main') expect(relation_delay3.successor_soonest_start).to eq(schedule.friday) end end diff --git a/spec/models/relations/scopes/visible_spec.rb b/spec/models/relations/scopes/visible_spec.rb index f9b5424e847d..9c9f5731c0df 100644 --- a/spec/models/relations/scopes/visible_spec.rb +++ b/spec/models/relations/scopes/visible_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Relations::Scopes::Visible do let(:from) { create(:work_package, project: project1) } @@ -34,7 +34,7 @@ let(:to) { create(:work_package, project: project2) } let(:project1) { create(:project) } let(:project2) { create(:project) } - let(:type) { "relates" } + let(:type) { 'relates' } let!(:relation1) { create(:relation, from:, to: intermediary, relation_type: type) } let!(:relation2) { create(:relation, from: intermediary, to:, relation_type: type) } let(:user) { create(:user) } @@ -53,36 +53,36 @@ roles: [role]) end - describe ".visible" do - context "when the user can see all work packages" do + describe '.visible' do + context 'when the user can see all work packages' do before do member_project1 member_project2 end - it "returns the relations" do + it 'returns the relations' do expect(Relation.visible(user)) .to contain_exactly(relation1, relation2) end end - context "when the user can see only the work packages in one project" do + context 'when the user can see only the work packages in one project' do before do member_project1 end - it "returns the relation within the one project" do + it 'returns the relation within the one project' do expect(Relation.visible(user)) .to contain_exactly(relation1) end end - context "when the user can see only the to work packages" do + context 'when the user can see only the to work packages' do before do member_project2 end - it "does not return any relation (as the relation points outside the project)" do + it 'does not return any relation (as the relation points outside the project)' do expect(Relation.visible(user)) .to be_empty end diff --git a/spec/models/reports_services_spec.rb b/spec/models/reports_services_spec.rb index f3c1de0661ff..810c1e89473f 100644 --- a/spec/models/reports_services_spec.rb +++ b/spec/models/reports_services_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Reports::ReportsService do let(:project) { create(:project) } - it "is initializable with a project" do + it 'is initializable with a project' do expect { Reports::ReportsService.new(project) }.not_to raise_error end - it "raises an error, when given no project" do + it 'raises an error, when given no project' do expect { Reports::ReportsService.new(nil) }.to raise_error("You must provide a project to report upon") end end diff --git a/spec/models/repository/git_spec.rb b/spec/models/repository/git_spec.rb index 0fd6e926cb8a..c21b0f7365cc 100644 --- a/spec/models/repository/git_spec.rb +++ b/spec/models/repository/git_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Repository::Git do - let(:encoding) { "UTF-8" } + let(:encoding) { 'UTF-8' } let(:instance) { build(:repository_git, path_encoding: encoding) } let(:adapter) { instance.scm } let(:config) { {} } @@ -41,81 +41,81 @@ allow(adapter.class).to receive(:config).and_return(config) end - describe "when disabled" do + describe 'when disabled' do let(:enabled_scm) { [] } - it "does not allow creating a repository" do + it 'does not allow creating a repository' do expect { instance.save! }.to raise_error ActiveRecord::RecordInvalid end end - describe "available types" do - it "allow local by default" do + describe 'available types' do + it 'allow local by default' do expect(instance.class.available_types).to eq([:local]) end - context "with disabled types" do + context 'with disabled types' do let(:config) { { disabled_types: %i[local managed] } } - it "does not have any types" do + it 'does not have any types' do expect(instance.class.available_types).to be_empty end end - context "with mixed disabled types" do - let(:config) { { disabled_types: [:local, "managed"] } } + context 'with mixed disabled types' do + let(:config) { { disabled_types: [:local, 'managed'] } } - it "does not have any types" do + it 'does not have any types' do expect(instance.class.available_types).to be_empty end end end - describe "managed git" do - let(:managed_path) { "/tmp/managed_git" } + describe 'managed git' do + let(:managed_path) { '/tmp/managed_git' } - it "is not manageable unless configured explicitly" do + it 'is not manageable unless configured explicitly' do expect(instance.manageable?).to be false end - context "with managed config" do + context 'with managed config' do let(:config) { { manages: managed_path } } let(:project) { build(:project) } - let(:identifier) { project.identifier + ".git" } + let(:identifier) { project.identifier + '.git' } - it "is manageable" do + it 'is manageable' do expect(instance.manageable?).to be true expect(instance.class.available_types).to eq(%i[local managed]) end - context "with disabled managed typed" do + context 'with disabled managed typed' do let(:config) { { disabled_types: [:managed] } } - it "is no longer manageable" do + it 'is no longer manageable' do expect(instance.class.available_types).to eq([:local]) expect(instance.manageable?).to be false end end - context "with string disabled types", - with_config: { "scm" => { "git" => { "disabled_types" => %w[managed local] } } } do + context 'with string disabled types', + with_config: { 'scm' => { 'git' => { 'disabled_types' => %w[managed local] } } } do before do allow(adapter.class).to receive(:config).and_call_original end - it "is no longer manageable" do + it 'is no longer manageable' do expect(instance.class.available_types).to eq([]) expect(instance.class.disabled_types).to eq(%i[managed local]) expect(instance.manageable?).to be false end end - context "and associated project" do + context 'and associated project' do before do instance.project = project end - it "outputs valid managed paths" do + it 'outputs valid managed paths' do expect(instance.repository_identifier).to eq(identifier) path = File.join(managed_path, identifier) expect(instance.managed_repository_path).to eq(path) @@ -123,7 +123,7 @@ end end - context "and associated project with parent" do + context 'and associated project with parent' do let(:parent) { build(:project) } let(:project) { build(:project, parent:) } @@ -131,7 +131,7 @@ instance.project = project end - it "outputs the correct hierarchy path" do + it 'outputs the correct hierarchy path' do expect(instance.managed_repository_path) .to eq(File.join(managed_path, identifier)) end @@ -139,44 +139,44 @@ end end - describe "URL validation" do + describe 'URL validation' do let(:instance) { build(:repository_git, url:) } - shared_examples "repository url is valid" do - it "is valid" do + shared_examples 'repository url is valid' do + it 'is valid' do expect(instance).to be_valid end end - context "file:// URLs" do - let(:url) { "file:///foo/bar" } + context 'file:// URLs' do + let(:url) { 'file:///foo/bar' } - it_behaves_like "repository url is valid" + it_behaves_like 'repository url is valid' end - context "absolute paths" do - let(:url) { "file:///foo/bar" } + context 'absolute paths' do + let(:url) { 'file:///foo/bar' } - it_behaves_like "repository url is valid" + it_behaves_like 'repository url is valid' end - context "https URLs" do - let(:url) { "https://localhost/git/foo" } + context 'https URLs' do + let(:url) { 'https://localhost/git/foo' } - it_behaves_like "repository url is valid" + it_behaves_like 'repository url is valid' end - context "SSH URLs" do - let(:url) { "ssh://-oProxyCommand=echo/wat" } + context 'SSH URLs' do + let(:url) { 'ssh://-oProxyCommand=echo/wat' } - it "is invalid" do + it 'is invalid' do expect(instance).not_to be_valid expect(instance.errors.full_messages).to eq(["URL must not be an SSH url."]) end end end - describe "with an actual repository" do + describe 'with an actual repository' do with_git_repository do |repo_dir| let(:url) { repo_dir } let(:instance) do @@ -191,7 +191,7 @@ instance.reload end - it "is available" do + it 'is available' do expect(instance.scm).to be_available end @@ -224,36 +224,36 @@ end end - it "fetches changesets from scratch" do + it 'fetches changesets from scratch' do expect(instance.changesets.count).to eq(22) # This test fails on macs since they count file changes to be 33, *nix system count 34 expect(instance.file_changes.count).to be_between(33, 34) - commit = instance.changesets.reorder(Arel.sql("committed_on ASC")).first + commit = instance.changesets.reorder(Arel.sql('committed_on ASC')).first expect(commit.comments).to eq("Initial import.\nThe repository contains 3 files.") - expect(commit.committer).to eq("jsmith ") + expect(commit.committer).to eq('jsmith ') # assert_equal User.find_by_login('jsmith'), commit.user # TODO: add a commit with commit time <> author time to the test repository - expect(commit.committed_on).to eq("2007-12-14 09:22:52") - expect(commit.commit_date).to eq("2007-12-14".to_date) - expect(commit.revision).to eq("7234cb2750b63f47bff735edc50a1c0a433c2518") - expect(commit.scmid).to eq("7234cb2750b63f47bff735edc50a1c0a433c2518") + expect(commit.committed_on).to eq('2007-12-14 09:22:52') + expect(commit.commit_date).to eq('2007-12-14'.to_date) + expect(commit.revision).to eq('7234cb2750b63f47bff735edc50a1c0a433c2518') + expect(commit.scmid).to eq('7234cb2750b63f47bff735edc50a1c0a433c2518') expect(commit.file_changes.count).to eq(3) change = commit.file_changes.min_by(&:path) - expect(change.path).to eq("README") - expect(change.action).to eq("A") + expect(change.path).to eq('README') + expect(change.action).to eq('A') end - it "fetches changesets incremental" do + it 'fetches changesets incremental' do # Remove the 3 latest changesets - instance.changesets.order(Arel.sql("committed_on DESC")).limit(8).each(&:destroy) + instance.changesets.order(Arel.sql('committed_on DESC')).limit(8).each(&:destroy) instance.reload expect(instance.changesets.count).to eq(14) - rev_a_commit = instance.changesets.order(Arel.sql("committed_on DESC")).first - expect(rev_a_commit.revision).to eq("ed5bb786bbda2dee66a2d50faf51429dbc043a7b") - expect(rev_a_commit.scmid).to eq("ed5bb786bbda2dee66a2d50faf51429dbc043a7b") + rev_a_commit = instance.changesets.order(Arel.sql('committed_on DESC')).first + expect(rev_a_commit.revision).to eq('ed5bb786bbda2dee66a2d50faf51429dbc043a7b') + expect(rev_a_commit.scmid).to eq('ed5bb786bbda2dee66a2d50faf51429dbc043a7b') # Mon Jul 5 22:34:26 2010 +0200 committed_on = Time.gm(2010, 9, 18, 19, 59, 46) expect(rev_a_commit.committed_on).to eq(committed_on) @@ -263,117 +263,117 @@ expect(instance.changesets.count).to eq(22) end - describe ".latest_changesets" do - it "fetches changesets with limits" do - changesets = instance.latest_changesets("", nil, 2) + describe '.latest_changesets' do + it 'fetches changesets with limits' do + changesets = instance.latest_changesets('', nil, 2) expect(changesets.size).to eq(2) end - it "fetches changesets with paths" do - changesets = instance.latest_changesets("images", nil) + it 'fetches changesets with paths' do + changesets = instance.latest_changesets('images', nil) expect(changesets.map(&:revision)) - .to eq(["deff712f05a90d96edbd70facc47d944be5897e3", - "899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['deff712f05a90d96edbd70facc47d944be5897e3', + '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("README", nil) + changesets = instance.latest_changesets('README', nil) expect(changesets.map(&:revision)) - .to eq(["32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf", - "4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8", - "713f4944648826f558cf548222f813dabe7cbb04", - "61b685fbe55ab05b5ac68402d5720c1a6ac973d1", - "899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['32ae898b720c2f7eec2723d5bdd558b4cb2d3ddf', + '4a07fe31bffcf2888791f3e6cbc9c4545cefe3e8', + '713f4944648826f558cf548222f813dabe7cbb04', + '61b685fbe55ab05b5ac68402d5720c1a6ac973d1', + '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) end - it "fetches changesets with path, revision and limit" do - changesets = instance.latest_changesets("images", "899a15dba") + it 'fetches changesets with path, revision and limit' do + changesets = instance.latest_changesets('images', '899a15dba') expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("images", "899a15dba", 1) + changesets = instance.latest_changesets('images', '899a15dba', 1) expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9']) - changesets = instance.latest_changesets("README", "899a15dba") + changesets = instance.latest_changesets('README', '899a15dba') expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("README", "899a15dba", 1) + changesets = instance.latest_changesets('README', '899a15dba', 1) expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9']) end - it "fetches changesets with tag" do - changesets = instance.latest_changesets("images", "tag01.annotated") + it 'fetches changesets with tag' do + changesets = instance.latest_changesets('images', 'tag01.annotated') expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("README", "899a15dba", 1) + changesets = instance.latest_changesets('README', '899a15dba', 1) expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9']) - changesets = instance.latest_changesets("README", "tag01.annotated") + changesets = instance.latest_changesets('README', 'tag01.annotated') expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("README", "tag01.annotated", 1) + changesets = instance.latest_changesets('README', 'tag01.annotated', 1) expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9']) end - it "fetches changesets with path, branch, and limit" do - changesets = instance.latest_changesets("images", "test_branch") + it 'fetches changesets with path, branch, and limit' do + changesets = instance.latest_changesets('images', 'test_branch') expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("images", "test_branch", 1) + changesets = instance.latest_changesets('images', 'test_branch', 1) expect(changesets.map(&:revision)) - .to eq(["899a15dba03a3b350b89c3f537e4bbe02a03cdc9"]) + .to eq(['899a15dba03a3b350b89c3f537e4bbe02a03cdc9']) - changesets = instance.latest_changesets("README", "test_branch") + changesets = instance.latest_changesets('README', 'test_branch') expect(changesets.map(&:revision)) - .to eq(["713f4944648826f558cf548222f813dabe7cbb04", - "61b685fbe55ab05b5ac68402d5720c1a6ac973d1", - "899a15dba03a3b350b89c3f537e4bbe02a03cdc9", - "7234cb2750b63f47bff735edc50a1c0a433c2518"]) + .to eq(['713f4944648826f558cf548222f813dabe7cbb04', + '61b685fbe55ab05b5ac68402d5720c1a6ac973d1', + '899a15dba03a3b350b89c3f537e4bbe02a03cdc9', + '7234cb2750b63f47bff735edc50a1c0a433c2518']) - changesets = instance.latest_changesets("README", "test_branch", 2) + changesets = instance.latest_changesets('README', 'test_branch', 2) expect(changesets.map(&:revision)) - .to eq(["713f4944648826f558cf548222f813dabe7cbb04", - "61b685fbe55ab05b5ac68402d5720c1a6ac973d1"]) + .to eq(['713f4944648826f558cf548222f813dabe7cbb04', + '61b685fbe55ab05b5ac68402d5720c1a6ac973d1']) end end - it "finds changeset by name" do - ["7234cb2750b63f47bff735edc50a1c0a433c2518", "7234cb2750b"].each do |r| + it 'finds changeset by name' do + ['7234cb2750b63f47bff735edc50a1c0a433c2518', '7234cb2750b'].each do |r| expect(instance.find_changeset_by_name(r).revision) - .to eq("7234cb2750b63f47bff735edc50a1c0a433c2518") + .to eq('7234cb2750b63f47bff735edc50a1c0a433c2518') end end - it "finds changeset by empty name" do - ["", " ", nil].each do |r| + it 'finds changeset by empty name' do + ['', ' ', nil].each do |r| expect(instance.find_changeset_by_name(r)).to be_nil end end - it "assigns scmid to identifier" do - c = instance.changesets.where(revision: "7234cb2750b63f47bff735edc50a1c0a433c2518").first + it 'assigns scmid to identifier' do + c = instance.changesets.where(revision: '7234cb2750b63f47bff735edc50a1c0a433c2518').first expect(c.scmid).to eq(c.identifier) end - it "formats identifier" do - c = instance.changesets.where(revision: "7234cb2750b63f47bff735edc50a1c0a433c2518").first - expect(c.format_identifier).to eq("7234cb27") + it 'formats identifier' do + c = instance.changesets.where(revision: '7234cb2750b63f47bff735edc50a1c0a433c2518').first + expect(c.format_identifier).to eq('7234cb27') end - it "finds previous changeset" do + it 'finds previous changeset' do %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1| changeset = instance.find_changeset_by_name(r1) %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2| @@ -382,14 +382,14 @@ end end - it "returns nil when no previous changeset" do + it 'returns nil when no previous changeset' do %w|7234cb2750b63f47bff735edc50a1c0a433c2518 7234cb2|.each do |r1| changeset = instance.find_changeset_by_name(r1) expect(changeset.previous).to be_nil end end - it "finds next changeset" do + it 'finds next changeset' do %w|64f1f3e89ad1cb57976ff0ad99a107012ba3481d 64f1f3e89ad1|.each do |r2| changeset = instance.find_changeset_by_name(r2) %w|1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127 1ca7f5ed|.each do |r1| @@ -398,81 +398,81 @@ end end - it "nexts nil" do + it 'nexts nil' do %w|71e5c1d3dca6304805b143b9d0e6695fb3895ea4 71e5c1d3|.each do |r1| changeset = instance.find_changeset_by_name(r1) expect(changeset.next).to be_nil end end - context "with an admin browsing activity" do + context 'with an admin browsing activity' do let(:user) { create(:admin) } let(:project) { create(:project) } def find_events(user, options = {}) - options[:scope] = ["changesets"] + options[:scope] = ['changesets'] fetcher = Activities::Fetcher.new(user, options) fetcher.events(from: 30.days.ago, to: 1.day.from_now) end - it "activitieses" do + it 'activitieses' do Changeset.create(repository: instance, committed_on: Time.now, - revision: "abc7234cb2750b63f47bff735edc50a1c0a433c2", - scmid: "abc7234cb2750b63f47bff735edc50a1c0a433c2", - comments: "test") + revision: 'abc7234cb2750b63f47bff735edc50a1c0a433c2', + scmid: 'abc7234cb2750b63f47bff735edc50a1c0a433c2', + comments: 'test') event = find_events(user).first - assert event.event_title.include?("abc7234c:") + assert event.event_title.include?('abc7234c:') assert event.event_path =~ /\?rev=abc7234cb2750b63f47bff735edc50a1c0a433c2$/ end end - describe "encoding" do + describe 'encoding' do let(:felix_hex) { "Felix Sch\xC3\xA4fer" } - it "displays UTF-8" do - c = instance.changesets.where(revision: "ed5bb786bbda2dee66a2d50faf51429dbc043a7b").first + it 'displays UTF-8' do + c = instance.changesets.where(revision: 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b').first expect(c.committer).to eq("#{felix_hex} ") - expect(c.committer).to eq("Felix Schäfer ") + expect(c.committer).to eq('Felix Schäfer ') end - context "with latin-1 encoding" do - let (:encoding) { "ISO-8859-1" } - let (:char1_hex) { "\xc3\x9c".force_encoding("UTF-8") } + context 'with latin-1 encoding' do + let (:encoding) { 'ISO-8859-1' } + let (:char1_hex) { "\xc3\x9c".force_encoding('UTF-8') } - it "latests changesets latin 1 dir" do + it 'latests changesets latin 1 dir' do instance.fetch_changesets instance.reload changesets = instance.latest_changesets( - "latin-1-dir/test-#{char1_hex}-subdir", "1ca7f5ed" + "latin-1-dir/test-#{char1_hex}-subdir", '1ca7f5ed' ) expect(changesets.map(&:revision)) - .to eq(["1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127"]) + .to eq(['1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127']) end - it "browses changesets" do + it 'browses changesets' do changesets = instance.latest_changesets( - "latin-1-dir/test-#{char1_hex}-2.txt", "64f1f3e89" + "latin-1-dir/test-#{char1_hex}-2.txt", '64f1f3e89' ) expect(changesets.map(&:revision)) - .to eq(["64f1f3e89ad1cb57976ff0ad99a107012ba3481d", - "4fc55c43bf3d3dc2efb66145365ddc17639ce81e"]) + .to eq(['64f1f3e89ad1cb57976ff0ad99a107012ba3481d', + '4fc55c43bf3d3dc2efb66145365ddc17639ce81e']) changesets = instance.latest_changesets( - "latin-1-dir/test-#{char1_hex}-2.txt", "64f1f3e89", 1 + "latin-1-dir/test-#{char1_hex}-2.txt", '64f1f3e89', 1 ) expect(changesets.map(&:revision)) - .to eq(["64f1f3e89ad1cb57976ff0ad99a107012ba3481d"]) + .to eq(['64f1f3e89ad1cb57976ff0ad99a107012ba3481d']) end end end - it_behaves_like "is a countable repository" do + it_behaves_like 'is a countable repository' do let(:repository) { instance } end end end - it_behaves_like "repository can be relocated", :git + it_behaves_like 'repository can be relocated', :git end diff --git a/spec/models/repository/subversion_spec.rb b/spec/models/repository/subversion_spec.rb index e444e3cb215e..686c117d1e4e 100644 --- a/spec/models/repository/subversion_spec.rb +++ b/spec/models/repository/subversion_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Repository::Subversion do let(:instance) { build(:repository_subversion) } @@ -40,51 +40,51 @@ allow(instance.class).to receive(:scm_config).and_return(config) end - describe "when disabled" do + describe 'when disabled' do let(:enabled_scm) { [] } - it "does not allow creating a repository" do + it 'does not allow creating a repository' do expect { instance.save! }.to raise_error ActiveRecord::RecordInvalid end - it "returns an error when trying to save" do + it 'returns an error when trying to save' do expect(instance.save).to be false - expect(instance.errors[:type]).to include I18n.t("activerecord.errors.models.repository.not_available") + expect(instance.errors[:type]).to include I18n.t('activerecord.errors.models.repository.not_available') end end - describe "default Subversion" do - it "is not manageable" do + describe 'default Subversion' do + it 'is not manageable' do expect(instance.manageable?).to be false end - it "has one available type" do + it 'has one available type' do expect(instance.class.available_types).to eq [:existing] end - context "with disabled types" do + context 'with disabled types' do let(:config) { { disabled_types: %i[existing managed] } } - it "does not have any types" do + it 'does not have any types' do expect(instance.class.available_types).to be_empty end end - context "with mixed disabled types" do - let(:config) { { disabled_types: ["existing", :managed] } } + context 'with mixed disabled types' do + let(:config) { { disabled_types: ['existing', :managed] } } - it "does not have any types" do + it 'does not have any types' do expect(instance.class.available_types).to be_empty end end - context "with string disabled types", - with_config: { "scm" => { "subversion" => { "disabled_types" => %w[managed unknowntype] } } } do + context 'with string disabled types', + with_config: { 'scm' => { 'subversion' => { 'disabled_types' => %w[managed unknowntype] } } } do before do allow(instance.class).to receive(:scm_config).and_call_original end - it "is no longer manageable" do + it 'is no longer manageable' do expect(instance.class.available_types).to eq([:existing]) expect(instance.class.disabled_types).to eq(%i[managed unknowntype]) expect(instance.manageable?).to be false @@ -92,44 +92,44 @@ end end - describe "managed Subversion" do - let(:managed_path) { "/tmp/managed_svn" } + describe 'managed Subversion' do + let(:managed_path) { '/tmp/managed_svn' } - it "is not manageable unless configured explicitly" do + it 'is not manageable unless configured explicitly' do expect(instance.manageable?).to be false end - context "with managed config" do + context 'with managed config' do let(:config) { { manages: managed_path } } let(:project) { build(:project) } - it "is manageable" do + it 'is manageable' do expect(instance.manageable?).to be true expect(instance.class.available_types).to eq(%i[existing managed]) end - context "with disabled managed typed" do + context 'with disabled managed typed' do let(:config) { { disabled_types: [:managed] } } - it "is no longer manageable" do + it 'is no longer manageable' do expect(instance.class.available_types).to eq([:existing]) expect(instance.manageable?).to be false end end - context "and associated project" do + context 'and associated project' do before do instance.project = project end - it "outputs valid managed paths" do + it 'outputs valid managed paths' do path = File.join(managed_path, project.identifier) expect(instance.managed_repository_path).to eq(path) expect(instance.managed_repository_url).to eq("file://#{path}") end end - context "and associated project with parent" do + context 'and associated project with parent' do let(:parent) { build(:project) } let(:project) { build(:project, parent:) } @@ -137,7 +137,7 @@ instance.project = project end - it "outputs the correct hierarchy path" do + it 'outputs the correct hierarchy path' do expect(instance.managed_repository_path) .to eq(File.join(managed_path, project.identifier)) end @@ -145,36 +145,36 @@ end end - describe "with a remote repository" do + describe 'with a remote repository' do let(:instance) do build(:repository_subversion, - url: "https://somewhere.example.org/svn/foo") + url: 'https://somewhere.example.org/svn/foo') end - it_behaves_like "is not a countable repository" do + it_behaves_like 'is not a countable repository' do let(:repository) { instance } end end - describe "with an actual repository" do + describe 'with an actual repository' do with_subversion_repository do |repo_dir| let(:url) { "file://#{repo_dir}" } let(:instance) { create(:repository_subversion, url:, root_url: url) } - it "is available" do + it 'is available' do expect(instance.scm).to be_available end - it "fetches changesets from scratch" do + it 'fetches changesets from scratch' do instance.fetch_changesets instance.reload expect(instance.changesets.count).to eq(14) expect(instance.file_changes.count).to eq(34) - expect(instance.changesets.find_by(revision: "1").comments).to eq("Initial import.") + expect(instance.changesets.find_by(revision: '1').comments).to eq('Initial import.') end - it "fetches changesets incremental" do + it 'fetches changesets incremental' do instance.fetch_changesets # Remove changesets with revision > 5 @@ -186,145 +186,145 @@ expect(instance.changesets.count).to eq(14) end - it "latests changesets" do + it 'latests changesets' do instance.fetch_changesets # with limit - changesets = instance.latest_changesets("", nil, 2) + changesets = instance.latest_changesets('', nil, 2) expect(changesets.size).to eq(2) - expect(instance.latest_changesets("", nil).to_a.slice(0, 2)).to eq(changesets) + expect(instance.latest_changesets('', nil).to_a.slice(0, 2)).to eq(changesets) # with path - changesets = instance.latest_changesets("subversion_test/folder", nil) + changesets = instance.latest_changesets('subversion_test/folder', nil) expect(changesets.map(&:revision)).to eq %w[10 9 7 6 5 2] # with path and revision - changesets = instance.latest_changesets("subversion_test/folder", 8) + changesets = instance.latest_changesets('subversion_test/folder', 8) expect(changesets.map(&:revision)).to eq %w[7 6 5 2] end - it "directories listing with square brackets in path" do + it 'directories listing with square brackets in path' do instance.fetch_changesets instance.reload - entries = instance.entries("subversion_test/[folder_with_brackets]") + entries = instance.entries('subversion_test/[folder_with_brackets]') expect(entries).not_to be_nil expect(entries.size).to eq(1) - expect(entries.first.name).to eq("README.txt") + expect(entries.first.name).to eq('README.txt') end - context "with square brackets in base" do + context 'with square brackets in base' do let(:url) { "file://#{repo_dir}/subversion_test/[folder_with_brackets]" } - it "directories listing with square brackets in base" do + it 'directories listing with square brackets in base' do instance.fetch_changesets instance.reload expect(instance.changesets.count).to eq(1) expect(instance.file_changes.count).to eq(2) - entries = instance.entries("") + entries = instance.entries('') expect(entries).not_to be_nil expect(entries.size).to eq(1) - expect(entries.first.name).to eq("README.txt") + expect(entries.first.name).to eq('README.txt') end end - it "shows the identifier" do + it 'shows the identifier' do instance.fetch_changesets instance.reload - c = instance.changesets.find_by(revision: "1") + c = instance.changesets.find_by(revision: '1') expect(c.revision).to eq(c.identifier) end - it "finds changeset by empty name" do + it 'finds changeset by empty name' do instance.fetch_changesets instance.reload - ["", " ", nil].each do |r| + ['', ' ', nil].each do |r| expect(instance.find_changeset_by_name(r)).to be_nil end end - it "identifiers nine digit" do + it 'identifiers nine digit' do c = Changeset.new(repository: instance, committed_on: Time.now, - revision: "123456789", comments: "test") + revision: '123456789', comments: 'test') expect(c.identifier).to eq(c.revision) end - it "formats identifier" do + it 'formats identifier' do instance.fetch_changesets instance.reload - c = instance.changesets.find_by(revision: "1") + c = instance.changesets.find_by(revision: '1') expect(c.format_identifier).to eq(c.revision) end - it "formats identifier nine digit" do + it 'formats identifier nine digit' do c = Changeset.new(repository: instance, committed_on: Time.now, - revision: "123456789", comments: "test") + revision: '123456789', comments: 'test') expect(c.format_identifier).to eq(c.revision) end - context "with windows-1252 encoding", + context 'with windows-1252 encoding', with_settings: { commit_logs_encoding: %w(windows-1252) } do - it "logs encoding ignore setting" do + it 'logs encoding ignore setting' do s1 = "\xC2\x80" s2 = "\xc3\x82\xc2\x80" if s1.respond_to?(:force_encoding) - s1.force_encoding("ISO-8859-1") - s2.force_encoding("UTF-8") - expect(s1.encode("UTF-8")).to eq(s2) + s1.force_encoding('ISO-8859-1') + s2.force_encoding('UTF-8') + expect(s1.encode('UTF-8')).to eq(s2) end c = Changeset.new(repository: instance, comments: s2, - revision: "123", + revision: '123', committed_on: Time.now) expect(c.save).to be true expect(c.comments).to eq(s2) end end - it "loads previous and next changeset" do + it 'loads previous and next changeset' do instance.fetch_changesets instance.reload - changeset2 = instance.find_changeset_by_name("2") - changeset3 = instance.find_changeset_by_name("3") + changeset2 = instance.find_changeset_by_name('2') + changeset3 = instance.find_changeset_by_name('3') expect(changeset3.previous).to eq(changeset2) expect(changeset2.next).to eq(changeset3) end - it "returns nil for no previous or next changeset" do + it 'returns nil for no previous or next changeset' do instance.fetch_changesets instance.reload - changeset = instance.find_changeset_by_name("1") + changeset = instance.find_changeset_by_name('1') expect(changeset.previous).to be_nil - changeset = instance.find_changeset_by_name("14") + changeset = instance.find_changeset_by_name('14') expect(changeset.next).to be_nil end - context "with an admin browsing activity" do + context 'with an admin browsing activity' do let(:user) { create(:admin) } let(:project) { create(:project) } def find_events(user, options = {}) - options[:scope] = ["changesets"] + options[:scope] = ['changesets'] fetcher = Activities::Fetcher.new(user, options) fetcher.events(from: 30.days.ago, to: 1.day.from_now) end - it "finds events" do + it 'finds events' do Changeset.create(repository: instance, committed_on: Time.now, - revision: "1", comments: "test") + revision: '1', comments: 'test') event = find_events(user).first - expect(event.event_title).to include("1:") + expect(event.event_title).to include('1:') expect(event.event_path).to match(/\?rev=1$/) end - it "finds events with larger numbers" do + it 'finds events with larger numbers' do Changeset.create(repository: instance, committed_on: Time.now, - revision: "123456789", comments: "test") + revision: '123456789', comments: 'test') event = find_events(user).first - expect(event.event_title).to include("123456789:") + expect(event.event_title).to include('123456789:') expect(event.event_path).to match(/\?rev=123456789$/) end end @@ -358,102 +358,102 @@ def find_events(user, options = {}) end end - it_behaves_like "is a countable repository" do + it_behaves_like 'is a countable repository' do let(:repository) { instance } end end end - it_behaves_like "repository can be relocated", :subversion + it_behaves_like 'repository can be relocated', :subversion - describe "ciphering" do - context "with cipher key", with_config: { "database_cipher_key" => "secret" } do - it "password is encrypted" do - r = create(:repository_subversion, password: "foo") + describe 'ciphering' do + context 'with cipher key', with_config: { 'database_cipher_key' => 'secret' } do + it 'password is encrypted' do + r = create(:repository_subversion, password: 'foo') expect(r.password) - .to eql("foo") + .to eql('foo') expect(r.read_attribute(:password)) .to match(/\Aaes-256-cbc:.+\Z/) end end - context "with blank cipher key", with_config: { "database_cipher_key" => "" } do - it "password is unencrypted" do - r = create(:repository_subversion, password: "foo") + context 'with blank cipher key', with_config: { 'database_cipher_key' => '' } do + it 'password is unencrypted' do + r = create(:repository_subversion, password: 'foo') expect(r.password) - .to eql("foo") + .to eql('foo') expect(r.read_attribute(:password)) - .to eql("foo") + .to eql('foo') end end - context "with cipher key nil", with_config: { "database_cipher_key" => nil } do - it "password is unencrypted" do - r = create(:repository_subversion, password: "foo") + context 'with cipher key nil', with_config: { 'database_cipher_key' => nil } do + it 'password is unencrypted' do + r = create(:repository_subversion, password: 'foo') expect(r.password) - .to eql("foo") + .to eql('foo') expect(r.read_attribute(:password)) - .to eql("foo") + .to eql('foo') end end - context "without a cipher key first but activating it later" do + context 'without a cipher key first but activating it later' do before do WithConfig.new(self).stub_key(:database_cipher_key, nil) - create(:repository_subversion, password: "clear") + create(:repository_subversion, password: 'clear') - WithConfig.new(self).stub_key(:database_cipher_key, "secret") + WithConfig.new(self).stub_key(:database_cipher_key, 'secret') end - it "unciphered password is readable" do + it 'unciphered password is readable' do expect(Repository.last.password) - .to eql("clear") + .to eql('clear') end end - describe "#encrypt_all" do - context "with unencrypted passwords first but then with an encryption key" do + describe '#encrypt_all' do + context 'with unencrypted passwords first but then with an encryption key' do before do Repository.delete_all WithConfig.new(self).stub_key(:database_cipher_key, nil) - create(:repository_subversion, password: "foo") - create(:repository_subversion, password: "bar") + create(:repository_subversion, password: 'foo') + create(:repository_subversion, password: 'bar') - WithConfig.new(self).stub_key(:database_cipher_key, "secret") + WithConfig.new(self).stub_key(:database_cipher_key, 'secret') end - it "encrypts formerly unencrypted passwords" do + it 'encrypts formerly unencrypted passwords' do expect(Repository.encrypt_all(:password)) .to be_truthy bar = Repository.last expect(bar.password) - .to eql("bar") + .to eql('bar') expect(bar.read_attribute(:password)) .to match(/\Aaes-256-cbc:.+\Z/) foo = Repository.first expect(foo.password) - .to eql("foo") + .to eql('foo') expect(foo.read_attribute(:password)) .to match(/\Aaes-256-cbc:.+\Z/) end end end - describe "#decrypt_all", with_config: { "database_cipher_key" => "secret" } do - it "removes cyphering from all passwords" do + describe '#decrypt_all', with_config: { 'database_cipher_key' => 'secret' } do + it 'removes cyphering from all passwords' do Repository.delete_all - foo = create(:repository_subversion, password: "foo") - bar = create(:repository_subversion, password: "bar") + foo = create(:repository_subversion, password: 'foo') + bar = create(:repository_subversion, password: 'bar') expect(Repository.decrypt_all(:password)) .to be_truthy @@ -461,16 +461,16 @@ def find_events(user, options = {}) bar.reload expect(bar.password) - .to eql("bar") + .to eql('bar') expect(bar.read_attribute(:password)) - .to eql("bar") + .to eql('bar') foo.reload expect(foo.password) - .to eql("foo") + .to eql('foo') expect(foo.read_attribute(:password)) - .to eql("foo") + .to eql('foo') end end end diff --git a/spec/models/role_spec.rb b/spec/models/role_spec.rb index 52f548a3f74a..7b3deeeadeea 100644 --- a/spec/models/role_spec.rb +++ b/spec/models/role_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Role do let(:permissions) { %i[permission1 permission2] } let(:build_role) { build(:project_role, permissions:) } let(:created_role) { create(:project_role, permissions:) } - describe ".create" do - it "is prevented for type Role" do + describe '.create' do + it 'is prevented for type Role' do build_role.type = described_class.name expect(build_role.save).to be_falsey end end - describe ".givable" do + describe '.givable' do let!(:project_role) { create(:project_role) } let!(:non_member_role) { create(:non_member) } let!(:anonymous_role) { create(:anonymous_role) } @@ -51,8 +51,8 @@ it { expect(described_class.givable.to_a).to eql [project_role, work_package_role, global_role] } end - describe "#by_permission" do - it "returns roles with given permission" do + describe '#by_permission' do + it 'returns roles with given permission' do created_role expect(Role.by_permission(permissions[0])).to include created_role @@ -60,9 +60,9 @@ end end - describe "#permissions" do - shared_examples_for "writing and reading" do - it "returns the values written before" do + describe '#permissions' do + shared_examples_for 'writing and reading' do + it 'returns the values written before' do perms = permissions + [:permission3] role.permissions = perms @@ -70,15 +70,15 @@ expect(role.permissions).to match_array(perms) end - it "removes empty permissions" do - perms = permissions + [""] + it 'removes empty permissions' do + perms = permissions + [''] role.permissions = perms expect(role.permissions).to match_array(permissions) end - it "does not readd permissions" do + it 'does not readd permissions' do perms = permissions + permissions.map(&:to_s) role.permissions = perms @@ -86,29 +86,29 @@ expect(role.permissions).to match_array(permissions) end - it "allows clearing the permissions" do + it 'allows clearing the permissions' do role.permissions = [] expect(role.permissions).to be_empty end end - context "for a non persisted role" do + context 'for a non persisted role' do let(:role) { build_role } - it_behaves_like "writing and reading" + it_behaves_like 'writing and reading' end - context "for a persisted role" do + context 'for a persisted role' do let(:role) { created_role } - it_behaves_like "writing and reading" + it_behaves_like 'writing and reading' end end - describe "#remove_permission!" do - shared_examples_for "removing" do - it "removes the specified permission" do + describe '#remove_permission!' do + shared_examples_for 'removing' do + it 'removes the specified permission' do perm = permissions.first role.remove_permission!(perm) @@ -117,48 +117,48 @@ end end - context "for a non persisted role" do + context 'for a non persisted role' do let(:role) { build_role } - it_behaves_like "removing" + it_behaves_like 'removing' end - context "for a persisted role" do + context 'for a persisted role' do let(:role) { created_role } - it_behaves_like "removing" + it_behaves_like 'removing' end end - describe "#add_permission!" do - shared_examples_for "adding" do - it "adds the specified permission" do + describe '#add_permission!' do + shared_examples_for 'adding' do + it 'adds the specified permission' do role.add_permission!(:permission3) - expect(role.role_permissions.map(&:permission)).to include "permission3" + expect(role.role_permissions.map(&:permission)).to include 'permission3' end end - context "for a non persisted role" do + context 'for a non persisted role' do let(:role) { build_role } - it_behaves_like "adding" + it_behaves_like 'adding' end - context "for a persisted role" do + context 'for a persisted role' do let(:role) { created_role } - it_behaves_like "adding" + it_behaves_like 'adding' end end - describe ".workflows.copy_from_role" do + describe '.workflows.copy_from_role' do before do allow(Workflow) .to receive(:copy) end - it "calls Workflow.copy" do + it 'calls Workflow.copy' do build_role.workflows.copy_from_role(created_role) expect(Workflow) diff --git a/spec/models/sessions/active_record_sessions_spec.rb b/spec/models/sessions/active_record_sessions_spec.rb index 970462d51c5e..6973b5209a51 100644 --- a/spec/models/sessions/active_record_sessions_spec.rb +++ b/spec/models/sessions/active_record_sessions_spec.rb @@ -26,48 +26,48 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Sessions::UserSession do - subject { described_class.new session_id: "foo" } + subject { described_class.new session_id: 'foo' } - describe "#save" do - it "can not save" do + describe '#save' do + it 'can not save' do expect { subject.save }.to raise_error(ActiveRecord::ReadOnlyRecord) expect { subject.save! }.to raise_error(ActiveRecord::ReadOnlyRecord) end end - describe "#update" do + describe '#update' do let(:session) { create(:user_session) } subject { described_class.find_by(session_id: session.session_id) } - it "can not update" do + it 'can not update' do expect { subject.save }.to raise_error(ActiveRecord::ReadOnlyRecord) expect { subject.save! }.to raise_error(ActiveRecord::ReadOnlyRecord) - expect { subject.update(session_id: "foo") }.to raise_error(ActiveRecord::ReadOnlyRecord) - expect { subject.update!(session_id: "foo") }.to raise_error(ActiveRecord::ReadOnlyRecord) + expect { subject.update(session_id: 'foo') }.to raise_error(ActiveRecord::ReadOnlyRecord) + expect { subject.update!(session_id: 'foo') }.to raise_error(ActiveRecord::ReadOnlyRecord) end end - describe "#destroy" do + describe '#destroy' do let(:sessions) { create(:user_session) } - it "can not destroy" do + it 'can not destroy' do expect { subject.destroy }.to raise_error(ActiveRecord::ReadOnlyRecord) expect { subject.destroy! }.to raise_error(ActiveRecord::ReadOnlyRecord) end end - describe ".for_user" do + describe '.for_user' do let(:user) { create(:user) } let!(:sessions) { create_list(:user_session, 2, user:) } subject { described_class.for_user(user) } - it "can find and delete, but not destroy those sessions" do + it 'can find and delete, but not destroy those sessions' do expect(subject.pluck(:session_id)).to match_array(sessions.map(&:session_id)) expect { subject.destroy_all }.to raise_error(ActiveRecord::ReadOnlyRecord) @@ -78,12 +78,12 @@ end end - describe ".non_user" do + describe '.non_user' do let!(:session) { create(:user_session, user: nil) } subject { described_class.non_user } - it "can find those sessions" do + it 'can find those sessions' do expect(subject.pluck(:session_id)).to contain_exactly(session.session_id) end end diff --git a/spec/models/sessions/sql_bypass_sessions_spec.rb b/spec/models/sessions/sql_bypass_sessions_spec.rb index a04b596aaee7..ab0b418814d0 100644 --- a/spec/models/sessions/sql_bypass_sessions_spec.rb +++ b/spec/models/sessions/sql_bypass_sessions_spec.rb @@ -26,29 +26,29 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Sessions::SqlBypass do subject { build(:user_session, user:) } - shared_examples "augments the user_id attribute" do + shared_examples 'augments the user_id attribute' do it do subject.save - expect(subject.data["user_id"]).to eq(user_id) + expect(subject.data['user_id']).to eq(user_id) end end - describe "when user_id is present" do + describe 'when user_id is present' do let(:user) { build_stubbed(:user) } let(:user_id) { user.id } - it_behaves_like "augments the user_id attribute" + it_behaves_like 'augments the user_id attribute' end - describe "when user_id is nil" do + describe 'when user_id is nil' do let(:user) { nil } let(:user_id) { nil } - it_behaves_like "augments the user_id attribute" + it_behaves_like 'augments the user_id attribute' end end diff --git a/spec/models/setting_spec.rb b/spec/models/setting_spec.rb index 509a74aeee1b..fed66ba63a20 100644 --- a/spec/models/setting_spec.rb +++ b/spec/models/setting_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Setting do before do @@ -39,35 +39,35 @@ end describe "OpenProject's default settings" do - it "has OpenProject as application title" do - expect(described_class.app_title).to eq "OpenProject" + it 'has OpenProject as application title' do + expect(described_class.app_title).to eq 'OpenProject' end - it "allows users to register themselves" do + it 'allows users to register themselves' do expect(described_class).to be_self_registration end - it "allows users to not access public information by default" do + it 'allows users to not access public information by default' do expect(described_class).to be_login_required end end # checks whether settings can be set and are persisted in the database - describe "changing a setting" do + describe 'changing a setting' do context "for a setting that doesn't exist in the database" do before do - described_class.host_name = "some name" + described_class.host_name = 'some name' end after do - described_class.find_by(name: "host_name").destroy + described_class.find_by(name: 'host_name').destroy end - it "sets the setting" do - expect(described_class.host_name).to eq "some name" + it 'sets the setting' do + expect(described_class.host_name).to eq 'some name' end - context "when overwritten" do + context 'when overwritten' do let!(:setting_definition) do Settings::Definition[:host_name].tap do |setting| allow(setting) @@ -76,56 +76,56 @@ end end - it "takes the setting from the definition" do + it 'takes the setting from the definition' do expect(described_class.host_name) .to eql setting_definition.value end end - it "stores the setting" do - expect(described_class.find_by(name: "host_name").value).to eq "some name" + it 'stores the setting' do + expect(described_class.find_by(name: 'host_name').value).to eq 'some name' end end - context "for a setting that already exist in the database" do + context 'for a setting that already exist in the database' do before do - described_class.host_name = "some name" - described_class.host_name = "some other name" + described_class.host_name = 'some name' + described_class.host_name = 'some other name' end after do - described_class.find_by(name: "host_name").destroy + described_class.find_by(name: 'host_name').destroy end - it "sets the setting" do - expect(described_class.host_name).to eq "some other name" + it 'sets the setting' do + expect(described_class.host_name).to eq 'some other name' end - it "stores the setting" do - expect(described_class.find_by(name: "host_name").value).to eq "some other name" + it 'stores the setting' do + expect(described_class.find_by(name: 'host_name').value).to eq 'some other name' end end end - describe ".[setting]" do - it "fetches the value" do + describe '.[setting]' do + it 'fetches the value' do expect(described_class.app_title) - .to eql("OpenProject") + .to eql('OpenProject') end - context "when value is blank but not nil" do - it "is read correctly for array" do - expect(Settings::Definition["apiv3_cors_origins"].format).to eq(:array) # safeguard - expect(described_class["apiv3_cors_origins"]).to eq([]) + context 'when value is blank but not nil' do + it 'is read correctly for array' do + expect(Settings::Definition['apiv3_cors_origins'].format).to eq(:array) # safeguard + expect(described_class['apiv3_cors_origins']).to eq([]) end - it "is read correctly for hash" do - expect(Settings::Definition["fog"].format).to eq(:hash) # safeguard - expect(described_class["fog"]).to eq({}) + it 'is read correctly for hash' do + expect(Settings::Definition['fog'].format).to eq(:hash) # safeguard + expect(described_class['fog']).to eq({}) end end - context "when value was seeded as empty string in database", :settings_reset do + context 'when value was seeded as empty string in database', :settings_reset do let(:setting_name) { "my_setting" } subject { described_class[setting_name] } @@ -136,7 +136,7 @@ default: nil, format: setting_format ) - described_class.create!(name: setting_name, value: "") + described_class.create!(name: setting_name, value: '') end %i[array boolean date datetime hash symbol].each do |setting_format| @@ -147,49 +147,49 @@ end end - context "for a string setting" do + context 'for a string setting' do let(:setting_format) { :string } - it { is_expected.to eq("") } + it { is_expected.to eq('') } end end end - describe ".[setting]?" do - it "fetches the value" do + describe '.[setting]?' do + it 'fetches the value' do expect(described_class.smtp_enable_starttls_auto?) .to be false end - it "works for non boolean settings as well (deprecated)" do + it 'works for non boolean settings as well (deprecated)' do expect(described_class.app_title?) .to be true end end - describe ".[setting]=" do - it "sets the value" do - described_class.app_title = "New title" + describe '.[setting]=' do + it 'sets the value' do + described_class.app_title = 'New title' expect(described_class.app_title) - .to eql("New title") + .to eql('New title') end - it "raises an error for a non writable setting" do - expect { described_class.smtp_openssl_verify_mode = "none" } + it 'raises an error for a non writable setting' do + expect { described_class.smtp_openssl_verify_mode = 'none' } .to raise_error NoMethodError end - context "for a integer setting with non-nil default value", :settings_reset do + context 'for a integer setting with non-nil default value', :settings_reset do before do Settings::Definition.add( - "my_setting", + 'my_setting', format: :integer, default: 42 ) end - it "does not save it when set to nil" do + it 'does not save it when set to nil' do expect(described_class.my_setting).to eq(42) described_class.my_setting = nil expect(described_class.my_setting).not_to be_nil @@ -197,51 +197,51 @@ end end - context "for a integer setting with nil default value", :settings_reset do + context 'for a integer setting with nil default value', :settings_reset do before do Settings::Definition.add( - "my_setting", + 'my_setting', format: :integer, default: nil ) end - it "saves it when set to nil" do + it 'saves it when set to nil' do described_class.my_setting = 42 expect(described_class.my_setting).to eq(42) described_class.my_setting = nil expect(described_class.my_setting).to be_nil end - it "saves it as nil when set to empty string" do + it 'saves it as nil when set to empty string' do described_class.my_setting = 42 expect(described_class.my_setting).to eq(42) - described_class.my_setting = "" + described_class.my_setting = '' expect(described_class.my_setting).to be_nil end end end - describe ".[setting]_writable?" do + describe '.[setting]_writable?' do before do allow(Settings::Definition[:host_name]) .to receive(:writable?) .and_return writable end - context "when definition states it to be writable" do + context 'when definition states it to be writable' do let(:writable) { true } - it "is writable" do + it 'is writable' do expect(described_class) .to be_host_name_writable end end - context "when definition states it to be non writable" do + context 'when definition states it to be non writable' do let(:writable) { false } - it "is non writable" do + it 'is non writable' do expect(described_class) .not_to be_host_name_writable end @@ -311,21 +311,21 @@ end # tests the serialization feature to store complex data types like arrays in settings - describe "serialized array settings" do + describe 'serialized array settings' do before do - described_class.default_projects_modules = ["some_input"] + described_class.default_projects_modules = ['some_input'] end - it "serializes arrays" do - expect(described_class.default_projects_modules).to eq ["some_input"] - expect(described_class.find_by(name: "default_projects_modules").value).to eq ["some_input"] + it 'serializes arrays' do + expect(described_class.default_projects_modules).to eq ['some_input'] + expect(described_class.find_by(name: 'default_projects_modules').value).to eq ['some_input'] end end # tests the serialization feature to store complex data types like arrays in settings - describe "serialized hash settings" do + describe 'serialized hash settings' do before do - setting = described_class.create!(name: "repository_checkout_data") + setting = described_class.create!(name: 'repository_checkout_data') setting.update_columns( value: { git: { enabled: 0 }, @@ -334,40 +334,40 @@ ) end - it "deserializes hashes stored with symbol keys as string keys" do + it 'deserializes hashes stored with symbol keys as string keys' do expected_value = { "git" => { "enabled" => 0 }, "subversion" => { "enabled" => 0 } } expect(described_class.repository_checkout_data).to eq(expected_value) - expect(described_class.find_by(name: "repository_checkout_data").value).to eq(expected_value) + expect(described_class.find_by(name: 'repository_checkout_data').value).to eq(expected_value) end end - describe "serialized hash settings with URI::Generic inside it" do + describe 'serialized hash settings with URI::Generic inside it' do before do - setting = described_class.create!(name: "repository_checkout_data") + setting = described_class.create!(name: 'repository_checkout_data') setting.update_columns( value: { - git: { enabled: 1, base_url: URI::Generic.build(scheme: "https", host: "git.example.com", path: "/public") }, + git: { enabled: 1, base_url: URI::Generic.build(scheme: 'https', host: 'git.example.com', path: '/public') }, subversion: { enabled: 0 } }.to_yaml ) end - it "deserializes correctly" do + it 'deserializes correctly' do expected_value = { "git" => { "enabled" => 1, "base_url" => "https://git.example.com/public" }, "subversion" => { "enabled" => 0 } } expect(described_class.repository_checkout_data).to eq(expected_value) - expect(described_class.find_by(name: "repository_checkout_data").value).to eq(expected_value) + expect(described_class.find_by(name: 'repository_checkout_data').value).to eq(expected_value) end end - describe "caching" do + describe 'caching' do let(:cache_key) { described_class.send :cache_key } before do @@ -380,8 +380,8 @@ Rails.cache.clear end - context "when cache is empty" do - it "requests the settings once from database" do + context 'when cache is empty' do + it 'requests the settings once from database' do allow(described_class).to receive(:pluck).with(:name, :value) .once .and_call_original @@ -395,7 +395,7 @@ # Falls back to default values, but hitting cache value = described_class.app_title - expect(described_class.app_title).to eq "OpenProject" + expect(described_class.app_title).to eq 'OpenProject' expect(value).to eq(described_class.app_title) expect(described_class).to have_received(:pluck).with(:name, :value).once @@ -407,44 +407,44 @@ expect(Rails.cache.read(cache_key)).to eq({}) end - it "clears the cache when writing a setting" do - expect(described_class.app_title).to eq "OpenProject" + it 'clears the cache when writing a setting' do + expect(described_class.app_title).to eq 'OpenProject' expect(RequestStore.read(:cached_settings)).to eq({}) - new_title = "OpenProject with changed title" + new_title = 'OpenProject with changed title' described_class.app_title = new_title expect(RequestStore.read(:cached_settings)).to be_nil expect(Rails.cache.read(cache_key)).to be_nil expect(described_class.app_title).to eq(new_title) expect(described_class.count).to eq(1) - expect(RequestStore.read(:cached_settings)).to eq("app_title" => new_title) + expect(RequestStore.read(:cached_settings)).to eq('app_title' => new_title) end end - context "when cache is not empty" do + context 'when cache is not empty' do let(:cached_hash) do - { "available_languages" => "---\n- en\n- de\n" } + { 'available_languages' => "---\n- en\n- de\n" } end before do Rails.cache.write(cache_key, cached_hash) end - it "returns the value from the deeper cache" do + it 'returns the value from the deeper cache' do expect(RequestStore.read(:cached_settings)).to be_nil expect(described_class.available_languages).to eq(%w(en de)) expect(RequestStore.read(:cached_settings)).to eq(cached_hash) end - it "expires the cache when writing a setting" do + it 'expires the cache when writing a setting' do described_class.available_languages = %w(en) expect(RequestStore.read(:cached_settings)).to be_nil # Creates a new cache key new_cache_key = described_class.send(:cache_key) - new_hash = { "available_languages" => "---\n- en\n" } + new_hash = { 'available_languages' => "---\n- en\n" } expect(new_cache_key).not_to be eq(cache_key) # No caching is done until first read @@ -459,7 +459,7 @@ end end - describe ".reload_mailer_settings!" do + describe '.reload_mailer_settings!' do before do allow(ActionMailer::Base) .to receive(:perform_deliveries=) @@ -467,16 +467,16 @@ .to receive(:delivery_method=) end - context "without smtp_authentication and without ssl" do - it "uses the setting values", + context 'without smtp_authentication and without ssl' do + it 'uses the setting values', with_settings: { email_delivery_method: :smtp, smtp_authentication: :none, - smtp_password: "old", - smtp_address: "smtp.example.com", - smtp_domain: "example.com", + smtp_password: 'old', + smtp_address: 'smtp.example.com', + smtp_domain: 'example.com', smtp_port: 25, - smtp_user_name: "username", + smtp_user_name: 'username', smtp_enable_starttls_auto: 1, smtp_ssl: 0 } do @@ -484,25 +484,25 @@ expect(ActionMailer::Base).to have_received(:perform_deliveries=).with(true) expect(ActionMailer::Base).to have_received(:delivery_method=).with(:smtp) expect(ActionMailer::Base.smtp_settings[:smtp_authentication]).to be_nil - expect(ActionMailer::Base.smtp_settings).to eq(address: "smtp.example.com", + expect(ActionMailer::Base.smtp_settings).to eq(address: 'smtp.example.com', port: 25, - domain: "example.com", + domain: 'example.com', enable_starttls_auto: true, - openssl_verify_mode: "peer", + openssl_verify_mode: 'peer', ssl: false) end end - context "without smtp_authentication and with ssl" do - it "users the setting values", + context 'without smtp_authentication and with ssl' do + it 'users the setting values', with_settings: { email_delivery_method: :smtp, smtp_authentication: :none, - smtp_password: "old", - smtp_address: "smtp.example.com", - smtp_domain: "example.com", + smtp_password: 'old', + smtp_address: 'smtp.example.com', + smtp_domain: 'example.com', smtp_port: 25, - smtp_user_name: "username", + smtp_user_name: 'username', smtp_enable_starttls_auto: 0, smtp_ssl: 1 } do @@ -510,24 +510,24 @@ expect(ActionMailer::Base).to have_received(:perform_deliveries=).with(true) expect(ActionMailer::Base).to have_received(:delivery_method=).with(:smtp) expect(ActionMailer::Base.smtp_settings[:smtp_authentication]).to be_nil - expect(ActionMailer::Base.smtp_settings).to eq(address: "smtp.example.com", + expect(ActionMailer::Base.smtp_settings).to eq(address: 'smtp.example.com', port: 25, - domain: "example.com", + domain: 'example.com', enable_starttls_auto: false, - openssl_verify_mode: "peer", + openssl_verify_mode: 'peer', ssl: true) end end - context "with smtp_authentication and without ssl" do - it "users the setting values", + context 'with smtp_authentication and without ssl' do + it 'users the setting values', with_settings: { email_delivery_method: :smtp, - smtp_password: "p4ssw0rd", - smtp_address: "smtp.example.com", - smtp_domain: "example.com", + smtp_password: 'p4ssw0rd', + smtp_address: 'smtp.example.com', + smtp_domain: 'example.com', smtp_port: 587, - smtp_user_name: "username", + smtp_user_name: 'username', smtp_enable_starttls_auto: 1, smtp_ssl: 0 } do @@ -535,27 +535,27 @@ expect(ActionMailer::Base).to have_received(:perform_deliveries=).with(true) expect(ActionMailer::Base).to have_received(:delivery_method=).with(:smtp) expect(ActionMailer::Base.smtp_settings[:smtp_authentication]).to be_nil - expect(ActionMailer::Base.smtp_settings).to eq(address: "smtp.example.com", + expect(ActionMailer::Base.smtp_settings).to eq(address: 'smtp.example.com', port: 587, - domain: "example.com", - authentication: "plain", - user_name: "username", - password: "p4ssw0rd", + domain: 'example.com', + authentication: 'plain', + user_name: 'username', + password: 'p4ssw0rd', enable_starttls_auto: true, - openssl_verify_mode: "peer", + openssl_verify_mode: 'peer', ssl: false) end end - context "with smtp_authentication and with ssl" do - it "users the setting values", + context 'with smtp_authentication and with ssl' do + it 'users the setting values', with_settings: { email_delivery_method: :smtp, - smtp_password: "p4ssw0rd", - smtp_address: "smtp.example.com", - smtp_domain: "example.com", + smtp_password: 'p4ssw0rd', + smtp_address: 'smtp.example.com', + smtp_domain: 'example.com', smtp_port: 587, - smtp_user_name: "username", + smtp_user_name: 'username', smtp_enable_starttls_auto: 0, smtp_ssl: 1 } do @@ -563,14 +563,14 @@ expect(ActionMailer::Base).to have_received(:perform_deliveries=).with(true) expect(ActionMailer::Base).to have_received(:delivery_method=).with(:smtp) expect(ActionMailer::Base.smtp_settings[:smtp_authentication]).to be_nil - expect(ActionMailer::Base.smtp_settings).to eq(address: "smtp.example.com", + expect(ActionMailer::Base.smtp_settings).to eq(address: 'smtp.example.com', port: 587, - domain: "example.com", - authentication: "plain", - user_name: "username", - password: "p4ssw0rd", + domain: 'example.com', + authentication: 'plain', + user_name: 'username', + password: 'p4ssw0rd', enable_starttls_auto: false, - openssl_verify_mode: "peer", + openssl_verify_mode: 'peer', ssl: true) end end diff --git a/spec/models/status_spec.rb b/spec/models/status_spec.rb index 40b68cd15e48..24209fbf387f 100644 --- a/spec/models/status_spec.rb +++ b/spec/models/status_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Status do let(:stubbed_status) { build_stubbed(:status) } - describe "default status" do - context "when default exists" do + describe 'default status' do + context 'when default exists' do let!(:status) { create(:default_status) } - it "returns that one" do + it 'returns that one' do expect(described_class.default).to eq(status) expect(described_class.where_default.pluck(:id)).to eq([status.id]) end - it "can not be set read only (Regression #33750)", with_ee: %i[readonly_work_packages] do + it 'can not be set read only (Regression #33750)', with_ee: %i[readonly_work_packages] do status.is_readonly = true expect(status.save).to be false expect(status.errors[:is_readonly]).to include(I18n.t("activerecord.errors.models.status.readonly_default_exlusive")) end - it "is removed from the existing default status upon creation of a new one" do + it 'is removed from the existing default status upon creation of a new one' do new_default = create(:status) new_default.is_default = true new_default.save @@ -56,26 +56,26 @@ end end - it "is not true by default" do - status = described_class.new name: "Status" + it 'is not true by default' do + status = described_class.new name: 'Status' expect(status) .not_to be_is_default end end - describe "#is_readonly" do + describe '#is_readonly' do let!(:status) { build(:status, is_readonly: true) } - context "when EE enabled", with_ee: %i[readonly_work_packages] do - it "is still marked read only" do + context 'when EE enabled', with_ee: %i[readonly_work_packages] do + it 'is still marked read only' do expect(status.is_readonly).to be_truthy expect(status).to be_is_readonly end end - context "when EE no longer enabled", with_ee: false do - it "is still marked read only" do + context 'when EE no longer enabled', with_ee: false do + it 'is still marked read only' do expect(status.is_readonly).to be_falsey expect(status).not_to be_is_readonly @@ -86,8 +86,8 @@ end end - describe "#cache_key" do - it "updates when the updated_at field changes" do + describe '#cache_key' do + it 'updates when the updated_at field changes' do old_cache_key = stubbed_status.cache_key stubbed_status.updated_at = Time.zone.now @@ -97,12 +97,12 @@ end end - describe ".update_done_ratios" do + describe '.update_done_ratios' do let(:status) { create(:status, default_done_ratio: 50) } let(:work_package) { create(:work_package, status:) } - context "with Setting.work_package_done_ratio using the field", with_settings: { work_package_done_ratio: "field" } do - it "changes nothing" do + context 'with Setting.work_package_done_ratio using the field', with_settings: { work_package_done_ratio: 'field' } do + it 'changes nothing' do done_ratio_before = work_package.done_ratio described_class.update_work_package_done_ratios @@ -111,7 +111,7 @@ end end - context "with Setting.work_package_done_ratio using the status", with_settings: { work_package_done_ratio: "status" } do + context 'with Setting.work_package_done_ratio using the status', with_settings: { work_package_done_ratio: 'status' } do it "updates all of the work package's % Complete values to match their status" do described_class.update_work_package_done_ratios @@ -121,15 +121,15 @@ end end - describe "#destroy" do - it "cannot be destroyed if the status is in use" do + describe '#destroy' do + it 'cannot be destroyed if the status is in use' do work_package = create(:work_package) expect { work_package.status.destroy } .to raise_error(RuntimeError, "Can't delete status") end - it "cleans up the workflows" do + it 'cleans up the workflows' do workflow = create(:workflow) expect { workflow.old_status.destroy } diff --git a/spec/models/system_user_spec.rb b/spec/models/system_user_spec.rb index 2159430f2318..bc3412e1b533 100644 --- a/spec/models/system_user_spec.rb +++ b/spec/models/system_user_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SystemUser do let(:system_user) { User.system } - describe "#run_given" do - it "runs block with SystemUser" do + describe '#run_given' do + it 'runs block with SystemUser' do before_user = User.current system_user.run_given do diff --git a/spec/models/timestamp_spec.rb b/spec/models/timestamp_spec.rb index eb5992383ca3..ea3d4a2143bb 100644 --- a/spec/models/timestamp_spec.rb +++ b/spec/models/timestamp_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Timestamp do describe ".new" do @@ -99,15 +99,15 @@ end { - "PT1H" => "PT1H", - "PT0001H" => "PT1H", - "PT0009H" => "PT9H", - "PT-1H" => "PT-1H", - "+PT1H" => "PT1H", - "-PT1H" => "PT-1H", - "-PT-1H" => "PT1H", - " PT1H " => "PT1H", - "-P1M-1DT1H-02M" => "P-1M1DT-1H2M" + 'PT1H' => 'PT1H', + 'PT0001H' => 'PT1H', + 'PT0009H' => 'PT9H', + 'PT-1H' => 'PT-1H', + '+PT1H' => 'PT1H', + '-PT1H' => 'PT-1H', + '-PT-1H' => 'PT1H', + ' PT1H ' => 'PT1H', + '-P1M-1DT1H-02M' => 'P-1M1DT-1H2M' }.each do |input, expected| context "with the duration #{input.inspect}" do subject { described_class.parse(input) } @@ -135,7 +135,7 @@ expect(subject).not_to be_relative end - context "with a non-UTC time" do + context 'with a non-UTC time' do subject { described_class.parse("2022-10-29T21:55:58+03:00") } it "returns a described_class representing that absolute time and preserve the timezone component" do @@ -147,7 +147,7 @@ end end - context "without the seconds designator" do + context 'without the seconds designator' do subject { described_class.parse("2022-10-29T21:55Z") } it "returns a described_class representing that absolute time" do @@ -412,7 +412,7 @@ end end - describe "when providing a Timestamp" do + describe 'when providing a Timestamp' do subject { described_class.parse(provided) } let(:provided) { described_class.new } @@ -522,10 +522,10 @@ end describe "for a timestamp as a date keyword representing a point in time relative to now" do - let(:timestamp) { described_class.new("oneDayAgo@12:00+02:00") } + let(:timestamp) { described_class.new('oneDayAgo@12:00+02:00') } it "returns an relative date keyword" do - expect(subject).to eq "oneDayAgo@12:00+02:00" + expect(subject).to eq 'oneDayAgo@12:00+02:00' end end end @@ -611,31 +611,31 @@ describe "#hash" do # rubocop:disable RSpec/IdenticalEqualityAssertion - context "for two instances of relative time representing the same point in time" do - it "is eql" do + context 'for two instances of relative time representing the same point in time' do + it 'is eql' do expect(described_class.new("PT0S").hash) .to eql described_class.new("PT0S").hash end end - context "for two instances of relative time representing different points in time" do - it "is different" do + context 'for two instances of relative time representing different points in time' do + it 'is different' do expect(described_class.new("PT0S").hash) .not_to eql described_class.new("PT10S").hash end end - context "for two instances of absolute time representing the same point in time" do + context 'for two instances of absolute time representing the same point in time' do let(:time) { Time.zone.now } - it "is equal" do + it 'is equal' do expect(described_class.new(time).hash) .to eql described_class.new(time).hash end end - context "for two instances of absolute time representing different points in time" do - it "is different" do + context 'for two instances of absolute time representing different points in time' do + it 'is different' do expect(described_class.new(10.seconds.ago).hash) .not_to eql described_class.new(5.seconds.ago).hash end diff --git a/spec/models/token/base_token_spec.rb b/spec/models/token/base_token_spec.rb index eb876f9440d5..fe3fc8c853e5 100644 --- a/spec/models/token/base_token_spec.rb +++ b/spec/models/token/base_token_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Token::Base do let(:user) { build(:user) } subject { described_class.new user: } - it "creates" do + it 'creates' do subject.save! expect(subject.value.length).to eq(64) end - it "create_should_remove_existing_tokenses" do + it 'create_should_remove_existing_tokenses' do subject.save! t2 = Token::AutoLogin.create(user:) expect(subject.value).not_to eq(t2.value) diff --git a/spec/models/token/hashed_token_spec.rb b/spec/models/token/hashed_token_spec.rb index fc49d4ff9091..fd447ddbee1a 100644 --- a/spec/models/token/hashed_token_spec.rb +++ b/spec/models/token/hashed_token_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Token::HashedToken do let(:user) { build(:user) } subject { described_class.new user: } - describe "token value" do - it "is generated on a new instance" do + describe 'token value' do + it 'is generated on a new instance' do expect(subject.value).to be_present end - it "provides the generated plain value on a new instance" do + it 'provides the generated plain value on a new instance' do expect(subject.valid_plaintext?(subject.plain_value)).to be true end - it "hashes the plain value to value" do + it 'hashes the plain value to value' do expect(subject.value).not_to eq(subject.plain_value) end - it "does not keep the value when finding it" do + it 'does not keep the value when finding it' do subject.save! instance = described_class.where(user:).last @@ -54,14 +54,14 @@ end end - describe "#find_by_plaintext_value" do + describe '#find_by_plaintext_value' do before do subject.save! end - it "finds using the plaintext value" do + it 'finds using the plaintext value' do expect(described_class.find_by_plaintext_value(subject.plain_value)).to eq subject - expect(described_class.find_by_plaintext_value("foobar")).to be_nil + expect(described_class.find_by_plaintext_value('foobar')).to be_nil end end end diff --git a/spec/models/token/ical_token_spec.rb b/spec/models/token/ical_token_spec.rb index 86744105f12d..065cba7ef4c4 100644 --- a/spec/models/token/ical_token_spec.rb +++ b/spec/models/token/ical_token_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Token::ICal do let(:user) { create(:user) } let(:project) { create(:project) } let(:query) { create(:query, project:) } - let(:name) { "unique_name" } + let(:name) { 'unique_name' } - it "inherits from Token::HashedToken" do + it 'inherits from Token::HashedToken' do expect(described_class).to be < Token::HashedToken end - describe "in contrast to HashedToken" do - it "needs to be assigned to a query with a name" do + describe 'in contrast to HashedToken' do + it 'needs to be assigned to a query with a name' do # ical tokens are only valid for a specific query (scoped to a query) # thus an ical_token cannot be created without such an assignment ical_token1 = described_class.create(user:) @@ -70,7 +70,7 @@ ) end - it "a user can have N ical tokens per query with different names" do + it 'a user can have N ical tokens per query with different names' do # Every time an ical url is generated, a new ical token will be generated for this url as well # the existing ical tokens (and thus urls) should still be valid # until the user decides to revert all existing ical tokens of a query @@ -104,7 +104,7 @@ ) end - it "a user cannot have N ical tokens per query with the same name" do + it 'a user cannot have N ical tokens per query with the same name' do ical_token1 = described_class.create( user:, ical_token_query_assignment_attributes: { query:, name: "#{name}_1" } @@ -136,8 +136,8 @@ ) end - describe "#create_and_return_value method" do - it "expects the query and token name and returns a token value" do + describe '#create_and_return_value method' do + it 'expects the query and token name and returns a token value' do ical_token1_value = nil expect do @@ -158,7 +158,7 @@ expect(ical_token1.ical_token_query_assignment.name).to eq name end - it "does not return a token value if token was not successfully persisted" do + it 'does not return a token value if token was not successfully persisted' do ical_token1_value = nil ical_token2_value = nil @@ -189,9 +189,9 @@ end end - describe "dependent destroyed" do - context "when associated query is destroyed" do - it "the ical_token is destroyed as well" do + describe 'dependent destroyed' do + context 'when associated query is destroyed' do + it 'the ical_token is destroyed as well' do described_class.create( user:, ical_token_query_assignment_attributes: { query:, name: } @@ -205,8 +205,8 @@ end end - context "when associated user is destroyed" do - it "the ical_token is destroyed as well" do + context 'when associated user is destroyed' do + it 'the ical_token is destroyed as well' do described_class.create( user:, ical_token_query_assignment_attributes: { query:, name: } @@ -220,8 +220,8 @@ end end - context "when ical_token is destroyed" do - it "the ical_token_query_assignment is destroyed as well" do + context 'when ical_token is destroyed' do + it 'the ical_token_query_assignment is destroyed as well' do ical_token = described_class.create( user:, ical_token_query_assignment_attributes: { query:, name: } @@ -236,7 +236,7 @@ end end - describe "behaves like Token::HashedToken if created with query assignment" do + describe 'behaves like Token::HashedToken if created with query assignment' do subject do described_class.new( user:, @@ -248,20 +248,20 @@ # in order to make sure the token behaves in the same way in it's basics # cheching for inheritance does not safely check if the basic behaviour is the same # is there a better way of reusing the specs from hashed_token_spec? - describe "token value" do - it "is generated on a new instance" do + describe 'token value' do + it 'is generated on a new instance' do expect(subject.value).to be_present end - it "provides the generated plain value on a new instance" do + it 'provides the generated plain value on a new instance' do expect(subject.valid_plaintext?(subject.plain_value)).to be true end - it "hashes the plain value to value" do + it 'hashes the plain value to value' do expect(subject.value).not_to eq(subject.plain_value) end - it "does not keep the value when finding it" do + it 'does not keep the value when finding it' do subject.save! instance = described_class.where(user:).last @@ -269,15 +269,15 @@ end end - describe "#find_by_plaintext_value" do + describe '#find_by_plaintext_value' do before do subject.save! end - it "finds using the plaintext value" do + it 'finds using the plaintext value' do # rubocop:disable Rails/DynamicFindBy expect(described_class.find_by_plaintext_value(subject.plain_value)).to eq subject - expect(described_class.find_by_plaintext_value("foobar")).to be_nil + expect(described_class.find_by_plaintext_value('foobar')).to be_nil # rubocop:enable Rails/DynamicFindBy end end diff --git a/spec/models/type/attribute_groups_spec.rb b/spec/models/type/attribute_groups_spec.rb index f411a862d723..9a093b752156 100644 --- a/spec/models/type/attribute_groups_spec.rb +++ b/spec/models/type/attribute_groups_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Type do let(:type) { build(:type) } @@ -39,7 +39,7 @@ end describe "#attribute_groups" do - shared_examples_for "returns default attributes" do + shared_examples_for 'returns default attributes' do it do expect(type.read_attribute(:attribute_groups)).to be_empty @@ -51,65 +51,65 @@ end end - context "with attributes provided" do + context 'with attributes provided' do before do - type.attribute_groups = [["foo", []], ["bar", %w(blubs date)]] + type.attribute_groups = [['foo', []], ['bar', %w(blubs date)]] end - it "removes unknown attributes from a group" do + it 'removes unknown attributes from a group' do group = type.attribute_groups[1] - expect(group.key).to eql "bar" - expect(group.members).to eql ["date"] + expect(group.key).to eql 'bar' + expect(group.members).to eql ['date'] end - it "keeps groups without attributes" do + it 'keeps groups without attributes' do group = type.attribute_groups[0] - expect(group.key).to eql "foo" + expect(group.key).to eql 'foo' expect(group.members).to eql [] end - it "does not have a children query" do + it 'does not have a children query' do expect(type.attribute_groups.detect { |group| group.key == :children }).to be_nil end end - context "with empty attributes provided" do + context 'with empty attributes provided' do before do type.attribute_groups = [] end - it "returns an empty attribute_groups" do + it 'returns an empty attribute_groups' do expect(type.attribute_groups).to be_empty end end - context "with no attributes provided" do - it_behaves_like "returns default attributes" + context 'with no attributes provided' do + it_behaves_like 'returns default attributes' end - context "with a query group" do + context 'with a query group' do let(:type) { create(:type) } let(:query) { build(:global_query, user_id: 0) } before do login_as(admin) - type.attribute_groups = [["some group", [query]]] + type.attribute_groups = [['some group', [query]]] type.save! type.reload end - it "retrieves the query" do + it 'retrieves the query' do expect(type.attribute_groups.length).to be 1 expect(type.attribute_groups[0].class).to eql Type::QueryGroup - expect(type.attribute_groups[0].key).to eql "some group" + expect(type.attribute_groups[0].key).to eql 'some group' expect(type.attribute_groups[0].query).to eql query end - it "removes the former query if a new one is assigned" do + it 'removes the former query if a new one is assigned' do new_query = build(:global_query, user_id: 0) type.attribute_groups[0].attributes = new_query type.save! @@ -118,7 +118,7 @@ expect(type.attribute_groups.length).to be 1 expect(type.attribute_groups[0].class).to eql Type::QueryGroup - expect(type.attribute_groups[0].key).to eql "some group" + expect(type.attribute_groups[0].key).to eql 'some group' expect(type.attribute_groups[0].query).to eql new_query expect(Query.count).to be 1 @@ -126,14 +126,14 @@ end end - describe "#default_attribute_groups" do + describe '#default_attribute_groups' do subject { type.default_attribute_groups } - it "returns an array" do + it 'returns an array' do expect(subject.any?).to be_truthy end - it "each attribute group is an array" do + it 'each attribute group is an array' do expect(subject.detect { |g| g.class != Array }).to be_falsey end @@ -145,7 +145,7 @@ expect(subject.detect { |g| g.second.class != Array }).to be_falsey end - it "does not return empty groups" do + it 'does not return empty groups' do # For instance, the `type` factory instance does not have custom fields. # Thus the `other` group shall not be returned. expect(subject.detect do |attribute_group| @@ -155,44 +155,44 @@ end end - describe "custom fields" do + describe 'custom fields' do let!(:custom_field) do create( :work_package_custom_field, - field_format: "string" + field_format: 'string' ) end let(:cf_identifier) do custom_field.attribute_name end - it "can be put into attribute groups" do + it 'can be put into attribute groups' do # Enforce fresh lookup of groups OpenProject::Cache.clear # Can be enabled - type.attribute_groups = [["foo", [cf_identifier]]] + type.attribute_groups = [['foo', [cf_identifier]]] expect(type.save).to be_truthy expect(type.read_attribute(:attribute_groups)).not_to be_empty end - context "with multiple CFs" do + context 'with multiple CFs' do let!(:custom_field2) do create( :work_package_custom_field, - field_format: "string" + field_format: 'string' ) end let(:cf_identifier2) do custom_field2.attribute_name end - it "they are kept in their respective positions in the group (Regression test #27940)" do + it 'they are kept in their respective positions in the group (Regression test #27940)' do # Enforce fresh lookup of groups OpenProject::Cache.clear # Can be enabled - type.attribute_groups = [["foo", [cf_identifier2, cf_identifier]]] + type.attribute_groups = [['foo', [cf_identifier2, cf_identifier]]] expect(type.save).to be_truthy expect(type.read_attribute(:attribute_groups)).not_to be_empty @@ -202,17 +202,17 @@ end end - describe "custom field added implicitly to type" do + describe 'custom field added implicitly to type' do let(:custom_field) do create( :work_package_custom_field, - field_format: "string", + field_format: 'string', is_for_all: true ) end let!(:type) { create(:type, custom_fields: [custom_field]) } - it "has the custom field in the default group" do + it 'has the custom field in the default group' do OpenProject::Cache.clear type.reload @@ -231,18 +231,18 @@ end end - describe "#destroy" do + describe '#destroy' do let(:query) { build(:global_query, user_id: 0) } before do login_as(admin) - type.attribute_groups = [["some name", [query]]] + type.attribute_groups = [['some name', [query]]] type.save! type.reload type.destroy end - it "destroys all queries references by query groups" do + it 'destroys all queries references by query groups' do expect(Query.find_by(id: query.id)).to be_nil end end diff --git a/spec/models/type_spec.rb b/spec/models/type_spec.rb index 43d9fbe48767..8287ccc3456d 100644 --- a/spec/models/type_spec.rb +++ b/spec/models/type_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Type do let(:type) { build(:type) } let(:type2) { build(:type) } let(:project) { build(:project, no_types: true) } - describe ".enabled_in(project)" do + describe '.enabled_in(project)' do before do type.projects << project type.save @@ -41,31 +41,31 @@ type2.save end - it "returns the types enabled in the provided project" do + it 'returns the types enabled in the provided project' do expect(Type.enabled_in(project)).to contain_exactly(type) end end - describe ".statuses" do + describe '.statuses' do subject { type.statuses } - context "when new" do + context 'when new' do let(:type) { build(:type) } - it "returns an empty relation" do + it 'returns an empty relation' do expect(subject).to be_empty end end - context "when existing but no statuses" do + context 'when existing but no statuses' do let(:type) { create(:type) } - it "returns an empty relation" do + it 'returns an empty relation' do expect(subject).to be_empty end end - context "when existing with workflow" do + context 'when existing with workflow' do let(:role) { create(:project_role) } let(:statuses) { (1..2).map { |_i| create(:status) } } @@ -79,29 +79,29 @@ assignee: false) end - it "returns the statuses relation" do + it 'returns the statuses relation' do expect(subject.pluck(:id)).to contain_exactly(statuses[0].id, statuses[1].id) end - context "with default status" do + context 'with default status' do let!(:default_status) { create(:default_status) } subject { type.statuses(include_default: true) } - it "returns the workflow and the default status" do + it 'returns the workflow and the default status' do expect(subject.pluck(:id)).to contain_exactly(default_status.id, statuses[0].id, statuses[1].id) end end end end - describe "#copy_from_type on workflows" do + describe '#copy_from_type on workflows' do before do allow(Workflow) .to receive(:copy) end - it "calls the .copy method on Workflow" do + it 'calls the .copy method on Workflow' do type.workflows.copy_from_type(type2) expect(Workflow) @@ -110,17 +110,17 @@ end end - describe "#work_package_attributes" do + describe '#work_package_attributes' do subject { type.work_package_attributes } - context "for the duration field" do - it "does not return the field" do + context 'for the duration field' do + it 'does not return the field' do expect(subject).not_to have_key("duration") end end - context "for the ignore_non_working_days field" do - it "does not return the field" do + context 'for the ignore_non_working_days field' do + it 'does not return the field' do expect(subject).not_to have_key("ignore_non_working_days") end end diff --git a/spec/models/types/scopes/milestone_spec.rb b/spec/models/types/scopes/milestone_spec.rb index 824276a9d8ac..aaf33ba623d8 100644 --- a/spec/models/types/scopes/milestone_spec.rb +++ b/spec/models/types/scopes/milestone_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Types::Scopes::Milestone do let!(:milestone) { create(:type, is_milestone: true) } let!(:other_type) { create(:type, is_milestone: false) } - describe ".milestone" do + describe '.milestone' do subject { Type.milestone } - it "returns only milestones" do + it 'returns only milestones' do expect(subject) .to contain_exactly(milestone) end diff --git a/spec/models/user_password_spec.rb b/spec/models/user_password_spec.rb index 7ddba4cc2308..b02bbc27fe6e 100644 --- a/spec/models/user_password_spec.rb +++ b/spec/models/user_password_spec.rb @@ -26,43 +26,43 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UserPassword do let(:old_password) { create(:old_user_password) } let(:user) { create(:user) } - let(:password) { create(:user_password, user:, plain_password: "adminAdmin!") } + let(:password) { create(:user_password, user:, plain_password: 'adminAdmin!') } - describe "#expired?" do - context "with expiry value set", + describe '#expired?' do + context 'with expiry value set', with_settings: { password_days_valid: 30 } do - it "is true for an old password when password expiry is activated" do + it 'is true for an old password when password expiry is activated' do expect(old_password.expired?).to be_truthy end - it "is false when password expiry is enabled and the password was changed recently" do + it 'is false when password expiry is enabled and the password was changed recently' do expect(password.expired?).to be_falsey end end - context "with expiry value disabled", + context 'with expiry value disabled', with_settings: { password_days_valid: 0 } do - it "is false for an old password when password expiry is disabled" do + it 'is false for an old password when password expiry is disabled' do expect(old_password.expired?).to be_falsey end end end - describe "#matches_plaintext?" do - it "still matches the password" do + describe '#matches_plaintext?' do + it 'still matches the password' do expect(password).to be_a(UserPassword.active_type) - expect(password.matches_plaintext?("adminAdmin!")).to be_truthy + expect(password.matches_plaintext?('adminAdmin!')).to be_truthy end end - describe "#rehash_as_active" do + describe '#rehash_as_active' do let(:password) do - pass = build(:legacy_sha1_password, user:, plain_password: "adminAdmin!") + pass = build(:legacy_sha1_password, user:, plain_password: 'adminAdmin!') expect(pass).to receive(:salt_and_hash_password!).and_return nil pass.save! @@ -74,31 +74,31 @@ user.reload end - it "rehashed the password when correct" do + it 'rehashed the password when correct' do expect(user.current_password).to be_a(UserPassword::SHA1) expect do - password.matches_plaintext?("adminAdmin!") + password.matches_plaintext?('adminAdmin!') end.not_to change { user.passwords.count } expect(user.current_password).to be_a(UserPassword::Bcrypt) - expect(user.current_password.hashed_password).to start_with "$2a$" + expect(user.current_password.hashed_password).to start_with '$2a$' end - it "does not alter the password when invalid" do - expect(password.matches_plaintext?("wat")).to be false + it 'does not alter the password when invalid' do + expect(password.matches_plaintext?('wat')).to be false expect(password).to be_a(UserPassword::SHA1) end - it "does not alter the password when disabled" do - expect(password.matches_plaintext?("adminAdmin!", update_legacy: false)).to be true + it 'does not alter the password when disabled' do + expect(password.matches_plaintext?('adminAdmin!', update_legacy: false)).to be true expect(user.current_password).to be_a(UserPassword::SHA1) end end - describe "#save" do + describe '#save' do let(:password) { build(:user_password) } - it "saves correctly" do + it 'saves correctly' do expect(password).to receive(:salt_and_hash_password!).and_call_original expect { password.save! }.not_to raise_error expect(password).not_to be_expired diff --git a/spec/models/user_passwords/sha1_spec.rb b/spec/models/user_passwords/sha1_spec.rb index 02e548771fdf..963d38e80ced 100644 --- a/spec/models/user_passwords/sha1_spec.rb +++ b/spec/models/user_passwords/sha1_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UserPassword::SHA1 do let(:legacy_password) do - pass = build(:legacy_sha1_password, plain_password: "adminAdmin!") + pass = build(:legacy_sha1_password, plain_password: 'adminAdmin!') expect(pass).to receive(:salt_and_hash_password!).and_return nil pass.save! pass end - describe "#matches_plaintext?" do - it "still matches for existing passwords" do + describe '#matches_plaintext?' do + it 'still matches for existing passwords' do expect(legacy_password).to be_a(UserPassword::SHA1) - expect(legacy_password.matches_plaintext?("adminAdmin!")).to be_truthy + expect(legacy_password.matches_plaintext?('adminAdmin!')).to be_truthy end end - describe "#create" do + describe '#create' do let(:legacy_password) { build(:legacy_sha1_password) } - it "raises an exception trying to save it" do + it 'raises an exception trying to save it' do expect { legacy_password.save! }.to raise_error(ArgumentError) end end diff --git a/spec/models/user_preference_spec.rb b/spec/models/user_preference_spec.rb index 272035014089..94a18fd3c4b8 100644 --- a/spec/models/user_preference_spec.rb +++ b/spec/models/user_preference_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UserPreference do subject(:preference) do @@ -39,8 +39,8 @@ let(:user) { build_stubbed(:user) } - shared_examples "accepts real and false booleans" do |setter, getter| - it "accepts true boolean" do + shared_examples 'accepts real and false booleans' do |setter, getter| + it 'accepts true boolean' do subject.send(setter, true) expect(subject.send(getter)).to be true @@ -48,7 +48,7 @@ expect(subject.send(getter)).to be false end - it "accepts false booleans" do + it 'accepts false booleans' do %w(true 1).each do |str| subject.send(setter, str) expect(subject.send(getter)).to be true @@ -61,73 +61,73 @@ end end - describe "#respond_to?" do - context "for created_at (key not in the schema)" do - it "is does not respond" do + describe '#respond_to?' do + context 'for created_at (key not in the schema)' do + it 'is does not respond' do expect(preference) .not_to respond_to(:created_at) end end end - describe "an unsupported method" do - context "for created_at (key not in the schema)" do - it "raises an error" do + describe 'an unsupported method' do + context 'for created_at (key not in the schema)' do + it 'raises an error' do expect { preference.created_at } .to raise_error NoMethodError end end end - describe "sort order" do - it_behaves_like "accepts real and false booleans", + describe 'sort order' do + it_behaves_like 'accepts real and false booleans', :comments_in_reverse_order=, :comments_in_reverse_order? - it "can be changed by string" do - subject.comments_sorting = "desc" + it 'can be changed by string' do + subject.comments_sorting = 'desc' expect(subject.comments_in_reverse_order?).to be true - subject.comments_sorting = "asc" + subject.comments_sorting = 'asc' expect(subject.comments_in_reverse_order?).to be false end end - describe "warn on unsaved changes" do - it_behaves_like "accepts real and false booleans", + describe 'warn on unsaved changes' do + it_behaves_like 'accepts real and false booleans', :warn_on_leaving_unsaved=, :warn_on_leaving_unsaved? end - describe "auto hide popups" do - it_behaves_like "accepts real and false booleans", + describe 'auto hide popups' do + it_behaves_like 'accepts real and false booleans', :auto_hide_popups=, :auto_hide_popups? - describe "without a value being stored and with default setting auto_hide_popups to false", + describe 'without a value being stored and with default setting auto_hide_popups to false', with_settings: { default_auto_hide_popups: false } do - it "disables auto hide popups" do + it 'disables auto hide popups' do expect(subject.auto_hide_popups).to be_falsey end end - context "without a value being stored and with default setting auto_hide_popups to true", + context 'without a value being stored and with default setting auto_hide_popups to true', with_settings: { default_auto_hide_popups: true } do - it "disables auto hide popups" do + it 'disables auto hide popups' do expect(subject.auto_hide_popups).to be_truthy end end end - describe "hide_mail" do - it_behaves_like "accepts real and false booleans", + describe 'hide_mail' do + it_behaves_like 'accepts real and false booleans', :hide_mail=, :hide_mail? - context "when a new pref instance" do + context 'when a new pref instance' do subject { described_class.new } - it "defaults to true" do + it 'defaults to true' do expect(subject.settings[:hide_mail]).to be_nil expect(subject.hide_mail).to be true expect(subject.hide_mail?).to be true @@ -140,36 +140,36 @@ end end - describe "#diff_type" do - it "can be set and written" do + describe '#diff_type' do + it 'can be set and written' do expect(subject.diff_type) - .to eql "inline" + .to eql 'inline' - subject.diff_type = "sbs" + subject.diff_type = 'sbs' expect(subject.diff_type) - .to eql "sbs" + .to eql 'sbs' end - context "with a new pref instance" do + context 'with a new pref instance' do subject { described_class.new } - it "defaults to `inline`" do + it 'defaults to `inline`' do expect(subject.diff_type) - .to eql "inline" + .to eql 'inline' end end end - describe "#daily_reminders" do - context "without reminders being stored" do - it "uses the defaults" do + describe '#daily_reminders' do + context 'without reminders being stored' do + it 'uses the defaults' do expect(subject.daily_reminders) .to eql("enabled" => true, "times" => ["08:00:00+00:00"]) end end - context "with reminders being stored" do + context 'with reminders being stored' do let(:settings) do { "daily_reminders" => { @@ -179,49 +179,49 @@ } end - it "returns the stored value" do + it 'returns the stored value' do expect(subject.daily_reminders) .to eql(settings["daily_reminders"]) end end end - describe "#workdays" do - context "without work days being stored" do - it "uses the defaults" do + describe '#workdays' do + context 'without work days being stored' do + it 'uses the defaults' do expect(subject.workdays) .to eq([1, 2, 3, 4, 5]) end end - context "with work days being stored" do + context 'with work days being stored' do let(:settings) do { "workdays" => [1, 2, 4, 5] } end - it "returns the stored value" do + it 'returns the stored value' do expect(subject.workdays) .to eql([1, 2, 4, 5]) end end - context "with work days being stored and empty" do + context 'with work days being stored and empty' do let(:settings) do { "workdays" => [] } end - it "return empty array" do + it 'return empty array' do expect(subject.workdays) .to eql([]) end end end - describe "[]=" do + describe '[]=' do let(:user) { create(:user) } it 'saves the values on sending "save"' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 9bbcb97d49f5..b4e9431ab4b3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe User do let(:user) { build(:user) } @@ -47,164 +47,164 @@ status:) end - describe "with long but allowed attributes" do - it "is valid" do - user.firstname = "a" * 256 - user.lastname = "b" * 256 + describe 'with long but allowed attributes' do + it 'is valid' do + user.firstname = 'a' * 256 + user.lastname = 'b' * 256 user.mail = "fo#{'o' * 237}@mail.example.com" expect(user).to be_valid expect(user.save).to be_truthy end end - describe "a user with and overly long firstname (> 256 chars)" do - it "is invalid" do - user.firstname = "a" * 257 + describe 'a user with and overly long firstname (> 256 chars)' do + it 'is invalid' do + user.firstname = 'a' * 257 expect(user).not_to be_valid expect(user.save).to be_falsey end end - describe "a user with and overly long lastname (> 256 chars)" do - it "is invalid" do - user.lastname = "a" * 257 + describe 'a user with and overly long lastname (> 256 chars)' do + it 'is invalid' do + user.lastname = 'a' * 257 expect(user).not_to be_valid expect(user.save).to be_falsey end end - describe "#mail" do + describe '#mail' do before do user.mail = mail end - context "with whitespaces" do - let(:mail) { " foo@bar.com " } + context 'with whitespaces' do + let(:mail) { ' foo@bar.com ' } - it "is stripped" do + it 'is stripped' do expect(user.mail) - .to eql "foo@bar.com" + .to eql 'foo@bar.com' end end - context "for local mail addresses" do - let(:mail) { "foobar@abc.def.some-internet" } + context 'for local mail addresses' do + let(:mail) { 'foobar@abc.def.some-internet' } - it "is valid" do + it 'is valid' do expect(user).to be_valid end end - context "for wrong mail addresses" do - let(:mail) { "foobar+abc.def.some-internet" } + context 'for wrong mail addresses' do + let(:mail) { 'foobar+abc.def.some-internet' } - it "is invalid" do + it 'is invalid' do expect(user).to be_invalid end end - context "for an already taken mail addresses (different take)" do - let(:mail) { "foo@bar.com" } - let!(:other_user) { create(:user, mail: "Foo@Bar.com") } + context 'for an already taken mail addresses (different take)' do + let(:mail) { 'foo@bar.com' } + let!(:other_user) { create(:user, mail: 'Foo@Bar.com') } - it "is invalid" do + it 'is invalid' do expect(user).to be_invalid end end end - describe "#login" do + describe '#login' do before do user.login = login end - context "with whitespace" do - context "with simple spaces" do - let(:login) { "a b c" } + context 'with whitespace' do + context 'with simple spaces' do + let(:login) { 'a b c' } - it "is valid" do + it 'is valid' do expect(user).to be_valid end - it "may be stored in the database" do + it 'may be stored in the database' do expect(user.save).to be_truthy end end - context "with line breaks" do + context 'with line breaks' do let(:login) { 'ab\nc' } - it "is invalid" do + it 'is invalid' do expect(user).not_to be_valid end - it "may not be stored in the database" do + it 'may not be stored in the database' do expect(user.save).to be_falsey end end - context "with tabs" do + context 'with tabs' do let(:login) { 'ab\tc' } - it "is invalid" do + it 'is invalid' do expect(user).not_to be_valid end - it "may not be stored in the database" do + it 'may not be stored in the database' do expect(user.save).to be_falsey end end end - context "with symbols" do + context 'with symbols' do %w[+ _ . - @].each do |symbol| context symbol do let(:login) { "foo#{symbol}bar" } - it "is valid" do + it 'is valid' do expect(user).to be_valid end - it "may be stored in the database" do + it 'may be stored in the database' do expect(user.save).to be_truthy end end end - context "with combination thereof" do - let(:login) { "the+boss-is@the_house." } + context 'with combination thereof' do + let(:login) { 'the+boss-is@the_house.' } - it "is valid" do + it 'is valid' do expect(user).to be_valid end - it "may be stored in the database" do + it 'may be stored in the database' do expect(user.save).to be_truthy end end - context "with invalid symbol" do - let(:login) { "invalid!name" } + context 'with invalid symbol' do + let(:login) { 'invalid!name' } - it "is invalid" do + it 'is invalid' do expect(user).not_to be_valid end - it "may not be stored in the database" do + it 'may not be stored in the database' do expect(user.save).to be_falsey end end end - context "with more that 255 chars" do - let(:login) { "a" * 256 } + context 'with more that 255 chars' do + let(:login) { 'a' * 256 } - it "is valid" do + it 'is valid' do user.login = login expect(user).to be_valid end - it "may be loaded from the database" do + it 'may be loaded from the database' do user.login = login expect(user.save).to be_truthy @@ -213,55 +213,55 @@ end end - context "with an invalid login" do - let(:login) { "me" } + context 'with an invalid login' do + let(:login) { 'me' } - it "is invalid" do + it 'is invalid' do user.login = login expect(user).not_to be_valid end end - context "with an overly long login (> 256 chars)" do - let(:login) { "a" * 257 } + context 'with an overly long login (> 256 chars)' do + let(:login) { 'a' * 257 } - it "is invalid" do + it 'is invalid' do expect(user).not_to be_valid end - it "may not be stored in the database" do + it 'may not be stored in the database' do expect(user.save).to be_falsey end end - context "with another user having the login in a different case" do - let!(:other_user) { create(:user, login: "NewUser") } - let(:login) { "newuser" } + context 'with another user having the login in a different case' do + let!(:other_user) { create(:user, login: 'NewUser') } + let(:login) { 'newuser' } - it "is invalid" do + it 'is invalid' do expect(user).not_to be_valid end end - context "when empty" do - let(:login) { "" } + context 'when empty' do + let(:login) { '' } - it "is invalid" do + it 'is invalid' do expect(user).not_to be_valid end end end - describe "name validation" do + describe 'name validation' do let(:user) do build(:user) end - it "restricts some options", :aggregate_failures do + it 'restricts some options', :aggregate_failures do [ - "http://foobar.com", - "", - "https://hello.com" + 'http://foobar.com', + '', + 'https://hello.com' ].each do |name| user.firstname = name user.lastname = name @@ -271,7 +271,7 @@ end end - it "allows a lot of options", :aggregate_failures do + it 'allows a lot of options', :aggregate_failures do [ "Tim O'Reilly", "🔴Emojinames", @@ -290,52 +290,52 @@ end end - describe "#name" do + describe '#name' do let(:user) do create(:user, - firstname: "John", - lastname: "Smith", - login: "username", - mail: "user@name.org") + firstname: 'John', + lastname: 'Smith', + login: 'username', + mail: 'user@name.org') end - context "for firstname_lastname", with_settings: { user_format: :firstname_lastname } do + context 'for firstname_lastname', with_settings: { user_format: :firstname_lastname } do it { expect(user.name).to eq "#{user.firstname} #{user.lastname}" } end - context "for firstname", with_settings: { user_format: :firstname } do + context 'for firstname', with_settings: { user_format: :firstname } do it { expect(user.name).to eq user.firstname } end - context "for lastname_firstname", with_settings: { user_format: :lastname_firstname } do + context 'for lastname_firstname', with_settings: { user_format: :lastname_firstname } do it { expect(user.name).to eq "#{user.lastname} #{user.firstname}" } end - context "for lastname_n_firstname", with_settings: { user_format: :lastname_n_firstname } do + context 'for lastname_n_firstname', with_settings: { user_format: :lastname_n_firstname } do it { expect(user.name).to eq "#{user.lastname}#{user.firstname}" } end - context "for lastname_coma_firstname", with_settings: { user_format: :lastname_coma_firstname } do + context 'for lastname_coma_firstname', with_settings: { user_format: :lastname_coma_firstname } do it { expect(user.name).to eq "#{user.lastname}, #{user.firstname}" } end - context "for username", with_settings: { user_format: :username } do + context 'for username', with_settings: { user_format: :username } do it { expect(user.name).to eq user.login } end end - describe "#authentication_provider" do + describe '#authentication_provider' do before do - user.identity_url = "test_provider:veryuniqueid" + user.identity_url = 'test_provider:veryuniqueid' user.save! end - it "creates a human readable name" do - expect(user.authentication_provider).to eql("Test Provider") + it 'creates a human readable name' do + expect(user.authentication_provider).to eql('Test Provider') end end - describe "#blocked" do + describe '#blocked' do let!(:blocked_user) do create(:user, failed_login_count: 3, @@ -348,55 +348,55 @@ allow(Setting).to receive(:brute_force_block_minutes).and_return(30) end - it "returns the single blocked user" do + it 'returns the single blocked user' do expect(described_class.blocked.length).to eq(1) expect(described_class.blocked.first.id).to eq(blocked_user.id) end end - describe "#change_password_allowed?" do + describe '#change_password_allowed?' do let(:user) { build(:user) } - context "for user without auth source" do + context 'for user without auth source' do before do user.ldap_auth_source = nil end - it "is true" do + it 'is true' do assert user.change_password_allowed? end end - context "for user with an auth source" do + context 'for user with an auth source' do let(:auth_source) { create(:ldap_auth_source) } before do user.ldap_auth_source = auth_source end - it "does not allow password changes" do + it 'does not allow password changes' do expect(user).not_to be_change_password_allowed end end - context "for user without LdapAuthSource and with external authentication" do + context 'for user without LdapAuthSource and with external authentication' do before do user.ldap_auth_source = nil allow(user).to receive(:uses_external_authentication?).and_return(true) end - it "does not allow a password change" do + it 'does not allow a password change' do expect(user).not_to be_change_password_allowed end end end - describe "#watches" do + describe '#watches' do before do user.save! end - describe "WHEN the user is watching" do + describe 'WHEN the user is watching' do let(:watcher) do Watcher.new(watchable: issue, user:) @@ -421,51 +421,51 @@ end end - describe "#uses_external_authentication?" do - context "with identity_url" do - let(:user) { build(:user, identity_url: "test_provider:veryuniqueid") } + describe '#uses_external_authentication?' do + context 'with identity_url' do + let(:user) { build(:user, identity_url: 'test_provider:veryuniqueid') } - it "returns true" do + it 'returns true' do expect(user).to be_uses_external_authentication end end - context "without identity_url" do + context 'without identity_url' do let(:user) { build(:user, identity_url: nil) } - it "returns false" do + it 'returns false' do expect(user).not_to be_uses_external_authentication end end end - describe "user create with empty password" do - let(:user) { described_class.new(firstname: "new", lastname: "user", mail: "newuser@somenet.foo") } + describe 'user create with empty password' do + let(:user) { described_class.new(firstname: 'new', lastname: 'user', mail: 'newuser@somenet.foo') } before do - user.login = "new_user" - user.password = "" - user.password_confirmation = "" + user.login = 'new_user' + user.password = '' + user.password_confirmation = '' user.save end it { expect(user).not_to be_valid } it { - expect(user.errors[:password]).to include I18n.t("activerecord.errors.messages.too_short", + expect(user.errors[:password]).to include I18n.t('activerecord.errors.messages.too_short', count: Setting.password_min_length.to_i) } end - describe "#random_password" do + describe '#random_password' do let(:user) { described_class.new } - context "without generation" do + context 'without generation' do it { expect(user.password).to be_nil } it { expect(user.password_confirmation).to be_nil } end - context "with generation" do + context 'with generation' do before do user.random_password! end @@ -476,9 +476,9 @@ end end - describe "#try_authentication_for_existing_user" do + describe '#try_authentication_for_existing_user' do def build_user_double_with_expired_password(is_expired) - user_double = double("User") + user_double = double('User') allow(user_double).to receive(:check_password?).and_return(true) allow(user_double).to receive(:active?).and_return(true) allow(user_double).to receive(:ldap_auth_source).and_return(nil) @@ -490,78 +490,78 @@ def build_user_double_with_expired_password(is_expired) user_double end - it "does not allow login with an expired password" do + it 'does not allow login with an expired password' do user_double = build_user_double_with_expired_password(true) # use !! to ensure value is boolean - expect(!!described_class.try_authentication_for_existing_user(user_double, "anypassword")).to \ + expect(!!described_class.try_authentication_for_existing_user(user_double, 'anypassword')).to \ be(false) end - it "allows login with a not expired password" do + it 'allows login with a not expired password' do user_double = build_user_double_with_expired_password(false) # use !! to ensure value is boolean - expect(!!described_class.try_authentication_for_existing_user(user_double, "anypassword")).to \ + expect(!!described_class.try_authentication_for_existing_user(user_double, 'anypassword')).to \ be(true) end - context "with an external auth source" do + context 'with an external auth source' do let(:auth_source) { build(:ldap_auth_source) } let(:user_with_external_auth_source) do - user = build(:user, login: "user") + user = build(:user, login: 'user') allow(user).to receive(:ldap_auth_source).and_return(auth_source) user end - context "and successful external authentication" do + context 'and successful external authentication' do before do - expect(auth_source).to receive(:authenticate).with("user", "password").and_return(true) + expect(auth_source).to receive(:authenticate).with('user', 'password').and_return(true) end - it "succeeds" do - expect(described_class.try_authentication_for_existing_user(user_with_external_auth_source, "password")) + it 'succeeds' do + expect(described_class.try_authentication_for_existing_user(user_with_external_auth_source, 'password')) .to eq(user_with_external_auth_source) end end - context "and failing external authentication" do + context 'and failing external authentication' do before do - expect(auth_source).to receive(:authenticate).with("user", "password").and_return(false) + expect(auth_source).to receive(:authenticate).with('user', 'password').and_return(false) end - it "fails when the authentication fails" do - expect(described_class.try_authentication_for_existing_user(user_with_external_auth_source, "password")) + it 'fails when the authentication fails' do + expect(described_class.try_authentication_for_existing_user(user_with_external_auth_source, 'password')) .to be_nil end end end end - describe "#wants_comments_in_reverse_order?" do + describe '#wants_comments_in_reverse_order?' do let(:user) { create(:user) } - it "is false by default" do + it 'is false by default' do expect(user) .not_to be_wants_comments_in_reverse_order end - it "is false if set to asc" do - user.pref.comments_sorting = "asc" + it 'is false if set to asc' do + user.pref.comments_sorting = 'asc' expect(user) .not_to be_wants_comments_in_reverse_order end - it "is true if set to asc" do - user.pref.comments_sorting = "desc" + it 'is true if set to asc' do + user.pref.comments_sorting = 'desc' expect(user) .to be_wants_comments_in_reverse_order end end - describe "#roles_for_project" do + describe '#roles_for_project' do let(:project) { create(:project) } let!(:user) do create(:user, @@ -569,24 +569,24 @@ def build_user_double_with_expired_password(is_expired) end let(:roles) { create_list(:project_role, 2) } - context "for a project the user has roles in" do - it "returns the roles" do + context 'for a project the user has roles in' do + it 'returns the roles' do expect(user.roles_for_project(project)) .to match_array roles end end - context "for a project the user does not have roles in" do + context 'for a project the user does not have roles in' do let(:other_project) { create(:project) } - it "returns an empty set" do + it 'returns an empty set' do expect(user.roles_for_project(other_project)) .to be_empty end end end - describe "#roles_for_work_package" do + describe '#roles_for_work_package' do let(:work_package) { create(:work_package) } let!(:user) do create(:user, @@ -598,30 +598,30 @@ def build_user_double_with_expired_password(is_expired) let(:project_roles) { create_list(:project_role, 2) } let(:work_package_roles) { create_list(:work_package_role, 1) } - context "for a work_package the user has roles in" do - it "returns the roles" do + context 'for a work_package the user has roles in' do + it 'returns the roles' do expect(user.roles_for_work_package(work_package)) .to match_array project_roles + work_package_roles end end - context "for a work_package the user does not have roles in" do + context 'for a work_package the user does not have roles in' do let(:other_work_package) { create(:work_package) } - it "returns an empty set" do + it 'returns an empty set' do expect(user.roles_for_work_package(other_work_package)) .to be_empty end end end - describe ".system" do - context "no SystemUser exists" do + describe '.system' do + context 'no SystemUser exists' do before do SystemUser.delete_all end - it "creates a SystemUser" do + it 'creates a SystemUser' do expect do system_user = described_class.system expect(system_user).not_to be_new_record @@ -630,13 +630,13 @@ def build_user_double_with_expired_password(is_expired) end end - context "a SystemUser exists" do + context 'a SystemUser exists' do before do @u = described_class.system expect(SystemUser.first).to eq(@u) end - it "returns existing SystemUser" do + it 'returns existing SystemUser' do expect do system_user = described_class.system expect(system_user).to eq(@u) @@ -645,16 +645,16 @@ def build_user_double_with_expired_password(is_expired) end end - describe ".default_admin_account_deleted_or_changed?" do + describe '.default_admin_account_deleted_or_changed?' do let(:default_admin) do - build(:user, login: "admin", password: "admin", password_confirmation: "admin", admin: true) + build(:user, login: 'admin', password: 'admin', password_confirmation: 'admin', admin: true) end before do Setting.password_min_length = 5 end - context "default admin account exists with default password" do + context 'default admin account exists with default password' do before do default_admin.save end @@ -662,17 +662,17 @@ def build_user_double_with_expired_password(is_expired) it { expect(described_class).not_to be_default_admin_account_changed } end - context "default admin account exists with changed password" do + context 'default admin account exists with changed password' do before do - default_admin.update_attribute :password, "dafaultAdminPwd" - default_admin.update_attribute :password_confirmation, "dafaultAdminPwd" + default_admin.update_attribute :password, 'dafaultAdminPwd' + default_admin.update_attribute :password_confirmation, 'dafaultAdminPwd' default_admin.save end it { expect(described_class).to be_default_admin_account_changed } end - context "default admin account was deleted" do + context 'default admin account was deleted' do before do default_admin.save default_admin.delete @@ -681,7 +681,7 @@ def build_user_double_with_expired_password(is_expired) it { expect(described_class).to be_default_admin_account_changed } end - context "default admin account was disabled" do + context 'default admin account was disabled' do before do default_admin.status = described_class.statuses[:locked] default_admin.save @@ -691,10 +691,10 @@ def build_user_double_with_expired_password(is_expired) end end - describe ".find_by_rss_key" do + describe '.find_by_rss_key' do let(:rss_key) { user.rss_key } - context "feeds enabled" do + context 'feeds enabled' do before do allow(Setting).to receive(:feeds_enabled?).and_return(true) end @@ -702,7 +702,7 @@ def build_user_double_with_expired_password(is_expired) it { expect(described_class.find_by_rss_key(rss_key)).to eq(user) } end - context "feeds disabled" do + context 'feeds disabled' do before do allow(Setting).to receive(:feeds_enabled?).and_return(false) end @@ -711,48 +711,48 @@ def build_user_double_with_expired_password(is_expired) end end - describe "#rss_key" do + describe '#rss_key' do let(:user) { create(:user) } - it "is created on the fly" do + it 'is created on the fly' do expect { user.rss_key } .to change { user.reload.rss_token.nil? } .from(true) .to(false) end - it "is persisted" do + it 'is persisted' do key = user.rss_key expect(user.reload.rss_key) .to eq key end - it "has a length of 64" do + it 'has a length of 64' do expect(user.rss_key.length) .to eq 64 end end - describe "#ical_tokens" do + describe '#ical_tokens' do let(:user) { create(:user) } let(:query) { create(:query, user:) } let(:ical_token) { create(:ical_token, user:, query:, name: "My Token") } let(:another_ical_token) { create(:ical_token, user:, query:, name: "My Other Token") } - it "are not present by default" do + it 'are not present by default' do expect(user.ical_tokens) .to be_empty end - it "returns all existing ical tokens from this user" do + it 'returns all existing ical tokens from this user' do ical_token another_ical_token expect(user.ical_tokens).to contain_exactly(ical_token, another_ical_token) end - it "are destroyed when the user is destroyed" do + it 'are destroyed when the user is destroyed' do ical_token another_ical_token @@ -762,68 +762,68 @@ def build_user_double_with_expired_password(is_expired) end end - describe ".newest" do + describe '.newest' do let!(:anonymous) { described_class.anonymous } let!(:user1) { create(:user) } let!(:user2) { create(:user) } let(:newest) { described_class.newest.to_a } - it "without anonymous user", :aggregate_failures do + it 'without anonymous user', :aggregate_failures do expect(newest).to include(user1) expect(newest).to include(user2) expect(newest).not_to include(anonymous) end end - describe "#mail_regexp" do - it "handles suffixed mails" do - _, suffixed = described_class.mail_regexp("foo+bar@example.org") + describe '#mail_regexp' do + it 'handles suffixed mails' do + _, suffixed = described_class.mail_regexp('foo+bar@example.org') expect(suffixed).to be_truthy end end - describe "#find_by_mail" do - let!(:user1) { create(:user, mail: "foo+test@example.org") } - let!(:user2) { create(:user, mail: "foo@example.org") } - let!(:user3) { create(:user, mail: "foo-bar@example.org") } + describe '#find_by_mail' do + let!(:user1) { create(:user, mail: 'foo+test@example.org') } + let!(:user2) { create(:user, mail: 'foo@example.org') } + let!(:user3) { create(:user, mail: 'foo-bar@example.org') } - context "with default plus suffix" do - it "finds users matching the suffix" do - expect(Setting.mail_suffix_separators).to eq "+" + context 'with default plus suffix' do + it 'finds users matching the suffix' do + expect(Setting.mail_suffix_separators).to eq '+' # Can match either of the first two - match2 = described_class.find_by_mail("foo@example.org") + match2 = described_class.find_by_mail('foo@example.org') expect([user1.id, user2.id]).to include(match2.id) - matches = described_class.where_mail_with_suffix("foo@example.org") + matches = described_class.where_mail_with_suffix('foo@example.org') expect(matches.pluck(:id)).to contain_exactly(user1.id, user2.id) - matches = described_class.where_mail_with_suffix("foo+test@example.org") + matches = described_class.where_mail_with_suffix('foo+test@example.org') expect(matches.pluck(:id)).to contain_exactly(user1.id) end end - context "with plus and minus suffix", with_settings: { mail_suffix_separators: "+-" } do - it "finds users matching the suffix" do - expect(Setting.mail_suffix_separators).to eq "+-" + context 'with plus and minus suffix', with_settings: { mail_suffix_separators: '+-' } do + it 'finds users matching the suffix' do + expect(Setting.mail_suffix_separators).to eq '+-' - match1 = described_class.find_by_mail("foo-bar@example.org") + match1 = described_class.find_by_mail('foo-bar@example.org') expect(match1).to eq(user3) # Can match either of the three - match2 = described_class.find_by_mail("foo@example.org") + match2 = described_class.find_by_mail('foo@example.org') expect([user1.id, user2.id, user3.id]).to include(match2.id) - matches = described_class.where_mail_with_suffix("foo@example.org") + matches = described_class.where_mail_with_suffix('foo@example.org') expect(matches.pluck(:id)).to contain_exactly(user1.id, user2.id, user3.id) end end end - describe ".try_to_login" do - let(:password) { "pwd123Password!" } - let(:login) { "the_login" } + describe '.try_to_login' do + let(:password) { 'pwd123Password!' } + let(:login) { 'the_login' } let(:status) { described_class.statuses[:active] } let!(:user) do @@ -834,59 +834,59 @@ def build_user_double_with_expired_password(is_expired) status:) end - context "with good credentials" do - it "returns the user" do + context 'with good credentials' do + it 'returns the user' do expect(described_class.try_to_login(login, password)) .to eq user end end - context "with wrong password" do - it "returns the user" do + context 'with wrong password' do + it 'returns the user' do expect(described_class.try_to_login(login, "#{password}!")) .to be_nil end end - context "with wrong case in login" do - it "returns the user" do - expect(described_class.try_to_login("The_login", password)) + context 'with wrong case in login' do + it 'returns the user' do + expect(described_class.try_to_login('The_login', password)) .to eq user end end - context "with wrong characters in login" do - it "returns nil" do + context 'with wrong characters in login' do + it 'returns nil' do expect(described_class.try_to_login(login[0..-2], password)) .to be_nil end end - context "with the user being locked" do + context 'with the user being locked' do let(:status) { described_class.statuses[:locked] } - it "returns nil" do + it 'returns nil' do expect(described_class.try_to_login(login, "#{password}!")) .to be_nil end end - context "with the user's password being changed" do - let(:new_password) { "newPWD12%abc" } + context 'with the user\'s password being changed' do + let(:new_password) { 'newPWD12%abc' } before do user.password = new_password user.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.try_to_login(login, new_password)) .to eq user end end end - describe ".find_by_api_key" do + describe '.find_by_api_key' do let(:status) { described_class.statuses[:active] } let!(:user) do @@ -897,82 +897,82 @@ def build_user_double_with_expired_password(is_expired) create(:api_token, user:) end - context "if the right token is used" do - it "returns the user" do + context 'if the right token is used' do + it 'returns the user' do expect(described_class.find_by_api_key(token.plain_value)) .to eq user end end - context "if it isn't the right user" do - it "returns nil" do + context 'if it isn\'t the right user' do + it 'returns nil' do expect(described_class.find_by_api_key("#{token.value}abc")) .to be_nil end end - context "if the right token is used but the user is locked" do + context 'if the right token is used but the user is locked' do let(:status) { described_class.statuses[:locked] } - it "returns nil" do + it 'returns nil' do expect(described_class.find_by_api_key(token.plain_value)) .to be_nil end end end - describe ".find_by_mail" do - let(:mail) { "the@mail.org" } + describe '.find_by_mail' do + let(:mail) { 'the@mail.org' } let!(:user) { create(:user, mail:) } - context "with the exact mail" do - it "finds the user" do + context 'with the exact mail' do + it 'finds the user' do expect(described_class.find_by(mail:)) .to eq user end end - context "with the mail address in uppercase" do - it "finds the user" do + context 'with the mail address in uppercase' do + it 'finds the user' do expect(described_class.find_by_mail(mail.upcase)) .to eq user end end - context "with a different mail address" do - it "is nil" do + context 'with a different mail address' do + it 'is nil' do expect(described_class.find_by_mail(mail[1..-2])) .to be_nil end end - context "with a mail suffix in the address" do - let(:mail) { "the+other@mail.org" } + context 'with a mail suffix in the address' do + let(:mail) { 'the+other@mail.org' } - it "finds the user" do - expect(described_class.find_by_mail("the@mail.org")) + it 'finds the user' do + expect(described_class.find_by_mail('the@mail.org')) .to eq user end end end - describe ".anonymous" do - it "creates an anonymous user on the fly" do + describe '.anonymous' do + it 'creates an anonymous user on the fly' do expect(described_class.anonymous) .to be_a(AnonymousUser) end - it "creates a persisted record" do + it 'creates a persisted record' do expect(described_class.anonymous) .to be_persisted end end - include_examples "creates an audit trail on destroy" do + include_examples 'creates an audit trail on destroy' do subject { create(:attachment) } end - it_behaves_like "acts_as_customizable included" do + it_behaves_like 'acts_as_customizable included' do let(:model_instance) { user } let(:custom_field) { create(:user_custom_field, :string) } end diff --git a/spec/models/users/allowed_scope_spec.rb b/spec/models/users/allowed_scope_spec.rb index 4db28c624502..c9b880d3077d 100644 --- a/spec/models/users/allowed_scope_spec.rb +++ b/spec/models/users/allowed_scope_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe User, "allowed scope" do +RSpec.describe User, 'allowed scope' do let(:user) { member.principal } let(:anonymous) { build(:anonymous) } let(:project) { build(:project, public: false) } @@ -62,7 +62,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed(action, project).where(id: user.id)).to contain_exactly(user) end end @@ -75,7 +75,7 @@ user.update_attribute(:admin, true) end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed(action, project).where(id: user.id)).to contain_exactly(user) end end @@ -91,7 +91,7 @@ user.update_attribute(:admin, true) end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -105,7 +105,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -118,7 +118,7 @@ role.add_permission! action end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -135,7 +135,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -154,7 +154,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -172,7 +172,7 @@ project.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed(action, project).where(id: user.id)).to contain_exactly(user) end end @@ -190,7 +190,7 @@ project.save! end - it "returns the anonymous user" do + it 'returns the anonymous user' do expect(described_class.allowed(action, project).where(id: [user.id, anonymous.id])).to contain_exactly(anonymous) end end @@ -208,7 +208,7 @@ project.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -224,7 +224,7 @@ project.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -245,7 +245,7 @@ non_member.add_permission! action end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project).where(id: user.id)).to be_empty end end @@ -259,7 +259,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed(public_action, project).where(id: user.id)).to contain_exactly(user) end end @@ -274,7 +274,7 @@ project.save end - it "returns the user and anonymous" do + it 'returns the user and anonymous' do expect(described_class.allowed(public_action, project).where(id: [user.id, anonymous.id])).to contain_exactly(user, anonymous) end @@ -296,7 +296,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.allowed(permission.name, project).where(id: user.id)).to eq [] end end @@ -317,7 +317,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed(permission.name, project).where(id: user.id)).to eq [user] end end @@ -334,7 +334,7 @@ project.update(active: false) end - it "is empty" do + it 'is empty' do expect(described_class.allowed(action, project)).to eq [] end end @@ -349,7 +349,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed_members(action, project).where(id: user.id)).to contain_exactly(user) end end @@ -362,7 +362,7 @@ user.update_attribute(:admin, true) end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed_members(action, project).where(id: user.id)).to be_empty end end @@ -379,7 +379,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed_members(action, project).where(id: user.id)).to contain_exactly(user) end end @@ -394,12 +394,12 @@ role.add_permission! action end - it "returns the user" do + it 'returns the user' do expect(described_class.allowed_members(action, project).where(id: user.id)).to be_empty end end - describe ".allowed_members_on_work_package" do + describe '.allowed_members_on_work_package' do shared_let(:richard) { create(:user) } shared_let(:dinesh) { create(:user) } shared_let(:gilfoyle) { create(:user) } diff --git a/spec/models/users/allowed_to_spec.rb b/spec/models/users/allowed_to_spec.rb index 8380152d9c85..66fda8ea677f 100644 --- a/spec/models/users/allowed_to_spec.rb +++ b/spec/models/users/allowed_to_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe User, "allowed_to?" do +RSpec.describe User, 'allowed_to?' do let(:user) { build(:user) } let(:anonymous) { build(:anonymous) } let(:project) { build(:project, public: false) } @@ -51,7 +51,7 @@ user.save! end - shared_examples_for "when inquiring for project" do + shared_examples_for 'when inquiring for project' do let(:permission) { :add_work_packages } let(:final_setup_step) {} @@ -59,10 +59,10 @@ project.save end - context "with the user being admin" do + context 'with the user being admin' do before { user.update(admin: true) } - context "with the project being persisted and active" do + context 'with the project being persisted and active' do before do project.save @@ -72,7 +72,7 @@ it { expect(user).to be_allowed_to(permission, project) } end - context "with the project being archived" do + context 'with the project being archived' do before do project.update(active: false) @@ -82,11 +82,11 @@ it { expect(user).not_to be_allowed_to(permission, project) } end - context "with the required module being inactive" do + context 'with the required module being inactive' do let(:permission) { :create_meetings } # pick a permission from a module before do - project.enabled_module_names -= ["meetings"] + project.enabled_module_names -= ['meetings'] final_setup_step end @@ -94,7 +94,7 @@ it { expect(user).not_to be_allowed_to(permission, project) } end - context "with the permission not being automatically granted to admins" do + context 'with the permission not being automatically granted to admins' do let(:permission) { :work_package_assigned } # permission that is not automatically granted to admins before do @@ -105,17 +105,17 @@ end end - context "without the user being a member in the project" do - context "with the project being private" do + context 'without the user being a member in the project' do + context 'with the project being private' do before { project.update(public: false) } - context "with the user being a member of a single work package inside the project" do + context 'with the user being a member of a single work package inside the project' do before do work_package.save! wp_member.save! end - context "with the role granting the permission" do + context 'with the role granting the permission' do before do wp_role.add_permission!(permission) end @@ -124,7 +124,7 @@ end end - context "and the permission being assigend to the non-member role" do + context 'and the permission being assigend to the non-member role' do before do non_member = ProjectRole.non_member non_member.add_permission! permission @@ -138,10 +138,10 @@ end end - context "and the project being public" do + context 'and the project being public' do before { project.update(public: true) } - context "and the permission not being assigend to the non-member role" do + context 'and the permission not being assigend to the non-member role' do before do non_member = ProjectRole.non_member non_member.remove_permission! permission @@ -152,7 +152,7 @@ it { expect(user).not_to be_allowed_to(permission, project) } end - context "and the permission being assigned to the non-member role" do + context 'and the permission being assigned to the non-member role' do before do non_member = ProjectRole.non_member non_member.add_permission! permission @@ -167,67 +167,67 @@ end end - context "with the user being a member in the project" do + context 'with the user being a member in the project' do before { member.save! } - context "without the role granting the requested permission" do + context 'without the role granting the requested permission' do before do role.remove_permission!(permission) end - context "and no permissions being assigned to the non-member role" do + context 'and no permissions being assigned to the non-member role' do before { final_setup_step } it { expect(user).not_to be_allowed_to(permission, project) } end end - context "with the role granting the requested permission" do + context 'with the role granting the requested permission' do let(:permission) { :view_news } before do role.add_permission!(permission) end - context "with the module being active" do + context 'with the module being active' do before do - project.enabled_module_names += ["news"] + project.enabled_module_names += ['news'] final_setup_step end - context "and the permission being requested with the permission name" do + context 'and the permission being requested with the permission name' do it { expect(user).to be_allowed_to(permission, project) } end - context "and the permission being requested with the controller name and action" do - it { expect(user).to be_allowed_to({ controller: "news", action: "show" }, project) } + context 'and the permission being requested with the controller name and action' do + it { expect(user).to be_allowed_to({ controller: 'news', action: 'show' }, project) } end end - context "without the module being active" do + context 'without the module being active' do before do - project.enabled_module_names -= ["news"] + project.enabled_module_names -= ['news'] final_setup_step end - context "and the permission being requested with the permission name" do + context 'and the permission being requested with the permission name' do it { expect(user).not_to be_allowed_to(permission, project) } end - context "and the permission being requested with the controller name and action" do - it { expect(user).not_to be_allowed_to({ controller: "news", action: "show" }, project) } + context 'and the permission being requested with the controller name and action' do + it { expect(user).not_to be_allowed_to({ controller: 'news', action: 'show' }, project) } end end end end - context "with the user being anonymous" do - context "with the project being public" do + context 'with the user being anonymous' do + context 'with the project being public' do before { project.update(public: true) } - context "without the anonymous role being given the permission" do + context 'without the anonymous role being given the permission' do before do anonymous_role.remove_permission!(permission) final_setup_step @@ -236,7 +236,7 @@ it { expect(anonymous).not_to be_allowed_to(permission, project) } end - context "with the anonymous role being given the permission" do + context 'with the anonymous role being given the permission' do before do anonymous_role.add_permission!(permission) final_setup_step @@ -245,7 +245,7 @@ it { expect(anonymous).to be_allowed_to(permission, project) } end - context "with a controller and action that is allowed via multiple permissions" do + context 'with a controller and action that is allowed via multiple permissions' do let(:permission) { :manage_categories } before do @@ -253,19 +253,19 @@ final_setup_step end - it { expect(anonymous).to be_allowed_to({ controller: "/projects/settings/categories", action: "show" }, project) } + it { expect(anonymous).to be_allowed_to({ controller: '/projects/settings/categories', action: 'show' }, project) } end end end - context "when requesting permission for multiple projects" do - context "with the user being a member of multiple projects" do + context 'when requesting permission for multiple projects' do + context 'with the user being a member of multiple projects' do before do member.save member2.save end - context "with the permission being granted in both projects" do + context 'with the permission being granted in both projects' do before do role.add_permission! permission role2.add_permission! permission @@ -277,7 +277,7 @@ end end - context "with the permission being granted in only one of the two projects" do + context 'with the permission being granted in only one of the two projects' do before do role.add_permission! permission role2.remove_permission! permission @@ -288,13 +288,13 @@ it { expect(user).not_to be_allowed_to(permission, [project, project2]) } end - context "with the user not being member of any projects, but both projects being public" do + context 'with the user not being member of any projects, but both projects being public' do before do project.update(public: true) project2.update(public: true) end - context "with non-member role having the permission" do + context 'with non-member role having the permission' do before do non_member = ProjectRole.non_member non_member.add_permission! permission @@ -304,7 +304,7 @@ it { expect(user).to be_allowed_to(permission, [project, project2]) } end - context "without non-member role having the permission" do + context 'without non-member role having the permission' do before do non_member = ProjectRole.non_member non_member.remove_permission! permission @@ -315,13 +315,13 @@ end end - context "with the user not being member of any projects, but one of the projects being public" do + context 'with the user not being member of any projects, but one of the projects being public' do before do project.update(public: true) project2.update(public: false) end - context "with non-member role having the permission" do + context 'with non-member role having the permission' do before do non_member = ProjectRole.non_member non_member.add_permission! permission @@ -333,27 +333,27 @@ end end - context "when requesting a global permission, but with the project as a context" do + context 'when requesting a global permission, but with the project as a context' do before do global_member.save! end - it "is false" do + it 'is false' do expect(user).not_to be_allowed_to(global_permission.name, project) end end end - shared_examples_for "when inquiring globally" do + shared_examples_for 'when inquiring globally' do let(:permission) { :add_work_packages } - context "when the user is an admin" do + context 'when the user is an admin' do before { user.update(admin: true) } it { expect(user).to be_allowed_to(permission, nil, global: true) } end - context "when the non-member role has the permission" do + context 'when the non-member role has the permission' do before do ProjectRole.non_member.add_permission! permission end @@ -361,21 +361,21 @@ it { expect(user).to be_allowed_to(permission, nil, global: true) } end - context "when there is a global role giving the permission" do + context 'when there is a global role giving the permission' do before { global_role.save! } - context "without the user having the role assigned" do + context 'without the user having the role assigned' do it { expect(user).not_to be_allowed_to(global_permission.name, nil, global: true) } end - context "with the user having the role assigned" do + context 'with the user having the role assigned' do before { global_member.save! } - context "with the role having the global permission" do + context 'with the role having the global permission' do it { expect(user).to be_allowed_to(global_permission.name, nil, global: true) } end - context "without the role having the global permission" do + context 'without the role having the global permission' do before do global_role.remove_permission!(global_permission.name) end @@ -385,16 +385,16 @@ end end - context "when the user is member of a project" do + context 'when the user is member of a project' do before { member.save } - context "and a project permission is requested globally" do - context "without the permission being assigned to the role" do + context 'and a project permission is requested globally' do + context 'without the permission being assigned to the role' do it { expect(user).not_to be_allowed_to(permission, nil, global: true) } end # TODO: Ask somebody why this is supposed to work!? - context "with the permissio being assigned to the role" do + context 'with the permissio being assigned to the role' do before do role.add_permission! permission end @@ -403,33 +403,33 @@ end end - context "when requesting a controller and action allowed by multiple permissions" do + context 'when requesting a controller and action allowed by multiple permissions' do let(:permission) { :manage_categories } - context "without the role having the permission" do + context 'without the role having the permission' do before { role.remove_permission!(permission) } it do expect(user) - .not_to be_allowed_to({ controller: "/projects/settings/categories", action: "show" }, nil, global: true) + .not_to be_allowed_to({ controller: '/projects/settings/categories', action: 'show' }, nil, global: true) end - context "with the non-member having the permission" do + context 'with the non-member having the permission' do before do ProjectRole.non_member.add_permission! permission end it do expect(user) - .to be_allowed_to({ controller: "/projects/settings/categories", action: "show" }, nil, global: true) + .to be_allowed_to({ controller: '/projects/settings/categories', action: 'show' }, nil, global: true) end end end end end - context "when the user is anonymous" do - context "with the anonymous role having the permission allowed" do + context 'when the user is anonymous' do + context 'with the anonymous role having the permission allowed' do before do anonymous_role.add_permission! permission end @@ -437,25 +437,25 @@ it { expect(anonymous).to be_allowed_to(permission, nil, global: true) } end - context "without the anonymous role having the permission allowed" do + context 'without the anonymous role having the permission allowed' do it { expect(anonymous).not_to be_allowed_to(permission, nil, global: true) } end end end - shared_examples_for "when inquiring for work_package" do + shared_examples_for 'when inquiring for work_package' do let(:permission) { :view_work_packages } before do project.save! work_package.save! end - context "with the user being a member of the work package" do + context 'with the user being a member of the work package' do before do wp_member.save! end - context "with the role granting the permission" do + context 'with the role granting the permission' do before do wp_role.add_permission!(permission) end @@ -463,10 +463,10 @@ it { expect(user).to be_allowed_to(permission, work_package) } end - context "without the role granting the permission" do + context 'without the role granting the permission' do it { expect(user).not_to be_allowed_to(permission, work_package) } - context "with a membership on the project granting the permission" do + context 'with a membership on the project granting the permission' do before do role.save! member.save! @@ -478,17 +478,17 @@ end end - context "without the user being a member of the work package" do - context "with the user being a member of the project the work package belongs to" do + context 'without the user being a member of the work package' do + context 'with the user being a member of the project the work package belongs to' do before do member.save! end - context "and the project role does not grant the permission" do + context 'and the project role does not grant the permission' do it { expect(user).not_to be_allowed_to(permission, work_package) } end - context "and the project role grants the permission" do + context 'and the project role grants the permission' do before do role.add_permission!(permission) end @@ -497,7 +497,7 @@ end end - context "with the user being a member of another project where the role grants the permission" do + context 'with the user being a member of another project where the role grants the permission' do before do role.save! member2.save! @@ -509,14 +509,14 @@ end end - context "without preloaded permissions" do - it_behaves_like "when inquiring for project" - it_behaves_like "when inquiring globally" - it_behaves_like "when inquiring for work_package" + context 'without preloaded permissions' do + it_behaves_like 'when inquiring for project' + it_behaves_like 'when inquiring globally' + it_behaves_like 'when inquiring for work_package' end - context "with preloaded permissions" do - it_behaves_like "when inquiring for project" do + context 'with preloaded permissions' do + it_behaves_like 'when inquiring for project' do let(:final_setup_step) do user.preload_projects_allowed_to(permission) end diff --git a/spec/models/users/permission_checks_spec.rb b/spec/models/users/permission_checks_spec.rb index 3aac7e74e61a..c22649f106a7 100644 --- a/spec/models/users/permission_checks_spec.rb +++ b/spec/models/users/permission_checks_spec.rb @@ -33,8 +33,8 @@ let(:project) { build_stubbed(:project) } - describe ".allowed" do - it "calls the Authorization.users method" do + describe '.allowed' do + it 'calls the Authorization.users method' do expect(Authorization).to receive(:users).with(:view_work_packages, project) described_class.allowed(:view_work_packages, project) end @@ -58,110 +58,110 @@ end end - describe "#allowed_based_on_permission_context?" do + describe '#allowed_based_on_permission_context?' do let(:project) { nil } let(:entity) { nil } let(:result) { subject.allowed_based_on_permission_context?(permission, project:, entity:) } let(:permission_object) { OpenProject::AccessControl.permission(permission) } - context "with a global permission" do + context 'with a global permission' do let(:permission) { :create_user } - it "uses the #allowed_globally? method" do + it 'uses the #allowed_globally? method' do expect(subject).to receive(:allowed_globally?).with(permission_object) result end end - context "with a project permission" do + context 'with a project permission' do let(:permission) { :manage_members } - context "without a project or entity" do + context 'without a project or entity' do let(:entity) { nil } let(:project) { nil } - it "uses the #allowed_in_any_project? method" do + it 'uses the #allowed_in_any_project? method' do expect(subject).to receive(:allowed_in_any_project?).with(permission_object) result end end - context "with a project" do + context 'with a project' do let(:project) { build_stubbed(:project) } - it "uses the #allowed_in_project? method" do + it 'uses the #allowed_in_project? method' do expect(subject).to receive(:allowed_in_project?).with(permission_object, project) result end end - context "with an entity that responds to #project" do + context 'with an entity that responds to #project' do let(:permission) { :manage_members } let(:entity) { build_stubbed(:meeting) } - it "uses the #allowed_in_project? method" do + it 'uses the #allowed_in_project? method' do expect(subject).to receive(:allowed_in_project?).with(permission_object, entity.project) result end - context "with the project being nil" do + context 'with the project being nil' do let(:entity) { build_stubbed(:meeting, project: nil) } - it "uses the #allowed_in_any_project? method" do + it 'uses the #allowed_in_any_project? method' do expect(subject).to receive(:allowed_in_any_project?).with(permission_object) result end end end - context "and an entity that does not respond to #project" do + context 'and an entity that does not respond to #project' do let(:entity) { build_stubbed(:user) } - it "uses the #allowed_in_any_project? method" do + it 'uses the #allowed_in_any_project? method' do expect(subject).to receive(:allowed_in_any_project?).with(permission_object) result end end end - context "with a work package (and a project) permission" do + context 'with a work package (and a project) permission' do let(:permission) { :log_own_time } - context "with a work package as the entity" do + context 'with a work package as the entity' do let(:entity) { build_stubbed(:work_package) } - it "uses the #allowed_in_work_package? method" do + it 'uses the #allowed_in_work_package? method' do expect(subject).to receive(:allowed_in_work_package?).with(permission_object, entity) result end end - context "with a not-persisted work package as the entity" do - context "with a project" do + context 'with a not-persisted work package as the entity' do + context 'with a project' do let(:entity) { build(:work_package) } - it "uses the #allowed_in_any_work_package? method with in_project: param" do + it 'uses the #allowed_in_any_work_package? method with in_project: param' do expect(subject).to receive(:allowed_in_any_work_package?).with(permission_object, in_project: entity.project) result end end end - context "with a project and no entity" do + context 'with a project and no entity' do let(:project) { build_stubbed(:project) } - it "uses the #allowed_in_any_work_package? method with in_project: param" do + it 'uses the #allowed_in_any_work_package? method with in_project: param' do expect(subject).to receive(:allowed_in_any_work_package?).with(permission_object, in_project: project) result end end - context "with a work package and a project" do + context 'with a work package and a project' do let(:permission) { :log_own_time } let(:entity) { build_stubbed(:work_package) } let(:project) { build_stubbed(:project) } - it "uses the #allowed_in_work_package? method" do + it 'uses the #allowed_in_work_package? method' do expect(subject).to receive(:allowed_in_work_package?).with(permission_object, entity) result end @@ -169,7 +169,7 @@ end end - describe "#all_permissions_for" do + describe '#all_permissions_for' do let(:project) { create(:project) } let!(:other_project) { create(:project, public: true) } @@ -182,67 +182,67 @@ member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) end - it "returns all permissions given on the project" do + it 'returns all permissions given on the project' do expect(subject.all_permissions_for(project)).to match_array(%i[view_work_packages edit_work_packages] + public_permissions) end - it "returns non-member permissions given on the project the user is not a member of" do + it 'returns non-member permissions given on the project the user is not a member of' do expect(subject.all_permissions_for(other_project)).to match_array(%i[view_work_packages manage_members] + public_permissions) end - it "returns all global permissions" do - skip "Current implementation of the Authorization.roles query returns ALL permissions the user has, not only global ones. " \ - "We should change this in the fututre, thats why this test is already in here." + it 'returns all global permissions' do + skip 'Current implementation of the Authorization.roles query returns ALL permissions the user has, not only global ones. ' \ + 'We should change this in the fututre, thats why this test is already in here.' expect(subject.all_permissions_for(nil)).to match_array(%i[create_user]) end - it "returns all permissions the user has (with project and global permissions)" do + it 'returns all permissions the user has (with project and global permissions)' do expect(subject.all_permissions_for(nil)).to match_array(%i[create_user view_work_packages edit_work_packages manage_members] + public_permissions) end end - describe "#access_to?" do + describe '#access_to?' do let(:project) { create(:project) } let(:another_project) { create(:project) } - context "when the user is a member of the project" do + context 'when the user is a member of the project' do subject { create(:user, member_with_permissions: { project => [:view_project] }) } - it "returns true" do + it 'returns true' do expect(subject.access_to?(project)).to be true end - it "returns false for another project" do + it 'returns false for another project' do expect(subject.access_to?(another_project)).to be false end end - context "when the user is not a member of the project" do + context 'when the user is not a member of the project' do subject { create(:user, member_with_permissions: { another_project => [:view_work_packages] }) } - it "returns false" do + it 'returns false' do expect(subject.access_to?(project)).to be false end end - context "when the user is member of a work package within the project" do + context 'when the user is member of a work package within the project' do let(:work_package) { create(:work_package, project:) } subject { create(:user, member_with_permissions: { work_package => [:view_work_packages] }) } - it "returns false" do + it 'returns false' do expect(subject.access_to?(project)).to be true end end - context "when the user is an admin" do + context 'when the user is an admin' do subject { create(:admin) } - it "returns true" do + it 'returns true' do expect(subject.access_to?(project)).to be true end end diff --git a/spec/models/users/scopes/find_by_login_spec.rb b/spec/models/users/scopes/find_by_login_spec.rb index 2cc38f414711..2d9b6fd7f144 100644 --- a/spec/models/users/scopes/find_by_login_spec.rb +++ b/spec/models/users/scopes/find_by_login_spec.rb @@ -26,38 +26,38 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::Scopes::FindByLogin do let!(:activity) { create(:time_entry_activity) } let!(:project) { create(:project) } let!(:user) { create(:user, login:) } - let(:login) { "Some string" } + let(:login) { 'Some string' } let(:search_login) { login } - describe ".find_by_login" do + describe '.find_by_login' do subject { User.find_by_login(search_login) } - context "with the exact same login" do - it "returns the user" do + context 'with the exact same login' do + it 'returns the user' do expect(subject) .to eql user end end - context "with a non existing login" do - let(:search_login) { "nothing" } + context 'with a non existing login' do + let(:search_login) { 'nothing' } - it "returns nil" do + it 'returns nil' do expect(subject) .to be_nil end end - context "with a lowercase login" do + context 'with a lowercase login' do let(:search_login) { login.downcase } - it "returns the user with the matching login" do + it 'returns the user with the matching login' do expect(subject) .to eql user end diff --git a/spec/models/users/scopes/having_reminder_mail_to_send_spec.rb b/spec/models/users/scopes/having_reminder_mail_to_send_spec.rb index 6f183e42e406..e4719942d378 100644 --- a/spec/models/users/scopes/having_reminder_mail_to_send_spec.rb +++ b/spec/models/users/scopes/having_reminder_mail_to_send_spec.rb @@ -26,9 +26,9 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe User, ".having_reminder_mail_to_send" do +RSpec.describe User, '.having_reminder_mail_to_send' do subject(:scope) do described_class.having_reminder_mail_to_send(scope_time) end @@ -48,7 +48,7 @@ let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: { time_zone: "Europe/Paris", workdays: paris_user_workdays, @@ -77,84 +77,84 @@ users end - context "for a user whose local time is matching the configured time" do - it "contains the user" do + context 'for a user whose local time is matching the configured time' do + it 'contains the user' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user whose local time is matching but the workday is disabled" do + context 'for a user whose local time is matching but the workday is disabled' do # Configured date is a thursday = 4 let(:paris_user_workdays) { [1, 2] } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching but the reminders are paused" do + context 'for a user whose local time is matching but the reminders are paused' do let(:paris_user_pause_reminders) do { enabled: true, - first_day: "2021-09-20", - last_day: "2021-10-05" + first_day: '2021-09-20', + last_day: '2021-10-05' } end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching but the reminders are paused until today" do + context 'for a user whose local time is matching but the reminders are paused until today' do let(:paris_user_pause_reminders) do { enabled: true, - first_day: "2021-09-10", - last_day: "2021-09-30" + first_day: '2021-09-10', + last_day: '2021-09-30' } end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching and the pause reminders is expired" do + context 'for a user whose local time is matching and the pause reminders is expired' do let(:paris_user_pause_reminders) do { enabled: true, - first_day: "2021-09-10", - last_day: "2021-09-29" + first_day: '2021-09-10', + last_day: '2021-09-29' } end - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user whose local time is not matching the configured time" do + context 'for a user whose local time is not matching the configured time' do let(:current_time) { "2021-09-30T08:20:59Z".to_datetime } let(:scope_time) { "2021-09-30T08:15:00Z".to_datetime } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is on the previous workday" do + context 'for a user whose local time is on the previous workday' do # 8:00 thursday Etc/UTC = 22:00 wednesday Pacific/Honolulu let(:hawaii_user) do create( :user, - firstname: "Pacific-Honolulu", + firstname: 'Pacific-Honolulu', preferences: { time_zone: "Pacific/Honolulu", workdays: hawaii_user_workdays, @@ -177,52 +177,52 @@ let(:users) { [hawaii_user] } let(:hawaii_user_workdays) { paris_user_workdays } - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(hawaii_user) end - context "when the user disables Wednesday as a workday" do + context 'when the user disables Wednesday as a workday' do let(:hawaii_user_workdays) { [1, 2, 4, 5, 6, 7] } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "with local date range for pausing that includes scope_time" do + context 'with local date range for pausing that includes scope_time' do let(:hawaii_user_pause_reminders) do { enabled: true, - first_day: "2021-09-29", - last_day: "2021-09-29" + first_day: '2021-09-29', + last_day: '2021-09-29' } end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "with local date range for pausing that excludes scope_time" do + context 'with local date range for pausing that excludes scope_time' do let(:hawaii_user_pause_reminders) do { enabled: true, - first_day: "2021-09-30", - last_day: "2021-09-30" + first_day: '2021-09-30', + last_day: '2021-09-30' } end - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(hawaii_user) end end end - context "for a user whose local time is on the next workday" do + context 'for a user whose local time is on the next workday' do # 12:00 thursday Etc/UTC = 03:00 friday @ Pacific/Apia let(:current_time) { "2021-09-30T12:05:59Z".to_datetime } let(:scope_time) { "2021-09-30T12:00:00Z".to_datetime } @@ -230,7 +230,7 @@ let(:samoa_user) do create( :user, - firstname: "Pacific-Apia", + firstname: 'Pacific-Apia', preferences: { time_zone: "Pacific/Apia", workdays: samoa_user_workdays, @@ -247,26 +247,26 @@ let(:users) { [samoa_user] } let(:samoa_user_workdays) { paris_user_workdays } - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(samoa_user) end - context "when the user disables Wednesday as a workday" do + context 'when the user disables Wednesday as a workday' do let(:samoa_user_workdays) { [1, 2, 3, 4, 6, 7] } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end end - context "for a user whose local time is matching the configured time (in a non CET time zone)" do + context 'for a user whose local time is matching the configured time (in a non CET time zone)' do let(:moscow_user) do create( :user, - firstname: "Europe-Moscow", + firstname: 'Europe-Moscow', preferences: { time_zone: "Europe/Moscow", daily_reminders: { @@ -281,13 +281,13 @@ end let(:users) { [moscow_user] } - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(moscow_user) end end - context "for a user whose local time is matching one of the configured times" do + context 'for a user whose local time is matching one of the configured times' do let(:paris_user_daily_reminders) do { enabled: true, @@ -299,13 +299,13 @@ } end - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user who has configured a slot between the earliest_time (in local time) and his current local time" do + context 'for a user who has configured a slot between the earliest_time (in local time) and his current local time' do let(:paris_user_daily_reminders) do { enabled: true, @@ -315,15 +315,15 @@ ] } end - let(:scope_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("06:00") } + let(:scope_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("06:00") } - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user who has configured a slot before the earliest_time (in local time) and after his current local time" do + context 'for a user who has configured a slot before the earliest_time (in local time) and after his current local time' do let(:paris_user_daily_reminders) do { enabled: true, @@ -335,24 +335,24 @@ end let(:scope_time) { current_time - 2.hours } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching the configured time but without a notification" do + context 'for a user whose local time is matching the configured time but without a notification' do let(:notifications) do nil end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching the configured time but with the reminder being deactivated" do + context 'for a user whose local time is matching the configured time but with the reminder being deactivated' do let(:paris_user_daily_reminders) do { enabled: false, @@ -360,55 +360,55 @@ } end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching the configured time but without a daily_reminders setting at 8:00" do + context 'for a user whose local time is matching the configured time but without a daily_reminders setting at 8:00' do let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: { time_zone: "Europe/Paris" } ) end - let(:current_time) { ActiveSupport::TimeZone["Europe/Paris"].parse("2021-09-30T08:09").utc } - let(:scope_time) { ActiveSupport::TimeZone["Europe/Paris"].parse("2021-09-30T08:00") } + let(:current_time) { ActiveSupport::TimeZone['Europe/Paris'].parse("2021-09-30T08:09").utc } + let(:scope_time) { ActiveSupport::TimeZone['Europe/Paris'].parse("2021-09-30T08:00") } - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user whose local time is matching the configured time but without a daily_reminders setting at 10:00" do + context 'for a user whose local time is matching the configured time but without a daily_reminders setting at 10:00' do let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: { time_zone: "Europe/Paris" } ) end - let(:current_time) { ActiveSupport::TimeZone["Europe/Paris"].parse("2021-09-30T10:00").utc } - let(:scope_time) { ActiveSupport::TimeZone["Europe/Paris"].parse("2021-09-30T10:00") } + let(:current_time) { ActiveSupport::TimeZone['Europe/Paris'].parse("2021-09-30T10:00").utc } + let(:scope_time) { ActiveSupport::TimeZone['Europe/Paris'].parse("2021-09-30T10:00") } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user who is in a 45 min time zone and having reminder set to 8:00 and being executed at 8:10" do + context 'for a user who is in a 45 min time zone and having reminder set to 8:00 and being executed at 8:10' do let(:kathmandu_user) do create( :user, - firstname: "Asia-Kathmandu", + firstname: 'Asia-Kathmandu', preferences: { time_zone: "Asia/Kathmandu", daily_reminders: { @@ -418,25 +418,25 @@ } ) end - let(:current_time) { ActiveSupport::TimeZone["Asia/Kathmandu"].parse("2021-09-30T08:10").utc } - let(:scope_time) { ActiveSupport::TimeZone["Asia/Kathmandu"].parse("2021-09-30T08:00").utc } + let(:current_time) { ActiveSupport::TimeZone['Asia/Kathmandu'].parse("2021-09-30T08:10").utc } + let(:scope_time) { ActiveSupport::TimeZone['Asia/Kathmandu'].parse("2021-09-30T08:00").utc } let(:notifications) do create(:notification, recipient: kathmandu_user, created_at: 5.minutes.ago) end let(:users) { [kathmandu_user] } - it "contains the user" do + it 'contains the user' do expect(scope) .to contain_exactly(kathmandu_user) end end - context "for a user who is in a 45 min time zone and having reminder set to 8:00 and being executed at 8:40" do + context 'for a user who is in a 45 min time zone and having reminder set to 8:00 and being executed at 8:40' do let(:kathmandu_user) do create( :user, - firstname: "Asia-Kathmandu", + firstname: 'Asia-Kathmandu', preferences: { time_zone: "Asia/Kathmandu", daily_reminders: { @@ -446,25 +446,25 @@ } ) end - let(:current_time) { ActiveSupport::TimeZone["Asia/Kathmandu"].parse("2021-09-30T08:40").utc } - let(:scope_time) { ActiveSupport::TimeZone["Asia/Kathmandu"].parse("2021-09-30T08:30").utc } + let(:current_time) { ActiveSupport::TimeZone['Asia/Kathmandu'].parse("2021-09-30T08:40").utc } + let(:scope_time) { ActiveSupport::TimeZone['Asia/Kathmandu'].parse("2021-09-30T08:30").utc } let(:notifications) do create(:notification, recipient: kathmandu_user, created_at: 5.minutes.ago) end let(:users) { [kathmandu_user] } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user who is in a 45 min time zone and having reminder set to 8:00 and being executed at 7:55" do + context 'for a user who is in a 45 min time zone and having reminder set to 8:00 and being executed at 7:55' do let(:kathmandu_user) do create( :user, - firstname: "Asia-Kathmandu", + firstname: 'Asia-Kathmandu', preferences: { time_zone: "Asia/Kathmandu", daily_reminders: { @@ -474,43 +474,43 @@ } ) end - let(:current_time) { ActiveSupport::TimeZone["Asia/Kathmandu"].parse("2021-09-30T07:55").utc } - let(:scope_time) { ActiveSupport::TimeZone["Asia/Kathmandu"].parse("2021-09-30T07:45").utc } + let(:current_time) { ActiveSupport::TimeZone['Asia/Kathmandu'].parse("2021-09-30T07:55").utc } + let(:scope_time) { ActiveSupport::TimeZone['Asia/Kathmandu'].parse("2021-09-30T07:45").utc } let(:notifications) do create(:notification, recipient: kathmandu_user, created_at: 5.minutes.ago) end let(:users) { [kathmandu_user] } - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching the configured time but with an already read notification (IAN)" do + context 'for a user whose local time is matching the configured time but with an already read notification (IAN)' do let(:notifications) do create(:notification, recipient: paris_user, created_at: 5.minutes.ago, read_ian: true) end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching the configured time but with an already read notification (reminder)" do + context 'for a user whose local time is matching the configured time but with an already read notification (reminder)' do let(:notifications) do create(:notification, recipient: paris_user, created_at: 5.minutes.ago, mail_reminder_sent: true) end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is matching the configured time but with the user being inactive" do + context 'for a user whose local time is matching the configured time but with the user being inactive' do let(:notifications) do create(:notification, recipient: paris_user, created_at: 5.minutes.ago) end @@ -519,13 +519,13 @@ paris_user.locked! end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is before the configured time" do + context 'for a user whose local time is before the configured time' do let(:paris_user_daily_reminders) do { enabled: true, @@ -533,13 +533,13 @@ } end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user whose local time is after the configured time" do + context 'for a user whose local time is after the configured time' do let(:paris_user_daily_reminders) do { enabled: true, @@ -547,17 +547,17 @@ } end - it "is empty" do + it 'is empty' do expect(scope) .to be_empty end end - context "for a user without a time zone" do + context 'for a user without a time zone' do let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: { daily_reminders: { enabled: true, @@ -567,19 +567,19 @@ ) end - it "is including the user as Etc/UTC is assumed" do + it 'is including the user as Etc/UTC is assumed' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user without a blank time zone" do + context 'for a user without a blank time zone' do let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: { - time_zone: "", + time_zone: '', daily_reminders: { enabled: true, times: [hitting_reminder_slot_for("Etc/UTC", current_time)] @@ -588,51 +588,51 @@ ) end - it "is including the user as Etc/UTC is assumed" do + it 'is including the user as Etc/UTC is assumed' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user without a time zone and daily_reminders at 08:00" do + context 'for a user without a time zone and daily_reminders at 08:00' do let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: {} ) end - let(:current_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T08:00").utc } + let(:current_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T08:00").utc } - it "is including the user as Etc/UTC at 08:00 is assumed" do + it 'is including the user as Etc/UTC at 08:00 is assumed' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user without a time zone and daily_reminders at 10:00" do + context 'for a user without a time zone and daily_reminders at 10:00' do let(:paris_user) do create( :user, - firstname: "Europe-Paris", + firstname: 'Europe-Paris', preferences: {} ) end - let(:current_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T10:00").utc } - let(:scope_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T10:00").utc } + let(:current_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T10:00").utc } + let(:scope_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T10:00").utc } - it "is empty as Etc/UTC at 08:00 is assumed" do + it 'is empty as Etc/UTC at 08:00 is assumed' do expect(scope) .to be_empty end end - context "for a user without a time zone and a default time zone configured", - with_settings: { user_default_timezone: "Europe/Moscow" } do + context 'for a user without a time zone and a default time zone configured', + with_settings: { user_default_timezone: 'Europe/Moscow' } do let(:moscow_user) do create( :user, - firstname: "Europe-Moscow", + firstname: 'Europe-Moscow', preferences: { daily_reminders: { enabled: true, @@ -646,44 +646,44 @@ end let(:users) { [moscow_user] } - it "is including the configured default timezone is assumed" do + it 'is including the configured default timezone is assumed' do expect(scope) .to contain_exactly(moscow_user) end end - context "when the provided scope_time is after the current time" do + context 'when the provided scope_time is after the current time' do let(:scope_time) { 1.minute.from_now } - it "raises an error" do + it 'raises an error' do expect { scope } .to raise_error ArgumentError end end - context "for a user without preferences at 08:00" do - let(:current_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T08:00").utc } - let(:scope_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T08:00").utc } + context 'for a user without preferences at 08:00' do + let(:current_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T08:00").utc } + let(:scope_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T08:00").utc } before do paris_user.pref.destroy end - it "is including the user as Etc/UTC at 08:00 is assumed" do + it 'is including the user as Etc/UTC at 08:00 is assumed' do expect(scope) .to contain_exactly(paris_user) end end - context "for a user without preferences at 10:00" do - let(:current_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T10:00").utc } - let(:scope_time) { ActiveSupport::TimeZone["Etc/UTC"].parse("2021-09-30T10:00").utc } + context 'for a user without preferences at 10:00' do + let(:current_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T10:00").utc } + let(:scope_time) { ActiveSupport::TimeZone['Etc/UTC'].parse("2021-09-30T10:00").utc } before do paris_user.pref.destroy end - it "is empty as Etc/UTC at 08:00 is assumed" do + it 'is empty as Etc/UTC at 08:00 is assumed' do expect(scope) .to be_empty end diff --git a/spec/models/users/scopes/newest_spec.rb b/spec/models/users/scopes/newest_spec.rb index e0f2ca045478..42a331466f51 100644 --- a/spec/models/users/scopes/newest_spec.rb +++ b/spec/models/users/scopes/newest_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::Scopes::Newest do - describe ".newest" do + describe '.newest' do let!(:anonymous_user) { create(:anonymous) } let!(:system_user) { create(:system) } let!(:deleted_user) { create(:deleted_user) } @@ -41,7 +41,7 @@ subject { User.newest } - it "returns only actual users ordered by creation date desc" do + it 'returns only actual users ordered by creation date desc' do expect(subject.to_a) .to eql [user3, user2, user1] end diff --git a/spec/models/users/scopes/with_time_zone_spec.rb b/spec/models/users/scopes/with_time_zone_spec.rb index 3bcb7b12ab66..ad0b95419eed 100644 --- a/spec/models/users/scopes/with_time_zone_spec.rb +++ b/spec/models/users/scopes/with_time_zone_spec.rb @@ -26,97 +26,97 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::Scopes::WithTimeZone do shared_let(:user_besancon) do create( :user, - firstname: "Besançon", - preferences: { time_zone: "Europe/Paris" } + firstname: 'Besançon', + preferences: { time_zone: 'Europe/Paris' } ) end shared_let(:user_kathmandu) do create( :user, - firstname: "Kathmandu", - preferences: { time_zone: "Asia/Kathmandu" } + firstname: 'Kathmandu', + preferences: { time_zone: 'Asia/Kathmandu' } ) end shared_let(:user_new_york) do create( :user, - firstname: "New York", - preferences: { time_zone: "America/New_York" } + firstname: 'New York', + preferences: { time_zone: 'America/New_York' } ) end shared_let(:user_paris) do create( :user, - firstname: "Paris", - preferences: { time_zone: "Europe/Paris" } + firstname: 'Paris', + preferences: { time_zone: 'Europe/Paris' } ) end shared_let(:user_without_preferences) do create( :user, - firstname: "no preference", + firstname: 'no preference', preferences: nil ) end shared_let(:user_without_time_zone) do create( :user, - firstname: "no preference", + firstname: 'no preference', preferences: {} ) end shared_let(:user_with_empty_time_zone) do create( :user, - firstname: "no preference", - preferences: { time_zone: "" } + firstname: 'no preference', + preferences: { time_zone: '' } ) end - describe ".with_time_zone" do - it "returns user having set a time zone in their preference matching the specified time zone(s)" do - expect(User.with_time_zone("Europe/Paris")) + describe '.with_time_zone' do + it 'returns user having set a time zone in their preference matching the specified time zone(s)' do + expect(User.with_time_zone('Europe/Paris')) .to contain_exactly(user_paris, user_besancon) expect(User.with_time_zone([])) .to eq([]) - expect(User.with_time_zone(["America/New_York", "Asia/Kathmandu"])) + expect(User.with_time_zone(['America/New_York', 'Asia/Kathmandu'])) .to contain_exactly(user_new_york, user_kathmandu) end - context "when users have no preferences" do - it "uses the default time zone returned by Setting.user_default_timezone", + context 'when users have no preferences' do + it 'uses the default time zone returned by Setting.user_default_timezone', with_settings: { user_default_timezone: "Europe/Berlin" } do expect(User.with_time_zone("Europe/Berlin")) .to include(user_without_preferences) end end - context "when users have preferences without time zone set" do - it "uses the default time zone returned by Setting.user_default_timezone", + context 'when users have preferences without time zone set' do + it 'uses the default time zone returned by Setting.user_default_timezone', with_settings: { user_default_timezone: "Europe/Berlin" } do expect(User.with_time_zone("Europe/Berlin")) .to include(user_without_time_zone) end end - context "when users have preferences with time zone set to empty string" do - it "uses the default time zone returned by Setting.user_default_timezone", + context 'when users have preferences with time zone set to empty string' do + it 'uses the default time zone returned by Setting.user_default_timezone', with_settings: { user_default_timezone: "Europe/Berlin" } do expect(User.with_time_zone("Europe/Berlin")) .to include(user_with_empty_time_zone) end end - context "when users have no time zone and default user time zone is not set" do - it "assumes Etc/UTC as default time zone", + context 'when users have no time zone and default user time zone is not set' do + it 'assumes Etc/UTC as default time zone', with_settings: { user_default_timezone: nil } do expect(User.with_time_zone("Etc/UTC")) .to contain_exactly(user_without_preferences, user_without_time_zone, user_with_empty_time_zone) diff --git a/spec/models/versions/scopes/order_by_semver_name_spec.rb b/spec/models/versions/scopes/order_by_semver_name_spec.rb index 2e330d0c86a4..5d42101e3986 100644 --- a/spec/models/versions/scopes/order_by_semver_name_spec.rb +++ b/spec/models/versions/scopes/order_by_semver_name_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Versions::Scopes::OrderBySemverName do let(:project) { create(:project) } @@ -26,7 +26,7 @@ subject { Version.order_by_semver_name } - it "returns the versions in semver order" do + it 'returns the versions in semver order' do expect(subject.to_a) .to eql [version6, version7, version4, version5, version3, version2, version1] end diff --git a/spec/models/versions/scopes/rolled_up_spec.rb b/spec/models/versions/scopes/rolled_up_spec.rb index cd6208f7dd3a..01c9b0b6161b 100644 --- a/spec/models/versions/scopes/rolled_up_spec.rb +++ b/spec/models/versions/scopes/rolled_up_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Versions::Scopes::RolledUp do shared_let(:parent_project) { create(:project) } @@ -40,13 +40,13 @@ shared_let(:parent_version) { create(:version, project: parent_project) } shared_let(:sibling_version) { create(:version, project: sibling_project) } - describe ".rolled_up" do - it "includes versions of self and all descendants" do + describe '.rolled_up' do + it 'includes versions of self and all descendants' do expect(project.rolled_up_versions) .to contain_exactly(version, child_version, grand_child_version) end - it "excludes versions from inactive projects" do + it 'excludes versions from inactive projects' do grand_child_project.update(active: false) expect(project.rolled_up_versions) diff --git a/spec/models/versions/scopes/shared_with_spec.rb b/spec/models/versions/scopes/shared_with_spec.rb index a47eda622080..8ba486266d12 100644 --- a/spec/models/versions/scopes/shared_with_spec.rb +++ b/spec/models/versions/scopes/shared_with_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Versions::Scopes::SharedWith do shared_let(:root_project) { create(:project) } @@ -38,16 +38,16 @@ shared_let(:child_project) { create(:project, parent: project) } shared_let(:grand_child_project) { create(:project, parent: child_project) } - describe ".shared_with" do - context "with the version not being shared" do - let!(:version) { create(:version, project:, sharing: "none") } + describe '.shared_with' do + context 'with the version not being shared' do + let!(:version) { create(:version, project:, sharing: 'none') } - it "is visible within the original project" do + it 'is visible within the original project' do expect(Version.shared_with(project)) .to contain_exactly(version) end - it "is not visible in any other project" do + it 'is not visible in any other project' do [parent_project, root_project, other_root_project, @@ -61,10 +61,10 @@ end end - context "with the version being shared with descendants" do - let!(:version) { create(:version, project:, sharing: "descendants") } + context 'with the version being shared with descendants' do + let!(:version) { create(:version, project:, sharing: 'descendants') } - it "is visible within the original project and it`s descendants" do + it 'is visible within the original project and it`s descendants' do [project, child_project, grand_child_project].each do |p| @@ -73,7 +73,7 @@ end end - it "is not visible in any other project" do + it 'is not visible in any other project' do [parent_project, root_project, other_root_project, @@ -84,7 +84,7 @@ end end - it "is not visible in any other project if the project is inactive" do + it 'is not visible in any other project if the project is inactive' do project.update(active: false) [parent_project, @@ -100,10 +100,10 @@ end end - context "with the version being shared with hierarchy" do - let!(:version) { create(:version, project:, sharing: "hierarchy") } + context 'with the version being shared with hierarchy' do + let!(:version) { create(:version, project:, sharing: 'hierarchy') } - it "is visible within the original project and it`s descendants and ancestors" do + it 'is visible within the original project and it`s descendants and ancestors' do [project, parent_project, root_project, @@ -114,7 +114,7 @@ end end - it "is not visible in any other project" do + it 'is not visible in any other project' do [other_root_project, aunt_project, sibling_project].each do |p| @@ -123,7 +123,7 @@ end end - it "is not visible in any other project if the project is inactive" do + it 'is not visible in any other project if the project is inactive' do project.update(active: false) [parent_project, @@ -139,10 +139,10 @@ end end - context "with the version being shared with tree" do - let(:version) { create(:version, project:, sharing: "tree") } + context 'with the version being shared with tree' do + let(:version) { create(:version, project:, sharing: 'tree') } - it "is visible within the original project and every project within the same tree" do + it 'is visible within the original project and every project within the same tree' do [project, parent_project, root_project, @@ -155,14 +155,14 @@ end end - it "is not visible projects outside of the tree" do + it 'is not visible projects outside of the tree' do [other_root_project].each do |p| expect(Version.shared_with(p)) .to be_empty end end - it "is not visible in any other project if the project is inactive" do + it 'is not visible in any other project if the project is inactive' do project.update(active: false) [parent_project, @@ -178,10 +178,10 @@ end end - context "with the version being shared with system" do - let(:version) { create(:version, project:, sharing: "system") } + context 'with the version being shared with system' do + let(:version) { create(:version, project:, sharing: 'system') } - it "is visible in all projects" do + it 'is visible in all projects' do [project, parent_project, root_project, @@ -195,7 +195,7 @@ end end - it "is not visible in any other project if the project is inactive" do + it 'is not visible in any other project if the project is inactive' do project.update(active: false) [parent_project, diff --git a/spec/models/watcher_spec.rb b/spec/models/watcher_spec.rb index 24b18d39476b..75520efab4d3 100644 --- a/spec/models/watcher_spec.rb +++ b/spec/models/watcher_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Watcher do let(:project) { watchable.project } @@ -52,24 +52,24 @@ end let(:saved_watchable) { create(:news) } - describe "#valid" do - it "is valid for an active user" do + describe '#valid' do + it 'is valid for an active user' do expect(watcher).to be_valid end - it "is valid for an invited user" do + it 'is valid for an invited user' do user.status = Principal.statuses[:invited] expect(watcher).to be_valid end - it "is valid for a registered user" do + it 'is valid for a registered user' do user.status = Principal.statuses[:registered] expect(watcher).to be_valid end end - describe ".prune" do - shared_examples_for "a pruned watchable" do + describe '.prune' do + shared_examples_for 'a pruned watchable' do before do watcher.save! other_watcher.save! @@ -77,86 +77,86 @@ user.reload end - context "with a matching user scope" do - it "removes the watcher" do + context 'with a matching user scope' do + it 'removes the watcher' do Watcher.prune(user:) expect(Watcher.find_by(id: watcher.id)).to be_nil end - it "leaves the other watcher" do + it 'leaves the other watcher' do Watcher.prune(user:) expect(Watcher.find_by(id: other_watcher.id)).to eql other_watcher end end - context "without a scope" do - it "removes the watcher" do + context 'without a scope' do + it 'removes the watcher' do Watcher.prune expect(Watcher.find_by(id: watcher.id)).to be_nil end - it "leaves the other watcher" do + it 'leaves the other watcher' do Watcher.prune expect(Watcher.find_by(id: other_watcher.id)).to eql other_watcher end end - context "with a non matching user scope" do + context 'with a non matching user scope' do let(:other_other_user) { create(:user) } - it "leaves the watcher" do + it 'leaves the watcher' do Watcher.prune(user: other_other_user) expect(Watcher.find_by(id: watcher.id)).to eql watcher end - it "leaves the other watcher" do + it 'leaves the other watcher' do Watcher.prune(user: other_other_user) expect(Watcher.find_by(id: other_watcher.id)).to eql other_watcher end end - context "with a matching user and project_id scope" do - it "removes the watcher" do + context 'with a matching user and project_id scope' do + it 'removes the watcher' do Watcher.prune(user:, project_id: project.id) expect(Watcher.find_by(id: watcher.id)).to be_nil end - it "leaves the other watcher" do + it 'leaves the other watcher' do Watcher.prune(user:, project_id: project.id) expect(Watcher.find_by(id: other_watcher.id)).to eql other_watcher end end - context "with a matching project_id scope" do - it "removes the watcher" do + context 'with a matching project_id scope' do + it 'removes the watcher' do Watcher.prune(project_id: project.id) expect(Watcher.find_by(id: watcher.id)).to be_nil end - it "leaves the other watcher" do + it 'leaves the other watcher' do Watcher.prune(project_id: project.id) expect(Watcher.find_by(id: other_watcher.id)).to eql other_watcher end end - context "with a non matching project_id scope" do - it "leaves the watcher" do + context 'with a non matching project_id scope' do + it 'leaves the watcher' do Watcher.prune(project_id: other_project.id) expect(Watcher.find_by(id: watcher.id)).to eql watcher end - it "leaves the other watcher" do + it 'leaves the other watcher' do Watcher.prune(project_id: other_project.id) expect(Watcher.find_by(id: other_watcher.id)).to eql other_watcher @@ -164,22 +164,22 @@ end end - shared_examples_for "no watcher exists" do + shared_examples_for 'no watcher exists' do before do watchable.save! end - it "is robust" do + it 'is robust' do expect { Watcher.prune }.not_to raise_error end end - context "for a work package" do - it_behaves_like "a pruned watchable" - it_behaves_like "no watcher exists" + context 'for a work package' do + it_behaves_like 'a pruned watchable' + it_behaves_like 'no watcher exists' end - context "for a message" do + context 'for a message' do let(:forum) { build(:forum) } let(:watchable) do forum.save! @@ -187,25 +187,25 @@ end let(:project) { forum.project } - it_behaves_like "a pruned watchable" - it_behaves_like "no watcher exists" + it_behaves_like 'a pruned watchable' + it_behaves_like 'no watcher exists' end end - describe "#add_watcher" do - it "returns true when the watcher is added" do + describe '#add_watcher' do + it 'returns true when the watcher is added' do expect(saved_watchable.add_watcher(saved_user)) .to be_truthy end - it "adds the user to watchers" do + it 'adds the user to watchers' do saved_watchable.add_watcher(saved_user) expect(saved_watchable.watchers.map(&:user)) .to match_array(saved_user) end - it "does not add the same user when called twice" do + it 'does not add the same user when called twice' do saved_watchable.add_watcher(saved_user) saved_watchable.add_watcher(saved_user) @@ -214,12 +214,12 @@ end end - describe "#remove_watcher" do + describe '#remove_watcher' do before do saved_watchable.watchers.create(user: saved_user) end - it "removes the watcher" do + it 'removes the watcher' do saved_watchable.remove_watcher(saved_user) expect(saved_watchable.watchers) @@ -227,28 +227,28 @@ end end - describe "#watched_by" do - context "for a watcher user" do + describe '#watched_by' do + context 'for a watcher user' do before do saved_watchable.watchers.create!(user: saved_user) end - it "is truthy" do + it 'is truthy' do expect(saved_watchable.watched_by?(saved_user)) .to be_truthy end end - context "for a non watcher user" do - it "is falsey" do + context 'for a non watcher user' do + it 'is falsey' do expect(saved_watchable.watched_by?(saved_user)) .to be_falsey end end end - describe "#watcher_user_ids" do - it "only adds unique users" do + describe '#watcher_user_ids' do + it 'only adds unique users' do saved_watchable.watcher_user_ids = [saved_user.id, saved_user.id] expect(saved_watchable) .to be_valid diff --git a/spec/models/week_day_spec.rb b/spec/models/week_day_spec.rb index 5eddc34896dd..f190fff50e1e 100644 --- a/spec/models/week_day_spec.rb +++ b/spec/models/week_day_spec.rb @@ -1,13 +1,13 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe WeekDay do - describe "#name" do - it "returns the translated week day name" do - expect(described_class.new(day: 1).name).to eq("Monday") - expect(described_class.new(day: 7).name).to eq("Sunday") + describe '#name' do + it 'returns the translated week day name' do + expect(described_class.new(day: 1).name).to eq('Monday') + expect(described_class.new(day: 7).name).to eq('Sunday') I18n.with_locale(:de) do - expect(described_class.new(day: 3).name).to eq("Mittwoch") - expect(described_class.new(day: 4).name).to eq("Donnerstag") + expect(described_class.new(day: 3).name).to eq('Mittwoch') + expect(described_class.new(day: 4).name).to eq('Donnerstag') end end end diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 4b72175b9b1b..1403c7f83f47 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiPage do shared_let(:author) { create(:user) } @@ -37,78 +37,78 @@ let(:wiki_page) { create(:wiki_page, wiki:, title:, author:) } let(:new_wiki_page) { build(:wiki_page, wiki:, title:) } - it_behaves_like "acts_as_watchable included" do + it_behaves_like 'acts_as_watchable included' do let(:model_instance) { create(:wiki_page) } let(:watch_permission) { :view_wiki_pages } let(:project) { model_instance.project } end - it_behaves_like "acts_as_attachable included" do + it_behaves_like 'acts_as_attachable included' do let(:model_instance) { create(:wiki_page) } let(:project) { model_instance.project } end - describe "#slug" do - context "when another project with same title exists" do + describe '#slug' do + context 'when another project with same title exists' do let(:project2) { create(:project) } let(:wiki2) { project2.wiki } - let!(:wiki_page1) { create(:wiki_page, wiki:, title: "asdf") } - let!(:wiki_page2) { create(:wiki_page, wiki: wiki2, title: "asdf") } + let!(:wiki_page1) { create(:wiki_page, wiki:, title: 'asdf') } + let!(:wiki_page2) { create(:wiki_page, wiki: wiki2, title: 'asdf') } - it "scopes the slug correctly" do - pages = described_class.where(title: "asdf") + it 'scopes the slug correctly' do + pages = described_class.where(title: 'asdf') expect(pages.count).to eq(2) - expect(pages.first.slug).to eq("asdf") - expect(pages.last.slug).to eq("asdf") + expect(pages.first.slug).to eq('asdf') + expect(pages.last.slug).to eq('asdf') end end - context "when only having a . for the title" do - let(:wiki_page) { create(:wiki_page, wiki:, title: ".") } + context 'when only having a . for the title' do + let(:wiki_page) { create(:wiki_page, wiki:, title: '.') } - it "creates a non empty slug" do - expect(wiki_page.slug).to eq("dot") + it 'creates a non empty slug' do + expect(wiki_page.slug).to eq('dot') end end - context "when only having a ! for the title" do - let(:wiki_page) { create(:wiki_page, wiki:, title: "!") } + context 'when only having a ! for the title' do + let(:wiki_page) { create(:wiki_page, wiki:, title: '!') } - it "creates a non empty slug" do - expect(wiki_page.slug).to eq("bang") + it 'creates a non empty slug' do + expect(wiki_page.slug).to eq('bang') end end - context "when only having a { for the title" do - let(:wiki_page) { create(:wiki_page, wiki:, title: "{") } + context 'when only having a { for the title' do + let(:wiki_page) { create(:wiki_page, wiki:, title: '{') } - it "fails to create" do + it 'fails to create' do expect { wiki_page } .to raise_error(ActiveRecord::RecordInvalid) end end - context "with another default language", with_settings: { default_language: "de" } do - let(:wiki_page) { build(:wiki_page, wiki:, title: "Übersicht") } + context 'with another default language', with_settings: { default_language: 'de' } do + let(:wiki_page) { build(:wiki_page, wiki:, title: 'Übersicht') } - it "stills use english slug methods" do + it 'stills use english slug methods' do expect(wiki_page.save).to be true - expect(wiki_page.slug).to eq "ubersicht" + expect(wiki_page.slug).to eq 'ubersicht' end end - context "with another I18n.locale set", with_settings: { default_language: "de" } do - let(:wiki_page) { build(:wiki_page, wiki:, title: "Übersicht") } + context 'with another I18n.locale set', with_settings: { default_language: 'de' } do + let(:wiki_page) { build(:wiki_page, wiki:, title: 'Übersicht') } - it "stills use english slug methods" do + it 'stills use english slug methods' do I18n.locale = :de expect(wiki_page.save).to be true - expect(wiki_page.slug).to eq "ubersicht" + expect(wiki_page.slug).to eq 'ubersicht' end end end - describe "#nearest_main_item" do + describe '#nearest_main_item' do let(:child_page) { create(:wiki_page, parent: wiki_page, wiki:) } let!(:child_page_wiki_menu_item) do create(:wiki_menu_item, wiki:, name: child_page.slug, parent: wiki_page.menu_item) @@ -116,43 +116,43 @@ let(:grand_child_page) { create(:wiki_page, parent: child_page, wiki:) } let!(:grand_child_page_wiki_menu_item) { create(:wiki_menu_item, wiki:, name: grand_child_page.slug) } - it "returns the menu item of the grand parent if the menu item of its parent is not a main item" do + it 'returns the menu item of the grand parent if the menu item of its parent is not a main item' do expect(grand_child_page.nearest_main_item).to eq(wiki_page.menu_item) end end - describe "#destroy" do - it "destroys the wiki page's journals as well" do + describe '#destroy' do + it 'destroys the wiki page\'s journals as well' do wiki_page expect { wiki_page.destroy } .to change(Journal.for_wiki_page, :count).from(1).to(0) end - context "when the only wiki page is destroyed" do + context 'when the only wiki page is destroyed' do before do wiki_page.destroy end - it "ensures there is still a wiki menu item" do + it 'ensures there is still a wiki menu item' do expect(wiki.wiki_menu_items).to be_one expect(wiki.wiki_menu_items.first).to be_is_main_item end end - context "when one of two wiki pages is destroyed" do + context 'when one of two wiki pages is destroyed' do before do create(:wiki_page, wiki:) wiki_page.destroy end - it "ensures that there is still a wiki menu item named like the wiki start page" do + it 'ensures that there is still a wiki menu item named like the wiki start page' do expect(wiki.wiki_menu_items).to be_one expect(wiki.wiki_menu_items.first.name).to eq described_class.slug(wiki.start_page) end end - context "when destroying a parent" do + context 'when destroying a parent' do let!(:child_wiki_page) do create(:wiki_page, parent_id: wiki_page.id, wiki:, project:) end @@ -161,18 +161,18 @@ wiki_page.destroy end - it "keeps the child but nils the parent_id" do + it 'keeps the child but nils the parent_id' do expect(child_wiki_page.reload.parent_id) .to be_nil end end end - describe "#title" do - context "when it is blank" do + describe '#title' do + context 'when it is blank' do let(:title) { nil } - it "is invalid" do + it 'is invalid' do new_wiki_page.valid? expect(new_wiki_page.errors.symbols_for(:title)) @@ -181,36 +181,36 @@ end end - describe "#protected?" do - it "is false by default" do + describe '#protected?' do + it 'is false by default' do expect(wiki_page.reload) .not_to be_protected end end - describe "#project" do - it "is the same as the project on wiki" do + describe '#project' do + it 'is the same as the project on wiki' do expect(wiki_page.project).to eql(wiki.project) end end - describe "#parent_title" do + describe '#parent_title' do let(:child_wiki_page) do create(:wiki_page, parent_id: wiki_page.id, wiki:, project:) end - it "is empty for a page without a parent" do + it 'is empty for a page without a parent' do expect(wiki_page.parent_title) .to be_nil end - it "is the name of the parent page if set" do + it 'is the name of the parent page if set' do expect(child_wiki_page.parent_title) .to eq wiki_page.title end end - describe "#parent_title=" do + describe '#parent_title=' do let(:other_wiki_page) do create(:wiki_page, wiki:, project:) end @@ -219,8 +219,8 @@ create(:wiki_page, parent: other_wiki_page, wiki:, project:) end - context "when setting it to the name of a wiki page" do - it "sets the parent to that wiki page" do + context 'when setting it to the name of a wiki page' do + it 'sets the parent to that wiki page' do wiki_page.parent_title = other_wiki_page.title wiki_page.save @@ -229,13 +229,13 @@ end end - context "when setting to an empty string" do + context 'when setting to an empty string' do let(:child_wiki_page) do create(:wiki_page, parent_id: wiki_page.id, wiki:, project:) end - it "unsets the parent" do - child_wiki_page.parent_title = "" + it 'unsets the parent' do + child_wiki_page.parent_title = '' child_wiki_page.save expect(child_wiki_page.reload.parent) @@ -243,36 +243,36 @@ end end - context "when setting to a child" do + context 'when setting to a child' do let(:child_wiki_page) do create(:wiki_page, parent_id: wiki_page.id, wiki:, project:) end - it "causes an error" do + it 'causes an error' do wiki_page.parent_title = child_wiki_page.title expect(wiki_page.save) .to be false expect(wiki_page.errors[:parent_title]) - .to eq [I18n.t("activerecord.errors.messages.circular_dependency")] + .to eq [I18n.t('activerecord.errors.messages.circular_dependency')] end end - context "when setting to a itself" do - it "causes an error" do + context 'when setting to a itself' do + it 'causes an error' do wiki_page.parent_title = wiki_page.title expect(wiki_page.save) .to be false expect(wiki_page.errors[:parent_title]) - .to eq [I18n.t("activerecord.errors.messages.circular_dependency")] + .to eq [I18n.t('activerecord.errors.messages.circular_dependency')] end end end - describe ".visible" do + describe '.visible' do let(:other_project) { create(:project).reload } let(:other_wiki) { project.wiki } let(:other_wiki_page) { create(:wiki_page, wiki:, title: wiki.wiki_menu_items.first.title) } @@ -282,47 +282,47 @@ member_with_roles: { project => role }) end - it "returns all pages for which the user has the 'view_wiki_pages' permission" do + it 'returns all pages for which the user has the \'view_wiki_pages\' permission' do expect(described_class.visible(user)) .to contain_exactly(wiki_page) end end - describe "#author" do - it "sets the author" do + describe '#author' do + it 'sets the author' do expect(wiki_page.author) .to eql author end end - describe "#journals", + describe '#journals', with_settings: { journal_aggregation_time_minutes: 0 } do - context "when creating" do - it "adds a journal" do + context 'when creating' do + it 'adds a journal' do expect(wiki_page.journals.count) .to be 1 end - it "journalizes the text" do + it 'journalizes the text' do expect(wiki_page.journals.last.data.text) .to eql wiki_page.text end end - context "when updating" do - let(:text) { "My new content" } + context 'when updating' do + let(:text) { 'My new content' } before do wiki_page.text = text end - it "adds a journal" do + it 'adds a journal' do expect { wiki_page.save! } .to change(wiki_page.journals, :count) .by(1) end - it "journalizes the text" do + it 'journalizes the text' do wiki_page.save! expect(wiki_page.journals.last.data.text) @@ -331,9 +331,9 @@ end end - describe "#text" do - it "does not truncate to 64k" do - content = described_class.create(title:, text: "a" * 500.kilobyte, author:, wiki:) + describe '#text' do + it 'does not truncate to 64k' do + content = described_class.create(title:, text: 'a' * 500.kilobyte, author:, wiki:) content.reload expect(content.text.size) @@ -341,11 +341,11 @@ end end - describe "#version", + describe '#version', with_settings: { journal_aggregation_time_minutes: 0 } do - context "when updating" do - it "updates the version" do - wiki_page.text = "My new content" + context 'when updating' do + it 'updates the version' do + wiki_page.text = 'My new content' expect { wiki_page.save! } .to change(wiki_page, :version) @@ -353,8 +353,8 @@ end end - context "when creating" do - it "sets the version to 1" do + context 'when creating' do + it 'sets the version to 1' do wiki_page.save! expect(wiki_page.version) @@ -362,9 +362,9 @@ end end - context "when new" do - it "starts with 0" do - wiki_page = described_class.new(title:, text: "a", author:) + context 'when new' do + it 'starts with 0' do + wiki_page = described_class.new(title:, text: 'a', author:) expect(wiki_page.version) .to be 0 @@ -372,10 +372,10 @@ end end - describe "mail sending" do + describe 'mail sending' do before do create(:user, - firstname: "project_watcher", + firstname: 'project_watcher', member_with_permissions: { wiki.project => [:view_wiki_pages] }, notification_settings: [ build(:notification_setting, @@ -384,7 +384,7 @@ ]) wiki_watcher = create(:user, - firstname: "wiki_watcher", + firstname: 'wiki_watcher', member_with_permissions: { wiki.project => [:view_wiki_pages] }, notification_settings: [ build(:notification_setting, @@ -395,8 +395,8 @@ wiki.watcher_users << wiki_watcher end - context "when creating" do - it "sends mails to the wiki`s watchers and project all watchers" do + context 'when creating' do + it 'sends mails to the wiki`s watchers and project all watchers' do expect do perform_enqueued_jobs do User.execute_as(author) do @@ -409,11 +409,11 @@ end end - context "when updating", + context 'when updating', with_settings: { journal_aggregation_time_minutes: 0 } do let!(:page_watcher) do watcher = create(:user, - firstname: "page_watcher", + firstname: 'page_watcher', member_with_permissions: { wiki.project => [:view_wiki_pages] }, notification_settings: [ build(:notification_setting, wiki_page_updated: true) @@ -424,10 +424,10 @@ end before do - wiki_page.text = "My new content" + wiki_page.text = 'My new content' end - it "sends mails to the watchers, the wiki`s watchers and project all watchers" do + it 'sends mails to the watchers, the wiki`s watchers and project all watchers' do expect do perform_enqueued_jobs do User.execute_as(author) do diff --git a/spec/models/wiki_redirect_spec.rb b/spec/models/wiki_redirect_spec.rb index 5173ddf845fd..5d5a12bc7c8f 100644 --- a/spec/models/wiki_redirect_spec.rb +++ b/spec/models/wiki_redirect_spec.rb @@ -25,95 +25,95 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiRedirect do let(:wiki) { create(:wiki) } - let(:wiki_page) { create(:wiki_page, wiki:, title: "Original title") } + let(:wiki_page) { create(:wiki_page, wiki:, title: 'Original title') } - context "when renaming the page" do + context 'when renaming the page' do before do - wiki_page.title = "New title" + wiki_page.title = 'New title' wiki_page.save end - it "creates a redirect" do + it 'creates a redirect' do expect(wiki.redirects) - .to exist(title: "original-title") + .to exist(title: 'original-title') end - it "allows to still find the page via the original title" do - expect(wiki.find_page("Original title")) + it 'allows to still find the page via the original title' do + expect(wiki.find_page('Original title')) .to eq wiki_page end - it "allows to still find the page via the original title even with a different case" do - expect(wiki.find_page("ORIGINAL title")) + it 'allows to still find the page via the original title even with a different case' do + expect(wiki.find_page('ORIGINAL title')) .to eq wiki_page end end - context "when renaming twice" do + context 'when renaming twice' do before do - wiki_page.title = "New old title" + wiki_page.title = 'New old title' wiki_page.save - wiki_page.title = "New title" + wiki_page.title = 'New title' wiki_page.save end - it "allows to still find the page via the original title" do - expect(wiki.find_page("Original title")) + it 'allows to still find the page via the original title' do + expect(wiki.find_page('Original title')) .to eq wiki_page end - it "allows to still find the page via the intermediate title" do - expect(wiki.find_page("New old title")) + it 'allows to still find the page via the intermediate title' do + expect(wiki.find_page('New old title')) .to eq wiki_page end - it "allows to still find the page via the current title" do - expect(wiki.find_page("New title")) + it 'allows to still find the page via the current title' do + expect(wiki.find_page('New title')) .to eq wiki_page end end - context "when reversing the rename" do + context 'when reversing the rename' do before do - wiki_page.title = "New title" + wiki_page.title = 'New title' wiki_page.save - wiki_page.title = "Original title" + wiki_page.title = 'Original title' wiki_page.save end - it "allows to find the page via the original title" do - expect(wiki.find_page("Original title")) + it 'allows to find the page via the original title' do + expect(wiki.find_page('Original title')) .to eq wiki_page end - it "allows to still find the page via the intermediate title" do - expect(wiki.find_page("New title")) + it 'allows to still find the page via the intermediate title' do + expect(wiki.find_page('New title')) .to eq wiki_page end end - context "when an equally named redirect already exists" do + context 'when an equally named redirect already exists' do before do - WikiRedirect.create!(wiki:, title: "an-old-page", redirects_to: "other-page") + WikiRedirect.create!(wiki:, title: 'an-old-page', redirects_to: 'other-page') - wiki_page.title = "An old page" + wiki_page.title = 'An old page' wiki_page.save end - it "overwrite the old redirect" do - expect(wiki.find_page("An old page")) + it 'overwrite the old redirect' do + expect(wiki.find_page('An old page')) .to eq wiki_page end end - it "is removed when deleting the page" do - redirect = WikiRedirect.create(wiki:, title: "an-old-page", redirects_to: wiki_page.slug) + it 'is removed when deleting the page' do + redirect = WikiRedirect.create(wiki:, title: 'an-old-page', redirects_to: wiki_page.slug) wiki_page.destroy expect(WikiRedirect) diff --git a/spec/models/wiki_spec.rb b/spec/models/wiki_spec.rb index c6cc84ef3c22..f2240a686f22 100644 --- a/spec/models/wiki_spec.rb +++ b/spec/models/wiki_spec.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Wiki do - let(:project) { create(:project, disable_modules: "wiki") } - let(:start_page) { "The wiki start page" } + let(:project) { create(:project, disable_modules: 'wiki') } + let(:start_page) { 'The wiki start page' } let(:wiki) { project.create_wiki start_page: } - describe "creation" do - it_behaves_like "acts_as_watchable included" do + describe 'creation' do + it_behaves_like 'acts_as_watchable included' do let(:model_instance) { create(:wiki) } let(:watch_permission) { :view_wiki_pages } let(:project) { model_instance.project } end - describe "#create" do - it "creates a wiki menu item on creation" do + describe '#create' do + it 'creates a wiki menu item on creation' do expect(wiki.wiki_menu_items).to be_one end - it "sets the wiki menu item title to the name of the start page" do + it 'sets the wiki menu item title to the name of the start page' do expect(wiki.wiki_menu_items.first.title).to eq(start_page) end - it "requires a start_page" do + it 'requires a start_page' do wiki = project.create_wiki start_page: nil expect(wiki) .to be_new_record @@ -57,119 +57,119 @@ end end - describe "#start_page" do - it "can be changed" do - wiki.start_page = "Another start page" + describe '#start_page' do + it 'can be changed' do + wiki.start_page = 'Another start page' wiki.save expect(Wiki) - .to exist(start_page: "Another start page") + .to exist(start_page: 'Another start page') end end - describe "#slug" do - context "with an umlaut" do - let(:wiki_page) { create(:wiki_page, wiki:, title: "Übersicht") } + describe '#slug' do + context 'with an umlaut' do + let(:wiki_page) { create(:wiki_page, wiki:, title: 'Übersicht') } - it "normalizes" do - expect(wiki_page.slug).to eq "ubersicht" + it 'normalizes' do + expect(wiki_page.slug).to eq 'ubersicht' end end end - describe "#find_page" do - let(:title) { "Übersicht" } + describe '#find_page' do + let(:title) { 'Übersicht' } let!(:wiki_page) { create(:wiki_page, wiki:, title:) } - let(:search_string) { "Übersicht" } + let(:search_string) { 'Übersicht' } subject { wiki.find_page(search_string) } - context "when using the title" do - it "finds the page" do + context 'when using the title' do + it 'finds the page' do expect(subject) .to eq wiki_page end end - context "when using the title in a different case" do - let(:search_string) { "ÜBERSICHT" } + context 'when using the title in a different case' do + let(:search_string) { 'ÜBERSICHT' } - it "finds the page" do + it 'finds the page' do expect(subject) .to eq wiki_page end end - context "for a date title" do + context 'for a date title' do let(:search_string) { '2009\\02\\09' } let(:title) { '2009\\02\\09' } - it "finds the page" do + it 'finds the page' do expect(subject) .to eq wiki_page end end - context "for non latin characters" do - let(:search_string) { "Этика менеджмента" } - let(:title) { "Этика менеджмента" } + context 'for non latin characters' do + let(:search_string) { 'Этика менеджмента' } + let(:title) { 'Этика менеджмента' } - it "finds the page" do + it 'finds the page' do expect(subject) .to eq wiki_page end end - context "with german default_language", with_settings: { default_language: "de" } do + context 'with german default_language', with_settings: { default_language: 'de' } do before do - wiki_page.update_column(:slug, "uebersicht") + wiki_page.update_column(:slug, 'uebersicht') end - it "finds the page with the default_language slug title (Regression #38606)" do + it 'finds the page with the default_language slug title (Regression #38606)' do expect(subject) .to eq wiki_page end end end - describe "#find_or_new_page" do - let(:title) { "Übersicht" } + describe '#find_or_new_page' do + let(:title) { 'Übersicht' } let!(:wiki_page) { create(:wiki_page, wiki:, title:) } subject { wiki.find_or_new_page(search_string) } - context "when using the title of an existing page" do + context 'when using the title of an existing page' do let(:search_string) { title } - it "returns that page" do + it 'returns that page' do expect(subject) .to eq wiki_page end end - context "when using the title in a different case" do - let(:search_string) { "ÜBERSICHT" } + context 'when using the title in a different case' do + let(:search_string) { 'ÜBERSICHT' } - it "finds the page" do + it 'finds the page' do expect(subject) .to eq wiki_page end end - context "when using a different title" do + context 'when using a different title' do let(:search_string) { title + title } - it "returns a wiki page" do + it 'returns a wiki page' do expect(subject) .to be_a WikiPage end - it "returns an unpersisted record" do + it 'returns an unpersisted record' do expect(subject) .to be_new_record end - it "set the title of the new wiki page" do + it 'set the title of the new wiki page' do expect(subject.title) .to eq search_string end diff --git a/spec/models/work_package/aggregate_ancestors_spec.rb b/spec/models/work_package/aggregate_ancestors_spec.rb index 79ea34f70f87..5f05e9f40184 100644 --- a/spec/models/work_package/aggregate_ancestors_spec.rb +++ b/spec/models/work_package/aggregate_ancestors_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage::Ancestors do let(:user) { create(:user) } @@ -79,7 +79,7 @@ login_as(user) end - context "with permission in the first project" do + context 'with permission in the first project' do before do create(:member, user:, @@ -87,16 +87,16 @@ roles: [view_role]) end - describe "fetching from db" do - it "returns the same results" do + describe 'fetching from db' do + it 'returns the same results' do expect(leaf.visible_ancestors(user)).to eq([root_work_package, intermediate]) end end - describe "leaf ids" do + describe 'leaf ids' do let(:ids) { leaf_ids } - it "returns ancestors for the leaf in project 1" do + it 'returns ancestors for the leaf in project 1' do expect(subject).to be_a(Hash) expect(subject.keys.length).to eq(2) @@ -105,10 +105,10 @@ end end - describe "intermediate ids" do + describe 'intermediate ids' do let(:ids) { intermediate_ids } - it "returns all ancestors in project 1" do + it 'returns all ancestors in project 1' do expect(subject).to be_a(Hash) expect(subject.keys.length).to eq(2) @@ -117,7 +117,7 @@ end end - context "and permission in second project" do + context 'and permission in second project' do before do create(:member, user:, @@ -125,10 +125,10 @@ roles: [view_role]) end - describe "leaf ids" do + describe 'leaf ids' do let(:ids) { leaf_ids } - it "returns all ancestors" do + it 'returns all ancestors' do expect(subject).to be_a(Hash) expect(subject.keys.length).to eq(2) @@ -139,7 +139,7 @@ end end - context "no permissions" do + context 'no permissions' do before do create(:member, user:, @@ -147,10 +147,10 @@ roles: [none_role]) end - describe "leaf ids" do + describe 'leaf ids' do let(:ids) { leaf_ids } - it "returns no results for all ids" do + it 'returns no results for all ids' do expect(subject).to be_a(Hash) expect(subject.keys.length).to eq(0) end diff --git a/spec/models/work_package/ask_before_destruction_spec.rb b/spec/models/work_package/ask_before_destruction_spec.rb index f29a5db4aeac..c4747ca5bc5c 100644 --- a/spec/models/work_package/ask_before_destruction_spec.rb +++ b/spec/models/work_package/ask_before_destruction_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do let(:work_package) do @@ -70,43 +70,43 @@ project: work_package2.project) end - describe "#cleanup_action_required_before_destructing?" do - describe "w/ the work package having a time entry" do + describe '#cleanup_action_required_before_destructing?' do + describe 'w/ the work package having a time entry' do before do work_package time_entry end - it "is true" do + it 'is true' do expect(WorkPackage.cleanup_action_required_before_destructing?(work_package)).to be_truthy end end - describe "w/ two work packages having a time entry" do + describe 'w/ two work packages having a time entry' do before do work_package time_entry time_entry2 end - it "is true" do + it 'is true' do expect(WorkPackage.cleanup_action_required_before_destructing?([work_package, work_package2])).to be_truthy end end - describe "w/o the work package having a time entry" do + describe 'w/o the work package having a time entry' do before do work_package end - it "is false" do + it 'is false' do expect(WorkPackage.cleanup_action_required_before_destructing?(work_package)).to be_falsey end end end - describe "#associated_classes_to_address_before_destructing?" do - describe "w/ the work package having a time entry" do + describe '#associated_classes_to_address_before_destructing?' do + describe 'w/ the work package having a time entry' do before do work_package time_entry @@ -117,44 +117,44 @@ end end - describe "w/o the work package having a time entry" do + describe 'w/o the work package having a time entry' do before do work_package end - it "is empty" do + it 'is empty' do expect(WorkPackage.associated_classes_to_address_before_destruction_of(work_package)).to be_empty end end end - describe "#cleanup_associated_before_destructing_if_required" do + describe '#cleanup_associated_before_destructing_if_required' do before do work_package time_entry end - describe "w/o a cleanup being necessary" do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, action: "reassign") } + describe 'w/o a cleanup being necessary' do + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, action: 'reassign') } before do time_entry.destroy end - it "returns true" do + it 'returns true' do expect(action).to be_truthy end end describe 'w/ "destroy" as action' do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, action: "destroy") } + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, action: 'destroy') } - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "does not touch the time_entry" do + it 'does not touch the time_entry' do action time_entry.reload @@ -162,14 +162,14 @@ end end - describe "w/o an action" do + describe 'w/o an action' do let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user) } - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "does not touch the time_entry" do + it 'does not touch the time_entry' do action time_entry.reload @@ -178,13 +178,13 @@ end describe 'w/ "nullify" as action' do - let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, action: "nullify") } + let(:action) { WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, action: 'nullify') } - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "sets the work_package_id of all time entries to nil" do + it 'sets the work_package_id of all time entries to nil' do action time_entry.reload @@ -194,11 +194,11 @@ describe 'w/ "reassign" as action w/ reassigning to a valid work_package' do - context "with a single work package" do + context 'with a single work package' do let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required(work_package, user, - action: "reassign", + action: 'reassign', reassign_to_id: work_package2.id) end @@ -208,11 +208,11 @@ member2 end - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "sets the work_package_id of all time entries to the new work package" do + it 'sets the work_package_id of all time entries to the new work package' do action time_entry.reload @@ -227,11 +227,11 @@ end end - context "with a collection of work packages" do + context 'with a collection of work packages' do let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, - action: "reassign", + action: 'reassign', reassign_to_id: work_package2.id) end @@ -242,11 +242,11 @@ member2.save! end - it "returns true" do + it 'returns true' do expect(action).to be_truthy end - it "sets the work_package_id of all time entries to the new work package" do + it 'sets the work_package_id of all time entries to the new work package' do action time_entry.reload @@ -267,7 +267,7 @@ let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, - action: "reassign", + action: 'reassign', reassign_to_id: work_package2.id) end @@ -275,11 +275,11 @@ work_package2 end - it "returns true" do + it 'returns true' do expect(action).to be_falsey end - it "does not alter the work_package_id of all time entries" do + it 'does not alter the work_package_id of all time entries' do action time_entry.reload @@ -292,26 +292,26 @@ let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, - action: "reassign", + action: 'reassign', reassign_to_id: 0) end - it "returns true" do + it 'returns true' do expect(action).to be_falsey end - it "does not alter the work_package_id of all time entries" do + it 'does not alter the work_package_id of all time entries' do action time_entry.reload expect(time_entry.work_package_id).to eq(work_package.id) end - it "sets an error on work packages" do + it 'sets an error on work packages' do action expect(work_package.errors[:base]) - .to eq([I18n.t(:"activerecord.errors.models.work_package.is_not_a_valid_target_for_time_entries", id: 0)]) + .to eq([I18n.t(:'activerecord.errors.models.work_package.is_not_a_valid_target_for_time_entries', id: 0)]) end end @@ -320,48 +320,48 @@ let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, - action: "reassign") + action: 'reassign') end - it "returns true" do + it 'returns true' do expect(action).to be_falsey end - it "does not alter the work_package_id of all time entries" do + it 'does not alter the work_package_id of all time entries' do action time_entry.reload expect(time_entry.work_package_id).to eq(work_package.id) end - it "sets an error on work packages" do + it 'sets an error on work packages' do action expect(work_package.errors[:base]) - .to eq([I18n.t(:"activerecord.errors.models.work_package.is_not_a_valid_target_for_time_entries", id: nil)]) + .to eq([I18n.t(:'activerecord.errors.models.work_package.is_not_a_valid_target_for_time_entries', id: nil)]) end end - describe "w/ an invalid option" do + describe 'w/ an invalid option' do let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, - action: "bogus") + action: 'bogus') end - it "returns false" do + it 'returns false' do expect(action).to be_falsey end end - describe "w/ nil as invalid option" do + describe 'w/ nil as invalid option' do let(:action) do WorkPackage.cleanup_associated_before_destructing_if_required([work_package], user, nil) end - it "returns false" do + it 'returns false' do expect(action).to be_falsey end end diff --git a/spec/models/work_package/exporter/csv_integration_spec.rb b/spec/models/work_package/exporter/csv_integration_spec.rb index 5c91f6ae38d5..6146b7955297 100644 --- a/spec/models/work_package/exporter/csv_integration_spec.rb +++ b/spec/models/work_package/exporter/csv_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage::Exports::CSV, "integration" do +RSpec.describe WorkPackage::Exports::CSV, 'integration' do before do login_as current_user end @@ -65,7 +65,7 @@ ) end - it "performs a successful export" do + it 'performs a successful export' do work_package.reload data = CSV.parse instance.export!.content @@ -75,6 +75,6 @@ expect(data.last).to include(work_package.description) expect(data.last).to include(current_user.name) expect(data.last).to include(work_package.updated_at.localtime.strftime("%m/%d/%Y %I:%M %p")) - expect(data.last).to include("(15.0 h)") + expect(data.last).to include('(15.0 h)') end end diff --git a/spec/models/work_package/hooks_spec.rb b/spec/models/work_package/hooks_spec.rb index d22fb1827121..ebd0b91b0033 100644 --- a/spec/models/work_package/hooks_spec.rb +++ b/spec/models/work_package/hooks_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do describe "#create" do diff --git a/spec/models/work_package/openproject_notifications_spec.rb b/spec/models/work_package/openproject_notifications_spec.rb index 0c962e1eecb6..dd7f24350367 100644 --- a/spec/models/work_package/openproject_notifications_spec.rb +++ b/spec/models/work_package/openproject_notifications_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' ## # Tests that email notifications will be sent upon creating or changing a work package. RSpec.describe WorkPackage, with_settings: { journal_aggregation_time_minutes: 0 } do - describe "OpenProject notifications" do + describe 'OpenProject notifications' do shared_let(:admin) { create(:admin) } let(:project) { create(:project) } let(:work_package) do create(:work_package, author: admin, - subject: "I can see you", + subject: 'I can see you', project:) end @@ -54,7 +54,7 @@ OpenProject::Notifications.unsubscribe(OpenProject::Events::AGGREGATED_WORK_PACKAGE_JOURNAL_READY, subscription) end - context "when after creation" do + context 'when after creation' do before do work_package perform_enqueued_jobs @@ -65,13 +65,13 @@ end end - describe "when after update" do + describe 'when after update' do before do work_package perform_enqueued_jobs journal_ids.clear - work_package.update(subject: "the wind of change") + work_package.update(subject: 'the wind of change') perform_enqueued_jobs end diff --git a/spec/models/work_package/work_package_acts_as_customizable_spec.rb b/spec/models/work_package/work_package_acts_as_customizable_spec.rb index e5f398bc198c..745673700697 100644 --- a/spec/models/work_package/work_package_acts_as_customizable_spec.rb +++ b/spec/models/work_package/work_package_acts_as_customizable_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "acts_as_customizable" do +RSpec.describe WorkPackage, 'acts_as_customizable' do let(:type) { create(:type_standard) } let(:project) { create(:project, types: [type]) } let(:user) { create(:user) } @@ -42,7 +42,7 @@ author: user, status:, priority:, - subject: "some subject" + subject: 'some subject' end def setup_custom_field(cf) @@ -52,8 +52,8 @@ def setup_custom_field(cf) RequestStore.clear! end - describe "#custom_field_values=" do - context "with an unpersisted work package and a version custom field" do + describe '#custom_field_values=' do + context 'with an unpersisted work package and a version custom field' do subject(:wp_with_assignee_cf) do setup_custom_field(version_cf) new_work_package.custom_field_values = { version_cf.id.to_s => version } @@ -63,28 +63,28 @@ def setup_custom_field(cf) let(:version) { create(:version, project:) } let(:version_cf) { create(:version_wp_custom_field, is_required: true) } - it "results in a valid work package" do + it 'results in a valid work package' do expect(wp_with_assignee_cf) .to be_valid end - it "sets the value" do + it 'sets the value' do expect(wp_with_assignee_cf.send(version_cf.attribute_getter)) .to eql version end end end - describe "#custom_field_values" do + describe '#custom_field_values' do subject(:work_package) do setup_custom_field(custom_field) new_work_package end - context "with a multi-value list custom field without default value" do + context 'with a multi-value list custom field without default value' do let(:custom_field) { create(:wp_custom_field, :multi_list) } - it "returns an array with a CustomValue with nil value" do + it 'returns an array with a CustomValue with nil value' do expect(work_package.custom_field_values) .to match([ an_instance_of(CustomValue).and(having_attributes(value: nil, custom_field_id: custom_field.id)) @@ -92,11 +92,11 @@ def setup_custom_field(cf) end end - context "with a multi-value list custom field with default value of 1 option" do - let(:custom_field) { create(:wp_custom_field, :multi_list, default_options: ["B"]) } + context 'with a multi-value list custom field with default value of 1 option' do + let(:custom_field) { create(:wp_custom_field, :multi_list, default_options: ['B']) } - it "returns an array with a CustomValue whose value is the stringified id of the default custom option" do - option_b = custom_field.custom_options.find_by(value: "B") + it 'returns an array with a CustomValue whose value is the stringified id of the default custom option' do + option_b = custom_field.custom_options.find_by(value: 'B') expect(work_package.custom_field_values) .to match([ an_instance_of(CustomValue).and(having_attributes(value: option_b.id.to_s, @@ -105,13 +105,13 @@ def setup_custom_field(cf) end end - context "with a multi-value list custom field with default value of multiple options" do - let(:custom_field) { create(:wp_custom_field, :multi_list, default_options: ["D", "B", "F"]) } + context 'with a multi-value list custom field with default value of multiple options' do + let(:custom_field) { create(:wp_custom_field, :multi_list, default_options: ['D', 'B', 'F']) } - it "returns an array with CustomValues whose values are the stringified ids of the default custom options" do - option_d = custom_field.custom_options.find_by(value: "D") - option_b = custom_field.custom_options.find_by(value: "B") - option_f = custom_field.custom_options.find_by(value: "F") + it 'returns an array with CustomValues whose values are the stringified ids of the default custom options' do + option_d = custom_field.custom_options.find_by(value: 'D') + option_b = custom_field.custom_options.find_by(value: 'B') + option_f = custom_field.custom_options.find_by(value: 'F') expect(work_package.custom_field_values) .to match([ an_instance_of(CustomValue).and(having_attributes(value: option_b.id.to_s, @@ -125,7 +125,7 @@ def setup_custom_field(cf) end end - describe "#custom_field_:id" do + describe '#custom_field_:id' do let(:included_cf) { build(:work_package_custom_field) } let(:other_cf) { build(:work_package_custom_field) } @@ -136,35 +136,35 @@ def setup_custom_field(cf) setup_custom_field(included_cf) end - it "says to respond to valid custom field accessors" do + it 'says to respond to valid custom field accessors' do expect(work_package).to respond_to(included_cf.attribute_getter) end - it "really responds to valid custom field accessors" do + it 'really responds to valid custom field accessors' do expect(work_package.send(included_cf.attribute_getter)).to be_nil end - it "says to not respond to foreign custom field accessors" do + it 'says to not respond to foreign custom field accessors' do expect(work_package).not_to respond_to(other_cf.attribute_getter) end - it "does really not respond to foreign custom field accessors" do + it 'does really not respond to foreign custom field accessors' do expect { work_package.send(other_cf.attribute_getter) }.to raise_error(NoMethodError) end end - describe "#valid?" do + describe '#valid?' do let(:cf1) { create(:work_package_custom_field, is_required: true) } let(:cf2) { create(:work_package_custom_field, is_required: true) } - it "does not duplicate error messages when invalid" do + it 'does not duplicate error messages when invalid' do # create work_package with one required custom field work_package = new_work_package # work_package.reload setup_custom_field(cf1) # set that custom field with a value, should be fine - work_package.custom_field_values = { cf1.id => "test" } + work_package.custom_field_values = { cf1.id => 'test' } work_package.save! work_package.reload @@ -181,37 +181,37 @@ def setup_custom_field(cf) end end - it_behaves_like "acts_as_customizable included" do + it_behaves_like 'acts_as_customizable included' do let(:model_instance) { work_package } let(:custom_field) { create(:string_wp_custom_field) } before do setup_custom_field(custom_field) end - context "with a default value" do + context 'with a default value' do before do - custom_field.update! default_value: "foobar" + custom_field.update! default_value: 'foobar' model_instance.custom_values.destroy_all end - it "returns no changes" do + it 'returns no changes' do expect(model_instance.custom_field_changes).to be_empty end end - context "with a bool custom_field having a default value" do + context 'with a bool custom_field having a default value' do before do - custom_field.update! field_format: "bool", default_value: "0" + custom_field.update! field_format: 'bool', default_value: '0' model_instance.custom_values.destroy_all end - it "returns no changes" do + it 'returns no changes' do expect(model_instance.custom_field_changes).to be_empty end end end - describe ".preload_available_custom_fields/#available_custom_fields" do + describe '.preload_available_custom_fields/#available_custom_fields' do let(:project) { create(:project) } let(:type) { create(:type) } let(:work_package) do @@ -230,39 +230,39 @@ def setup_custom_field(cf) let!(:custom_field_of_project_and_type) do create(:work_package_custom_field, - name: "Custom field of type and project").tap do |cf| + name: 'Custom field of type and project').tap do |cf| project.work_package_custom_fields << cf type.custom_fields << cf end end let!(:custom_field_of_project_not_type) do create(:work_package_custom_field, - name: "Custom field of project not type").tap do |cf| + name: 'Custom field of project not type').tap do |cf| project.work_package_custom_fields << cf end end let!(:custom_field_of_type_not_project) do create(:work_package_custom_field, - name: "Custom field of type not project").tap do |cf| + name: 'Custom field of type not project').tap do |cf| type.custom_fields << cf end end let!(:custom_field_for_all_and_type) do create(:work_package_custom_field, - name: "Custom field for all and type", + name: 'Custom field for all and type', is_for_all: true).tap do |cf| type.custom_fields << cf end end let!(:custom_field_for_all_not_type) do create(:work_package_custom_field, - name: "Custom field for all not type", + name: 'Custom field for all not type', is_for_all: true) end let!(:custom_field_of_projects_and_types_for_all) do create(:work_package_custom_field, - name: "Custom field for all and many types and projects", + name: 'Custom field for all and many types and projects', is_for_all: true).tap do |cf| project.work_package_custom_fields << cf type.custom_fields << cf @@ -271,7 +271,7 @@ def setup_custom_field(cf) end end - context "when preloading the custom fields" do + context 'when preloading the custom fields' do before do described_class.preload_available_custom_fields([work_package, work_package2]) # Bad replacement to check that no database query is run. @@ -280,19 +280,19 @@ def setup_custom_field(cf) .and_call_original end - it "returns all custom fields of the project and type for work_package" do + it 'returns all custom fields of the project and type for work_package' do expect(work_package.available_custom_fields) .to contain_exactly(custom_field_of_project_and_type, custom_field_for_all_and_type, custom_field_of_projects_and_types_for_all) end - it "returns all custom fields of the project and type for work_package2" do + it 'returns all custom fields of the project and type for work_package2' do expect(work_package2.available_custom_fields) .to contain_exactly(custom_field_of_projects_and_types_for_all) end - it "does not call the database" do + it 'does not call the database' do work_package.available_custom_fields work_package2.available_custom_fields @@ -301,8 +301,8 @@ def setup_custom_field(cf) end end - context "when not preloading the custom fields" do - it "returns all custom fields of the project and type" do + context 'when not preloading the custom fields' do + it 'returns all custom fields of the project and type' do expect(work_package.available_custom_fields) .to contain_exactly(custom_field_of_project_and_type, custom_field_for_all_and_type, diff --git a/spec/models/work_package/work_package_acts_as_event_spec.rb b/spec/models/work_package/work_package_acts_as_event_spec.rb index 93183675b856..456c85b81e27 100644 --- a/spec/models/work_package/work_package_acts_as_event_spec.rb +++ b/spec/models/work_package/work_package_acts_as_event_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do - describe "acts_as_event" do + describe 'acts_as_event' do let(:stub_work_package) { build_stubbed(:work_package) } - describe "#event_url" do + describe '#event_url' do let(:expected_url) { { controller: :work_packages, action: :show, id: stub_work_package.id } } it { expect(stub_work_package.event_url).to eq(expected_url) } diff --git a/spec/models/work_package/work_package_acts_as_searchable_spec.rb b/spec/models/work_package/work_package_acts_as_searchable_spec.rb index 610d161d8a61..1fcc11180cde 100644 --- a/spec/models/work_package/work_package_acts_as_searchable_spec.rb +++ b/spec/models/work_package/work_package_acts_as_searchable_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "acts_as_searchable" do +RSpec.describe WorkPackage, 'acts_as_searchable' do include BecomeMember - let(:wp_subject) { "the quick brown fox jumps over the lazy dog" } + let(:wp_subject) { 'the quick brown fox jumps over the lazy dog' } let(:project) do create(:project, public: false) @@ -43,7 +43,7 @@ end let(:user) { create(:user) } - describe "#search" do + describe '#search' do describe "w/ the user being logged in w/ searching for a matching string w/ being member with the appropriate permission" do @@ -54,7 +54,7 @@ become_member_with_permissions(project, user, :view_work_packages) end - it "returns the work package" do + it 'returns the work package' do expect(WorkPackage.search(wp_subject.split).first).to include(work_package) end end @@ -65,7 +65,7 @@ w/ searching with an offset" do # this offset recreates the way the time is transformed in the controller # This will have to be cleaned up - let(:offset) { (work_package.created_at - 1.minute).strftime("%Y%m%d%H%M%S").to_time } + let(:offset) { (work_package.created_at - 1.minute).strftime('%Y%m%d%H%M%S').to_time } before do work_package @@ -74,7 +74,7 @@ become_member_with_permissions(project, user, :view_work_packages) end - it "returns the work package if the offset is before the work packages created at value" do + it 'returns the work package if the offset is before the work packages created at value' do expect(WorkPackage.search(wp_subject.split, nil, offset:).first).to include(work_package) end end diff --git a/spec/models/work_package/work_package_acts_as_watchable_spec.rb b/spec/models/work_package/work_package_acts_as_watchable_spec.rb index 99c967c6a7ac..07d74bf46447 100644 --- a/spec/models/work_package/work_package_acts_as_watchable_spec.rb +++ b/spec/models/work_package/work_package_acts_as_watchable_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -require "support/shared/acts_as_watchable" +require 'support/shared/acts_as_watchable' RSpec.describe WorkPackage do let(:project) { create(:project) } @@ -37,7 +37,7 @@ project:) end - it_behaves_like "acts_as_watchable included" do + it_behaves_like 'acts_as_watchable included' do let(:model_instance) { create(:work_package) } let(:watch_permission) { :view_work_packages } let(:project) { model_instance.project } diff --git a/spec/models/work_package/work_package_custom_actions_spec.rb b/spec/models/work_package/work_package_custom_actions_spec.rb index 3b58b98415f9..64493120cc66 100644 --- a/spec/models/work_package/work_package_custom_actions_spec.rb +++ b/spec/models/work_package/work_package_custom_actions_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "custom_actions" do +RSpec.describe WorkPackage, 'custom_actions' do let(:work_package) do build_stubbed(:work_package, project:) @@ -55,8 +55,8 @@ action end - describe "#custom_actions" do - context "with the custom action having no restriction" do + describe '#custom_actions' do + context 'with the custom action having no restriction' do let(:conditions) do [] end @@ -65,56 +65,56 @@ work_package.status_id = status.id end - it "returns the action" do + it 'returns the action' do expect(work_package.custom_actions(user)) .to contain_exactly(custom_action) end end - context "with a status restriction" do - context "with the work package having the same status" do + context 'with a status restriction' do + context 'with the work package having the same status' do before do work_package.status_id = status.id end - it "returns the action" do + it 'returns the action' do expect(work_package.custom_actions(user)) .to contain_exactly(custom_action) end end - context "with the work package having a different status" do + context 'with the work package having a different status' do before do work_package.status_id = other_status.id end - it "does not return the action" do + it 'does not return the action' do expect(work_package.custom_actions(user)) .to be_empty end end end - context "with a role restriction" do + context 'with a role restriction' do let(:conditions) do [CustomActions::Conditions::Role.new(role.id)] end - context "with the user having the same role" do - it "returns the action" do + context 'with the user having the same role' do + it 'returns the action' do expect(work_package.custom_actions(user)) .to contain_exactly(custom_action) end end - context "with the condition requiring a different role" do + context 'with the condition requiring a different role' do let(:other_role) { create(:project_role) } let(:conditions) do [CustomActions::Conditions::Role.new(other_role.id)] end - it "does not return the action" do + it 'does not return the action' do expect(work_package.custom_actions(user)) .to be_empty end diff --git a/spec/models/work_package/work_package_custom_fields_spec.rb b/spec/models/work_package/work_package_custom_fields_spec.rb index 66aad60cf47d..8a6bca2d1275 100644 --- a/spec/models/work_package/work_package_custom_fields_spec.rb +++ b/spec/models/work_package/work_package_custom_fields_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do - describe "#custom_fields" do + describe '#custom_fields' do let(:type) { create(:type_standard) } let(:project) { create(:project, types: [type]) } let(:work_package) do @@ -39,15 +39,15 @@ end let(:custom_field) do create(:work_package_custom_field, - name: "Database", - field_format: "list", + name: 'Database', + field_format: 'list', possible_values: %w(MySQL PostgreSQL Oracle), is_required: cf_required) end let(:cf_required) { true } - shared_context "project with custom field" do |save = true| + shared_context 'project with custom field' do |save = true| before do project.work_package_custom_fields << custom_field type.custom_fields << custom_field @@ -65,71 +65,71 @@ def self.change_custom_field_value(work_package, value, save: true) end end - shared_examples_for "work package with required custom field" do + shared_examples_for 'work package with required custom field' do subject { work_package.available_custom_fields } it { is_expected.to include(custom_field) } end - context "touch on save" do - include_context "project with custom field" + context 'touch on save' do + include_context 'project with custom field' let(:cf_required) { false } before do work_package.update_columns(updated_at: 3.days.ago) end - context "creating a cf value" do - it "updates the updated_at attribute" do + context 'creating a cf value' do + it 'updates the updated_at attribute' do expect { change_custom_field_value(work_package, custom_field.possible_values.first) } .to change { work_package.updated_at } end - it "updates the lock_version attribute" do + it 'updates the lock_version attribute' do expect { change_custom_field_value(work_package, custom_field.possible_values.first) } .to change { work_package.lock_version }.by(1) end end - context "deleting a cf value" do + context 'deleting a cf value' do before do change_custom_field_value(work_package, custom_field.possible_values.first) end - it "updates the updated_at attribute" do + it 'updates the updated_at attribute' do expect { change_custom_field_value(work_package, nil) } .to change { work_package.updated_at } end - it "updates the lock_version attribute" do + it 'updates the lock_version attribute' do expect { change_custom_field_value(work_package, nil) } .to change { work_package.lock_version }.by(1) end end - context "updating a cf value" do + context 'updating a cf value' do before do change_custom_field_value(work_package, custom_field.possible_values.first) end - it "updates the updated_at attribute" do + it 'updates the updated_at attribute' do expect { change_custom_field_value(work_package, custom_field.possible_values.last) } .to change { work_package.updated_at } end - it "updates the lock_version attribute" do + it 'updates the lock_version attribute' do expect { change_custom_field_value(work_package, custom_field.possible_values.last) } .to change { work_package.lock_version }.by(1) end end - context "updating a cf value and another attribute at the same time" do + context 'updating a cf value and another attribute at the same time' do before do change_custom_field_value(work_package, custom_field.possible_values.first) end - it "updates the lock_version attribute by 1" do - work_package.subject = "new subject" + it 'updates the lock_version attribute by 1' do + work_package.subject = 'new subject' expect { change_custom_field_value(work_package, custom_field.possible_values.last) } .to change { work_package.lock_version }.by(1) @@ -137,21 +137,21 @@ def self.change_custom_field_value(work_package, value, save: true) end end - context "required custom field exists" do - include_context "project with custom field" + context 'required custom field exists' do + include_context 'project with custom field' - it_behaves_like "work package with required custom field" + it_behaves_like 'work package with required custom field' - describe "invalid custom field values" do - context "short error message" do - shared_examples_for "custom field with invalid value" do + describe 'invalid custom field values' do + context 'short error message' do + shared_examples_for 'custom field with invalid value' do let(:custom_field_key) { custom_field.attribute_name.to_sym } before do change_custom_field_value(work_package, custom_field_value) end - describe "error message" do + describe 'error message' do before { work_package.save } subject { work_package.errors[custom_field_key] } @@ -161,91 +161,91 @@ def self.change_custom_field_value(work_package, value, save: true) } end - describe "symbols_for" do + describe 'symbols_for' do before do work_package.save end - it "stores the symbol" do + it 'stores the symbol' do actual_symbols = work_package.errors.symbols_for(custom_field_key) expect(actual_symbols).to contain_exactly(error_key.to_sym) end end - describe "work package attribute update" do + describe 'work package attribute update' do subject { work_package.save } it { is_expected.to be_falsey } end end - context "no value given" do + context 'no value given' do let(:custom_field_value) { nil } - it_behaves_like "custom field with invalid value" do - let(:error_key) { "blank" } + it_behaves_like 'custom field with invalid value' do + let(:error_key) { 'blank' } end end - context "empty value given" do - let(:custom_field_value) { "" } + context 'empty value given' do + let(:custom_field_value) { '' } - it_behaves_like "custom field with invalid value" do - let(:error_key) { "blank" } + it_behaves_like 'custom field with invalid value' do + let(:error_key) { 'blank' } end end - context "invalid value given" do - let(:custom_field_value) { "SQLServer" } + context 'invalid value given' do + let(:custom_field_value) { 'SQLServer' } - it_behaves_like "custom field with invalid value" do - let(:error_key) { "inclusion" } + it_behaves_like 'custom field with invalid value' do + let(:error_key) { 'inclusion' } end end end - context "full error message" do - before { change_custom_field_value(work_package, "SQLServer") } + context 'full error message' do + before { change_custom_field_value(work_package, 'SQLServer') } subject { work_package.errors.full_messages.first } - it "matches" do + it 'matches' do expect(subject).to eq("Database #{I18n.t('activerecord.errors.messages.inclusion')}") end end end - describe "valid value given" do - before { change_custom_field_value(work_package, "PostgreSQL") } + describe 'valid value given' do + before { change_custom_field_value(work_package, 'PostgreSQL') } - context "errors" do + context 'errors' do subject { work_package.errors[:custom_values] } it { is_expected.to be_empty } end - context "save" do + context 'save' do subject { work_package.typed_custom_value_for(custom_field.id) } - it { is_expected.to eq("PostgreSQL") } + it { is_expected.to eq('PostgreSQL') } end end - describe "only updates when actually saving" do + describe 'only updates when actually saving' do before do - change_custom_field_value(work_package, "PostgreSQL") - change_custom_field_value(work_package, "MySQL", save: false) + change_custom_field_value(work_package, 'PostgreSQL') + change_custom_field_value(work_package, 'MySQL', save: false) work_package.reload end subject { work_package.typed_custom_value_for(custom_field.id) } - it { is_expected.to eql("PostgreSQL") } + it { is_expected.to eql('PostgreSQL') } end end - describe "work package type change" do + describe 'work package type change' do let (:custom_field_2) { create(:work_package_custom_field) } let(:type_feature) do create(:type_feature, @@ -257,16 +257,16 @@ def self.change_custom_field_value(work_package, value, save: true) project.types << type_feature end - context "with initial type" do - include_context "project with custom field" + context 'with initial type' do + include_context 'project with custom field' - describe "pre-condition" do - it_behaves_like "work package with required custom field" + describe 'pre-condition' do + it_behaves_like 'work package with required custom field' end - describe "does not change custom fields w/o save" do + describe 'does not change custom fields w/o save' do before do - change_custom_field_value(work_package, "PostgreSQL") + change_custom_field_value(work_package, 'PostgreSQL') work_package.reload work_package.type = type_feature @@ -274,24 +274,24 @@ def self.change_custom_field_value(work_package, value, save: true) subject { WorkPackage.find(work_package.id).typed_custom_value_for(custom_field) } - it { is_expected.to eq("PostgreSQL") } + it { is_expected.to eq('PostgreSQL') } end end - context "w/o initial type" do + context 'w/o initial type' do let(:work_package_without_type) do build_stubbed(:work_package, project:, type:) end - describe "pre-condition" do + describe 'pre-condition' do subject { work_package_without_type.custom_field_values } it { is_expected.to be_empty } end - context "with assigning type" do + context 'with assigning type' do before { work_package_without_type.type = type_feature } subject { work_package_without_type.custom_field_values } @@ -300,12 +300,12 @@ def self.change_custom_field_value(work_package, value, save: true) end end - describe "assign type id first" do + describe 'assign type id first' do let(:attribute_hash) { ActiveSupport::OrderedHash.new } before do - attribute_hash["custom_field_values"] = { custom_field_2.id => "true" } - attribute_hash["type_id"] = type_feature.id + attribute_hash['custom_field_values'] = { custom_field_2.id => 'true' } + attribute_hash['type_id'] = type_feature.id end subject do @@ -322,19 +322,19 @@ def self.change_custom_field_value(work_package, value, save: true) end describe "custom field type 'text'" do - let(:value) { "text" * 1024 } + let(:value) { 'text' * 1024 } let(:custom_field) do create(:work_package_custom_field, - name: "Test Text", - field_format: "text", + name: 'Test Text', + field_format: 'text', is_required: true) end - include_context "project with custom field" + include_context 'project with custom field' - it_behaves_like "work package with required custom field" + it_behaves_like 'work package with required custom field' - describe "value" do + describe 'value' do let(:relevant_journal) do work_package.journals.find { |j| j.customizable_journals.size > 0 } end @@ -349,15 +349,15 @@ def self.change_custom_field_value(work_package, value, save: true) end end - describe "default values" do - include_context "project with custom field", false + describe 'default values' do + include_context 'project with custom field', false - context "for a custom field with default value" do + context 'for a custom field with default value' do before do custom_field.custom_options[1].update_attribute(:default_value, true) end - it "sets the default values for custom_field_values" do + it 'sets the default values for custom_field_values' do expect(work_package.custom_field_values.length) .to be 1 @@ -366,8 +366,8 @@ def self.change_custom_field_value(work_package, value, save: true) end end - context "for a custom field without default value" do - it "sets the default values for custom_field_values" do + context 'for a custom field without default value' do + it 'sets the default values for custom_field_values' do expect(work_package.custom_field_values.length) .to be 1 @@ -377,26 +377,26 @@ def self.change_custom_field_value(work_package, value, save: true) end end - describe "validation error interpolation" do + describe 'validation error interpolation' do let :custom_field do create(:work_package_custom_field, - name: "PIN", - field_format: "text", + name: 'PIN', + field_format: 'text', max_length: 4, is_required: true) end - include_context "project with custom field" + include_context 'project with custom field' - it "works for the max length validation" do - work_package.custom_field_values.first.value = "12345" + it 'works for the max length validation' do + work_package.custom_field_values.first.value = '12345' # don't want to see I18n::MissingInterpolationArgument specifically expect { work_package.valid? }.not_to raise_error expect(work_package.valid?).to be_falsey expect(work_package.errors.full_messages.first) - .to eq "PIN is too long (maximum is 4 characters)." + .to eq 'PIN is too long (maximum is 4 characters).' end end end diff --git a/spec/models/work_package/work_package_multi_value_custom_fields_spec.rb b/spec/models/work_package/work_package_multi_value_custom_fields_spec.rb index c231647e120f..f7b6b2bdf617 100644 --- a/spec/models/work_package/work_package_multi_value_custom_fields_spec.rb +++ b/spec/models/work_package/work_package_multi_value_custom_fields_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do let(:type) { create(:type) } @@ -64,15 +64,15 @@ let(:values) { work_package.custom_value_for(custom_field) } let(:typed_values) { work_package.typed_custom_value_for(custom_field.id) } - it "returns the properly typed values" do + it 'returns the properly typed values' do expect(values.map(&:value)).to eq(custom_values) expect(typed_values).to eq(%w(ham onions pineapple)) end - context "when value not present" do + context 'when value not present' do let(:work_package) { create(:work_package, project:, type:) } - it "returns nil properly" do + it 'returns nil properly' do # I suspect this should rather be # expect(values.map(&:value)).to eq([nil]) expect(values.value).to be_nil @@ -80,14 +80,14 @@ end end - describe "setting and reading values" do - shared_examples_for "custom field values updates" do + describe 'setting and reading values' do + shared_examples_for 'custom field values updates' do before do # Reload to reset i.e. the saved_changes filter on custom_values work_package.reload end - it "touches the work_package" do + it 'touches the work_package' do expect do work_package.custom_field_values = { custom_field.id => ids } work_package.save @@ -95,7 +95,7 @@ .to(change(work_package, :lock_version)) end - it "sets the values" do + it 'sets the values' do work_package.custom_field_values = { custom_field.id => ids } work_package.save @@ -104,22 +104,22 @@ end end - context "when removing some custom values" do - it_behaves_like "custom field values updates" do + context 'when removing some custom values' do + it_behaves_like 'custom field values updates' do let(:ids) { [custom_values.first.to_s] } - let(:values) { ["ham"] } + let(:values) { ['ham'] } end end - context "when removing all custom values" do - it_behaves_like "custom field values updates" do + context 'when removing all custom values' do + it_behaves_like 'custom field values updates' do let(:ids) { [] } let(:values) { [nil] } end end - context "when adding values" do - it_behaves_like "custom field values updates" do + context 'when adding values' do + it_behaves_like 'custom field values updates' do let(:ids) do CustomOption.where(value: ["ham", "onions", "pineapple", "mushrooms"]).pluck(:id).map(&:to_s) end @@ -127,10 +127,10 @@ end end - context "when first having no values and then adding some" do + context 'when first having no values and then adding some' do let(:custom_values) { [] } - it_behaves_like "custom field values updates" do + it_behaves_like 'custom field values updates' do let(:ids) do CustomOption.where(value: ["ham", "mushrooms"]).pluck(:id).map(&:to_s) end diff --git a/spec/models/work_package/work_package_relations_spec.rb b/spec/models/work_package/work_package_relations_spec.rb index d1281a319124..7557e0e80e78 100644 --- a/spec/models/work_package/work_package_relations_spec.rb +++ b/spec/models/work_package/work_package_relations_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do - describe "#relation" do + describe '#relation' do let(:closed_state) do create(:status, is_closed: true) end - describe "#duplicate" do + describe '#duplicate' do let(:status) { create(:status) } let(:type) { create(:type) } let(:original) do @@ -66,7 +66,7 @@ current_user { create(:user) } - context "closes duplicates" do + context 'closes duplicates' do let(:dup_2) do create(:work_package, project:, @@ -99,13 +99,13 @@ dup_2.reload end - it "only duplicates are closed" do + it 'only duplicates are closed' do expect(dup_1).to be_closed expect(dup_2).to be_closed end end - context "duplicated is not closed" do + context 'duplicated is not closed' do before do relation_org_dup_1 @@ -121,7 +121,7 @@ end end - describe "#soonest_start" do + describe '#soonest_start' do let(:predecessor) do create(:work_package, due_date: predecessor_due_date) @@ -159,83 +159,83 @@ relations end - context "without a predecessor" do + context 'without a predecessor' do let(:work_packages) { [successor] } let(:relations) { [] } it { expect(successor.soonest_start).to be_nil } end - context "with a predecessor" do + context 'with a predecessor' do let(:work_packages) { [predecessor, successor] } - context "start date exists in predecessor" do + context 'start date exists in predecessor' do let(:predecessor_due_date) { Date.today } it { expect(successor_child.soonest_start).to eq(predecessor.due_date + 1) } end - context "no date in predecessor" do + context 'no date in predecessor' do it { expect(successor_child.soonest_start).to be_nil } end end - context "with the parent having a predecessor" do + context 'with the parent having a predecessor' do let(:work_packages) { [predecessor, successor, successor_child] } - context "start date exists in predecessor" do + context 'start date exists in predecessor' do let(:predecessor_due_date) { Date.today } it { expect(successor_child.soonest_start).to eq(predecessor.due_date + 1) } - context "with the parent manually scheduled" do + context 'with the parent manually scheduled' do let(:successor_schedule_manually) { true } it { expect(successor_child.soonest_start).to be_nil } end end - context "no start date exists in related work packages" do + context 'no start date exists in related work packages' do it { expect(successor_child.soonest_start).to be_nil } end end - context "with the grandparent having a predecessor" do + context 'with the grandparent having a predecessor' do let(:work_packages) { [predecessor, successor, successor_child, successor_grandchild] } - context "start date exists in predecessor" do + context 'start date exists in predecessor' do let(:predecessor_due_date) { Date.today } it { expect(successor_grandchild.soonest_start).to eq(predecessor.due_date + 1) } - context "with the grandparent manually scheduled" do + context 'with the grandparent manually scheduled' do let(:successor_schedule_manually) { true } it { expect(successor_grandchild.soonest_start).to be_nil } end - context "with the parent manually scheduled" do + context 'with the parent manually scheduled' do let(:successor_child_schedule_manually) { true } it { expect(successor_grandchild.soonest_start).to be_nil } end end - context "no start date exists in related work packages" do + context 'no start date exists in related work packages' do it { expect(successor_grandchild.soonest_start).to be_nil } end end end end - describe "#destroy" do + describe '#destroy' do let(:work_package) { create(:work_package) } let(:other_work_package) { create(:work_package) } - context "for a work package with a relation as to" do + context 'for a work package with a relation as to' do let!(:to_relation) { create(:follows_relation, from: other_work_package, to: work_package) } - it "removes the relation as well as the work package" do + it 'removes the relation as well as the work package' do work_package.destroy expect(Relation) @@ -243,10 +243,10 @@ end end - context "for a work package with a relation as from" do + context 'for a work package with a relation as from' do let!(:from_relation) { create(:follows_relation, to: other_work_package, from: work_package) } - it "removes the relation as well as the work package" do + it 'removes the relation as well as the work package' do work_package.destroy expect(Relation) diff --git a/spec/models/work_package/work_package_scheduling_spec.rb b/spec/models/work_package/work_package_scheduling_spec.rb index 6e62b04973d9..ed8da3387c8b 100644 --- a/spec/models/work_package/work_package_scheduling_spec.rb +++ b/spec/models/work_package/work_package_scheduling_spec.rb @@ -26,52 +26,52 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage do - describe "#overdue" do + describe '#overdue' do let(:work_package) do create(:work_package, due_date:) end - shared_examples_for "overdue" do + shared_examples_for 'overdue' do subject { work_package.overdue? } it { is_expected.to be_truthy } end - shared_examples_for "on time" do + shared_examples_for 'on time' do subject { work_package.overdue? } it { is_expected.to be_falsey } end - context "one day ago" do + context 'one day ago' do let(:due_date) { 1.day.ago.to_date } - it_behaves_like "overdue" + it_behaves_like 'overdue' end - context "today" do + context 'today' do let(:due_date) { Date.today.to_date } - it_behaves_like "on time" + it_behaves_like 'on time' end - context "next day" do + context 'next day' do let(:due_date) { 1.day.from_now.to_date } - it_behaves_like "on time" + it_behaves_like 'on time' end - context "no finish date" do + context 'no finish date' do let(:due_date) { nil } - it_behaves_like "on time" + it_behaves_like 'on time' end - context "status closed" do + context 'status closed' do let(:due_date) { 1.day.ago.to_date } let(:status) do create(:status, @@ -82,7 +82,7 @@ work_package.status = status end - it_behaves_like "on time" + it_behaves_like 'on time' end end end diff --git a/spec/models/work_package/work_package_status_spec.rb b/spec/models/work_package/work_package_status_spec.rb index e214b0137ede..e31afe47c553 100644 --- a/spec/models/work_package/work_package_status_spec.rb +++ b/spec/models/work_package/work_package_status_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "status" do +RSpec.describe WorkPackage, 'status' do let(:status) { create(:status) } let!(:work_package) do create(:work_package, status:) end - describe "#readonly" do + describe '#readonly' do let(:status) { create(:status, is_readonly: true) } - context "with EE", with_ee: %i[readonly_work_packages] do - it "marks work package as read only" do + context 'with EE', with_ee: %i[readonly_work_packages] do + it 'marks work package as read only' do expect(work_package).to be_readonly_status end end - context "without EE" do - it "is not marked as read only" do + context 'without EE' do + it 'is not marked as read only' do expect(work_package).not_to be_readonly_status end end diff --git a/spec/models/work_package/work_package_visibility_spec.rb b/spec/models/work_package/work_package_visibility_spec.rb index 791d74672dbc..2bb0d9bfee00 100644 --- a/spec/models/work_package/work_package_visibility_spec.rb +++ b/spec/models/work_package/work_package_visibility_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "WorkPackage-Visibility" do +RSpec.describe 'WorkPackage-Visibility' do shared_let(:admin) { create(:admin) } let(:anonymous) { create(:anonymous) } let(:user) { create(:user) } @@ -38,10 +38,10 @@ let(:view_work_packages) { create(:project_role, permissions: [:view_work_packages]) } let(:view_work_packages_role2) { create(:project_role, permissions: [:view_work_packages]) } - describe "of public projects" do + describe 'of public projects' do subject { create(:work_package, project: public_project) } - it "is viewable by anonymous, with the view_work_packages permission" do + it 'is viewable by anonymous, with the view_work_packages permission' do # it is not really clear, where these kind of "preconditions" belong to: This setting # is a default in Redmine::DefaultData::Loader - but this not loaded in the tests: here we # just make sure, that the work package is visible, when this permission is set @@ -50,18 +50,18 @@ end end - describe "of private projects" do + describe 'of private projects' do subject { create(:work_package, project: private_project) } - it "is visible for the admin, even if the project is private" do + it 'is visible for the admin, even if the project is private' do expect(WorkPackage.visible(admin)).to contain_exactly(subject) end - it "is not visible for anonymous users, when the project is private" do + it 'is not visible for anonymous users, when the project is private' do expect(WorkPackage.visible(anonymous)).to be_empty end - it "is visible for members of the project, with the view_work_packages permission" do + it 'is visible for members of the project, with the view_work_packages permission' do create(:member, user:, project: private_project, @@ -70,7 +70,7 @@ expect(WorkPackage.visible(user)).to contain_exactly(subject) end - it "is only returned once for members with two roles having view_work_packages permission" do + it 'is only returned once for members with two roles having view_work_packages permission' do subject create(:member, @@ -82,11 +82,11 @@ expect(WorkPackage.visible(user).pluck(:id)).to contain_exactly(subject.id) end - it "is not visible for non-members of the project without the view_work_packages permission" do + it 'is not visible for non-members of the project without the view_work_packages permission' do expect(WorkPackage.visible(user)).to be_empty end - it "is not visible for members of the project, without the view_work_packages permission" do + it 'is not visible for members of the project, without the view_work_packages permission' do no_permission = create(:project_role, permissions: [:no_permission]) create(:member, user:, diff --git a/spec/models/work_package_custom_field_spec.rb b/spec/models/work_package_custom_field_spec.rb index b3e11a0adb17..1751b91b650e 100644 --- a/spec/models/work_package_custom_field_spec.rb +++ b/spec/models/work_package_custom_field_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackageCustomField do - describe ".summable" do + describe '.summable' do let!(:list_custom_field) do create(:list_wp_custom_field) end @@ -40,8 +40,8 @@ create(:float_wp_custom_field) end - context "with a summable field" do - it "contains the custom_field" do + context 'with a summable field' do + it 'contains the custom_field' do expect(described_class.summable) .to contain_exactly(int_custom_field, float_custom_field) end diff --git a/spec/models/work_package_role_spec.rb b/spec/models/work_package_role_spec.rb index 5a9955f0e951..519c3aed90be 100644 --- a/spec/models/work_package_role_spec.rb +++ b/spec/models/work_package_role_spec.rb @@ -1,21 +1,21 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackageRole do let(:work_package_role) { build(:view_work_package_role) } subject do - described_class.create(name: "work_package_role", + described_class.create(name: 'work_package_role', permissions: %w[permissions]) end - describe "validations" do + describe 'validations' do it { is_expected.to validate_presence_of :name } it { is_expected.to validate_uniqueness_of :name } it { is_expected.to validate_length_of(:name).is_at_most(256) } end - describe "#member?" do - it "is one (even though it is builtin)" do + describe '#member?' do + it 'is one (even though it is builtin)' do expect(work_package_role).to be_member end end diff --git a/spec/models/work_packages/blocks_relation_spec.rb b/spec/models/work_packages/blocks_relation_spec.rb index 8aecac4c7f91..5326b2dc8354 100644 --- a/spec/models/work_packages/blocks_relation_spec.rb +++ b/spec/models/work_packages/blocks_relation_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "blocks/blocked_by relations" do +RSpec.describe WorkPackage, 'blocks/blocked_by relations' do create_shared_association_defaults_for_work_package_factory - shared_let(:work_package) { create(:work_package, subject: "blocked wp") } + shared_let(:work_package) { create(:work_package, subject: 'blocked wp') } - it "is not blocked by default" do + it 'is not blocked by default' do expect(work_package).not_to be_blocked expect(work_package.blockers).to be_empty end - context "with blocking work package" do - shared_let(:blocker) { create(:work_package, subject: "blocking wp") } + context 'with blocking work package' do + shared_let(:blocker) { create(:work_package, subject: 'blocking wp') } shared_let(:relation) do create(:relation, from: blocker, @@ -46,19 +46,19 @@ relation_type: Relation::TYPE_BLOCKS) end - it "is being blocked" do + it 'is being blocked' do expect(work_package).to be_blocked expect(work_package.blockers).to include blocker end - context "when work package is closed" do + context 'when work package is closed' do let(:closed_status) { create(:closed_status) } before do work_package.update_column :status_id, closed_status.id end - it "is not blocked" do + it 'is not blocked' do expect(work_package).not_to be_blocked expect(work_package.blockers).to be_empty end diff --git a/spec/models/work_packages/derived_dates_spec.rb b/spec/models/work_packages/derived_dates_spec.rb index b96c2973f989..af2f46d70aea 100644 --- a/spec/models/work_packages/derived_dates_spec.rb +++ b/spec/models/work_packages/derived_dates_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "derived dates" do +RSpec.describe WorkPackage, 'derived dates' do let(:work_package) do create(:work_package) end @@ -66,86 +66,86 @@ work_packages end - shared_examples_for "derived dates" do - context "with all dates being set" do - it "the derived_start_date is the minimum of both start and due date" do + shared_examples_for 'derived dates' do + context 'with all dates being set' do + it 'the derived_start_date is the minimum of both start and due date' do expect(subject.derived_start_date).to eql child_start_date end - it "the derived_due_date is the maximum of both start and due date" do + it 'the derived_due_date is the maximum of both start and due date' do expect(subject.derived_due_date).to eql other_child_due_date end end - context "with the due dates being minimal (start date being nil)" do + context 'with the due dates being minimal (start date being nil)' do let(:child_start_date) { nil } let(:other_child_start_date) { nil } - it "the derived_start_date is the minimum of the due dates" do + it 'the derived_start_date is the minimum of the due dates' do expect(subject.derived_start_date).to eql child_due_date end - it "the derived_due_date is the maximum of the due dates" do + it 'the derived_due_date is the maximum of the due dates' do expect(subject.derived_due_date).to eql other_child_due_date end end - context "with the start date being maximum (due date being nil)" do + context 'with the start date being maximum (due date being nil)' do let(:child_due_date) { nil } let(:other_child_due_date) { nil } - it "the derived_start_date is the minimum of the start dates" do + it 'the derived_start_date is the minimum of the start dates' do expect(subject.derived_start_date).to eql child_start_date end - it "has the derived_due_date is the maximum of the start dates" do + it 'has the derived_due_date is the maximum of the start dates' do expect(subject.derived_due_date).to eql other_child_start_date end end - context "with child dates being nil" do + context 'with child dates being nil' do let(:child_start_date) { nil } let(:child_due_date) { nil } let(:other_child_start_date) { nil } let(:other_child_due_date) { nil } - it "is nil" do + it 'is nil' do expect(subject.derived_start_date).to be_nil end end - context "without children" do + context 'without children' do let(:work_packages) { [work_package] } - it "is nil" do + it 'is nil' do expect(subject.derived_start_date).to be_nil end end end - context "for a work_package loaded individually" do + context 'for a work_package loaded individually' do subject { work_package } - it_behaves_like "derived dates" + it_behaves_like 'derived dates' end - context "for a work package that had derived dates loaded" do + context 'for a work package that had derived dates loaded' do subject { WorkPackage.include_derived_dates.first } - it_behaves_like "derived dates" + it_behaves_like 'derived dates' end - context "for an unpersisted work_package" do + context 'for an unpersisted work_package' do let(:work_package) { WorkPackage.new } let(:work_packages) { [] } subject { work_package } - it "the derived_start_date is nil" do + it 'the derived_start_date is nil' do expect(subject.derived_start_date).to be_nil end - it "the derived_due_date is nil" do + it 'the derived_due_date is nil' do expect(subject.derived_due_date).to be_nil end end diff --git a/spec/models/work_packages/pdf_export/work_package_list_to_pdf_spec.rb b/spec/models/work_packages/pdf_export/work_package_list_to_pdf_spec.rb index 960b6658dec1..beb8c371b629 100644 --- a/spec/models/work_packages/pdf_export/work_package_list_to_pdf_spec.rb +++ b/spec/models/work_packages/pdf_export/work_package_list_to_pdf_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage::PDFExport::WorkPackageListToPdf do include Redmine::I18n @@ -47,7 +47,7 @@ let(:types) { [type_standard, type_bug] } let(:project) do create(:project, - name: "Foo Bla. Report No. 4/2021 with/for Case 42", + name: 'Foo Bla. Report No. 4/2021 with/for Case 42', types:, work_package_custom_fields: [list_custom_field]) end @@ -61,12 +61,12 @@ create(:work_package, project:, type: type_standard, - subject: "Work package 1", + subject: 'Work package 1', story_points: 1, - description: "This is a description", + description: 'This is a description', list_custom_field.attribute_name => [ - list_custom_field.value_of("Foo"), - list_custom_field.value_of("Bar") + list_custom_field.value_of('Foo'), + list_custom_field.value_of('Bar') ]) end let(:work_package_child) do @@ -74,10 +74,10 @@ project:, parent: work_package_parent, type: type_bug, - subject: "Work package 2", + subject: 'Work package 2', story_points: 2, - description: "This is work package 2", - list_custom_field.attribute_name => list_custom_field.value_of("Foo")) + description: 'This is work package 2', + list_custom_field.attribute_name => list_custom_field.value_of('Foo')) end let(:work_packages) do [work_package_parent, work_package_child] @@ -132,22 +132,22 @@ def show PDF::Inspector::Text.analyze(File.read(export_pdf.content.path)) end - describe "with a request for a PDF table" do - it "contains correct data" do + describe 'with a request for a PDF table' do + it 'contains correct data' do expect(pdf.strings).to eq([ query.name, *column_titles, *work_package_columns(work_package_parent), *work_package_columns(work_package_child), - "1/1", export_time_formatted, query.name + '1/1', export_time_formatted, query.name ]) end end - describe "with a request for a PDF table grouped" do - let(:query_attributes) { { group_by: "type" } } + describe 'with a request for a PDF table grouped' do + let(:query_attributes) { { group_by: 'type' } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ query.name, work_package_parent.type.name, @@ -156,149 +156,149 @@ def show work_package_child.type.name, *column_titles, *work_package_columns(work_package_child), - "1/1", export_time_formatted, query.name + '1/1', export_time_formatted, query.name ]) end end - describe "with a request for a PDF table grouped with sums" do - let(:query_attributes) { { group_by: "type", display_sums: true } } + describe 'with a request for a PDF table grouped with sums' do + let(:query_attributes) { { group_by: 'type', display_sums: true } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ query.name, work_package_parent.type.name, *column_titles, *work_package_columns(work_package_parent), - I18n.t("js.label_sum"), work_package_parent.story_points.to_s, + I18n.t('js.label_sum'), work_package_parent.story_points.to_s, work_package_child.type.name, *column_titles, *work_package_columns(work_package_child), - I18n.t("js.label_sum"), work_package_child.story_points.to_s, - "1/1", export_time_formatted, query.name + I18n.t('js.label_sum'), work_package_child.story_points.to_s, + '1/1', export_time_formatted, query.name ]) end end - describe "with a request for a PDF table grouped by a custom field with sums" do + describe 'with a request for a PDF table grouped by a custom field with sums' do let(:query_attributes) { { group_by: list_custom_field.column_name, display_sums: true } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ query.name, "Foo", *column_titles, *work_package_columns(work_package_child), - I18n.t("js.label_sum"), work_package_child.story_points.to_s, + I18n.t('js.label_sum'), work_package_child.story_points.to_s, "Foo, Bar", *column_titles, *work_package_columns(work_package_parent), - I18n.t("js.label_sum"), work_package_parent.story_points.to_s, - "1/1", export_time_formatted, query.name + I18n.t('js.label_sum'), work_package_parent.story_points.to_s, + '1/1', export_time_formatted, query.name ]) end end - describe "with a request for a PDF Report" do + describe 'with a request for a PDF Report' do let(:options) { { show_report: true } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ *cover_page_content, query.name, - "1.", "2", work_package_parent.subject, - "2.", "2", work_package_child.subject, - "1/2", export_time_formatted, query.name, + '1.', '2', work_package_parent.subject, + '2.', '2', work_package_child.subject, + '1/2', export_time_formatted, query.name, *work_package_details(work_package_parent, "1"), *work_package_details(work_package_child, "2"), - "2/2", export_time_formatted, query.name + '2/2', export_time_formatted, query.name ]) end end - describe "with a request for a PDF Report with hierarchies" do + describe 'with a request for a PDF Report with hierarchies' do let(:options) { { show_report: true } } let(:query_attributes) { { show_hierarchies: true } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ *cover_page_content, query.name, - "1.", "2", work_package_parent.subject, - "1.1.", "2", work_package_child.subject, - "1/2", export_time_formatted, query.name, - *work_package_details(work_package_parent, "1"), - *work_package_details(work_package_child, "1.1"), - "2/2", export_time_formatted, query.name + '1.', '2', work_package_parent.subject, + '1.1.', '2', work_package_child.subject, + '1/2', export_time_formatted, query.name, + *work_package_details(work_package_parent, '1'), + *work_package_details(work_package_child, '1.1'), + '2/2', export_time_formatted, query.name ]) end end - describe "with a request for a PDF Report with sums" do + describe 'with a request for a PDF Report with sums' do let(:options) { { show_report: true } } let(:query_attributes) { { display_sums: true } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ *cover_page_content, query.name, - "1.", "2", work_package_parent.subject, - "2.", "2", work_package_child.subject, - "1/2", export_time_formatted, query.name, - I18n.t("js.work_packages.tabs.overview"), + '1.', '2', work_package_parent.subject, + '2.', '2', work_package_child.subject, + '1/2', export_time_formatted, query.name, + I18n.t('js.work_packages.tabs.overview'), column_title(:story_points), - I18n.t("js.label_sum"), work_packages_sum.to_s, + I18n.t('js.label_sum'), work_packages_sum.to_s, *work_package_details(work_package_parent, "1"), *work_package_details(work_package_child, "2"), - "2/2", export_time_formatted, query.name + '2/2', export_time_formatted, query.name ]) end end - describe "with a request for a PDF Report grouped with sums" do + describe 'with a request for a PDF Report grouped with sums' do let(:options) { { show_report: true } } - let(:query_attributes) { { display_sums: true, group_by: "type" } } + let(:query_attributes) { { display_sums: true, group_by: 'type' } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ *cover_page_content, query.name, - "1.", "2", work_package_parent.subject, - "2.", "2", work_package_child.subject, - "1/2", export_time_formatted, query.name, - I18n.t("js.work_packages.tabs.overview"), + '1.', '2', work_package_parent.subject, + '2.', '2', work_package_child.subject, + '1/2', export_time_formatted, query.name, + I18n.t('js.work_packages.tabs.overview'), column_title(:type), column_title(:story_points), work_package_parent.type.name, work_package_parent.story_points.to_s, work_package_child.type.name, work_package_child.story_points.to_s, - I18n.t("js.label_sum"), work_packages_sum.to_s, + I18n.t('js.label_sum'), work_packages_sum.to_s, *work_package_details(work_package_parent, "1"), *work_package_details(work_package_child, "2"), - "2/2", export_time_formatted, query.name + '2/2', export_time_formatted, query.name ]) end end - describe "with a request for a PDF Report grouped by a custom field with sums" do + describe 'with a request for a PDF Report grouped by a custom field with sums' do let(:options) { { show_report: true } } let(:query_attributes) { { display_sums: true, group_by: list_custom_field.column_name } } - it "contains correct data" do + it 'contains correct data' do expect(pdf.strings).to eq([ *cover_page_content, query.name, - "1.", "2", work_package_child.subject, - "2.", "2", work_package_parent.subject, - "1/2", export_time_formatted, query.name, - I18n.t("js.work_packages.tabs.overview"), + '1.', '2', work_package_child.subject, + '2.', '2', work_package_parent.subject, + '1/2', export_time_formatted, query.name, + I18n.t('js.work_packages.tabs.overview'), list_custom_field.name.upcase, column_title(:story_points), "Foo", work_package_child.story_points.to_s, "Foo, Bar", work_package_parent.story_points.to_s, - I18n.t("js.label_sum"), work_packages_sum.to_s, + I18n.t('js.label_sum'), work_packages_sum.to_s, *work_package_details(work_package_child, "1"), *work_package_details(work_package_parent, "2"), - "2/2", export_time_formatted, query.name + '2/2', export_time_formatted, query.name ]) end end diff --git a/spec/models/work_packages/pdf_export/work_package_to_pdf_spec.rb b/spec/models/work_packages/pdf_export/work_package_to_pdf_spec.rb index f6fd8f60c8db..0316600ee6fd 100644 --- a/spec/models/work_packages/pdf_export/work_package_to_pdf_spec.rb +++ b/spec/models/work_packages/pdf_export/work_package_to_pdf_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackage::PDFExport::WorkPackageToPdf do include Redmine::I18n @@ -38,7 +38,7 @@ end let(:project) do create(:project, - name: "Foo Bla. Report No. 4/2021 with/for Case 42", + name: 'Foo Bla. Report No. 4/2021 with/for Case 42', types: [type], work_package_custom_fields: [cf_long_text, cf_disabled_in_project, cf_global_bool], work_package_custom_field_ids: [cf_long_text.id, cf_global_bool.id]) # cf_disabled_in_project.id is disabled @@ -52,15 +52,15 @@ let(:image_path) { Rails.root.join("spec/fixtures/files/image.png") } let(:image_attachment) { Attachment.new author: user, file: File.open(image_path) } let(:attachments) { [image_attachment] } - let(:cf_long_text) { create(:issue_custom_field, :text, name: "LongText") } + let(:cf_long_text) { create(:issue_custom_field, :text, name: 'LongText') } let!(:cf_disabled_in_project) do # NOT enabled by project.work_package_custom_field_ids => NOT in PDF - create(:float_wp_custom_field, name: "DisabledCustomField") + create(:float_wp_custom_field, name: 'DisabledCustomField') end let(:cf_global_bool) do create( :work_package_custom_field, - field_format: "bool", + field_format: 'bool', is_for_all: true, default_value: true ) @@ -83,12 +83,12 @@ create(:work_package, project:, type:, - subject: "Work package 1", + subject: 'Work package 1', story_points: 1, description:, custom_values: { - cf_long_text.id => "foo", - cf_disabled_in_project.id => "6.25", + cf_long_text.id => 'foo', + cf_disabled_in_project.id => '6.25', cf_global_bool.id => true }).tap do |wp| allow(wp) @@ -124,8 +124,8 @@ def get_column_value(column_name) end } end - describe "with a request for a PDF" do - it "contains correct data" do + describe 'with a request for a PDF' do + it 'contains correct data' do details = exporter.send(:attributes_data_by_wp, work_package) .flat_map do |item| value = get_column_value(item[:name]) @@ -134,20 +134,20 @@ def get_column_value(column_name) result end # Joining the results for comparison since word wrapping leads to a different array for the same content - result = pdf[:strings].join(" ") + result = pdf[:strings].join(' ') expected_result = [ "#{type.name} ##{work_package.id} - #{work_package.subject}", *details, label_title(:description), - "Lorem", " ", "ipsum", " ", "dolor", " ", "sit", " ", - "amet", ", consetetur sadipscing elitr.", " ", "@OpenProject Admin", - "Image Caption", - "Foo", - "LongText", "foo", - "1", export_time_formatted, project.name - ].join(" ") + 'Lorem', ' ', 'ipsum', ' ', 'dolor', ' ', 'sit', ' ', + 'amet', ', consetetur sadipscing elitr.', ' ', '@OpenProject Admin', + 'Image Caption', + 'Foo', + 'LongText', 'foo', + '1', export_time_formatted, project.name + ].join(' ') expect(result).to eq(expected_result) - expect(result).not_to include("DisabledCustomField") + expect(result).not_to include('DisabledCustomField') expect(pdf[:images].length).to eq(2) end end diff --git a/spec/models/work_packages/scopes/allowed_to_spec.rb b/spec/models/work_packages/scopes/allowed_to_spec.rb index 7346616d0798..775ec723ebd5 100644 --- a/spec/models/work_packages/scopes/allowed_to_spec.rb +++ b/spec/models/work_packages/scopes/allowed_to_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, ".allowed_to" do +RSpec.describe WorkPackage, '.allowed_to' do let(:user) { create(:user) } let!(:private_project) { create(:project, public: false, active: project_status) } @@ -57,28 +57,28 @@ let(:public_non_module_action) { :view_project } let(:non_module_action) { :edit_project } - context "when querying for a permission that does not exist" do - it "raises an error" do + context 'when querying for a permission that does not exist' do + it 'raises an error' do expect do described_class.allowed_to(build(:user), :non_existing_permission) end.to raise_error(Authorization::UnknownPermissionError) end end - context "when querying for a permission that does not apply to the context" do - it "raises an error" do + context 'when querying for a permission that does not apply to the context' do + it 'raises an error' do expect do described_class.allowed_to(build(:user), public_action) end.to raise_error(Authorization::IllegalPermissionContextError) end end - context "when the user is an admin" do + context 'when the user is an admin' do let(:user) { create(:admin) } subject { described_class.allowed_to(user, action) } - it "returns all work packages" do + it 'returns all work packages' do expect(subject).to contain_exactly( work_package_in_public_project, work_package_in_private_project, @@ -86,29 +86,29 @@ ) end - context "when the project is archived" do + context 'when the project is archived' do before do public_project.update!(active: false) private_project.update!(active: false) end - it "returns no work packages" do + it 'returns no work packages' do expect(subject).to be_empty end end - context "when the user is locked" do + context 'when the user is locked' do before do user.locked! end - it "returns no work packages" do + it 'returns no work packages' do expect(subject).to be_empty end end end - context "when the user has the permission directly on the work package" do + context 'when the user has the permission directly on the work package' do let(:work_package_permissions) { [action] } before do @@ -118,33 +118,33 @@ subject { described_class.allowed_to(user, action) } - it "returns the authorized work package" do + it 'returns the authorized work package' do expect(subject).to contain_exactly(work_package_in_private_project) end - context "when the project is archived" do + context 'when the project is archived' do before do public_project.update!(active: false) private_project.update!(active: false) end - it "returns no work packages" do + it 'returns no work packages' do expect(subject).to be_empty end end - context "when the user is locked" do + context 'when the user is locked' do before do user.locked! end - it "returns no work packages" do + it 'returns no work packages' do expect(subject).to be_empty end end end - context "when the user has the permission on the project the work package belongs to" do + context 'when the user has the permission on the project the work package belongs to' do let(:project_permissions) { [action] } before do @@ -153,36 +153,36 @@ subject { described_class.allowed_to(user, action) } - it "returns the authorized work packages" do + it 'returns the authorized work packages' do expect(subject).to contain_exactly( work_package_in_private_project, other_work_package_in_private_project ) end - context "when the project is archived" do + context 'when the project is archived' do before do public_project.update!(active: false) private_project.update!(active: false) end - it "returns no work packages" do + it 'returns no work packages' do expect(subject).to be_empty end end - context "when the user is locked" do + context 'when the user is locked' do before do user.locked! end - it "returns no work packages" do + it 'returns no work packages' do expect(subject).to be_empty end end end - context "when the user has a different permission on the project, but the requested one on a specific work package" do + context 'when the user has a different permission on the project, but the requested one on a specific work package' do let(:project_permissions) { [:view_work_packages] } let(:work_package_permissions) { %i[view_work_packages edit_work_packages] } @@ -191,24 +191,24 @@ create(:member, project: private_project, user:, roles: [project_role]) end - context "and requesting a permission that is only granted on the single work package" do + context 'and requesting a permission that is only granted on the single work package' do subject { described_class.allowed_to(user, :edit_work_packages) } - it "returns the authorized work packages" do + it 'returns the authorized work packages' do expect(subject).to contain_exactly(work_package_in_private_project) end end - context "and requesting a permission that is granted on the project and the work package" do + context 'and requesting a permission that is granted on the project and the work package' do subject { described_class.allowed_to(user, :view_work_packages) } - it "returns the authorized work packages" do + it 'returns the authorized work packages' do expect(subject).to contain_exactly(work_package_in_private_project, other_work_package_in_private_project) end end end - context "when the user is not logged in (anonymous)" do + context 'when the user is not logged in (anonymous)' do let(:user) { User.anonymous } let(:action) { :view_work_packages } @@ -218,24 +218,24 @@ subject { described_class.allowed_to(user, action) } - context "with the anonymous role having the permission" do + context 'with the anonymous role having the permission' do let(:anonymous_permissions) { [action] } - it "returns work packages in the public project" do + it 'returns work packages in the public project' do expect(subject).to contain_exactly(work_package_in_public_project) end end - context "with the anonymous role lacking the permission" do + context 'with the anonymous role lacking the permission' do let(:anonymous_permissions) { [] } - it "is empty" do + it 'is empty' do expect(subject).to be_empty end end end - context "when the user isn`t member in the project" do + context 'when the user isn`t member in the project' do let(:user) { create(:user) } let(:action) { :view_work_packages } @@ -245,18 +245,18 @@ subject { described_class.allowed_to(user, action) } - context "with the non member role having the permission" do + context 'with the non member role having the permission' do let(:non_member_permissions) { [action] } - it "returns work packages in the public project" do + it 'returns work packages in the public project' do expect(subject).to contain_exactly(work_package_in_public_project) end end - context "with the non member role lacking the permission" do + context 'with the non member role lacking the permission' do let(:non_member_permissions) { [] } - it "is empty" do + it 'is empty' do expect(subject).to be_empty end end diff --git a/spec/models/work_packages/scopes/covering_dates_and_days_of_week_spec.rb b/spec/models/work_packages/scopes/covering_dates_and_days_of_week_spec.rb index d1aea82e5521..2e44a3f76c21 100644 --- a/spec/models/work_packages/scopes/covering_dates_and_days_of_week_spec.rb +++ b/spec/models/work_packages/scopes/covering_dates_and_days_of_week_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" +require 'rails_helper' RSpec.describe WorkPackages::Scopes::CoveringDatesAndDaysOfWeek do create_shared_association_defaults_for_work_package_factory shared_let(:next_monday) { Date.current.next_occurring(:monday) } - shared_examples_for "covering days" do + shared_examples_for 'covering days' do # Construct the keyword arguments for the `#covering_dates_and_days_of_week` method. # It builds the expected day values based on the argument type provided (`:dates`, `:days_of_week`) # and based on the day values provided. @@ -49,7 +49,7 @@ end end - it "returns work packages having start date or due date being in the given days of week" do + it 'returns work packages having start date or due date being in the given days of week' do schedule = create_schedule(<<~CHART) days | MTWTFSS | @@ -74,7 +74,7 @@ ) end - it "returns work packages having days between start date and due date being in the given days of week" do + it 'returns work packages having days between start date and due date being in the given days of week' do schedule = create_schedule(<<~CHART) days | MTWTFSS | @@ -91,8 +91,8 @@ ) end - context "if work package ignores non working days" do - it "does not returns it" do + context 'if work package ignores non working days' do + it 'does not returns it' do create_schedule(<<~CHART) days | MTWTFSS | not_covered | XXXXXXX | working days include weekends @@ -103,7 +103,7 @@ end end - it "does not return work packages having follows relation covering the given days of week" do + it 'does not return work packages having follows relation covering the given days of week' do create_schedule(<<~CHART) days | MTWTFSS | not_covered1 | X | @@ -116,7 +116,7 @@ .to eq([]) end - it "does not return work packages having follows relation with delay covering the given days of week" do + it 'does not return work packages having follows relation with delay covering the given days of week' do create_schedule(<<~CHART) days | MTWTFSS | not_covered1 | X | @@ -129,7 +129,7 @@ .to eq([]) end - it "accepts a single day of week or an array of days" do + it 'accepts a single day of week or an array of days' do schedule = create_schedule(<<~CHART) days | MTWTFSS | @@ -148,7 +148,7 @@ end end - context "with the days of week" do + context 'with the days of week' do let(:days) do { days_of_week: { @@ -159,10 +159,10 @@ } end - it_behaves_like "covering days" + it_behaves_like 'covering days' end - context "with specific dates" do + context 'with specific dates' do let(:days) do { dates: { @@ -173,10 +173,10 @@ } end - it_behaves_like "covering days" + it_behaves_like 'covering days' end - context "with days of week and specific dates mixed" do + context 'with days of week and specific dates mixed' do let(:days) do { days_of_week: { wednesday: 3 }, @@ -187,6 +187,6 @@ } end - it_behaves_like "covering days" + it_behaves_like 'covering days' end end diff --git a/spec/models/work_packages/scopes/directly_related_spec.rb b/spec/models/work_packages/scopes/directly_related_spec.rb index 5cf62f66083e..6237128ce7fb 100644 --- a/spec/models/work_packages/scopes/directly_related_spec.rb +++ b/spec/models/work_packages/scopes/directly_related_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::Scopes::DirectlyRelated, ".directly_related scope" do +RSpec.describe WorkPackages::Scopes::DirectlyRelated, '.directly_related scope' do create_shared_association_defaults_for_work_package_factory shared_let(:origin) { create(:work_package) } @@ -68,7 +68,7 @@ subject(:directly_related) { WorkPackage.directly_related(origin, ignored_relation: ignored_relations) } - it "is an AR scope" do + it 'is an AR scope' do expect(directly_related) .to be_a ActiveRecord::Relation end @@ -77,7 +77,7 @@ let(:relation_type) { current_type } context "with existing relations of type '#{current_type}'" do - it "contains the directly related work packages in both directions" do + it 'contains the directly related work packages in both directions' do expect(directly_related) .to contain_exactly(related_work_package_to, related_work_package_from) end @@ -86,7 +86,7 @@ context "with existing relations of type '#{current_type}' and ignoring one relation" do let(:ignored_relations) { relation_to } - it "contains the directly related work packages for which the relation isn`t ignored" do + it 'contains the directly related work packages for which the relation isn`t ignored' do expect(directly_related) .to contain_exactly(related_work_package_from) end diff --git a/spec/models/work_packages/scopes/for_scheduling_spec.rb b/spec/models/work_packages/scopes/for_scheduling_spec.rb index 2967f5f8aa42..7f99d65c51ce 100644 --- a/spec/models/work_packages/scopes/for_scheduling_spec.rb +++ b/spec/models/work_packages/scopes/for_scheduling_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::Scopes::ForScheduling, "allowed scope" do +RSpec.describe WorkPackages::Scopes::ForScheduling, 'allowed scope' do create_shared_association_defaults_for_work_package_factory let(:project) { create(:project) } @@ -92,418 +92,418 @@ end let(:blocker) do create(:work_package, project:).tap do |blo| - create(:relation, relation_type: "blocks", from: blo, to: origin) + create(:relation, relation_type: 'blocks', from: blo, to: origin) end end let(:includer) do create(:work_package, project:).tap do |inc| - create(:relation, relation_type: "includes", from: inc, to: origin) + create(:relation, relation_type: 'includes', from: inc, to: origin) end end let(:existing_work_packages) { [] } - describe ".for_scheduling" do - it "is a AR scope" do + describe '.for_scheduling' do + it 'is a AR scope' do expect(WorkPackage.for_scheduling([origin])) .to be_a ActiveRecord::Relation end - context "for an empty array" do - it "is empty" do + context 'for an empty array' do + it 'is empty' do expect(WorkPackage.for_scheduling([])) .to be_empty end end - context "for a work package with a predecessor" do + context 'for a work package with a predecessor' do let!(:existing_work_packages) { [predecessor] } - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "for a work package with a parent" do + context 'for a work package with a parent' do let!(:existing_work_packages) { [parent] } - it "consists of the parent" do + it 'consists of the parent' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(parent) end end - context "for a work package with a successor" do + context 'for a work package with a successor' do let!(:existing_work_packages) { [successor] } - it "consists of the successor" do + it 'consists of the successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor) end end - context "for a work package with a blocking work package" do + context 'for a work package with a blocking work package' do let!(:existing_work_packages) { [blocker] } - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "for a work package with an including work package" do + context 'for a work package with an including work package' do let!(:existing_work_packages) { [includer] } - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "for a work package with a successor which has parent and child" do + context 'for a work package with a successor which has parent and child' do let!(:existing_work_packages) { [successor, successor_child, successor_parent] } - context "with all scheduled automatically" do - it "consists of the successor, its child and parent" do + context 'with all scheduled automatically' do + it 'consists of the successor, its child and parent' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_parent) end end - context "with successor scheduled manually" do + context 'with successor scheduled manually' do before do successor.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "with the successor's parent scheduled manually" do + context 'with the successor\'s parent scheduled manually' do before do successor_parent.update_column(:schedule_manually, true) end - it "consists of the successor and its child" do + it 'consists of the successor and its child' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child) end end - context "with successor's child scheduled manually" do + context 'with successor\'s child scheduled manually' do before do successor_child.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end end - context "for a work package with a successor having a parent and child and a successor of its own which is a child itself" do + context 'for a work package with a successor having a parent and child and a successor of its own which is a child itself' do let!(:existing_work_packages) { [successor, successor_child, successor_parent, successor_successor] } before do successor_successor.update(parent: successor_parent) end - context "with all scheduled automatically" do - it "consists of the successor, its child and parent and the successor successor" do + context 'with all scheduled automatically' do + it 'consists of the successor, its child and parent and the successor successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_parent, successor_successor) end end - context "with successor parent scheduled manually" do + context 'with successor parent scheduled manually' do before do successor_parent.update_column(:schedule_manually, true) end - it "consists of the successor, its child and successor successor" do + it 'consists of the successor, its child and successor successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_successor) end end - context "with successor's child scheduled manually" do + context 'with successor\'s child scheduled manually' do before do successor_child.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end end - context "for a work package with a successor which has parent and the parent has a follows relationship itself" do + context 'for a work package with a successor which has parent and the parent has a follows relationship itself' do let!(:existing_work_packages) { [successor, successor_parent] } before do create(:follows_relation, from: successor_parent, to: origin) end - context "with all scheduled automatically" do - it "consists of the successor, its child and parent" do + context 'with all scheduled automatically' do + it 'consists of the successor, its child and parent' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_parent) end end - context "with successor scheduled manually" do + context 'with successor scheduled manually' do before do successor.update_column(:schedule_manually, true) end - it "is empty (hierarchy over relationships)" do + it 'is empty (hierarchy over relationships)' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "with the successor's parent scheduled manually" do + context 'with the successor\'s parent scheduled manually' do before do successor_parent.update_column(:schedule_manually, true) end - it "consists of the successor" do + it 'consists of the successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor) end end - context "with both scheduled manually" do + context 'with both scheduled manually' do before do successor.update_column(:schedule_manually, true) successor_parent.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end end - context "for a work package with a successor with two children and the successor having a successor" do + context 'for a work package with a successor with two children and the successor having a successor' do let!(:existing_work_packages) { [successor, successor_child, successor_child2, successor_successor] } - context "with all scheduled automatically" do - it "consists of the successor, its child and the successor˚s successor" do + context 'with all scheduled automatically' do + it 'consists of the successor, its child and the successor˚s successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_child2, successor_successor) end end - context "with one of the successor`s children scheduled manually" do + context 'with one of the successor`s children scheduled manually' do before do successor_child2.update_column(:schedule_manually, true) end - it "consists of the successor, its automatically scheduled child and the successor˚s successor" do + it 'consists of the successor, its automatically scheduled child and the successor˚s successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor_child, successor, successor_successor) end end - context "with both of the successor`s children scheduled manually" do + context 'with both of the successor`s children scheduled manually' do before do successor_child.update_column(:schedule_manually, true) successor_child2.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end end - context "for a work package with a parent and grandparent" do + context 'for a work package with a parent and grandparent' do let!(:existing_work_packages) { [parent, grandparent] } - it "consists of the parent, grandparent" do + it 'consists of the parent, grandparent' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(parent, grandparent) end end - context "for a work package with a parent which has a successor" do + context 'for a work package with a parent which has a successor' do let!(:existing_work_packages) { [parent, parent_successor] } - it "consists of the parent, parent successor" do + it 'consists of the parent, parent successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(parent, parent_successor) end end - context "for a work package with a parent which has a successor which has parent and child" do + context 'for a work package with a parent which has a successor which has parent and child' do let!(:existing_work_packages) { [parent, parent_successor, parent_successor_child, parent_successor_parent] } - context "with all scheduled automatically" do - it "consists of the parent, self and the whole parent successor hierarchy" do + context 'with all scheduled automatically' do + it 'consists of the parent, self and the whole parent successor hierarchy' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(parent, parent_successor, parent_successor_parent, parent_successor_child) end end - context "with the parent successor scheduled manually" do + context 'with the parent successor scheduled manually' do before do parent_successor.update_column(:schedule_manually, true) end - it "consists of the parent" do + it 'consists of the parent' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(parent) end end - context "with the parent scheduled manually" do + context 'with the parent scheduled manually' do before do parent.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "with the parent successor's child scheduled manually" do + context 'with the parent successor\'s child scheduled manually' do before do parent_successor_child.update_column(:schedule_manually, true) end - it "contains the parent and self" do + it 'contains the parent and self' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(parent) end end end - context "for a work package with a successor that has a successor" do + context 'for a work package with a successor that has a successor' do let!(:existing_work_packages) { [successor, successor_successor] } - context "with all scheduled automatically" do - it "consists of both successors" do + context 'with all scheduled automatically' do + it 'consists of both successors' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_successor) end end - context "with the successor scheduled manually" do + context 'with the successor scheduled manually' do before do successor.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "with the successor's successor scheduled manually" do + context 'with the successor\'s successor scheduled manually' do before do successor_successor.update_column(:schedule_manually, true) end - it "contains the successor" do + it 'contains the successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor) end end end - context "for a work package with a successor that has a child and grandchild" do + context 'for a work package with a successor that has a child and grandchild' do let!(:existing_work_packages) { [successor, successor_child, successor_grandchild] } - context "with all scheduled automatically" do - it "consists of both successors" do + context 'with all scheduled automatically' do + it 'consists of both successors' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_grandchild) end end - context "with the successor's child scheduled manually" do + context 'with the successor\'s child scheduled manually' do before do successor_child.update_column(:schedule_manually, true) end - it "contains the successor" do + it 'contains the successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor) end end end - context "for a work package with a successor that has a child and two grandchildren" do + context 'for a work package with a successor that has a child and two grandchildren' do let(:successor_grandchild2) do create(:work_package, project:, parent: successor_child) end let!(:existing_work_packages) { [successor, successor_child, successor_grandchild, successor_grandchild2] } - context "with all scheduled automatically" do - it "consists of the successor with its descendants" do + context 'with all scheduled automatically' do + it 'consists of the successor with its descendants' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_grandchild, successor_grandchild2) end end - context "with one of the successor's grandchildren scheduled manually" do + context 'with one of the successor\'s grandchildren scheduled manually' do before do successor_grandchild.update_column(:schedule_manually, true) end - it "contains the successor and the non automatically scheduled descendants" do + it 'contains the successor and the non automatically scheduled descendants' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, successor_child, successor_grandchild2) end end - context "with both of the successor's grandchildren scheduled manually" do + context 'with both of the successor\'s grandchildren scheduled manually' do before do successor_grandchild.update_column(:schedule_manually, true) successor_grandchild2.update_column(:schedule_manually, true) end - it "includes successor" do + it 'includes successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor) end end - context "with both of the successor's grandchildren and child scheduled manually" do + context 'with both of the successor\'s grandchildren and child scheduled manually' do before do successor_child.update_column(:schedule_manually, true) successor_grandchild.update_column(:schedule_manually, true) successor_grandchild2.update_column(:schedule_manually, true) end - it "is empty" do + it 'is empty' do expect(WorkPackage.for_scheduling([origin])) .to be_empty end end - context "with the successor's child scheduled manually" do + context 'with the successor\'s child scheduled manually' do before do successor_child.update_column(:schedule_manually, true) end - it "contains the successor" do + it 'contains the successor' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor) end end end - context "for a work package with a sibling and a successor that also has a sibling" do + context 'for a work package with a sibling and a successor that also has a sibling' do let(:sibling) do create(:work_package, project:, parent:) end @@ -513,7 +513,7 @@ let!(:existing_work_packages) { [parent, sibling, successor, successor_parent, successor_sibling] } - it "contains the successor and the parents but not the siblings" do + it 'contains the successor and the parents but not the siblings' do expect(WorkPackage.for_scheduling([origin])) .to contain_exactly(successor, parent, successor_parent) end diff --git a/spec/models/work_packages/scopes/involving_user_spec.rb b/spec/models/work_packages/scopes/involving_user_spec.rb index e07b13715176..6c12206d97a6 100644 --- a/spec/models/work_packages/scopes/involving_user_spec.rb +++ b/spec/models/work_packages/scopes/involving_user_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::Scopes::InvolvingUser do create_shared_association_defaults_for_work_package_factory @@ -39,7 +39,7 @@ ) end - it "returns work packages for which a user is assigned to" do + it 'returns work packages for which a user is assigned to' do _work_package_blank = create(:work_package) work_package_assigned1 = create(:work_package, assigned_to: user) work_package_assigned2 = create(:work_package, assigned_to: user) @@ -48,7 +48,7 @@ .to contain_exactly(work_package_assigned1, work_package_assigned2) end - it "returns work packages for which a user is accountable / responsible" do + it 'returns work packages for which a user is accountable / responsible' do _work_package_blank = create(:work_package) work_package_responsible1 = create(:work_package, responsible: user) work_package_responsible2 = create(:work_package, responsible: user) @@ -57,7 +57,7 @@ .to contain_exactly(work_package_responsible1, work_package_responsible2) end - it "returns work packages for which a user is a watcher" do + it 'returns work packages for which a user is a watcher' do _work_package_blank = create(:work_package) work_package_watched1 = create(:work_package) create(:watcher, watchable: work_package_watched1, user:) @@ -68,10 +68,10 @@ .to contain_exactly(work_package_watched1, work_package_watched2) end - context "when user is part of a group" do + context 'when user is part of a group' do shared_let(:group) { create(:group, members: [user]) } - it "returns work packages for which the group is assigned to" do + it 'returns work packages for which the group is assigned to' do _work_package_blank = create(:work_package) work_package_assigned = create(:work_package, assigned_to: group) @@ -79,7 +79,7 @@ .to contain_exactly(work_package_assigned) end - it "returns work packages for which the group is accountable / responsible" do + it 'returns work packages for which the group is accountable / responsible' do _work_package_blank = create(:work_package) work_package_responsible = create(:work_package, responsible: group) diff --git a/spec/models/work_packages/scopes/relatable_spec.rb b/spec/models/work_packages/scopes/relatable_spec.rb index 2f55caee1af8..17e03639f714 100644 --- a/spec/models/work_packages/scopes/relatable_spec.rb +++ b/spec/models/work_packages/scopes/relatable_spec.rb @@ -24,9 +24,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::Scopes::Relatable, ".relatable scope" do +RSpec.describe WorkPackages::Scopes::Relatable, '.relatable scope' do create_shared_association_defaults_for_work_package_factory let(:origin) { create(:work_package) } @@ -77,29 +77,29 @@ subject(:relatable) { WorkPackage.relatable(origin, relation_type, ignored_relation:) } - it "is an AR scope" do + it 'is an AR scope' do expect(relatable) .to be_a ActiveRecord::Relation end - context "for an unpersisted work package" do + context 'for an unpersisted work package' do let(:origin) { WorkPackage.new } let!(:existing_work_packages) { [unrelated_work_package] } - it "contains every other work package" do + it 'contains every other work package' do expect(relatable) .to contain_exactly(unrelated_work_package) end end - context "with a completely unrelated work package" do + context 'with a completely unrelated work package' do let!(:existing_work_packages) { [unrelated_work_package] } Relation::TYPES.each_key do |current_type| context "for the '#{current_type}' type" do let(:relation_type) { current_type } - it "contains the unrelated_work_package" do + it 'contains the unrelated_work_package' do expect(relatable) .to contain_exactly(unrelated_work_package) end @@ -110,7 +110,7 @@ let(:relation_type) { current_type } let(:unrelated_work_package) { create(:work_package, project: create(:project)) } - it "contains the unrelated_work_package" do + it 'contains the unrelated_work_package' do expect(relatable) .to be_empty end @@ -121,7 +121,7 @@ let(:relation_type) { current_type } let(:unrelated_work_package) { create(:work_package, project: create(:project)) } - it "contains the unrelated_work_package" do + it 'contains the unrelated_work_package' do expect(relatable) .to contain_exactly(unrelated_work_package) end @@ -129,14 +129,14 @@ end end - context "with a directly related work package" do + context 'with a directly related work package' do let!(:existing_work_packages) { [directly_related_work_package] } Relation::TYPES.each_key do |current_type| context "with the existing relation and the queried being '#{current_type}' typed" do let(:relation_type) { current_type } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -146,7 +146,7 @@ let(:relation_type) { current_type } let(:directly_related_work_package_type) { Relation::TYPES.keys[(Relation::TYPES.keys.find_index(current_type) + 1)] } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -156,7 +156,7 @@ let(:relation_type) { current_type } let(:ignored_relation) { directly_related_work_package.relations.first } - it "contains the directly related work package" do + it 'contains the directly related work package' do expect(relatable) .to contain_exactly directly_related_work_package end @@ -164,14 +164,14 @@ end end - context "with a parent and a sibling" do + context 'with a parent and a sibling' do let!(:existing_work_packages) { [parent, sibling] } Relation::TYPES.each_key do |current_type| context "for the '#{current_type}' type" do let(:relation_type) { current_type } - it "contains the sibling" do + it 'contains the sibling' do expect(relatable) .to contain_exactly(sibling) end @@ -179,11 +179,11 @@ end end - context "with a transitively related work package" do + context 'with a transitively related work package' do let!(:existing_work_packages) { [directly_related_work_package, transitively_related_work_package] } context "for a 'follows' relation and the existing relations being in the same direction" do - it "contains the transitively related work package" do + it 'contains the transitively related work package' do expect(relatable) .to contain_exactly(transitively_related_work_package) end @@ -193,7 +193,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_PRECEDES } let(:transitively_related_work_package_type) { Relation::TYPE_PRECEDES } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -204,7 +204,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_FOLLOWS } let(:transitively_related_work_package_type) { Relation::TYPE_FOLLOWS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -219,7 +219,7 @@ # complicated to switch around the relations subject(:relatable) { WorkPackage.relatable(transitively_related_work_package, relation_type) } - it "includes the not directly related work package" do + it 'includes the not directly related work package' do expect(relatable) .to contain_exactly(origin) end @@ -230,7 +230,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_FOLLOWS } let(:transitively_related_work_package_type) { Relation::TYPE_FOLLOWS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -241,7 +241,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_PRECEDES } let(:transitively_related_work_package_type) { Relation::TYPE_PRECEDES } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -252,7 +252,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_FOLLOWS } let(:transitively_related_work_package_type) { Relation::TYPE_FOLLOWS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -263,7 +263,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_PRECEDES } let(:transitively_related_work_package_type) { Relation::TYPE_PRECEDES } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -277,7 +277,7 @@ # This leads to a relationship that, on the domain level does not really make sense where at least # transitively, the child blocks the parent. But since such a relation does not strictly carry that # semantic in the system, the relationship is not prohibited. - it "contains the transitively related work package" do + it 'contains the transitively related work package' do expect(relatable) .to contain_exactly(transitively_related_work_package) end @@ -288,7 +288,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_BLOCKS } let(:transitively_related_work_package_type) { Relation::TYPE_BLOCKS } - it "contains the transitively related work package" do + it 'contains the transitively related work package' do expect(relatable) .to contain_exactly(transitively_related_work_package) end @@ -302,7 +302,7 @@ # This leads to a relationship that, on the domain level does not really make sense where at least # transitively, the parent blocks the child. But since such a relation does not strictly carry that # semantic in the system, the relationship is not prohibited. - it "contains the transitively related work package" do + it 'contains the transitively related work package' do expect(relatable) .to contain_exactly(transitively_related_work_package) end @@ -314,7 +314,7 @@ let(:transitively_related_work_package_type) { Relation::TYPE_BLOCKS } let(:ignored_relation) { origin.relations.first } - it "contains the related work packages" do + it 'contains the related work packages' do expect(relatable) .to contain_exactly(directly_related_work_package, transitively_related_work_package) end @@ -325,7 +325,7 @@ let(:transitively_related_work_package_type) { Relation::TYPE_PRECEDES } let(:ignored_relation) { origin.relations.first } - it "contains the related work packages" do + it 'contains the related work packages' do expect(relatable) .to contain_exactly(directly_related_work_package, transitively_related_work_package) end @@ -339,7 +339,7 @@ context "for a '#{current_type}' type" do let(:relation_type) { current_type } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -362,7 +362,7 @@ let(:existing_relation_type) { Relation::TYPE_FOLLOWS } let(:relation_type) { Relation::TYPE_FOLLOWS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -373,7 +373,7 @@ let(:existing_relation_type) { Relation::TYPE_PRECEDES } let(:relation_type) { Relation::TYPE_FOLLOWS } - it "contains the work packages in the other hierarchy" do + it 'contains the work packages in the other hierarchy' do expect(relatable) .to contain_exactly(other_parent, other_child) end @@ -384,7 +384,7 @@ let(:existing_relation_type) { Relation::TYPE_BLOCKED } let(:relation_type) { Relation::TYPE_BLOCKS } - it "contains the work packages in the other hierarchy" do + it 'contains the work packages in the other hierarchy' do expect(relatable) .to contain_exactly(other_parent, other_child) end @@ -394,20 +394,20 @@ let(:existing_relation_type) { Relation::TYPE_BLOCKS } let(:relation_type) { Relation::TYPE_BLOCKS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end end end - context "with a child, parent, grandparent and aunt" do + context 'with a child, parent, grandparent and aunt' do let!(:existing_work_packages) { [origin, origin_child, parent, grandparent, aunt] } context "for a 'parent' relation" do let(:relation_type) { Relation::TYPE_PARENT } - it "contains grandparent and aunt" do + it 'contains grandparent and aunt' do expect(relatable) .to contain_exactly(grandparent, aunt) end @@ -416,7 +416,7 @@ context "for a 'child' relation" do let(:relation_type) { Relation::TYPE_CHILD } - it "contains aunt" do + it 'contains aunt' do expect(relatable) .to contain_exactly(aunt) end @@ -425,7 +425,7 @@ context "for a 'follows' relation" do let(:relation_type) { Relation::TYPE_FOLLOWS } - it "contains aunt" do + it 'contains aunt' do expect(relatable) .to contain_exactly(aunt) end @@ -434,7 +434,7 @@ context "for a 'blocks' relation" do let(:relation_type) { Relation::TYPE_BLOCKS } - it "contains aunt" do + it 'contains aunt' do expect(relatable) .to contain_exactly(aunt) end @@ -447,7 +447,7 @@ create(:follows_relation, from: origin_child, to: aunt) end - it "contains grandparent" do + it 'contains grandparent' do expect(relatable) .to contain_exactly(grandparent) end @@ -460,7 +460,7 @@ create(:follows_relation, from: origin_child, to: aunt) end - it "contains aunt" do + it 'contains aunt' do expect(relatable) .to contain_exactly(aunt) end @@ -473,7 +473,7 @@ create(:follows_relation, from: origin_child, to: aunt) end - it "contains aunt and grandparent" do + it 'contains aunt and grandparent' do expect(relatable) .to contain_exactly(aunt, grandparent) end @@ -482,14 +482,14 @@ context "for a 'relates' relation" do let(:relation_type) { Relation::TYPE_RELATES } - it "contains aunt and grandparent" do + it 'contains aunt and grandparent' do expect(relatable) .to contain_exactly(aunt, grandparent) end end end - context "with an ancestor chain of 3 work packages" do + context 'with an ancestor chain of 3 work packages' do let(:grand_grandparent) do create(:work_package).tap do |par| grandparent.update(parent: par) @@ -501,7 +501,7 @@ context "for a 'parent' relation" do let(:relation_type) { Relation::TYPE_PARENT } - it "contains grandparent and grand_grandparent" do + it 'contains grandparent and grand_grandparent' do expect(relatable) .to contain_exactly(grandparent, grand_grandparent) end @@ -510,7 +510,7 @@ context "for a 'child' relation" do let(:relation_type) { Relation::TYPE_CHILD } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -519,7 +519,7 @@ context "for a 'follows' relation" do let(:relation_type) { Relation::TYPE_FOLLOWS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -528,14 +528,14 @@ context "for a 'blocks' relation" do let(:relation_type) { Relation::TYPE_BLOCKS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end end end - context "with a descendant chain of 3 work packages" do + context 'with a descendant chain of 3 work packages' do let(:grandchild) do create(:work_package, parent: origin_child) end @@ -548,7 +548,7 @@ context "for a 'parent' relation" do let(:relation_type) { Relation::TYPE_PARENT } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -557,7 +557,7 @@ context "for a 'child' relation" do let(:relation_type) { Relation::TYPE_CHILD } - it "contains grandchild and grand_grandchild" do + it 'contains grandchild and grand_grandchild' do expect(relatable) .to contain_exactly(grandchild, grand_grandchild) end @@ -566,7 +566,7 @@ context "for a 'follows' relation" do let(:relation_type) { Relation::TYPE_FOLLOWS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -575,14 +575,14 @@ context "for a 'blocks' relation" do let(:relation_type) { Relation::TYPE_BLOCKS } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end end end - context "with a predecessor having a parent" do + context 'with a predecessor having a parent' do let(:predecessor_parent) do create(:work_package) end @@ -612,7 +612,7 @@ end end - context "with two predecessors being in a hierarchy" do + context 'with two predecessors being in a hierarchy' do let(:predecessor_parent) do create(:work_package).tap do |pre| create(:relation, from: origin, to: pre, relation_type: Relation::TYPE_FOLLOWS) @@ -644,7 +644,7 @@ end end - context "with a predecessor having a parent that has a predecessor" do + context 'with a predecessor having a parent that has a predecessor' do let(:predecessor_parent_predecessor) do create(:work_package).tap do |pre| create(:relation, from: predecessor_parent, to: pre, relation_type: Relation::TYPE_FOLLOWS) @@ -672,7 +672,7 @@ context "for a 'child' relation" do let(:relation_type) { Relation::TYPE_CHILD } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -724,7 +724,7 @@ end end - context "with a predecessor having a parent that has a successor" do + context 'with a predecessor having a parent that has a successor' do let(:predecessor_parent_successor) do create(:work_package).tap do |suc| create(:relation, to: predecessor_parent, from: suc, relation_type: Relation::TYPE_FOLLOWS) @@ -804,7 +804,7 @@ end end - context "with a successor having a parent that has a successor" do + context 'with a successor having a parent that has a successor' do let(:successor_parent_successor) do create(:work_package).tap do |suc| create(:relation, to: successor_parent, from: suc, relation_type: Relation::TYPE_FOLLOWS) @@ -884,7 +884,7 @@ end end - context "with a successor having a parent that has a predecessor" do + context 'with a successor having a parent that has a predecessor' do let(:successor_parent_predecessor) do create(:work_package).tap do |pre| create(:relation, from: successor_parent, to: pre, relation_type: Relation::TYPE_FOLLOWS) @@ -964,7 +964,7 @@ end end - context "with a parent that has a predecessor" do + context 'with a parent that has a predecessor' do let(:parent_predecessor) do create(:work_package).tap do |pre| create(:follows_relation, from: parent, to: pre) @@ -1027,7 +1027,7 @@ end end - context "with a parent that has a successor" do + context 'with a parent that has a successor' do let(:parent_successor) do create(:work_package).tap do |suc| create(:follows_relation, to: parent, from: suc) @@ -1090,7 +1090,7 @@ end end - context "with a child that has a successor that has a parent and a grandparent" do + context 'with a child that has a successor that has a parent and a grandparent' do let(:child_successor) do create(:work_package, parent: child_successor_parent).tap do |suc| create(:follows_relation, from: suc, to: origin_child) @@ -1150,7 +1150,7 @@ end end - context "with a child that has a predecessor that has a parent and a grandparent" do + context 'with a child that has a predecessor that has a parent and a grandparent' do let(:child_predecessor) do create(:work_package, parent: child_predecessor_parent).tap do |pre| create(:follows_relation, from: origin_child, to: pre) @@ -1210,7 +1210,7 @@ end end - context "with a child that blocks a work package that has a parent and a grandparent" do + context 'with a child that blocks a work package that has a parent and a grandparent' do let(:child_blocked) do create(:work_package, parent: child_blocked_parent).tap do |wp| create(:relation, relation_type: Relation::TYPE_BLOCKS, from: origin_child, to: wp) @@ -1288,7 +1288,7 @@ end end - context "with a predecessor that has a child" do + context 'with a predecessor that has a child' do let(:predecessor_child) do create(:work_package, parent: predecessor) end @@ -1363,7 +1363,7 @@ end end - context "with a blocks work package that has a child and a parent" do + context 'with a blocks work package that has a child and a parent' do let(:blocks_child) do create(:work_package, parent: blocks) end @@ -1414,7 +1414,7 @@ end end - context "with a blocked work package that has a child and a parent" do + context 'with a blocked work package that has a child and a parent' do let(:blocked_child) do create(:work_package, parent: blocked) end @@ -1465,7 +1465,7 @@ end end - context "with a predecessor chain where the first has parent and child and that child has a predecessor" do + context 'with a predecessor chain where the first has parent and child and that child has a predecessor' do let(:direct_predecessor) do create(:work_package).tap do |pre| create(:follows_relation, from: origin, to: pre) @@ -1514,7 +1514,7 @@ end end - context "with a successor chain where the last has parent and child" do + context 'with a successor chain where the last has parent and child' do let(:direct_successor) do create(:work_package).tap do |suc| create(:follows_relation, to: origin, from: suc) @@ -1554,7 +1554,7 @@ end end - context "with a transitively related work package that is also directly related" do + context 'with a transitively related work package that is also directly related' do let!(:existing_work_packages) { [directly_related_work_package, transitively_related_work_package] } let!(:additional_direct_relation) do create(:relation, @@ -1564,7 +1564,7 @@ end context "for a 'follows' relation and the existing relations being in the same direction" do - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -1574,7 +1574,7 @@ let(:directly_related_work_package_type) { Relation::TYPE_PRECEDES } let(:transitively_related_work_package_type) { Relation::TYPE_PRECEDES } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end @@ -1585,27 +1585,27 @@ let(:transitively_related_work_package_type) { Relation::TYPE_PRECEDES } let(:ignored_relation) { additional_direct_relation } - it "is empty" do + it 'is empty' do expect(relatable) .to be_empty end end end - context "when ignoring anything else than a single relation" do + context 'when ignoring anything else than a single relation' do let(:ignored_relation) { transitively_related_work_package.relations } - it "raises an error" do + it 'raises an error' do expect { relatable } .to raise_error ArgumentError end end - context "when ignoring with a relation neither starting nor ending in the work package queried for" do + context 'when ignoring with a relation neither starting nor ending in the work package queried for' do let!(:existing_work_packages) { [directly_related_work_package, transitively_related_work_package] } let(:ignored_relation) { transitively_related_work_package.relations.first } - it "raises an error" do + it 'raises an error' do expect { relatable } .to raise_error ArgumentError end diff --git a/spec/models/work_packages/search_spec.rb b/spec/models/work_packages/search_spec.rb index 3dcd197ecfa9..947ff789bdda 100644 --- a/spec/models/work_packages/search_spec.rb +++ b/spec/models/work_packages/search_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "search" do +RSpec.describe WorkPackage, 'search' do shared_let(:description_searchword) { "descKeyword" } shared_let(:project) { create(:project) } shared_let(:work_package) do @@ -36,31 +36,31 @@ end let(:permissions) { [:view_work_packages] } - let(:searchword) { "keyword" } + let(:searchword) { 'keyword' } current_user { create(:user, member_with_permissions: { project => permissions }) } subject { described_class.search("%#{searchword}%").first } - context "with the keyword being in the description" do + context 'with the keyword being in the description' do let(:searchword) { description_searchword } - it "finds the work package" do + it 'finds the work package' do expect(subject) .to eq [work_package] end - context "when lacking the permissions to see the work package" do + context 'when lacking the permissions to see the work package' do let(:permissions) { [] } - it "does not find the work package" do + it 'does not find the work package' do expect(subject) .to be_empty end end end - context "with multiple hits in journals", with_settings: { journal_aggregation_time_minutes: 0 } do + context 'with multiple hits in journals', with_settings: { journal_aggregation_time_minutes: 0 } do before do # Adding two journals with the keyword in it work_package.journals.first.update_column(:notes, "A note with the #{searchword} in it.") @@ -69,7 +69,7 @@ work_package.save end - it "finds the work package" do + it 'finds the work package' do expect(subject) .to eq [work_package] end diff --git a/spec/models/work_packages/spent_time_spec.rb b/spec/models/work_packages/spent_time_spec.rb index 4266406b77c5..760946afe08b 100644 --- a/spec/models/work_packages/spent_time_spec.rb +++ b/spec/models/work_packages/spent_time_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackage, "spent_time" do +RSpec.describe WorkPackage, 'spent_time' do let(:project) do work_package.project end @@ -89,26 +89,26 @@ login_as user end - shared_examples_for "spent hours" do - it "has the spent time of the time entry" do + shared_examples_for 'spent hours' do + it 'has the spent time of the time entry' do expect(subject).to eql time_entry.hours end - it "sums up the spent time of the time entries" do + it 'sums up the spent time of the time entries' do sum = time_entry.hours + time_entry2.hours expect(subject).to eql sum end - it "inherits the spent time of the descendants" do + it 'inherits the spent time of the descendants' do sum = time_entry.hours + child_time_entry.hours expect(subject).to eql sum end - context "permissions" do - it "counts the child if that child is in a project in which the user " + - "has the necessary permissions" do + context 'permissions' do + it 'counts the child if that child is in a project in which the user ' + + 'has the necessary permissions' do create(:member, user:, project: other_project, @@ -119,8 +119,8 @@ expect(subject).to eql sum end - it "does not count the child if that child is in a project in which the user " + - "lacks the view_time_entries permission" do + it 'does not count the child if that child is in a project in which the user ' + + 'lacks the view_time_entries permission' do create(:member, user:, project: other_project, @@ -132,8 +132,8 @@ expect(subject).to eql sum end - it "does not count the child if that child is in a project in which the user " + - "lacks the view_work_packages permission" do + it 'does not count the child if that child is in a project in which the user ' + + 'lacks the view_work_packages permission' do create(:member, user:, project: other_project, @@ -147,15 +147,15 @@ end end - context "for a work_package loaded individually" do + context 'for a work_package loaded individually' do subject { work_package.spent_hours } - it_behaves_like "spent hours" + it_behaves_like 'spent hours' end - context "for a work package that had spent time eager loaded" do + context 'for a work package that had spent time eager loaded' do subject { WorkPackage.include_spent_time(user).where(id: work_package.id).first.spent_hours } - it_behaves_like "spent hours" + it_behaves_like 'spent hours' end end diff --git a/spec/models/workflow_spec.rb b/spec/models/workflow_spec.rb index f70914e5dfb2..c8e9edb56bc0 100644 --- a/spec/models/workflow_spec.rb +++ b/spec/models/workflow_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Workflow do - describe ".copy" do + describe '.copy' do shared_let(:status0) { create(:status) } shared_let(:status1) { create(:status) } shared_let(:role) { create(:project_role) } @@ -39,7 +39,7 @@ shared_let(:role_target2) { create(:project_role) } shared_let(:type_target2) { create(:type) } - shared_examples_for "copied workflow" do + shared_examples_for 'copied workflow' do let(:expected_type) { type_target } let(:expected_role) { role_target } @@ -56,7 +56,7 @@ it { expect(subject.assignee).to eq(workflow_src.assignee) } end - context "for a workflow w/o author or assignee" do + context 'for a workflow w/o author or assignee' do let!(:workflow_src) do create(:workflow, old_status: status0, @@ -67,12 +67,12 @@ before { described_class.copy(type, role, type_target, role_target) } - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("id DESC")).first } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('id DESC')).first } end end - context "for a workflow with author" do + context 'for a workflow with author' do let!(:workflow_src) do create(:workflow, old_status: status0, @@ -84,12 +84,12 @@ before { described_class.copy(type, role, type_target, role_target) } - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("id DESC")).first } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('id DESC')).first } end end - context "for a workflow with assignee" do + context 'for a workflow with assignee' do let!(:workflow_src) do create(:workflow, old_status: status0, @@ -101,12 +101,12 @@ before { described_class.copy(type, role, type_target, role_target) } - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("id DESC")).first } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('id DESC')).first } end end - context "when copying to multiple types and roles" do + context 'when copying to multiple types and roles' do let!(:workflow_src) do create(:workflow, old_status: status0, @@ -117,29 +117,29 @@ before { described_class.copy(type, role, [type_target, type_target2], [role_target, role_target2]) } - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("type_id DESC, role_id DESC")).first } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).first } let(:expected_role) { role_target2 } let(:expected_type) { type_target2 } end - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("type_id DESC, role_id DESC")).second } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).second } let(:expected_role) { role_target } let(:expected_type) { type_target2 } end - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("type_id DESC, role_id DESC")).third } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).third } let(:expected_role) { role_target2 } let(:expected_type) { type_target } end - it_behaves_like "copied workflow" do - subject { described_class.order(Arel.sql("type_id DESC, role_id DESC")).fourth } + it_behaves_like 'copied workflow' do + subject { described_class.order(Arel.sql('type_id DESC, role_id DESC')).fourth } let(:expected_role) { role_target } let(:expected_type) { type_target } diff --git a/spec/modules/backlogs/app/seeders/basic_data/backlogs/setting_seeder_spec.rb b/spec/modules/backlogs/app/seeders/basic_data/backlogs/setting_seeder_spec.rb index 57fc3a1e59e8..62bafc559ca2 100644 --- a/spec/modules/backlogs/app/seeders/basic_data/backlogs/setting_seeder_spec.rb +++ b/spec/modules/backlogs/app/seeders/basic_data/backlogs/setting_seeder_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::Backlogs::SettingSeeder do subject(:setting_seeder) { described_class.new(basic_seed_data) } @@ -39,10 +39,10 @@ let(:type_bug) { basic_seed_data.find_reference(:default_type_bug) } let(:type_task) { basic_seed_data.find_reference(:default_type_task) } - context "with standard edition" do - include_context "with basic seed data", edition: "standard" + context 'with standard edition' do + include_context 'with basic seed data', edition: 'standard' - it "configures Setting.plugin_openproject_backlogs" do + it 'configures Setting.plugin_openproject_backlogs' do setting_seeder.seed! expect(Setting.plugin_openproject_backlogs).to match( @@ -53,7 +53,7 @@ ) end - it "can run multiple times" do + it 'can run multiple times' do # run once setting_seeder.seed! # run a second time without the references in seed_data @@ -87,10 +87,10 @@ include_examples "sets missing setting to its default value", key: "wiki_template", expected_value: "" end - context "with BIM edition" do - include_context "with basic seed data", edition: "bim" + context 'with BIM edition' do + include_context 'with basic seed data', edition: 'bim' - it "configures Setting.plugin_openproject_backlogs" do + it 'configures Setting.plugin_openproject_backlogs' do setting_seeder.seed! expect(Setting.plugin_openproject_backlogs).to match( @@ -101,7 +101,7 @@ ) end - it "can run multiple times" do + it 'can run multiple times' do # run once setting_seeder.seed! # run a second time without the references in seed_data diff --git a/spec/permissions/add_messages_spec.rb b/spec/permissions/add_messages_spec.rb index ba3a515d232d..9fbc3bfec546 100644 --- a/spec/permissions/add_messages_spec.rb +++ b/spec/permissions/add_messages_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/permission_specs" +require 'spec_helper' +require 'support/permission_specs' -RSpec.describe MessagesController, "add_messages permission", type: :controller do +RSpec.describe MessagesController, 'add_messages permission', type: :controller do include PermissionSpecs - check_permission_required_for("messages#preview", :add_messages) + check_permission_required_for('messages#preview', :add_messages) end diff --git a/spec/permissions/copy_projects_spec.rb b/spec/permissions/copy_projects_spec.rb index c081760a213b..168c87e00a44 100644 --- a/spec/permissions/copy_projects_spec.rb +++ b/spec/permissions/copy_projects_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/permission_specs", __dir__) +require 'spec_helper' +require File.expand_path('../support/permission_specs', __dir__) -RSpec.describe ProjectsController, "copy_projects permission", type: :controller do +RSpec.describe ProjectsController, 'copy_projects permission', type: :controller do include PermissionSpecs - check_permission_required_for("projects#copy", :copy_projects) + check_permission_required_for('projects#copy', :copy_projects) end diff --git a/spec/permissions/delete_work_packages_spec.rb b/spec/permissions/delete_work_packages_spec.rb index 3fd7bd2e1c3a..30371810a6a3 100644 --- a/spec/permissions/delete_work_packages_spec.rb +++ b/spec/permissions/delete_work_packages_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/permission_specs" +require 'spec_helper' +require_relative '../support/permission_specs' -RSpec.describe WorkPackages::BulkController, "delete_work_packages permission", type: :controller do +RSpec.describe WorkPackages::BulkController, 'delete_work_packages permission', type: :controller do include PermissionSpecs - check_permission_required_for("work_packages/bulk#destroy", :delete_work_packages) + check_permission_required_for('work_packages/bulk#destroy', :delete_work_packages) end diff --git a/spec/permissions/edit_messages_spec.rb b/spec/permissions/edit_messages_spec.rb index 6d8e13d36abf..3789c8c8ba18 100644 --- a/spec/permissions/edit_messages_spec.rb +++ b/spec/permissions/edit_messages_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/permission_specs" +require 'spec_helper' +require 'support/permission_specs' -RSpec.describe MessagesController, "edit_messages permission", type: :controller do +RSpec.describe MessagesController, 'edit_messages permission', type: :controller do include PermissionSpecs - check_permission_required_for("messages#preview", :edit_messages) + check_permission_required_for('messages#preview', :edit_messages) end diff --git a/spec/permissions/edit_own_messages_spec.rb b/spec/permissions/edit_own_messages_spec.rb index 963232dd4141..d58504d2e9d1 100644 --- a/spec/permissions/edit_own_messages_spec.rb +++ b/spec/permissions/edit_own_messages_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/permission_specs" +require 'spec_helper' +require 'support/permission_specs' -RSpec.describe MessagesController, "edit_own_messages permission", type: :controller do +RSpec.describe MessagesController, 'edit_own_messages permission', type: :controller do include PermissionSpecs - check_permission_required_for("messages#preview", :edit_own_messages) + check_permission_required_for('messages#preview', :edit_own_messages) end diff --git a/spec/permissions/edit_wiki_pages_spec.rb b/spec/permissions/edit_wiki_pages_spec.rb index abffd4957a0c..6d7ffe0e07b3 100644 --- a/spec/permissions/edit_wiki_pages_spec.rb +++ b/spec/permissions/edit_wiki_pages_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/permission_specs" +require 'spec_helper' +require 'support/permission_specs' -RSpec.describe WikiController, "edit_wiki_pages permission", type: :controller do +RSpec.describe WikiController, 'edit_wiki_pages permission', type: :controller do include PermissionSpecs - check_permission_required_for("wiki#preview", :edit_wiki_pages) + check_permission_required_for('wiki#preview', :edit_wiki_pages) end diff --git a/spec/permissions/export_work_packages_spec.rb b/spec/permissions/export_work_packages_spec.rb index a46638c67142..1246fd16e51d 100644 --- a/spec/permissions/export_work_packages_spec.rb +++ b/spec/permissions/export_work_packages_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/permission_specs", __dir__) +require 'spec_helper' +require File.expand_path('../support/permission_specs', __dir__) -RSpec.describe WorkPackagesController, "export_work_packages permission", type: :controller do +RSpec.describe WorkPackagesController, 'export_work_packages permission', type: :controller do include PermissionSpecs - check_permission_required_for("work_packages#index", :export_work_packages) - check_permission_required_for("work_packages#all", :export_work_packages) + check_permission_required_for('work_packages#index', :export_work_packages) + check_permission_required_for('work_packages#all', :export_work_packages) end diff --git a/spec/permissions/manage_forums_spec.rb b/spec/permissions/manage_forums_spec.rb index 8143cecac5e3..5498ee927d00 100644 --- a/spec/permissions/manage_forums_spec.rb +++ b/spec/permissions/manage_forums_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/permission_specs", __dir__) +require 'spec_helper' +require File.expand_path('../support/permission_specs', __dir__) -RSpec.describe ForumsController, "manage_forums permission", type: :controller do +RSpec.describe ForumsController, 'manage_forums permission', type: :controller do include PermissionSpecs - check_permission_required_for("forums#create", :manage_forums) - check_permission_required_for("forums#move", :manage_forums) + check_permission_required_for('forums#create', :manage_forums) + check_permission_required_for('forums#move', :manage_forums) end diff --git a/spec/permissions/manage_news_spec.rb b/spec/permissions/manage_news_spec.rb index 7ae3917c5789..a8e89afd83d3 100644 --- a/spec/permissions/manage_news_spec.rb +++ b/spec/permissions/manage_news_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "support/permission_specs" +require 'spec_helper' +require 'support/permission_specs' -RSpec.describe NewsController, "manage_news permission", type: :controller do +RSpec.describe NewsController, 'manage_news permission', type: :controller do include PermissionSpecs - check_permission_required_for("news#preview", :manage_news) + check_permission_required_for('news#preview', :manage_news) end diff --git a/spec/permissions/manage_repositories_spec.rb b/spec/permissions/manage_repositories_spec.rb index 1060575a0194..3052aecf2691 100644 --- a/spec/permissions/manage_repositories_spec.rb +++ b/spec/permissions/manage_repositories_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/permission_specs", __dir__) +require 'spec_helper' +require File.expand_path('../support/permission_specs', __dir__) -RSpec.describe RepositoriesController, "manage_repository permission", type: :controller do +RSpec.describe RepositoriesController, 'manage_repository permission', type: :controller do include PermissionSpecs - check_permission_required_for("repositories#edit", :manage_repository) + check_permission_required_for('repositories#edit', :manage_repository) end diff --git a/spec/permissions/translations_spec.rb b/spec/permissions/translations_spec.rb index b776f028f263..95b546a1041c 100644 --- a/spec/permissions/translations_spec.rb +++ b/spec/permissions/translations_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Permissions", "I18n" do +RSpec.describe 'Permissions', 'I18n' do subject(:permissions) do OpenProject::AccessControl.instance_variable_get(:@mapped_permissions) end - it "has an english translation for every permission", :aggregate_failures do + it 'has an english translation for every permission', :aggregate_failures do permissions.each do |permission| expect(I18n.exists?("permission_#{permission.name}", :en)) .to be(true), "English translation for #{permission.name} is missing" diff --git a/spec/permissions/view_work_packages_spec.rb b/spec/permissions/view_work_packages_spec.rb index b5a018ef2332..b950e0316b24 100644 --- a/spec/permissions/view_work_packages_spec.rb +++ b/spec/permissions/view_work_packages_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require File.expand_path("../support/permission_specs", __dir__) +require 'spec_helper' +require File.expand_path('../support/permission_specs', __dir__) -RSpec.describe WorkPackagesController, "view_work_packages permission", type: :controller do +RSpec.describe WorkPackagesController, 'view_work_packages permission', type: :controller do include PermissionSpecs - check_permission_required_for("work_packages#show", :view_work_packages) - check_permission_required_for("work_packages#index", :view_work_packages) + check_permission_required_for('work_packages#show', :view_work_packages) + check_permission_required_for('work_packages#index', :view_work_packages) end diff --git a/spec/permissions/work_packages_bulk_spec.rb b/spec/permissions/work_packages_bulk_spec.rb index dc7799206781..d247540b05e2 100644 --- a/spec/permissions/work_packages_bulk_spec.rb +++ b/spec/permissions/work_packages_bulk_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "../support/permission_specs" +require 'spec_helper' +require_relative '../support/permission_specs' -RSpec.describe WorkPackages::BulkController, "edit_work_packages permission", type: :controller do +RSpec.describe WorkPackages::BulkController, 'edit_work_packages permission', type: :controller do include PermissionSpecs - check_permission_required_for("work_packages/bulk#edit", :edit_work_packages) - check_permission_required_for("work_packages/bulk#update", :edit_work_packages) + check_permission_required_for('work_packages/bulk#edit', :edit_work_packages) + check_permission_required_for('work_packages/bulk#update', :edit_work_packages) end diff --git a/spec/policies/query_policy_spec.rb b/spec/policies/query_policy_spec.rb index 6daf177b93cc..5088835ab88c 100644 --- a/spec/policies/query_policy_spec.rb +++ b/spec/policies/query_policy_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe QueryPolicy, type: :controller do let(:user) { build_stubbed(:user) } let(:project) { build_stubbed(:project) } let(:query) { build_stubbed(:query, project:, user:) } - describe "#allowed?" do + describe '#allowed?' do let(:subject) { described_class.new(user) } - shared_examples "viewing queries" do |global| - context (global ? "in global context" : "in project context").to_s do + shared_examples 'viewing queries' do |global| + context (global ? 'in global context' : 'in project context').to_s do let(:other_user) { build_stubbed(:user) } if global @@ -50,13 +50,13 @@ end end - it "is true if the query is public and another user views it" do + it 'is true if the query is public and another user views it' do query.public = true query.user = other_user expect(subject.allowed?(query, :show)).to be_truthy end - context "query belongs to a different user" do + context 'query belongs to a different user' do let(:query) do build_stubbed(:query, project:, @@ -64,11 +64,11 @@ public: false) end - it "is true if the query is private and the owner views it" do + it 'is true if the query is private and the owner views it' do expect(subject.allowed?(query, :show)).to be_truthy end - it "is false if the query is private and another user views it" do + it 'is false if the query is private and another user views it' do query.user = other_user expect(subject.allowed?(query, :show)).to be_falsy end @@ -76,7 +76,7 @@ end end - shared_examples "action on persisted" do |action, global| + shared_examples 'action on persisted' do |action, global| context "for #{action} #{global ? 'in global context' : 'in project context'}" do if global let(:project) { nil } @@ -87,13 +87,13 @@ allow(query).to receive(:persisted?).and_return true end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user, &:forbid_everything) expect(subject.allowed?(query, action)).to be_falsy end - it "is false if the user has the save_query permission in the project AND the query is not persisted" do + it 'is false if the user has the save_query permission in the project AND the query is not persisted' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -102,7 +102,7 @@ expect(subject.allowed?(query, action)).to be_falsy end - it "is true if the user has the save_query permission in the project AND it is his query" do + it 'is true if the user has the save_query permission in the project AND it is his query' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -111,7 +111,7 @@ expect(subject.allowed?(query, action)).to be_truthy end - it "is false if the user has the save_query permission in the project AND it is not his query" do + it 'is false if the user has the save_query permission in the project AND it is not his query' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -120,7 +120,7 @@ expect(subject.allowed?(query, action)).to be_falsy end - it "is false if the user lacks the save_query permission in the project AND it is his query" do + it 'is false if the user lacks the save_query permission in the project AND it is his query' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -130,9 +130,9 @@ expect(subject.allowed?(query, action)).to be_falsy end - it "is true if the user has the manage_public_query permission in the project " + - "AND it is anothers query " + - "AND the query is public" do + it 'is true if the user has the manage_public_query permission in the project ' + + 'AND it is anothers query ' + + 'AND the query is public' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -142,9 +142,9 @@ expect(subject.allowed?(query, action)).to be_truthy end - it "is false if the user lacks the manage_public_query permission in the project " + - "AND it is anothers query " + - "AND the query is public" do + it 'is false if the user lacks the manage_public_query permission in the project ' + + 'AND it is anothers query ' + + 'AND the query is public' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -154,9 +154,9 @@ expect(subject.allowed?(query, action)).to be_falsy end - it "is false if the user has the manage_public_query permission in the project " + - "AND it is anothers query " + - "AND the query is not public" do + it 'is false if the user has the manage_public_query permission in the project ' + + 'AND it is anothers query ' + + 'AND the query is not public' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -168,7 +168,7 @@ end end - shared_examples "action on unpersisted" do |action, global| + shared_examples 'action on unpersisted' do |action, global| context "for #{action} #{global ? 'in global context' : 'in project context'}" do if global let(:project) { nil } @@ -179,7 +179,7 @@ allow(query).to receive(:persisted?).and_return false end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -187,7 +187,7 @@ expect(subject.allowed?(query, action)).to be_falsy end - it "is true if the user has the save_query permission in the project" do + it 'is true if the user has the save_query permission in the project' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -195,8 +195,8 @@ expect(subject.allowed?(query, action)).to be_truthy end - it "is false if the user has the save_query permission in the project " + - "AND the query is persisted" do + it 'is false if the user has the save_query permission in the project ' + + 'AND the query is persisted' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -208,13 +208,13 @@ end end - shared_examples "publicize" do |global| - context (global ? "in global context" : "in project context").to_s do + shared_examples 'publicize' do |global| + context (global ? 'in global context' : 'in project context').to_s do if global let(:project) { nil } end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -222,8 +222,8 @@ expect(subject.allowed?(query, :publicize)).to be_falsy end - it "is true if the user has the manage_public_query permission in the project " + - "AND it is his query" do + it 'is true if the user has the manage_public_query permission in the project ' + + 'AND it is his query' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -231,9 +231,9 @@ expect(subject.allowed?(query, :publicize)).to be_truthy end - it "is false if the user has the manage_public_query permission in the project " + - "AND the query is not public " + - "AND it is not his query" do + it 'is false if the user has the manage_public_query permission in the project ' + + 'AND the query is not public ' + + 'AND it is not his query' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -245,13 +245,13 @@ end end - shared_examples "depublicize" do |global| - context (global ? "in global context" : "in project context").to_s do + shared_examples 'depublicize' do |global| + context (global ? 'in global context' : 'in project context').to_s do if global let(:project) { nil } end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -259,9 +259,9 @@ expect(subject.allowed?(query, :depublicize)).to be_falsy end - it "is true if the user has the manage_public_query permission in the project " + - "AND the query belongs to another user" + - "AND the query is public" do + it 'is true if the user has the manage_public_query permission in the project ' + + 'AND the query belongs to another user' + + 'AND the query is public' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -272,8 +272,8 @@ expect(subject.allowed?(query, :depublicize)).to be_truthy end - it "is false if the user has the manage_public_query permission in the project " + - "AND the query is not public" do + it 'is false if the user has the manage_public_query permission in the project ' + + 'AND the query is not public' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -284,13 +284,13 @@ end end - shared_examples "star" do |global| - context (global ? "in global context" : "in project context").to_s do + shared_examples 'star' do |global| + context (global ? 'in global context' : 'in project context').to_s do if global let(:project) { nil } end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -300,13 +300,13 @@ end end - shared_examples "update ordered_work_packages" do |global| - context (global ? "in global context" : "in project context").to_s do + shared_examples 'update ordered_work_packages' do |global| + context (global ? 'in global context' : 'in project context').to_s do if global let(:project) { nil } end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -314,7 +314,7 @@ expect(subject.allowed?(query, :reorder_work_packages)).to be_falsy end - it "is true if the user has the edit_work_packages permission in the project AND it public" do + it 'is true if the user has the edit_work_packages permission in the project AND it public' do mock_permissions_for(user) do |mock| mock.allow_in_project :edit_work_packages, project: global ? build_stubbed(:project) : project end @@ -323,7 +323,7 @@ expect(subject.allowed?(query, :reorder_work_packages)).to be_truthy end - it "is false if the user has the edit_work_packages permission in the project AND it is not his" do + it 'is false if the user has the edit_work_packages permission in the project AND it is not his' do mock_permissions_for(user) do |mock| mock.allow_in_project :edit_work_packages, project: global ? build_stubbed(:project) : project end @@ -333,7 +333,7 @@ expect(subject.allowed?(query, :reorder_work_packages)).to be_falsey end - it "is true if the user has the save_queries permission in the project AND it is his query" do + it 'is true if the user has the save_queries permission in the project AND it is his query' do mock_permissions_for(user) do |mock| mock.allow_in_project :save_queries, project: global ? build_stubbed(:project) : project end @@ -341,8 +341,8 @@ expect(subject.allowed?(query, :reorder_work_packages)).to be_truthy end - it "is true if the user has the manage_public_query permission in the project " + - "AND it is a public query" do + it 'is true if the user has the manage_public_query permission in the project ' + + 'AND it is a public query' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -351,9 +351,9 @@ expect(subject.allowed?(query, :reorder_work_packages)).to be_truthy end - it "is false if the user has the manage_public_query permission in the project " + - "AND the query is not public " + - "AND it is not his query" do + it 'is false if the user has the manage_public_query permission in the project ' + + 'AND the query is not public ' + + 'AND it is not his query' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_public_queries, project: global ? build_stubbed(:project) : project end @@ -365,13 +365,13 @@ end end - shared_examples "share via ical" do |global| - context (global ? "in global context" : "in project context").to_s do + shared_examples 'share via ical' do |global| + context (global ? 'in global context' : 'in project context').to_s do if global let(:project) { nil } end - it "is false if the user has no permission in the project" do + it 'is false if the user has no permission in the project' do mock_permissions_for(user) do |mock| mock.forbid_everything end @@ -379,7 +379,7 @@ expect(subject.allowed?(query, :share_via_ical)).to be_falsy end - it "is true if the user has permission in the project" do + it 'is true if the user has permission in the project' do mock_permissions_for(user) do |mock| mock.allow_in_project :share_calendars, project: global ? build_stubbed(:project) : project end @@ -389,25 +389,25 @@ end end - it_behaves_like "action on persisted", :update, global: true - it_behaves_like "action on persisted", :update, global: false - it_behaves_like "action on persisted", :destroy, global: true - it_behaves_like "action on persisted", :destroy, global: false - it_behaves_like "action on unpersisted", :create, global: true - it_behaves_like "action on unpersisted", :create, global: false - it_behaves_like "publicize", global: false - it_behaves_like "publicize", global: true - it_behaves_like "depublicize", global: false - it_behaves_like "depublicize", global: true - it_behaves_like "action on persisted", :star, global: false - it_behaves_like "action on persisted", :star, global: true - it_behaves_like "action on persisted", :unstar, global: false - it_behaves_like "action on persisted", :unstar, global: true - it_behaves_like "viewing queries", global: true - it_behaves_like "viewing queries", global: false + it_behaves_like 'action on persisted', :update, global: true + it_behaves_like 'action on persisted', :update, global: false + it_behaves_like 'action on persisted', :destroy, global: true + it_behaves_like 'action on persisted', :destroy, global: false + it_behaves_like 'action on unpersisted', :create, global: true + it_behaves_like 'action on unpersisted', :create, global: false + it_behaves_like 'publicize', global: false + it_behaves_like 'publicize', global: true + it_behaves_like 'depublicize', global: false + it_behaves_like 'depublicize', global: true + it_behaves_like 'action on persisted', :star, global: false + it_behaves_like 'action on persisted', :star, global: true + it_behaves_like 'action on persisted', :unstar, global: false + it_behaves_like 'action on persisted', :unstar, global: true + it_behaves_like 'viewing queries', global: true + it_behaves_like 'viewing queries', global: false # TODO: should this be better done in 'action on persisted' context? # I'm not sure if the action on persisted perrmission dependecies apply to the share via ical context - it_behaves_like "share via ical", global: true - it_behaves_like "share via ical", global: false + it_behaves_like 'share via ical', global: true + it_behaves_like 'share via ical', global: false end end diff --git a/spec/policies/redirect_policy_spec.rb b/spec/policies/redirect_policy_spec.rb index 86393f394b52..a43c8205edb4 100644 --- a/spec/policies/redirect_policy_spec.rb +++ b/spec/policies/redirect_policy_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe RedirectPolicy, type: :controller do - let(:host) { "test.host" } + let(:host) { 'test.host' } let(:return_escaped) { true } - let(:default) { "http://test.foo/default" } + let(:default) { 'http://test.foo/default' } let(:policy) do described_class.new( @@ -44,28 +44,28 @@ end let(:subject) { policy.redirect_url } - shared_examples "redirects to default" do |url| + shared_examples 'redirects to default' do |url| let(:back_url) { url } it "#{url} redirects to the default URL" do expect(subject).to eq(default) end end - shared_examples "valid redirect URL" do |url| + shared_examples 'valid redirect URL' do |url| let(:back_url) { url } it "#{url} is valid" do expect(subject).to eq(url) end end - shared_examples "valid redirect, escaped URL" do |input, output| + shared_examples 'valid redirect, escaped URL' do |input, output| let(:back_url) { input } it "#{input} is valid, but escaped to #{output}" do expect(subject).to eq(output) end end - shared_examples "ignores invalid URLs" do + shared_examples 'ignores invalid URLs' do uris = %w( //test.foo/fake //bar@test.foo @@ -79,49 +79,49 @@ ) uris.each do |uri| - it_behaves_like "redirects to default", uri + it_behaves_like 'redirects to default', uri end end - it_behaves_like "ignores invalid URLs" - it_behaves_like "valid redirect URL", "/work_packages/1234?filter=[foo,bar]" + it_behaves_like 'ignores invalid URLs' + it_behaves_like 'valid redirect URL', '/work_packages/1234?filter=[foo,bar]' - it_behaves_like "valid redirect, escaped URL", + it_behaves_like 'valid redirect, escaped URL', 'http://test.host/?a=\11\15', - "http://test.host/?a=%5C11%5C15" + 'http://test.host/?a=%5C11%5C15' - context "without escaped return URLs" do + context 'without escaped return URLs' do let(:return_escaped) { false } - it_behaves_like "valid redirect URL", "/work_packages/1234?filter=[foo,bar]" - it_behaves_like "valid redirect URL", 'http://test.host/?a=\11\15' + it_behaves_like 'valid redirect URL', '/work_packages/1234?filter=[foo,bar]' + it_behaves_like 'valid redirect URL', 'http://test.host/?a=\11\15' end - context "with relative root" do - let(:relative_root) { "/mysubdir" } + context 'with relative root' do + let(:relative_root) { '/mysubdir' } before do allow(OpenProject::Configuration) - .to receive(:[]).with("rails_relative_url_root") + .to receive(:[]).with('rails_relative_url_root') .and_return(relative_root) end - it_behaves_like "valid redirect URL", "/mysubdir/work_packages/1234" - it_behaves_like "valid redirect URL", "/mysubdir" - it_behaves_like "redirects to default", "/" - it_behaves_like "redirects to default", "/foobar" - it_behaves_like "redirects to default", "/mysubdir/../foobar" - it_behaves_like "redirects to default", "/mysubdir/%2E%2E/secret/etc/passwd" - it_behaves_like "redirects to default", "/%2E%2E/secret/etc/passwd" - it_behaves_like "redirects to default", "/foobar/%2E%2E/secret/etc/passwd" - it_behaves_like "redirects to default", "wusdus/%2E%2E/%2E%2E/secret/etc/passwd" + it_behaves_like 'valid redirect URL', '/mysubdir/work_packages/1234' + it_behaves_like 'valid redirect URL', '/mysubdir' + it_behaves_like 'redirects to default', '/' + it_behaves_like 'redirects to default', '/foobar' + it_behaves_like 'redirects to default', '/mysubdir/../foobar' + it_behaves_like 'redirects to default', '/mysubdir/%2E%2E/secret/etc/passwd' + it_behaves_like 'redirects to default', '/%2E%2E/secret/etc/passwd' + it_behaves_like 'redirects to default', '/foobar/%2E%2E/secret/etc/passwd' + it_behaves_like 'redirects to default', 'wusdus/%2E%2E/%2E%2E/secret/etc/passwd' end - describe "auth credentials" do - let(:back_url) { "http://user:pass@test.host/work_packages/123" } + describe 'auth credentials' do + let(:back_url) { 'http://user:pass@test.host/work_packages/123' } - it "removes the credentials" do - expect(subject).to eq("http://test.host/work_packages/123") + it 'removes the credentials' do + expect(subject).to eq('http://test.host/work_packages/123') end end end diff --git a/spec/policies/work_package_policy_spec.rb b/spec/policies/work_package_policy_spec.rb index d95d3bc568aa..0f89e5b3d605 100644 --- a/spec/policies/work_package_policy_spec.rb +++ b/spec/policies/work_package_policy_spec.rb @@ -26,23 +26,23 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackagePolicy, type: :controller do let(:user) { build_stubbed(:user) } let(:project) { build_stubbed(:project) } let(:work_package) { build_stubbed(:work_package, project:) } - describe "#allowed?" do + describe '#allowed?' do let(:subject) { described_class.new(user) } - context "for edit" do - it "is false if the user has no permissions" do + context 'for edit' do + it 'is false if the user has no permissions' do mock_permissions_for(user, &:forbid_everything) expect(subject).not_to be_allowed(work_package, :edit) end - it "is true if the user has the edit_work_package permission" do + it 'is true if the user has the edit_work_package permission' do mock_permissions_for(user) do |mock| mock.allow_in_project :edit_work_packages, project: end @@ -50,7 +50,7 @@ expect(subject).to be_allowed(work_package, :edit) end - it "is true if the user has the edit_work_package permission on the work packge" do + it 'is true if the user has the edit_work_package permission on the work packge' do mock_permissions_for(user) do |mock| mock.allow_in_work_package :edit_work_packages, work_package: end @@ -58,7 +58,7 @@ expect(subject).to be_allowed(work_package, :edit) end - it "is false if the user has only the add_work_package_notes permission" do + it 'is false if the user has only the add_work_package_notes permission' do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_package_notes, project: end @@ -66,7 +66,7 @@ expect(subject).not_to be_allowed(work_package, :edit) end - it "is false if the user has the permissions but the work package is unpersisted" do + it 'is false if the user has the permissions but the work package is unpersisted' do mock_permissions_for(user) do |mock| mock.allow_in_project :edit_work_packages, :add_work_package_notes, project: end @@ -77,8 +77,8 @@ end end - context "for manage_subtasks" do - it "is true if the user has the manage_subtasks permission in the project" do + context 'for manage_subtasks' do + it 'is true if the user has the manage_subtasks permission in the project' do mock_permissions_for(user) do |mock| mock.allow_in_project :manage_subtasks, project: end @@ -87,26 +87,26 @@ end end - context "for comment" do - it "is false if the user lacks permission" do + context 'for comment' do + it 'is false if the user lacks permission' do expect(subject).not_to be_allowed(work_package, :comment) end - it "is true if the user has the add_work_package_notes permission" do + it 'is true if the user has the add_work_package_notes permission' do mock_permissions_for(user) do |mock| mock.allow_in_project :add_work_package_notes, project: end expect(subject).to be_allowed(work_package, :comment) end - it "is true if the user has the add_work_package_notes permission on the work package" do + it 'is true if the user has the add_work_package_notes permission on the work package' do mock_permissions_for(user) do |mock| mock.allow_in_work_package :add_work_package_notes, work_package: end expect(subject).to be_allowed(work_package, :comment) end - it "is true if the user has the edit_work_packages permission" do + it 'is true if the user has the edit_work_packages permission' do mock_permissions_for(user) do |mock| mock.allow_in_project :edit_work_packages, project: end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 46f28236affd..aae428c1f398 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -25,17 +25,17 @@ # # See COPYRIGHT and LICENSE files for more details. -ENV["RAILS_ENV"] ||= "test" -require File.expand_path("../config/environment", __dir__) -require "factory_bot" -require "factory_bot_rails" -require "rspec/rails" -require "shoulda/matchers" +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../config/environment', __dir__) +require 'factory_bot' +require 'factory_bot_rails' +require 'rspec/rails' +require 'shoulda/matchers' # Require test_prof helpers for better performance around factories/specs # see https://test-prof.evilmartians.io for all options. -require "test_prof/recipes/rspec/before_all" -require "test_prof/recipes/rspec/let_it_be" +require 'test_prof/recipes/rspec/before_all' +require 'test_prof/recipes/rspec/let_it_be' require "test_prof/recipes/rspec/factory_default" # Encourages fixing factories as soon as possible require "test_prof/factory_prof/nate_heckler" @@ -44,16 +44,16 @@ # Add PaperTrail integration so that it is disabled by default # https://github.com/paper-trail-gem/paper_trail#7b-rspec -require "paper_trail/frameworks/rspec" +require 'paper_trail/frameworks/rspec' # Add rubocop rspec helpers for our cop tests. It needs to be done before RSpec # requires all files so that the CopHelper module does not hide some let # definitions. # # Ideally we should move our cops to their own gem. -require "rubocop" -require "rubocop/rspec/shared_contexts" -require "rubocop/rspec/support" +require 'rubocop' +require 'rubocop/rspec/shared_contexts' +require 'rubocop/rspec/support' # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are @@ -77,18 +77,18 @@ require_relative "support/parallel_helper" require_relative "support/download_list" require_relative "support/capybara" -Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |f| require_relative f } -Dir[Rails.root.join("spec/features/support/**/*.rb")].sort.each { |f| require f } -Dir[Rails.root.join("spec/lib/api/v3/support/**/*.rb")].sort.each { |f| require f } -Dir[Rails.root.join("spec/requests/api/v3/support/**/*.rb")].sort.each { |f| require f } +Dir[Rails.root.join('spec/support/**/*.rb')].sort.each { |f| require_relative f } +Dir[Rails.root.join('spec/features/support/**/*.rb')].sort.each { |f| require f } +Dir[Rails.root.join('spec/lib/api/v3/support/**/*.rb')].sort.each { |f| require f } +Dir[Rails.root.join('spec/requests/api/v3/support/**/*.rb')].sort.each { |f| require f } # Checks for pending migration and applies them before tests are run. # If you are not using ActiveRecord, you can remove this line. -ActiveRecord::Migration.maintain_test_schema! unless ENV["CI"] +ActiveRecord::Migration.maintain_test_schema! unless ENV['CI'] RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_paths = [Rails.root.join("spec/fixtures").to_s] + config.fixture_paths = [Rails.root.join('spec/fixtures').to_s] # Filter lines from Rails gems in backtraces. config.filter_rails_from_backtrace! @@ -102,5 +102,5 @@ config.include ActiveSupport::Testing::Assertions config.include ActiveJob::TestHelper - OpenProject::Configuration["attachments_storage_path"] = "tmp/files" + OpenProject::Configuration['attachments_storage_path'] = 'tmp/files' end diff --git a/spec/requests/admin/attachments/quarantined_attachments_spec.rb b/spec/requests/admin/attachments/quarantined_attachments_spec.rb index af1b9eb5e4bd..9264f17a5e4c 100644 --- a/spec/requests/admin/attachments/quarantined_attachments_spec.rb +++ b/spec/requests/admin/attachments/quarantined_attachments_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Quarantined attachments", +RSpec.describe 'Quarantined attachments', :skip_csrf, type: :rails_request, with_ee: %i[virus_scanning] do @@ -37,25 +37,25 @@ shared_let(:container) { create(:work_package) } shared_let(:quarantined_attachment) do - create(:attachment, container:, status: :quarantined, author: other_author, filename: "other-1.txt") + create(:attachment, container:, status: :quarantined, author: other_author, filename: 'other-1.txt') end shared_let(:scanned_attachment) do - create(:attachment, container:, status: :scanned, author: other_author, filename: "scanned-1.txt") + create(:attachment, container:, status: :scanned, author: other_author, filename: 'scanned-1.txt') end before do login_as admin end - describe "DELETE /admin/quarantined_attachments/:id" do - it "allows management of attachments" do + describe 'DELETE /admin/quarantined_attachments/:id' do + it 'allows management of attachments' do delete admin_quarantined_attachment_path(quarantined_attachment) expect(response).to be_redirect expect { quarantined_attachment.reload }.to raise_error(ActiveRecord::RecordNotFound) end - it "fails to find if not quarantined" do + it 'fails to find if not quarantined' do delete admin_quarantined_attachment_path(scanned_attachment) expect(response).to have_http_status :not_found end diff --git a/spec/requests/admin/attachments/virus_scanning_settings_spec.rb b/spec/requests/admin/attachments/virus_scanning_settings_spec.rb index 556081a524ac..0e9473f4d59c 100644 --- a/spec/requests/admin/attachments/virus_scanning_settings_spec.rb +++ b/spec/requests/admin/attachments/virus_scanning_settings_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Attachments virus scanning", +RSpec.describe 'Attachments virus scanning', :skip_csrf, type: :rails_request do shared_let(:admin) { create(:admin) } @@ -43,50 +43,50 @@ allow(service).to receive(:ping) end - describe "enabling virus scanning", + describe 'enabling virus scanning', with_ee: %i[virus_scanning] do subject do - patch "/admin/settings/virus_scanning", + patch '/admin/settings/virus_scanning', params: { settings: { - antivirus_scan_mode: "clamav_socket" + antivirus_scan_mode: 'clamav_socket' } } response end - it "shows an error if ClamAV cannot be reached" do + it 'shows an error if ClamAV cannot be reached' do allow(service).to receive(:ping).and_raise(Errno::ECONNREFUSED) expect(subject).to be_redirect follow_redirect! - expect(response.body).to have_text I18n.t("settings.antivirus.clamav_ping_failed") + expect(response.body).to have_text I18n.t('settings.antivirus.clamav_ping_failed') expect(Setting.antivirus_scan_mode).to eq(:disabled) end - it "shows no error if ClamAV can be reached" do + it 'shows no error if ClamAV can be reached' do expect(subject).to be_redirect follow_redirect! - expect(response.body).to have_no_text I18n.t("settings.antivirus.clamav_ping_failed") + expect(response.body).to have_no_text I18n.t('settings.antivirus.clamav_ping_failed') expect(Setting.antivirus_scan_mode).to eq(:clamav_socket) end end - describe "rescanning uploaded files", + describe 'rescanning uploaded files', with_ee: %i[virus_scanning] do shared_let(:attachment) { create(:attachment, status: :uploaded) } - it "triggers rescanning of the uploaded files" do - patch "/admin/settings/virus_scanning", + it 'triggers rescanning of the uploaded files' do + patch '/admin/settings/virus_scanning', params: { settings: { - antivirus_scan_mode: "clamav_socket" + antivirus_scan_mode: 'clamav_socket' } } expect(response).to be_redirect follow_redirect! - expect(response.body).to have_text "This process has been scheduled in the background" + expect(response.body).to have_text 'This process has been scheduled in the background' expect(Setting.antivirus_scan_mode).to eq(:clamav_socket) expect(attachment.reload).to be_status_rescan @@ -95,44 +95,44 @@ end end - describe "disabling virus scanning", + describe 'disabling virus scanning', with_ee: %i[virus_scanning] do shared_let(:attachment) { create(:attachment, status: :quarantined) } - it "shows no warning if there are no quarantined files" do + it 'shows no warning if there are no quarantined files' do attachment.destroy! - patch "/admin/settings/virus_scanning", + patch '/admin/settings/virus_scanning', params: { settings: { - antivirus_scan_mode: "disabled" + antivirus_scan_mode: 'disabled' } } expect(response).to be_redirect follow_redirect! - expect(response.body).to have_no_text "remain in quarantine." + expect(response.body).to have_no_text 'remain in quarantine.' expect(Setting.antivirus_scan_mode).to eq(:disabled) end - it "shows a warning if there are still quarantined files" do - patch "/admin/settings/virus_scanning", + it 'shows a warning if there are still quarantined files' do + patch '/admin/settings/virus_scanning', params: { settings: { - antivirus_scan_mode: "disabled" + antivirus_scan_mode: 'disabled' } } expect(response).to be_redirect follow_redirect! - expect(response.body).to have_text "1 file remain in quarantine." + expect(response.body).to have_text '1 file remain in quarantine.' expect(Setting.antivirus_scan_mode).to eq(:disabled) end end - describe "without ee" do - it "redirects to upsale" do - get "/admin/settings/virus_scanning" - expect(response.body).to have_text "Virus scanning is an Enterprise add-on", normalize_ws: true + describe 'without ee' do + it 'redirects to upsale' do + get '/admin/settings/virus_scanning' + expect(response.body).to have_text 'Virus scanning is an Enterprise add-on', normalize_ws: true end end end diff --git a/spec/requests/api/v3/action_resource_spec.rb b/spec/requests/api/v3/action_resource_spec.rb index 155fa67c65a0..57fe42e9646c 100644 --- a/spec/requests/api/v3/action_resource_spec.rb +++ b/spec/requests/api/v3/action_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 action resource", content_type: :json do +RSpec.describe 'API v3 action resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -39,7 +39,7 @@ create(:user) end - describe "GET api/v3/actions" do + describe 'GET api/v3/actions' do let(:path) { api_v3_paths.actions } before do @@ -47,62 +47,62 @@ end # 20 because this is the standard pagination size - it_behaves_like "API V3 collection response", Action.count, 20, "Action" do + it_behaves_like 'API V3 collection response', Action.count, 20, 'Action' do let(:elements) { Action.order(id: :asc).limit(20).to_a } end end - describe "GET /api/v3/actions/:id" do + describe 'GET /api/v3/actions/:id' do let(:path) { api_v3_paths.action("memberships/create") } before do get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the action" do + it 'returns the action' do expect(subject.body) - .to be_json_eql("Action".to_json) - .at_path("_type") + .to be_json_eql('Action'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql("memberships/create".to_json) - .at_path("id") + .at_path('id') end - context "with an action that has an underscore" do + context 'with an action that has an underscore' do let(:path) { api_v3_paths.action("work_packages/read") } - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the action" do + it 'returns the action' do expect(subject.body) - .to be_json_eql("Action".to_json) - .at_path("_type") + .to be_json_eql('Action'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql("work_packages/read".to_json) - .at_path("id") + .at_path('id') end end - context "if querying a non existing action" do + context 'if querying a non existing action' do let(:path) { api_v3_paths.action("foo/bar") } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "if querying with malformed id" do + context 'if querying with malformed id' do let(:path) { api_v3_paths.action("foobar") } - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/activities_api_spec.rb b/spec/requests/api/v3/activities_api_spec.rb index 3ba368123812..57bbd58728ca 100644 --- a/spec/requests/api/v3/activities_api_spec.rb +++ b/spec/requests/api/v3/activities_api_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Activities::ActivitiesAPI, content_type: :json do include Rack::Test::Methods @@ -42,32 +42,32 @@ end let(:permissions) { %i[view_work_packages edit_work_package_notes] } let(:activity) { work_package.journals.first } - let(:comment) { "This is a new test comment!" } + let(:comment) { 'This is a new test comment!' } - shared_examples_for "valid activity request" do |type| + shared_examples_for 'valid activity request' do |type| subject { last_response } - it "returns an activity of the correct type" do - expect(subject.body).to be_json_eql(type.to_json).at_path("_type") - expect(subject.body).to be_json_eql(activity.id.to_json).at_path("id") + it 'returns an activity of the correct type' do + expect(subject.body).to be_json_eql(type.to_json).at_path('_type') + expect(subject.body).to be_json_eql(activity.id.to_json).at_path('id') end - it "responds 200 OK" do + it 'responds 200 OK' do expect(subject.status).to eq(200) end end - shared_examples_for "valid activity patch request" do - it "updates the activity comment" do - expect(last_response.body).to be_json_eql(comment.to_json).at_path("comment/raw") + shared_examples_for 'valid activity patch request' do + it 'updates the activity comment' do + expect(last_response.body).to be_json_eql(comment.to_json).at_path('comment/raw') end - it "changes the comment" do + it 'changes the comment' do expect(activity.reload.notes).to eql comment end end - describe "PATCH /api/v3/activities/:activityId" do + describe 'PATCH /api/v3/activities/:activityId' do let(:params) { { comment: } } before do @@ -75,12 +75,12 @@ patch api_v3_paths.activity(activity.id), params.to_json end - it_behaves_like "valid activity request", "Activity::Comment" + it_behaves_like 'valid activity request', 'Activity::Comment' - it_behaves_like "valid activity patch request" + it_behaves_like 'valid activity patch request' - it_behaves_like "invalid activity request", - "Cause type is not set to one of the allowed values." do + it_behaves_like 'invalid activity request', + 'Cause type is not set to one of the allowed values.' do let(:activity) do # Invalidating the journal work_package.journals.first.tap do |journal| @@ -89,12 +89,12 @@ end end - it_behaves_like "constraint violation" do - let(:message) { "Cause type is not set to one of the allowed values." } + it_behaves_like 'constraint violation' do + let(:message) { 'Cause type is not set to one of the allowed values.' } end end - context "for an activity created by a different user" do + context 'for an activity created by a different user' do let(:activity) do work_package.journals.first.tap do |journal| # it does not matter that the user does not exist @@ -102,81 +102,81 @@ end end - context "when having the necessary permission" do - it_behaves_like "valid activity request", "Activity::Comment" + context 'when having the necessary permission' do + it_behaves_like 'valid activity request', 'Activity::Comment' - it_behaves_like "valid activity patch request" + it_behaves_like 'valid activity patch request' end - context "when having only the edit own permission" do + context 'when having only the edit own permission' do let(:permissions) { %i[view_work_packages edit_own_work_package_notes] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - context "when having only the edit own permission" do + context 'when having only the edit own permission' do let(:permissions) { %i[view_work_packages edit_own_work_package_notes] } - it_behaves_like "valid activity request", "Activity::Comment" + it_behaves_like 'valid activity request', 'Activity::Comment' - it_behaves_like "valid activity patch request" + it_behaves_like 'valid activity patch request' end - context "without sufficient permissions to edit" do + context 'without sufficient permissions to edit' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "without sufficient permissions to see" do + context 'without sufficient permissions to see' do let(:permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "#get api" do + describe '#get api' do let(:get_path) { api_v3_paths.activity activity.id } before do login_as(current_user) end - context "logged in user" do + context 'logged in user' do before do get get_path end - context "for a journal without a comment" do - it_behaves_like "valid activity request", "Activity" + context 'for a journal without a comment' do + it_behaves_like 'valid activity request', 'Activity' end - context "for a journal with a comment" do + context 'for a journal with a comment' do let(:activity) do work_package.journals.first.tap do |journal| journal.update_column(:notes, comment) end end - it_behaves_like "valid activity request", "Activity::Comment" + it_behaves_like 'valid activity request', 'Activity::Comment' end - context "requesting nonexistent activity" do + context 'requesting nonexistent activity' do let(:get_path) { api_v3_paths.activity 9999 } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "without sufficient permissions" do + context 'without sufficient permissions' do let(:permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "anonymous user" do - it_behaves_like "handling anonymous user" do + context 'anonymous user' do + it_behaves_like 'handling anonymous user' do let(:project) { create(:project, public: true) } let(:path) { get_path } end diff --git a/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb b/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb index 10d9a5293358..f662e7d51218 100644 --- a/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb +++ b/spec/requests/api/v3/attachments/attachment_resource_shared_examples.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.shared_examples "it supports direct uploads" do +RSpec.shared_examples 'it supports direct uploads' do include Rack::Test::Methods include API::V3::Utilities::PathHelper include FileHelpers @@ -41,10 +41,10 @@ allow(User).to receive(:current).and_return current_user end - describe "POST /prepare", with_settings: { attachment_max_size: 512 } do + describe 'POST /prepare', with_settings: { attachment_max_size: 512 } do let(:request_parts) { { metadata: metadata.to_json, file: } } - let(:metadata) { { fileName: "cat.png", fileSize: file.size, contentType: "image/png" } } - let(:file) { mock_uploaded_file(name: "original-filename.txt") } + let(:metadata) { { fileName: 'cat.png', fileSize: file.size, contentType: 'image/png' } } + let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:json_response) { JSON.parse last_response.body } def request! @@ -53,52 +53,52 @@ def request! subject(:response) { last_response } - context "with local storage" do + context 'with local storage' do before do request! end - it "responds with a validation error" do + it 'responds with a validation error' do expect(subject.status).to eq(422) end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "is not available due to a system configuration" } end end - context "with remote AWS storage", :with_direct_uploads do + context 'with remote AWS storage', :with_direct_uploads do before do request! end - context "with no filesize metadata" do - let(:metadata) { { fileName: "cat.png" } } + context 'with no filesize metadata' do + let(:metadata) { { fileName: 'cat.png' } } let(:json) { JSON.parse subject.body } - it "responds with 422 due to missing file size metadata" do + it 'responds with 422 due to missing file size metadata' do expect(subject.status).to eq(422) - expect(subject.body).to include "Size" + expect(subject.body).to include 'Size' end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Size #{I18n.t('activerecord.errors.messages.blank')}" } end end - context "with the correct parameters" do + context 'with the correct parameters' do let(:json) { JSON.parse subject.body } - it "prepares a direct upload" do + it 'prepares a direct upload' do expect(subject.status).to eq 201 expect(json["_type"]).to eq "AttachmentUpload" expect(json["fileName"]).to eq "cat.png" end - describe "response" do - describe "_links" do - describe "container" do + describe 'response' do + describe '_links' do + describe 'container' do let(:link) { json.dig "_links", "container" } before do @@ -110,22 +110,22 @@ def request! end end - describe "addAttachment" do + describe 'addAttachment' do let(:link) { json.dig "_links", "addAttachment" } before do expect(link).to be_present end - it "points to AWS" do + it 'points to AWS' do expect(link["href"]).to eq "https://#{MockCarrierwave.bucket}.s3.amazonaws.com/" end - it "has the method POST" do + it 'has the method POST' do expect(link["method"]).to eq "post" end - it "includes form fields" do + it 'includes form fields' do fields = link["form_fields"] expect(fields).to be_present @@ -140,7 +140,7 @@ def request! expect(fields["key"]).to end_with "cat.png" end - it "also includes the content type and the necessary policy in the form fields" do + it 'also includes the content type and the necessary policy in the form fields' do fields = link["form_fields"] expect(fields).to include("policy", "Content-Type") @@ -155,29 +155,29 @@ def request! end end - context "with an attachment whitelist", with_settings: { attachment_whitelist: ["text/csv"] } do - context "with an allowed content type" do - let(:metadata) { { fileName: "cats.csv", fileSize: file.size, contentType: "text/csv" } } + context 'with an attachment whitelist', with_settings: { attachment_whitelist: ['text/csv'] } do + context 'with an allowed content type' do + let(:metadata) { { fileName: 'cats.csv', fileSize: file.size, contentType: 'text/csv' } } - it "succeeds" do + it 'succeeds' do expect(subject.status).to eq 201 end end - context "with a forbidden content type" do - let(:metadata) { { fileName: "cats.txt", fileSize: file.size, contentType: "text/plain" } } + context 'with a forbidden content type' do + let(:metadata) { { fileName: 'cats.txt', fileSize: file.size, contentType: 'text/plain' } } - it "fails" do + it 'fails' do expect(subject.status).to eq 422 expect(subject.body).to include "not whitelisted" end end - context "with a non-specific content type not on the whitelist" do - let(:metadata) { { fileName: "cats.bin", fileSize: file.size, contentType: "application/binary" } } + context 'with a non-specific content type not on the whitelist' do + let(:metadata) { { fileName: 'cats.bin', fileSize: file.size, contentType: 'application/binary' } } # the actual whitelist check will be performed in the FinishDirectUpload job in this case - it "still succeeds" do + it 'still succeeds' do expect(subject.status).to eq 201 end end @@ -186,7 +186,7 @@ def request! end end -RSpec.shared_examples "an APIv3 attachment resource", content_type: :json, type: :request do |include_by_container: true| +RSpec.shared_examples 'an APIv3 attachment resource', content_type: :json, type: :request do |include_by_container: true| include Rack::Test::Methods include API::V3::Utilities::PathHelper include FileHelpers @@ -223,48 +223,48 @@ def request! allow(User).to receive(:current).and_return current_user end - describe "#get" do + describe '#get' do subject(:response) { last_response } let(:get_path) { api_v3_paths.attachment attachment.id } let(:container) { send(attachment_type) } - context "logged in user" do + context 'logged in user' do before do get get_path end - it "responds with 200" do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with correct attachment" do - expect(subject.body).to be_json_eql(attachment.filename.to_json).at_path("fileName") + it 'responds with correct attachment' do + expect(subject.body).to be_json_eql(attachment.filename.to_json).at_path('fileName') end - context "requesting nonexistent attachment" do + context 'requesting nonexistent attachment' do let(:get_path) { api_v3_paths.attachment 9999 } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "requesting attachments without sufficient permissions" do + context 'requesting attachments without sufficient permissions' do let(:current_user) { missing_permissions_user } let(:permissions) { all_permissions - Array(read_permission) } - it_behaves_like "not found" + it_behaves_like 'not found' end end end - describe "#post" do + describe '#post' do let(:permissions) { Array(update_permission) } let(:request_path) { api_v3_paths.attachments } let(:request_parts) { { metadata: metadata.to_json, file: } } - let(:metadata) { { fileName: "cat.png" } } - let(:file) { mock_uploaded_file(name: "original-filename.txt") } + let(:metadata) { { fileName: 'cat.png' } } + let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:max_file_size) { 1 } # given in kiB before do @@ -274,64 +274,64 @@ def request! subject(:response) { last_response } - it "responds with HTTP Created" do + it 'responds with HTTP Created' do expect(subject.status).to eq(201) end - it "returns the new attachment without container" do - expect(subject.body).to be_json_eql("Attachment".to_json).at_path("_type") - expect(subject.body).to be_json_eql(nil.to_json).at_path("_links/container/href") + it 'returns the new attachment without container' do + expect(subject.body).to be_json_eql('Attachment'.to_json).at_path('_type') + expect(subject.body).to be_json_eql(nil.to_json).at_path('_links/container/href') end - it "ignores the original file name" do - expect(subject.body).to be_json_eql("cat.png".to_json).at_path("fileName") + it 'ignores the original file name' do + expect(subject.body).to be_json_eql('cat.png'.to_json).at_path('fileName') end - context "metadata section is missing" do + context 'metadata section is missing' do let(:request_parts) { { file: } } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "File #{I18n.t('activerecord.errors.messages.blank')}" } end end - context "file section is missing" do + context 'file section is missing' do # rack-test won't send a multipart request without a file being present # however as long as we depend on correctly named sections this test should do just fine let(:request_parts) { { metadata: metadata.to_json, wrongFileSection: file } } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "The content type of the file cannot be blank" } end end - context "metadata section is no valid JSON" do + context 'metadata section is no valid JSON' do let(:request_parts) { { metadata: '"fileName": "cat.png"', file: } } - it_behaves_like "parse error" + it_behaves_like 'parse error' end - context "metadata is missing the fileName" do + context 'metadata is missing the fileName' do let(:metadata) { Hash.new } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "File #{I18n.t('activerecord.errors.messages.blank')}" } end end - context "file is too large" do - let(:file) { mock_uploaded_file(content: "a" * 2.kilobytes) } + context 'file is too large' do + let(:file) { mock_uploaded_file(content: 'a' * 2.kilobytes) } let(:expanded_localization) do - I18n.t("activerecord.errors.messages.file_too_large", count: max_file_size.kilobytes) + I18n.t('activerecord.errors.messages.file_too_large', count: max_file_size.kilobytes) end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "File #{expanded_localization}" } end end - context "missing permissions" do + context 'missing permissions' do let(:permissions) do # Some attachables use public permissions # which more or less allows everybody to upload attachments. @@ -347,11 +347,11 @@ def request! [] end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "#delete" do + describe '#delete' do let(:path) { api_v3_paths.attachment attachment.id } before do @@ -360,17 +360,17 @@ def request! subject(:response) { last_response } - shared_examples_for "deletes the attachment" do - it "responds with HTTP No Content" do + shared_examples_for 'deletes the attachment' do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "removes the attachment from the DB" do + it 'removes the attachment from the DB' do expect(Attachment.exists?(attachment.id)).to be_falsey end end - shared_examples_for "does not delete the attachment" do |status = 403| + shared_examples_for 'does not delete the attachment' do |status = 403| it "responds with #{status}" do if permissions.any? || read_permission.nil? expect(subject.status).to eq status @@ -381,45 +381,45 @@ def request! end end - it "does not delete the attachment" do + it 'does not delete the attachment' do expect(Attachment.exists?(attachment.id)).to be_truthy end end - context "with required permissions" do + context 'with required permissions' do let(:permissions) { [read_permission, delete_permission].flatten.uniq.compact } - it_behaves_like "deletes the attachment" + it_behaves_like 'deletes the attachment' - context "for a non-existent attachment" do + context 'for a non-existent attachment' do let(:path) { api_v3_paths.attachment 1337 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "without required permissions" do + context 'without required permissions' do let(:permissions) { all_permissions.without(delete_permission) } - it_behaves_like "does not delete the attachment" + it_behaves_like 'does not delete the attachment' end context "with an uncontainered attachment" do let(:container) { nil } - context "with the user being the author" do - it_behaves_like "deletes the attachment" + context 'with the user being the author' do + it_behaves_like 'deletes the attachment' end - context "with the user not being the author" do + context 'with the user not being the author' do let(:author) { create(:user) } - it_behaves_like "does not delete the attachment", 404 + it_behaves_like 'does not delete the attachment', 404 end end end - describe "#content" do + describe '#content' do let(:path) { api_v3_paths.attachment_content attachment.id } before do @@ -428,8 +428,8 @@ def request! subject(:response) { last_response } - context "with required permissions" do - shared_examples "for a local file" do + context 'with required permissions' do + shared_examples 'for a local file' do let(:mock_file) { raise "define mock_file" } let(:content_disposition) { raise "define content_disposition" } @@ -443,15 +443,15 @@ def request! att end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq 200 end - it "has the necessary headers for content and caching" do - expect(subject.headers["Content-Disposition"]) + it 'has the necessary headers for content and caching' do + expect(subject.headers['Content-Disposition']) .to eql content_disposition - expect(subject.headers["Content-Type"]) + expect(subject.headers['Content-Type']) .to eql mock_file.content_type max_age = OpenProject::Configuration.fog_download_url_expires_in.to_i - 10 @@ -465,30 +465,30 @@ def request! expect(expires_time > Time.now.utc + max_age - 60).to be_truthy end - it "sends the file in binary" do + it 'sends the file in binary' do expect(subject.body) .to match(mock_file.read) end end - context "for a local text file" do - it_behaves_like "for a local file" do - let(:mock_file) { FileHelpers.mock_uploaded_file name: "foobar.txt" } + context 'for a local text file' do + it_behaves_like 'for a local file' do + let(:mock_file) { FileHelpers.mock_uploaded_file name: 'foobar.txt' } let(:content_disposition) { "inline; filename=foobar.txt" } end end - context "for a local binary file" do - it_behaves_like "for a local file" do - let(:mock_file) { FileHelpers.mock_uploaded_file name: "foobar.dat", content_type: "application/octet-stream" } + context 'for a local binary file' do + it_behaves_like 'for a local file' do + let(:mock_file) { FileHelpers.mock_uploaded_file name: 'foobar.dat', content_type: "application/octet-stream" } let(:content_disposition) { "attachment; filename=foobar.dat" } end end - context "for a local json file" do - it_behaves_like "for a local file" do + context 'for a local json file' do + it_behaves_like 'for a local file' do let(:mock_file) do - FileHelpers.mock_uploaded_file(name: "foobar.json", + FileHelpers.mock_uploaded_file(name: 'foobar.json', content_type: "application/json", content: '{"id": "12342"}') end @@ -496,9 +496,9 @@ def request! end end - context "for a remote file" do - let(:external_url) { "http://some_service.org/blubs.gif" } - let(:mock_file) { FileHelpers.mock_uploaded_file name: "foobar.txt" } + context 'for a remote file' do + let(:external_url) { 'http://some_service.org/blubs.gif' } + let(:mock_file) { FileHelpers.mock_uploaded_file name: 'foobar.txt' } let(:attachment) do create(:attachment, container:, file: mock_file, author: current_user).tap do # need to mock here to avoid dependency on external service @@ -508,9 +508,9 @@ def request! end end - it "responds with 302 Redirect" do + it 'responds with 302 Redirect' do expect(subject.status).to eq 302 - expect(subject.headers["Location"]) + expect(subject.headers['Location']) .to eql external_url max_age = OpenProject::Configuration.fog_download_url_expires_in.to_i - 10 @@ -527,15 +527,15 @@ def request! end end - context "by container", if: include_by_container do - it_behaves_like "it supports direct uploads" do + context 'by container', if: include_by_container do + it_behaves_like 'it supports direct uploads' do let(:request_path) { "/api/v3/#{attachment_type}s/#{container.id}/attachments/prepare" } let(:container_href) { "/api/v3/#{attachment_type}s/#{container.id}" } end subject(:response) { last_response } - describe "#get" do + describe '#get' do let(:get_path) { api_v3_paths.send :"attachments_by_#{attachment_type}", container.id } before do @@ -543,18 +543,18 @@ def request! get get_path end - it "responds with 200" do + it 'responds with 200' do expect(subject.status).to eq(200) end - it_behaves_like "API V3 collection response", 2, 2, "Attachment" + it_behaves_like 'API V3 collection response', 2, 2, 'Attachment' end - describe "#post" do + describe '#post' do let(:request_path) { api_v3_paths.send :"attachments_by_#{attachment_type}", container.id } let(:request_parts) { { metadata: metadata.to_json, file: } } - let(:metadata) { { fileName: "cat.png" } } - let(:file) { mock_uploaded_file(name: "original-filename.txt") } + let(:metadata) { { fileName: 'cat.png' } } + let(:file) { mock_uploaded_file(name: 'original-filename.txt') } let(:max_file_size) { 1 } # given in kiB before do @@ -562,73 +562,73 @@ def request! post request_path, request_parts end - it "responds with HTTP Created" do + it 'responds with HTTP Created' do expect(subject.status).to eq(201) end - it "returns the new attachment" do - expect(subject.body).to be_json_eql("Attachment".to_json).at_path("_type") + it 'returns the new attachment' do + expect(subject.body).to be_json_eql('Attachment'.to_json).at_path('_type') end - it "ignores the original file name" do - expect(subject.body).to be_json_eql("cat.png".to_json).at_path("fileName") + it 'ignores the original file name' do + expect(subject.body).to be_json_eql('cat.png'.to_json).at_path('fileName') end - context "metadata section is missing" do + context 'metadata section is missing' do let(:request_parts) { { file: } } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do # File here is the localized name for fileName property # which is derived from the missing metadata let(:message) { "File #{I18n.t('activerecord.errors.messages.blank')}" } end end - context "file section is missing" do + context 'file section is missing' do # rack-test won't send a multipart request without a file being present # however as long as we depend on correctly named sections this test should do just fine let(:request_parts) { { metadata: metadata.to_json, wrongFileSection: file } } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "The content type of the file cannot be blank." } end end - context "metadata section is no valid JSON" do + context 'metadata section is no valid JSON' do let(:request_parts) { { metadata: '"fileName": "cat.png"', file: } } - it_behaves_like "parse error" + it_behaves_like 'parse error' end - context "metadata is missing the fileName" do + context 'metadata is missing the fileName' do let(:metadata) { Hash.new } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "File #{I18n.t('activerecord.errors.messages.blank')}" } end end - context "file is too large" do - let(:file) { mock_uploaded_file(content: "a" * 2.kilobytes) } + context 'file is too large' do + let(:file) { mock_uploaded_file(content: 'a' * 2.kilobytes) } let(:expanded_localization) do - I18n.t("activerecord.errors.messages.file_too_large", count: max_file_size.kilobytes) + I18n.t('activerecord.errors.messages.file_too_large', count: max_file_size.kilobytes) end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "File #{expanded_localization}" } end end - context "only allowed to add, but not to edit" do + context 'only allowed to add, but not to edit' do let(:permissions) { [create_permission, read_permission].flatten.uniq.compact.without(update_permission) } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "only allowed to view" do + context 'only allowed to view' do let(:permissions) { Array(read_permission) } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/attachments/forum_message_spec.rb b/spec/requests/api/v3/attachments/forum_message_spec.rb index ba60dcf4ad05..c418dfc863ff 100644 --- a/spec/requests/api/v3/attachments/forum_message_spec.rb +++ b/spec/requests/api/v3/attachments/forum_message_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "attachment_resource_shared_examples" +require 'spec_helper' +require_relative 'attachment_resource_shared_examples' RSpec.describe "forum message attachments" do it_behaves_like "an APIv3 attachment resource", include_by_container: false do diff --git a/spec/requests/api/v3/attachments/wiki_page_spec.rb b/spec/requests/api/v3/attachments/wiki_page_spec.rb index fabf9ab0f553..7b4c0263c331 100644 --- a/spec/requests/api/v3/attachments/wiki_page_spec.rb +++ b/spec/requests/api/v3/attachments/wiki_page_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "attachment_resource_shared_examples" +require 'spec_helper' +require_relative 'attachment_resource_shared_examples' RSpec.describe "wiki page attachments" do it_behaves_like "an APIv3 attachment resource" do diff --git a/spec/requests/api/v3/attachments/work_package_spec.rb b/spec/requests/api/v3/attachments/work_package_spec.rb index ed1fe4caa207..c613a842b310 100644 --- a/spec/requests/api/v3/attachments/work_package_spec.rb +++ b/spec/requests/api/v3/attachments/work_package_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "attachment_resource_shared_examples" +require 'spec_helper' +require_relative 'attachment_resource_shared_examples' RSpec.describe "work package attachments" do it_behaves_like "an APIv3 attachment resource" do @@ -42,7 +42,7 @@ end end - context "with :add_work_package_attachments as update permission" do + context 'with :add_work_package_attachments as update permission' do it_behaves_like "an APIv3 attachment resource" do let(:attachment_type) { :work_package } diff --git a/spec/requests/api/v3/attachments/work_packages_export_spec.rb b/spec/requests/api/v3/attachments/work_packages_export_spec.rb index dc115971db6f..74987c5c80ea 100644 --- a/spec/requests/api/v3/attachments/work_packages_export_spec.rb +++ b/spec/requests/api/v3/attachments/work_packages_export_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "attachment_resource_shared_examples" +require 'spec_helper' +require_relative 'attachment_resource_shared_examples' RSpec.describe "#{WorkPackages::Export} attachments" do it_behaves_like "an APIv3 attachment resource", include_by_container: false do @@ -44,7 +44,7 @@ let(:other_user_attachment) { create(:attachment, container: export, author: other_user) } - describe "#get" do + describe '#get' do subject(:response) { last_response } let(:get_path) { api_v3_paths.attachment attachment.id } @@ -53,23 +53,23 @@ get get_path end - context "for a user different from the author" do + context 'for a user different from the author' do let(:attachment) { other_user_attachment } - it "responds with 404" do + it 'responds with 404' do expect(subject.status).to eq(404) end end end - describe "#delete" do + describe '#delete' do let(:path) { api_v3_paths.attachment attachment.id } before do delete path end - context "for a user different from the author" do + context 'for a user different from the author' do let(:attachment) { other_user_attachment } subject(:response) { last_response } @@ -78,13 +78,13 @@ expect(subject.status).to eq 404 end - it "does not delete the attachment" do + it 'does not delete the attachment' do expect(Attachment.exists?(attachment.id)).to be_truthy end end end - describe "#content" do + describe '#content' do let(:path) { api_v3_paths.attachment_content attachment.id } before do @@ -93,7 +93,7 @@ subject(:response) { last_response } - context "for a user different from the author" do + context 'for a user different from the author' do let(:attachment) { other_user_attachment } it "responds with 404" do diff --git a/spec/requests/api/v3/attachments_spec.rb b/spec/requests/api/v3/attachments_spec.rb index 3385e8b8dc9d..d84b9e539c05 100644 --- a/spec/requests/api/v3/attachments_spec.rb +++ b/spec/requests/api/v3/attachments_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "attachments/attachment_resource_shared_examples" +require 'spec_helper' +require_relative 'attachments/attachment_resource_shared_examples' RSpec.describe API::V3::Attachments::AttachmentsAPI do include Rack::Test::Methods @@ -40,47 +40,47 @@ let(:role) { create(:project_role, permissions:) } let(:permissions) { [:add_work_packages] } - describe "permissions", :with_direct_uploads do + describe 'permissions', :with_direct_uploads do let(:request_path) { api_v3_paths.prepare_new_attachment_upload } let(:request_parts) { { metadata: metadata.to_json, file: } } - let(:metadata) { { fileName: "cat.png", fileSize: file.size, contentType: "image/png" } } - let(:file) { mock_uploaded_file(name: "original-filename.txt") } + let(:metadata) { { fileName: 'cat.png', fileSize: file.size, contentType: 'image/png' } } + let(:file) { mock_uploaded_file(name: 'original-filename.txt') } before do allow(User).to receive(:current).and_return current_user post request_path, request_parts end - context "with missing permissions" do + context 'with missing permissions' do let(:permissions) { [] } - it "forbids to prepare attachments" do + it 'forbids to prepare attachments' do expect(last_response.status).to eq 403 end end - context "with :edit_work_packages permission" do + context 'with :edit_work_packages permission' do let(:permissions) { [:edit_work_packages] } - it "can prepare attachments" do + it 'can prepare attachments' do expect(last_response.status).to eq 201 end end - context "with :add_work_package_attachments permission" do + context 'with :add_work_package_attachments permission' do let(:permissions) { [:add_work_package_attachments] } - it "can prepare attachments" do + it 'can prepare attachments' do expect(last_response.status).to eq 201 end end end - it_behaves_like "it supports direct uploads" do + it_behaves_like 'it supports direct uploads' do let(:request_path) { api_v3_paths.prepare_new_attachment_upload } let(:container_href) { nil } - describe "GET /uploaded" do + describe 'GET /uploaded' do let(:status) { :prepared } let(:attachment) do create(:attachment, status:, author: current_user, container: nil, container_type: nil) @@ -90,24 +90,24 @@ get "/api/v3/attachments/#{attachment.id}/uploaded" end - context "with no pending attachments" do + context 'with no pending attachments' do let(:status) { :uploaded } - it "returns 404" do + it 'returns 404' do expect(last_response.status).to eq 404 end end - context "with a pending attachment" do - it "enqueues a FinishDirectUpload job" do + context 'with a pending attachment' do + it 'enqueues a FinishDirectUpload job' do expect(Attachments::FinishDirectUploadJob).to have_been_enqueued.at_least(1) end - it "responds with HTTP OK" do + it 'responds with HTTP OK' do expect(last_response.status).to eq 200 end - it "returns the attachment representation" do + it 'returns the attachment representation' do json = JSON.parse last_response.body expect(json["_type"]).to eq "Attachment" @@ -116,5 +116,5 @@ end end - context "with an quarantined attachments" + context 'with an quarantined attachments' end diff --git a/spec/requests/api/v3/authentication_spec.rb b/spec/requests/api/v3/authentication_spec.rb index 10ee53ab5769..da10b365ec93 100644 --- a/spec/requests/api/v3/authentication_spec.rb +++ b/spec/requests/api/v3/authentication_spec.rb @@ -26,256 +26,256 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3 do let(:resource) { "/api/v3/projects" } let(:user) { create(:user) } - describe "oauth" do - let(:oauth_access_token) { "" } + describe 'oauth' do + let(:oauth_access_token) { '' } before do login_as user - header "Authorization", "Bearer #{oauth_access_token}" + header 'Authorization', "Bearer #{oauth_access_token}" get resource end - context "with a valid access token" do + context 'with a valid access token' do let(:token) { create(:oauth_access_token, resource_owner: user) } let(:oauth_access_token) { token.plaintext_token } - it "authenticates successfully" do + it 'authenticates successfully' do expect(last_response.status).to eq 200 end end - context "with an invalid access token" do - let(:oauth_access_token) { "1337" } + context 'with an invalid access token' do + let(:oauth_access_token) { '1337' } - it "returns unauthorized" do + it 'returns unauthorized' do expect(last_response.status).to eq 401 end end - context "with an expired access token" do + context 'with an expired access token' do let(:token) { create(:oauth_access_token, resource_owner: user, revoked_at: DateTime.now) } let(:oauth_access_token) { token.plaintext_token } - it "returns unauthorized" do + it 'returns unauthorized' do expect(last_response.status).to eq 401 end end end - describe "basic auth" do + describe 'basic auth' do let(:response_401) do { - "_type" => "Error", - "errorIdentifier" => "urn:openproject-org:api:v3:errors:Unauthenticated", - "message" => expected_message + '_type' => 'Error', + 'errorIdentifier' => 'urn:openproject-org:api:v3:errors:Unauthenticated', + 'message' => expected_message } end - let(:expected_message) { "You need to be authenticated to access this resource." } + let(:expected_message) { 'You need to be authenticated to access this resource.' } strategies = OpenProject::Authentication::Strategies::Warden def set_basic_auth_header(user, password) credentials = ActionController::HttpAuthentication::Basic.encode_credentials user, password - header "Authorization", credentials + header 'Authorization', credentials end - shared_examples "it is basic auth protected" do - context "when not allowed", with_config: { apiv3_enable_basic_auth: false } do - context "with valid credentials" do + shared_examples 'it is basic auth protected' do + context 'when not allowed', with_config: { apiv3_enable_basic_auth: false } do + context 'with valid credentials' do before do set_basic_auth_header(username, password) get resource end - it "returns 401 unauthorized" do + it 'returns 401 unauthorized' do expect(last_response.status).to eq 401 end end end - context "when allowed", with_config: { apiv3_enable_basic_auth: true } do - context "without credentials" do + context 'when allowed', with_config: { apiv3_enable_basic_auth: true } do + context 'without credentials' do before do get resource end - it "returns 401 unauthorized" do + it 'returns 401 unauthorized' do expect(last_response.status).to eq 401 end - it "returns the correct JSON response" do + it 'returns the correct JSON response' do expect(JSON.parse(last_response.body)).to eq response_401 end - it "returns the WWW-Authenticate header" do - expect(last_response.header["WWW-Authenticate"]) + it 'returns the WWW-Authenticate header' do + expect(last_response.header['WWW-Authenticate']) .to include 'Basic realm="OpenProject API"' end end - context "with invalid credentials" do - let(:expected_message) { "You did not provide the correct credentials." } + context 'with invalid credentials' do + let(:expected_message) { 'You did not provide the correct credentials.' } before do set_basic_auth_header(username, password.reverse) get resource end - it "returns 401 unauthorized" do + it 'returns 401 unauthorized' do expect(last_response.status).to eq 401 end - it "returns the correct JSON response" do + it 'returns the correct JSON response' do expect(JSON.parse(last_response.body)).to eq response_401 end - it "returns the correct content type header" do - expect(last_response.headers["Content-Type"]).to eq "application/hal+json; charset=utf-8" + it 'returns the correct content type header' do + expect(last_response.headers['Content-Type']).to eq 'application/hal+json; charset=utf-8' end - it "returns the WWW-Authenticate header" do - expect(last_response.header["WWW-Authenticate"]) + it 'returns the WWW-Authenticate header' do + expect(last_response.header['WWW-Authenticate']) .to include 'Basic realm="OpenProject API"' end end - context "with no credentials" do - let(:expected_message) { "You need to be authenticated to access this resource." } + context 'with no credentials' do + let(:expected_message) { 'You need to be authenticated to access this resource.' } before do - post "/api/v3/time_entries/form" + post '/api/v3/time_entries/form' end - it "returns 401 unauthorized" do + it 'returns 401 unauthorized' do expect(last_response.status).to eq 401 end - it "returns the correct JSON response" do + it 'returns the correct JSON response' do expect(JSON.parse(last_response.body)).to eq response_401 end - it "returns the correct content type header" do - expect(last_response.headers["Content-Type"]).to eq "application/hal+json; charset=utf-8" + it 'returns the correct content type header' do + expect(last_response.headers['Content-Type']).to eq 'application/hal+json; charset=utf-8' end - it "returns the WWW-Authenticate header" do - expect(last_response.header["WWW-Authenticate"]) + it 'returns the WWW-Authenticate header' do + expect(last_response.header['WWW-Authenticate']) .to include 'Basic realm="OpenProject API"' end end context 'with invalid credentials an X-Authentication-Scheme "Session"' do - let(:expected_message) { "You did not provide the correct credentials." } + let(:expected_message) { 'You did not provide the correct credentials.' } before do set_basic_auth_header(username, password.reverse) - header "X-Authentication-Scheme", "Session" + header 'X-Authentication-Scheme', 'Session' get resource end - it "returns 401 unauthorized" do + it 'returns 401 unauthorized' do expect(last_response.status).to eq 401 end - it "returns the correct JSON response" do + it 'returns the correct JSON response' do expect(JSON.parse(last_response.body)).to eq response_401 end - it "returns the correct content type header" do - expect(last_response.headers["Content-Type"]).to eq "application/hal+json; charset=utf-8" + it 'returns the correct content type header' do + expect(last_response.headers['Content-Type']).to eq 'application/hal+json; charset=utf-8' end - it "returns the WWW-Authenticate header" do - expect(last_response.header["WWW-Authenticate"]) + it 'returns the WWW-Authenticate header' do + expect(last_response.header['WWW-Authenticate']) .to include 'Session realm="OpenProject API"' end end - context "with valid credentials" do + context 'with valid credentials' do before do set_basic_auth_header(username, password) get resource end - it "returns 200 OK" do + it 'returns 200 OK' do expect(last_response.status).to eq 200 end end end end - context "with login required" do + context 'with login required' do before do allow(Setting).to receive(:login_required).and_return(true) allow(Setting).to receive(:login_required?).and_return(true) end - context "with global basic auth configured" do - let(:username) { "root" } - let(:password) { "toor" } + context 'with global basic auth configured' do + let(:username) { 'root' } + let(:password) { 'toor' } before do - strategies::GlobalBasicAuth.configure! user: "root", password: "toor" + strategies::GlobalBasicAuth.configure! user: 'root', password: 'toor' end - it_behaves_like "it is basic auth protected" + it_behaves_like 'it is basic auth protected' - describe "user basic auth" do + describe 'user basic auth' do let(:api_key) { create(:api_token) } - let(:username) { "apikey" } + let(:username) { 'apikey' } let(:password) { api_key.plain_value } # check that user basic auth is tried when global basic auth fails - it_behaves_like "it is basic auth protected" + it_behaves_like 'it is basic auth protected' end end - describe "user basic auth" do + describe 'user basic auth' do let(:api_key) { create(:api_token) } - let(:username) { "apikey" } + let(:username) { 'apikey' } let(:password) { api_key.plain_value } # check that user basic auth works on its own too - it_behaves_like "it is basic auth protected" + it_behaves_like 'it is basic auth protected' end end - context "when enabled", with_config: { apiv3_enable_basic_auth: true } do - context "without login required" do + context 'when enabled', with_config: { apiv3_enable_basic_auth: true } do + context 'without login required' do before do allow(Setting).to receive(:login_required).and_return(false) allow(Setting).to receive(:login_required?).and_return(false) end - context "with global and user basic auth enabled" do - let(:username) { "hancholo" } - let(:password) { "olooleol" } + context 'with global and user basic auth enabled' do + let(:username) { 'hancholo' } + let(:password) { 'olooleol' } - let(:api_user) { create(:user, login: "user_account") } + let(:api_user) { create(:user, login: 'user_account') } let(:api_key) { create(:api_token, user: api_user) } before do - config = { user: "global_account", password: "global_password" } + config = { user: 'global_account', password: 'global_password' } strategies::GlobalBasicAuth.configure! config end - context "without credentials" do + context 'without credentials' do before do get resource end - it "returns 200 OK" do + it 'returns 200 OK' do expect(last_response.status).to eq 200 end @@ -284,35 +284,35 @@ def set_basic_auth_header(user, password) end end - context "with invalid credentials" do + context 'with invalid credentials' do before do set_basic_auth_header(username, password) get resource end - it "returns 401 unauthorized" do + it 'returns 401 unauthorized' do expect(last_response.status).to eq 401 end end - context "with valid global credentials" do + context 'with valid global credentials' do before do - set_basic_auth_header("global_account", "global_password") + set_basic_auth_header('global_account', 'global_password') get resource end - it "returns 200 OK" do + it 'returns 200 OK' do expect(last_response.status).to eq 200 end end - context "with valid user credentials" do + context 'with valid user credentials' do before do - set_basic_auth_header("apikey", api_key.plain_value) + set_basic_auth_header('apikey', api_key.plain_value) get resource end - it "returns 200 OK" do + it 'returns 200 OK' do expect(last_response.status).to eq 200 end end diff --git a/spec/requests/api/v3/backups/backups_api_spec.rb b/spec/requests/api/v3/backups/backups_api_spec.rb index dc964fc06b5d..b4650e29536d 100644 --- a/spec/requests/api/v3/backups/backups_api_spec.rb +++ b/spec/requests/api/v3/backups/backups_api_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Backups::BackupsAPI, with_config: { backup_enabled: true } do include API::V3::Utilities::PathHelper diff --git a/spec/requests/api/v3/capabilities/contexts/global_resource_spec.rb b/spec/requests/api/v3/capabilities/contexts/global_resource_spec.rb index 31e55e45ed0e..20cda7382b27 100644 --- a/spec/requests/api/v3/capabilities/contexts/global_resource_spec.rb +++ b/spec/requests/api/v3/capabilities/contexts/global_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 capabilities global context resource", content_type: :json do +RSpec.describe 'API v3 capabilities global context resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -39,26 +39,26 @@ create(:user) end - describe "GET /api/v3/capabilities/contexts/global" do + describe 'GET /api/v3/capabilities/contexts/global' do let(:path) { api_v3_paths.capabilities_contexts_global } before do get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be 200 end - it "returns the global context" do + it 'returns the global context' do expect(subject.body) - .to be_json_eql("CapabilityContext".to_json) - .at_path("_type") + .to be_json_eql('CapabilityContext'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("global".to_json) - .at_path("id") + .to be_json_eql('global'.to_json) + .at_path('id') end end end diff --git a/spec/requests/api/v3/capability_resource_spec.rb b/spec/requests/api/v3/capability_resource_spec.rb index da554fbda8a4..6a9a64f5ac84 100644 --- a/spec/requests/api/v3/capability_resource_spec.rb +++ b/spec/requests/api/v3/capability_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 capabilities resource", content_type: :json do +RSpec.describe 'API v3 capabilities resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -60,7 +60,7 @@ project:) end - describe "GET api/v3/capabilities" do + describe 'GET api/v3/capabilities' do let(:setup) do other_user_global_member other_user_member @@ -74,45 +74,45 @@ get path end - context "without params" do - it "responds 400 Bad Request" do + context 'without params' do + it 'responds 400 Bad Request' do expect(subject.status).to eq(400) end - it "communicates that either a context or a principal filter is required" do + it 'communicates that either a context or a principal filter is required' do expect(subject.body) - .to be_json_eql("Error".to_json) - .at_path("_type") + .to be_json_eql('Error'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:InvalidQuery'.to_json) + .at_path('errorIdentifier') end end - context "when filtering by principal id (with a user)" do + context 'when filtering by principal id (with a user)' do let(:filters) do - [{ "principalId" => { - "operator" => "=", - "values" => [current_user.id.to_s] + [{ 'principalId' => { + 'operator' => '=', + 'values' => [current_user.id.to_s] } }] end - it "contains only the filtered capabilities in the response" do + it 'contains only the filtered capabilities in the response' do expect(subject.body) - .to be_json_eql("4") - .at_path("total") + .to be_json_eql('4') + .at_path('total') expect(subject.body) .to be_json_eql(api_v3_paths.user(current_user.id).to_json) - .at_path("_embedded/elements/0/_links/principal/href") + .at_path('_embedded/elements/0/_links/principal/href') end end - context "with pageSize, offset and sortBy and filter" do + context 'with pageSize, offset and sortBy and filter' do def expect_self_link(link, overrides = {}) - href = JSON.parse(subject.body).dig("_links", link, "href").split("?") - expected_path_params = Rack::Utils.parse_nested_query(path.split("?").last) + href = JSON.parse(subject.body).dig('_links', link, 'href').split('?') + expected_path_params = Rack::Utils.parse_nested_query(path.split('?').last) expect(href.first) .to eql(api_v3_paths.capabilities) @@ -122,52 +122,52 @@ def expect_self_link(link, overrides = {}) end let(:filters) do - [{ "principal" => { - "operator" => "=", - "values" => [other_user.id.to_s] + [{ 'principal' => { + 'operator' => '=', + 'values' => [other_user.id.to_s] } }] end let(:path) do api_v3_paths.path_for(:capabilities, filters:, sort_by: [%i(id asc)], - select: "*,elements/*", + select: '*,elements/*', page_size: 2, offset: 3) end - it "returns a slice of the visible memberships" do + it 'returns a slice of the visible memberships' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("7") - .at_path("total") + .to be_json_eql('7') + .at_path('total') expect(subject.body) - .to be_json_eql("2") - .at_path("count") + .to be_json_eql('2') + .at_path('count') expect(subject.body) .to be_json_eql("users/create/g-#{other_user.id}".to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end - it "includes links for self and jumping" do - expect_self_link("self") - expect_self_link("jumpTo", "offset" => "{offset}") - expect_self_link("changeSize", "pageSize" => "{size}") - expect_self_link("previousByOffset", "offset" => "2") - expect_self_link("nextByOffset", "offset" => "4") + it 'includes links for self and jumping' do + expect_self_link('self') + expect_self_link('jumpTo', 'offset' => '{offset}') + expect_self_link('changeSize', 'pageSize' => '{size}') + expect_self_link('previousByOffset', 'offset' => '2') + expect_self_link('nextByOffset', 'offset' => '4') end end - context "when filtering by principal id (group)" do + context 'when filtering by principal id (group)' do let(:filters) do - [{ "principalId" => { - "operator" => "=", - "values" => [group.id.to_s] + [{ 'principalId' => { + 'operator' => '=', + 'values' => [group.id.to_s] } }] end let(:other_user) { group } @@ -177,26 +177,26 @@ def expect_self_link(link, overrides = {}) other_user_member end - it "returns a collection of capabilities" do + it 'returns a collection of capabilities' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("4") - .at_path("total") + .to be_json_eql('4') + .at_path('total') expect(subject.body) .to be_json_eql("activities/read/p#{project.id}-#{other_user.id}".to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "when filtering by principal id (placeholder user)" do + context 'when filtering by principal id (placeholder user)' do let(:filters) do - [{ "principalId" => { - "operator" => "=", - "values" => [placeholder_user.id.to_s] + [{ 'principalId' => { + 'operator' => '=', + 'values' => [placeholder_user.id.to_s] } }] end let(:other_user) { placeholder_user } @@ -208,69 +208,69 @@ def expect_self_link(link, overrides = {}) other_user_member end - it "returns a collection of capabilities" do + it 'returns a collection of capabilities' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("4") - .at_path("total") + .to be_json_eql('4') + .at_path('total') expect(subject.body) .to be_json_eql("activities/read/p#{project.id}-#{other_user.id}".to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "when filtering by principal id (with a user) but with the not operator" do + context 'when filtering by principal id (with a user) but with the not operator' do let(:filters) do - [{ "principalId" => { - "operator" => "!", - "values" => [current_user.id.to_s] + [{ 'principalId' => { + 'operator' => '!', + 'values' => [current_user.id.to_s] } }] end - it "responds 400 Bad Request" do + it 'responds 400 Bad Request' do expect(subject.status).to eq(400) end - it "communicates that either a context or a principal filter is required" do + it 'communicates that either a context or a principal filter is required' do expect(subject.body) - .to be_json_eql("Error".to_json) - .at_path("_type") + .to be_json_eql('Error'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:InvalidQuery'.to_json) + .at_path('errorIdentifier') end end - context "with an invalid filter" do + context 'with an invalid filter' do let(:filters) do - [{ "bogus" => { - "operator" => "=", - "values" => [current_user.id.to_s] + [{ 'bogus' => { + 'operator' => '=', + 'values' => [current_user.id.to_s] } }] end - it "returns 422" do + it 'returns 422' do expect(subject.status) .to be 422 end - it "communicates the error message" do + it 'communicates the error message' do expect(subject.body) - .to be_json_eql("Error".to_json) - .at_path("_type") + .to be_json_eql('Error'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:MultipleErrors".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:MultipleErrors'.to_json) + .at_path('errorIdentifier') end end - context "when filtering by project context" do + context 'when filtering by project context' do let(:other_project) { create(:project) } let(:other_user_other_member) do create(:member, @@ -280,9 +280,9 @@ def expect_self_link(link, overrides = {}) end let(:filters) do - [{ "context" => { - "operator" => "=", - "values" => ["p#{other_project.id}"] + [{ 'context' => { + 'operator' => '=', + 'values' => ["p#{other_project.id}"] } }] end @@ -292,47 +292,47 @@ def expect_self_link(link, overrides = {}) other_user_other_member end - it "contains only the filtered capabilities in the response" do + it 'contains only the filtered capabilities in the response' do expect(subject.body) - .to be_json_eql("4") - .at_path("total") + .to be_json_eql('4') + .at_path('total') expect(subject.body) .to be_json_eql(api_v3_paths.project(other_project.id).to_json) - .at_path("_embedded/elements/0/_links/context/href") + .at_path('_embedded/elements/0/_links/context/href') end end - context "when filtering by global context" do + context 'when filtering by global context' do let(:filters) do - [{ "context" => { - "operator" => "=", - "values" => ["g"] + [{ 'context' => { + 'operator' => '=', + 'values' => ["g"] } }] end - it "contains only the filtered capabilities in the response" do + it 'contains only the filtered capabilities in the response' do expect(subject.body) - .to be_json_eql("3") - .at_path("total") + .to be_json_eql('3') + .at_path('total') expect(subject.body) .to be_json_eql(api_v3_paths.capabilities_contexts_global.to_json) - .at_path("_embedded/elements/0/_links/context/href") + .at_path('_embedded/elements/0/_links/context/href') end end - context "when signaling to only include a subset of properties" do - let(:path) { api_v3_paths.path_for(:capabilities, filters:, sort_by: [%i(id asc)], select: "elements/id") } + context 'when signaling to only include a subset of properties' do + let(:path) { api_v3_paths.path_for(:capabilities, filters:, sort_by: [%i(id asc)], select: 'elements/id') } let(:filters) do - [{ "principalId" => { - "operator" => "=", - "values" => [current_user.id.to_s] + [{ 'principalId' => { + 'operator' => '=', + 'values' => [current_user.id.to_s] } }] end - it "contains only the filtered capabilities in the response" do + it 'contains only the filtered capabilities in the response' do expected = { _embedded: { elements: [ @@ -357,38 +357,38 @@ def expect_self_link(link, overrides = {}) end end - context "without permissions" do + context 'without permissions' do current_user do create(:user) end let(:filters) do - [{ "context" => { - "operator" => "=", - "values" => ["g"] + [{ 'context' => { + 'operator' => '=', + 'values' => ["g"] } }] end - it "is empty and includes an empty element set", :aggregate_failures do + it 'is empty and includes an empty element set', :aggregate_failures do expect(subject.body) - .to be_json_eql("0") - .at_path("total") + .to be_json_eql('0') + .at_path('total') expect(subject.body) .to be_json_eql([].to_json) - .at_path("_embedded/elements") + .at_path('_embedded/elements') end end - context "when filtering by action" do + context 'when filtering by action' do let(:filters) do - [{ "action" => { - "operator" => "=", - "values" => ["memberships/create"] + [{ 'action' => { + 'operator' => '=', + 'values' => ["memberships/create"] } }, - { "principalId" => { - "operator" => "=", - "values" => [other_user.id.to_s] + { 'principalId' => { + 'operator' => '=', + 'values' => [other_user.id.to_s] } }] end @@ -396,19 +396,19 @@ def expect_self_link(link, overrides = {}) other_user_member end - it "contains only the filtered capabilities in the response" do + it 'contains only the filtered capabilities in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql("memberships/create/p#{project.id}-#{other_user.id}".to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end end - describe "GET /api/v3/capabilities/:id" do + describe 'GET /api/v3/capabilities/:id' do let(:path) { api_v3_paths.capability("memberships/create/p#{project.id}-#{other_user.id}") } let(:setup) do @@ -421,45 +421,45 @@ def expect_self_link(link, overrides = {}) get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the capability" do + it 'returns the capability' do expect(subject.body) - .to be_json_eql("Capability".to_json) - .at_path("_type") + .to be_json_eql('Capability'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql("memberships/create/p#{project.id}-#{other_user.id}".to_json) - .at_path("id") + .at_path('id') end - context "if querying a non existing capability" do + context 'if querying a non existing capability' do let(:path) { api_v3_paths.capability("foo/bar/p#{project.id}-#{other_user.id}") } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be 404 end end - context "if querying with malformed id" do + context 'if querying with malformed id' do let(:path) { api_v3_paths.capability("foo/bar/baz-5") } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be 404 end end - context "if querying for an invisible user" do + context 'if querying for an invisible user' do current_user do create(:user) end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be 404 end diff --git a/spec/requests/api/v3/category_resource_spec.rb b/spec/requests/api/v3/category_resource_spec.rb index b4ad3aaea0eb..a7a2fb3d0e4c 100644 --- a/spec/requests/api/v3/category_resource_spec.rb +++ b/spec/requests/api/v3/category_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Category resource" do +RSpec.describe 'API v3 Category resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -51,10 +51,10 @@ assigned_to: privileged_user) end - describe "categories by project" do + describe 'categories by project' do subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do let(:get_path) { api_v3_paths.categories_by_project private_project.id } before do @@ -63,10 +63,10 @@ get get_path end - it_behaves_like "API V3 collection response", 5, 5, "Category" + it_behaves_like 'API V3 collection response', 5, 5, 'Category' end - context "not logged in user" do + context 'not logged in user' do let(:get_path) { api_v3_paths.categories_by_project private_project.id } before do @@ -75,14 +75,14 @@ get get_path end - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "categories/:id" do + describe 'categories/:id' do subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do let(:get_path) { api_v3_paths.category categories.first.id } before do @@ -91,24 +91,24 @@ get get_path end - context "valid priority id" do - it "returns HTTP 200" do + context 'valid priority id' do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "invalid priority id" do - let(:get_path) { api_v3_paths.category "bogus" } + context 'invalid priority id' do + let(:get_path) { api_v3_paths.category 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } - let(:type) { "Category" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + let(:type) { 'Category' } end end end - context "not logged in user" do - let(:get_path) { api_v3_paths.category "bogus" } + context 'not logged in user' do + let(:get_path) { api_v3_paths.category 'bogus' } before do allow(User).to receive(:current).and_return anonymous_user @@ -116,9 +116,9 @@ get get_path end - it_behaves_like "param validation error" do - let(:id) { "bogus" } - let(:type) { "Category" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + let(:type) { 'Category' } end end end diff --git a/spec/requests/api/v3/configuration_resource_spec.rb b/spec/requests/api/v3/configuration_resource_spec.rb index 6d24e6b4c23c..ac0ea1aed0ae 100644 --- a/spec/requests/api/v3/configuration_resource_spec.rb +++ b/spec/requests/api/v3/configuration_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Configuration resource" do +RSpec.describe 'API v3 Configuration resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -44,38 +44,38 @@ last_response end - describe "#GET" do - it "returns 200 OK" do + describe '#GET' do + it 'returns 200 OK' do expect(subject.status).to eq(200) end - it "returns the configuration", with_settings: { per_page_options: "3, 5, 8, 13" } do + it 'returns the configuration', with_settings: { per_page_options: '3, 5, 8, 13' } do expect(subject.body) - .to be_json_eql("Configuration".to_json) + .to be_json_eql('Configuration'.to_json) .at_path("_type") expect(subject.body) .to be_json_eql([3, 5, 8, 13].to_json) - .at_path("perPageOptions") + .at_path('perPageOptions') end - it "embedds the current user preferences" do + it 'embedds the current user preferences' do expect(subject.body) - .to be_json_eql("UserPreferences".to_json) - .at_path("_embedded/userPreferences/_type") + .to be_json_eql('UserPreferences'.to_json) + .at_path('_embedded/userPreferences/_type') end - it "does not embed the preferences" do + it 'does not embed the preferences' do expect(subject.body) - .not_to have_json_path("_embedded/user_preferences") + .not_to have_json_path('_embedded/user_preferences') end - context "with feature flags", + context 'with feature flags', :settings_reset, with_env: { - "OPENPROJECT_FEATURE_AN_EXAMPLE_ACTIVE" => "true", - "OPENPROJECT_FEATURE_ANOTHER_EXAMPLE_ACTIVE" => "true", - "OPENPROJECT_FEATURE_INACTIVE_EXAMPLE_ACTIVE" => "false" + 'OPENPROJECT_FEATURE_AN_EXAMPLE_ACTIVE' => 'true', + 'OPENPROJECT_FEATURE_ANOTHER_EXAMPLE_ACTIVE' => 'true', + 'OPENPROJECT_FEATURE_INACTIVE_EXAMPLE_ACTIVE' => 'false' } do before do OpenProject::FeatureDecisions.add :an_example @@ -84,26 +84,26 @@ OpenProject::FeatureDecisions.add :default_example end - it "lists the active feature flags" do + it 'lists the active feature flags' do expect(subject.body) .to be_json_eql(%w[anExample anotherExample].to_json) - .at_path("activeFeatureFlags") + .at_path('activeFeatureFlags') end end - context "for a non logged in user" do + context 'for a non logged in user' do current_user { User.anonymous } - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status).to eq(200) end end - context "for a non logged in user with login_required", + context 'for a non logged in user with login_required', with_settings: { login_required?: true } do current_user { User.anonymous } - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status).to eq(200) end end diff --git a/spec/requests/api/v3/content_type_header_spec.rb b/spec/requests/api/v3/content_type_header_spec.rb index 5bd99118355a..45900ea52473 100644 --- a/spec/requests/api/v3/content_type_header_spec.rb +++ b/spec/requests/api/v3/content_type_header_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Content-Type header" do +RSpec.describe 'API v3 Content-Type header' do include Rack::Test::Methods include Capybara::RSpecMatchers include API::V3::Utilities::PathHelper @@ -46,28 +46,28 @@ end end - describe "a missing Content-Type header" do - context "on a GET request" do - it "is successful" do + describe 'a missing Content-Type header' do + context 'on a GET request' do + it 'is successful' do get api_v3_paths.work_package(work_package.id) expect(last_response.status).not_to eq(406) expect(last_response).to be_ok end end - context "on a DELETE request" do - it "is successful" do + context 'on a DELETE request' do + it 'is successful' do delete api_v3_paths.work_package(work_package.id) expect(last_response.status).not_to eq(406) expect(last_response).to be_no_content end end - context "on any other HTTP method" do - it "responds with a 406 status and a missing Content-Type header message" do + context 'on any other HTTP method' do + it 'responds with a 406 status and a missing Content-Type header message' do patch api_v3_paths.work_package(work_package.id), {} expect(last_response.status).to eq(406) - expect(last_response.body).to include("Missing content-type header") + expect(last_response.body).to include('Missing content-type header') end end end diff --git a/spec/requests/api/v3/cors_header_spec.rb b/spec/requests/api/v3/cors_header_spec.rb index 950392f5fa1a..6694c16640e2 100644 --- a/spec/requests/api/v3/cors_header_spec.rb +++ b/spec/requests/api/v3/cors_header_spec.rb @@ -26,79 +26,79 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 CORS headers", +RSpec.describe 'API v3 CORS headers', content_type: :json do include Rack::Test::Methods include Capybara::RSpecMatchers include API::V3::Utilities::PathHelper - shared_examples "outputs CORS headers" do |request_path| - it "outputs CORS headers", :aggregate_failures do + shared_examples 'outputs CORS headers' do |request_path| + it 'outputs CORS headers', :aggregate_failures do options request_path, nil, - "HTTP_ORIGIN" => "https://foo.example.com", - "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "GET", - "HTTP_ACCESS_CONTROL_REQUEST_HEADERS" => "test" + 'HTTP_ORIGIN' => 'https://foo.example.com', + 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET', + 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'test' - expect(last_response.headers["Access-Control-Allow-Origin"]).to eq("https://foo.example.com") - expect(last_response.headers["Access-Control-Allow-Methods"]).to eq("GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS") - expect(last_response.headers["Access-Control-Allow-Headers"]).to eq("test") - expect(last_response.headers).to have_key("Access-Control-Max-Age") + expect(last_response.headers['Access-Control-Allow-Origin']).to eq('https://foo.example.com') + expect(last_response.headers['Access-Control-Allow-Methods']).to eq('GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS') + expect(last_response.headers['Access-Control-Allow-Headers']).to eq('test') + expect(last_response.headers).to have_key('Access-Control-Max-Age') end - it "rejects CORS headers for invalid origin" do + it 'rejects CORS headers for invalid origin' do options request_path, nil, - "HTTP_ORIGIN" => "invalid.example.com", - "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "GET", - "HTTP_ACCESS_CONTROL_REQUEST_HEADERS" => "test" + 'HTTP_ORIGIN' => 'invalid.example.com', + 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET', + 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'test' - expect(last_response.headers).not_to have_key "Access-Control-Allow-Origin" - expect(last_response.headers).not_to have_key "Access-Control-Allow-Methods" - expect(last_response.headers).not_to have_key "Access-Control-Allow-Headers" - expect(last_response.headers).not_to have_key "Access-Control-Max-Age" + expect(last_response.headers).not_to have_key 'Access-Control-Allow-Origin' + expect(last_response.headers).not_to have_key 'Access-Control-Allow-Methods' + expect(last_response.headers).not_to have_key 'Access-Control-Allow-Headers' + expect(last_response.headers).not_to have_key 'Access-Control-Max-Age' end end - context "with setting enabled", + context 'with setting enabled', with_settings: { apiv3_cors_enabled: true } do - context "with allowed origin set to specific values", + context 'with allowed origin set to specific values', with_settings: { apiv3_cors_origins: %w[https://foo.example.com bla.test] } do - it_behaves_like "outputs CORS headers", "/api/v3" - it_behaves_like "outputs CORS headers", "/oauth/token" - it_behaves_like "outputs CORS headers", "/oauth/authorize" - it_behaves_like "outputs CORS headers", "/oauth/revoke" + it_behaves_like 'outputs CORS headers', '/api/v3' + it_behaves_like 'outputs CORS headers', '/oauth/token' + it_behaves_like 'outputs CORS headers', '/oauth/authorize' + it_behaves_like 'outputs CORS headers', '/oauth/revoke' # CORS needs to output headers even if you're unauthorized to allow authentication # to happen - it "returns the CORS header on an unauthorized resource as well", :aggregate_failures do - options "/api/v3/work_packages/form", + it 'returns the CORS header on an unauthorized resource as well', :aggregate_failures do + options '/api/v3/work_packages/form', nil, - "HTTP_ORIGIN" => "https://foo.example.com" + 'HTTP_ORIGIN' => 'https://foo.example.com' - expect(last_response.headers["Access-Control-Allow-Origin"]).to eq("https://foo.example.com") - expect(last_response.headers["Access-Control-Allow-Methods"]).to eq("GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS") - expect(last_response.headers).to have_key("Access-Control-Max-Age") + expect(last_response.headers['Access-Control-Allow-Origin']).to eq('https://foo.example.com') + expect(last_response.headers['Access-Control-Allow-Methods']).to eq('GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS') + expect(last_response.headers).to have_key('Access-Control-Max-Age') end end end - context "when disabled", + context 'when disabled', with_settings: { apiv3_cors_enabled: false, apiv3_cors_origins: %w[foo.example.com] } do - it "does not output CORS headers even though origin matches", :aggregate_failures do - options "/api/v3", + it 'does not output CORS headers even though origin matches', :aggregate_failures do + options '/api/v3', nil, - "HTTP_ORIGIN" => "foo.example.com", - "HTTP_ACCESS_CONTROL_REQUEST_METHOD" => "GET", - "HTTP_ACCESS_CONTROL_REQUEST_HEADERS" => "test" + 'HTTP_ORIGIN' => 'foo.example.com', + 'HTTP_ACCESS_CONTROL_REQUEST_METHOD' => 'GET', + 'HTTP_ACCESS_CONTROL_REQUEST_HEADERS' => 'test' - expect(last_response.headers).not_to have_key "Access-Control-Allow-Origin" - expect(last_response.headers).not_to have_key "Access-Control-Allow-Methods" - expect(last_response.headers).not_to have_key "Access-Control-Allow-Headers" - expect(last_response.headers).not_to have_key "Access-Control-Max-Age" + expect(last_response.headers).not_to have_key 'Access-Control-Allow-Origin' + expect(last_response.headers).not_to have_key 'Access-Control-Allow-Methods' + expect(last_response.headers).not_to have_key 'Access-Control-Allow-Headers' + expect(last_response.headers).not_to have_key 'Access-Control-Max-Age' end end end diff --git a/spec/requests/api/v3/custom_actions/custom_actions_api_spec.rb b/spec/requests/api/v3/custom_actions/custom_actions_api_spec.rb index 17a4cd6f67a7..7793435f46ca 100644 --- a/spec/requests/api/v3/custom_actions/custom_actions_api_spec.rb +++ b/spec/requests/api/v3/custom_actions/custom_actions_api_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API::V3::CustomActions::CustomActionsAPI" do +RSpec.describe 'API::V3::CustomActions::CustomActionsAPI' do include API::V3::Utilities::PathHelper let(:role) do @@ -63,76 +63,76 @@ login_as(user) end - describe "GET api/v3/custom_actions/:id" do - shared_context "get request" do + describe 'GET api/v3/custom_actions/:id' do + shared_context 'get request' do before do get api_v3_paths.custom_action(action.id) end end - context "for an existing action" do - include_context "get request" + context 'for an existing action' do + include_context 'get request' - it "is a 200 OK" do + it 'is a 200 OK' do expect(last_response.status) .to be(200) end end - context "for a non existing action" do + context 'for a non existing action' do before do get api_v3_paths.custom_action(0) end - it "is a 404 NOT FOUND" do + it 'is a 404 NOT FOUND' do expect(last_response.status) .to be(404) end end - context "when lacking permissions" do + context 'when lacking permissions' do let(:user) { create(:user) } - include_context "get request" + include_context 'get request' - it "is a 403 NOT AUTHORIZED" do + it 'is a 403 NOT AUTHORIZED' do expect(last_response.status) .to be(403) end end end - describe "POST api/v3/custom_actions/:id/execute" do - shared_context "post request" do + describe 'POST api/v3/custom_actions/:id/execute' do + shared_context 'post request' do before do post api_v3_paths.custom_action_execute(action.id), parameters.to_json, - "CONTENT_TYPE" => "application/json" + 'CONTENT_TYPE' => 'application/json' end end - context "for an existing action" do - include_context "post request" + context 'for an existing action' do + include_context 'post request' - it "is a 200 OK" do + it 'is a 200 OK' do expect(last_response.status) .to be(200) end - it "returns the altered work package" do + it 'returns the altered work package' do expect(last_response.body) - .to be_json_eql("WorkPackage".to_json) - .at_path("_type") + .to be_json_eql('WorkPackage'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql(nil.to_json) - .at_path("_links/assignee/href") + .at_path('_links/assignee/href') expect(last_response.body) .to be_json_eql(work_package.lock_version + 1) - .at_path("lockVersion") + .at_path('lockVersion') end end - context "on a conflict" do + context 'on a conflict' do let(:parameters) do { lockVersion: 0, @@ -149,12 +149,12 @@ WorkPackage.where(id: work_package.id).update_all(lock_version: 1) end - include_context "post request" + include_context 'post request' - it_behaves_like "update conflict" + it_behaves_like 'update conflict' end - context "without a lock version" do + context 'without a lock version' do let(:parameters) do { _links: { @@ -165,27 +165,27 @@ } end - include_context "post request" + include_context 'post request' - it_behaves_like "update conflict" + it_behaves_like 'update conflict' end - context "without a work package" do + context 'without a work package' do let(:parameters) do { lockVersion: 1 } end - include_context "post request" + include_context 'post request' - it "returns a 422 error" do + it 'returns a 422 error' do expect(last_response.status) .to be 422 end end - context "with a non visible work package" do + context 'with a non visible work package' do let(:invisible_work_package) { create(:work_package) } let(:parameters) do @@ -199,9 +199,9 @@ } end - include_context "post request" + include_context 'post request' - it "returns a 422 error" do + it 'returns a 422 error' do expect(last_response.status) .to be 422 end diff --git a/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb b/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb index a2a32f245540..2c338b39a7cc 100644 --- a/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb +++ b/spec/requests/api/v3/custom_options/custom_options_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Custom Options resource", :aggregate_failures do +RSpec.describe 'API v3 Custom Options resource', :aggregate_failures do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -43,7 +43,7 @@ subject(:response) { last_response } - describe "GET api/v3/custom_options/:id" do + describe 'GET api/v3/custom_options/:id' do let(:path) { api_v3_paths.custom_option custom_option.id } before do @@ -54,7 +54,7 @@ get path end - describe "WorkPackageCustomField" do + describe 'WorkPackageCustomField' do shared_let(:custom_field) do cf = create(:list_wp_custom_field) @@ -67,37 +67,37 @@ custom_field:) end - context "when being allowed" do + context 'when being allowed' do let(:permissions) { [:view_work_packages] } - it "is successful" do + it 'is successful' do expect(subject.status) .to be(200) expect(response.body) - .to be_json_eql("CustomOption".to_json) - .at_path("_type") + .to be_json_eql('CustomOption'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(custom_option.id.to_json) - .at_path("id") + .at_path('id') expect(response.body) .to be_json_eql(custom_option.value.to_json) - .at_path("value") + .at_path('value') end end - context "when lacking permission" do + context 'when lacking permission' do let(:permissions) { [] } - it "is 404" do + it 'is 404' do expect(subject.status) .to be(404) end end - context "when custom option not in project" do + context 'when custom option not in project' do let(:permissions) { [:view_work_packages] } let(:modification) do -> do @@ -106,51 +106,51 @@ end end - it "is 404" do + it 'is 404' do expect(subject.status) .to be(404) end end end - describe "ProjectCustomField" do + describe 'ProjectCustomField' do shared_let(:custom_field) { create(:list_project_custom_field) } shared_let(:custom_option) { create(:custom_option, custom_field:) } - context "when being allowed" do + context 'when being allowed' do let(:permissions) { [:view_project] } - it "is successful" do + it 'is successful' do expect(subject.status) .to be(200) expect(response.body) - .to be_json_eql("CustomOption".to_json) - .at_path("_type") + .to be_json_eql('CustomOption'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(custom_option.id.to_json) - .at_path("id") + .at_path('id') expect(response.body) .to be_json_eql(custom_option.value.to_json) - .at_path("value") + .at_path('value') end end - context "when lacking permission" do + context 'when lacking permission' do let(:user) { User.anonymous } let(:permissions) { [] } - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "error response", + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'error response', 401, - "Unauthenticated", - I18n.t("api_v3.errors.code_401") + 'Unauthenticated', + I18n.t('api_v3.errors.code_401') end - context "when not login_required", with_settings: { login_required: false } do - it "is 404" do + context 'when not login_required', with_settings: { login_required: false } do + it 'is 404' do expect(subject.status) .to be(404) end @@ -158,75 +158,75 @@ end end - describe "TimeEntryCustomField" do + describe 'TimeEntryCustomField' do shared_let(:custom_field) { create(:time_entry_custom_field, :list) } shared_let(:custom_option) { create(:custom_option, custom_field:) } - context "when being allowed with log_time" do + context 'when being allowed with log_time' do let(:permissions) { [:log_time] } - it "is successful" do + it 'is successful' do expect(subject.status) .to be(200) expect(response.body) - .to be_json_eql("CustomOption".to_json) - .at_path("_type") + .to be_json_eql('CustomOption'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(custom_option.id.to_json) - .at_path("id") + .at_path('id') expect(response.body) .to be_json_eql(custom_option.value.to_json) - .at_path("value") + .at_path('value') end end - context "when being allowed with log_own_time" do + context 'when being allowed with log_own_time' do let(:permissions) { [:log_own_time] } - it "is successful" do + it 'is successful' do expect(subject.status) .to be(200) end end - context "when lacking permission" do + context 'when lacking permission' do let(:user) { User.anonymous } let(:permissions) { [] } - it_behaves_like "not found response based on login_required" + it_behaves_like 'not found response based on login_required' end end - describe "UserCustomField" do + describe 'UserCustomField' do shared_let(:custom_field) { create(:user_custom_field, :list) } shared_let(:custom_option) { create(:custom_option, custom_field:) } let(:permissions) { [] } - it "is successful" do + it 'is successful' do expect(subject.status) .to be(200) end end - describe "GroupCustomField" do + describe 'GroupCustomField' do shared_let(:custom_field) { create(:group_custom_field, :list) } shared_let(:custom_option) { create(:custom_option, custom_field:) } let(:permissions) { [] } - it "is successful" do + it 'is successful' do expect(subject.status) .to be(200) end end - context "when not existing" do + context 'when not existing' do let(:path) { api_v3_paths.custom_option 0 } let(:permissions) { [:view_work_packages] } - it "is 404" do + it 'is 404' do expect(subject.status) .to be(404) end diff --git a/spec/requests/api/v3/days/day_spec.rb b/spec/requests/api/v3/days/day_spec.rb index 5c2df6196eaf..3f3e72d988e7 100644 --- a/spec/requests/api/v3/days/day_spec.rb +++ b/spec/requests/api/v3/days/day_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::DaysAPI, content_type: :json do @@ -41,30 +41,30 @@ get api_v3_paths.path_for :days, filters: end - context "for an admin user" do + context 'for an admin user' do let(:user) { build(:admin) } nb_days = Time.zone.today.end_of_month.day + Time.zone.today.next_month.end_of_month.day - it_behaves_like "API V3 collection response", nb_days, nb_days, "Day" + it_behaves_like 'API V3 collection response', nb_days, nb_days, 'Day' - context "when filtering by date" do + context 'when filtering by date' do let(:filters) do - [{ date: { operator: "<>d", + [{ date: { operator: '<>d', values: [Time.zone.today.iso8601, 5.days.from_now.to_date.iso8601] } }] end - it_behaves_like "API V3 collection response", 6, 6, "Day" + it_behaves_like 'API V3 collection response', 6, 6, 'Day' end - context "when filtering by working" do + context 'when filtering by working' do let(:filters) do - [{ working: { operator: "=", - values: ["t"] } }] + [{ working: { operator: '=', + values: ['t'] } }] end nb_days = (Time.zone.today.at_beginning_of_month..Time.zone.today.next_month.at_end_of_month) .count { |d| !(d.saturday? || d.sunday?) } - it_behaves_like "API V3 collection response", nb_days, nb_days, "Day" + it_behaves_like 'API V3 collection response', nb_days, nb_days, 'Day' end end end diff --git a/spec/requests/api/v3/days/non_working_days_index_resource_spec.rb b/spec/requests/api/v3/days/non_working_days_index_resource_spec.rb index 5723312ed8b4..3a67c3416e99 100644 --- a/spec/requests/api/v3/days/non_working_days_index_resource_spec.rb +++ b/spec/requests/api/v3/days/non_working_days_index_resource_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "services/work_packages/shared/shared_examples_days" +require 'spec_helper' +require 'services/work_packages/shared/shared_examples_days' RSpec.describe API::V3::Days::NonWorkingDaysAPI, - "index", + 'index', content_type: :json do include API::V3::Utilities::PathHelper @@ -42,18 +42,18 @@ get api_v3_paths.path_for :days_non_working, filters: end - context "for an admin user", :non_working_days_from_this_and_next_year do + context 'for an admin user', :non_working_days_from_this_and_next_year do let(:user) { build(:admin) } - it_behaves_like "API V3 collection response", 2, 2, "NonWorkingDay" + it_behaves_like 'API V3 collection response', 2, 2, 'NonWorkingDay' - context "when filtering by date" do + context 'when filtering by date' do let(:filters) do - [{ date: { operator: "<>d", + [{ date: { operator: '<>d', values: [first_of_may.date.beginning_of_month.iso8601, new_year_day.date.iso8601] } }] end - it_behaves_like "API V3 collection response", 3, 3, "NonWorkingDay" + it_behaves_like 'API V3 collection response', 3, 3, 'NonWorkingDay' end end end diff --git a/spec/requests/api/v3/days/non_working_days_show_resource_spec.rb b/spec/requests/api/v3/days/non_working_days_show_resource_spec.rb index 6b2c73e9903b..56af7a4201fd 100644 --- a/spec/requests/api/v3/days/non_working_days_show_resource_spec.rb +++ b/spec/requests/api/v3/days/non_working_days_show_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::NonWorkingDaysAPI, - "show", + 'show', content_type: :json do include API::V3::Utilities::PathHelper @@ -42,44 +42,44 @@ get path end - context "for an admin user" do + context 'for an admin user' do let(:user) { build(:admin) } - it_behaves_like "successful response" + it_behaves_like 'successful response' - it "responds with the correct day" do - expect(subject).to be_json_eql("NonWorkingDay".to_json).at_path("_type") - expect(subject).to be_json_eql(non_working_day.date.to_json).at_path("date") + it 'responds with the correct day' do + expect(subject).to be_json_eql('NonWorkingDay'.to_json).at_path('_type') + expect(subject).to be_json_eql(non_working_day.date.to_json).at_path('date') end - context "when requesting nonexistent date" do + context 'when requesting nonexistent date' do let(:path) { api_v3_paths.days_non_working_day(Time.zone.today) } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "when requesting an incorrect date" do + context 'when requesting an incorrect date' do let(:path) { api_v3_paths.days_non_working_day("incorrect") } - it_behaves_like "param validation error" do - let(:id) { "incorrect" } + it_behaves_like 'param validation error' do + let(:id) { 'incorrect' } end end end - context "for a not logged in user" do + context 'for a not logged in user' do let(:user) { build(:anonymous) } - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it_behaves_like "successful response" + context 'when not login_required', with_settings: { login_required: false } do + it_behaves_like 'successful response' - it "responds with the correct _type and day", :aggregate_failures do - expect(subject).to be_json_eql("NonWorkingDay".to_json).at_path("_type") - expect(subject).to be_json_eql(non_working_day.date.to_json).at_path("date") + it 'responds with the correct _type and day', :aggregate_failures do + expect(subject).to be_json_eql('NonWorkingDay'.to_json).at_path('_type') + expect(subject).to be_json_eql(non_working_day.date.to_json).at_path('date') end end end diff --git a/spec/requests/api/v3/days/week_show_resource_spec.rb b/spec/requests/api/v3/days/week_show_resource_spec.rb index cc4797d04c3d..f594e277aa57 100644 --- a/spec/requests/api/v3/days/week_show_resource_spec.rb +++ b/spec/requests/api/v3/days/week_show_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::WeekAPI, - "show", + 'show', content_type: :json do include API::V3::Utilities::PathHelper @@ -41,36 +41,36 @@ get path end - context "for an admin user" do + context 'for an admin user' do let(:user) { build(:admin) } - it_behaves_like "successful response" + it_behaves_like 'successful response' - it "responds with the correct day" do - expect(subject).to be_json_eql("WeekDay".to_json).at_path("_type") - expect(subject).to be_json_eql(1.to_json).at_path("day") + it 'responds with the correct day' do + expect(subject).to be_json_eql('WeekDay'.to_json).at_path('_type') + expect(subject).to be_json_eql(1.to_json).at_path('day') end - context "when requesting nonexistent day" do + context 'when requesting nonexistent day' do let(:path) { api_v3_paths.days_week_day(0) } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "for a not logged in user" do + context 'for a not logged in user' do let(:user) { build(:anonymous) } - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it_behaves_like "successful response" + context 'when not login_required', with_settings: { login_required: false } do + it_behaves_like 'successful response' - it "responds with the correct day", :aggregate_failures do - expect(subject).to be_json_eql("WeekDay".to_json).at_path("_type") - expect(subject).to be_json_eql(1.to_json).at_path("day") + it 'responds with the correct day', :aggregate_failures do + expect(subject).to be_json_eql('WeekDay'.to_json).at_path('_type') + expect(subject).to be_json_eql(1.to_json).at_path('day') end end end diff --git a/spec/requests/api/v3/days/week_spec.rb b/spec/requests/api/v3/days/week_spec.rb index a7badb55e5bc..04ecc7894bbd 100644 --- a/spec/requests/api/v3/days/week_spec.rb +++ b/spec/requests/api/v3/days/week_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Days::WeekAPI, - "index", + 'index', content_type: :json do include API::V3::Utilities::PathHelper @@ -40,9 +40,9 @@ get api_v3_paths.days_week end - context "for an admin user" do + context 'for an admin user' do let(:user) { build(:admin) } - it_behaves_like "API V3 collection response", 7, 7, "WeekDay" + it_behaves_like 'API V3 collection response', 7, 7, 'WeekDay' end end diff --git a/spec/requests/api/v3/groups/group_resource_spec.rb b/spec/requests/api/v3/groups/group_resource_spec.rb index 4d6619fe9b01..ac9a78e68271 100644 --- a/spec/requests/api/v3/groups/group_resource_spec.rb +++ b/spec/requests/api/v3/groups/group_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Group resource", content_type: :json do +RSpec.describe 'API v3 Group resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -51,58 +51,58 @@ member_with_roles: { project => role }) end - describe "GET api/v3/groups/:id" do + describe 'GET api/v3/groups/:id' do let(:get_path) { api_v3_paths.group group.id } before do get get_path end - context "having the necessary permission" do - it "responds with 200 OK" do + context 'having the necessary permission' do + it 'responds with 200 OK' do expect(subject.status) .to eq(200) end - it "responds with the correct group resource including the members" do + it 'responds with the correct group resource including the members' do expect(subject.body) - .to be_json_eql("Group".to_json) - .at_path("_type") + .to be_json_eql('Group'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(group.name.to_json) - .at_path("name") + .at_path('name') - expect(JSON::parse(subject.body).dig("_links", "members").map { |link| link["href"] }) + expect(JSON::parse(subject.body).dig('_links', 'members').map { |link| link['href'] }) .to match_array(members.map { |m| api_v3_paths.user(m.id) }) end end - context "requesting nonexistent group" do + context 'requesting nonexistent group' do let(:get_path) { api_v3_paths.group 9999 } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "not having the necessary permission to see any group" do + context 'not having the necessary permission to see any group' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "not having the necessary permission to see the specific group" do + context 'not having the necessary permission to see the specific group' do let(:permissions) { %i[view_members] } let(:group) { create(:group) } - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "POST api/v3/groups" do + describe 'POST api/v3/groups' do let(:path) { api_v3_paths.groups } let(:body) do { - name: "The new group", + name: 'The new group', members: [ { href: api_v3_paths.user(members.first.id) @@ -118,15 +118,15 @@ post path, body end - context "when the user is allowed and the input is valid" do + context 'when the user is allowed and the input is valid' do current_user { create(:admin) } - it "responds with 201" do + it 'responds with 201' do expect(last_response.status).to eq(201) end - it "creates the group and sets the members" do - group = Group.find_by(name: "The new group") + it 'creates the group and sets the members' do + group = Group.find_by(name: 'The new group') expect(group) .to be_present @@ -134,41 +134,41 @@ .to match_array members end - it "returns the newly created group" do + it 'returns the newly created group' do expect(last_response.body) - .to be_json_eql("Group".to_json) - .at_path("_type") + .to be_json_eql('Group'.to_json) + .at_path('_type') expect(last_response.body) - .to be_json_eql("The new group".to_json) - .at_path("name") + .to be_json_eql('The new group'.to_json) + .at_path('name') end end - context "when the user is allowed and the input is invalid" do + context 'when the user is allowed and the input is invalid' do current_user { create(:admin) } let(:body) do { - name: "" + name: '' }.to_json end - it "responds with 422 and explains the error" do + it 'responds with 422 and explains the error' do expect(last_response.status).to eq(422) expect(last_response.body) .to be_json_eql("Name can't be blank.".to_json) - .at_path("message") + .at_path('message') end end - context "not having the necessary permission" do - it_behaves_like "unauthorized access" + context 'not having the necessary permission' do + it_behaves_like 'unauthorized access' end end - describe "PATCH api/v3/groups/:id" do + describe 'PATCH api/v3/groups/:id' do let(:path) { api_v3_paths.group(group.id) } let(:another_role) { create(:project_role) } let(:another_user) do @@ -217,14 +217,14 @@ end end - context "when the user is allowed and the input is valid" do + context 'when the user is allowed and the input is valid' do current_user { admin } - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end - it "updates the group" do + it 'updates the group' do group.reload expect(group.users) @@ -235,27 +235,27 @@ .to be_truthy end - it "returns the updated group" do + it 'returns the updated group' do expect(last_response.body) - .to be_json_eql("Group".to_json) - .at_path("_type") + .to be_json_eql('Group'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql([{ href: api_v3_paths.user(members.last.id), title: members.last.name }, { href: api_v3_paths.user(another_user.id), title: another_user.name }].to_json) - .at_path("_links/members") + .at_path('_links/members') # unchanged expect(last_response.body) .to be_json_eql(group.name.to_json) - .at_path("name") + .at_path('name') # includes the memberships the group has applied to the added user expect(other_project.reload.users) .to contain_exactly(members.last, another_user) end - it "sends mails notifying of the added and updated project memberships to the added user" do + it 'sends mails notifying of the added and updated project memberships to the added user' do expect(ActionMailer::Base.deliveries.size) .to eq 2 @@ -263,12 +263,12 @@ .to match_array another_user.mail expect(ActionMailer::Base.deliveries.map(&:subject).flatten) - .to contain_exactly(I18n.t(:"mail_member_updated_project.subject", project: project.name), - I18n.t(:"mail_member_added_project.subject", project: other_project.name)) + .to contain_exactly(I18n.t(:'mail_member_updated_project.subject', project: project.name), + I18n.t(:'mail_member_added_project.subject', project: other_project.name)) end end - context "if attempting to set an empty name" do + context 'if attempting to set an empty name' do current_user { admin } let(:body) do @@ -283,20 +283,20 @@ } ] }, - name: "" + name: '' }.to_json end - it "returns 422" do + it 'returns 422' do expect(last_response.status) .to be(422) expect(last_response.body) .to be_json_eql("Name can't be blank.".to_json) - .at_path("message") + .at_path('message') end - it "does not alter the group" do + it 'does not alter the group' do group.reload expect(group.users) @@ -307,20 +307,20 @@ end end - context "when not being an admin" do + context 'when not being an admin' do let(:permissions) { [:manage_members] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "when lacking the view permissions" do + context 'when lacking the view permissions' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "DELETE /api/v3/groups/:id" do + describe 'DELETE /api/v3/groups/:id' do let(:path) { api_v3_paths.group(group.id) } let(:other_project) { create(:project) } let!(:membership) do @@ -351,19 +351,19 @@ subject(:response) { last_response } - context "with required permissions" do + context 'with required permissions' do current_user { admin } - it "responds with 202" do + it 'responds with 202' do expect(subject.status).to eq 202 end - it "deletes the group" do + it 'deletes the group' do expect(Group) .not_to exist(group.id) end - it "deletes the memberships of the members but keeps the ones a user had independently of the group" do + it 'deletes the memberships of the members but keeps the ones a user had independently of the group' do expect(other_project.users) .to contain_exactly(members.first) @@ -371,24 +371,24 @@ .to contain_exactly(another_role) end - context "for a non-existent group" do + context 'for a non-existent group' do let(:path) { api_v3_paths.group 11111337 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "without permission to delete groups" do - it_behaves_like "unauthorized access" + context 'without permission to delete groups' do + it_behaves_like 'unauthorized access' - it "does not delete the member" do + it 'does not delete the member' do expect(Group) .to exist(group.id) end end end - describe "GET api/v3/groups" do + describe 'GET api/v3/groups' do let(:get_path) { api_v3_paths.groups } let(:other_group) do create(:group) @@ -401,12 +401,12 @@ get get_path end - it_behaves_like "API V3 collection response", 2, 2, "Group" do + it_behaves_like 'API V3 collection response', 2, 2, 'Group' do let(:elements) { [other_group, group] } end - context "when signaling" do - let(:get_path) { api_v3_paths.path_for :groups, select: "total,count,elements/*" } + context 'when signaling' do + let(:get_path) { api_v3_paths.path_for :groups, select: 'total,count,elements/*' } let(:expected) do { @@ -415,7 +415,7 @@ _embedded: { elements: [ { - _type: "Group", + _type: 'Group', id: other_group.id, name: other_group.name, _links: { @@ -426,7 +426,7 @@ } }, { - _type: "Group", + _type: 'Group', id: group.id, name: group.name, _links: { @@ -441,16 +441,16 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(last_response.body) .to be_json_eql(expected.to_json) end end - context "when not having the necessary permission" do + context 'when not having the necessary permission' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/help_texts/help_texts_resource_spec.rb b/spec/requests/api/v3/help_texts/help_texts_resource_spec.rb index 55acc25f70d3..381c31dc292f 100644 --- a/spec/requests/api/v3/help_texts/help_texts_resource_spec.rb +++ b/spec/requests/api/v3/help_texts/help_texts_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Help texts resource" do +RSpec.describe 'API v3 Help texts resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -47,62 +47,62 @@ custom_field = create(:text_wp_custom_field) [ - create(:work_package_help_text, attribute_name: "assignee"), - create(:work_package_help_text, attribute_name: "status"), + create(:work_package_help_text, attribute_name: 'assignee'), + create(:work_package_help_text, attribute_name: 'status'), create(:work_package_help_text, attribute_name: custom_field.attribute_name) ] end - describe "help_texts" do - describe "#get" do + describe 'help_texts' do + describe '#get' do let(:get_path) { api_v3_paths.help_texts } subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do before do login_as(current_user) get get_path end - it_behaves_like "API V3 collection response", 2, 2, "HelpText" + it_behaves_like 'API V3 collection response', 2, 2, 'HelpText' end end end - describe "help_texts/:id" do - describe "#get" do + describe 'help_texts/:id' do + describe '#get' do let(:help_text) { help_texts.first } let(:get_path) { api_v3_paths.help_text help_text.id } subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do before do login_as(current_user) get get_path end - context "valid type id" do + context 'valid type id' do it { expect(response.status).to eq(200) } end - context "invalid type id" do - let(:get_path) { api_v3_paths.type "bogus" } + context 'invalid type id' do + let(:get_path) { api_v3_paths.type 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } - let(:type) { "HelpText" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + let(:type) { 'HelpText' } end end - context "invisible type id" do + context 'invisible type id' do # cf not visible to the user let(:help_text) { help_texts.last } - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/locale_spec.rb b/spec/requests/api/v3/locale_spec.rb index bfb33bf1924b..01c1fef35da5 100644 --- a/spec/requests/api/v3/locale_spec.rb +++ b/spec/requests/api/v3/locale_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' # This takes the schema endpoint to test localization as there # are localized strings in the response. -RSpec.describe "API localization" do +RSpec.describe 'API localization' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -43,12 +43,12 @@ create(:user, member_with_permissions: { project => %i[view_work_packages edit_work_packages] }, language: :fr) end - describe "GET /api/v3/work_packages/schemas/:id" do + describe 'GET /api/v3/work_packages/schemas/:id' do before do allow(User).to receive(:current).and_return(current_user) end - context "with the user having selected a language" do + context 'with the user having selected a language' do before do get schema_path end @@ -57,22 +57,22 @@ expected_i18n = WorkPackage.human_attribute_name(:subject, locale: current_user.language).to_json - expect(last_response.body).to be_json_eql(expected_i18n).at_path("subject/name") + expect(last_response.body).to be_json_eql(expected_i18n).at_path('subject/name') end end - context "when sending a header and not having a language selected" do + context 'when sending a header and not having a language selected' do before do current_user.language = nil - header "ACCEPT_LANGUAGE", "de,en-US;q=0.8,en;q=0.6" + header 'ACCEPT_LANGUAGE', 'de,en-US;q=0.8,en;q=0.6' get schema_path end it "responds in the user's locale" do - expected_i18n = WorkPackage.human_attribute_name(:subject, locale: "de").to_json + expected_i18n = WorkPackage.human_attribute_name(:subject, locale: 'de').to_json - expect(last_response.body).to be_json_eql(expected_i18n).at_path("subject/name") + expect(last_response.body).to be_json_eql(expected_i18n).at_path('subject/name') end end end diff --git a/spec/requests/api/v3/membership_resources_spec.rb b/spec/requests/api/v3/membership_resources_spec.rb index 1a64fbfb490e..ae71af0e1da6 100644 --- a/spec/requests/api/v3/membership_resources_spec.rb +++ b/spec/requests/api/v3/membership_resources_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 memberships resource", content_type: :json do +RSpec.describe 'API v3 memberships resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -76,10 +76,10 @@ subject(:response) { last_response } - shared_examples_for "sends mails" do + shared_examples_for 'sends mails' do let(:expected_receivers) { defined?(receivers) ? receivers : [principal] } - it "sends a mail to the principal of the member" do + it 'sends a mail to the principal of the member' do expect(ActionMailer::Base.deliveries.size) .to eql expected_receivers.length @@ -93,7 +93,7 @@ end end - describe "GET api/v3/memberships" do + describe 'GET api/v3/memberships' do let(:members) { [own_member, other_member, invisible_member, global_member, work_package_member] } let(:filters) { nil } let(:path) { api_v3_paths.path_for(:memberships, filters:, sort_by: [%i(id asc)]) } @@ -106,87 +106,87 @@ get path end - context "without params" do - it "responds 200 OK" do + context 'without params' do + it 'responds 200 OK' do expect(subject.status).to eq(200) end - it "returns a collection of memberships containing only the visible ones" do + it 'returns a collection of memberships containing only the visible ones' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') # the one membership stems from the membership the user has himself expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) .to be_json_eql(own_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(other_member.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') end end - context "as an admin" do + context 'as an admin' do let(:current_user) { admin } - it "returns a collection of memberships containing only the visible ones", :aggregate_failures do + it 'returns a collection of memberships containing only the visible ones', :aggregate_failures do expect(subject.status).to eq(200) expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') # the one membership stems from the membership the user has himself expect(subject.body) - .to be_json_eql("4") - .at_path("total") + .to be_json_eql('4') + .at_path('total') expect(subject.body) .to be_json_eql(own_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(other_member.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') expect(subject.body) .to be_json_eql(invisible_member.id.to_json) - .at_path("_embedded/elements/2/id") + .at_path('_embedded/elements/2/id') expect(subject.body) .to be_json_eql(global_member.id.to_json) - .at_path("_embedded/elements/3/id") + .at_path('_embedded/elements/3/id') end end - context "with pageSize, offset and sortBy" do + context 'with pageSize, offset and sortBy' do let(:path) { "#{api_v3_paths.path_for(:memberships, sort_by: [%i(id asc)])}&pageSize=1&offset=2" } - it "returns a slice of the visible memberships" do + it 'returns a slice of the visible memberships' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) - .to be_json_eql("1") - .at_path("count") + .to be_json_eql('1') + .at_path('count') expect(subject.body) .to be_json_eql(other_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "with a group" do + context 'with a group' do let(:group) { create(:group) } let(:group_member) do create(:member, @@ -196,26 +196,26 @@ end let(:members) { [own_member, group_member] } - it "returns that group membership together with the rest of them" do + it 'returns that group membership together with the rest of them' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) .to be_json_eql(own_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(group_member.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') end end - context "with a placeholder_user" do + context 'with a placeholder_user' do let(:placeholder_user) do create(:placeholder_user) end @@ -227,45 +227,45 @@ end let(:members) { [own_member, placeholder_member] } - it "returns that placeholder user membership together with the rest of them" do + it 'returns that placeholder user membership together with the rest of them' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) .to be_json_eql(own_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(placeholder_member.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') end end - context "when filtering by user name" do + context 'when filtering by user name' do let(:filters) do - [{ "any_name_attribute" => { - "operator" => "~", - "values" => [other_member.principal.login] + [{ 'any_name_attribute' => { + 'operator' => '~', + 'values' => [other_member.principal.login] } }] end - it "contains only the filtered member in the response" do + it 'contains only the filtered member in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(other_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "when filtering by project" do + context 'when filtering by project' do let(:members) { [own_member, other_member, invisible_member, own_other_member] } let(:own_other_member) do @@ -278,24 +278,24 @@ let(:other_project) { create(:project) } let(:filters) do - [{ "project" => { - "operator" => "=", - "values" => [other_project.id] + [{ 'project' => { + 'operator' => '=', + 'values' => [other_project.id] } }] end - it "contains only the filtered memberships in the response" do + it 'contains only the filtered memberships in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(own_other_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "when filtering by principal" do + context 'when filtering by principal' do let(:group) { create(:group) } let(:group_member) do create(:member, @@ -306,102 +306,102 @@ let(:members) { [own_member, other_member, group_member, invisible_member] } let(:filters) do - [{ "principal" => { - "operator" => "=", - "values" => [group.id.to_s, current_user.id.to_s] + [{ 'principal' => { + 'operator' => '=', + 'values' => [group.id.to_s, current_user.id.to_s] } }] end - it "contains only the filtered members in the response" do + it 'contains only the filtered members in the response' do expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) .to be_json_eql(own_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(subject.body) .to be_json_eql(group_member.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') end - context "when principal is a group without any memberships" do + context 'when principal is a group without any memberships' do let(:members) { [own_member, other_member, invisible_member] } let(:filters) do - [{ "principal" => { - "operator" => "=", - "values" => [group.id.to_s] + [{ 'principal' => { + 'operator' => '=', + 'values' => [group.id.to_s] } }] end - it "returns empty members" do + it 'returns empty members' do expect(subject.status).to eq(200) expect(subject.body) .to be_json_eql([]) - .at_path("_embedded/elements") + .at_path('_embedded/elements') end end end - context "with the outdated created_on sort by (renamed to created_at)" do + context 'with the outdated created_on sort by (renamed to created_at)' do let(:path) { "#{api_v3_paths.path_for(:memberships, sort_by: [%i(created_on desc)])}&pageSize=1&offset=2" } - it "is still supported and returns a slice of the visible memberships" do + it 'is still supported and returns a slice of the visible memberships' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) - .to be_json_eql("1") - .at_path("count") + .to be_json_eql('1') + .at_path('count') expect(subject.body) .to be_json_eql(own_member.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "invalid filter" do + context 'invalid filter' do let(:members) { [own_member] } let(:filters) do - [{ "bogus" => { - "operator" => "=", - "values" => ["1"] + [{ 'bogus' => { + 'operator' => '=', + 'values' => ['1'] } }] end - it "returns an error" do + it 'returns an error' do expect(subject.status).to eq(400) expect(subject.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:InvalidQuery'.to_json) + .at_path('errorIdentifier') end end - context "without permissions" do + context 'without permissions' do let(:permissions) { [] } - it "is empty" do + it 'is empty' do expect(subject.body) - .to be_json_eql("0") - .at_path("total") + .to be_json_eql('0') + .at_path('total') end end end - describe "POST api/v3/memberships" do + describe 'POST api/v3/memberships' do let(:path) { api_v3_paths.memberships } let(:principal) { other_user } let(:principal_path) { api_v3_paths.user(principal.id) } - let(:custom_message) { "Wish you where **here**." } + let(:custom_message) { 'Wish you where **here**.' } let(:body) do { _links: { @@ -434,48 +434,48 @@ end end - shared_examples_for "successful member creation" do + shared_examples_for 'successful member creation' do let(:role) { defined?(expected_role) ? expected_role : other_role } - it "responds with 201" do + it 'responds with 201' do expect(last_response.status).to eq(201) end - it "creates the member" do + it 'creates the member' do expect(Member.find_by(principal:, project:)) .to be_present end - it "returns the newly created member" do + it 'returns the newly created member' do expect(last_response.body) - .to be_json_eql("Membership".to_json) - .at_path("_type") + .to be_json_eql('Membership'.to_json) + .at_path('_type') if project expect(last_response.body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_links/project/href") + .at_path('_links/project/href') end expect(last_response.body) .to be_json_eql(principal_path.to_json) - .at_path("_links/principal/href") + .at_path('_links/principal/href') expect(last_response.body) .to have_json_size(1) - .at_path("_links/roles") + .at_path('_links/roles') expect(last_response.body) .to be_json_eql(api_v3_paths.role(role.id).to_json) - .at_path("_links/roles/0/href") + .at_path('_links/roles/0/href') end end - context "for a user" do - it_behaves_like "successful member creation" - it_behaves_like "sends mails" + context 'for a user' do + it_behaves_like 'successful member creation' + it_behaves_like 'sends mails' - context "when deactivating notification sending" do + context 'when deactivating notification sending' do let(:body) do { _links: { @@ -497,16 +497,16 @@ }.to_json end - it_behaves_like "successful member creation" + it_behaves_like 'successful member creation' - it "sends no mail to the principal of the member" do + it 'sends no mail to the principal of the member' do expect(ActionMailer::Base.deliveries) .to be_empty end end end - context "for a group" do + context 'for a group' do let(:group) do create(:group, members: users) end @@ -536,19 +536,19 @@ }.to_json end - it_behaves_like "successful member creation" - it_behaves_like "sends mails" do + it_behaves_like 'successful member creation' + it_behaves_like 'sends mails' do let(:receivers) { users } end - it "creates the memberships for the group members" do + it 'creates the memberships for the group members' do users.each do |user| expect(Member.find_by(user_id: user.id, project:)) .to be_present end end - context "when deactivating notification sending" do + context 'when deactivating notification sending' do let(:body) do { _links: { @@ -570,15 +570,15 @@ }.to_json end - it_behaves_like "successful member creation" + it_behaves_like 'successful member creation' - it "sends no mail to the principal of the member" do + it 'sends no mail to the principal of the member' do expect(ActionMailer::Base.deliveries) .to be_empty end end - context "when creating global role permission as admin" do + context 'when creating global role permission as admin' do let(:current_user) { admin } let(:project) { nil } let(:expected_role) { global_role } @@ -602,11 +602,11 @@ }.to_json end - it_behaves_like "successful member creation" + it_behaves_like 'successful member creation' end end - context "for a placeholder user" do + context 'for a placeholder user' do let(:placeholder_user) { create(:placeholder_user) } let(:principal) { placeholder_user } let(:principal_path) { api_v3_paths.placeholder_user(placeholder_user.id) } @@ -633,14 +633,14 @@ }.to_json end - it_behaves_like "successful member creation" + it_behaves_like 'successful member creation' - it_behaves_like "sends mails" do + it_behaves_like 'sends mails' do let(:receivers) { [] } end end - context "for a global membership" do + context 'for a global membership' do let(:expected_role) { global_role } let(:body) do { @@ -666,25 +666,25 @@ end let(:project) { nil } - context "as an admin" do + context 'as an admin' do let(:current_user) { admin } - it_behaves_like "successful member creation" - it_behaves_like "sends mails" + it_behaves_like 'successful member creation' + it_behaves_like 'sends mails' end - context "as a non admin" do - it "responds with 422 and explains the error" do + context 'as a non admin' do + it 'responds with 422 and explains the error' do expect(last_response.status).to eq(422) expect(last_response.body) .to be_json_eql("Project can't be blank.".to_json) - .at_path("message") + .at_path('message') end end end - context "if providing an already taken user" do + context 'if providing an already taken user' do let(:body) do { _links: { @@ -704,16 +704,16 @@ }.to_json end - it "responds with 422 and explains the error" do + it 'responds with 422 and explains the error' do expect(last_response.status).to eq(422) expect(last_response.body) .to be_json_eql("User has already been taken.".to_json) - .at_path("message") + .at_path('message') end end - context "if providing erroneous hrefs" do + context 'if providing erroneous hrefs' do let(:body) do { _links: { @@ -733,7 +733,7 @@ }.to_json end - it "responds with 422 and explains the error" do + it 'responds with 422 and explains the error' do expect(last_response.status).to eq(422) error_message = "For property 'user' a link like '/api/v3/groups/:id' or " + @@ -742,11 +742,11 @@ expect(last_response.body) .to be_json_eql(error_message.to_json) - .at_path("message") + .at_path('message') end end - context "if providing no roles" do + context 'if providing no roles' do let(:body) do { _links: { @@ -761,23 +761,23 @@ }.to_json end - it "responds with 422 and explains the error" do + it 'responds with 422 and explains the error' do expect(last_response.status).to eq(422) expect(last_response.body) .to be_json_eql("Roles need to be assigned.".to_json) - .at_path("message") + .at_path('message') end end - context "if lacking the manage permissions" do + context 'if lacking the manage permissions' do let(:permissions) { [:view_members] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "GET /api/v3/memberships/:id" do + describe 'GET /api/v3/memberships/:id' do let(:path) { api_v3_paths.membership(other_member.id) } let(:members) { [own_member, other_member] } @@ -790,46 +790,46 @@ get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the member" do + it 'returns the member' do expect(subject.body) - .to be_json_eql("Membership".to_json) - .at_path("_type") + .to be_json_eql('Membership'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(other_member.id.to_json) - .at_path("id") + .at_path('id') end - context "if querying an invisible member" do + context 'if querying an invisible member' do let(:path) { api_v3_paths.membership(invisible_member.id) } let(:members) { [own_member, invisible_member] } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:permissions) { [] } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end end end - describe "PATCH api/v3/memberships/:id" do + describe 'PATCH api/v3/memberships/:id' do let(:path) { api_v3_paths.membership(other_member.id) } let(:another_role) { create(:project_role) } - let(:custom_message) { "Wish you where **here**." } + let(:custom_message) { 'Wish you where **here**.' } let(:body) do { _links: { @@ -860,12 +860,12 @@ end end - context "for a user" do - it "responds with 200" do + context 'for a user' do + it 'responds with 200' do expect(last_response.status).to eq(200) end - it "updates the member" do + it 'updates the member' do other_member.reload expect(other_member.roles) @@ -876,30 +876,30 @@ .to be_truthy end - it "returns the updated membership" do + it 'returns the updated membership' do expect(last_response.body) - .to be_json_eql("Membership".to_json) - .at_path("_type") + .to be_json_eql('Membership'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql([{ href: api_v3_paths.role(another_role.id), title: another_role.name }].to_json) - .at_path("_links/roles") + .at_path('_links/roles') # unchanged expect(last_response.body) .to be_json_eql(project.name.to_json) - .at_path("_links/project/title") + .at_path('_links/project/title') expect(last_response.body) .to be_json_eql(other_user.name.to_json) - .at_path("_links/principal/title") + .at_path('_links/principal/title') end - it_behaves_like "sends mails" do + it_behaves_like 'sends mails' do let(:receivers) { [other_member.principal] } end - context "when deactivating notification sending" do + context 'when deactivating notification sending' do let(:body) do { _links: { @@ -915,14 +915,14 @@ }.to_json end - it "sends no mail to the principal of the member" do + it 'sends no mail to the principal of the member' do expect(ActionMailer::Base.deliveries) .to be_empty end end end - context "with a group" do + context 'with a group' do # first user has no direct roles # second user has direct role `another_role` # both users belong to a group which has `other_role`, so this role is inherited by users @@ -954,11 +954,11 @@ let(:first_user_member_updated_at) { Member.find_by(principal: users.first).updated_at } let(:last_user_member_updated_at) { Member.find_by(principal: users.last).updated_at } - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end - it "updates the member and all inherited members but does not update memberships users have already had" do + it 'updates the member and all inherited members but does not update memberships users have already had' do expect(other_member.reload.roles) .to contain_exactly(another_role) @@ -982,31 +982,31 @@ .to eql first_user_member_updated_at end - it "returns the updated membership" do + it 'returns the updated membership' do expect(last_response.body) - .to be_json_eql("Membership".to_json) - .at_path("_type") + .to be_json_eql('Membership'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql([{ href: api_v3_paths.role(another_role.id), title: another_role.name }].to_json) - .at_path("_links/roles") + .at_path('_links/roles') # unchanged expect(last_response.body) .to be_json_eql(project.name.to_json) - .at_path("_links/project/title") + .at_path('_links/project/title') expect(last_response.body) .to be_json_eql(group.name.to_json) - .at_path("_links/principal/title") + .at_path('_links/principal/title') end - it_behaves_like "sends mails" do + it_behaves_like 'sends mails' do # Only sends to the second user since the first user's membership is unchanged let(:receivers) { [users.last] } end - context "when deactivating notification sending" do + context 'when deactivating notification sending' do let(:body) do { _links: { @@ -1022,13 +1022,13 @@ }.to_json end - it "sends no mail to the principal of the member" do + it 'sends no mail to the principal of the member' do expect(ActionMailer::Base.deliveries) .to be_empty end end - context "when updating global role permission as admin" do + context 'when updating global role permission as admin' do let(:group) do create(:group, global_roles: [other_role], members: users) end @@ -1037,11 +1037,11 @@ let(:other_role) { create(:global_role) } let(:another_role) { create(:global_role) } - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end - it "updates the member and all inherited members but does not update memberships users have already had" do + it 'updates the member and all inherited members but does not update memberships users have already had' do # other member is the group member expect(other_member.reload.roles) .to contain_exactly(another_role) @@ -1068,7 +1068,7 @@ end end - context "if attempting to empty the roles" do + context 'if attempting to empty the roles' do let(:body) do { _links: { @@ -1077,17 +1077,17 @@ }.to_json end - it "returns 422" do + it 'returns 422' do expect(last_response.status) .to be(422) expect(last_response.body) .to be_json_eql("Roles need to be assigned.".to_json) - .at_path("message") + .at_path('message') end end - context "if attempting to assign unassignable roles" do + context 'if attempting to assign unassignable roles' do let(:anonymous_role) { create(:anonymous_role) } let(:body) do { @@ -1101,17 +1101,17 @@ }.to_json end - it "returns 422" do + it 'returns 422' do expect(last_response.status) .to be(422) expect(last_response.body) .to be_json_eql("Roles has an unassignable role.".to_json) - .at_path("message") + .at_path('message') end end - context "when attempting to switch the project" do + context 'when attempting to switch the project' do let(:other_project) do create(:project).tap do |p| create(:member, @@ -1132,10 +1132,10 @@ }.to_json end - it_behaves_like "read-only violation", "project", Member + it_behaves_like 'read-only violation', 'project', Member end - context "if attempting to switch the principal" do + context 'if attempting to switch the principal' do let(:another_user) do create(:user) end @@ -1151,23 +1151,23 @@ }.to_json end - it_behaves_like "read-only violation", "user", Member + it_behaves_like 'read-only violation', 'user', Member end - context "if lacking the manage permissions" do + context 'if lacking the manage permissions' do let(:permissions) { [:view_members] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "if lacking the view permissions" do + context 'if lacking the view permissions' do let(:permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "DELETE /api/v3/memberships/:id" do + describe 'DELETE /api/v3/memberships/:id' do let(:path) { api_v3_paths.membership(other_member.id) } let(:members) { [own_member, other_member] } @@ -1182,23 +1182,23 @@ subject { last_response } - context "with required permissions" do - it "responds with HTTP No Content" do + context 'with required permissions' do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "deletes the member" do + it 'deletes the member' do expect(Member).not_to exist(other_member.id) end - context "for a non-existent version" do + context 'for a non-existent version' do let(:path) { api_v3_paths.membership 1337 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "with a group" do + context 'with a group' do let(:group) do create(:group, member_with_roles: { project => other_role }, members: users) end @@ -1222,11 +1222,11 @@ end let(:first_user_member_updated_at) { Member.find_by(principal: users.first).updated_at } - it "responds with HTTP No Content" do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "deletes the member but does not remove the previously assigned role" do + it 'deletes the member but does not remove the previously assigned role' do expect(Member).not_to exist(other_member.id) expect(Member.where(principal: users.last)).not_to be_exists @@ -1239,18 +1239,18 @@ .to be_truthy end - it_behaves_like "sends mails" do + it_behaves_like 'sends mails' do # Only sends to the user who's membership only got updated, not removed let(:receivers) { [users.first] } end end - context "without permission to delete members" do + context 'without permission to delete members' do let(:permissions) { [:view_members] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' - it "does not delete the member" do + it 'does not delete the member' do expect(Member).to exist(other_member.id) end end diff --git a/spec/requests/api/v3/memberships/available_projects_resource_spec.rb b/spec/requests/api/v3/memberships/available_projects_resource_spec.rb index 8a8417215765..58774a5467c4 100644 --- a/spec/requests/api/v3/memberships/available_projects_resource_spec.rb +++ b/spec/requests/api/v3/memberships/available_projects_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 memberships available projects resource" do +RSpec.describe 'API v3 memberships available projects resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -73,7 +73,7 @@ subject(:response) { last_response } - describe "GET api/v3/memberships/available_projects" do + describe 'GET api/v3/memberships/available_projects' do let(:projects) { [manage_project, unauthorized_project] } let(:path) { api_v3_paths.memberships_available_projects } let(:filter_path) { "#{api_v3_paths.memberships_available_projects}?#{{ filters: filters.to_json }.to_query}" } @@ -85,51 +85,51 @@ get path end - context "without params" do - it "responds 200 OK" do + context 'without params' do + it 'responds 200 OK' do expect(subject.status).to eq(200) end - it "returns a collection of projects containing only the ones for which the user has :manage_members permission" do + it 'returns a collection of projects containing only the ones for which the user has :manage_members permission' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(manage_project.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "invalid filter" do + context 'invalid filter' do let(:members) { [own_member] } let(:filters) do - [{ "bogus" => { - "operator" => "=", - "values" => ["1"] + [{ 'bogus' => { + 'operator' => '=', + 'values' => ['1'] } }] end let(:path) { filter_path } - it "returns an error" do + it 'returns an error' do expect(subject.status).to eq(400) expect(subject.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:InvalidQuery'.to_json) + .at_path('errorIdentifier') end end - context "without permissions" do + context 'without permissions' do let(:permissions) { [:view_members] } - it "returns a 403" do + it 'returns a 403' do expect(subject.status) .to eq(403) end diff --git a/spec/requests/api/v3/memberships/create_form_resource_spec.rb b/spec/requests/api/v3/memberships/create_form_resource_spec.rb index 20e10935cebd..2c5fb057e0dd 100644 --- a/spec/requests/api/v3/memberships/create_form_resource_spec.rb +++ b/spec/requests/api/v3/memberships/create_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Memberships::CreateFormAPI, content_type: :json do include Rack::Test::Methods @@ -51,48 +51,48 @@ subject(:response) { last_response } - describe "#POST /api/v3/memberships/form" do - it "returns 200 OK" do + describe '#POST /api/v3/memberships/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - it "does not create a member" do + it 'does not create a member' do # 1 as the current user already has a membership expect(Member.count) .to be 1 end - context "with empty parameters" do - it "has 4 validation errors" do + context 'with empty parameters' do + it 'has 4 validation errors' do # There are 4 validation errors instead of 2 with two duplicating each other - expect(subject.body).to have_json_size(4).at_path("_embedded/validationErrors") + expect(subject.body).to have_json_size(4).at_path('_embedded/validationErrors') end - it "has a validation error on principal" do - expect(subject.body).to have_json_path("_embedded/validationErrors/principal") + it 'has a validation error on principal' do + expect(subject.body).to have_json_path('_embedded/validationErrors/principal') end - it "has a validation error on roles" do - expect(subject.body).to have_json_path("_embedded/validationErrors/roles") + it 'has a validation error on roles' do + expect(subject.body).to have_json_path('_embedded/validationErrors/roles') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with all parameters" do + context 'with all parameters' do let!(:int_cf) { create(:version_custom_field, :integer) } let!(:list_cf) { create(:version_custom_field, :list) } let(:parameters) do @@ -118,45 +118,45 @@ } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/payload/_links/project/href") + .at_path('_embedded/payload/_links/project/href') expect(body) .to be_json_eql(api_v3_paths.user(other_user.id).to_json) - .at_path("_embedded/payload/_links/principal/href") + .at_path('_embedded/payload/_links/principal/href') expect(subject.body) .to have_json_size(1) - .at_path("_embedded/payload/_links/roles") + .at_path('_embedded/payload/_links/roles') expect(last_response.body) .to be_json_eql(api_v3_paths.role(role.id).to_json) - .at_path("_embedded/payload/_links/roles/0/href") + .at_path('_embedded/payload/_links/roles/0/href') expect(last_response.body) .to be_json_eql("Join the **dark** side.".to_json) - .at_path("_embedded/payload/_meta/notificationMessage/raw") + .at_path('_embedded/payload/_meta/notificationMessage/raw') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.memberships.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:permissions) { [] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end diff --git a/spec/requests/api/v3/memberships/schemas/membership_schema_resource_spec.rb b/spec/requests/api/v3/memberships/schemas/membership_schema_resource_spec.rb index e23246a49c5d..e32ad4175f92 100644 --- a/spec/requests/api/v3/memberships/schemas/membership_schema_resource_spec.rb +++ b/spec/requests/api/v3/memberships/schemas/membership_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Membership schema resource", content_type: :json do +RSpec.describe 'API v3 Membership schema resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -48,30 +48,30 @@ subject(:response) { last_response } - describe "#GET /memberships/schema" do + describe '#GET /memberships/schema' do before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns a schema" do + it 'returns a schema' do expect(subject.body) - .to be_json_eql("Schema".to_json) - .at_path "_type" + .to be_json_eql('Schema'.to_json) + .at_path '_type' end - it "does not embed" do + it 'does not embed' do expect(subject.body) - .not_to have_json_path("project/_links/allowedValues") + .not_to have_json_path('project/_links/allowedValues') end - context "if lacking permissions" do + context 'if lacking permissions' do let(:permissions) { [] } - it "responds with 403" do + it 'responds with 403' do expect(subject.status).to eq(403) end end diff --git a/spec/requests/api/v3/memberships/update_form_resource_spec.rb b/spec/requests/api/v3/memberships/update_form_resource_spec.rb index fbb950b1ced6..a9d17ee050a1 100644 --- a/spec/requests/api/v3/memberships/update_form_resource_spec.rb +++ b/spec/requests/api/v3/memberships/update_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Memberships::UpdateFormAPI, content_type: :json do include Rack::Test::Methods @@ -71,53 +71,53 @@ subject(:response) { last_response } - describe "#POST /api/v3/memberships/:id/form" do - it "returns 200 OK" do + describe '#POST /api/v3/memberships/:id/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - it "does not update the member (no new roles)" do + it 'does not update the member (no new roles)' do expect(member.roles.reload) .to contain_exactly(role, another_role) end - it "contains the update roles in the payload" do + it 'contains the update roles in the payload' do expect(response.body) .to have_json_size(2) - .at_path("_embedded/payload/_links/roles") + .at_path('_embedded/payload/_links/roles') expect(response.body) .to be_json_eql(api_v3_paths.role(role.id).to_json) - .at_path("_embedded/payload/_links/roles/0/href") + .at_path('_embedded/payload/_links/roles/0/href') expect(response.body) .to be_json_eql(api_v3_paths.role(other_role.id).to_json) - .at_path("_embedded/payload/_links/roles/1/href") + .at_path('_embedded/payload/_links/roles/1/href') end - it "contains the notification message" do + it 'contains the notification message' do expect(response.body) .to be_json_eql("Join the **dark** side.".to_json) - .at_path("_embedded/payload/_meta/notificationMessage/raw") + .at_path('_embedded/payload/_meta/notificationMessage/raw') end - it "does not contain the project in the payload" do + it 'does not contain the project in the payload' do expect(response.body) - .not_to have_json_path("_embedded/payload/_links/project") + .not_to have_json_path('_embedded/payload/_links/project') end - it "does not contain the principal in the payload" do + it 'does not contain the principal in the payload' do expect(response.body) - .not_to have_json_path("_embedded/payload/_links/principal") + .not_to have_json_path('_embedded/payload/_links/principal') end - context "with wanting to remove all roles" do + context 'with wanting to remove all roles' do let(:parameters) do { _links: { @@ -126,23 +126,23 @@ } end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "notes roles cannot be empty" do + it 'notes roles cannot be empty' do expect(subject.body) .to be_json_eql("Roles need to be assigned.".to_json) - .at_path("_embedded/validationErrors/roles/message") + .at_path('_embedded/validationErrors/roles/message') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with wanting to alter the project" do + context 'with wanting to alter the project' do let(:other_project) do role = create(:project_role, permissions:) @@ -159,27 +159,27 @@ } end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end - it "notes project to not be writable" do + it 'notes project to not be writable' do expect(subject.body) .to be_json_eql(false) - .at_path("_embedded/schema/project/writable") + .at_path('_embedded/schema/project/writable') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with wanting to alter the principal" do + context 'with wanting to alter the principal' do let(:other_principal) do create(:user) end @@ -193,38 +193,38 @@ } end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on principal" do - expect(subject.body).to have_json_path("_embedded/validationErrors/user") + it 'has a validation error on principal' do + expect(subject.body).to have_json_path('_embedded/validationErrors/user') end - it "notes principal to not be writable" do + it 'notes principal to not be writable' do expect(subject.body) .to be_json_eql(false) - .at_path("_embedded/schema/principal/writable") + .at_path('_embedded/schema/principal/writable') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "without the necessary edit permission" do + context 'without the necessary edit permission' do let(:permissions) { [:view_members] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end - context "without the necessary view permission" do + context 'without the necessary view permission' do let(:permissions) { [] } - it "returns 404 Not Found" do + it 'returns 404 Not Found' do expect(response.status).to eq(404) end end diff --git a/spec/requests/api/v3/news_resource_spec.rb b/spec/requests/api/v3/news_resource_spec.rb index d93d34d64aaf..810dc532e41c 100644 --- a/spec/requests/api/v3/news_resource_spec.rb +++ b/spec/requests/api/v3/news_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 news resource" do +RSpec.describe 'API v3 news resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -59,10 +59,10 @@ login_as(current_user) end - describe "GET api/v3/news" do + describe 'GET api/v3/news' do let(:path) { api_v3_paths.newses } - context "without params" do + context 'without params' do before do news invisible_news @@ -70,26 +70,26 @@ get path end - it "responds 200 OK" do + it 'responds 200 OK' do expect(subject.status).to eq(200) end - it "returns a collection of news containing only the visible ones" do + it 'returns a collection of news containing only the visible ones' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(news.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "with pageSize, offset and sortBy" do + context 'with pageSize, offset and sortBy' do let(:path) { "#{api_v3_paths.newses}?pageSize=1&offset=2&sortBy=#{[%i(id asc)].to_json}" } before do @@ -100,27 +100,27 @@ get path end - it "returns a slice of the news" do + it 'returns a slice of the news' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("2") - .at_path("total") + .to be_json_eql('2') + .at_path('total') expect(subject.body) - .to be_json_eql("1") - .at_path("count") + .to be_json_eql('1') + .at_path('count') expect(subject.body) .to be_json_eql(other_news.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end end - describe "GET /api/v3/news/:id" do + describe 'GET /api/v3/news/:id' do let(:path) { api_v3_paths.news(news.id) } before do @@ -129,25 +129,25 @@ get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the news" do + it 'returns the news' do expect(subject.body) - .to be_json_eql("News".to_json) - .at_path("_type") + .to be_json_eql('News'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(news.id.to_json) - .at_path("id") + .at_path('id') end - context "when lacking permissions" do + context 'when lacking permissions' do let(:path) { api_v3_paths.news(invisible_news.id) } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end diff --git a/spec/requests/api/v3/notifications/bulk_read_ian_resource_spec.rb b/spec/requests/api/v3/notifications/bulk_read_ian_resource_spec.rb index 4844fbaf6550..dad211a49774 100644 --- a/spec/requests/api/v3/notifications/bulk_read_ian_resource_spec.rb +++ b/spec/requests/api/v3/notifications/bulk_read_ian_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Notifications::NotificationsAPI, - "bulk set read status", + 'bulk set read status', content_type: :json do include API::V3::Utilities::PathHelper @@ -58,15 +58,15 @@ post read_path end - describe "POST /api/v3/notifications/read_ian" do + describe 'POST /api/v3/notifications/read_ian' do let(:current_user) { recipient } - it "returns 204" do + it 'returns 204' do expect(last_response.status) .to be(204) end - it "sets all the current users`s notifications to read" do + it 'sets all the current users`s notifications to read' do expect(Notification.where(id: [notification1.id, notification2.id, notification3.id]).pluck(:read_ian)) .to all(be_truthy) @@ -74,20 +74,20 @@ .to all(be_falsey) end - context "with a filter for id" do + context 'with a filter for id' do let(:filters) do [ { - "id" => { - "operator" => "=", - "values" => [notification1.id.to_s, notification2.id.to_s] + 'id' => { + 'operator' => '=', + 'values' => [notification1.id.to_s, notification2.id.to_s] } } ] end - it "sets the current users`s notifications matching the filter to read" do + it 'sets the current users`s notifications matching the filter to read' do expect(Notification.where(id: [notification1.id, notification2.id]).pluck(:read_ian)) .to all(be_truthy) @@ -96,20 +96,20 @@ end end - context "with an invalid filter" do + context 'with an invalid filter' do let(:filters) do [ { - "bogus" => { - "operator" => "=", - "values" => [] + 'bogus' => { + 'operator' => '=', + 'values' => [] } } ] end - it "returns 400" do + it 'returns 400' do expect(last_response.status) .to be(400) end diff --git a/spec/requests/api/v3/notifications/bulk_unread_ian_resource_spec.rb b/spec/requests/api/v3/notifications/bulk_unread_ian_resource_spec.rb index 870c90ae6a25..f1aa3ca7f9ba 100644 --- a/spec/requests/api/v3/notifications/bulk_unread_ian_resource_spec.rb +++ b/spec/requests/api/v3/notifications/bulk_unread_ian_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Notifications::NotificationsAPI, - "bulk unset read status", + 'bulk unset read status', content_type: :json do include API::V3::Utilities::PathHelper @@ -68,15 +68,15 @@ post read_path end - describe "POST /api/v3/notifications/unread_ian" do + describe 'POST /api/v3/notifications/unread_ian' do let(:current_user) { recipient } - it "returns 204" do + it 'returns 204' do expect(last_response.status) .to be(204) end - it "sets all the current users`s notifications to read" do + it 'sets all the current users`s notifications to read' do expect(Notification.where(id: [notification1.id, notification2.id, notification3.id]).pluck(:read_ian)) .to all(be_falsey) @@ -84,20 +84,20 @@ .to all(be_truthy) end - context "with a filter for id" do + context 'with a filter for id' do let(:filters) do [ { - "id" => { - "operator" => "=", - "values" => [notification1.id.to_s, notification2.id.to_s] + 'id' => { + 'operator' => '=', + 'values' => [notification1.id.to_s, notification2.id.to_s] } } ] end - it "sets the current users`s notifications matching the filter to read" do + it 'sets the current users`s notifications matching the filter to read' do expect(Notification.where(id: [notification1.id, notification2.id]).order(id: :asc).pluck(:read_ian)) .to all(be_falsey) @@ -106,20 +106,20 @@ end end - context "with an invalid filter" do + context 'with an invalid filter' do let(:filters) do [ { - "bogus" => { - "operator" => "=", - "values" => [] + 'bogus' => { + 'operator' => '=', + 'values' => [] } } ] end - it "returns 400" do + it 'returns 400' do expect(last_response.status) .to be(400) end diff --git a/spec/requests/api/v3/notifications/details_resource_spec.rb b/spec/requests/api/v3/notifications/details_resource_spec.rb index 81a0901514b0..8e62bce40bf4 100644 --- a/spec/requests/api/v3/notifications/details_resource_spec.rb +++ b/spec/requests/api/v3/notifications/details_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Notifications::NotificationsAPI, - "fetch notification details", + 'fetch notification details', content_type: :json do include API::V3::Utilities::PathHelper @@ -69,100 +69,100 @@ login_as current_user end - describe "recipient user" do + describe 'recipient user' do let(:current_user) { recipient } - context "for a non dateAlert notification" do + context 'for a non dateAlert notification' do let(:reason) { :mentioned } - it "returns a 404 response" do + it 'returns a 404 response' do send_request expect(last_response.status).to eq(404) end end - context "for a start date alert notification" do + context 'for a start date alert notification' do let(:reason) { :date_alert_start_date } - it "can get the notification details for a start date" do + it 'can get the notification details for a start date' do send_request expect(last_response.body) - .to be_json_eql("startDate".to_json) - .at_path("property") + .to be_json_eql('startDate'.to_json) + .at_path('property') expect(last_response.body) .to be_json_eql(API::V3::Utilities::DateTimeFormatter.format_date(resource.start_date).to_json) - .at_path("value") + .at_path('value') expect(last_response.body) .to be_json_eql(notification_detail_path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') expect(last_response.body) .to be_json_eql("/api/v3/values/schemas/startDate".to_json) - .at_path("_links/schema/href") + .at_path('_links/schema/href') end end - context "for a due date alert notification" do + context 'for a due date alert notification' do let(:reason) { :date_alert_due_date } - it "can get the notification details for a due date" do + it 'can get the notification details for a due date' do send_request expect(last_response.body) - .to be_json_eql("dueDate".to_json) - .at_path("property") + .to be_json_eql('dueDate'.to_json) + .at_path('property') expect(last_response.body) .to be_json_eql(API::V3::Utilities::DateTimeFormatter.format_date(resource.due_date).to_json) - .at_path("value") + .at_path('value') expect(last_response.body) .to be_json_eql(notification_detail_path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') expect(last_response.body) .to be_json_eql("/api/v3/values/schemas/dueDate".to_json) - .at_path("_links/schema/href") + .at_path('_links/schema/href') end end - context "for a start date alert notification with a milestone resource" do + context 'for a start date alert notification with a milestone resource' do let(:notification) { milestone_notification } let(:reason) { :date_alert_start_date } - it "can get the notification details for a start date" do + it 'can get the notification details for a start date' do send_request expect(last_response.body) - .to be_json_eql("date".to_json) - .at_path("property") + .to be_json_eql('date'.to_json) + .at_path('property') expect(last_response.body) .to be_json_eql(API::V3::Utilities::DateTimeFormatter.format_date(resource.due_date).to_json) - .at_path("value") + .at_path('value') expect(last_response.body) .to be_json_eql(notification_detail_path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') expect(last_response.body) .to be_json_eql("/api/v3/values/schemas/date".to_json) - .at_path("_links/schema/href") + .at_path('_links/schema/href') end end end - describe "admin user" do + describe 'admin user' do current_user { build_stubbed(:admin) } before do send_request end - it "returns a 404 response" do + it 'returns a 404 response' do expect(last_response.status).to eq(404) end end - describe "unauthorized user" do + describe 'unauthorized user' do current_user { build_stubbed(:user) } before do send_request end - it "returns a 404 response" do + it 'returns a 404 response' do expect(last_response.status).to eq(404) end end diff --git a/spec/requests/api/v3/notifications/index_resource_spec.rb b/spec/requests/api/v3/notifications/index_resource_spec.rb index 8fe6639b26b3..321020e318c4 100644 --- a/spec/requests/api/v3/notifications/index_resource_spec.rb +++ b/spec/requests/api/v3/notifications/index_resource_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Notifications::NotificationsAPI, - "index", content_type: :json do + 'index', content_type: :json do include API::V3::Utilities::PathHelper shared_let(:work_package) { create(:work_package) } @@ -70,36 +70,36 @@ send_request end - describe "as the user with notifications" do + describe 'as the user with notifications' do let(:current_user) { recipient } - it_behaves_like "API V3 collection response", 2, 2, "Notification" do + it_behaves_like 'API V3 collection response', 2, 2, 'Notification' do let(:elements) { [date_alert_notification, mentioned_notification] } end - context "with a readIAN filter" do + context 'with a readIAN filter' do let(:nil_notification) { create(:notification, recipient:, read_ian: nil) } let(:filters) do [ { - "readIAN" => { - "operator" => "=", - "values" => ["f"] + 'readIAN' => { + 'operator' => '=', + 'values' => ['f'] } } ] end - context "with the filter being set to false" do - it_behaves_like "API V3 collection response", 2, 2, "Notification" do + context 'with the filter being set to false' do + it_behaves_like 'API V3 collection response', 2, 2, 'Notification' do let(:elements) { [date_alert_notification, mentioned_notification] } end end end - context "with a resource filter" do + context 'with a resource filter' do shared_let(:other_work_package) { create(:work_package, project: work_package.project) } shared_let(:other_resource_notification) do create(:notification, @@ -111,26 +111,26 @@ let(:filters) do [ { - "resourceId" => { - "operator" => "=", - "values" => [other_work_package.id.to_s] + 'resourceId' => { + 'operator' => '=', + 'values' => [other_work_package.id.to_s] } }, { - "resourceType" => { - "operator" => "=", - "values" => [WorkPackage.name.to_s] + 'resourceType' => { + 'operator' => '=', + 'values' => [WorkPackage.name.to_s] } } ] end - it_behaves_like "API V3 collection response", 1, 1, "Notification" do + it_behaves_like 'API V3 collection response', 1, 1, 'Notification' do let(:elements) { [other_resource_notification] } end end - context "with a project filter" do + context 'with a project filter' do shared_let(:other_project) do create(:project, members: { recipient => recipient.members.first.roles }) @@ -146,20 +146,20 @@ let(:filters) do [ { - "project" => { - "operator" => "=", - "values" => [other_work_package.project_id.to_s] + 'project' => { + 'operator' => '=', + 'values' => [other_work_package.project_id.to_s] } } ] end - it_behaves_like "API V3 collection response", 1, 1, "Notification" do + it_behaves_like 'API V3 collection response', 1, 1, 'Notification' do let(:elements) { [other_project_notification] } end end - context "with a reason filter", with_ee: %i[date_alerts] do + context 'with a reason filter', with_ee: %i[date_alerts] do shared_let(:assigned_notification) do create(:notification, reason: :assigned, @@ -180,64 +180,64 @@ let(:filters) do [ { - "reason" => { - "operator" => "=", - "values" => [mentioned_notification.reason.to_s, responsible_notification.reason.to_s, "dateAlert"] + 'reason' => { + 'operator' => '=', + 'values' => [mentioned_notification.reason.to_s, responsible_notification.reason.to_s, 'dateAlert'] } } ] end - it_behaves_like "API V3 collection response", 3, 3, "Notification" do + it_behaves_like 'API V3 collection response', 3, 3, 'Notification' do let(:elements) { [responsible_notification, date_alert_notification, mentioned_notification] } end - context "when using date alerts without enterprise", with_ee: false do + context 'when using date alerts without enterprise', with_ee: false do let(:filters) do [ { - "reason" => { - "operator" => "=", - "values" => ["dateAlert"] + 'reason' => { + 'operator' => '=', + 'values' => ['dateAlert'] } } ] end - it "returns an error" do + it 'returns an error' do expect(last_response.status) .to be 400 expect(last_response.body) .to be_json_eql("Filters Reason filter has invalid values.".to_json) - .at_path("message") + .at_path('message') end end - context "with an invalid reason" do + context 'with an invalid reason' do let(:filters) do [ { - "reason" => { - "operator" => "=", - "values" => ["bogus"] + 'reason' => { + 'operator' => '=', + 'values' => ['bogus'] } } ] end - it "returns an error" do + it 'returns an error' do expect(last_response.status) .to be 400 expect(last_response.body) .to be_json_eql("Filters Reason filter has invalid values.".to_json) - .at_path("message") + .at_path('message') end end end - context "with a non ian notification" do + context 'with a non ian notification' do shared_let(:wiki_page) { create(:wiki_page) } shared_let(:non_ian_notification) do @@ -249,12 +249,12 @@ journal: wiki_page.journals.first) end - it_behaves_like "API V3 collection response", 2, 2, "Notification" do + it_behaves_like 'API V3 collection response', 2, 2, 'Notification' do let(:elements) { [date_alert_notification, mentioned_notification] } end end - context "with a reason groupBy" do + context 'with a reason groupBy' do shared_let(:responsible_notification) do create(:notification, recipient:, @@ -276,27 +276,27 @@ get api_v3_paths.path_for :notifications, group_by: :reason end - let(:groups) { parsed_response["groups"] } + let(:groups) { parsed_response['groups'] } - it_behaves_like "API V3 collection response", 4, 4, "Notification" do + it_behaves_like 'API V3 collection response', 4, 4, 'Notification' do let(:elements) do [mentioned_notification, responsible_notification, date_alert_notification, due_date_alert_notification] end end - it "contains the reason groups", :aggregate_failures do + it 'contains the reason groups', :aggregate_failures do expect(groups).to be_a Array expect(groups.count).to eq 3 - keyed = groups.index_by { |el| el["value"] } - expect(keyed.keys).to contain_exactly "mentioned", "responsible", "dateAlert" - expect(keyed["mentioned"]["count"]).to eq 1 - expect(keyed["responsible"]["count"]).to eq 1 - expect(keyed["dateAlert"]["count"]).to eq 2 + keyed = groups.index_by { |el| el['value'] } + expect(keyed.keys).to contain_exactly 'mentioned', 'responsible', 'dateAlert' + expect(keyed['mentioned']['count']).to eq 1 + expect(keyed['responsible']['count']).to eq 1 + expect(keyed['dateAlert']['count']).to eq 2 end end - context "with a project groupBy" do + context 'with a project groupBy' do shared_let(:other_project) do create(:project, members: { recipient => recipient.members.first.roles }) @@ -315,34 +315,34 @@ get api_v3_paths.path_for :notifications, group_by: :project end - let(:groups) { parsed_response["groups"] } + let(:groups) { parsed_response['groups'] } - it_behaves_like "API V3 collection response", 3, 3, "Notification" + it_behaves_like 'API V3 collection response', 3, 3, 'Notification' - it "contains the project groups", :aggregate_failures do + it 'contains the project groups', :aggregate_failures do expect(groups).to be_a Array expect(groups.count).to eq 2 - keyed = groups.index_by { |el| el["value"] } + keyed = groups.index_by { |el| el['value'] } expect(keyed.keys).to contain_exactly other_project.name, work_package.project.name - expect(keyed[work_package.project.name]["count"]).to eq 2 - expect(keyed[work_package2.project.name]["count"]).to eq 1 + expect(keyed[work_package.project.name]['count']).to eq 2 + expect(keyed[work_package2.project.name]['count']).to eq 1 - expect(keyed.dig(work_package.project.name, "_links", "valueLink")[0]["href"]) + expect(keyed.dig(work_package.project.name, '_links', 'valueLink')[0]['href']) .to eq "/api/v3/projects/#{work_package.project.id}" end end - context "when having lost the permission to see the work package" do + context 'when having lost the permission to see the work package' do let(:additional_setup) do Member.where(principal: recipient).destroy_all end - it_behaves_like "API V3 collection response", 0, 0, "Notification" + it_behaves_like 'API V3 collection response', 0, 0, 'Notification' end - context "when signaling" do - let(:select) { "total,count" } + context 'when signaling' do + let(:select) { 'total,count' } let(:send_request) do get api_v3_paths.path_for :notifications, select: end @@ -354,28 +354,28 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(last_response.body) .to be_json_eql(expected.to_json) end end end - describe "admin user" do + describe 'admin user' do let(:current_user) { build(:admin) } - it_behaves_like "API V3 collection response", 0, 0, "Notification" + it_behaves_like 'API V3 collection response', 0, 0, 'Notification' end - describe "as any user" do + describe 'as any user' do let(:current_user) { build(:user) } - it_behaves_like "API V3 collection response", 0, 0, "Notification" + it_behaves_like 'API V3 collection response', 0, 0, 'Notification' end - describe "as an anonymous user" do + describe 'as an anonymous user' do let(:current_user) { User.anonymous } - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end diff --git a/spec/requests/api/v3/notifications/read_ian_resource_spec.rb b/spec/requests/api/v3/notifications/read_ian_resource_spec.rb index 696cd8eba49f..8f0596591335 100644 --- a/spec/requests/api/v3/notifications/read_ian_resource_spec.rb +++ b/spec/requests/api/v3/notifications/read_ian_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Notifications::NotificationsAPI, - "update read status", + 'update read status', content_type: :json do include API::V3::Utilities::PathHelper @@ -59,10 +59,10 @@ login_as current_user end - describe "recipient user" do + describe 'recipient user' do let(:current_user) { recipient } - it "can read and unread" do + it 'can read and unread' do send_read expect(last_response.status).to eq(204) expect(notification.reload.read_ian).to be_truthy @@ -73,10 +73,10 @@ end end - describe "admin user" do + describe 'admin user' do let(:current_user) { build(:admin) } - it "returns a 404 response" do + it 'returns a 404 response' do send_read expect(last_response.status).to eq(404) diff --git a/spec/requests/api/v3/notifications/show_resource_examples.rb b/spec/requests/api/v3/notifications/show_resource_examples.rb index 2c9e589c5718..fdadcd4b195c 100644 --- a/spec/requests/api/v3/notifications/show_resource_examples.rb +++ b/spec/requests/api/v3/notifications/show_resource_examples.rb @@ -25,28 +25,28 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_examples "represents the notification" do - it "represents the notification", :aggregate_failures do +RSpec.shared_examples 'represents the notification' do + it 'represents the notification', :aggregate_failures do expect(last_response.status) .to eq(200) expect(last_response.body) - .to be_json_eql("Notification".to_json) - .at_path("_type") + .to be_json_eql('Notification'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql(notification.read_ian.to_json) - .at_path("readIAN") + .at_path('readIAN') expect(last_response.body) .to be_json_eql(API::V3::Utilities::DateTimeFormatter.format_datetime(notification.created_at).to_json) - .at_path("createdAt") + .at_path('createdAt') expect(last_response.body) .to be_json_eql(API::V3::Utilities::DateTimeFormatter.format_datetime(notification.updated_at).to_json) - .at_path("updatedAt") + .at_path('updatedAt') expect(last_response.body) .to be_json_eql(notification.id.to_json) - .at_path("id") + .at_path('id') end end diff --git a/spec/requests/api/v3/notifications/show_resource_spec.rb b/spec/requests/api/v3/notifications/show_resource_spec.rb index c12bce676fa3..a7c19b0bbc20 100644 --- a/spec/requests/api/v3/notifications/show_resource_spec.rb +++ b/spec/requests/api/v3/notifications/show_resource_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require_relative "show_resource_examples" +require 'spec_helper' +require_relative 'show_resource_examples' RSpec.describe API::V3::Notifications::NotificationsAPI, - "show", + 'show', content_type: :json do include API::V3::Utilities::PathHelper @@ -54,17 +54,17 @@ get api_v3_paths.notification(notification.id) end - describe "recipient user" do + describe 'recipient user' do current_user { recipient } before do send_request end - it_behaves_like "represents the notification" + it_behaves_like 'represents the notification' end - describe "recipient user for a dateAlert notification" do + describe 'recipient user for a dateAlert notification' do current_user { recipient } before do @@ -78,39 +78,39 @@ send_request end - it_behaves_like "represents the notification" + it_behaves_like 'represents the notification' - it "includes the value of the work package associated in the details", :aggregate_failures do + it 'includes the value of the work package associated in the details', :aggregate_failures do expect(last_response.body) - .to be_json_eql("dueDate".to_json) - .at_path("_embedded/details/0/property") + .to be_json_eql('dueDate'.to_json) + .at_path('_embedded/details/0/property') expect(last_response.body) .to be_json_eql(API::V3::Utilities::DateTimeFormatter.format_date(resource.due_date).to_json) - .at_path("_embedded/details/0/value") + .at_path('_embedded/details/0/value') end end - describe "admin user" do + describe 'admin user' do current_user { build_stubbed(:admin) } before do send_request end - it "returns a 404 response" do + it 'returns a 404 response' do expect(last_response.status).to eq(404) end end - describe "unauthorized user" do + describe 'unauthorized user' do current_user { build_stubbed(:user) } before do send_request end - it "returns a 404 response" do + it 'returns a 404 response' do expect(last_response.status).to eq(404) end end diff --git a/spec/requests/api/v3/placeholder_users/create_resource_spec.rb b/spec/requests/api/v3/placeholder_users/create_resource_spec.rb index faefd36171b8..9564c1bb8830 100644 --- a/spec/requests/api/v3/placeholder_users/create_resource_spec.rb +++ b/spec/requests/api/v3/placeholder_users/create_resource_spec.rb @@ -25,31 +25,31 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" -require_relative "create_shared_examples" +require 'spec_helper' +require 'rack/test' +require_relative 'create_shared_examples' RSpec.describe API::V3::PlaceholderUsers::PlaceholderUsersAPI, - "create" do + 'create' do current_user { user } - describe "admin user" do + describe 'admin user' do let(:user) { build(:admin) } - it_behaves_like "create placeholder user request flow" + it_behaves_like 'create placeholder user request flow' end - describe "user with manage_placeholder_user permission" do + describe 'user with manage_placeholder_user permission' do let(:user) { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "create placeholder user request flow" + it_behaves_like 'create placeholder user request flow' end - describe "unauthorized user" do - include_context "create placeholder user request context" + describe 'unauthorized user' do + include_context 'create placeholder user request context' let(:user) { build(:user) } - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(403) end diff --git a/spec/requests/api/v3/placeholder_users/create_shared_examples.rb b/spec/requests/api/v3/placeholder_users/create_shared_examples.rb index d0827cd509be..aee8316197e5 100644 --- a/spec/requests/api/v3/placeholder_users/create_shared_examples.rb +++ b/spec/requests/api/v3/placeholder_users/create_shared_examples.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_context "create placeholder user request context" do +RSpec.shared_context 'create placeholder user request context' do include API::V3::Utilities::PathHelper let(:parameters) do - { name: "PLACEHOLDER" } + { name: 'PLACEHOLDER' } end let(:send_request) do @@ -40,27 +40,27 @@ let(:parsed_response) { JSON.parse(last_response.body) } end -RSpec.shared_examples "create placeholder user request flow" do - include_context "create placeholder user request context" +RSpec.shared_examples 'create placeholder user request flow' do + include_context 'create placeholder user request context' - describe "with EE", with_ee: %i[placeholder_users] do - describe "empty request body" do + describe 'with EE', with_ee: %i[placeholder_users] do + describe 'empty request body' do let(:parameters) { {} } - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(422) expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyConstraintViolation".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyConstraintViolation'.to_json) + .at_path('errorIdentifier') - expect(parsed_response["_embedded"]["details"]["attribute"]) - .to eq "name" + expect(parsed_response['_embedded']['details']['attribute']) + .to eq 'name' end end - it "creates the placeholder when valid" do + it 'creates the placeholder when valid' do send_request expect(last_response.status).to eq(201) @@ -68,37 +68,37 @@ expect(placeholder).to be_present end - describe "when the user name already exists" do - let!(:placeholder) { create(:placeholder_user, name: "PLACEHOLDER") } + describe 'when the user name already exists' do + let!(:placeholder) { create(:placeholder_user, name: 'PLACEHOLDER') } - it "returns an error" do + it 'returns an error' do send_request expect(last_response.status).to eq(422) expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyConstraintViolation".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyConstraintViolation'.to_json) + .at_path('errorIdentifier') - expect(parsed_response["_embedded"]["details"]["attribute"]) - .to eq "name" + expect(parsed_response['_embedded']['details']['attribute']) + .to eq 'name' - expect(parsed_response["message"]) - .to eq "Name has already been taken." + expect(parsed_response['message']) + .to eq 'Name has already been taken.' end end end - describe "without ee" do - it "adds an error that its only available in EE" do + describe 'without ee' do + it 'adds an error that its only available in EE' do send_request expect(last_response.status).to eq(422) - expect(parsed_response["message"]) - .to eq("Placeholder Users is only available in the OpenProject Enterprise edition") + expect(parsed_response['message']) + .to eq('Placeholder Users is only available in the OpenProject Enterprise edition') expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyConstraintViolation".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyConstraintViolation'.to_json) + .at_path('errorIdentifier') end end end diff --git a/spec/requests/api/v3/placeholder_users/delete_resource_examples.rb b/spec/requests/api/v3/placeholder_users/delete_resource_examples.rb index 185e6efc7f43..41478c989d39 100644 --- a/spec/requests/api/v3/placeholder_users/delete_resource_examples.rb +++ b/spec/requests/api/v3/placeholder_users/delete_resource_examples.rb @@ -25,12 +25,12 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_examples "deletion allowed" do - it "responds with 202" do +RSpec.shared_examples 'deletion allowed' do + it 'responds with 202' do expect(last_response.status).to eq 202 end - it "locks the account and mark for deletion" do + it 'locks the account and mark for deletion' do expect(Principals::DeleteJob) .to have_been_enqueued .with(placeholder) @@ -38,19 +38,19 @@ expect(placeholder.reload).to be_locked end - context "with a non-existent user" do + context 'with a non-existent user' do let(:path) { api_v3_paths.placeholder_user 1337 } - it_behaves_like "not found" + it_behaves_like 'not found' end end -RSpec.shared_examples "deletion is not allowed" do - it "responds with 403" do +RSpec.shared_examples 'deletion is not allowed' do + it 'responds with 403' do expect(last_response.status).to eq 403 end - it "does not delete the user" do + it 'does not delete the user' do expect(PlaceholderUser).to exist(placeholder.id) end end diff --git a/spec/requests/api/v3/placeholder_users/delete_resource_spec.rb b/spec/requests/api/v3/placeholder_users/delete_resource_spec.rb index 2af69bd5fd05..4c647852ee81 100644 --- a/spec/requests/api/v3/placeholder_users/delete_resource_spec.rb +++ b/spec/requests/api/v3/placeholder_users/delete_resource_spec.rb @@ -25,14 +25,14 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require_relative "delete_resource_examples" +require 'spec_helper' +require_relative 'delete_resource_examples' RSpec.describe API::V3::PlaceholderUsers::PlaceholderUsersAPI, - "delete" do + 'delete' do include API::V3::Utilities::PathHelper - shared_let(:placeholder) { create(:placeholder_user, name: "foo") } + shared_let(:placeholder) { create(:placeholder_user, name: 'foo') } let(:send_request) do header "Content-Type", "application/json" @@ -48,42 +48,42 @@ delete path end - context "when admin" do + context 'when admin' do let(:user) { build_stubbed(:admin) } - it_behaves_like "deletion allowed" + it_behaves_like 'deletion allowed' end - context "when locked admin" do + context 'when locked admin' do let(:user) { build_stubbed(:admin, status: Principal.statuses[:locked]) } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end - context "when non-admin" do + context 'when non-admin' do let(:user) { build_stubbed(:user, admin: false) } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end - context "when user with manage_placeholder_user permission" do + context 'when user with manage_placeholder_user permission' do let(:user) { create(:user, global_permissions: %[manage_placeholder_user]) } - it_behaves_like "deletion allowed" + it_behaves_like 'deletion allowed' end - context "when anonymous user" do + context 'when anonymous user' do let(:user) { create(:anonymous) } - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "error response", + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'error response', 401, - "Unauthenticated", - I18n.t("api_v3.errors.code_401") + 'Unauthenticated', + I18n.t('api_v3.errors.code_401') end - context "when not login_required", with_settings: { login_required: false } do - it_behaves_like "deletion is not allowed" + context 'when not login_required', with_settings: { login_required: false } do + it_behaves_like 'deletion is not allowed' end end end diff --git a/spec/requests/api/v3/placeholder_users/index_resource_spec.rb b/spec/requests/api/v3/placeholder_users/index_resource_spec.rb index 3a49eee615f5..6f19d260cb85 100644 --- a/spec/requests/api/v3/placeholder_users/index_resource_spec.rb +++ b/spec/requests/api/v3/placeholder_users/index_resource_spec.rb @@ -25,16 +25,16 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::PlaceholderUsers::PlaceholderUsersAPI, - "index", + 'index', content_type: :json do include API::V3::Utilities::PathHelper - shared_let(:placeholder1) { create(:placeholder_user, name: "foo") } - shared_let(:placeholder2) { create(:placeholder_user, name: "bar") } + shared_let(:placeholder1) { create(:placeholder_user, name: 'foo') } + shared_let(:placeholder2) { create(:placeholder_user, name: 'bar') } let(:send_request) do get api_v3_paths.placeholder_users @@ -48,16 +48,16 @@ send_request end - context "for an admin user" do + context 'for an admin user' do let(:user) { build(:admin) } - it_behaves_like "API V3 collection response", 2, 2, "PlaceholderUser" + it_behaves_like 'API V3 collection response', 2, 2, 'PlaceholderUser' end - context "when signaling for the desired properties" do + context 'when signaling for the desired properties' do let(:user) { build(:admin) } let(:send_request) do - get api_v3_paths.path_for :placeholder_users, select: "total,count,elements/*" + get api_v3_paths.path_for :placeholder_users, select: 'total,count,elements/*' end let(:expected) do @@ -67,7 +67,7 @@ _embedded: { elements: [ { - _type: "PlaceholderUser", + _type: 'PlaceholderUser', id: placeholder2.id, name: placeholder2.name, _links: { @@ -78,7 +78,7 @@ } }, { - _type: "PlaceholderUser", + _type: 'PlaceholderUser', id: placeholder1.id, name: placeholder1.name, _links: { @@ -93,28 +93,28 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(last_response.body) .to be_json_eql(expected.to_json) end end - context "for a user with manage_placeholder_user permission" do + context 'for a user with manage_placeholder_user permission' do let(:user) { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "API V3 collection response", 2, 2, "PlaceholderUser" + it_behaves_like 'API V3 collection response', 2, 2, 'PlaceholderUser' end - context "for a user with manage_members permission" do + context 'for a user with manage_members permission' do let(:project) { create(:project) } let(:user) { create(:user, member_with_permissions: { project => %i[manage_members] }) } - it_behaves_like "API V3 collection response", 2, 2, "PlaceholderUser" + it_behaves_like 'API V3 collection response', 2, 2, 'PlaceholderUser' end - context "for an unauthorized user" do + context 'for an unauthorized user' do let(:user) { build(:user) } - it_behaves_like "API V3 collection response", 0, 0, "PlaceholderUser" + it_behaves_like 'API V3 collection response', 0, 0, 'PlaceholderUser' end end diff --git a/spec/requests/api/v3/placeholder_users/show_resource_examples.rb b/spec/requests/api/v3/placeholder_users/show_resource_examples.rb index 1a7f451172ec..287072c34bd4 100644 --- a/spec/requests/api/v3/placeholder_users/show_resource_examples.rb +++ b/spec/requests/api/v3/placeholder_users/show_resource_examples.rb @@ -25,16 +25,16 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_examples "represents the placeholder" do +RSpec.shared_examples 'represents the placeholder' do it do expect(last_response.status).to eq(200) expect(last_response.body) - .to(be_json_eql("PlaceholderUser".to_json).at_path("_type")) + .to(be_json_eql('PlaceholderUser'.to_json).at_path('_type')) expect(last_response.body) - .to(be_json_eql(placeholder.name.to_json).at_path("name")) + .to(be_json_eql(placeholder.name.to_json).at_path('name')) expect(last_response.body) - .to(be_json_eql(placeholder.id.to_json).at_path("id")) + .to(be_json_eql(placeholder.id.to_json).at_path('id')) end end diff --git a/spec/requests/api/v3/placeholder_users/show_resource_spec.rb b/spec/requests/api/v3/placeholder_users/show_resource_spec.rb index 3a4cd43697cb..eb25d2cdfc19 100644 --- a/spec/requests/api/v3/placeholder_users/show_resource_spec.rb +++ b/spec/requests/api/v3/placeholder_users/show_resource_spec.rb @@ -25,14 +25,14 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require_relative "show_resource_examples" +require 'spec_helper' +require_relative 'show_resource_examples' RSpec.describe API::V3::PlaceholderUsers::PlaceholderUsersAPI, - "show" do + 'show' do include API::V3::Utilities::PathHelper - shared_let(:placeholder) { create(:placeholder_user, name: "foo") } + shared_let(:placeholder) { create(:placeholder_user, name: 'foo') } let(:send_request) do header "Content-Type", "application/json" @@ -47,30 +47,30 @@ send_request end - describe "admin user" do + describe 'admin user' do let(:user) { build(:admin) } - it_behaves_like "represents the placeholder" + it_behaves_like 'represents the placeholder' end - describe "user with manage_placeholder_user permission" do + describe 'user with manage_placeholder_user permission' do let(:user) { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "represents the placeholder" + it_behaves_like 'represents the placeholder' end - describe "user with manage_members permission" do + describe 'user with manage_members permission' do let(:role) { create(:project_role, permissions: %i[manage_members]) } let(:project) { create(:project, members: { placeholder => role }) } let(:user) { create(:user, member_with_roles: { project => role }) } - it_behaves_like "represents the placeholder" + it_behaves_like 'represents the placeholder' end - describe "unauthorized user" do + describe 'unauthorized user' do let(:user) { build(:user) } - it "returns a 403 response" do + it 'returns a 403 response' do expect(last_response.status).to eq(403) end end diff --git a/spec/requests/api/v3/placeholder_users/update_resource_examples.rb b/spec/requests/api/v3/placeholder_users/update_resource_examples.rb index b6feb8996cce..32564fc8abb8 100644 --- a/spec/requests/api/v3/placeholder_users/update_resource_examples.rb +++ b/spec/requests/api/v3/placeholder_users/update_resource_examples.rb @@ -25,37 +25,37 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_examples "updates the placeholder" do - context "with an empty name" do +RSpec.shared_examples 'updates the placeholder' do + context 'with an empty name' do let(:parameters) do - { name: "" } + { name: '' } end - it "returns an error" do + it 'returns an error' do expect(last_response.status).to eq(422) expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyConstraintViolation".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyConstraintViolation'.to_json) + .at_path('errorIdentifier') - expect(parsed_response["_embedded"]["details"]["attribute"]) - .to eq "name" + expect(parsed_response['_embedded']['details']['attribute']) + .to eq 'name' - expect(parsed_response["message"]) + expect(parsed_response['message']) .to eq "Name can't be blank." end end - context "with a new name" do + context 'with a new name' do let(:parameters) do - { name: "my new name" } + { name: 'my new name' } end - it "updates the placeholder" do + it 'updates the placeholder' do expect(last_response.status).to eq(200) placeholder.reload - expect(placeholder.name).to eq "my new name" + expect(placeholder.name).to eq 'my new name' end end end diff --git a/spec/requests/api/v3/placeholder_users/update_resource_spec.rb b/spec/requests/api/v3/placeholder_users/update_resource_spec.rb index ecd50789329e..5bd041a1938e 100644 --- a/spec/requests/api/v3/placeholder_users/update_resource_spec.rb +++ b/spec/requests/api/v3/placeholder_users/update_resource_spec.rb @@ -25,14 +25,14 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require_relative "update_resource_examples" +require 'spec_helper' +require_relative 'update_resource_examples' RSpec.describe API::V3::PlaceholderUsers::PlaceholderUsersAPI, - "update" do + 'update' do include API::V3::Utilities::PathHelper - shared_let(:placeholder) { create(:placeholder_user, name: "foo") } + shared_let(:placeholder) { create(:placeholder_user, name: 'foo') } let(:parameters) do {} @@ -51,22 +51,22 @@ send_request end - describe "admin user" do + describe 'admin user' do let(:user) { build(:admin) } - it_behaves_like "updates the placeholder" + it_behaves_like 'updates the placeholder' end - describe "user with manage_placeholder_user permission" do + describe 'user with manage_placeholder_user permission' do let(:user) { create(:user, global_permissions: %i[manage_placeholder_user]) } - it_behaves_like "updates the placeholder" + it_behaves_like 'updates the placeholder' end - describe "unauthorized user" do + describe 'unauthorized user' do let(:user) { build(:user) } - it "returns a 403 response" do + it 'returns a 403 response' do expect(last_response.status).to eq(403) end end diff --git a/spec/requests/api/v3/posts_resource_spec.rb b/spec/requests/api/v3/posts_resource_spec.rb index 896f5577e4ed..a2ecf22902ea 100644 --- a/spec/requests/api/v3/posts_resource_spec.rb +++ b/spec/requests/api/v3/posts_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 posts resource" do +RSpec.describe 'API v3 posts resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -48,32 +48,32 @@ login_as(current_user) end - describe "GET /api/v3/posts/:id" do + describe 'GET /api/v3/posts/:id' do let(:path) { api_v3_paths.post(message.id) } before do get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the message page" do + it 'returns the message page' do expect(subject.body) - .to be_json_eql("Post".to_json) - .at_path("_type") + .to be_json_eql('Post'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(message.id.to_json) - .at_path("id") + .at_path('id') end - context "when lacking permissions" do + context 'when lacking permissions' do let(:current_user) { create(:user) } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end diff --git a/spec/requests/api/v3/principals/principals_resource_spec.rb b/spec/requests/api/v3/principals/principals_resource_spec.rb index 6b3374e62f61..20198b1360c4 100644 --- a/spec/requests/api/v3/principals/principals_resource_spec.rb +++ b/spec/requests/api/v3/principals/principals_resource_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Principals resource" do +RSpec.describe 'API v3 Principals resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#GET /api/v3/principals" do + describe '#GET /api/v3/principals' do subject(:response) { last_response } let(:path) do @@ -50,8 +50,8 @@ let(:user) do user = create(:user, member_with_roles: { project => role }, - lastname: "Aaaa", - mail: "aaaa@example.com") + lastname: 'Aaaa', + mail: 'aaaa@example.com') create(:member, project: other_project, @@ -63,22 +63,22 @@ let!(:other_user) do create(:user, member_with_roles: { other_project => role }, - lastname: "Bbbb") + lastname: 'Bbbb') end let!(:user_in_non_member_project) do create(:user, member_with_roles: { non_member_project => role }, - lastname: "Cccc") + lastname: 'Cccc') end let!(:group) do create(:group, member_with_roles: { project => role }, - lastname: "Gggg") + lastname: 'Gggg') end let!(:placeholder_user) do create(:placeholder_user, member_with_roles: { project => role }, - name: "Pppp") + name: 'Pppp') end current_user { user } @@ -87,108 +87,108 @@ get path end - it "succeeds" do + it 'succeeds' do expect(response.status) .to eq(200) end - it_behaves_like "API V3 collection response", 4, 4 do + it_behaves_like 'API V3 collection response', 4, 4 do let(:elements) { [placeholder_user, group, other_user, user] } end - context "with a filter for project the user is member in" do + context 'with a filter for project the user is member in' do let(:filter) do - [{ member: { operator: "=", values: [project.id.to_s] } }] + [{ member: { operator: '=', values: [project.id.to_s] } }] end - it_behaves_like "API V3 collection response", 3, 3 + it_behaves_like 'API V3 collection response', 3, 3 end context 'with a filter for type "User"' do let(:filter) do - [{ type: { operator: "=", values: ["User"] } }] + [{ type: { operator: '=', values: ['User'] } }] end - it_behaves_like "API V3 collection response", 2, 2, nil + it_behaves_like 'API V3 collection response', 2, 2, nil end context 'with a filter for type "Group"' do let(:filter) do - [{ type: { operator: "=", values: ["Group"] } }] + [{ type: { operator: '=', values: ['Group'] } }] end - it_behaves_like "API V3 collection response", 1, 1, "Group" + it_behaves_like 'API V3 collection response', 1, 1, 'Group' end context 'with a filter for type "PlaceholderUser"' do let(:filter) do - [{ type: { operator: "=", values: ["PlaceholderUser"] } }] + [{ type: { operator: '=', values: ['PlaceholderUser'] } }] end - it_behaves_like "API V3 collection response", 1, 1, "PlaceholderUser" + it_behaves_like 'API V3 collection response', 1, 1, 'PlaceholderUser' end - context "with a without a project membership" do + context 'with a without a project membership' do let(:user) { create(:user) } # The user herself - it_behaves_like "API V3 collection response", 1, 1, "User" + it_behaves_like 'API V3 collection response', 1, 1, 'User' end - context "with a filter for any name attribute" do + context 'with a filter for any name attribute' do let(:filter) do - [{ any_name_attribute: { operator: "~", values: ["aaaa@example.com"] } }] + [{ any_name_attribute: { operator: '~', values: ['aaaa@example.com'] } }] end - it_behaves_like "API V3 collection response", 1, 1, "User" + it_behaves_like 'API V3 collection response', 1, 1, 'User' end - context "with a filter for id" do + context 'with a filter for id' do let(:filter) do - [{ id: { operator: "=", values: [user.id.to_s] } }] + [{ id: { operator: '=', values: [user.id.to_s] } }] end - it_behaves_like "API V3 collection response", 1, 1, "User" do + it_behaves_like 'API V3 collection response', 1, 1, 'User' do let(:elements) { [user] } end end - context "with a filter for id with the `me` value" do + context 'with a filter for id with the `me` value' do let(:filter) do - [{ id: { operator: "=", values: ["me"] } }] + [{ id: { operator: '=', values: ['me'] } }] end - it_behaves_like "API V3 collection response", 1, 1, "User" do + it_behaves_like 'API V3 collection response', 1, 1, 'User' do let(:elements) { [current_user] } end end - context "with the permission to `manage_members`" do + context 'with the permission to `manage_members`' do let(:permissions) { [:manage_members] } - it_behaves_like "API V3 collection response", 5, 5 do + it_behaves_like 'API V3 collection response', 5, 5 do let(:elements) { [placeholder_user, group, user_in_non_member_project, other_user, user] } end end - context "with the permission to `manage_user`" do + context 'with the permission to `manage_user`' do let(:permissions) { [:manage_user] } - it_behaves_like "API V3 collection response", 5, 5 do + it_behaves_like 'API V3 collection response', 5, 5 do let(:elements) { [placeholder_user, group, user_in_non_member_project, other_user, user] } end end - context "with the permission to `share_work_packages`" do + context 'with the permission to `share_work_packages`' do let(:permissions) { [:share_work_packages] } - it_behaves_like "API V3 collection response", 5, 5 do + it_behaves_like 'API V3 collection response', 5, 5 do let(:elements) { [placeholder_user, group, user_in_non_member_project, other_user, user] } end end - context "when signaling" do - let(:select) { "total,count,elements/*" } + context 'when signaling' do + let(:select) { 'total,count,elements/*' } let(:expected) do { @@ -197,7 +197,7 @@ _embedded: { elements: [ { - _type: "PlaceholderUser", + _type: 'PlaceholderUser', id: placeholder_user.id, name: placeholder_user.name, _links: { @@ -208,7 +208,7 @@ } }, { - _type: "Group", + _type: 'Group', id: group.id, name: group.name, _links: { @@ -247,7 +247,7 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(last_response.body) .to be_json_eql(expected.to_json) end @@ -255,7 +255,7 @@ # This request is executed like this by the user dropdown in the frontend # INFO -- : duration=55.89 db=29.21 view=26.68 status=200 method=GET path=/api/v3/principals params={"filters"=>"[{\"status\":{\"operator\":\"!\",\"values\":[\"3\"]}},{\"type\":{\"operator\":\"=\",\"values\":[\"User\",\"Group\",\"PlaceholderUser\"]}},{\"member\":{\"operator\":\"*\",\"values\":[]}}]", "pageSize"=>"-1", "select"=>"elements/id,elements/name,elements/self,total,count,pageSize"} host=localhost user=4 - describe "REGRESSION #50930: When the user is member of multiple projects, filtering for memberships and using select" do + describe 'REGRESSION #50930: When the user is member of multiple projects, filtering for memberships and using select' do let(:filter) do [ { status: { operator: "!", values: ["3"] } }, @@ -319,7 +319,7 @@ } end - it "contains each user element only once" do + it 'contains each user element only once' do pending "This is just a fix to note that we have the bug, the fix will be done in the frontend at first, then we can come back here" expect(last_response.body).to be_json_eql(expected.to_json) end diff --git a/spec/requests/api/v3/priority_resource_spec.rb b/spec/requests/api/v3/priority_resource_spec.rb index 38547bf77dc4..6388fbd54c0b 100644 --- a/spec/requests/api/v3/priority_resource_spec.rb +++ b/spec/requests/api/v3/priority_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Priority resource" do +RSpec.describe 'API v3 Priority resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -41,64 +41,64 @@ let!(:priorities) { create_list(:priority, 2) } - describe "priorities" do + describe 'priorities' do subject(:response) { last_response } let(:get_path) { api_v3_paths.priorities } - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - it_behaves_like "API V3 collection response", 2, 2, "Priority" + it_behaves_like 'API V3 collection response', 2, 2, 'Priority' end - context "not logged in user" do + context 'not logged in user' do before do get get_path end - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end - describe "priorities/:id" do + describe 'priorities/:id' do subject(:response) { last_response } let(:get_path) { api_v3_paths.priority priorities.first.id } - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - context "valid priority id" do - it "returns HTTP 200" do + context 'valid priority id' do + it 'returns HTTP 200' do expect(response.status).to be(200) end end - context "invalid priority id" do - let(:get_path) { api_v3_paths.priority "bogus" } + context 'invalid priority id' do + let(:get_path) { api_v3_paths.priority 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } - let(:type) { "IssuePriority" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + let(:type) { 'IssuePriority' } end end end - context "when not logged in user" do + context 'when not logged in user' do before do get get_path end - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end end diff --git a/spec/requests/api/v3/projects/available_assignees_api_spec.rb b/spec/requests/api/v3/projects/available_assignees_api_spec.rb index f380ab79a006..7132418a4185 100644 --- a/spec/requests/api/v3/projects/available_assignees_api_spec.rb +++ b/spec/requests/api/v3/projects/available_assignees_api_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "API::V3::Projects::AvailableAssigneesAPI" do include API::V3::Utilities::PathHelper - it_behaves_like "available principals", :assignees do + it_behaves_like 'available principals', :assignees do let(:base_permissions) { %i[add_work_packages] } let(:href) { api_v3_paths.available_assignees_in_project(project.id) } end diff --git a/spec/requests/api/v3/projects/available_parents_resource_spec.rb b/spec/requests/api/v3/projects/available_parents_resource_spec.rb index fab1de2e0d86..6ae8b4ac7bf4 100644 --- a/spec/requests/api/v3/projects/available_parents_resource_spec.rb +++ b/spec/requests/api/v3/projects/available_parents_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Project available parents resource", content_type: :json do +RSpec.describe 'API v3 Project available parents resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -76,7 +76,7 @@ project_without_add_subproject_permission] end - describe "GET /api/v3/projects/available_parent_projects" do + describe 'GET /api/v3/projects/available_parent_projects' do subject(:response) do other_projects @@ -85,38 +85,38 @@ last_response end - context "without a project candidate" do + context 'without a project candidate' do before do response end - it_behaves_like "API V3 collection response", 3, 3, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 3, 3, 'Project', 'Collection' do let(:elements) { [project, project_with_add_subproject_permission, child_project_with_add_subproject_permission] } end end - context "with a project candidate" do + context 'with a project candidate' do let(:path) { api_v3_paths.projects_available_parents + "?of=#{project.id}" } before do response end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be 200 end # Returns projects for which the user has the add_subprojects permission but # excludes the queried for project and its descendants - it_behaves_like "API V3 collection response", 1, 1, "Project", "Collection" do + it_behaves_like 'API V3 collection response', 1, 1, 'Project', 'Collection' do let(:elements) { [project_with_add_subproject_permission] } end end - context "when signaling the properties to include" do + context 'when signaling the properties to include' do let(:other_projects) { [] } - let(:select) { "elements/id,elements/name,elements/ancestors,total" } + let(:select) { 'elements/id,elements/name,elements/ancestors,total' } let(:path) { api_v3_paths.path_for(:projects_available_parents, select:) } let(:expected) do { @@ -135,50 +135,50 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(response.body) .to be_json_eql(expected.to_json) end end - context "when lacking edit and add permission" do + context 'when lacking edit and add permission' do let(:permissions) { %i[] } let(:global_permissions) { %i[] } let(:other_projects) do [project_without_add_subproject_permission] end - it "returns 403" do + it 'returns 403' do expect(subject.status) .to be 403 end end - context "when having only add_subprojects permission" do + context 'when having only add_subprojects permission' do let(:permissions) { %i[add_subprojects] } let(:global_permissions) { %i[] } - it "returns 200" do + it 'returns 200' do expect(subject.status) .to be 200 end end - context "when having only edit permission" do + context 'when having only edit permission' do let(:permissions) { %i[edit_project] } let(:global_permissions) { %i[] } - it "returns 200" do + it 'returns 200' do expect(subject.status) .to be 200 end end - context "when having only add_project permission" do + context 'when having only add_project permission' do let(:permissions) { %i[] } let(:global_permissions) { %i[add_project] } - it "returns 200" do + it 'returns 200' do expect(subject.status) .to be 200 end diff --git a/spec/requests/api/v3/projects/available_responsibles_api_spec.rb b/spec/requests/api/v3/projects/available_responsibles_api_spec.rb index 6a81b0b7ea6d..59535db24a59 100644 --- a/spec/requests/api/v3/projects/available_responsibles_api_spec.rb +++ b/spec/requests/api/v3/projects/available_responsibles_api_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "API::V3::Projects::AvailableResponsiblesAPI" do include API::V3::Utilities::PathHelper - it_behaves_like "available principals", :responsibles do + it_behaves_like 'available principals', :responsibles do let(:base_permissions) { %i[view_work_packages] } let(:href) { api_v3_paths.available_responsibles(project.id) } end diff --git a/spec/requests/api/v3/projects/copy/copy_form_resource_spec.rb b/spec/requests/api/v3/projects/copy/copy_form_resource_spec.rb index 1f4ccd4df231..b4269528e875 100644 --- a/spec/requests/api/v3/projects/copy/copy_form_resource_spec.rb +++ b/spec/requests/api/v3/projects/copy/copy_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Projects::Copy::CreateFormAPI, content_type: :json do include Rack::Test::Methods @@ -42,7 +42,7 @@ shared_let(:source_project) do create(:project, custom_field_values: { - text_custom_field.id => "source text", + text_custom_field.id => 'source text', list_custom_field.id => list_custom_field.custom_options.last.id }) end @@ -65,20 +65,20 @@ subject(:response) { last_response } - it "returns 200 FORM response", :aggregate_failures do + it 'returns 200 FORM response', :aggregate_failures do expect(response.status).to eq(200) expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') expect(Project.count) .to be 1 end - it "retains the values from the source project" do + it 'retains the values from the source project' do expect(response.body) - .to be_json_eql("source text".to_json) + .to be_json_eql('source text'.to_json) .at_path("_embedded/payload/customField#{text_custom_field.id}/raw") expect(response.body) @@ -86,7 +86,7 @@ .at_path("_embedded/payload/_links/customField#{list_custom_field.id}/title") end - it "contains a meta property with copy properties for every module" do + it 'contains a meta property with copy properties for every module' do Projects::CopyService.copyable_dependencies.each do |dep| identifier = dep[:identifier].to_s.camelize expect(response.body) @@ -95,9 +95,9 @@ end end - it "shows an empty name as not set" do + it 'shows an empty name as not set' do expect(response.body) - .to be_json_eql("".to_json) + .to be_json_eql(''.to_json) .at_path("_embedded/payload/name") expect(response.body) @@ -105,11 +105,11 @@ .at_path("_embedded/validationErrors/name/message") end - context "updating the form payload" do + context 'updating the form payload' do let(:params) do { - name: "My copied project", - identifier: "foobar", + name: 'My copied project', + identifier: 'foobar', text_custom_field.attribute_name(:camel_case) => { raw: "CF text" }, @@ -119,31 +119,31 @@ href: api_v3_paths.custom_option(list_custom_field.custom_options.first.id) }, status: { - href: api_v3_paths.project_status("on_track") + href: api_v3_paths.project_status('on_track') } } } end - it "sets those values" do + it 'sets those values' do expect(response.body) - .to be_json_eql("My copied project".to_json) + .to be_json_eql('My copied project'.to_json) .at_path("_embedded/payload/name") expect(response.body) - .to be_json_eql("foobar".to_json) + .to be_json_eql('foobar'.to_json) .at_path("_embedded/payload/identifier") expect(response.body) - .to be_json_eql(api_v3_paths.project_status("on_track").to_json) + .to be_json_eql(api_v3_paths.project_status('on_track').to_json) .at_path("_embedded/payload/_links/status/href") expect(response.body) - .to be_json_eql("A magic dwells in each beginning.".to_json) + .to be_json_eql('A magic dwells in each beginning.'.to_json) .at_path("_embedded/payload/statusExplanation/raw") expect(response.body) - .to be_json_eql("CF text".to_json) + .to be_json_eql('CF text'.to_json) .at_path("_embedded/payload/customField#{text_custom_field.id}/raw") expect(response.body) @@ -168,7 +168,7 @@ end end - context "when setting copy meta properties" do + context 'when setting copy meta properties' do let(:params) do { _meta: { @@ -177,7 +177,7 @@ } end - it "sets all values to true" do + it 'sets all values to true' do Projects::CopyService.copyable_dependencies.each do |dep| identifier = dep[:identifier].to_s.camelize expect(response.body) @@ -187,20 +187,20 @@ end end - describe "send_notification" do - context "when not present" do + describe 'send_notification' do + context 'when not present' do let(:params) do {} end - it "returns it as false" do + it 'returns it as false' do expect(response.body) .to be_json_eql(false.to_json) .at_path("_embedded/payload/_meta/sendNotifications") end end - context "when set to false" do + context 'when set to false' do let(:params) do { _meta: { @@ -209,14 +209,14 @@ } end - it "returns it as false" do + it 'returns it as false' do expect(response.body) .to be_json_eql(false.to_json) .at_path("_embedded/payload/_meta/sendNotifications") end end - context "when set to true" do + context 'when set to true' do let(:params) do { _meta: { @@ -225,7 +225,7 @@ } end - it "returns it as true" do + it 'returns it as true' do expect(response.body) .to be_json_eql(true.to_json) .at_path("_embedded/payload/_meta/sendNotifications") @@ -233,13 +233,13 @@ end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:current_user) do create(:user, member_with_permissions: { source_project => %i[view_project view_work_packages] }) end - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end diff --git a/spec/requests/api/v3/projects/copy/copy_resource_spec.rb b/spec/requests/api/v3/projects/copy/copy_resource_spec.rb index 388df4960808..9cc4632c960e 100644 --- a/spec/requests/api/v3/projects/copy/copy_resource_spec.rb +++ b/spec/requests/api/v3/projects/copy/copy_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Projects::Copy::CopyAPI, content_type: :json do include Rack::Test::Methods @@ -43,7 +43,7 @@ create(:project, enabled_module_names: %w[work_package_tracking wiki], custom_field_values: { - text_custom_field.id => "source text", + text_custom_field.id => 'source text', list_custom_field.id => list_custom_field.custom_options.last.id }) end @@ -69,14 +69,14 @@ subject(:response) { last_response } - describe "#POST /api/v3/projects/:id/copy" do - describe "with empty params" do - it "returns 422", :aggregate_failures do + describe '#POST /api/v3/projects/:id/copy' do + describe 'with empty params' do + it 'returns 422', :aggregate_failures do expect(response.status).to eq(422) expect(response.body) - .to be_json_eql("Error".to_json) - .at_path("_type") + .to be_json_eql('Error'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql("Name can't be blank.".to_json) @@ -84,16 +84,16 @@ end end - describe "with attributes given" do + describe 'with attributes given' do let(:params) do - { name: "My copied project", - identifier: "my-copied-project", + { name: 'My copied project', + identifier: 'my-copied-project', text_custom_field.attribute_name(:camel_case) => { raw: "CF text" } } end - it "returns with a redirect to job" do + it 'returns with a redirect to job' do aggregate_failures do expect(response.status).to eq(302) @@ -107,7 +107,7 @@ expect(last_response.status).to eq 200 expect(last_response.body) - .to be_json_eql("in_queue".to_json) + .to be_json_eql('in_queue'.to_json) .at_path("status") perform_enqueued_jobs @@ -117,35 +117,35 @@ expect(last_response.status).to eq 200 expect(last_response.body) - .to be_json_eql("success".to_json) + .to be_json_eql('success'.to_json) .at_path("status") expect(last_response.body) .to be_json_eql("Created project My copied project".to_json) .at_path("message") - project = Project.find_by(identifier: "my-copied-project") + project = Project.find_by(identifier: 'my-copied-project') expect(project).to be_present - expect(project.custom_value_for(text_custom_field).value).to eq "CF text" + expect(project.custom_value_for(text_custom_field).value).to eq 'CF text' expect(project.custom_value_for(list_custom_field).formatted_value).to eq list_custom_field.custom_options.last.value end end - describe "with restricted copying" do + describe 'with restricted copying' do let(:params) do - { name: "My copied project", - identifier: "my-copied-project", + { name: 'My copied project', + identifier: 'my-copied-project', _meta: { copyWorkPackages: true, copyWiki: false } } end - it "does not copy the wiki" do + it 'does not copy the wiki' do perform_enqueued_jobs - project = Project.find_by(identifier: "my-copied-project") + project = Project.find_by(identifier: 'my-copied-project') expect(project).to be_present expect(source_project.wiki.pages.count).to eq 1 @@ -156,19 +156,19 @@ end end - describe "sendNotifications" do + describe 'sendNotifications' do let(:params) do - { name: "My copied project", - identifier: "my-copied-project", + { name: 'My copied project', + identifier: 'my-copied-project', _meta: { sendNotifications: } } end - context "when false" do + context 'when false' do let(:sendNotifications) { false } - it "queues the job without notifications" do + it 'queues the job without notifications' do expect(CopyProjectJob) .to have_been_enqueued.with do |args| expect(args[:send_mails]).to be false @@ -176,10 +176,10 @@ end end - context "when true" do + context 'when true' do let(:sendNotifications) { true } - it "queues the job with notifications" do + it 'queues the job with notifications' do expect(CopyProjectJob) .to have_been_enqueued.with do |args| expect(args[:send_mails]).to be true @@ -188,13 +188,13 @@ end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:current_user) do create(:user, member_with_permissions: { source_project => %i[view_project view_work_packages] }) end - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end diff --git a/spec/requests/api/v3/projects/create_form_resource_spec.rb b/spec/requests/api/v3/projects/create_form_resource_spec.rb index c92041ef0dcd..47c4f8e25404 100644 --- a/spec/requests/api/v3/projects/create_form_resource_spec.rb +++ b/spec/requests/api/v3/projects/create_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Projects::CreateFormAPI, content_type: :json do include Rack::Test::Methods @@ -61,35 +61,35 @@ post path, params.to_json end - describe "#POST /api/v3/projects/form" do - it "returns 200 OK" do + describe '#POST /api/v3/projects/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - it "does not create a project" do + it 'does not create a project' do expect(Project.count) .to be 0 end - context "with empty parameters" do - it "has one validation error for name", :aggregate_failures do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") - expect(subject.body).to have_json_path("_embedded/validationErrors/name") - expect(subject.body).not_to have_json_path("_links/commit") + context 'with empty parameters' do + it 'has one validation error for name', :aggregate_failures do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') + expect(subject.body).to have_json_path('_embedded/validationErrors/name') + expect(subject.body).not_to have_json_path('_links/commit') end end - context "with all parameters" do + context 'with all parameters' do let(:params) do { - identifier: "new_project_identifier", - name: "Project name", + identifier: 'new_project_identifier', + name: 'Project name', text_custom_field.attribute_name(:camel_case) => { raw: "CF text" }, @@ -99,29 +99,29 @@ href: api_v3_paths.custom_option(list_custom_field.custom_options.first.id) }, status: { - href: api_v3_paths.project_status("on_track") + href: api_v3_paths.project_status('on_track') } } } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) - .to be_json_eql("new_project_identifier".to_json) - .at_path("_embedded/payload/identifier") + .to be_json_eql('new_project_identifier'.to_json) + .at_path('_embedded/payload/identifier') expect(body) - .to be_json_eql("Project name".to_json) - .at_path("_embedded/payload/name") + .to be_json_eql('Project name'.to_json) + .at_path('_embedded/payload/name') expect(body) - .to be_json_eql("CF text".to_json) + .to be_json_eql('CF text'.to_json) .at_path("_embedded/payload/customField#{text_custom_field.id}/raw") expect(body) @@ -129,8 +129,8 @@ .at_path("_embedded/payload/_links/customField#{list_custom_field.id}/href") expect(body) - .to be_json_eql(api_v3_paths.project_status("on_track").to_json) - .at_path("_embedded/payload/_links/status/href") + .to be_json_eql(api_v3_paths.project_status('on_track').to_json) + .at_path('_embedded/payload/_links/status/href') expect(body) .to be_json_eql( @@ -142,18 +142,18 @@ ).at_path("_embedded/payload/statusExplanation") end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.projects.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "with faulty status parameters" do + context 'with faulty status parameters' do let(:params) do { - identifier: "new_project_identifier", - name: "Project name", + identifier: 'new_project_identifier', + name: 'Project name', _links: { status: { href: api_v3_paths.project_status("bogus") @@ -162,21 +162,21 @@ } end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on status" do - expect(subject.body).to have_json_path("_embedded/validationErrors/status") + it 'has a validation error on status' do + expect(subject.body).to have_json_path('_embedded/validationErrors/status') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with only add_subprojects permission" do + context 'with only add_subprojects permission' do current_user do create(:user, member_with_permissions: { parent_project => %i[add_subprojects] }) @@ -194,21 +194,21 @@ } end - it "returns 200 OK" do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns the schema with a required parent field" do + it 'returns the schema with a required parent field' do expect(response.body) .to be_json_eql(true) - .at_path("_embedded/schema/parent/required") + .at_path('_embedded/schema/parent/required') end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:permissions) { [] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end diff --git a/spec/requests/api/v3/projects/delete_resource_spec.rb b/spec/requests/api/v3/projects/delete_resource_spec.rb index 74bb49e82c55..db2933c9afcb 100644 --- a/spec/requests/api/v3/projects/delete_resource_spec.rb +++ b/spec/requests/api/v3/projects/delete_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Project resource delete", content_type: :json do +RSpec.describe 'API v3 Project resource delete', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -57,25 +57,25 @@ subject { last_response } - context "with required permissions (admin)" do - it "responds with HTTP No Content" do + context 'with required permissions (admin)' do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "deletes the project" do + it 'deletes the project' do expect(Project).not_to exist(project.id) end - context "for a project with work packages" do + context 'for a project with work packages' do let(:work_package) { create(:work_package, project:) } let(:setup) { work_package } - it "deletes the work packages" do + it 'deletes the work packages' do expect(WorkPackage).not_to exist(work_package.id) end end - context "for a project with members" do + context 'for a project with members' do let(:member) do create(:member, project:, @@ -88,16 +88,16 @@ member_role end - it "deletes the member" do + it 'deletes the member' do expect(Member).not_to exist(member.id) end - it "deletes the MemberRole" do + it 'deletes the MemberRole' do expect(MemberRole).not_to exist(member_role.id) end end - context "for a project with a forum" do + context 'for a project with a forum' do let(:forum) do create(:forum, project:) @@ -106,39 +106,39 @@ forum end - it "deletes the forum" do + it 'deletes the forum' do expect(Forum).not_to exist(forum.id) end end - context "for a non-existent project" do + context 'for a non-existent project' do let(:path) { api_v3_paths.project 0 } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "for a project which has a version foreign work packages refer to" do + context 'for a project which has a version foreign work packages refer to' do let(:version) { create(:version, project:) } let(:work_package) { create(:work_package, version:) } let(:setup) { work_package } - it "responds with 422" do + it 'responds with 422' do expect(subject.status).to eq 422 end - it "explains the error" do + it 'explains the error' do expect(subject.body) - .to be_json_eql(I18n.t(:"activerecord.errors.models.project.foreign_wps_reference_version").to_json) - .at_path("message") + .to be_json_eql(I18n.t(:'activerecord.errors.models.project.foreign_wps_reference_version').to_json) + .at_path('message') end end end - context "without required permissions" do + context 'without required permissions' do current_user { member_user } - it "responds with 403" do + it 'responds with 403' do expect(subject.status).to eq 403 end end diff --git a/spec/requests/api/v3/projects/index_resource_spec.rb b/spec/requests/api/v3/projects/index_resource_spec.rb index d330421e2892..4573675503af 100644 --- a/spec/requests/api/v3/projects/index_resource_spec.rb +++ b/spec/requests/api/v3/projects/index_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Project resource index", content_type: :json do +RSpec.describe 'API v3 Project resource index', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -67,9 +67,9 @@ get get_path end - it_behaves_like "API V3 collection response", 1, 1, "Project" + it_behaves_like 'API V3 collection response', 1, 1, 'Project' - context "with a pageSize and offset" do + context 'with a pageSize and offset' do let(:projects) { [project, project2, project3] } let(:project2) do create(:project, @@ -84,28 +84,28 @@ api_v3_paths.path_for :projects, sort_by: { id: :asc }, page_size: 2, offset: 2 end - it_behaves_like "API V3 collection response", 3, 1, "Project" do + it_behaves_like 'API V3 collection response', 3, 1, 'Project' do let(:elements) { [project3] } end end - context "when filtering for project by ancestor" do + context 'when filtering for project by ancestor' do let(:projects) { [project, other_project, parent_project] } let(:filters) do - [{ ancestor: { operator: "=", values: [parent_project.id.to_s] } }] + [{ ancestor: { operator: '=', values: [parent_project.id.to_s] } }] end - it_behaves_like "API V3 collection response", 1, 1, "Project" + it_behaves_like 'API V3 collection response', 1, 1, 'Project' - it "returns the child project" do + it 'returns the child project' do expect(response.body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end - context "with filtering by capability action" do + context 'with filtering by capability action' do let(:other_project) { create(:project) } let(:another_project) { create(:project) } let(:projects) { [project, other_project, another_project] } @@ -122,66 +122,66 @@ api_v3_paths.path_for :projects, filters: [{ user_action: { operator:, values: %w[projects/copy work_packages/read] } }] end - context "if using the equals operator" do - let(:operator) { "=" } + context 'if using the equals operator' do + let(:operator) { '=' } - it_behaves_like "API V3 collection response", 2, 2, "Project" + it_behaves_like 'API V3 collection response', 2, 2, 'Project' end - context "if using the all operator" do - let(:operator) { "&=" } + context 'if using the all operator' do + let(:operator) { '&=' } - it_behaves_like "API V3 collection response", 1, 1, "Project" + it_behaves_like 'API V3 collection response', 1, 1, 'Project' - it "returns the project the current user has the capabilities in" do + it 'returns the project the current user has the capabilities in' do expect(response.body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end end - context "when filtering for principals (members)" do + context 'when filtering for principals (members)' do let(:other_project) do ProjectRole.non_member create(:public_project) end let(:projects) { [project, other_project] } - context "if filtering for a value" do + context 'if filtering for a value' do let(:filter_query) do - [{ principal: { operator: "=", values: [current_user.id.to_s] } }] + [{ principal: { operator: '=', values: [current_user.id.to_s] } }] end let(:get_path) do api_v3_paths.path_for :projects, filters: filter_query end - it "returns the filtered for value" do + it 'returns the filtered for value' do expect(response.body) .to be_json_eql(project.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "if filtering for a negative value" do + context 'if filtering for a negative value' do let(:filter_query) do - [{ principal: { operator: "!", values: [current_user.id.to_s] } }] + [{ principal: { operator: '!', values: [current_user.id.to_s] } }] end let(:get_path) do api_v3_paths.path_for :projects, filters: filter_query end - it "returns the projects not matching the value" do + it 'returns the projects not matching the value' do expect(last_response.body) .to be_json_eql(other_project.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end end - context "with filtering by visiblity" do + context 'with filtering by visiblity' do let(:public_project) do # Otherwise, the public project is invisible create(:non_member) @@ -208,45 +208,45 @@ current_user { admin } - it_behaves_like "API V3 collection response", 2, 2, "Project" + it_behaves_like 'API V3 collection response', 2, 2, 'Project' - it "contains the expected projects" do + it 'contains the expected projects' do expect(last_response.body) .to be_json_eql(public_project.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') expect(last_response.body) .to be_json_eql(member_project.id.to_json) - .at_path("_embedded/elements/1/id") + .at_path('_embedded/elements/1/id') end end - context "with the project being archived/inactive" do + context 'with the project being archived/inactive' do let(:project_active) { false } let(:projects) { [project] } - context "with the user being admin" do + context 'with the user being admin' do current_user { admin } - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(last_response.status).to eq(200) end - it_behaves_like "API V3 collection response", 1, 1, "Project" + it_behaves_like 'API V3 collection response', 1, 1, 'Project' end - context "with the user being no admin" do - it_behaves_like "API V3 collection response", 0, 0, "Project" + context 'with the user being no admin' do + it_behaves_like 'API V3 collection response', 0, 0, 'Project' - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end end end - context "when signaling the properties to include" do + context 'when signaling the properties to include' do let(:projects) { [project, parent_project] } - let(:select) { "elements/id,elements/name,elements/ancestors,total" } + let(:select) { 'elements/id,elements/name,elements/ancestors,total' } let(:get_path) do api_v3_paths.path_for :projects, select: end @@ -277,22 +277,22 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(last_response.body) .to be_json_eql(expected.to_json) end end - context "as project collection" do + context 'as project collection' do let(:role) { create(:project_role, permissions: %i[view_work_packages]) } let(:projects) { [project] } let(:expected) do "#{api_v3_paths.project(project.id)}/work_packages" end - it "has projects with links to their work packages" do + it 'has projects with links to their work packages' do expect(last_response.body) - .to be_json_eql(expected.to_json).at_path("_embedded/elements/0/_links/workPackages/href") + .to be_json_eql(expected.to_json).at_path('_embedded/elements/0/_links/workPackages/href') end end end diff --git a/spec/requests/api/v3/projects/schemas/project_schema_resource_spec.rb b/spec/requests/api/v3/projects/schemas/project_schema_resource_spec.rb index 0b1b08e54321..c843b9b0abc2 100644 --- a/spec/requests/api/v3/projects/schemas/project_schema_resource_spec.rb +++ b/spec/requests/api/v3/projects/schemas/project_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Projects schema resource", content_type: :json do +RSpec.describe 'API v3 Projects schema resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -45,24 +45,24 @@ subject(:response) { last_response } - describe "#GET /projects/schema" do + describe '#GET /projects/schema' do before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns a schema" do + it 'returns a schema' do expect(subject.body) - .to be_json_eql("Schema".to_json) - .at_path "_type" + .to be_json_eql('Schema'.to_json) + .at_path '_type' end - it "does not embed" do + it 'does not embed' do expect(subject.body) - .not_to have_json_path("parent/_links/allowedValues") + .not_to have_json_path('parent/_links/allowedValues') end end end diff --git a/spec/requests/api/v3/projects/statuses/project_status_resource_spec.rb b/spec/requests/api/v3/projects/statuses/project_status_resource_spec.rb index 1c6273b55c0f..8ef02f9d955d 100644 --- a/spec/requests/api/v3/projects/statuses/project_status_resource_spec.rb +++ b/spec/requests/api/v3/projects/statuses/project_status_resource_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Project status resource", content_type: :json do +RSpec.describe 'API v3 Project status resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper current_user { create(:user) } - describe "#get /project_statuses/:id" do + describe '#get /project_statuses/:id' do subject(:response) do get get_path @@ -45,28 +45,28 @@ let(:status) { Project.status_codes.keys.last } let(:get_path) { api_v3_paths.project_status status } - context "logged in user" do - it "responds with 200 OK" do + context 'logged in user' do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "responds with the correct project" do + it 'responds with the correct project' do expect(subject.body) - .to be_json_eql("ProjectStatus".to_json) - .at_path("_type") + .to be_json_eql('ProjectStatus'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(status.to_json) - .at_path("id") + .at_path('id') end - context "requesting nonexistent status" do - let(:status) { "bogus" } + context 'requesting nonexistent status' do + let(:status) { 'bogus' } before do response end - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/projects/update_form_resource_spec.rb b/spec/requests/api/v3/projects/update_form_resource_spec.rb index 490af1651edb..d09376822807 100644 --- a/spec/requests/api/v3/projects/update_form_resource_spec.rb +++ b/spec/requests/api/v3/projects/update_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Projects::UpdateFormAPI, content_type: :json do include Rack::Test::Methods @@ -72,55 +72,55 @@ subject(:response) { last_response } - describe "#POST /api/v3/projects/:id/form" do - it "returns 200 OK" do + describe '#POST /api/v3/projects/:id/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - context "with empty parameters" do - it "has no validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + context 'with empty parameters' do + it 'has no validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "returns the current project value`s in the payload" do + it 'returns the current project value`s in the payload' do expect(subject.body) .to be_json_eql(project.name.to_json) - .at_path("_embedded/payload/name") + .at_path('_embedded/payload/name') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) - .to have_json_path("_links/commit") + .to have_json_path('_links/commit') end end - context "with faulty parameters" do + context 'with faulty parameters' do let(:params) do { name: nil } end - it "has one validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has one validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on name" do - expect(subject.body).to have_json_path("_embedded/validationErrors/name") + it 'has a validation error on name' do + expect(subject.body).to have_json_path('_embedded/validationErrors/name') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end - it "does not alter the project" do + it 'does not alter the project' do name_before = project.name expect(project.reload.name) @@ -128,8 +128,8 @@ end end - context "with a viable parent project" do - context "with a correct parameter" do + context 'with a viable parent project' do + context 'with a correct parameter' do let(:params) do { _links: { @@ -140,57 +140,57 @@ } end - it "sets the project in the payload" do + it 'sets the project in the payload' do expect(subject.body) .to be_json_eql(api_v3_paths.project(viable_parent_project.id).to_json) - .at_path("_embedded/payload/_links/parent/href") + .at_path('_embedded/payload/_links/parent/href') end - it "links to the allowed parents in the schema" do + it 'links to the allowed parents in the schema' do expect(subject.body) .to be_json_eql((api_v3_paths.projects_available_parents + "?of=#{project.id}").to_json) - .at_path("_embedded/schema/parent/_links/allowedValues/href") + .at_path('_embedded/schema/parent/_links/allowedValues/href') end end end - context "with valid parameters" do + context 'with valid parameters' do let(:params) do { - identifier: "new_project_identifier", - name: "Project name", + identifier: 'new_project_identifier', + name: 'Project name', text_custom_field.attribute_name(:camel_case) => { raw: "new CF text" }, - statusExplanation: { raw: "Something goes awry." }, + statusExplanation: { raw: 'Something goes awry.' }, _links: { list_custom_field.attribute_name(:camel_case) => { href: api_v3_paths.custom_option(list_custom_field.custom_options.last.id) }, status: { - href: api_v3_paths.project_status("off_track") + href: api_v3_paths.project_status('off_track') } } } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) - .to be_json_eql("new_project_identifier".to_json) - .at_path("_embedded/payload/identifier") + .to be_json_eql('new_project_identifier'.to_json) + .at_path('_embedded/payload/identifier') expect(body) - .to be_json_eql("Project name".to_json) - .at_path("_embedded/payload/name") + .to be_json_eql('Project name'.to_json) + .at_path('_embedded/payload/name') expect(body) - .to be_json_eql("new CF text".to_json) + .to be_json_eql('new CF text'.to_json) .at_path("_embedded/payload/customField#{text_custom_field.id}/raw") expect(body) @@ -198,78 +198,78 @@ .at_path("_embedded/payload/_links/customField#{list_custom_field.id}/href") expect(body) - .to be_json_eql(api_v3_paths.project_status("off_track").to_json) + .to be_json_eql(api_v3_paths.project_status('off_track').to_json) .at_path("_embedded/payload/_links/status/href") expect(body) - .to be_json_eql("Something goes awry.".to_json) + .to be_json_eql('Something goes awry.'.to_json) .at_path("_embedded/payload/statusExplanation/raw") end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end - it "does not alter the project" do + it 'does not alter the project' do attributes_before = project.attributes expect(project.reload.name) - .to eql attributes_before["name"] + .to eql attributes_before['name'] expect(project.identifier) - .to eql attributes_before["identifier"] + .to eql attributes_before['identifier'] expect(project.send(text_custom_field.attribute_getter)) - .to eql "CF text" + .to eql 'CF text' expect(project.send(list_custom_field.attribute_getter)) .to eql list_custom_field.custom_options.first.value end end - context "with faulty status parameters" do + context 'with faulty status parameters' do let(:params) do { status: { - href: api_v3_paths.project_status("bogus") + href: api_v3_paths.project_status('bogus') } } end - it "displays the faulty status in the payload" do + it 'displays the faulty status in the payload' do expect(subject.body) - .to be_json_eql({ href: api_v3_paths.project_status("bogus") }.to_json) - .at_path("_embedded/payload/_links/status") + .to be_json_eql({ href: api_v3_paths.project_status('bogus') }.to_json) + .at_path('_embedded/payload/_links/status') end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on status" do - expect(subject.body).to have_json_path("_embedded/validationErrors/status") + it 'has a validation error on status' do + expect(subject.body).to have_json_path('_embedded/validationErrors/status') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:permissions) { [] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end - context "with a non existing id" do + context 'with a non existing id' do let(:path) { api_v3_paths.project_form(1) } - it "returns 404 Not found" do + it 'returns 404 Not found' do expect(response.status).to eq(404) end end diff --git a/spec/requests/api/v3/projects/version_resource_spec.rb b/spec/requests/api/v3/projects/version_resource_spec.rb index 062de28e46b7..7cad470e9d0e 100644 --- a/spec/requests/api/v3/projects/version_resource_spec.rb +++ b/spec/requests/api/v3/projects/version_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "API v3 project's versions resource" do include Rack::Test::Methods @@ -49,10 +49,10 @@ subject(:response) { last_response } - describe "#get (index)" do + describe '#get (index)' do let(:get_path) { api_v3_paths.versions_by_project project.id } - context "logged in user" do + context 'logged in user' do before do current_user @@ -62,10 +62,10 @@ get get_path end - it_behaves_like "API V3 collection response", 4, 4, "Version" + it_behaves_like 'API V3 collection response', 4, 4, 'Version' end - context "logged in user without permission" do + context 'logged in user without permission' do let(:role) { create(:project_role, permissions: []) } before do @@ -74,7 +74,7 @@ get get_path end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/queries/columns/query_columns_resource_spec.rb b/spec/requests/api/v3/queries/columns/query_columns_resource_spec.rb index 005240dffae7..e1761980d43d 100644 --- a/spec/requests/api/v3/queries/columns/query_columns_resource_spec.rb +++ b/spec/requests/api/v3/queries/columns/query_columns_resource_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Column resource" do +RSpec.describe 'API v3 Query Column resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#get queries/columns/:id" do + describe '#get queries/columns/:id' do let(:path) { api_v3_paths.query_column(column_name) } - let(:column_name) { "status" } + let(:column_name) { 'status' } let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } let(:permissions) { [:view_work_packages] } @@ -52,27 +52,27 @@ get path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to eq(200) end - it "returns the column" do + it 'returns the column' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "non existing group by" do - let(:path) { api_v3_paths.query_column("bogus") } + context 'non existing group by' do + let(:path) { api_v3_paths.query_column('bogus') } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end diff --git a/spec/requests/api/v3/queries/create_form_api_spec.rb b/spec/requests/api/v3/queries/create_form_api_spec.rb index 3c08545f59c8..487f24662db1 100644 --- a/spec/requests/api/v3/queries/create_form_api_spec.rb +++ b/spec/requests/api/v3/queries/create_form_api_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "POST /api/v3/queries/form", with_ee: %i[baseline_comparison] do @@ -43,7 +43,7 @@ spentTime startDate status subject type updatedAt version).map do |id| { - _type: "QueryColumn::Property", + _type: 'QueryColumn::Property', id: } end @@ -51,7 +51,7 @@ let(:custom_field_columns_json) do [ { - _type: "QueryColumn::Property", + _type: 'QueryColumn::Property', id: "customField#{custom_field.id}" } ] @@ -59,7 +59,7 @@ let(:relation_to_type_columns_json) do project.types.map do |type| { - _type: "QueryColumn::RelationToType", + _type: 'QueryColumn::RelationToType', id: "relationsToType#{type.id}" } end @@ -67,7 +67,7 @@ let(:relation_of_type_columns_json) do Relation::TYPES.map do |_, value| { - _type: "QueryColumn::RelationOfType", + _type: 'QueryColumn::RelationOfType', id: "relationsOfType#{value[:sym].camelcase}" } end @@ -75,7 +75,7 @@ let(:non_project_type_relation_column_json) do [ { - _type: "QueryColumn::RelationToType", + _type: 'QueryColumn::RelationToType', id: "relationsToType#{non_project_type.id}" } ] @@ -99,49 +99,49 @@ perform_request.call end - it "returns 200(OK)" do + it 'returns 200(OK)' do expect(last_response.status).to eq(200) end - it "is of type form" do + it 'is of type form' do expect(form["_type"]).to eq "Form" end - it "has the available_projects link for creation in the schema" do + it 'has the available_projects link for creation in the schema' do expect(form.dig("_embedded", "schema", "project", "_links", "allowedValues", "href")) .to eq "/api/v3/queries/available_projects" end - describe "with empty parameters" do - it "has 1 validation error" do + describe 'with empty parameters' do + it 'has 1 validation error' do expect(form.dig("_embedded", "validationErrors").size).to eq 1 end - it "has a validation error on name" do + it 'has a validation error on name' do expect(form.dig("_embedded", "validationErrors", "name", "message")).to eq "Name can't be blank." end - it "has no commit link" do + it 'has no commit link' do expect(form.dig("_links", "commit")).to be_nil end end - describe "with all minimum parameters" do + describe 'with all minimum parameters' do let(:parameters) do { name: "Some Query" } end - it "has 0 validation errors" do + it 'has 0 validation errors' do expect(form.dig("_embedded", "validationErrors")).to be_empty end - it "has the given name set" do + it 'has the given name set' do expect(form.dig("_embedded", "payload", "name")).to eq parameters[:name] end - describe "the commit link" do + describe 'the commit link' do it "has the correct URL" do expect(form.dig("_links", "commit", "href")).to eq "/api/v3/queries" end @@ -151,7 +151,7 @@ end end - describe "columns" do + describe 'columns' do let(:relation_columns_allowed) { true } let(:custom_field) do @@ -180,23 +180,23 @@ .and_return(relation_columns_allowed) end - context "with relation columns allowed by the enterprise token" do - it "has the static, custom field and relation columns" do + context 'with relation columns allowed by the enterprise token' do + it 'has the static, custom field and relation columns' do expected_columns = static_columns_json + custom_field_columns_json + relation_to_type_columns_json + relation_of_type_columns_json + non_project_type_relation_column_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -204,22 +204,22 @@ end end - context "with relation columns disallowed by the enterprise token" do + context 'with relation columns disallowed by the enterprise token' do let(:relation_columns_allowed) { false } - it "has the static and custom field" do + it 'has the static and custom field' do expected_columns = static_columns_json + custom_field_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -232,10 +232,10 @@ end end - describe "with minimum parameters for a project" do + describe 'with minimum parameters for a project' do let(:parameters) do { - name: "Some Query", + name: 'Some Query', _links: { project: { href: "/api/v3/projects/#{project.id}" @@ -244,7 +244,7 @@ } end - describe "columns" do + describe 'columns' do let(:relation_columns_allowed) { true } let(:custom_field) do @@ -273,22 +273,22 @@ .and_return(relation_columns_allowed) end - context "with relation columns allowed by the enterprise token" do - it "has the static, custom field and relation columns" do + context 'with relation columns allowed by the enterprise token' do + it 'has the static, custom field and relation columns' do expected_columns = static_columns_json + custom_field_columns_json + relation_to_type_columns_json + relation_of_type_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -297,22 +297,22 @@ end end - context "with relation columns disallowed by the enterprise token" do + context 'with relation columns disallowed by the enterprise token' do let(:relation_columns_allowed) { false } - it "has the static and custom field" do + it 'has the static and custom field' do expected_columns = static_columns_json + custom_field_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -325,9 +325,9 @@ end end - describe "with all parameters given" do + describe 'with all parameters given' do let(:status) { create(:status) } - let(:timestamps) { [1.week.ago.iso8601, "lastWorkingDay@12:00+00:00", "P0D"] } + let(:timestamps) { [1.week.ago.iso8601, 'lastWorkingDay@12:00+00:00', "P0D"] } let(:parameters) do { @@ -381,29 +381,29 @@ } end - it "has 0 validation errors" do + it 'has 0 validation errors' do expect(form.dig("_embedded", "validationErrors")).to be_empty end - it "has a commit link" do + it 'has a commit link' do expect(form.dig("_links", "commit")).to be_present end - it "has the given name set" do + it 'has the given name set' do expect(form.dig("_embedded", "payload", "name")).to eq parameters[:name] end - it "has the project set" do + it 'has the project set' do project_link = { "href" => "/api/v3/projects/#{project.id}", "title" => project.name } expect(form.dig("_embedded", "payload", "_links", "project")).to eq project_link end - it "is set to public" do + it 'is set to public' do expect(form.dig("_embedded", "payload", "public")).to be true end - it "has the filters set" do + it 'has the filters set' do filters = [ { "_links" => { @@ -413,7 +413,7 @@ }, "operator" => { "href" => "/api/v3/queries/operators/%3D", - "title" => "is (OR)" + "title" => 'is (OR)' }, "values" => [ { @@ -428,22 +428,22 @@ expect(form.dig("_embedded", "payload", "filters")).to eq filters end - it "has the columns set" do + it 'has the columns set' do columns = [ - { "href" => "/api/v3/queries/columns/id", "title" => "ID" }, - { "href" => "/api/v3/queries/columns/subject", "title" => "Subject" } + { "href" => "/api/v3/queries/columns/id", "title" => 'ID' }, + { "href" => "/api/v3/queries/columns/subject", "title" => 'Subject' } ] expect(form.dig("_embedded", "payload", "_links", "columns")).to eq columns end - it "has the groupBy set" do - group_by = { "href" => "/api/v3/queries/group_bys/assignee", "title" => "Assignee" } + it 'has the groupBy set' do + group_by = { "href" => "/api/v3/queries/group_bys/assignee", "title" => 'Assignee' } expect(form.dig("_embedded", "payload", "_links", "groupBy")).to eq group_by end - it "has the columns set" do + it 'has the columns set' do sort_by = [ { "href" => "/api/v3/queries/sort_bys/id-desc", "title" => "ID (Descending)" }, { "href" => "/api/v3/queries/sort_bys/assignee-asc", "title" => "Assignee (Ascending)" } @@ -452,14 +452,14 @@ expect(form.dig("_embedded", "payload", "_links", "sortBy")).to eq sort_by end - it "has the timestamps set" do + it 'has the timestamps set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq timestamps end - context "with one timestamp is present only" do + context 'with one timestamp is present only' do let(:timestamps) { "PT0S" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end @@ -564,10 +564,10 @@ end end - context "with invalid timestamps" do - context "when one timestamp cannot be parsed" do + context 'with invalid timestamps' do + context 'when one timestamp cannot be parsed' do let(:override_params) do - { timestamps: ["invalid", "P0D"] } + { timestamps: ['invalid', 'P0D'] } end it "returns a validation error" do @@ -576,9 +576,9 @@ end end - context "when one timestamp cannot be parsed (malformed)" do + context 'when one timestamp cannot be parsed (malformed)' do let(:override_params) do - { timestamps: ["2022-03-02 invalid string 20:45:56Z", "P0D"] } + { timestamps: ['2022-03-02 invalid string 20:45:56Z', 'P0D'] } end it "returns a validation error" do @@ -587,9 +587,9 @@ end end - context "when one timestamp cannot be parsed (malformed)#2" do + context 'when one timestamp cannot be parsed (malformed)#2' do let(:override_params) do - { timestamps: ["LastWorkingDayInvalid@12:00", "P0D"] } + { timestamps: ['LastWorkingDayInvalid@12:00', 'P0D'] } end it "returns a validation error" do @@ -598,9 +598,9 @@ end end - context "when both timestamps cannot be parsed" do + context 'when both timestamps cannot be parsed' do let(:override_params) do - { timestamps: ["invalid", "invalid2"] } + { timestamps: ['invalid', 'invalid2'] } end it "returns a validation error" do @@ -619,37 +619,37 @@ end end - context "with EE token", with_ee: %i[baseline_comparison] do - describe "timestamps" do - context "with a value within 1 day" do + context 'with EE token', with_ee: %i[baseline_comparison] do + describe 'timestamps' do + context 'with a value within 1 day' do let(:timestamps) { "oneDayAgo@00:00+00:00" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end - context "with a value older than 1 day" do + context 'with a value older than 1 day' do let(:timestamps) { "P-2D" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end end end - context "without EE token", with_ee: false do - describe "timestamps" do - context "with a value within 1 day" do + context 'without EE token', with_ee: false do + describe 'timestamps' do + context 'with a value within 1 day' do let(:timestamps) { "oneDayAgo@00:00+00:00" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end - context "with a value older than 1 day" do + context 'with a value older than 1 day' do let(:timestamps) { "P-2D" } it "returns a validation error" do @@ -661,7 +661,7 @@ end end - describe "posting to a project-query form with a CF present only there (Regression #29873)" do + describe 'posting to a project-query form with a CF present only there (Regression #29873)' do let(:custom_field) do create( :string_wp_custom_field, @@ -700,15 +700,15 @@ it "returns a valid form" do expect(form.dig("_embedded", "validationErrors")).to be_empty - filters = form.dig("_embedded", "payload", "filters") + filters = form.dig('_embedded', 'payload', 'filters') # Expect one CF filter expect(filters.length).to eq 1 cf_filter = filters.first - expect(cf_filter["values"]).to eq ["ABC"] - expect(cf_filter.dig("_links", "filter", "href")).to eq "/api/v3/queries/filters/customField#{custom_field.id}" - expect(cf_filter.dig("_links", "operator", "title")).to eq "is" + expect(cf_filter['values']).to eq ['ABC'] + expect(cf_filter.dig('_links', 'filter', 'href')).to eq "/api/v3/queries/filters/customField#{custom_field.id}" + expect(cf_filter.dig('_links', 'operator', 'title')).to eq 'is' end end end diff --git a/spec/requests/api/v3/queries/create_query_spec.rb b/spec/requests/api/v3/queries/create_query_spec.rb index ebd7719b3ced..7ffb745823b5 100644 --- a/spec/requests/api/v3/queries/create_query_spec.rb +++ b/spec/requests/api/v3/queries/create_query_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "POST /api/v3/queries", with_ee: %i[baseline_comparison] do shared_let(:user) { create(:admin) } shared_let(:status) { create(:status) } shared_let(:project) { create(:project) } - let(:timestamps) { [1.week.ago.iso8601, "lastWorkingDay@12:00+00:00", "P0D"] } + let(:timestamps) { [1.week.ago.iso8601, 'lastWorkingDay@12:00+00:00', "P0D"] } let(:default_params) do { @@ -109,16 +109,16 @@ def json post "/api/v3/queries", params.to_json end - it "returns 201 (created)" do + it 'returns 201 (created)' do expect(last_response.status).to eq(201) end - it "renders the created query" do + it 'renders the created query' do expect(json["_type"]).to eq "Query" expect(json["name"]).to eq "Dummy Query" end - it "creates the query correctly" do + it 'creates the query correctly' do query = Query.find_by(name: params[:name]) expect(query).to be_present @@ -137,20 +137,20 @@ def json expect(filter.values).to eq [status.id.to_s] end - context "without EE", with_ee: false do - it "yields a 422 error given a timestamp older than 1 day" do + context 'without EE', with_ee: false do + it 'yields a 422 error given a timestamp older than 1 day' do expect(last_response.status).to eq 422 expect(json["message"]).to eq "Timestamps contain forbidden values: #{timestamps.first}" end - context "when timestamps are within 1 day" do + context 'when timestamps are within 1 day' do let(:timestamps) { ["oneDayAgo@12:00+00:00"] } - it "returns 201 (created)" do + it 'returns 201 (created)' do expect(last_response.status).to eq(201) end - it "updates the query timestamps" do + it 'updates the query timestamps' do expect(Query.first.timestamps).to eq(timestamps.map { |t| Timestamp.new(t) }) end end diff --git a/spec/requests/api/v3/queries/filters/query_filters_resource_spec.rb b/spec/requests/api/v3/queries/filters/query_filters_resource_spec.rb index 871deecd57fe..b4313b244c59 100644 --- a/spec/requests/api/v3/queries/filters/query_filters_resource_spec.rb +++ b/spec/requests/api/v3/queries/filters/query_filters_resource_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Filter resource" do +RSpec.describe 'API v3 Query Filter resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#get queries/filters/:id" do + describe '#get queries/filters/:id' do let(:path) { api_v3_paths.query_filter(filter_name) } - let(:filter_name) { "assignee" } + let(:filter_name) { 'assignee' } let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } let(:permissions) { [:view_work_packages] } @@ -52,45 +52,45 @@ get path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to eq(200) end - it "returns the filter" do + it 'returns the filter' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "non existing filter" do - let(:filter_name) { "bogus" } + context 'non existing filter' do + let(:filter_name) { 'bogus' } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end end - context "custom field filter" do + context 'custom field filter' do let(:list_wp_custom_field) { create(:list_wp_custom_field) } let(:filter_name) { list_wp_custom_field.attribute_name(:camel_case) } - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to eq(200) end - it "returns the filter" do + it 'returns the filter' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end end diff --git a/spec/requests/api/v3/queries/group_bys/query_group_bys_resource_spec.rb b/spec/requests/api/v3/queries/group_bys/query_group_bys_resource_spec.rb index ea99eaf8c6ee..9a2e2453cba0 100644 --- a/spec/requests/api/v3/queries/group_bys/query_group_bys_resource_spec.rb +++ b/spec/requests/api/v3/queries/group_bys/query_group_bys_resource_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Group By resource" do +RSpec.describe 'API v3 Query Group By resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#get queries/group_bys/:id" do + describe '#get queries/group_bys/:id' do let(:path) { api_v3_paths.query_group_by(group_by_name) } - let(:group_by_name) { "status" } + let(:group_by_name) { 'status' } let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } let(:permissions) { [:view_work_packages] } @@ -52,36 +52,36 @@ get path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to be(200) end - it "returns the group_by" do + it 'returns the group_by' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "non existing group by" do - let(:path) { api_v3_paths.query_group_by("bogus") } + context 'non existing group by' do + let(:path) { api_v3_paths.query_group_by('bogus') } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end end - context "non groupable group by" do - let(:path) { api_v3_paths.query_group_by("id") } + context 'non groupable group by' do + let(:path) { api_v3_paths.query_group_by('id') } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end diff --git a/spec/requests/api/v3/queries/ical_url/query_ical_url_api_spec.rb b/spec/requests/api/v3/queries/ical_url/query_ical_url_api_spec.rb index bc78a5e2eb57..627639349231 100644 --- a/spec/requests/api/v3/queries/ical_url/query_ical_url_api_spec.rb +++ b/spec/requests/api/v3/queries/ical_url/query_ical_url_api_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query ICal Url" do +RSpec.describe 'API v3 Query ICal Url' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#post queries/:id/ical_url" do + describe '#post queries/:id/ical_url' do let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } # TODO: check OpenProject::Configuration.ical_subscriptions_enabled configuration @@ -56,44 +56,44 @@ post path, params.to_json end - shared_examples_for "success" do - it "succeeds" do + shared_examples_for 'success' do + it 'succeeds' do expect(last_response.status) .to eq(201) end - it "returns the path pointing to self" do + it 'returns the path pointing to self' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - it "returns the path pointing to the associated query" do + it 'returns the path pointing to the associated query' do expect(last_response.body) .to be_json_eql(api_v3_paths.query(query.id).to_json) - .at_path("_links/query/href") + .at_path('_links/query/href') end - it "returns the tokenized, absolute url pointing to iCalendar endpoint" do + it 'returns the tokenized, absolute url pointing to iCalendar endpoint' do json = JSON.parse(last_response.body) - expect(json["_links"]["icalUrl"]["href"]).to include("http") - expect(json["_links"]["icalUrl"]["href"]).to include( + expect(json['_links']['icalUrl']['href']).to include('http') + expect(json['_links']['icalUrl']['href']).to include( "projects/#{project.id}/calendars/#{query.id}/ical?ical_token=" ) end end - context "when user has sufficient permissions and owns the query" do - context "when icalendar sharing is enabled globally", with_settings: { ical_enabled: true } do - it_behaves_like "success" + context 'when user has sufficient permissions and owns the query' do + context 'when icalendar sharing is enabled globally', with_settings: { ical_enabled: true } do + it_behaves_like 'success' end - context "when icalendar sharing is disabled globally", with_settings: { ical_enabled: false } do - it_behaves_like "unauthorized access" + context 'when icalendar sharing is disabled globally', with_settings: { ical_enabled: false } do + it_behaves_like 'unauthorized access' end end - context "when user has sufficient permissions and tries to get the iCalendar url of the public query of another user" do + context 'when user has sufficient permissions and tries to get the iCalendar url of the public query of another user' do let(:role_of_other_user) { create(:project_role, permissions: [:view_work_packages]) } let(:other_user) do create(:user, @@ -102,43 +102,43 @@ let(:query) { create(:query, project:, user: other_user, public: true) } let(:path) { api_v3_paths.query_ical_url(query.id) } - context "when icalendar sharing is enabled globally", with_settings: { ical_enabled: true } do - it_behaves_like "success" + context 'when icalendar sharing is enabled globally', with_settings: { ical_enabled: true } do + it_behaves_like 'success' end - context "when icalendar sharing is disabled globally", with_settings: { ical_enabled: false } do - it_behaves_like "unauthorized access" + context 'when icalendar sharing is disabled globally', with_settings: { ical_enabled: false } do + it_behaves_like 'unauthorized access' end end - context "when user has no access to the associated project", with_settings: { ical_enabled: true } do + context 'when user has no access to the associated project', with_settings: { ical_enabled: true } do let(:other_project) { create(:project) } let(:query) { create(:query, project: other_project, user:) } let(:path) { api_v3_paths.query_ical_url(query.id) } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "when user tries to get an iCalendar url from a private query of another user", + context 'when user tries to get an iCalendar url from a private query of another user', with_settings: { ical_enabled: true } do let(:other_user) { create(:user) } let(:query) { create(:query, project:, user: other_user, public: false) } let(:path) { api_v3_paths.query_ical_url(query.id) } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "when user has insufficient permissions", with_settings: { ical_enabled: true } do + context 'when user has insufficient permissions', with_settings: { ical_enabled: true } do # :view_work_packages permission is mandatory, otherwise a 404 is returned. let(:permissions) { [:view_work_packages] } # share_calendars is missing - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "when query does not exist" do + context 'when query does not exist' do let(:path) { api_v3_paths.query_ical_url(query.id + 42) } - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/queries/operators/query_operators_resource_spec.rb b/spec/requests/api/v3/queries/operators/query_operators_resource_spec.rb index e22cfcf35e28..8de98fb7950a 100644 --- a/spec/requests/api/v3/queries/operators/query_operators_resource_spec.rb +++ b/spec/requests/api/v3/queries/operators/query_operators_resource_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Operator resource" do +RSpec.describe 'API v3 Query Operator resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#get queries/operators/:id" do + describe '#get queries/operators/:id' do let(:path) { api_v3_paths.query_operator(CGI.escape(operator)) } - let(:operator) { "=" } + let(:operator) { '=' } let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } let(:permissions) { [:view_work_packages] } @@ -52,27 +52,27 @@ get path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to eq(200) end - it "returns the operator" do + it 'returns the operator' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "non existing operator" do - let(:operator) { "bogus" } + context 'non existing operator' do + let(:operator) { 'bogus' } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end diff --git a/spec/requests/api/v3/queries/order/query_order_api_spec.rb b/spec/requests/api/v3/queries/order/query_order_api_spec.rb index 680d69beffb0..284397e23aaa 100644 --- a/spec/requests/api/v3/queries/order/query_order_api_spec.rb +++ b/spec/requests/api/v3/queries/order/query_order_api_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "/api/v3/queries/:id/order" do let(:user) { create(:admin) } @@ -40,7 +40,7 @@ header "Content-Type", "application/json" end - describe "with order present" do + describe 'with order present' do let(:wp1) { create(:work_package) } let(:wp2) { create(:work_package) } @@ -49,7 +49,7 @@ query.ordered_work_packages.create(work_package_id: wp2.id, position: 8192) end - it "returns the order" do + it 'returns the order' do get path expect(last_response.status).to eq 200 @@ -58,7 +58,7 @@ end end - describe "#patch" do + describe '#patch' do let!(:wp1) { create(:work_package) } let!(:wp2) { create(:work_package) } @@ -68,21 +68,21 @@ query.ordered_work_packages.create(work_package_id: wp1.id, position: 0) end - it "allows inserting a delta" do + it 'allows inserting a delta' do patch path, { delta: { wp2.id.to_s => 1234 } }.to_json expect(last_response.status).to eq 200 query.reload - expect(body).to eq("t" => timestamp) + expect(body).to eq('t' => timestamp) expect(query.ordered_work_packages.find_by(work_package: wp2).position).to eq 1234 end - it "allows removing an item" do + it 'allows removing an item' do patch path, { delta: { wp1.id.to_s => -1 } }.to_json expect(last_response.status).to eq 200 query.reload - expect(body).to eq("t" => timestamp) + expect(body).to eq('t' => timestamp) expect(query.ordered_work_packages.to_a).to be_empty end end diff --git a/spec/requests/api/v3/queries/queries_by_project_resource_spec.rb b/spec/requests/api/v3/queries/queries_by_project_resource_spec.rb index 963df18234d8..92662f251e20 100644 --- a/spec/requests/api/v3/queries/queries_by_project_resource_spec.rb +++ b/spec/requests/api/v3/queries/queries_by_project_resource_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query resource" do +RSpec.describe 'API v3 Query resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - let(:project) { create(:project, identifier: "test_project", public: false) } + let(:project) { create(:project, identifier: 'test_project', public: false) } let(:current_user) do create(:user, member_with_roles: { project => role }) end @@ -44,14 +44,14 @@ allow(User).to receive(:current).and_return current_user end - describe "#get projects/:project_id/queries/default" do + describe '#get projects/:project_id/queries/default' do let(:base_path) { api_v3_paths.query_project_default(project.id) } - it_behaves_like "GET individual query" do - context "lacking permissions" do + it_behaves_like 'GET individual query' do + context 'lacking permissions' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/queries/query_resource_spec.rb b/spec/requests/api/v3/queries/query_resource_spec.rb index 1124cdb24ce1..ff69d7e82d9b 100644 --- a/spec/requests/api/v3/queries/query_resource_spec.rb +++ b/spec/requests/api/v3/queries/query_resource_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query resource", +RSpec.describe 'API v3 Query resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper - let(:project) { create(:project, identifier: "test_project", public: false) } + let(:project) { create(:project, identifier: 'test_project', public: false) } let(:other_project) { create(:project) } let(:current_user) do create(:user, member_with_roles: { project => role }) @@ -53,7 +53,7 @@ allow(User).to receive(:current).and_return current_user end - describe "#get queries/" do + describe '#get queries/' do let(:path) { api_v3_paths.queries } let(:prepare) {} @@ -63,21 +63,21 @@ get path end - context "user has view_work_packages in a project" do - it "succeeds" do + context 'user has view_work_packages in a project' do + it 'succeeds' do expect(last_response.status).to eq(200) end end - context "user has manage_public_queries in a project" do + context 'user has manage_public_queries in a project' do let(:permissions) { [:manage_public_queries] } - it "succeeds" do + it 'succeeds' do expect(last_response.status).to eq(200) end end - context "user not allowed to see queries" do + context 'user not allowed to see queries' do let(:current_user) { create(:user) } let(:non_member_permissions) { [:view_work_packages] } @@ -86,20 +86,20 @@ create(:project, public: true, active: true) end - include_context "with non-member permissions from non_member_permissions" + include_context 'with non-member permissions from non_member_permissions' - it "succeeds" do + it 'succeeds' do expect(last_response.status).to eq(200) end - context "that is not allowed to see queries anywhere" do + context 'that is not allowed to see queries anywhere' do let(:non_member_permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - context "filtering for project" do + context 'filtering for project' do let(:path) do filter = [project: { operator: "=", values: [project.id.to_s] }] @@ -117,7 +117,7 @@ user: current_user) end - it "includes only queries from the specified project" do + it 'includes only queries from the specified project' do expect(last_response.body) .to be_json_eql(1) .at_path("count") @@ -130,7 +130,7 @@ end end - context "filtering for global query" do + context 'filtering for global query' do let(:path) do filter = [project: { operator: "!*", values: [] }] @@ -148,7 +148,7 @@ user: current_user) end - it "includes only queries not belonging to a project" do + it 'includes only queries not belonging to a project' do expect(last_response.body) .to be_json_eql(1) .at_path("count") @@ -161,7 +161,7 @@ end end - context "filtering by updated_at" do + context 'filtering by updated_at' do let(:old_query) { create(:public_query, project:) } let(:prepare) do @@ -175,7 +175,7 @@ api_v3_paths.path_for(:queries, filters: filter) end - it "includes only queries updated after the value" do + it 'includes only queries updated after the value' do expect(last_response.body) .to be_json_eql(1) .at_path("count") @@ -188,7 +188,7 @@ end end - context "filtering by id" do + context 'filtering by id' do let(:prepare) do query global_query @@ -200,7 +200,7 @@ api_v3_paths.path_for(:queries, filters: filter) end - it "includes only queries with that id" do + it 'includes only queries with that id' do expect(last_response.body) .to be_json_eql(1) .at_path("count") @@ -214,31 +214,31 @@ end end - describe "#get queries/:id" do + describe '#get queries/:id' do let(:base_path) { api_v3_paths.query(query.id) } - it_behaves_like "GET individual query" do - context "lacking permissions" do + it_behaves_like 'GET individual query' do + context 'lacking permissions' do let(:permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end end end - describe "#get queries/default" do + describe '#get queries/default' do let(:base_path) { api_v3_paths.query_default } - it_behaves_like "GET individual query" do - context "lacking permissions" do + it_behaves_like 'GET individual query' do + context 'lacking permissions' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end - describe "#delete queries/:id" do + describe '#delete queries/:id' do let(:path) { api_v3_paths.query query.id } let(:permissions) { %i[view_work_packages manage_public_queries] } @@ -246,204 +246,204 @@ delete path end - it "responds with HTTP No Content" do + it 'responds with HTTP No Content' do expect(last_response.status).to eq 204 end - it "deletes the Query" do + it 'deletes the Query' do expect(Query.exists?(query.id)).to be_falsey end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' - it "does not delete the Query" do + it 'does not delete the Query' do expect(Query.exists?(query.id)).to be_truthy end end - context "for a non-existent query" do + context 'for a non-existent query' do let(:query_id) { 1337 } # could be anything as long as we do not create an actual query let(:path) { api_v3_paths.query query_id } - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "#get queries/available_projects" do + describe '#get queries/available_projects' do before do other_project get api_v3_paths.query_available_projects end - it "succeeds" do + it 'succeeds' do expect(last_response.status).to eq(200) end - it "returns a Collection of projects for which the user has view work packages permission" do + it 'returns a Collection of projects for which the user has view work packages permission' do expect(last_response.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql(1.to_json) - .at_path("count") + .at_path('count') expect(last_response.body) .to be_json_eql(1.to_json) - .at_path("total") + .at_path('total') expect(last_response.body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "#star" do + describe '#star' do let(:star_path) { api_v3_paths.query_star query.id } before do patch star_path end - describe "public queries" do - context "user with permission to manage public queries" do + describe 'public queries' do + context 'user with permission to manage public queries' do let(:permissions) { %i[view_work_packages manage_public_queries] } - context "when starring an unstarred query" do - it "responds with 200" do + context 'when starring an unstarred query' do + it 'responds with 200' do expect(last_response.status).to eq(200) end it 'returns the query with "starred" property set to true' do - expect(last_response.body).to be_json_eql(true).at_path("starred") + expect(last_response.body).to be_json_eql(true).at_path('starred') end end - context "when starring already starred query" do - it "responds with 200" do + context 'when starring already starred query' do + it 'responds with 200' do expect(last_response.status).to eq(200) end it 'returns the query with "starred" property set to true' do - expect(last_response.body).to be_json_eql(true).at_path("starred") + expect(last_response.body).to be_json_eql(true).at_path('starred') end end - context "when trying to star nonexistent query" do + context 'when trying to star nonexistent query' do let(:star_path) { api_v3_paths.query_star 999 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "user without permission to manage public queries" do + context 'user without permission to manage public queries' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "private queries" do - context "user with permission to save queries" do + describe 'private queries' do + context 'user with permission to save queries' do let(:query) { create(:private_query, project:, user: current_user) } let(:permissions) { %i[view_work_packages save_queries] } - context "starring his own query" do - it "responds with 200" do + context 'starring his own query' do + it 'responds with 200' do expect(last_response.status).to eq(200) end it 'returns the query with "starred" property set to true' do - expect(last_response.body).to be_json_eql(true).at_path("starred") + expect(last_response.body).to be_json_eql(true).at_path('starred') end end - context "trying to star somebody else's query" do + context 'trying to star somebody else\'s query' do let(:another_user) { create(:user) } let(:query) { create(:private_query, project:, user: another_user) } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "user without permission to save queries" do + context 'user without permission to save queries' do let(:query) { create(:private_query, project:, user: current_user) } let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end - describe "#unstar" do + describe '#unstar' do let(:unstar_path) { api_v3_paths.query_unstar query.id } - describe "public queries" do + describe 'public queries' do let(:query) { create(:public_query, project:) } - context "user with permission to manage public queries" do + context 'user with permission to manage public queries' do let(:permissions) { %i[view_work_packages manage_public_queries] } - context "when unstarring a starred query" do + context 'when unstarring a starred query' do let(:query) { create(:public_query, project:, starred: true) } before do patch unstar_path end - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end it 'returns the query with "starred" property set to false' do - expect(last_response.body).to be_json_eql(false).at_path("starred") + expect(last_response.body).to be_json_eql(false).at_path('starred') end end - context "when unstarring an unstarred query" do + context 'when unstarring an unstarred query' do before do patch unstar_path end - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end it 'returns the query with "starred" property set to false' do - expect(last_response.body).to be_json_eql(false).at_path("starred") + expect(last_response.body).to be_json_eql(false).at_path('starred') end end - context "when trying to unstar nonexistent query" do + context 'when trying to unstar nonexistent query' do let(:unstar_path) { api_v3_paths.query_unstar 999 } before do patch unstar_path end - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "user without permission to manage public queries" do + context 'user without permission to manage public queries' do let(:permissions) { [:view_work_packages] } before do patch unstar_path end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "private queries" do - context "user with permission to save queries" do + describe 'private queries' do + context 'user with permission to save queries' do let(:query) { create(:private_query, project:, user: current_user) } let(:permissions) { %i[view_work_packages save_queries] } @@ -451,25 +451,25 @@ patch unstar_path end - context "unstarring his own query" do - it "responds with 200" do + context 'unstarring his own query' do + it 'responds with 200' do expect(last_response.status).to eq(200) end it 'returns the query with "starred" property set to true' do - expect(last_response.body).to be_json_eql(false).at_path("starred") + expect(last_response.body).to be_json_eql(false).at_path('starred') end end - context "trying to unstar somebody else's query" do + context 'trying to unstar somebody else\'s query' do let(:another_user) { create(:user) } let(:query) { create(:private_query, project:, user: another_user) } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "user without permission to save queries" do + context 'user without permission to save queries' do let(:query) { create(:private_query, project:, user: current_user) } let(:permissions) { [:view_work_packages] } @@ -477,26 +477,26 @@ patch unstar_path end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end - describe "#post queries/form" do + describe '#post queries/form' do let(:path) { api_v3_paths.create_query_form } before do post path end - it "succeeds" do + it 'succeeds' do expect(last_response.status).to eq(200) end - it "returns the form" do + it 'returns the form' do expect(last_response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end end end diff --git a/spec/requests/api/v3/queries/schemas/query_filter_instance_schema_resource_spec.rb b/spec/requests/api/v3/queries/schemas/query_filter_instance_schema_resource_spec.rb index 0b52bf2f6ff8..90b23da77af8 100644 --- a/spec/requests/api/v3/queries/schemas/query_filter_instance_schema_resource_spec.rb +++ b/spec/requests/api/v3/queries/schemas/query_filter_instance_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Filter Schema resource" do +RSpec.describe 'API v3 Query Filter Schema resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -58,41 +58,41 @@ last_response end - describe "#GET /api/v3/queries/filter_instance_schemas" do + describe '#GET /api/v3/queries/filter_instance_schemas' do %i[global project].each do |current_path| context current_path do let(:path) { send :"#{current_path}_path" } - it "succeeds" do + it 'succeeds' do expect(subject.status) .to eq(200) end - it "returns a collection of schemas" do + it 'returns a collection of schemas' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') expected_type = "QueryFilterInstanceSchema" expect(subject.body) .to be_json_eql(expected_type.to_json) - .at_path("_embedded/elements/0/_type") + .at_path('_embedded/elements/0/_type') end - context "when the user is not allowed" do + context 'when the user is not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end - context "when in a global context" do + context 'when in a global context' do let(:path) { global_path } before do @@ -100,21 +100,21 @@ get path end - it "includes only global specific filter" do - instance_paths = JSON.parse(subject.body).dig("_embedded", "elements").map { |f| f.dig("_links", "self", "href") } + it 'includes only global specific filter' do + instance_paths = JSON.parse(subject.body).dig('_embedded', 'elements').map { |f| f.dig('_links', 'self', 'href') } expect(instance_paths) - .not_to include(api_v3_paths.query_filter_instance_schema("category")) + .not_to include(api_v3_paths.query_filter_instance_schema('category')) expect(instance_paths) - .to include(api_v3_paths.query_filter_instance_schema("project")) + .to include(api_v3_paths.query_filter_instance_schema('project')) expect(instance_paths) - .not_to include(api_v3_paths.query_filter_instance_schema("subprojectId")) + .not_to include(api_v3_paths.query_filter_instance_schema('subprojectId')) end end - context "when in a project context" do + context 'when in a project context' do let(:path) { project_path } before do @@ -122,46 +122,46 @@ get path end - it "includes project specific filter" do - instance_paths = JSON.parse(subject.body).dig("_embedded", "elements").map { |f| f.dig("_links", "self", "href") } + it 'includes project specific filter' do + instance_paths = JSON.parse(subject.body).dig('_embedded', 'elements').map { |f| f.dig('_links', 'self', 'href') } expect(instance_paths) - .to include(api_v3_paths.query_filter_instance_schema("category")) + .to include(api_v3_paths.query_filter_instance_schema('category')) expect(instance_paths) - .to include(api_v3_paths.query_filter_instance_schema("project")) + .to include(api_v3_paths.query_filter_instance_schema('project')) expect(instance_paths) - .to include(api_v3_paths.query_filter_instance_schema("subprojectId")) + .to include(api_v3_paths.query_filter_instance_schema('subprojectId')) end end end - describe "#GET /api/v3/queries/filter_instance_schemas/:id" do - let(:filter_name) { "assignee" } + describe '#GET /api/v3/queries/filter_instance_schemas/:id' do + let(:filter_name) { 'assignee' } let(:path) { api_v3_paths.query_filter_instance_schema(filter_name) } - it "succeeds" do + it 'succeeds' do expect(subject.status) .to eq(200) end - it "returns the instance schema" do + it 'returns the instance schema' do expect(subject.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "when the user is not allowed" do + context 'when the user is not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "when the id is not found" do - let(:filter_name) { "bogus" } + context 'when the id is not found' do + let(:filter_name) { 'bogus' } - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/queries/schemas/query_project_schema_resource_spec.rb b/spec/requests/api/v3/queries/schemas/query_project_schema_resource_spec.rb index 644eddaa920a..29fdbe907949 100644 --- a/spec/requests/api/v3/queries/schemas/query_project_schema_resource_spec.rb +++ b/spec/requests/api/v3/queries/schemas/query_project_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Schema resource" do +RSpec.describe 'API v3 Query Schema resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -43,7 +43,7 @@ login_as(user) end - describe "#get queries/schema" do + describe '#get queries/schema' do subject { last_response } let(:path) { api_v3_paths.query_project_schema(project.id) } @@ -52,21 +52,21 @@ get path end - it "succeeds" do + it 'succeeds' do expect(subject.status) .to be(200) end - it "returns the schema" do + it 'returns the schema' do expect(subject.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/queries/schemas/query_schema_resource_spec.rb b/spec/requests/api/v3/queries/schemas/query_schema_resource_spec.rb index 6551ea63e8fc..862a1e5dbd24 100644 --- a/spec/requests/api/v3/queries/schemas/query_schema_resource_spec.rb +++ b/spec/requests/api/v3/queries/schemas/query_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Schema resource" do +RSpec.describe 'API v3 Query Schema resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -46,7 +46,7 @@ .and_return(user) end - describe "#get queries/schema" do + describe '#get queries/schema' do subject { last_response } let(:path) { api_v3_paths.query_schema } @@ -55,21 +55,21 @@ get path end - it "succeeds" do + it 'succeeds' do expect(subject.status) .to be(200) end - it "returns the schema" do + it 'returns the schema' do expect(subject.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/queries/sort_bys/query_sort_bys_resource_spec.rb b/spec/requests/api/v3/queries/sort_bys/query_sort_bys_resource_spec.rb index aa357d002972..9c8112a7ee53 100644 --- a/spec/requests/api/v3/queries/sort_bys/query_sort_bys_resource_spec.rb +++ b/spec/requests/api/v3/queries/sort_bys/query_sort_bys_resource_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Query Sort Bys resource" do +RSpec.describe 'API v3 Query Sort Bys resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "#get queries/sort_bys/:id" do + describe '#get queries/sort_bys/:id' do let(:path) { api_v3_paths.query_sort_by(column_name, direction) } - let(:column_name) { "status" } - let(:direction) { "desc" } + let(:column_name) { 'status' } + let(:direction) { 'desc' } let(:project) { create(:project) } let(:role) { create(:project_role, permissions:) } let(:permissions) { [:view_work_packages] } @@ -53,45 +53,45 @@ get path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to eq(200) end - it "returns the sort by" do + it 'returns the sort by' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "user not allowed" do + context 'user not allowed' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "non existing sort by" do - let(:path) { api_v3_paths.query_sort_by("bogus", direction) } + context 'non existing sort by' do + let(:path) { api_v3_paths.query_sort_by('bogus', direction) } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end end - context "non existing direction" do - let(:path) { api_v3_paths.query_sort_by(column_name, "bogus") } + context 'non existing direction' do + let(:path) { api_v3_paths.query_sort_by(column_name, 'bogus') } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end end - context "non sortable sort by" do - let(:path) { api_v3_paths.query_sort_by("spent_time", direction) } + context 'non sortable sort by' do + let(:path) { api_v3_paths.query_sort_by('spent_time', direction) } - it "returns 404" do + it 'returns 404' do expect(last_response.status) .to be(404) end diff --git a/spec/requests/api/v3/queries/update_form_api_spec.rb b/spec/requests/api/v3/queries/update_form_api_spec.rb index 6d8fb54c8162..6d19bb816cbc 100644 --- a/spec/requests/api/v3/queries/update_form_api_spec.rb +++ b/spec/requests/api/v3/queries/update_form_api_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "POST /api/v3/queries/form", with_ee: %i[baseline_comparison] do @@ -36,7 +36,7 @@ let(:user) { create(:admin) } let(:role) { create(:existing_project_role, permissions:) } let(:permissions) { %i(view_work_packages manage_public_queries) } - let(:timestamps) { [1.week.ago.iso8601, "lastWorkingDay@12:00+00:00", "P0D"] } + let(:timestamps) { [1.week.ago.iso8601, 'lastWorkingDay@12:00+00:00', "P0D"] } let!(:project) { create(:project_with_types, members: { user => role }) } @@ -60,45 +60,45 @@ before do additional_setup - header "CONTENT_TYPE", "application/json" + header 'CONTENT_TYPE', 'application/json' post path, parameters.merge(override_params).to_json end - it "returns 200(OK)" do + it 'returns 200(OK)' do expect(last_response.status).to eq(200) end - it "is of type form" do + it 'is of type form' do expect(form["_type"]).to eq "Form" end - it "has the available_projects link for creation in the schema" do + it 'has the available_projects link for creation in the schema' do expect(form.dig("_embedded", "schema", "project", "_links", "allowedValues", "href")) .to eq "/api/v3/queries/available_projects" end - describe "with empty parameters" do - it "has 0 validation errors" do + describe 'with empty parameters' do + it 'has 0 validation errors' do expect(form.dig("_embedded", "validationErrors").size).to eq 0 end end - describe "with all minimum parameters" do + describe 'with all minimum parameters' do let(:parameters) do { name: "Some Query" } end - it "has 0 validation errors" do + it 'has 0 validation errors' do expect(form.dig("_embedded", "validationErrors")).to be_empty end - it "has the given name set" do + it 'has the given name set' do expect(form.dig("_embedded", "payload", "name")).to eq parameters[:name] end - describe "the commit link" do + describe 'the commit link' do it "has the correct URL" do expect(form.dig("_links", "commit", "href")).to eq "/api/v3/queries/#{query.id}" end @@ -108,7 +108,7 @@ end end - describe "columns" do + describe 'columns' do let(:relation_columns_allowed) { true } let(:additional_setup) do @@ -144,7 +144,7 @@ spentTime startDate status subject type updatedAt version).map do |id| { - _type: "QueryColumn::Property", + _type: 'QueryColumn::Property', id: } end @@ -153,7 +153,7 @@ let(:custom_field_columns_json) do [ { - _type: "QueryColumn::Property", + _type: 'QueryColumn::Property', id: "customField#{custom_field.id}" } ] @@ -162,7 +162,7 @@ let(:relation_to_type_columns_json) do project.types.map do |type| { - _type: "QueryColumn::RelationToType", + _type: 'QueryColumn::RelationToType', id: "relationsToType#{type.id}" } end @@ -171,7 +171,7 @@ let(:relation_of_type_columns_json) do Relation::TYPES.map do |_, value| { - _type: "QueryColumn::RelationOfType", + _type: 'QueryColumn::RelationOfType', id: "relationsOfType#{value[:sym].camelcase}" } end @@ -180,29 +180,29 @@ let(:non_project_type_relation_column_json) do [ { - _type: "QueryColumn::RelationToType", + _type: 'QueryColumn::RelationToType', id: "relationsToType#{non_project_type.id}" } ] end - context "within a project" do - context "with relation columns allowed by the enterprise token" do - it "has the static, custom field and relation columns" do + context 'within a project' do + context 'with relation columns allowed by the enterprise token' do + it 'has the static, custom field and relation columns' do expected_columns = static_columns_json + custom_field_columns_json + relation_to_type_columns_json + relation_of_type_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -211,20 +211,20 @@ end end - context "with relation columns disallowed by the enterprise token" do - it "has the static and custom field" do + context 'with relation columns disallowed by the enterprise token' do + it 'has the static and custom field' do expected_columns = static_columns_json + custom_field_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -236,7 +236,7 @@ end end - context "globally (no project)" do + context 'globally (no project)' do let(:additional_setup) do custom_field @@ -253,23 +253,23 @@ .and_return(relation_columns_allowed) end - context "with relation columns allowed by the enterprise token" do - it "has the static, custom field and relation columns" do + context 'with relation columns allowed by the enterprise token' do + it 'has the static, custom field and relation columns' do expected_columns = static_columns_json + custom_field_columns_json + relation_to_type_columns_json + non_project_type_relation_column_json + relation_of_type_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -277,20 +277,20 @@ end end - context "with relation columns disallowed by the enterprise token" do - it "has the static, custom field and relation columns" do + context 'with relation columns disallowed by the enterprise token' do + it 'has the static, custom field and relation columns' do expected_columns = static_columns_json + custom_field_columns_json - actual_columns = form.dig("_embedded", - "schema", - "columns", - "_embedded", - "allowedValues") + actual_columns = form.dig('_embedded', + 'schema', + 'columns', + '_embedded', + 'allowedValues') .map do |column| { - _type: column["_type"], - id: column["id"] + _type: column['_type'], + id: column['id'] } end @@ -304,7 +304,7 @@ end end - describe "with all parameters given" do + describe 'with all parameters given' do let(:status) { create(:status) } let(:additional_setup) do @@ -364,39 +364,39 @@ } end - it "has 0 validation errors" do + it 'has 0 validation errors' do expect(form.dig("_embedded", "validationErrors")).to be_empty end - it "has a commit link" do + it 'has a commit link' do expect(form.dig("_links", "commit")).to be_present end - it "has the given name set" do + it 'has the given name set' do expect(form.dig("_embedded", "payload", "name")).to eq parameters[:name] end - it "has the project set" do - project_link = { "href" => "/api/v3/projects/#{project.id}", "title" => project.name } + it 'has the project set' do + project_link = { "href" => "/api/v3/projects/#{project.id}", 'title' => project.name } expect(form.dig("_embedded", "payload", "_links", "project")).to eq project_link end - it "is set to public" do + it 'is set to public' do expect(form.dig("_embedded", "payload", "public")).to be true end - it "has the filters set" do + it 'has the filters set' do filters = [ { "_links" => { "filter" => { "href" => "/api/v3/queries/filters/status", - "title" => "Status" + 'title' => 'Status' }, "operator" => { "href" => "/api/v3/queries/operators/%3D", - "title" => "is (OR)" + "title" => 'is (OR)' }, "values" => [ { @@ -411,38 +411,38 @@ expect(form.dig("_embedded", "payload", "filters")).to eq filters end - it "has the columns set" do + it 'has the columns set' do columns = [ - { "href" => "/api/v3/queries/columns/id", "title" => "ID" }, - { "href" => "/api/v3/queries/columns/subject", "title" => "Subject" } + { "href" => "/api/v3/queries/columns/id", 'title' => 'ID' }, + { "href" => "/api/v3/queries/columns/subject", 'title' => 'Subject' } ] expect(form.dig("_embedded", "payload", "_links", "columns")).to eq columns end - it "has the groupBy set" do - group_by = { "href" => "/api/v3/queries/group_bys/assignee", "title" => "Assignee" } + it 'has the groupBy set' do + group_by = { "href" => "/api/v3/queries/group_bys/assignee", 'title' => 'Assignee' } expect(form.dig("_embedded", "payload", "_links", "groupBy")).to eq group_by end - it "has the columns set" do + it 'has the columns set' do sort_by = [ - { "href" => "/api/v3/queries/sort_bys/id-desc", "title" => "ID (Descending)" }, - { "href" => "/api/v3/queries/sort_bys/assignee-asc", "title" => "Assignee (Ascending)" } + { "href" => "/api/v3/queries/sort_bys/id-desc", 'title' => 'ID (Descending)' }, + { "href" => "/api/v3/queries/sort_bys/assignee-asc", 'title' => 'Assignee (Ascending)' } ] expect(form.dig("_embedded", "payload", "_links", "sortBy")).to eq sort_by end - it "has the timestamps set" do + it 'has the timestamps set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq timestamps end - context "with one timestamp is present only" do + context 'with one timestamp is present only' do let(:timestamps) { "PT0S" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end @@ -459,7 +459,7 @@ end it "still finds the project" do - project_link = { "href" => "/api/v3/projects/#{project.id}", "title" => project.name } + project_link = { "href" => "/api/v3/projects/#{project.id}", 'title' => project.name } expect(form.dig("_embedded", "payload", "_links", "project")).to eq project_link end @@ -531,10 +531,10 @@ end end - context "with invalid timestamps" do - context "when one timestamp cannot be parsed" do + context 'with invalid timestamps' do + context 'when one timestamp cannot be parsed' do let(:override_params) do - { timestamps: ["invalid", "P0D"] } + { timestamps: ['invalid', 'P0D'] } end it "returns a validation error" do @@ -543,9 +543,9 @@ end end - context "when one timestamp cannot be parsed (malformed)" do + context 'when one timestamp cannot be parsed (malformed)' do let(:override_params) do - { timestamps: ["2022-03-02 invalid string 20:45:56Z", "P0D"] } + { timestamps: ['2022-03-02 invalid string 20:45:56Z', 'P0D'] } end it "returns a validation error" do @@ -554,9 +554,9 @@ end end - context "when one timestamp cannot be parsed (malformed)#2" do + context 'when one timestamp cannot be parsed (malformed)#2' do let(:override_params) do - { timestamps: ["LastWorkingDayInvalid@12:00", "P0D"] } + { timestamps: ['LastWorkingDayInvalid@12:00', 'P0D'] } end it "returns a validation error" do @@ -565,9 +565,9 @@ end end - context "when both timestamps cannot be parsed" do + context 'when both timestamps cannot be parsed' do let(:override_params) do - { timestamps: ["invalid", "invalid2"] } + { timestamps: ['invalid', 'invalid2'] } end it "returns a validation error" do @@ -577,37 +577,37 @@ end end - context "with EE token", with_ee: %i[baseline_comparison] do - describe "timestamps" do - context "with a value within 1 day" do + context 'with EE token', with_ee: %i[baseline_comparison] do + describe 'timestamps' do + context 'with a value within 1 day' do let(:timestamps) { "oneDayAgo@00:00+00:00" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end - context "with a value older than 1 day" do + context 'with a value older than 1 day' do let(:timestamps) { "P-2D" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end end end - context "without EE token", with_ee: false do - describe "timestamps" do - context "with a value within 1 day" do + context 'without EE token', with_ee: false do + describe 'timestamps' do + context 'with a value within 1 day' do let(:timestamps) { "oneDayAgo@00:00+00:00" } - it "has the timestamp set" do + it 'has the timestamp set' do expect(form.dig("_embedded", "payload", "timestamps")).to eq [timestamps] end end - context "with a value older than 1 day" do + context 'with a value older than 1 day' do let(:timestamps) { "P-2D" } it "returns a validation error" do diff --git a/spec/requests/api/v3/queries/update_query_spec.rb b/spec/requests/api/v3/queries/update_query_spec.rb index 50a9046d26c5..b1b6e0a388d1 100644 --- a/spec/requests/api/v3/queries/update_query_spec.rb +++ b/spec/requests/api/v3/queries/update_query_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "PATCH /api/v3/queries/:id", with_ee: %i[baseline_comparison] do shared_let(:user) { create(:admin) } shared_let(:status) { create(:status) } shared_let(:project) { create(:project) } - let(:timestamps) { [1.week.ago.iso8601, "lastWorkingDay@12:00+00:00", "P0D"] } + let(:timestamps) { [1.week.ago.iso8601, 'lastWorkingDay@12:00+00:00', "P0D"] } let!(:query) do create( @@ -120,16 +120,16 @@ def json patch "/api/v3/queries/#{query.id}", params.to_json end - it "returns 200 (ok)" do + it 'returns 200 (ok)' do expect(last_response.status).to eq(200) end - it "renders the updated query" do + it 'renders the updated query' do expect(json["_type"]).to eq "Query" expect(json["name"]).to eq "Dummy Query" end - it "updates the query correctly" do + it 'updates the query correctly' do query = Query.first expect(query.group_by_column.name).to eq :assigned_to @@ -157,20 +157,20 @@ def json end end - context "without EE", with_ee: false do - it "yields a 422 error given a timestamp older than 1 day" do + context 'without EE', with_ee: false do + it 'yields a 422 error given a timestamp older than 1 day' do expect(last_response.status).to eq 422 expect(json["message"]).to eq "Timestamps contain forbidden values: #{timestamps.first}" end - context "when timestamps are within 1 day" do + context 'when timestamps are within 1 day' do let(:timestamps) { ["oneDayAgo@12:00+00:00"] } - it "returns 200 (ok)" do + it 'returns 200 (ok)' do expect(last_response.status).to eq(200) end - it "updates the query timestamps" do + it 'updates the query timestamps' do expect(Query.first.timestamps).to eq(timestamps.map { |t| Timestamp.new(t) }) end end diff --git a/spec/requests/api/v3/rack_deflater_spec.rb b/spec/requests/api/v3/rack_deflater_spec.rb index f6807c308e6c..35a09ab1ed86 100644 --- a/spec/requests/api/v3/rack_deflater_spec.rb +++ b/spec/requests/api/v3/rack_deflater_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Rack::Deflater do include API::V3::Utilities::PathHelper - let(:text) { "text" } + let(:text) { 'text' } - it "produces an identical eTag whether content is deflated or not" do + it 'produces an identical eTag whether content is deflated or not' do # Using the api_v3_paths.configuration because of the endpoint's simplicity. # It could be any endpoint really. get api_v3_paths.configuration - expect(last_response.headers["Content-Encoding"]).to be_nil + expect(last_response.headers['Content-Encoding']).to be_nil - etag = last_response.headers["Etag"] - content_length = last_response.headers["Content-Length"].to_i + etag = last_response.headers['Etag'] + content_length = last_response.headers['Content-Length'].to_i header "Accept-Encoding", "gzip" get api_v3_paths.configuration - expect(last_response.headers["Etag"]).to eql etag - expect(last_response.headers["Content-Length"].to_i).not_to eql content_length - expect(last_response.headers["Content-Encoding"]).to eql "gzip" + expect(last_response.headers['Etag']).to eql etag + expect(last_response.headers['Content-Length'].to_i).not_to eql content_length + expect(last_response.headers['Content-Encoding']).to eql 'gzip' end end diff --git a/spec/requests/api/v3/relations/relations_api_spec.rb b/spec/requests/api/v3/relations/relations_api_spec.rb index fbb1d59d3801..6447d14f4852 100644 --- a/spec/requests/api/v3/relations/relations_api_spec.rb +++ b/spec/requests/api/v3/relations/relations_api_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "API v3 Relation resource", content_type: :json do +RSpec.describe 'API v3 Relation resource', content_type: :json do include API::V3::Utilities::PathHelper let(:user) { create(:admin) } @@ -70,8 +70,8 @@ end describe "creating a relation" do - shared_examples_for "creates the relation" do - it "creates the relation correctly" do + shared_examples_for 'creates the relation' do + it 'creates the relation correctly' do rel = API::V3::Relations::RelationPayloadRepresenter.new(Relation.new, current_user: user).from_json last_response.body expect(rel.from).to eq from @@ -92,17 +92,17 @@ post api_v3_paths.work_package_relations(from.id), params.to_json end - it "returns 201 (created)" do + it 'returns 201 (created)' do expect(last_response.status).to eq(201) end - it "has created a new relation" do + it 'has created a new relation' do expect(Relation.count).to eq 1 end - it_behaves_like "creates the relation" + it_behaves_like 'creates the relation' - context "when the relation would create a circular scheduling dependency" do + context 'when the relation would create a circular scheduling dependency' do let(:from_child) do create(:work_package, parent: from) end @@ -120,14 +120,14 @@ children_follows_relation end - it "responds with error" do + it 'responds with error' do expect(last_response.status).to be 422 end - it "states the reason for the error" do + it 'states the reason for the error' do expect(last_response.body) - .to be_json_eql(I18n.t(:"activerecord.errors.messages.circular_dependency").to_json) - .at_path("message") + .to be_json_eql(I18n.t(:'activerecord.errors.messages.circular_dependency').to_json) + .at_path('message') end end @@ -158,7 +158,7 @@ relation_b_c end - it "returns 201 (created) and creates the relation" do + it 'returns 201 (created) and creates the relation' do expect(last_response.status) .to eq(201) @@ -174,7 +174,7 @@ end end - context "follows relation within siblings" do + context 'follows relation within siblings' do let(:sibling) do create(:work_package) end @@ -187,8 +187,8 @@ wp.children = [sibling, from, to, other_sibling] end let(:existing_follows) do - create(:relation, relation_type: "follows", from: to, to: sibling) - create(:relation, relation_type: "follows", from: other_sibling, to: from) + create(:relation, relation_type: 'follows', from: to, to: sibling) + create(:relation, relation_type: 'follows', from: other_sibling, to: from) end let(:setup) do @@ -196,10 +196,10 @@ existing_follows end - it_behaves_like "creates the relation" + it_behaves_like 'creates the relation' end - context "follows relation to sibling's child" do + context 'follows relation to sibling\'s child' do let(:sibling) do create(:work_package) end @@ -212,7 +212,7 @@ wp.children = [sibling, from, to] end let(:existing_follows) do - create(:relation, relation_type: "follows", from: to, to: sibling_child) + create(:relation, relation_type: 'follows', from: to, to: sibling_child) end let(:setup) do @@ -220,7 +220,7 @@ existing_follows end - it_behaves_like "creates the relation" + it_behaves_like 'creates the relation' end end @@ -396,20 +396,20 @@ expect(Relation.exists?(relation.id)).to be_falsey end - context "lacking the permission" do + context 'lacking the permission' do let(:permissions) { %i[view_work_packages] } - it "returns 403" do + it 'returns 403' do expect(last_response.status).to eq 403 end - it "leaves the relation" do + it 'leaves the relation' do expect(Relation.exists?(relation.id)).to be_truthy end end end - describe "GET /api/v3/relations?[filter]" do + describe 'GET /api/v3/relations?[filter]' do let(:user) { create(:user) } let(:role) { create(:project_role, permissions: [:view_work_packages]) } let(:member_project_to) do @@ -445,7 +445,7 @@ let(:members) { [member_project_to, member_project_from] } let(:filter) do - [{ involved: { operator: "=", values: [from.id.to_s] } }] + [{ involved: { operator: '=', values: [from.id.to_s] } }] end before do @@ -457,26 +457,26 @@ get "#{api_v3_paths.relations}?filters=#{CGI::escape(JSON::dump(filter))}" end - it "returns 200" do + it 'returns 200' do expect(last_response.status).to be 200 end - it "returns the visible relation (and only the visible one) satisfying the filter" do + it 'returns the visible relation (and only the visible one) satisfying the filter' do expect(last_response.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(last_response.body) - .to be_json_eql("1") - .at_path("count") + .to be_json_eql('1') + .at_path('count') expect(last_response.body) .to be_json_eql(relation.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - describe "GET /api/v3/relations/:id" do + describe 'GET /api/v3/relations/:id' do let(:path) do api_v3_paths.relation(relation.id) end @@ -500,12 +500,12 @@ get path end - context "for a relation with visible work packages" do - it "returns 200" do + context 'for a relation with visible work packages' do + it 'returns 200' do expect(last_response.status).to be 200 end - it "returns the relation" do + it 'returns the relation' do # Creation leads to journal creation which leads to touching the work package which is not # reflected in the value returned from the wp factory. from.reload @@ -520,7 +520,7 @@ end end - context "for a relation with an invisible work package" do + context 'for a relation with an invisible work package' do let(:invisible_relation) do invisible_wp = create(:work_package) @@ -533,7 +533,7 @@ api_v3_paths.relation(invisible_relation.id) end - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(last_response.status).to be 404 end end diff --git a/spec/requests/api/v3/relations/relations_index_spec.rb b/spec/requests/api/v3/relations/relations_index_spec.rb index 02577a61ef16..12e9f94c0983 100644 --- a/spec/requests/api/v3/relations/relations_index_spec.rb +++ b/spec/requests/api/v3/relations/relations_index_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "GET /api/v3/relations" do +RSpec.describe 'GET /api/v3/relations' do let(:user) { create(:admin) } let(:work_package) { create(:work_package) } @@ -47,10 +47,10 @@ def new_work_package end [ - new_relation(from: work_package, to: other_work_package, type: "follows"), - new_relation(from: work_package, to: new_work_package, type: "blocks"), - new_relation(from: new_work_package, to: work_package, type: "follows"), - new_relation(from: new_work_package, to: new_work_package, type: "blocks") + new_relation(from: work_package, to: other_work_package, type: 'follows'), + new_relation(from: work_package, to: new_work_package, type: 'blocks'), + new_relation(from: new_work_package, to: work_package, type: 'follows'), + new_relation(from: new_work_package, to: new_work_package, type: 'blocks') ] end @@ -83,7 +83,7 @@ def filter_relations(name, operator, values) # Initializing the relations takes very long (about 2s) and it's unnecessary # to repeat that step for every example as we are not mutating anything. # This saves about 75% on the runtime (6s vs 24s on this machine) of the spec. - it "work" do + it 'work' do expect(filter_relations("id", "=", [relations[0], relations[2]])) .to contain_exactly(relations[0], relations[2]) expect(filter_relations("id", "!", [relations[0], relations[2]])) diff --git a/spec/requests/api/v3/relations_resource_spec.rb b/spec/requests/api/v3/relations_resource_spec.rb index 83f270804c66..3e7b594696cc 100644 --- a/spec/requests/api/v3/relations_resource_spec.rb +++ b/spec/requests/api/v3/relations_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Relation resource" do +RSpec.describe 'API v3 Relation resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -71,10 +71,10 @@ subject(:response) { last_response } - describe "#get" do + describe '#get' do let(:path) { api_v3_paths.work_package_relations(work_package.id) } - context "when having the view_work_packages permission" do + context 'when having the view_work_packages permission' do let(:permissions) { [:view_work_packages] } before do @@ -84,20 +84,20 @@ get path end - it_behaves_like "API V3 collection response", 1, 1, "Relation" do + it_behaves_like 'API V3 collection response', 1, 1, 'Relation' do let(:elements) { [visible_relation] } end end - context "when not having view_work_packages" do + context 'when not having view_work_packages' do let(:permissions) { [] } before do get path end - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end end end diff --git a/spec/requests/api/v3/render_resource_spec.rb b/spec/requests/api/v3/render_resource_spec.rb index 2a69b3183d81..6ec7459705f1 100644 --- a/spec/requests/api/v3/render_resource_spec.rb +++ b/spec/requests/api/v3/render_resource_spec.rb @@ -26,48 +26,48 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Render resource" do +RSpec.describe 'API v3 Render resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper let(:project) { create(:project, public: false) } let(:work_package) { create(:work_package, project:) } let(:user) { create(:user, member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) } - let(:content_type) { "text/plain, charset=UTF-8" } + let(:content_type) { 'text/plain, charset=UTF-8' } let(:path) { api_v3_paths.render_markup plain:, link: context } let(:context) { nil } before do login_as(user) - post path, params, "CONTENT_TYPE" => content_type + post path, params, 'CONTENT_TYPE' => content_type end - shared_examples_for "valid response" do + shared_examples_for 'valid response' do it { expect(subject.status).to eq(200) } - it { expect(subject.content_type).to eq("text/html") } + it { expect(subject.content_type).to eq('text/html') } it { expect(subject.body).to be_html_eql(text) } end - describe "markdown" do + describe 'markdown' do let(:plain) { false } - describe "#post" do + describe '#post' do subject(:response) { last_response } - describe "response" do - describe "valid" do - context "w/o context" do + describe 'response' do + describe 'valid' do + context 'w/o context' do let(:params) do - "Hello World! This *is* markdown with a " + - "[link](http://community.openproject.org) and ümläutß." + 'Hello World! This *is* markdown with a ' + + '[link](http://community.openproject.org) and ümläutß.' end - it_behaves_like "valid response" do + it_behaves_like 'valid response' do let(:text) do <<~HTML

      @@ -82,7 +82,7 @@ end end - context "with context" do + context 'with context' do let(:params) { "Hello World! Have a look at ##{work_package.id}" } let(:id) { work_package.id } let(:href) { "/work_packages/#{id}" } @@ -97,70 +97,70 @@ HTML end - context "with work package context" do + context 'with work package context' do let(:context) { api_v3_paths.work_package work_package.id } - it_behaves_like "valid response" + it_behaves_like 'valid response' end - context "with project context" do + context 'with project context' do let(:context) { "/api/v3/projects/#{work_package.project_id}" } - it_behaves_like "valid response" + it_behaves_like 'valid response' end end end - describe "invalid" do - context "content type" do - let(:content_type) { "application/json" } + describe 'invalid' do + context 'content type' do + let(:content_type) { 'application/json' } let(:params) do - { "text" => "Hello World! Have a look at ##{work_package.id}" }.to_json + { 'text' => "Hello World! Have a look at ##{work_package.id}" }.to_json end - it_behaves_like "unsupported content type", - I18n.t("api_v3.errors.invalid_content_type", - content_type: "text/plain", - actual: "application/json") + it_behaves_like 'unsupported content type', + I18n.t('api_v3.errors.invalid_content_type', + content_type: 'text/plain', + actual: 'application/json') end - context "with context" do - let(:params) { "" } + context 'with context' do + let(:params) { '' } - describe "work package does not exist" do + describe 'work package does not exist' do let(:context) { api_v3_paths.work_package -1 } - it_behaves_like "invalid render context", - I18n.t("api_v3.errors.render.context_object_not_found") + it_behaves_like 'invalid render context', + I18n.t('api_v3.errors.render.context_object_not_found') end - describe "work package not visible" do + describe 'work package not visible' do let(:invisible_work_package) { create(:work_package) } let(:context) { api_v3_paths.work_package invisible_work_package.id } - it_behaves_like "invalid render context", - I18n.t("api_v3.errors.render.context_object_not_found") + it_behaves_like 'invalid render context', + I18n.t('api_v3.errors.render.context_object_not_found') end - describe "context does not exist" do + describe 'context does not exist' do let(:context) { api_v3_paths.root } - it_behaves_like "invalid render context", - I18n.t("api_v3.errors.render.context_not_parsable") + it_behaves_like 'invalid render context', + I18n.t('api_v3.errors.render.context_not_parsable') end - describe "unsupported context resource found" do + describe 'unsupported context resource found' do let(:context) { api_v3_paths.activity 2 } - it_behaves_like "invalid render context", - I18n.t("api_v3.errors.render.unsupported_context") + it_behaves_like 'invalid render context', + I18n.t('api_v3.errors.render.unsupported_context') end - describe "unsupported context version found" do - let(:context) { "/api/v4/work_packages/2" } + describe 'unsupported context version found' do + let(:context) { '/api/v4/work_packages/2' } - it_behaves_like "invalid render context", - I18n.t("api_v3.errors.render.unsupported_context") + it_behaves_like 'invalid render context', + I18n.t('api_v3.errors.render.unsupported_context') end end end @@ -168,17 +168,17 @@ end end - describe "plain" do - describe "#post" do + describe 'plain' do + describe '#post' do let(:plain) { true } subject(:response) { last_response } - describe "response" do - describe "valid" do + describe 'response' do + describe 'valid' do let(:params) { "Hello *World*! Have a look at #1\n\nwith two lines." } - it_behaves_like "valid response" do + it_behaves_like 'valid response' do let(:text) do "

      Hello *World*! Have a look at #1

      \n\n

      with two lines.

      " end diff --git a/spec/requests/api/v3/repositories/revisions_by_work_package_resource_spec.rb b/spec/requests/api/v3/repositories/revisions_by_work_package_resource_spec.rb index 0b80a2689030..abc2edca814c 100644 --- a/spec/requests/api/v3/repositories/revisions_by_work_package_resource_spec.rb +++ b/spec/requests/api/v3/repositories/revisions_by_work_package_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Revisions by work package resource" do +RSpec.describe 'API v3 Revisions by work package resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper include FileHelpers @@ -50,7 +50,7 @@ allow(User).to receive(:current).and_return current_user end - describe "#get" do + describe '#get' do let(:get_path) { api_v3_paths.work_package_revisions work_package.id } before do @@ -58,13 +58,13 @@ get get_path end - it "responds with 200" do + it 'responds with 200' do expect(subject.status).to eq(200) end - it_behaves_like "API V3 collection response", 0, 0, "Revision" + it_behaves_like 'API V3 collection response', 0, 0, 'Revision' - context "with existing revisions" do + context 'with existing revisions' do let(:revisions) do build_list(:changeset, 5, @@ -72,24 +72,24 @@ repository:) end - it_behaves_like "API V3 collection response", 5, 5, "Revision" + it_behaves_like 'API V3 collection response', 5, 5, 'Revision' - context "user unauthorized to view revisions" do + context 'user unauthorized to view revisions' do let(:permissions) { [:view_work_packages] } - it_behaves_like "API V3 collection response", 0, 0, "Revision" + it_behaves_like 'API V3 collection response', 0, 0, 'Revision' end end - context "user unauthorized to view work package" do + context 'user unauthorized to view work package' do let(:current_user) { create(:user) } - it "responds with 404" do + it 'responds with 404' do expect(subject.status).to eq(404) end end - describe "revisions linked from another project" do + describe 'revisions linked from another project' do let(:subproject) { create(:project, parent: project) } let(:repository) { create(:repository_subversion, project: subproject) } let!(:revisions) do @@ -99,16 +99,16 @@ repository:) end - context "with permissions in subproject" do + context 'with permissions in subproject' do let(:current_user) do create(:user, member_with_roles: { project => role, subproject => role }) end - it_behaves_like "API V3 collection response", 2, 2, "Revision" + it_behaves_like 'API V3 collection response', 2, 2, 'Revision' end - context "with no permission in subproject" do - it_behaves_like "API V3 collection response", 0, 0, "Revision" + context 'with no permission in subproject' do + it_behaves_like 'API V3 collection response', 0, 0, 'Revision' end end end diff --git a/spec/requests/api/v3/repositories/revisions_resource_spec.rb b/spec/requests/api/v3/repositories/revisions_resource_spec.rb index e060d753a6c5..a81a828fa8f5 100644 --- a/spec/requests/api/v3/repositories/revisions_resource_spec.rb +++ b/spec/requests/api/v3/repositories/revisions_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Revisions resource" do +RSpec.describe 'API v3 Revisions resource' do include Rack::Test::Methods include Capybara::RSpecMatchers include API::V3::Utilities::PathHelper @@ -37,14 +37,14 @@ let(:revision) do create(:changeset, repository:, - comments: "Some commit message", - committer: "foo bar ") + comments: 'Some commit message', + committer: 'foo bar ') end let(:repository) do create(:repository_subversion, project:) end let(:project) do - create(:project, identifier: "test_project", public: false) + create(:project, identifier: 'test_project', public: false) end let(:role) do create(:project_role, @@ -56,41 +56,41 @@ let(:unauthorized_user) { create(:user) } - describe "#get" do + describe '#get' do let(:get_path) { api_v3_paths.revision revision.id } - context "when acting as a user with permission to view revisions" do + context 'when acting as a user with permission to view revisions' do before do allow(User).to receive(:current).and_return current_user get get_path end - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end - describe "response body" do + describe 'response body' do subject(:response) { last_response.body } - it "responds with revision in HAL+JSON format" do - expect(subject).to be_json_eql(revision.id.to_json).at_path("id") + it 'responds with revision in HAL+JSON format' do + expect(subject).to be_json_eql(revision.id.to_json).at_path('id') end end - context "requesting nonexistent revision" do + context 'requesting nonexistent revision' do let(:get_path) { api_v3_paths.revision 909090 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "when acting as an user without permission to view work package" do + context 'when acting as an user without permission to view work package' do before do allow(User).to receive(:current).and_return unauthorized_user get get_path end - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/role_resource_spec.rb b/spec/requests/api/v3/role_resource_spec.rb index 4685dafd569d..245522d10349 100644 --- a/spec/requests/api/v3/role_resource_spec.rb +++ b/spec/requests/api/v3/role_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 roles resource" do +RSpec.describe 'API v3 roles resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -45,7 +45,7 @@ subject(:response) { last_response } - describe "GET api/v3/roles" do + describe 'GET api/v3/roles' do let(:get_path) { api_v3_paths.roles } let(:response) { last_response } let(:roles) { [role] } @@ -58,16 +58,16 @@ get get_path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to be(200) end - it_behaves_like "API V3 collection response", 1, 1, "Role" + it_behaves_like 'API V3 collection response', 1, 1, 'Role' - context "filtering by assignable" do + context 'filtering by assignable' do let(:filters) do - [{ grantable: { operator: "=", values: ["t"] } }] + [{ grantable: { operator: '=', values: ['t'] } }] end let(:non_member_role) { ProjectRole.non_member } @@ -75,22 +75,22 @@ let(:get_path) { api_v3_paths.path_for(:roles, filters:) } - it "contains only the filtered member in the response" do + it 'contains only the filtered member in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(role.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "filtering by unit" do + context 'filtering by unit' do let(:filters) do - [{ "unit" => { - "operator" => "=", - "values" => ["project"] + [{ 'unit' => { + 'operator' => '=', + 'values' => ['project'] } }] end @@ -100,28 +100,28 @@ let(:get_path) { api_v3_paths.path_for(:roles, filters:) } - it "contains only the filtered member in the response" do + it 'contains only the filtered member in the response' do expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(role.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:permissions) { [] } - it "returns 403" do + it 'returns 403' do expect(subject.status) .to be(403) end end end - describe "GET /api/v3/roles/:id" do + describe 'GET /api/v3/roles/:id' do let(:path) { api_v3_paths.role(role.id) } let(:roles) { [role] } @@ -134,34 +134,34 @@ get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the member" do + it 'returns the member' do expect(subject.body) - .to be_json_eql("Role".to_json) - .at_path("_type") + .to be_json_eql('Role'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(role.id.to_json) - .at_path("id") + .at_path('id') end - context "if querying an non existent" do + context 'if querying an non existent' do let(:path) { api_v3_paths.role(0) } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end end - context "without the necessary permissions" do + context 'without the necessary permissions' do let(:permissions) { [] } - it "returns 403" do + it 'returns 403' do expect(subject.status) .to be(403) end diff --git a/spec/requests/api/v3/root_resource_spec.rb b/spec/requests/api/v3/root_resource_spec.rb index d7f6e3ed9aa1..255b4698a376 100644 --- a/spec/requests/api/v3/root_resource_spec.rb +++ b/spec/requests/api/v3/root_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Root resource" do +RSpec.describe 'API v3 Root resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -39,51 +39,51 @@ let(:role) { create(:project_role, permissions: []) } let(:project) { create(:project, public: false) } - describe "#get" do + describe '#get' do let(:response) { last_response } let(:get_path) { api_v3_paths.root } subject { response.body } - context "anonymous user" do + context 'anonymous user' do before do get get_path end - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "error response", + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'error response', 401, - "Unauthenticated", - I18n.t("api_v3.errors.code_401") + 'Unauthenticated', + I18n.t('api_v3.errors.code_401') end - context "when not login_required", with_settings: { login_required: false } do - it "responds with 200", :aggregate_failures do + context 'when not login_required', with_settings: { login_required: false } do + it 'responds with 200', :aggregate_failures do expect(response.status).to eq(200) - expect(subject).to have_json_path("instanceName") + expect(subject).to have_json_path('instanceName') end end end - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - it "responds with 200" do + it 'responds with 200' do expect(response.status).to eq(200) end - it "responds with a root representer" do - expect(subject).to have_json_path("instanceName") + it 'responds with a root representer' do + expect(subject).to have_json_path('instanceName') end - context "without the X-requested-with header", :skip_xhr_header do - it "returns OK because GET requests are allowed" do + context 'without the X-requested-with header', :skip_xhr_header do + it 'returns OK because GET requests are allowed' do expect(response.status).to eq(200) - expect(subject).to have_json_path("instanceName") + expect(subject).to have_json_path('instanceName') end end end diff --git a/spec/requests/api/v3/status_resource_spec.rb b/spec/requests/api/v3/status_resource_spec.rb index b45371050d17..5893649a2c3e 100644 --- a/spec/requests/api/v3/status_resource_spec.rb +++ b/spec/requests/api/v3/status_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Status resource" do +RSpec.describe 'API v3 Status resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -41,66 +41,66 @@ let!(:statuses) { create_list(:status, 4) } - describe "statuses" do - describe "#get" do + describe 'statuses' do + describe '#get' do let(:get_path) { api_v3_paths.statuses } subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - it_behaves_like "API V3 collection response", 4, 4, "Status" + it_behaves_like 'API V3 collection response', 4, 4, 'Status' end - context "not logged in user" do + context 'not logged in user' do before do get get_path end - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end end - describe "statuses/:id" do - describe "#get" do + describe 'statuses/:id' do + describe '#get' do let(:status) { statuses.first } let(:get_path) { api_v3_paths.status status.id } subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return(current_user) get get_path end - context "valid status id" do + context 'valid status id' do it { expect(response.status).to eq(200) } end - context "invalid status id" do - let(:get_path) { api_v3_paths.status "bogus" } + context 'invalid status id' do + let(:get_path) { api_v3_paths.status 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } - let(:type) { "Status" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + let(:type) { 'Status' } end end end - context "not logged in user" do + context 'not logged in user' do before do get get_path end - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end end diff --git a/spec/requests/api/v3/string_objects_resource_spec.rb b/spec/requests/api/v3/string_objects_resource_spec.rb index 6799833116bc..32127c2af5d5 100644 --- a/spec/requests/api/v3/string_objects_resource_spec.rb +++ b/spec/requests/api/v3/string_objects_resource_spec.rb @@ -26,35 +26,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 String Objects resource" do +RSpec.describe 'API v3 String Objects resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper - describe "string_objects" do + describe 'string_objects' do subject(:response) { last_response } - let(:path) { api_v3_paths.string_object "foo bar" } + let(:path) { api_v3_paths.string_object 'foo bar' } before do get path end - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it "return 410 GONE" do + context 'when not login_required', with_settings: { login_required: false } do + it 'return 410 GONE' do expect(subject.status).to be(410) end - context "nil string" do - let(:path) { "/api/v3/string_objects?value" } + context 'nil string' do + let(:path) { '/api/v3/string_objects?value' } - it "return 410 GONE" do + it 'return 410 GONE' do expect(subject.status).to be(410) end end diff --git a/spec/requests/api/v3/support/api_helper.rb b/spec/requests/api/v3/support/api_helper.rb index a942810ec8b4..ebeee4fc722e 100644 --- a/spec/requests/api/v3/support/api_helper.rb +++ b/spec/requests/api/v3/support/api_helper.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "safeguarded API" do +RSpec.shared_examples_for 'safeguarded API' do it { expect(last_response.status).to eq(404) } end -RSpec.shared_examples_for "valid activity request" do +RSpec.shared_examples_for 'valid activity request' do shared_let(:admin) { create(:admin) } let(:status_code) { 200 } @@ -40,16 +40,16 @@ it { expect(last_response.status).to eq(status_code) } - describe "response body" do + describe 'response body' do subject { last_response.body } - it { is_expected.to be_json_eql("Activity::Comment".to_json).at_path("_type") } + it { is_expected.to be_json_eql('Activity::Comment'.to_json).at_path('_type') } - it { is_expected.to be_json_eql(comment.to_json).at_path("comment/raw") } + it { is_expected.to be_json_eql(comment.to_json).at_path('comment/raw') } end end -RSpec.shared_examples_for "invalid activity request" do +RSpec.shared_examples_for 'invalid activity request' do shared_let(:admin) { create(:admin) } before do diff --git a/spec/requests/api/v3/support/api_v3_collection_response.rb b/spec/requests/api/v3/support/api_v3_collection_response.rb index a3bde3e9c36a..9f795fe15d8b 100644 --- a/spec/requests/api/v3/support/api_v3_collection_response.rb +++ b/spec/requests/api/v3/support/api_v3_collection_response.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "API V3 collection response" do |total, count, element_type, collection_type = "Collection"| +RSpec.shared_examples_for 'API V3 collection response' do |total, count, element_type, collection_type = 'Collection'| subject { last_response.body } # If an array of elements is provided, those elements are expected @@ -57,7 +57,7 @@ # Allow overriding the expect HTTP status code let(:expected_status_code) { 200 } - it "returns a collection successfully" do + it 'returns a collection successfully' do aggregate_failures do expect(last_response.status).to eq(expected_status_code) errors = JSON.parse(subject).dig("_embedded", "errors")&.map { _1["message"] } @@ -65,15 +65,15 @@ end end - it "contains all elements" do + it 'contains all elements' do aggregate_failures do - expect(subject).to be_json_eql(collection_type.to_json).at_path("_type") - expect(subject).to be_json_eql(count_number.to_json).at_path("count") - expect(subject).to be_json_eql(total_number.to_json).at_path("total") - expect(subject).to have_json_size(count_number).at_path("_embedded/elements") + expect(subject).to be_json_eql(collection_type.to_json).at_path('_type') + expect(subject).to be_json_eql(count_number.to_json).at_path('count') + expect(subject).to be_json_eql(total_number.to_json).at_path('total') + expect(subject).to have_json_size(count_number).at_path('_embedded/elements') if element_type && count_number > 0 - expect(subject).to be_json_eql(element_type.to_json).at_path("_embedded/elements/0/_type") + expect(subject).to be_json_eql(element_type.to_json).at_path('_embedded/elements/0/_type') end elements&.each_with_index do |element, index| diff --git a/spec/requests/api/v3/support/authorization.rb b/spec/requests/api/v3/support/authorization.rb index 1c30bf12f6e7..d26a70865492 100644 --- a/spec/requests/api/v3/support/authorization.rb +++ b/spec/requests/api/v3/support/authorization.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "handling anonymous user" do - context "anonymous user" do +RSpec.shared_examples_for 'handling anonymous user' do + context 'anonymous user' do before do allow(User).to receive(:current).and_return(User.anonymous) end - context "when access for anonymous user is not allowed" do + context 'when access for anonymous user is not allowed' do before do allow(Setting).to receive(:login_required?).and_return(true) get path end - it_behaves_like "unauthenticated access" + it_behaves_like 'unauthenticated access' end end end diff --git a/spec/requests/api/v3/support/response_examples.rb b/spec/requests/api/v3/support/response_examples.rb index 2974b634ec78..a484d971f802 100644 --- a/spec/requests/api/v3/support/response_examples.rb +++ b/spec/requests/api/v3/support/response_examples.rb @@ -26,39 +26,39 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples_for "successful response" do |code = 200| +RSpec.shared_examples_for 'successful response' do |code = 200| it "has the status code #{code}" do expect(last_response.status).to eq(code) end - it "has a HAL+JSON Content-Type" do - expected_content_type = "application/hal+json; charset=utf-8" - expect(last_response.headers).to include "Content-Type" - expect(last_response.headers["Content-Type"].downcase).to eql expected_content_type + it 'has a HAL+JSON Content-Type' do + expected_content_type = 'application/hal+json; charset=utf-8' + expect(last_response.headers).to include 'Content-Type' + expect(last_response.headers['Content-Type'].downcase).to eql expected_content_type end end -RSpec.shared_examples_for "successful no content response" do |code = 204| +RSpec.shared_examples_for 'successful no content response' do |code = 204| it "has the status code #{code}" do expect(last_response.status).to eq(code) end end -RSpec.shared_examples_for "redirect response" do |code = 303| - let(:location) { "" } +RSpec.shared_examples_for 'redirect response' do |code = 303| + let(:location) { '' } it "has the status code #{code}" do expect(last_response.status).to eq(code) end - it "redirects to expected location" do - expect(last_response.headers["Location"]).to eq(location) + it 'redirects to expected location' do + expect(last_response.headers['Location']).to eq(location) end end -RSpec.shared_examples_for "error response" do |code, id, provided_message = nil| +RSpec.shared_examples_for 'error response' do |code, id, provided_message = nil| let(:expected_message) do provided_message || message end @@ -67,194 +67,194 @@ expect(last_response.status).to eq(code) end - it "has a HAL+JSON Content-Type" do - expected_content_type = "application/hal+json; charset=utf-8" - expect(last_response.headers).to include "Content-Type" - expect(last_response.headers["Content-Type"].downcase).to eql expected_content_type + it 'has a HAL+JSON Content-Type' do + expected_content_type = 'application/hal+json; charset=utf-8' + expect(last_response.headers).to include 'Content-Type' + expect(last_response.headers['Content-Type'].downcase).to eql expected_content_type end - describe "response body" do + describe 'response body' do subject { JSON.parse(last_response.body) } - describe "errorIdentifier" do - it { expect(subject["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:#{id}") } + describe 'errorIdentifier' do + it { expect(subject['errorIdentifier']).to eq("urn:openproject-org:api:v3:errors:#{id}") } end - describe "message" do - it { expect(subject["message"]).to include(expected_message) } + describe 'message' do + it { expect(subject['message']).to include(expected_message) } - it "includes punctuation" do - expect(subject["message"]).to match(/(\.|\?|!)\z/) + it 'includes punctuation' do + expect(subject['message']).to match(/(\.|\?|!)\z/) end end end end -RSpec.shared_examples_for "invalid render context" do |message| - it_behaves_like "error response", +RSpec.shared_examples_for 'invalid render context' do |message| + it_behaves_like 'error response', 400, - "InvalidRenderContext", + 'InvalidRenderContext', message end -RSpec.shared_examples_for "invalid request body" do |message| - it_behaves_like "error response", +RSpec.shared_examples_for 'invalid request body' do |message| + it_behaves_like 'error response', 400, - "InvalidRequestBody", + 'InvalidRequestBody', message end -RSpec.shared_examples_for "invalid resource link" do |message| - it_behaves_like "error response", +RSpec.shared_examples_for 'invalid resource link' do |message| + it_behaves_like 'error response', 422, - "ResourceTypeMismatch", + 'ResourceTypeMismatch', message end -RSpec.shared_examples_for "unsupported content type" do |message| - it_behaves_like "error response", +RSpec.shared_examples_for 'unsupported content type' do |message| + it_behaves_like 'error response', 415, - "TypeNotSupported", + 'TypeNotSupported', message end -RSpec.shared_examples_for "parse error" do |details| - it_behaves_like "invalid request body", - I18n.t("api_v3.errors.invalid_json") +RSpec.shared_examples_for 'parse error' do |details| + it_behaves_like 'invalid request body', + I18n.t('api_v3.errors.invalid_json') - it "shows the given details" do + it 'shows the given details' do if details expect(last_response.body).to be_json_eql(details.to_json) - .at_path("_embedded/details/parseError") + .at_path('_embedded/details/parseError') end end end -RSpec.shared_examples_for "invalid filters" do - it_behaves_like "error response", +RSpec.shared_examples_for 'invalid filters' do + it_behaves_like 'error response', 400, - "InvalidQuery", - I18n.t("api_v3.errors.missing_or_malformed_parameter", parameter: "filters") + 'InvalidQuery', + I18n.t('api_v3.errors.missing_or_malformed_parameter', parameter: 'filters') end -RSpec.shared_examples_for "unauthenticated access" do - it_behaves_like "error response", +RSpec.shared_examples_for 'unauthenticated access' do + it_behaves_like 'error response', 401, - "Unauthenticated", - I18n.t("api_v3.errors.code_401") + 'Unauthenticated', + I18n.t('api_v3.errors.code_401') end -RSpec.shared_examples_for "unauthorized access" do - it_behaves_like "error response", +RSpec.shared_examples_for 'unauthorized access' do + it_behaves_like 'error response', 403, - "MissingPermission", - I18n.t("api_v3.errors.code_403") + 'MissingPermission', + I18n.t('api_v3.errors.code_403') end -RSpec.shared_examples_for "not found" do |message = I18n.t("api_v3.errors.code_404")| - include_examples "error response", +RSpec.shared_examples_for 'not found' do |message = I18n.t('api_v3.errors.code_404')| + include_examples 'error response', 404, - "NotFound", + 'NotFound', message end -RSpec.shared_examples_for "forbidden response based on login_required" do - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" +RSpec.shared_examples_for 'forbidden response based on login_required' do + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it_behaves_like "unauthorized access" + context 'when not login_required', with_settings: { login_required: false } do + it_behaves_like 'unauthorized access' end end -RSpec.shared_examples_for "not found response based on login_required" do |message = I18n.t("api_v3.errors.code_404")| - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" +RSpec.shared_examples_for 'not found response based on login_required' do |message = I18n.t('api_v3.errors.code_404')| + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it_behaves_like "not found", message + context 'when not login_required', with_settings: { login_required: false } do + it_behaves_like 'not found', message end end -RSpec.shared_examples_for "param validation error" do +RSpec.shared_examples_for 'param validation error' do subject { JSON.parse(last_response.body) } - it "results in a validation error" do + it 'results in a validation error' do expect(last_response.status).to eq(400) - expect(subject["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:BadRequest") - expect(subject["message"]).to match /Bad request: .+? is invalid/ + expect(subject['errorIdentifier']).to eq("urn:openproject-org:api:v3:errors:BadRequest") + expect(subject['message']).to match /Bad request: .+? is invalid/ end end -RSpec.shared_examples_for "update conflict" do - it_behaves_like "error response", +RSpec.shared_examples_for 'update conflict' do + it_behaves_like 'error response', 409, - "UpdateConflict", - I18n.t("api_v3.errors.code_409") + 'UpdateConflict', + I18n.t('api_v3.errors.code_409') end -RSpec.shared_examples_for "constraint violation" do - it_behaves_like "error response", +RSpec.shared_examples_for 'constraint violation' do + it_behaves_like 'error response', 422, - "PropertyConstraintViolation" + 'PropertyConstraintViolation' end -RSpec.shared_examples_for "format error" do |message| - it_behaves_like "error response", +RSpec.shared_examples_for 'format error' do |message| + it_behaves_like 'error response', 422, - "PropertyFormatError", + 'PropertyFormatError', message end -RSpec.shared_examples_for "missing property" do |message| - it_behaves_like "error response", +RSpec.shared_examples_for 'missing property' do |message| + it_behaves_like 'error response', 422, - "PropertyMissingError", + 'PropertyMissingError', message end -RSpec.shared_examples_for "read-only violation" do |attribute, model, attribute_message = nil| - describe "details" do - subject { JSON.parse(last_response.body)["_embedded"]["details"] } +RSpec.shared_examples_for 'read-only violation' do |attribute, model, attribute_message = nil| + describe 'details' do + subject { JSON.parse(last_response.body)['_embedded']['details'] } - it { expect(subject["attribute"]).to eq(attribute) } + it { expect(subject['attribute']).to eq(attribute) } end message = [ attribute_message || model.human_attribute_name(attribute), - I18n.t("activerecord.errors.messages.error_readonly") + I18n.t('activerecord.errors.messages.error_readonly') ].join(" ") - it_behaves_like "error response", + it_behaves_like 'error response', 422, - "PropertyIsReadOnly", + 'PropertyIsReadOnly', message end -RSpec.shared_examples_for "multiple errors" do |code, _message| - it_behaves_like "error response", +RSpec.shared_examples_for 'multiple errors' do |code, _message| + it_behaves_like 'error response', code, - "MultipleErrors", - I18n.t("api_v3.errors.multiple_errors") + 'MultipleErrors', + I18n.t('api_v3.errors.multiple_errors') end -RSpec.shared_examples_for "multiple errors of the same type" do |error_count, id| - subject { JSON.parse(last_response.body)["_embedded"]["errors"] } +RSpec.shared_examples_for 'multiple errors of the same type' do |error_count, id| + subject { JSON.parse(last_response.body)['_embedded']['errors'] } it { expect(subject.count).to eq(error_count) } - it "has child errors of expected type" do + it 'has child errors of expected type' do subject.each do |error| - expect(error["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:#{id}") + expect(error['errorIdentifier']).to eq("urn:openproject-org:api:v3:errors:#{id}") end end end -RSpec.shared_examples_for "multiple errors of the same type with details" do |expected_details, expected_detail_values| - let(:errors) { JSON.parse(last_response.body)["_embedded"]["errors"] } +RSpec.shared_examples_for 'multiple errors of the same type with details' do |expected_details, expected_detail_values| + let(:errors) { JSON.parse(last_response.body)['_embedded']['errors'] } let(:details) do - errors.each_with_object([]) { |error, l| l << error["_embedded"]["details"] }.compact + errors.each_with_object([]) { |error, l| l << error['_embedded']['details'] }.compact end subject do @@ -265,17 +265,17 @@ it { expect(subject.keys).to match_array(Array(expected_details)) } - it "contains all expected values" do + it 'contains all expected values' do Array(expected_details).each do |detail| expect(subject[detail]).to match_array(Array(expected_detail_values[detail])) end end end -RSpec.shared_examples_for "multiple errors of the same type with messages" do - let(:errors) { JSON.parse(last_response.body)["_embedded"]["errors"] } +RSpec.shared_examples_for 'multiple errors of the same type with messages' do + let(:errors) { JSON.parse(last_response.body)['_embedded']['errors'] } let(:actual_messages) do - errors.each_with_object([]) { |error, l| l << error["message"] }.compact + errors.each_with_object([]) { |error, l| l << error['message'] }.compact end before do diff --git a/spec/requests/api/v3/types/type_resource_spec.rb b/spec/requests/api/v3/types/type_resource_spec.rb index 0a0da5dff3fd..b98ab24b08db 100644 --- a/spec/requests/api/v3/types/type_resource_spec.rb +++ b/spec/requests/api/v3/types/type_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Type resource" do +RSpec.describe 'API v3 Type resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -41,66 +41,66 @@ let!(:types) { create_list(:type, 4) } - describe "types" do - describe "#get" do + describe 'types' do + describe '#get' do let(:get_path) { api_v3_paths.types } subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - it_behaves_like "API V3 collection response", 4, 4, "Type" + it_behaves_like 'API V3 collection response', 4, 4, 'Type' end - context "not logged in user" do + context 'not logged in user' do before do get get_path end - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end end - describe "types/:id" do - describe "#get" do + describe 'types/:id' do + describe '#get' do let(:type) { types.first } let(:get_path) { api_v3_paths.type type.id } subject(:response) { last_response } - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return(current_user) get get_path end - context "valid type id" do + context 'valid type id' do it { expect(response.status).to eq(200) } end - context "invalid type id" do - let(:get_path) { api_v3_paths.type "bogus" } + context 'invalid type id' do + let(:get_path) { api_v3_paths.type 'bogus' } - it_behaves_like "param validation error" do - let(:id) { "bogus" } - let(:type) { "Type" } + it_behaves_like 'param validation error' do + let(:id) { 'bogus' } + let(:type) { 'Type' } end end end - context "not logged in user" do + context 'not logged in user' do before do get get_path end - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end end diff --git a/spec/requests/api/v3/types/types_by_project_resource_spec.rb b/spec/requests/api/v3/types/types_by_project_resource_spec.rb index d18fd4dbdc1e..c0cedfa2a5cd 100644 --- a/spec/requests/api/v3/types/types_by_project_resource_spec.rb +++ b/spec/requests/api/v3/types/types_by_project_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "/api/v3/projects/:id/types" do +RSpec.describe '/api/v3/projects/:id/types' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -43,7 +43,7 @@ let!(:irrelevant_types) { create_list(:type, 4) } let!(:expected_types) { create_list(:type, 4) } - describe "#get" do + describe '#get' do let(:get_path) { api_v3_paths.types_by_project requested_project.id } subject(:response) { last_response } @@ -52,44 +52,44 @@ project.types << expected_types end - context "logged in user" do + context 'logged in user' do before do allow(User).to receive(:current).and_return current_user get get_path end - it_behaves_like "API V3 collection response", 4, 4, "Type" + it_behaves_like 'API V3 collection response', 4, 4, 'Type' - it "only contains expected types" do - actual_types = JSON.parse(subject.body)["_embedded"]["elements"] - actual_type_ids = actual_types.map { |hash| hash["id"] } + it 'only contains expected types' do + actual_types = JSON.parse(subject.body)['_embedded']['elements'] + actual_type_ids = actual_types.map { |hash| hash['id'] } expected_type_ids = expected_types.map(&:id) expect(actual_type_ids).to match_array expected_type_ids end # N.B. this test depends on order, while this is not strictly necessary - it "only contains expected types" do + it 'only contains expected types' do 4.times do |i| expected_id = expected_types[i].id.to_json expect(subject.body).to be_json_eql(expected_id).at_path("_embedded/elements/#{i}/id") end end - context "in a foreign project" do + context 'in a foreign project' do let(:requested_project) { create(:project, public: false) } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "not logged in user" do + context 'not logged in user' do before do get get_path end - it_behaves_like "not found response based on login_required" + it_behaves_like 'not found response based on login_required' end end end diff --git a/spec/requests/api/v3/user/create_form_resource_spec.rb b/spec/requests/api/v3/user/create_form_resource_spec.rb index a9cd83532176..9a9a7efca817 100644 --- a/spec/requests/api/v3/user/create_form_resource_spec.rb +++ b/spec/requests/api/v3/user/create_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Users::CreateFormAPI, content_type: :json do include Rack::Test::Methods @@ -43,90 +43,90 @@ subject(:response) { last_response } - context "with authorized user" do + context 'with authorized user' do shared_let(:current_user) { create(:user, global_permissions: [:create_user]) } - describe "empty params" do + describe 'empty params' do let(:payload) do {} end # rubocop:disable RSpec/ExampleLength - it "returns a payload with validation errors", + it 'returns a payload with validation errors', :aggregate_failures, with_settings: { default_language: :es } do expect(response.status).to eq(200) - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') expect(body) - .to be_json_eql("".to_json) - .at_path("_embedded/payload/login") + .to be_json_eql(''.to_json) + .at_path('_embedded/payload/login') expect(body) - .to be_json_eql("".to_json) - .at_path("_embedded/payload/email") + .to be_json_eql(''.to_json) + .at_path('_embedded/payload/email') expect(body) - .to be_json_eql("es".to_json) - .at_path("_embedded/payload/language") + .to be_json_eql('es'.to_json) + .at_path('_embedded/payload/language') expect(body) - .to be_json_eql("active".to_json) - .at_path("_embedded/payload/status") + .to be_json_eql('active'.to_json) + .at_path('_embedded/payload/status') expect(body) .to have_json_size(5) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') expect(body) - .to have_json_path("_embedded/validationErrors/password") + .to have_json_path('_embedded/validationErrors/password') expect(body) - .to have_json_path("_embedded/validationErrors/login") + .to have_json_path('_embedded/validationErrors/login') expect(body) - .to have_json_path("_embedded/validationErrors/email") + .to have_json_path('_embedded/validationErrors/email') expect(body) - .to have_json_path("_embedded/validationErrors/firstName") + .to have_json_path('_embedded/validationErrors/firstName') expect(body) - .to have_json_path("_embedded/validationErrors/lastName") + .to have_json_path('_embedded/validationErrors/lastName') expect(body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end # rubocop:enable RSpec/ExampleLength end - describe "inviting a user" do + describe 'inviting a user' do let(:payload) do { - email: "foo@example.com", - status: "invited" + email: 'foo@example.com', + status: 'invited' } end - it "returns a valid payload", :aggregate_failures do + it 'returns a valid payload', :aggregate_failures do expect(response.status).to eq(200) - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') expect(body) - .to be_json_eql("invited".to_json) - .at_path("_embedded/payload/status") + .to be_json_eql('invited'.to_json) + .at_path('_embedded/payload/status') expect(body) - .to be_json_eql("foo@example.com".to_json) - .at_path("_embedded/payload/email") + .to be_json_eql('foo@example.com'.to_json) + .at_path('_embedded/payload/email') expect(body) - .to be_json_eql("foo".to_json) - .at_path("_embedded/payload/firstName") + .to be_json_eql('foo'.to_json) + .at_path('_embedded/payload/firstName') expect(body) - .to be_json_eql("@example.com".to_json) - .at_path("_embedded/payload/lastName") + .to be_json_eql('@example.com'.to_json) + .at_path('_embedded/payload/lastName') expect(body) .to have_json_size(0) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') end end - describe "with custom fields" do + describe 'with custom fields' do let!(:custom_field) do create(:user_custom_field, :string) end @@ -137,8 +137,8 @@ let(:payload) do { - email: "cfuser@example.com", - status: "invited", + email: 'cfuser@example.com', + status: 'invited', custom_field.attribute_name(:camel_case) => "A custom value", _links: { list_custom_field.attribute_name(:camel_case) => { @@ -148,28 +148,28 @@ } end - it "returns a valid form response" do + it 'returns a valid form response' do expect(response.status).to eq(200) - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') expect(body) - .to be_json_eql("invited".to_json) - .at_path("_embedded/payload/status") + .to be_json_eql('invited'.to_json) + .at_path('_embedded/payload/status') expect(body) - .to be_json_eql("cfuser@example.com".to_json) - .at_path("_embedded/payload/email") + .to be_json_eql('cfuser@example.com'.to_json) + .at_path('_embedded/payload/email') expect(body) - .to be_json_eql("cfuser".to_json) - .at_path("_embedded/payload/firstName") + .to be_json_eql('cfuser'.to_json) + .at_path('_embedded/payload/firstName') expect(body) - .to be_json_eql("@example.com".to_json) - .at_path("_embedded/payload/lastName") + .to be_json_eql('@example.com'.to_json) + .at_path('_embedded/payload/lastName') expect(body) - .to be_json_eql("A custom value".to_json) + .to be_json_eql('A custom value'.to_json) .at_path("_embedded/payload/customField#{custom_field.id}") expect(body) @@ -178,17 +178,17 @@ expect(body) .to have_json_size(0) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') end end end - context "with unauthorized user" do + context 'with unauthorized user' do shared_let(:current_user) { create(:user) } let(:payload) do {} end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end diff --git a/spec/requests/api/v3/user/create_user_common_examples.rb b/spec/requests/api/v3/user/create_user_common_examples.rb index b55219a3786a..93f166477c01 100644 --- a/spec/requests/api/v3/user/create_user_common_examples.rb +++ b/spec/requests/api/v3/user/create_user_common_examples.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_examples "represents the created user" do |expected_attributes| - it "returns the represented user" do +RSpec.shared_examples 'represents the created user' do |expected_attributes| + it 'returns the represented user' do send_request expect(last_response.status).to eq(201) - expect(last_response.body).to have_json_type(Object).at_path("_links") + expect(last_response.body).to have_json_type(Object).at_path('_links') expect(last_response.body) - .to be_json_eql("User".to_json) - .at_path("_type") + .to be_json_eql('User'.to_json) + .at_path('_type') parameters.merge!(expected_attributes) if expected_attributes @@ -44,8 +44,8 @@ end end -RSpec.shared_examples "property is not writable" do |attribute_name| - it "returns an error for the unwritable property" do +RSpec.shared_examples 'property is not writable' do |attribute_name| + it 'returns an error for the unwritable property' do send_request attr = JSON.parse(last_response.body).dig "_embedded", "details", "attribute" @@ -55,100 +55,100 @@ end end -RSpec.shared_examples "create user request flow" do - let(:errors) { parse_json(last_response.body)["_embedded"]["errors"] } +RSpec.shared_examples 'create user request flow' do + let(:errors) { parse_json(last_response.body)['_embedded']['errors'] } - describe "empty request body" do + describe 'empty request body' do let(:parameters) { {} } - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(422) expect(errors.count).to eq(5) - expect(errors.collect { |el| el["_embedded"]["details"]["attribute"] }) - .to contain_exactly("password", "login", "firstName", "lastName", "email") + expect(errors.collect { |el| el['_embedded']['details']['attribute'] }) + .to contain_exactly('password', 'login', 'firstName', 'lastName', 'email') expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:MultipleErrors".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:MultipleErrors'.to_json) + .at_path('errorIdentifier') end end - describe "invited status" do - let(:status) { "invited" } + describe 'invited status' do + let(:status) { 'invited' } let(:invitation_request) do { status:, - email: "foo@example.org" + email: 'foo@example.org' } end - describe "invitation successful" do + describe 'invitation successful' do before do expect(OpenProject::Notifications).to receive(:send) do |event, _| - expect(event).to eq "user_invited" + expect(event).to eq 'user_invited' end end - context "only mail set" do + context 'only mail set' do let(:parameters) { invitation_request } - it_behaves_like "represents the created user", - firstName: "foo", - lastName: "@example.org" + it_behaves_like 'represents the created user', + firstName: 'foo', + lastName: '@example.org' - it "sets the other attributes" do + it 'sets the other attributes' do send_request - user = User.find_by!(login: "foo@example.org") - expect(user.firstname).to eq("foo") - expect(user.lastname).to eq("@example.org") - expect(user.mail).to eq("foo@example.org") + user = User.find_by!(login: 'foo@example.org') + expect(user.firstname).to eq('foo') + expect(user.lastname).to eq('@example.org') + expect(user.mail).to eq('foo@example.org') end end - context "mail and name set" do - let(:parameters) { invitation_request.merge(firstName: "First", lastName: "Last") } + context 'mail and name set' do + let(:parameters) { invitation_request.merge(firstName: 'First', lastName: 'Last') } - it_behaves_like "represents the created user" + it_behaves_like 'represents the created user' end end - context "missing email" do + context 'missing email' do let(:parameters) { { status: } } - it "marks the mail as missing" do + it 'marks the mail as missing' do send_request expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:MultipleErrors".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:MultipleErrors'.to_json) + .at_path('errorIdentifier') expect(errors.count).to eq 4 - attributes = errors.map { |error| error.dig("_embedded", "details", "attribute") } - expect(attributes).to contain_exactly("login", "firstName", "lastName", "email") + attributes = errors.map { |error| error.dig('_embedded', 'details', 'attribute') } + expect(attributes).to contain_exactly('login', 'firstName', 'lastName', 'email') end end end - describe "invalid status" do - let(:parameters) { { status: "blablu" } } + describe 'invalid status' do + let(:parameters) { { status: 'blablu' } } - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(422) expect(errors).not_to be_empty expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:MultipleErrors".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:MultipleErrors'.to_json) + .at_path('errorIdentifier') - expect(errors.collect { |el| el["message"] }) - .to include "Status is not a valid status for new users." + expect(errors.collect { |el| el['message'] }) + .to include 'Status is not a valid status for new users.' end end end diff --git a/spec/requests/api/v3/user/create_user_resource_spec.rb b/spec/requests/api/v3/user/create_user_resource_spec.rb index 61ca8db92182..a07fa09d0216 100644 --- a/spec/requests/api/v3/user/create_user_resource_spec.rb +++ b/spec/requests/api/v3/user/create_user_resource_spec.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" -require_relative "create_user_common_examples" +require 'spec_helper' +require 'rack/test' +require_relative 'create_user_common_examples' RSpec.describe API::V3::Users::UsersAPI do include API::V3::Utilities::PathHelper @@ -35,12 +35,12 @@ let(:path) { api_v3_paths.users } let(:parameters) do { - status: "active", - login: "myusername", - firstName: "Foo", - lastName: "Bar", - email: "foobar@example.org", - language: "de" + status: 'active', + login: 'myusername', + firstName: 'Foo', + lastName: 'Bar', + email: 'foobar@example.org', + language: 'de' } end @@ -53,16 +53,16 @@ def send_request post path, parameters.to_json end - describe "admin user" do + describe 'admin user' do let(:current_user) { create(:admin) } - it_behaves_like "create user request flow" + it_behaves_like 'create user request flow' - context "with auth_source" do - let(:ldap_auth_source_id) { "some_ldap" } + context 'with auth_source' do + let(:ldap_auth_source_id) { 'some_ldap' } let(:auth_source) { create(:ldap_auth_source, name: ldap_auth_source_id) } - context "ID" do + context 'ID' do before do parameters[:_links] = { auth_source: { @@ -71,7 +71,7 @@ def send_request } end - it "creates the user with the given auth_source ID" do + it 'creates the user with the given auth_source ID' do send_request user = User.find_by(login: parameters[:login]) @@ -79,10 +79,10 @@ def send_request expect(user.ldap_auth_source).to eq auth_source end - it_behaves_like "represents the created user" + it_behaves_like 'represents the created user' end - context "name" do + context 'name' do before do parameters[:_links] = { auth_source: { @@ -91,7 +91,7 @@ def send_request } end - it "creates the user with the given auth_source ID" do + it 'creates the user with the given auth_source ID' do send_request user = User.find_by(login: parameters[:login]) @@ -99,10 +99,10 @@ def send_request expect(user.ldap_auth_source).to eq auth_source end - it_behaves_like "represents the created user" + it_behaves_like 'represents the created user' end - context "invalid identifier" do + context 'invalid identifier' do before do parameters[:_links] = { auth_source: { @@ -111,42 +111,42 @@ def send_request } end - it "returns an error on that attribute" do + it 'returns an error on that attribute' do send_request expect(last_response.status).to eq(422) expect(last_response.body) - .to be_json_eql("authSource".to_json) - .at_path("_embedded/details/attribute") + .to be_json_eql('authSource'.to_json) + .at_path('_embedded/details/attribute') expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyConstraintViolation".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyConstraintViolation'.to_json) + .at_path('errorIdentifier') end end end - describe "active status" do + describe 'active status' do let(:parameters) do { - status: "active", - login: "myusername", - firstName: "Foo", - lastName: "Bar", - email: "foobar@example.org", - language: "de" + status: 'active', + login: 'myusername', + firstName: 'Foo', + lastName: 'Bar', + email: 'foobar@example.org', + language: 'de' } end - context "with identity_url" do - let(:identity_url) { "google:3289272389298" } + context 'with identity_url' do + let(:identity_url) { 'google:3289272389298' } before do parameters[:identityUrl] = identity_url end - it "creates the user with the given identity_url" do + it 'creates the user with the given identity_url' do send_request user = User.find_by(login: parameters[:login]) @@ -154,37 +154,37 @@ def send_request expect(user.identity_url).to eq identity_url end - it_behaves_like "represents the created user" + it_behaves_like 'represents the created user' end - context "with password" do - let(:password) { "admin!admin!" } + context 'with password' do + let(:password) { 'admin!admin!' } before do parameters[:password] = password end - it "returns the represented user" do + it 'returns the represented user' do send_request expect(last_response.body).not_to have_json_path("_embedded/errors") - expect(last_response.body).to have_json_type(Object).at_path("_links") + expect(last_response.body).to have_json_type(Object).at_path('_links') expect(last_response.body) - .to be_json_eql("User".to_json) - .at_path("_type") + .to be_json_eql('User'.to_json) + .at_path('_type') end - it_behaves_like "represents the created user" + it_behaves_like 'represents the created user' - context "empty password" do - let(:password) { "" } + context 'empty password' do + let(:password) { '' } - it "marks the password missing and too short" do + it 'marks the password missing and too short' do send_request - errors = parse_json(last_response.body)["_embedded"]["errors"] + errors = parse_json(last_response.body)['_embedded']['errors'] expect(errors.count).to eq(2) - expect(errors.collect { |el| el["_embedded"]["details"]["attribute"] }) + expect(errors.collect { |el| el['_embedded']['details']['attribute'] }) .to match_array %w(password password) end end @@ -192,35 +192,35 @@ def send_request end end - describe "user with global user create permission" do + describe 'user with global user create permission' do shared_let(:current_user) { create(:user, global_permissions: [:create_user]) } - it_behaves_like "create user request flow" + it_behaves_like 'create user request flow' - describe "active status" do - context "with identity_url" do - let(:identity_url) { "google:3289272389298" } + describe 'active status' do + context 'with identity_url' do + let(:identity_url) { 'google:3289272389298' } before do parameters[:identityUrl] = identity_url end - it_behaves_like "property is not writable", "identityUrl" + it_behaves_like 'property is not writable', 'identityUrl' end - context "with password" do - let(:password) { "admin!admin!" } + context 'with password' do + let(:password) { 'admin!admin!' } before do parameters[:password] = password end - it_behaves_like "property is not writable", "password" + it_behaves_like 'property is not writable', 'password' end end - context "with auth_source" do - let(:ldap_auth_source_id) { "some_ldap" } + context 'with auth_source' do + let(:ldap_auth_source_id) { 'some_ldap' } let(:auth_source) { create(:ldap_auth_source, name: ldap_auth_source_id) } before do @@ -231,7 +231,7 @@ def send_request } end - it "creates the user with the given auth source id" do + it 'creates the user with the given auth source id' do send_request user = User.find_by(login: parameters[:login]) @@ -241,11 +241,11 @@ def send_request end end - describe "unauthorized user" do + describe 'unauthorized user' do let(:current_user) { build(:user) } - let(:parameters) { { status: "invited", email: "foo@example.org" } } + let(:parameters) { { status: 'invited', email: 'foo@example.org' } } - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(403) end diff --git a/spec/requests/api/v3/user/filters_spec.rb b/spec/requests/api/v3/user/filters_spec.rb index bd9435a45ee8..f2f417931d3c 100644 --- a/spec/requests/api/v3/user/filters_spec.rb +++ b/spec/requests/api/v3/user/filters_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe "GET /api/v3/users" do +RSpec.describe 'GET /api/v3/users' do let!(:users) do [ - create(:admin, login: "admin", status: :active), - create(:user, login: "h.wurst", status: :active), - create(:user, login: "h.heine", status: :locked), - create(:user, login: "m.mario", status: :active) + create(:admin, login: 'admin', status: :active), + create(:user, login: 'h.wurst', status: :active), + create(:user, login: 'h.heine', status: :locked), + create(:user, login: 'm.mario', status: :active) ] end @@ -59,30 +59,30 @@ def filter_users(name, operator, values) Array(Hash(json).dig("_embedded", "elements")).map { |e| e["login"] } end - describe "status filter" do - it "=" do + describe 'status filter' do + it '=' do expect(filter_users("status", "=", :active)).to contain_exactly("admin", "h.wurst", "m.mario") end - it "!" do + it '!' do expect(filter_users("status", "!", :active)).to contain_exactly("h.heine") end end - describe "login filter" do - it "=" do + describe 'login filter' do + it '=' do expect(filter_users("login", "=", "admin")).to contain_exactly("admin") end - it "!" do + it '!' do expect(filter_users("login", "!", "admin")).to contain_exactly("h.wurst", "h.heine", "m.mario") end - it "~" do + it '~' do expect(filter_users("login", "~", "h.")).to contain_exactly("h.wurst", "h.heine") end - it "!~" do + it '!~' do expect(filter_users("login", "!~", "h.")).to contain_exactly("admin", "m.mario") end end diff --git a/spec/requests/api/v3/user/schemas/user_schema_resource_spec.rb b/spec/requests/api/v3/user/schemas/user_schema_resource_spec.rb index 5da2ccf8e63c..f5697da2601f 100644 --- a/spec/requests/api/v3/user/schemas/user_schema_resource_spec.rb +++ b/spec/requests/api/v3/user/schemas/user_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Users schema resource", content_type: :json do +RSpec.describe 'API v3 Users schema resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -45,19 +45,19 @@ subject(:response) { last_response } - describe "#GET /users/schema" do + describe '#GET /users/schema' do before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns a schema" do + it 'returns a schema' do expect(subject.body) - .to be_json_eql("Schema".to_json) - .at_path "_type" + .to be_json_eql('Schema'.to_json) + .at_path '_type' end end end diff --git a/spec/requests/api/v3/user/update_form_resource_spec.rb b/spec/requests/api/v3/user/update_form_resource_spec.rb index 94f5a5a5dff4..6c31971386f2 100644 --- a/spec/requests/api/v3/user/update_form_resource_spec.rb +++ b/spec/requests/api/v3/user/update_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Users::UpdateFormAPI, content_type: :json do include Rack::Test::Methods @@ -58,92 +58,92 @@ subject(:response) { last_response } - context "with authorized user" do + context 'with authorized user' do # Required to satisfy the Users::UpdateContract#at_least_one_admin_is_active shared_let(:default_admin) { create(:admin) } shared_let(:current_user) do create(:user, global_permissions: [:manage_user]) end - describe "empty payload" do - it "returns a valid form", :aggregate_failures do + describe 'empty payload' do + it 'returns a valid form', :aggregate_failures do expect(response.status).to eq(200) - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') expect(body) .to be_json_eql(user.mail.to_json) - .at_path("_embedded/payload/email") + .at_path('_embedded/payload/email') expect(body) .to be_json_eql(user.firstname.to_json) - .at_path("_embedded/payload/firstName") + .at_path('_embedded/payload/firstName') expect(body) .to be_json_eql(user.lastname.to_json) - .at_path("_embedded/payload/lastName") + .at_path('_embedded/payload/lastName') expect(body) .to have_json_size(0) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') end end - describe "with a writable status" do + describe 'with a writable status' do let(:payload) do { - status: "locked" + status: 'locked' } end - it "returns a valid response", :aggregate_failures do + it 'returns a valid response', :aggregate_failures do expect(response.status).to eq(200) - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') expect(subject.body) .to have_json_size(0) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') expect(body) - .to be_json_eql("locked".to_json) - .at_path("_embedded/payload/status") + .to be_json_eql('locked'.to_json) + .at_path('_embedded/payload/status') # Does not change the user's status user.reload - expect(user.status).to eq "active" + expect(user.status).to eq 'active' end end - describe "with an empty firstname" do + describe 'with an empty firstname' do let(:payload) do { firstName: nil } end - it "returns an invalid form", :aggregate_failures do + it 'returns an invalid form', :aggregate_failures do expect(response.status).to eq(200) - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') expect(body) .to be_json_eql(user.mail.to_json) - .at_path("_embedded/payload/email") + .at_path('_embedded/payload/email') expect(body) - .not_to have_json_path("_embedded/payload/firstName") + .not_to have_json_path('_embedded/payload/firstName') expect(body) .to be_json_eql(user.lastname.to_json) - .at_path("_embedded/payload/lastName") + .at_path('_embedded/payload/lastName') expect(subject.body) .to have_json_size(1) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') expect(subject.body) - .to have_json_path("_embedded/validationErrors/firstName") + .to have_json_path('_embedded/validationErrors/firstName') expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') name_before = user.name @@ -152,18 +152,18 @@ end end - context "with a non existing id" do + context 'with a non existing id' do let(:path) { api_v3_paths.user_form(12345) } - it "returns 404 Not found" do + it 'returns 404 Not found' do expect(response.status).to eq(404) end end end - context "with unauthorized user" do + context 'with unauthorized user' do let(:current_user) { create(:user) } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end diff --git a/spec/requests/api/v3/user/update_user_resource_spec.rb b/spec/requests/api/v3/user/update_user_resource_spec.rb index 272c1185ddd3..6ef2fb1eceda 100644 --- a/spec/requests/api/v3/user/update_user_resource_spec.rb +++ b/spec/requests/api/v3/user/update_user_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Users::UsersAPI do include API::V3::Utilities::PathHelper @@ -44,15 +44,15 @@ def send_request patch path, parameters.to_json end - shared_examples "successful update" do |expected_attributes| - it "responds with the represented updated user" do + shared_examples 'successful update' do |expected_attributes| + it 'responds with the represented updated user' do send_request expect(last_response.status).to eq(200) - expect(last_response.body).to have_json_type(Object).at_path("_links") + expect(last_response.body).to have_json_type(Object).at_path('_links') expect(last_response.body) - .to be_json_eql("User".to_json) - .at_path("_type") + .to be_json_eql('User'.to_json) + .at_path('_type') updated_user = User.find(user.id) (expected_attributes || {}).each do |key, val| @@ -61,51 +61,51 @@ def send_request end end - shared_examples "update flow" do - describe "empty request body" do - it_behaves_like "successful update" + shared_examples 'update flow' do + describe 'empty request body' do + it_behaves_like 'successful update' end - describe "attribute change" do - let(:parameters) { { email: "foo@example.org", language: "de" } } + describe 'attribute change' do + let(:parameters) { { email: 'foo@example.org', language: 'de' } } - it_behaves_like "successful update", mail: "foo@example.org", language: "de" + it_behaves_like 'successful update', mail: 'foo@example.org', language: 'de' end - describe "attribute collision" do - let(:parameters) { { email: "foo@example.org" } } - let(:collision) { create(:user, mail: "foo@example.org") } + describe 'attribute collision' do + let(:parameters) { { email: 'foo@example.org' } } + let(:collision) { create(:user, mail: 'foo@example.org') } before do collision end - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(422) expect(last_response.body) - .to be_json_eql("email".to_json) - .at_path("_embedded/details/attribute") + .to be_json_eql('email'.to_json) + .at_path('_embedded/details/attribute') expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyConstraintViolation".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyConstraintViolation'.to_json) + .at_path('errorIdentifier') end end end - describe "admin user" do + describe 'admin user' do let(:current_user) { build(:admin) } - it_behaves_like "update flow" + it_behaves_like 'update flow' - describe "password update" do - let(:password) { "my!new!password123" } + describe 'password update' do + let(:password) { 'my!new!password123' } let(:parameters) { { password: } } - it "updates the users password correctly" do + it 'updates the users password correctly' do send_request expect(last_response.status).to eq(200) @@ -115,47 +115,47 @@ def send_request end end - describe "unknown user" do - let(:parameters) { { email: "foo@example.org" } } + describe 'unknown user' do + let(:parameters) { { email: 'foo@example.org' } } let(:path) { api_v3_paths.user(666) } - it "responds with 404" do + it 'responds with 404' do send_request expect(last_response.status).to be(404) end end end - describe "user with global manage_user permission" do + describe 'user with global manage_user permission' do shared_let(:global_manage_user) { create(:user, global_permissions: :manage_user) } let(:current_user) { global_manage_user } - it_behaves_like "update flow" + it_behaves_like 'update flow' - describe "password update" do - let(:password) { "my!new!password123" } + describe 'password update' do + let(:password) { 'my!new!password123' } let(:parameters) { { password: } } - it "rejects the users password update" do + it 'rejects the users password update' do send_request expect(last_response.status).to eq(422) expect(last_response.body) - .to be_json_eql("password".to_json) - .at_path("_embedded/details/attribute") + .to be_json_eql('password'.to_json) + .at_path('_embedded/details/attribute') expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyIsReadOnly".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyIsReadOnly'.to_json) + .at_path('errorIdentifier') end end end - describe "unauthorized user" do + describe 'unauthorized user' do let(:current_user) { build(:user) } - let(:parameters) { { email: "new@example.org" } } + let(:parameters) { { email: 'new@example.org' } } - it "returns an erroneous response" do + it 'returns an erroneous response' do send_request expect(last_response.status).to eq(403) end diff --git a/spec/requests/api/v3/user/user_resource_spec.rb b/spec/requests/api/v3/user/user_resource_spec.rb index 30112c990751..b613061992c3 100644 --- a/spec/requests/api/v3/user/user_resource_spec.rb +++ b/spec/requests/api/v3/user/user_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 User resource", +RSpec.describe 'API v3 User resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -39,7 +39,7 @@ let(:admin) { create(:admin) } let(:locked_admin) { create(:admin, status: Principal.statuses[:locked]) } let(:user_with_global_manage_user) do - create(:user, firstname: "Global", lastname: "User", global_permissions: [:manage_user]) + create(:user, firstname: 'Global', lastname: 'User', global_permissions: [:manage_user]) end subject(:response) { last_response } @@ -48,7 +48,7 @@ login_as(current_user) end - describe "#index" do + describe '#index' do let(:get_path) { api_v3_paths.path_for(:users, sort_by: [%i[id asc]]) } before do @@ -56,66 +56,66 @@ get get_path end - shared_examples "flow with permitted user" do - it "responds with 200" do + shared_examples 'flow with permitted user' do + it 'responds with 200' do expect(subject.status).to eq(200) end # note that the order of the users is depending on the id # meaning the order in which they where saved - it "contains the user in the response" do + it 'contains the user in the response' do expect(subject.body) .to be_json_eql(current_user.name.to_json) - .at_path("_embedded/elements/0/name") + .at_path('_embedded/elements/0/name') end - it "contains the current user in the response" do + it 'contains the current user in the response' do expect(subject.body) .to be_json_eql(user.name.to_json) - .at_path("_embedded/elements/1/name") + .at_path('_embedded/elements/1/name') end - it "has the users index path for link self href" do + it 'has the users index path for link self href' do expect(subject.body) .to be_json_eql("#{api_v3_paths.users}?filters=%5B%5D" \ "\u0026offset=1\u0026pageSize=20\u0026sortBy=%5B%5B%22id%22%2C%22asc%22%5D%5D".to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - context "if pageSize = 1 and offset = 2" do + context 'if pageSize = 1 and offset = 2' do let(:get_path) { api_v3_paths.path_for(:users, page_size: 1, offset: 2) } - it "contains the current user in the response" do + it 'contains the current user in the response' do expect(subject.body) .to be_json_eql(current_user.name.to_json) - .at_path("_embedded/elements/0/name") + .at_path('_embedded/elements/0/name') end end - context "when filtering by name" do + context 'when filtering by name' do let(:get_path) do - filter = [{ "name" => { - "operator" => "~", - "values" => [user.name] + filter = [{ 'name' => { + 'operator' => '~', + 'values' => [user.name] } }] "#{api_v3_paths.users}?#{{ filters: filter.to_json }.to_query}" end - it "contains the filtered user in the response" do + it 'contains the filtered user in the response' do expect(subject.body) .to be_json_eql(user.name.to_json) - .at_path("_embedded/elements/0/name") + .at_path('_embedded/elements/0/name') end - it "contains no more users" do + it 'contains no more users' do expect(subject.body) .to be_json_eql(1.to_json) - .at_path("total") + .at_path('total') end end - context "when sorting" do + context 'when sorting' do let(:users_by_name_order) do User.human.ordered_by_name(desc: true) end @@ -126,40 +126,40 @@ "#{api_v3_paths.users}?#{{ sortBy: sort.to_json }.to_query}" end - it "contains the first user as the first element" do + it 'contains the first user as the first element' do expect(subject.body) .to be_json_eql(users_by_name_order[0].name.to_json) - .at_path("_embedded/elements/0/name") + .at_path('_embedded/elements/0/name') end - it "contains the first user as the second element" do + it 'contains the first user as the second element' do expect(subject.body) .to be_json_eql(users_by_name_order[1].name.to_json) - .at_path("_embedded/elements/1/name") + .at_path('_embedded/elements/1/name') end end - context "with an invalid filter" do + context 'with an invalid filter' do let(:get_path) do - filter = [{ "name" => { - "operator" => "a", - "values" => [user.name] + filter = [{ 'name' => { + 'operator' => 'a', + 'values' => [user.name] } }] "#{api_v3_paths.users}?#{{ filters: filter.to_json }.to_query}" end - it "returns an error" do + it 'returns an error' do expect(subject.status).to be(400) end end - context "when signaling desired properties" do + context 'when signaling desired properties' do let(:get_path) do api_v3_paths.path_for :users, sort_by: [%w[name desc]], page_size: 1, - select: "total,elements/name" + select: 'total,elements/name' end let(:expected) do @@ -175,86 +175,86 @@ } end - it "returns an error" do + it 'returns an error' do expect(subject.body) .to be_json_eql(expected.to_json) end end end - context "for an admin" do + context 'for an admin' do let(:current_user) { admin } - it_behaves_like "flow with permitted user" + it_behaves_like 'flow with permitted user' end - context "for a user with global manage_user permission" do + context 'for a user with global manage_user permission' do let(:current_user) { user_with_global_manage_user } - it_behaves_like "flow with permitted user" + it_behaves_like 'flow with permitted user' end - context "for a locked admin" do + context 'for a locked admin' do let(:current_user) { locked_admin } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "for another user" do - it_behaves_like "unauthorized access" + context 'for another user' do + it_behaves_like 'unauthorized access' end end - describe "#get" do + describe '#get' do let(:get_path) { api_v3_paths.user user.id } before do get get_path end - context "logged in user" do - it "responds with 200" do + context 'logged in user' do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with correct body" do - expect(subject.body).to be_json_eql(user.name.to_json).at_path("name") + it 'responds with correct body' do + expect(subject.body).to be_json_eql(user.name.to_json).at_path('name') end - context "requesting nonexistent user" do + context 'requesting nonexistent user' do let(:get_path) { api_v3_paths.user 9999 } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "requesting current user" do - let(:get_path) { api_v3_paths.user "me" } + context 'requesting current user' do + let(:get_path) { api_v3_paths.user 'me' } - it "responses with 200" do + it 'responses with 200' do expect(subject.status).to eq(200) - expect(subject.body).to be_json_eql(user.name.to_json).at_path("name") + expect(subject.body).to be_json_eql(user.name.to_json).at_path('name') end end end - context "get with login" do + context 'get with login' do let(:get_path) { api_v3_paths.user user.login } - it "responds with 200" do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with correct body" do - expect(subject.body).to be_json_eql(user.name.to_json).at_path("name") + it 'responds with correct body' do + expect(subject.body).to be_json_eql(user.name.to_json).at_path('name') end end - it_behaves_like "handling anonymous user" do + it_behaves_like 'handling anonymous user' do let(:path) { api_v3_paths.user user.id } end end - describe "#delete" do + describe '#delete' do let(:path) { api_v3_paths.user user.id } let(:admin_delete) { true } let(:self_delete) { true } @@ -267,12 +267,12 @@ user.reload end - shared_examples "deletion allowed" do - it "responds with 202" do + shared_examples 'deletion allowed' do + it 'responds with 202' do expect(subject.status).to eq 202 end - it "locks the account and mark for deletion" do + it 'locks the account and mark for deletion' do expect(Principals::DeleteJob) .to have_been_enqueued .with(user) @@ -280,89 +280,89 @@ expect(user).to be_locked end - context "with a non-existent user" do + context 'with a non-existent user' do let(:path) { api_v3_paths.user 1337 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - shared_examples "deletion is not allowed" do - it_behaves_like "unauthorized access" + shared_examples 'deletion is not allowed' do + it_behaves_like 'unauthorized access' - it "does not delete the user" do + it 'does not delete the user' do expect(User).to exist(user.id) end end - context "as admin" do + context 'as admin' do let(:current_user) { admin } - context "with users deletable by admins" do + context 'with users deletable by admins' do let(:admin_delete) { true } - it_behaves_like "deletion allowed" + it_behaves_like 'deletion allowed' end - context "with users not deletable by admins" do + context 'with users not deletable by admins' do let(:admin_delete) { false } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end end - context "as locked admin" do + context 'as locked admin' do let(:current_user) { locked_admin } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end - context "as non-admin" do + context 'as non-admin' do let(:current_user) { create(:user, admin: false) } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end - context "as user with manage_user permission" do + context 'as user with manage_user permission' do let(:current_user) { user_with_global_manage_user } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end - context "as self" do + context 'as self' do let(:current_user) { user } - context "with self-deletion allowed" do + context 'with self-deletion allowed' do let(:self_delete) { true } - it_behaves_like "deletion allowed" + it_behaves_like 'deletion allowed' end - context "with self-deletion not allowed" do + context 'with self-deletion not allowed' do let(:self_delete) { false } - it_behaves_like "deletion is not allowed" + it_behaves_like 'deletion is not allowed' end end - context "as anonymous user" do + context 'as anonymous user' do let(:current_user) { create(:anonymous) } - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "error response", + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'error response', 401, - "Unauthenticated", - I18n.t("api_v3.errors.code_401") + 'Unauthenticated', + I18n.t('api_v3.errors.code_401') end - context "when not login_required", with_settings: { login_required: false } do - it_behaves_like "deletion is not allowed" + context 'when not login_required', with_settings: { login_required: false } do + it_behaves_like 'deletion is not allowed' end - context "requesting current user" do - let(:get_path) { api_v3_paths.user "me" } + context 'requesting current user' do + let(:get_path) { api_v3_paths.user 'me' } - it_behaves_like "forbidden response based on login_required" + it_behaves_like 'forbidden response based on login_required' end end end diff --git a/spec/requests/api/v3/user/userlock_resource_spec.rb b/spec/requests/api/v3/user/userlock_resource_spec.rb index 8bea6c9aee13..44d2c29c7215 100644 --- a/spec/requests/api/v3/user/userlock_resource_spec.rb +++ b/spec/requests/api/v3/user/userlock_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 UserLock resource", content_type: :json do +RSpec.describe 'API v3 UserLock resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -41,7 +41,7 @@ subject(:response) { last_response } - describe "#post" do + describe '#post' do before do allow(User).to receive(:current).and_return current_user post lock_path @@ -50,44 +50,44 @@ end # Locking is only available for admins - context "when logged in as admin" do + context 'when logged in as admin' do let(:current_user) { build_stubbed(:admin) } - context "user account can be locked" do - it "responds with 200" do + context 'user account can be locked' do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with an updated lock status in the user model" do - expect(parse_json(subject.body, "status")).to eq "locked" + it 'responds with an updated lock status in the user model' do + expect(parse_json(subject.body, 'status')).to eq 'locked' end end - context "user account is incompatible" do + context 'user account is incompatible' do let(:user) do create(:user, status: User.statuses[:registered]) end - it "fails for invalid transitions" do + it 'fails for invalid transitions' do expect(subject.status).to eq(400) end end end - context "requesting nonexistent user" do + context 'requesting nonexistent user' do let(:lock_path) { api_v3_paths.user_lock 9999 } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "non-admin user" do - it "responds with 403" do + context 'non-admin user' do + it 'responds with 403' do expect(subject.status).to eq(403) end end end - describe "#delete" do + describe '#delete' do before do allow(User).to receive(:current).and_return current_user delete lock_path @@ -96,32 +96,32 @@ end # Unlocking is only available for admins - context "when logged in as admin" do + context 'when logged in as admin' do let(:current_user) { build_stubbed(:admin) } - context "user account can be unlocked" do - it "responds with 200" do + context 'user account can be unlocked' do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with an updated lock status in the user model" do - expect(parse_json(subject.body, "status")).to eq "active" + it 'responds with an updated lock status in the user model' do + expect(parse_json(subject.body, 'status')).to eq 'active' end end - context "user account is incompatible" do + context 'user account is incompatible' do let(:user) do create(:user, status: User.statuses[:registered]) end - it "fails for invalid transitions" do + it 'fails for invalid transitions' do expect(subject.status).to eq(400) end end end - context "non-admin user" do - it "responds with 403" do + context 'non-admin user' do + it 'responds with 403' do expect(subject.status).to eq(403) end end diff --git a/spec/requests/api/v3/user_preferences/user_preferences_resource_spec.rb b/spec/requests/api/v3/user_preferences/user_preferences_resource_spec.rb index 288e307c3134..b7410eff8815 100644 --- a/spec/requests/api/v3/user_preferences/user_preferences_resource_spec.rb +++ b/spec/requests/api/v3/user_preferences/user_preferences_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 UserPreferences resource", content_type: :json do +RSpec.describe 'API v3 UserPreferences resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -49,55 +49,55 @@ current_user { user } - describe "#GET" do + describe '#GET' do before do get preference_path end - context "when not logged in" do + context 'when not logged in' do let(:user) { User.anonymous } - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it "responds with a UserPreferences representer", :aggregate_failures do + context 'when not login_required', with_settings: { login_required: false } do + it 'responds with a UserPreferences representer', :aggregate_failures do expect(subject.status).to eq(200) - expect(subject.body).to be_json_eql("UserPreferences".to_json).at_path("_type") + expect(subject.body).to be_json_eql('UserPreferences'.to_json).at_path('_type') end end end - context "when logged in" do - it "responds with 200" do + context 'when logged in' do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with a UserPreferences representer" do - expect(subject.body).to be_json_eql("UserPreferences".to_json).at_path("_type") + it 'responds with a UserPreferences representer' do + expect(subject.body).to be_json_eql('UserPreferences'.to_json).at_path('_type') end end end - describe "#PATCH" do + describe '#PATCH' do before do patch preference_path, params.to_json preference.reload end - context "when not logged in" do + context 'when not logged in' do let(:user) { User.anonymous } let(:params) do { whatever: true } end - it "responds with 401" do + it 'responds with 401' do expect(subject.status).to eq(401) end end - context "when updating the email_reminder settings" do + context 'when updating the email_reminder settings' do let(:params) do { dailyReminders: { @@ -107,18 +107,18 @@ } end - it "responds with 200" do + it 'responds with 200' do expect(subject.status) .to eq(200) end - it "updates the time zone" do + it 'updates the time zone' do expect(preference.daily_reminders) .to eql("enabled" => true, "times" => %w[08:00:00+00:00 18:00:00+00:00]) end end - context "when attempting to update the email_reminder settings with invalid values" do + context 'when attempting to update the email_reminder settings with invalid values' do let(:params) do { dailyReminders: { @@ -128,78 +128,78 @@ } end - it "responds with 422 and explains the error" do + it 'responds with 422 and explains the error' do expect(subject.status).to eq(422) expect(subject.body) .to be_json_eql("Daily reminders does not match the expected format 'time' at path 'times/0'.".to_json) - .at_path("_embedded/errors/0/message") + .at_path('_embedded/errors/0/message') expect(subject.body) .to be_json_eql("dailyReminders".to_json) - .at_path("_embedded/errors/0/_embedded/details/attribute") + .at_path('_embedded/errors/0/_embedded/details/attribute') expect(subject.body) .to be_json_eql("Daily reminders can only be configured to be delivered at a full hour.".to_json) - .at_path("_embedded/errors/1/message") + .at_path('_embedded/errors/1/message') expect(subject.body) .to be_json_eql("dailyReminders".to_json) - .at_path("_embedded/errors/1/_embedded/details/attribute") + .at_path('_embedded/errors/1/_embedded/details/attribute') end - it "keeps the previous values" do + it 'keeps the previous values' do expect(preference.daily_reminders) .to eql("enabled" => false, "times" => %w[07:00:00+00:00 15:00:00+00:00]) end end - context "when updating the timezone" do - context "with invalid timezone" do + context 'when updating the timezone' do + context 'with invalid timezone' do let(:params) do - { timeZone: "Europe/Awesomeland" } + { timeZone: 'Europe/Awesomeland' } end - it_behaves_like "constraint violation" do - let(:message) { "Time zone is not set to one of the allowed values." } + it_behaves_like 'constraint violation' do + let(:message) { 'Time zone is not set to one of the allowed values.' } end end - context "with valid time zone" do + context 'with valid time zone' do let(:params) do - { timeZone: "Europe/Paris" } + { timeZone: 'Europe/Paris' } end - it "responds with a UserPreferences representer" do - expect(subject.body).to be_json_eql("Europe/Paris".to_json).at_path("timeZone") - expect(preference.time_zone).to eq("Europe/Paris") + it 'responds with a UserPreferences representer' do + expect(subject.body).to be_json_eql('Europe/Paris'.to_json).at_path('timeZone') + expect(preference.time_zone).to eq('Europe/Paris') end end end end - describe "/api/v3/my_preferences endpoint" do + describe '/api/v3/my_preferences endpoint' do let(:preference_path) { api_v3_paths.my_preferences } - describe "#GET" do + describe '#GET' do before do get preference_path end - it "redirects to /api/v3/users/me/preferences" do + it 'redirects to /api/v3/users/me/preferences' do expect(subject.status).to eq(301) # Moved Permanently, it may change the method to GET - expect(response.get_header("Location")).to eq(api_v3_paths.user_preferences("me")) + expect(response.get_header('Location')).to eq(api_v3_paths.user_preferences("me")) end end - describe "#PATCH" do + describe '#PATCH' do before do patch preference_path end - it "redirects to /api/v3/users/me/preferences with 308 to keep the http method" do + it 'redirects to /api/v3/users/me/preferences with 308 to keep the http method' do expect(subject.status).to eq(308) # Method redirect, it keeps the same HTTP method. - expect(response.get_header("Location")).to eq(api_v3_paths.user_preferences("me")) + expect(response.get_header('Location')).to eq(api_v3_paths.user_preferences("me")) end end end diff --git a/spec/requests/api/v3/values/schemas/value_schema_resource_spec.rb b/spec/requests/api/v3/values/schemas/value_schema_resource_spec.rb index 7f8f372c4d8f..c77967fa9cfe 100644 --- a/spec/requests/api/v3/values/schemas/value_schema_resource_spec.rb +++ b/spec/requests/api/v3/values/schemas/value_schema_resource_spec.rb @@ -26,96 +26,96 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Values::Schemas::ValueSchemaAPI, - "show", + 'show', content_type: :json do include API::V3::Utilities::PathHelper current_user { build_stubbed(:user) } let(:path) { api_v3_paths.value_schema(schema_id) } - let(:schema_id) { "bogus" } + let(:schema_id) { 'bogus' } before do get path end - context "for a logged in user" do - context "for a startDate" do - let(:schema_id) { "startDate" } + context 'for a logged in user' do + context 'for a startDate' do + let(:schema_id) { 'startDate' } - it "returns the schema", :aggregate_failures do + it 'returns the schema', :aggregate_failures do expect(last_response.status) .to eq 200 expect(last_response.body) - .to be_json_eql("Schema".to_json) - .at_path("_type") + .to be_json_eql('Schema'.to_json) + .at_path('_type') expect(last_response.body) - .to be_json_eql("Date".to_json) - .at_path("value/type") + .to be_json_eql('Date'.to_json) + .at_path('value/type') expect(last_response.body) - .to be_json_eql("Start date".to_json) - .at_path("value/name") + .to be_json_eql('Start date'.to_json) + .at_path('value/name') end end - context "for a dueDate" do - let(:schema_id) { "dueDate" } + context 'for a dueDate' do + let(:schema_id) { 'dueDate' } - it "returns the schema", :aggregate_failures do + it 'returns the schema', :aggregate_failures do expect(last_response.status) .to eq 200 expect(last_response.body) - .to be_json_eql("Schema".to_json) - .at_path("_type") + .to be_json_eql('Schema'.to_json) + .at_path('_type') expect(last_response.body) - .to be_json_eql("Date".to_json) - .at_path("value/type") + .to be_json_eql('Date'.to_json) + .at_path('value/type') expect(last_response.body) - .to be_json_eql("Finish date".to_json) - .at_path("value/name") + .to be_json_eql('Finish date'.to_json) + .at_path('value/name') end end - context "for a date" do - let(:schema_id) { "date" } + context 'for a date' do + let(:schema_id) { 'date' } - it "returns the schema", :aggregate_failures do + it 'returns the schema', :aggregate_failures do expect(last_response.status) .to eq 200 expect(last_response.body) - .to be_json_eql("Schema".to_json) - .at_path("_type") + .to be_json_eql('Schema'.to_json) + .at_path('_type') expect(last_response.body) - .to be_json_eql("Date".to_json) - .at_path("value/type") + .to be_json_eql('Date'.to_json) + .at_path('value/type') expect(last_response.body) - .to be_json_eql("Date".to_json) - .at_path("value/name") + .to be_json_eql('Date'.to_json) + .at_path('value/name') end end - context "for a non existing property" do - let(:schema_id) { "bogus" } + context 'for a non existing property' do + let(:schema_id) { 'bogus' } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "for an underscore property" do - let(:schema_id) { "start_date" } + context 'for an underscore property' do + let(:schema_id) { 'start_date' } - it_behaves_like "param validation error" + it_behaves_like 'param validation error' end end end diff --git a/spec/requests/api/v3/version_resource_spec.rb b/spec/requests/api/v3/version_resource_spec.rb index 58bd7dd67f97..5102c2c5f32f 100644 --- a/spec/requests/api/v3/version_resource_spec.rb +++ b/spec/requests/api/v3/version_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Version resource", content_type: :json do +RSpec.describe 'API v3 Version resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -44,28 +44,28 @@ let(:version_in_other_project) do build(:version, project: other_project, - sharing: "system", + sharing: 'system', custom_field_values: { int_cf.id => 123 }) end subject(:response) { last_response } - describe "GET api/v3/versions/:id" do + describe 'GET api/v3/versions/:id' do let(:get_path) { api_v3_paths.version version_in_project.id } - shared_examples_for "successful response" do - it "responds with 200" do + shared_examples_for 'successful response' do + it 'responds with 200' do expect(last_response.status).to eq(200) end - it "returns the version" do + it 'returns the version' do expect(last_response.body) - .to be_json_eql("Version".to_json) - .at_path("_type") + .to be_json_eql('Version'.to_json) + .at_path('_type') expect(last_response.body) .to be_json_eql(expected_version.id.to_json) - .at_path("id") + .at_path('id') expect(last_response.body) .to be_json_eql(123.to_json) @@ -73,7 +73,7 @@ end end - context "logged in user with permissions" do + context 'logged in user with permissions' do before do version_in_project.save! login_as current_user @@ -81,12 +81,12 @@ get get_path end - it_behaves_like "successful response" do + it_behaves_like 'successful response' do let(:expected_version) { version_in_project } end end - context "logged in user with permission on project a version is shared with" do + context 'logged in user with permission on project a version is shared with' do let(:get_path) { api_v3_paths.version version_in_other_project.id } before do @@ -96,12 +96,12 @@ get get_path end - it_behaves_like "successful response" do + it_behaves_like 'successful response' do let(:expected_version) { version_in_other_project } end end - context "logged in user without permission" do + context 'logged in user without permission' do let(:permissions) { [] } before do @@ -111,20 +111,20 @@ get get_path end - it_behaves_like "not found" + it_behaves_like 'not found' end end - describe "PATCH api/v3/versions" do + describe 'PATCH api/v3/versions' do let(:path) { api_v3_paths.version(version.id) } let(:version) do create(:version, - name: "Old name", - description: "Old description", - start_date: "2017-06-01", - effective_date: "2017-07-01", - status: "open", - sharing: "none", + name: 'Old name', + description: 'Old description', + start_date: '2017-06-01', + effective_date: '2017-07-01', + status: 'open', + sharing: 'none', project:, custom_field_values: { int_cf.id => 123, list_cf.id => list_cf.custom_options.first.id }) @@ -133,9 +133,9 @@ let!(:list_cf) { create(:version_custom_field, :list) } let(:body) do { - name: "New name", + name: 'New name', description: { - raw: "New description" + raw: 'New description' }, "customField#{int_cf.id}": 5, startDate: "2018-01-01", @@ -156,48 +156,48 @@ patch path, body end - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end - it "updates the version" do - expect(Version.find_by(name: "New name")) + it 'updates the version' do + expect(Version.find_by(name: 'New name')) .to be_present end - it "returns the updated version" do + it 'returns the updated version' do expect(last_response.body) - .to be_json_eql("Version".to_json) - .at_path("_type") + .to be_json_eql('Version'.to_json) + .at_path('_type') expect(last_response.body) - .to be_json_eql("New name".to_json) - .at_path("name") + .to be_json_eql('New name'.to_json) + .at_path('name') expect(last_response.body) - .to be_json_eql("

      New description

      ".to_json) - .at_path("description/html") + .to be_json_eql('

      New description

      '.to_json) + .at_path('description/html') expect(last_response.body) - .to be_json_eql("2018-01-01".to_json) - .at_path("startDate") + .to be_json_eql('2018-01-01'.to_json) + .at_path('startDate') expect(last_response.body) - .to be_json_eql("2018-01-09".to_json) - .at_path("endDate") + .to be_json_eql('2018-01-09'.to_json) + .at_path('endDate') expect(last_response.body) - .to be_json_eql("closed".to_json) - .at_path("status") + .to be_json_eql('closed'.to_json) + .at_path('status') expect(last_response.body) - .to be_json_eql("descendants".to_json) - .at_path("sharing") + .to be_json_eql('descendants'.to_json) + .at_path('sharing') # unchanged expect(last_response.body) .to be_json_eql(project.name.to_json) - .at_path("_links/definingProject/title") + .at_path('_links/definingProject/title') expect(last_response.body) .to be_json_eql(api_v3_paths.custom_option(list_cf.custom_options.last.id).to_json) @@ -208,7 +208,7 @@ .at_path("customField#{int_cf.id}") end - context "if attempting to switch the project" do + context 'if attempting to switch the project' do let(:other_project) do create(:project).tap do |p| create(:member, @@ -231,22 +231,22 @@ }.to_json end - it_behaves_like "read-only violation", "project", Version + it_behaves_like 'read-only violation', 'project', Version end - context "if lacking the manage permissions" do + context 'if lacking the manage permissions' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "if lacking the manage permissions" do + context 'if lacking the manage permissions' do let(:permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "if having the manage permission in a different project" do + context 'if having the manage permission in a different project' do let(:other_membership) do create(:member, project: create(:project), @@ -260,19 +260,19 @@ [:view_work_packages] end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "POST api/v3/versions" do + describe 'POST api/v3/versions' do let(:path) { api_v3_paths.versions } let!(:int_cf) { create(:version_custom_field, :integer) } let!(:list_cf) { create(:version_custom_field, :list) } let(:body) do { - name: "New version", + name: 'New version', description: { - raw: "A new description" + raw: 'A new description' }, "customField#{int_cf.id}": 5, startDate: "2018-01-01", @@ -296,47 +296,47 @@ post path, body end - it "responds with 201" do + it 'responds with 201' do expect(last_response.status).to eq(201) end - it "creates the version" do - expect(Version.find_by(name: "New version")) + it 'creates the version' do + expect(Version.find_by(name: 'New version')) .to be_present end - it "returns the newly created version" do + it 'returns the newly created version' do expect(last_response.body) - .to be_json_eql("Version".to_json) - .at_path("_type") + .to be_json_eql('Version'.to_json) + .at_path('_type') expect(last_response.body) - .to be_json_eql("New version".to_json) - .at_path("name") + .to be_json_eql('New version'.to_json) + .at_path('name') expect(last_response.body) - .to be_json_eql("

      A new description

      ".to_json) - .at_path("description/html") + .to be_json_eql('

      A new description

      '.to_json) + .at_path('description/html') expect(last_response.body) - .to be_json_eql("2018-01-01".to_json) - .at_path("startDate") + .to be_json_eql('2018-01-01'.to_json) + .at_path('startDate') expect(last_response.body) - .to be_json_eql("2018-01-09".to_json) - .at_path("endDate") + .to be_json_eql('2018-01-09'.to_json) + .at_path('endDate') expect(last_response.body) - .to be_json_eql("closed".to_json) - .at_path("status") + .to be_json_eql('closed'.to_json) + .at_path('status') expect(last_response.body) - .to be_json_eql("descendants".to_json) - .at_path("sharing") + .to be_json_eql('descendants'.to_json) + .at_path('sharing') expect(last_response.body) .to be_json_eql(project.name.to_json) - .at_path("_links/definingProject/title") + .at_path('_links/definingProject/title') expect(last_response.body) .to be_json_eql(api_v3_paths.custom_option(list_cf.custom_options.first.id).to_json) @@ -347,13 +347,13 @@ .at_path("customField#{int_cf.id}") end - context "if lacking the manage permissions" do + context 'if lacking the manage permissions' do let(:permissions) { [] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "if having the manage permission in a different project" do + context 'if having the manage permission in a different project' do let(:other_membership) do create(:member, project: create(:project), @@ -367,11 +367,11 @@ [:view_work_packages] end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "GET api/v3/versions" do + describe 'GET api/v3/versions' do let(:get_path) { api_v3_paths.versions } let(:response) { last_response } let(:versions) { [version_in_project] } @@ -383,44 +383,44 @@ get get_path end - it "succeeds" do + it 'succeeds' do expect(last_response.status) .to be(200) end - it_behaves_like "API V3 collection response", 1, 1, "Version" + it_behaves_like 'API V3 collection response', 1, 1, 'Version' - it "is the version the user has permission in" do + it 'is the version the user has permission in' do expect(response.body) .to be_json_eql(api_v3_paths.version(version_in_project.id).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end - context "filtering for project by sharing" do + context 'filtering for project by sharing' do let(:shared_version_in_project) do - build(:version, project:, sharing: "system") + build(:version, project:, sharing: 'system') end let(:versions) { [version_in_project, shared_version_in_project] } let(:filter_query) do - [{ sharing: { operator: "=", values: ["system"] } }] + [{ sharing: { operator: '=', values: ['system'] } }] end let(:get_path) do "#{api_v3_paths.versions}?filters=#{CGI.escape(JSON.dump(filter_query))}" end - it_behaves_like "API V3 collection response", 1, 1, "Version" + it_behaves_like 'API V3 collection response', 1, 1, 'Version' - it "returns the shared version" do + it 'returns the shared version' do expect(response.body) .to be_json_eql(api_v3_paths.version(shared_version_in_project.id).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end end - describe "DELETE /api/v3/versions/:id" do + describe 'DELETE /api/v3/versions/:id' do let(:path) { api_v3_paths.version(version.id) } let(:version) do create(:version, @@ -435,23 +435,23 @@ subject { last_response } - context "with required permissions" do - it "responds with HTTP No Content" do + context 'with required permissions' do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "deletes the version" do + it 'deletes the version' do expect(Version.exists?(version.id)).to be_falsey end - context "for a non-existent version" do + context 'for a non-existent version' do let(:path) { api_v3_paths.version 1337 } - it_behaves_like "not found" + it_behaves_like 'not found' end end - context "with work packages attached to it" do + context 'with work packages attached to it' do let(:version) do create(:version, project:).tap do |v| @@ -461,28 +461,28 @@ end end - it "returns a 422" do + it 'returns a 422' do expect(subject.status) .to be 422 end - it "does not delete the version" do + it 'does not delete the version' do expect(Version.exists?(version.id)).to be_truthy end end - context "without permission to see versions" do + context 'without permission to see versions' do let(:permissions) { [] } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "without permission to delete versions" do + context 'without permission to delete versions' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' - it "does not delete the version" do + it 'does not delete the version' do expect(Version.exists?(version.id)).to be_truthy end end diff --git a/spec/requests/api/v3/versions/available_projects_resource_spec.rb b/spec/requests/api/v3/versions/available_projects_resource_spec.rb index 608fca4b282e..1c5d71cce6ff 100644 --- a/spec/requests/api/v3/versions/available_projects_resource_spec.rb +++ b/spec/requests/api/v3/versions/available_projects_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 members available projects resource" do +RSpec.describe 'API v3 members available projects resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -78,7 +78,7 @@ subject(:response) { last_response } - describe "GET api/v3/members/available_projects" do + describe 'GET api/v3/members/available_projects' do let(:projects) { [manage_project, view_project, unauthorized_project] } let(:path) { api_v3_paths.versions_available_projects } @@ -89,30 +89,30 @@ get path end - context "without params" do - it "responds 200 OK" do + context 'without params' do + it 'responds 200 OK' do expect(subject.status).to eq(200) end - it "returns a collection of projects containing only the ones for which the user has :manage_versions permission" do + it 'returns a collection of projects containing only the ones for which the user has :manage_versions permission' do expect(subject.body) - .to be_json_eql("Collection".to_json) - .at_path("_type") + .to be_json_eql('Collection'.to_json) + .at_path('_type') expect(subject.body) - .to be_json_eql("1") - .at_path("total") + .to be_json_eql('1') + .at_path('total') expect(subject.body) .to be_json_eql(manage_project.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end end - context "without permissions" do + context 'without permissions' do let(:permissions) { [:view_versions] } - it "returns a 403" do + it 'returns a 403' do expect(subject.status) .to eq(403) end diff --git a/spec/requests/api/v3/versions/create_form_resource_spec.rb b/spec/requests/api/v3/versions/create_form_resource_spec.rb index 47fca5b70762..2a3b96ffbdbc 100644 --- a/spec/requests/api/v3/versions/create_form_resource_spec.rb +++ b/spec/requests/api/v3/versions/create_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Versions::CreateFormAPI, content_type: :json do include Rack::Test::Methods @@ -48,42 +48,42 @@ subject(:response) { last_response } - describe "#POST /api/v3/versions/form" do - it "returns 200 OK" do + describe '#POST /api/v3/versions/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - it "does not create a version" do + it 'does not create a version' do expect(Version.count) .to be 0 end - context "with empty parameters" do - it "has 2 validation errors" do - expect(subject.body).to have_json_size(2).at_path("_embedded/validationErrors") + context 'with empty parameters' do + it 'has 2 validation errors' do + expect(subject.body).to have_json_size(2).at_path('_embedded/validationErrors') end - it "has a validation error on name" do - expect(subject.body).to have_json_path("_embedded/validationErrors/name") + it 'has a validation error on name' do + expect(subject.body).to have_json_path('_embedded/validationErrors/name') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with all minimum parameters" do + context 'with all minimum parameters' do let(:parameters) do { _links: { @@ -91,29 +91,29 @@ href: api_v3_paths.project(project.id) } }, - name: "lorem ipsum" + name: 'lorem ipsum' } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.versions.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "with all parameters" do + context 'with all parameters' do let!(:int_cf) { create(:version_custom_field, :integer) } let!(:list_cf) { create(:version_custom_field, :list) } let(:parameters) do { - name: "New version", + name: 'New version', description: { - raw: "A new description" + raw: 'A new description' }, int_cf.attribute_name(:camel_case) => 5, startDate: "2018-01-01", @@ -131,40 +131,40 @@ } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) - .to be_json_eql("New version".to_json) - .at_path("_embedded/payload/name") + .to be_json_eql('New version'.to_json) + .at_path('_embedded/payload/name') expect(last_response.body) - .to be_json_eql("

      A new description

      ".to_json) - .at_path("_embedded/payload/description/html") + .to be_json_eql('

      A new description

      '.to_json) + .at_path('_embedded/payload/description/html') expect(last_response.body) - .to be_json_eql("2018-01-01".to_json) - .at_path("_embedded/payload/startDate") + .to be_json_eql('2018-01-01'.to_json) + .at_path('_embedded/payload/startDate') expect(last_response.body) - .to be_json_eql("2018-01-09".to_json) - .at_path("_embedded/payload/endDate") + .to be_json_eql('2018-01-09'.to_json) + .at_path('_embedded/payload/endDate') expect(last_response.body) - .to be_json_eql("closed".to_json) - .at_path("_embedded/payload/status") + .to be_json_eql('closed'.to_json) + .at_path('_embedded/payload/status') expect(last_response.body) - .to be_json_eql("descendants".to_json) - .at_path("_embedded/payload/sharing") + .to be_json_eql('descendants'.to_json) + .at_path('_embedded/payload/sharing') expect(body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/payload/_links/definingProject/href") + .at_path('_embedded/payload/_links/definingProject/href') expect(last_response.body) .to be_json_eql(api_v3_paths.custom_option(list_cf.custom_options.first.id).to_json) @@ -175,17 +175,17 @@ .at_path("_embedded/payload/customField#{int_cf.id}") end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.versions.to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "without the necessary permission" do + context 'without the necessary permission' do let(:permissions) { [] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end diff --git a/spec/requests/api/v3/versions/project_resource_spec.rb b/spec/requests/api/v3/versions/project_resource_spec.rb index e3dd254e0418..cac5d1b62d3f 100644 --- a/spec/requests/api/v3/versions/project_resource_spec.rb +++ b/spec/requests/api/v3/versions/project_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe "API v3 version's projects resource" do include Rack::Test::Methods @@ -47,14 +47,14 @@ let(:project2) { create(:project, public: false) } let(:project3) { create(:project, public: false) } let(:project4) { create(:project, public: false) } - let(:version) { create(:version, project:, sharing: "system") } + let(:version) { create(:version, project:, sharing: 'system') } subject(:response) { last_response } - describe "#get (index)" do + describe '#get (index)' do let(:get_path) { api_v3_paths.projects_by_version version.id } - context "logged in user with permissions" do + context 'logged in user with permissions' do before do current_user @@ -73,16 +73,16 @@ get get_path end - it_behaves_like "API V3 collection response", 3, 3, "Project" + it_behaves_like 'API V3 collection response', 3, 3, 'Project' - it "includes only the projects which the user can see" do - id_in_response = JSON.parse(response.body)["_embedded"]["elements"].map { |p| p["id"] } + it 'includes only the projects which the user can see' do + id_in_response = JSON.parse(response.body)['_embedded']['elements'].map { |p| p['id'] } expect(id_in_response).to contain_exactly(project.id, project2.id, project3.id) end end - context "logged in user without permissions" do + context 'logged in user without permissions' do let(:role) { role_without_permissions } before do @@ -91,7 +91,7 @@ get get_path end - it_behaves_like "not found" + it_behaves_like 'not found' end end end diff --git a/spec/requests/api/v3/versions/schemas/version_schema_resource_spec.rb b/spec/requests/api/v3/versions/schemas/version_schema_resource_spec.rb index f9262061f1cf..3f5091c9fff6 100644 --- a/spec/requests/api/v3/versions/schemas/version_schema_resource_spec.rb +++ b/spec/requests/api/v3/versions/schemas/version_schema_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Version schema resource", content_type: :json do +RSpec.describe 'API v3 Version schema resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -48,30 +48,30 @@ subject(:response) { last_response } - describe "#GET /versions/schema" do + describe '#GET /versions/schema' do before do get path end - it "responds with 200 OK" do + it 'responds with 200 OK' do expect(subject.status).to eq(200) end - it "returns a schema" do + it 'returns a schema' do expect(subject.body) - .to be_json_eql("Schema".to_json) - .at_path "_type" + .to be_json_eql('Schema'.to_json) + .at_path '_type' end - it "does not embed" do + it 'does not embed' do expect(subject.body) - .not_to have_json_path("definingProject/_links/allowedValues") + .not_to have_json_path('definingProject/_links/allowedValues') end - context "if lacking permissions" do + context 'if lacking permissions' do let(:permissions) { [] } - it "responds with 403" do + it 'responds with 403' do expect(subject.status).to eq(403) end end diff --git a/spec/requests/api/v3/versions/update_form_resource_spec.rb b/spec/requests/api/v3/versions/update_form_resource_spec.rb index fbc564db2822..305476404226 100644 --- a/spec/requests/api/v3/versions/update_form_resource_spec.rb +++ b/spec/requests/api/v3/versions/update_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Versions::UpdateFormAPI, content_type: :json do include Rack::Test::Methods @@ -42,7 +42,7 @@ let(:path) { api_v3_paths.version_form(version.id) } let(:parameters) do { - name: "A new version name" + name: 'A new version name' } end @@ -53,23 +53,23 @@ subject(:response) { last_response } - describe "#POST /api/v3/versions/:id/form" do - it "returns 200 OK" do + describe '#POST /api/v3/versions/:id/form' do + it 'returns 200 OK' do expect(response.status).to eq(200) end - it "returns a form" do + it 'returns a form' do expect(response.body) - .to be_json_eql("Form".to_json) - .at_path("_type") + .to be_json_eql('Form'.to_json) + .at_path('_type') end - it "does not update the version" do + it 'does not update the version' do expect(version.reload.name) - .not_to eql "A new version name" + .not_to eql 'A new version name' end - context "with nulling parameters" do + context 'with nulling parameters' do let(:parameters) do { name: nil, @@ -81,25 +81,25 @@ } end - it "has 2 validation errors" do - expect(subject.body).to have_json_size(2).at_path("_embedded/validationErrors") + it 'has 2 validation errors' do + expect(subject.body).to have_json_size(2).at_path('_embedded/validationErrors') end - it "has a validation error on name" do - expect(subject.body).to have_json_path("_embedded/validationErrors/name") + it 'has a validation error on name' do + expect(subject.body).to have_json_path('_embedded/validationErrors/name') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with wanting to alter the project" do + context 'with wanting to alter the project' do let(:other_project) do role = create(:project_role, permissions:) @@ -116,34 +116,34 @@ } end - it "has 1 validation errors" do - expect(subject.body).to have_json_size(1).at_path("_embedded/validationErrors") + it 'has 1 validation errors' do + expect(subject.body).to have_json_size(1).at_path('_embedded/validationErrors') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end - it "notes definingProject to not be writable" do + it 'notes definingProject to not be writable' do expect(subject.body) .to be_json_eql(false) - .at_path("_embedded/schema/definingProject/writable") + .at_path('_embedded/schema/definingProject/writable') end - it "has no commit link" do + it 'has no commit link' do expect(subject.body) - .not_to have_json_path("_links/commit") + .not_to have_json_path('_links/commit') end end - context "with all parameters" do + context 'with all parameters' do let!(:int_cf) { create(:version_custom_field, :integer) } let!(:list_cf) { create(:version_custom_field, :list) } let(:parameters) do { - name: "New version", + name: 'New version', description: { - raw: "A new description" + raw: 'A new description' }, int_cf.attribute_name(:camel_case) => 5, startDate: "2018-01-01", @@ -158,36 +158,36 @@ } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the values prefilled in the payload" do + it 'has the values prefilled in the payload' do body = subject.body expect(body) - .to be_json_eql("New version".to_json) - .at_path("_embedded/payload/name") + .to be_json_eql('New version'.to_json) + .at_path('_embedded/payload/name') expect(last_response.body) - .to be_json_eql("

      A new description

      ".to_json) - .at_path("_embedded/payload/description/html") + .to be_json_eql('

      A new description

      '.to_json) + .at_path('_embedded/payload/description/html') expect(last_response.body) - .to be_json_eql("2018-01-01".to_json) - .at_path("_embedded/payload/startDate") + .to be_json_eql('2018-01-01'.to_json) + .at_path('_embedded/payload/startDate') expect(last_response.body) - .to be_json_eql("2018-01-09".to_json) - .at_path("_embedded/payload/endDate") + .to be_json_eql('2018-01-09'.to_json) + .at_path('_embedded/payload/endDate') expect(last_response.body) - .to be_json_eql("closed".to_json) - .at_path("_embedded/payload/status") + .to be_json_eql('closed'.to_json) + .at_path('_embedded/payload/status') expect(last_response.body) - .to be_json_eql("descendants".to_json) - .at_path("_embedded/payload/sharing") + .to be_json_eql('descendants'.to_json) + .at_path('_embedded/payload/sharing') expect(last_response.body) .to be_json_eql(api_v3_paths.custom_option(list_cf.custom_options.first.id).to_json) @@ -198,31 +198,31 @@ .at_path("_embedded/payload/customField#{int_cf.id}") end - it "has no definingProject path" do + it 'has no definingProject path' do # As the definingProject is not writable expect(body) - .not_to have_json_path("_embedded/payload/_links/definingProject") + .not_to have_json_path('_embedded/payload/_links/definingProject') end - it "has a commit link" do + it 'has a commit link' do expect(subject.body) .to be_json_eql(api_v3_paths.version(version.id).to_json) - .at_path("_links/commit/href") + .at_path('_links/commit/href') end end - context "without the necessary edit permission" do + context 'without the necessary edit permission' do let(:permissions) { [:view_work_packages] } - it "returns 403 Not Authorized" do + it 'returns 403 Not Authorized' do expect(response.status).to eq(403) end end - context "without the necessary view permission" do + context 'without the necessary view permission' do let(:permissions) { [] } - it "returns 404 Not Found" do + it 'returns 404 Not Found' do expect(response.status).to eq(404) end end diff --git a/spec/requests/api/v3/views/create_resource_spec.rb b/spec/requests/api/v3/views/create_resource_spec.rb index 8cdae129f461..4ff1878efd1a 100644 --- a/spec/requests/api/v3/views/create_resource_spec.rb +++ b/spec/requests/api/v3/views/create_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Views::ViewsAPI, - "create", + 'create', content_type: :json do include API::V3::Utilities::PathHelper @@ -60,7 +60,7 @@ end let(:send_request) do - post api_v3_paths.views_type("work_packages_table"), body + post api_v3_paths.views_type('work_packages_table'), body end current_user { permitted_user } @@ -73,83 +73,83 @@ send_request end - describe "POST /api/v3/views/work_packages_table" do - context "with a user allowed to save the query" do - it "returns 201 CREATED" do + describe 'POST /api/v3/views/work_packages_table' do + context 'with a user allowed to save the query' do + it 'returns 201 CREATED' do expect(response.status) .to eq(201) end - it "returns the view" do + it 'returns the view' do expect(response.body) - .to be_json_eql("Views::WorkPackagesTable".to_json) - .at_path("_type") + .to be_json_eql('Views::WorkPackagesTable'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(View.last.id.to_json) - .at_path("id") + .at_path('id') end end - context "with a user not allowed to see the query" do + context 'with a user not allowed to see the query' do let(:additional_setup) do role.update_attribute(:permissions, []) end - it "responds with 422 and explains the error" do + it 'responds with 422 and explains the error' do expect(last_response.status).to eq(422) expect(last_response.body) .to be_json_eql("Query does not exist.".to_json) - .at_path("message") + .at_path('message') end end end - describe "POST /api/v3/views/work_packages_calendar" do + describe 'POST /api/v3/views/work_packages_calendar' do let(:send_request) do - post api_v3_paths.views_type("work_packages_calendar"), body + post api_v3_paths.views_type('work_packages_calendar'), body end - context "with a user allowed to save the query and see the calendar" do + context 'with a user allowed to save the query and see the calendar' do let(:additional_setup) do role.update_attribute(:permissions, role.permissions + [:view_calendar]) end - it "returns 201 CREATED" do + it 'returns 201 CREATED' do expect(response.status) .to eq(201) end - it "returns the view" do + it 'returns the view' do expect(response.body) - .to be_json_eql("Views::WorkPackagesCalendar".to_json) - .at_path("_type") + .to be_json_eql('Views::WorkPackagesCalendar'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(View.last.id.to_json) - .at_path("id") + .at_path('id') end end - context "with a user allowed to save the query but not to view calendars" do - it_behaves_like "unauthorized access" + context 'with a user allowed to save the query but not to view calendars' do + it_behaves_like 'unauthorized access' end - context "with a user not allowed to see the query" do + context 'with a user not allowed to see the query' do let(:additional_setup) do role.update_attribute(:permissions, []) end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "POST /api/v3/views/bogus" do + describe 'POST /api/v3/views/bogus' do let(:send_request) do - post api_v3_paths.views_type("bogus"), body + post api_v3_paths.views_type('bogus'), body end - it_behaves_like "not found" + it_behaves_like 'not found' end end diff --git a/spec/requests/api/v3/views/index_resource_spec.rb b/spec/requests/api/v3/views/index_resource_spec.rb index 2e3fb3ba055e..f4c53de3d4e0 100644 --- a/spec/requests/api/v3/views/index_resource_spec.rb +++ b/spec/requests/api/v3/views/index_resource_spec.rb @@ -25,11 +25,11 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::Views::ViewsAPI, - "index", + 'index', content_type: :json do include API::V3::Utilities::PathHelper @@ -106,8 +106,8 @@ send_request end - context "without any filter" do - it_behaves_like "API V3 collection response", 3, 3, "Views::WorkPackagesTable" do + context 'without any filter' do + it_behaves_like 'API V3 collection response', 3, 3, 'Views::WorkPackagesTable' do let(:elements) do [ user_private_other_project_view, @@ -118,19 +118,19 @@ end end - context "with a project filter" do + context 'with a project filter' do let(:filters) do [ { - "project" => { - "operator" => "=", - "values" => [project.id.to_s] + 'project' => { + 'operator' => '=', + 'values' => [project.id.to_s] } } ] end - it_behaves_like "API V3 collection response", 2, 2, "Views::WorkPackagesTable" do + it_behaves_like 'API V3 collection response', 2, 2, 'Views::WorkPackagesTable' do let(:elements) do [ user_public_project_view, @@ -140,7 +140,7 @@ end end - context "with a type filter" do + context 'with a type filter' do let(:other_user_private_project_query) do create(:query, user: permitted_user, @@ -163,15 +163,15 @@ let(:filters) do [ { - "type" => { - "operator" => "=", - "values" => ["Views::TeamPlanner"] + 'type' => { + 'operator' => '=', + 'values' => ['Views::TeamPlanner'] } } ] end - it_behaves_like "API V3 collection response", 1, 1, "Views::TeamPlanner" do + it_behaves_like 'API V3 collection response', 1, 1, 'Views::TeamPlanner' do let(:elements) do [ user_private_project_team_planner_view @@ -180,9 +180,9 @@ end end - context "for a user without any visible queries" do + context 'for a user without any visible queries' do current_user { create(:user) } - it_behaves_like "API V3 collection response", 0, 0, "Views::WorkPackagesTable" + it_behaves_like 'API V3 collection response', 0, 0, 'Views::WorkPackagesTable' end end diff --git a/spec/requests/api/v3/views/show_resource_spec.rb b/spec/requests/api/v3/views/show_resource_spec.rb index 606db351cf70..01667b3c0069 100644 --- a/spec/requests/api/v3/views/show_resource_spec.rb +++ b/spec/requests/api/v3/views/show_resource_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::Views::ViewsAPI, - "show", + 'show', content_type: :json do include API::V3::Utilities::PathHelper @@ -61,30 +61,30 @@ send_request end - context "with a user allowed to see the query" do - it "returns 200 OK" do + context 'with a user allowed to see the query' do + it 'returns 200 OK' do expect(response.status) .to eq(200) end - it "returns the view" do + it 'returns the view' do expect(response.body) - .to be_json_eql("Views::WorkPackagesTable".to_json) - .at_path("_type") + .to be_json_eql('Views::WorkPackagesTable'.to_json) + .at_path('_type') expect(response.body) .to be_json_eql(view.id.to_json) - .at_path("id") + .at_path('id') end end - context "with a user not allowed to see the query" do + context 'with a user not allowed to see the query' do current_user do create(:user, member_with_roles: { project => role }) end - it "returns a 404 response" do + it 'returns a 404 response' do expect(last_response.status).to eq(404) end end diff --git a/spec/requests/api/v3/watcher_resource_spec.rb b/spec/requests/api/v3/watcher_resource_spec.rb index b837790c9bfc..dbe206ed6fed 100644 --- a/spec/requests/api/v3/watcher_resource_spec.rb +++ b/spec/requests/api/v3/watcher_resource_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Watcher resource", content_type: :json do +RSpec.describe 'API v3 Watcher resource', content_type: :json do include Rack::Test::Methods include API::V3::Utilities::PathHelper - shared_let(:project) { create(:project, identifier: "test_project", public: false) } + shared_let(:project) { create(:project, identifier: 'test_project', public: false) } let(:current_user) do create(:user, member_with_roles: { project => role }) end @@ -43,8 +43,8 @@ let(:work_package) { create(:work_package, project:) } let(:available_watcher) do create(:user, - firstname: "Something", - lastname: "Strange", + firstname: 'Something', + lastname: 'Strange', member_with_roles: { project => view_work_packages_role }) end @@ -58,8 +58,8 @@ let!(:watching_blocked_user) do create(:user, - login: "lockedUser", - mail: "lockedUser@gmail.com", + login: 'lockedUser', + mail: 'lockedUser@gmail.com', member_with_roles: { project => view_work_packages_role }) end let!(:existing_blocked_watcher) do @@ -75,7 +75,7 @@ existing_watcher end - describe "#get" do + describe '#get' do let(:get_path) { api_v3_paths.work_package_watchers work_package.id } let(:permissions) { %i[view_work_packages view_work_package_watchers] } @@ -83,23 +83,23 @@ get get_path end - it_behaves_like "API V3 collection response", 1, 1, "User" + it_behaves_like 'API V3 collection response', 1, 1, 'User' - context "for a user not allowed to see watchers" do + context 'for a user not allowed to see watchers' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "for a user not allowed to see work package" do + context 'for a user not allowed to see work package' do let(:permissions) { [] } - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end end - describe "#post" do + describe '#post' do let(:post_path) { api_v3_paths.work_package_watchers work_package.id } let(:post_body) do { @@ -116,15 +116,15 @@ end end - it "responds with 201" do + it 'responds with 201' do expect(subject.status).to eq(201) end - it "responds with newly added watcher" do - expect(subject.body).to be_json_eql("User".to_json).at_path("_type") + it 'responds with newly added watcher' do + expect(subject.body).to be_json_eql('User'.to_json).at_path('_type') end - it "sends mails" do + it 'sends mails' do expect(ActionMailer::Base.deliveries.size) .to be 1 @@ -137,44 +137,44 @@ watcher_changer: User.current) end - context "when user is already watcher" do + context 'when user is already watcher' do let(:new_watcher) { watching_user } - it "responds with 200" do + it 'responds with 200' do expect(subject.status).to eq(200) end - it "responds with correct watcher" do - expect(subject.body).to be_json_eql("User".to_json).at_path("_type") + it 'responds with correct watcher' do + expect(subject.body).to be_json_eql('User'.to_json).at_path('_type') end end - context "when the work package does not exist" do + context 'when the work package does not exist' do let(:post_path) { api_v3_paths.work_package_watchers 9999 } - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end - context "when the user does not exist" do + context 'when the user does not exist' do let(:post_body) do { user: { href: api_v3_paths.user(99999) } }.to_json end - it_behaves_like "not found" + it_behaves_like 'not found' end - context "when the target user is not allowed to watch the work package" do + context 'when the target user is not allowed to watch the work package' do let(:new_watcher) { create(:user) } - it_behaves_like "constraint violation" do - let(:message) { "User is not allowed to view this resource." } + it_behaves_like 'constraint violation' do + let(:message) { 'User is not allowed to view this resource.' } end end - context "when the target user is locked" do + context 'when the target user is locked' do let(:new_watcher) do user = create(:user, member_with_roles: { project => view_work_packages_role }) @@ -182,30 +182,30 @@ user end - it_behaves_like "constraint violation" do - let(:message) { "User is locked." } + it_behaves_like 'constraint violation' do + let(:message) { 'User is locked.' } end end - context "for an unauthorized user" do - context "when the current user is trying to assign another user as watcher" do + context 'for an unauthorized user' do + context 'when the current user is trying to assign another user as watcher' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "when the current user tries to watch the work package her- or himself" do + context 'when the current user tries to watch the work package her- or himself' do let(:current_user) { available_watcher } let(:new_watcher) { available_watcher } - it "responds with 201" do + it 'responds with 201' do expect(subject.status).to eq(201) end end end end - describe "#delete" do + describe '#delete' do let(:deleted_watcher) { watching_user } let(:delete_path) { api_v3_paths.watcher deleted_watcher.id, work_package.id } @@ -215,14 +215,14 @@ end end - context "for an authorized user" do + context 'for an authorized user' do let(:permissions) { %i[delete_work_package_watchers view_work_packages] } - it "responds with 204" do + it 'responds with 204' do expect(subject.status).to eq(204) end - it "sends mails" do + it 'sends mails' do expect(ActionMailer::Base.deliveries.size) .to be 1 @@ -235,47 +235,47 @@ watcher_changer: User.current) end - context "when removing nonexistent user" do + context 'when removing nonexistent user' do let(:delete_path) { api_v3_paths.watcher 9999, work_package.id } - it_behaves_like "not found" + it_behaves_like 'not found' end - context "when removing user that is not watching" do + context 'when removing user that is not watching' do let(:deleted_watcher) { available_watcher } - it "responds with 204" do + it 'responds with 204' do expect(subject.status).to eq(204) end end - context "when work package doesn't exist" do + context 'when work package doesn\'t exist' do let(:delete_path) { api_v3_paths.watcher watching_user.id, 9999 } - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end end - context "for an unauthorized user" do - context "when the current user tries to deassign another user from the watchers" do + context 'for an unauthorized user' do + context 'when the current user tries to deassign another user from the watchers' do let(:permissions) { [:view_work_packages] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end - context "when the current user tries to unwatch the work package her- or himself" do + context 'when the current user tries to unwatch the work package her- or himself' do let(:current_user) { watching_user } let(:deleted_watcher) { watching_user } - it "responds with 204" do + it 'responds with 204' do expect(subject.status).to eq(204) end end end end - describe "#available_watchers" do + describe '#available_watchers' do let(:permissions) { %i[add_work_package_watchers view_work_packages] } let(:available_watchers_path) { api_v3_paths.available_watchers work_package.id } @@ -284,12 +284,12 @@ get available_watchers_path end - it_behaves_like "API V3 collection response", 2, 2, "User" do + it_behaves_like 'API V3 collection response', 2, 2, 'User' do let(:elements) { [available_watcher, current_user] } end - context "when signaling" do - let(:select) { "total,count,elements/*" } + context 'when signaling' do + let(:select) { 'total,count,elements/*' } let(:available_watchers_path) do "#{api_v3_paths.available_watchers(work_package.id)}?select=#{select}" @@ -330,21 +330,21 @@ } end - it "is the reduced set of properties of the embedded elements" do + it 'is the reduced set of properties of the embedded elements' do expect(last_response.body) .to be_json_eql(expected.to_json) end end - context "when the user does not have the necessary permissions" do + context 'when the user does not have the necessary permissions' do let(:permissions) { [:view_work_packages] } - it "responds with 403" do + it 'responds with 403' do expect(subject.status).to be(403) end end - describe "searching for a user" do + describe 'searching for a user' do let(:available_watchers_path) do path = api_v3_paths.available_watchers work_package.id filters = %([{ "name": { "operator": "~", "values": ["#{query}"] } }]) @@ -352,16 +352,16 @@ "#{path}?filters=#{URI::RFC2396_Parser.new.escape(filters)}" end - context "when that user does not exist" do - let(:query) { "asdfasdfasdfasdf" } + context 'when that user does not exist' do + let(:query) { 'asdfasdfasdfasdf' } - it_behaves_like "API V3 collection response", 0, 0, "User" + it_behaves_like 'API V3 collection response', 0, 0, 'User' end - context "when that user does exist" do - let(:query) { "strange" } + context 'when that user does exist' do + let(:query) { 'strange' } - it_behaves_like "API V3 collection response", 1, 1, "User" + it_behaves_like 'API V3 collection response', 1, 1, 'User' end end end diff --git a/spec/requests/api/v3/wiki_pages_resource_spec.rb b/spec/requests/api/v3/wiki_pages_resource_spec.rb index d6c1f7832eb8..8b491a22f7e8 100644 --- a/spec/requests/api/v3/wiki_pages_resource_spec.rb +++ b/spec/requests/api/v3/wiki_pages_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 wiki_pages resource" do +RSpec.describe 'API v3 wiki_pages resource' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -54,32 +54,32 @@ login_as(current_user) end - describe "GET /api/v3/wiki_pages/:id" do + describe 'GET /api/v3/wiki_pages/:id' do let(:path) { api_v3_paths.wiki_page(wiki_page.id) } before do get path end - it "returns 200 OK" do + it 'returns 200 OK' do expect(subject.status) .to be(200) end - it "returns the wiki page" do + it 'returns the wiki page' do expect(subject.body) - .to be_json_eql("WikiPage".to_json) - .at_path("_type") + .to be_json_eql('WikiPage'.to_json) + .at_path('_type') expect(subject.body) .to be_json_eql(wiki_page.id.to_json) - .at_path("id") + .at_path('id') end - context "when lacking permissions" do + context 'when lacking permissions' do let(:permissions) { [] } - it "returns 404 NOT FOUND" do + it 'returns 404 NOT FOUND' do expect(subject.status) .to be(404) end diff --git a/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb b/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb index 78f161bb8f4a..02fc18fb2eb5 100644 --- a/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb +++ b/spec/requests/api/v3/work_packages/available_assignees_api_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe "API::V3::WorkPackages::AvailableAssigneesAPI" do include API::V3::Utilities::PathHelper - it_behaves_like "available principals", :assignees, work_package_scope: true do + it_behaves_like 'available principals', :assignees, work_package_scope: true do let(:base_permissions) { %i[edit_work_packages view_work_packages] } let(:href) { api_v3_paths.available_assignees_in_work_package(work_package.id) } end diff --git a/spec/requests/api/v3/work_packages/available_projects_on_create_api_spec.rb b/spec/requests/api/v3/work_packages/available_projects_on_create_api_spec.rb index b23b42a81598..070ccd96072f 100644 --- a/spec/requests/api/v3/work_packages/available_projects_on_create_api_spec.rb +++ b/spec/requests/api/v3/work_packages/available_projects_on_create_api_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::WorkPackages::AvailableProjectsOnCreateAPI do include API::V3::Utilities::PathHelper @@ -43,7 +43,7 @@ member_with_roles: { project => add_role }) end - context "with a type filter present" do + context 'with a type filter present' do let(:type) { create(:type) } let(:type_id) { type.id } let(:project_with_type) { create(:project, types: [type]) } @@ -56,36 +56,36 @@ project_with_type member - params = [type_id: { operator: "=", values: [type_id] }] + params = [type_id: { operator: '=', values: [type_id] }] escaped = CGI.escape(JSON.dump(params)) get "#{api_v3_paths.available_projects_on_create}?filters=#{escaped}" end - it_behaves_like "API V3 collection response", 1, 1, "Project" do + it_behaves_like 'API V3 collection response', 1, 1, 'Project' do let(:elements) { [project_with_type] } end end - describe "with a single project" do + describe 'with a single project' do before do project get api_v3_paths.available_projects_on_create end - context "with the necessary permissions" do - it_behaves_like "API V3 collection response", 1, 1, "Project" do + context 'with the necessary permissions' do + it_behaves_like 'API V3 collection response', 1, 1, 'Project' do let(:elements) { [project] } end end - context "without any add_work_packages permission" do + context 'without any add_work_packages permission' do let(:add_role) do create(:project_role, permissions: []) end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/api/v3/work_packages/available_projects_on_edit_api_spec.rb b/spec/requests/api/v3/work_packages/available_projects_on_edit_api_spec.rb index 832ddfee235c..90a3b82d8a13 100644 --- a/spec/requests/api/v3/work_packages/available_projects_on_edit_api_spec.rb +++ b/spec/requests/api/v3/work_packages/available_projects_on_edit_api_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API::V3::WorkPackages::AvailableProjectsOnEditAPI" do +RSpec.describe 'API::V3::WorkPackages::AvailableProjectsOnEditAPI' do include API::V3::Utilities::PathHelper let(:edit_role) do @@ -57,17 +57,17 @@ get api_v3_paths.available_projects_on_edit(work_package.id) end - context "with the necessary permissions" do - it_behaves_like "API V3 collection response", 1, 1, "Project" do + context 'with the necessary permissions' do + it_behaves_like 'API V3 collection response', 1, 1, 'Project' do let(:elements) { [target_project] } end end - context "without the edit_work_packages permission" do + context 'without the edit_work_packages permission' do let(:edit_role) do create(:project_role, permissions: [:view_work_packages]) end - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end diff --git a/spec/requests/api/v3/work_packages/available_relation_candidates_resource_spec.rb b/spec/requests/api/v3/work_packages/available_relation_candidates_resource_spec.rb index 6aa67633a335..361f0eb4dd53 100644 --- a/spec/requests/api/v3/work_packages/available_relation_candidates_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/available_relation_candidates_resource_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackages::AvailableRelationCandidatesAPI do shared_let(:user) { create(:admin) } @@ -70,11 +70,11 @@ def work_packages current_user { user } - context "with no permissions" do + context 'with no permissions' do let(:user) { create(:user) } - it "does not return any work packages" do - expect(result["errorIdentifier"]).to eq("urn:openproject-org:api:v3:errors:NotFound") + it 'does not return any work packages' do + expect(result["errorIdentifier"]).to eq('urn:openproject-org:api:v3:errors:NotFound') end end @@ -141,7 +141,7 @@ def work_packages expect(subjects).to contain_exactly(wp1.id, wp1_1.id, wp1_2.id, wp1_2_1.id, wp2_1.id, wp2_2.id) end - describe "with an already existing relationship from the work package" do + describe 'with an already existing relationship from the work package' do shared_let(:relation_wp2_to_wp2_2) do create(:relation, from: wp2, to: wp2_2, relation_type: "follows") end @@ -149,64 +149,64 @@ def work_packages shared_let(:relation_wp1_1_to_wp2) do create(:relation, from: wp1_1, to: wp2, relation_type: "follows") end - context "for a follows relationship" do - it "does not contain the work packages already related in the opposite direction nor the parent" do + context 'for a follows relationship' do + it 'does not contain the work packages already related in the opposite direction nor the parent' do expect(subjects).to contain_exactly(wp1_2.id, wp1_2_1.id, wp2_1.id) end end - context "for a precedes relationship" do + context 'for a precedes relationship' do let(:href) { "/api/v3/work_packages/#{wp2.id}/available_relation_candidates?query=WP&type=precedes" } - it "does not contain the work packages already related but the parent" do + it 'does not contain the work packages already related but the parent' do expect(subjects).to contain_exactly(wp1.id, wp1_2.id, wp1_2_1.id, wp2_1.id) end end - context "for a parent relationship" do + context 'for a parent relationship' do let(:href) { "/api/v3/work_packages/#{wp2.id}/available_relation_candidates?query=WP&type=parent" } - it "does not contain the work packages already related but the parent" do + it 'does not contain the work packages already related but the parent' do expect(subjects).to contain_exactly(wp1.id, wp1_2.id, wp1_2_1.id, wp2_1.id) end end - context "for a child relationship" do + context 'for a child relationship' do let(:href) { "/api/v3/work_packages/#{wp2.id}/available_relation_candidates?query=WP&type=child" } - it "does not contain the work packages already related nor the parent" do + it 'does not contain the work packages already related nor the parent' do expect(subjects).to contain_exactly(wp1_2.id, wp1_2_1.id, wp2_1.id) end end - context "for a relates relationship" do + context 'for a relates relationship' do let(:href) { "/api/v3/work_packages/#{wp2.id}/available_relation_candidates?query=WP&type=relates" } - it "does not contain the work packages already related but the parent" do + it 'does not contain the work packages already related but the parent' do expect(subjects).to contain_exactly(wp1.id, wp1_2.id, wp1_2_1.id, wp2_1.id) end end end end - context "when a project is archived" do + context 'when a project is archived' do let(:href) { "/api/v3/work_packages/#{wp2.id}/available_relation_candidates?query=WP" } before do project1.update_column(:active, false) end - it "does not return work packages from that project" do + it 'does not return work packages from that project' do expect(subjects).to contain_exactly(wp2_1.id, wp2_2.id) end end end - context "when the user is not an admin and has access to just one project" do + context 'when the user is not an admin and has access to just one project' do let(:user) { create(:user, member_with_permissions: { project2 => %i[view_work_packages edit_work_packages] }) } let(:href) { "/api/v3/work_packages/#{wp2.id}/available_relation_candidates?query=WP" } - it "only includes work packages from the first project" do + it 'only includes work packages from the first project' do expect(subjects).to contain_exactly(wp2_1.id, wp2_2.id) end end diff --git a/spec/requests/api/v3/work_packages/by_project_create_resource_spec.rb b/spec/requests/api/v3/work_packages/by_project_create_resource_spec.rb index 7d4706a719b2..780c2496d789 100644 --- a/spec/requests/api/v3/work_packages/by_project_create_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/by_project_create_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::WorkPackages::WorkPackagesByProjectAPI, content_type: :json do include Rack::Test::Methods @@ -41,7 +41,7 @@ let(:other_user) { nil } let(:parameters) do { - subject: "new work packages", + subject: 'new work packages', _links: { type: { href: api_v3_paths.type(project.types.first.id) @@ -64,7 +64,7 @@ end end - describe "notifications" do + describe 'notifications' do let(:other_user) do create(:user, member_with_permissions: { project => %i(view_work_packages) }, @@ -74,76 +74,76 @@ ]) end - it "creates a notification" do + it 'creates a notification' do expect(Notification.where(recipient: other_user, resource: WorkPackage.last)) .to exist end - context "without notifications" do + context 'without notifications' do let(:path) { "#{api_v3_paths.work_packages_by_project(project.id)}?notify=false" } - it "creates no notification" do + it 'creates no notification' do expect(Notification) .not_to exist end end - context "with notifications" do + context 'with notifications' do let(:path) { "#{api_v3_paths.work_packages_by_project(project.id)}?notify=true" } - it "creates a notification" do + it 'creates a notification' do expect(Notification.where(recipient: other_user, resource: WorkPackage.last)) .to exist end end end - it "returns Created(201)" do + it 'returns Created(201)' do expect(last_response.status).to eq(201) end - it "creates a work package" do + it 'creates a work package' do expect(WorkPackage.all.count).to eq(1) end - it "uses the given parameters" do + it 'uses the given parameters' do expect(WorkPackage.first.subject).to eq(parameters[:subject]) end - context "without permissions" do + context 'without permissions' do let(:current_user) { create(:user) } - it "hides the endpoint" do + it 'hides the endpoint' do expect(last_response.status).to eq(404) end end - context "with view_project permission" do + context 'with view_project permission' do # Note that this just removes the add_work_packages permission # view_project is actually provided by being a member of the project let(:permissions) { [:view_project] } - it "points out the missing permission" do + it 'points out the missing permission' do expect(last_response.status).to eq(403) end end - context "with empty parameters" do + context 'with empty parameters' do let(:parameters) { {} } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Subject can't be blank" } end - it "does not create a work package" do + it 'does not create a work package' do expect(WorkPackage.all.count).to eq(0) end end - context "with bogus parameters" do + context 'with bogus parameters' do let(:parameters) do { - bogus: "bogus", + bogus: 'bogus', _links: { type: { href: api_v3_paths.type(project.types.first.id) @@ -152,16 +152,16 @@ } end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Subject can't be blank" } end - it "does not create a work package" do + it 'does not create a work package' do expect(WorkPackage.all.count).to eq(0) end end - context "with an invalid value" do + context 'with an invalid value' do let(:parameters) do { subject: nil, @@ -173,11 +173,11 @@ } end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Subject can't be blank" } end - it "does not create a work package" do + it 'does not create a work package' do expect(WorkPackage.all.count).to eq(0) end end diff --git a/spec/requests/api/v3/work_packages/by_project_index_resource_spec.rb b/spec/requests/api/v3/work_packages/by_project_index_resource_spec.rb index 2ca4e4b1f70e..fc86d71ad427 100644 --- a/spec/requests/api/v3/work_packages/by_project_index_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/by_project_index_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::WorkPackages::WorkPackagesByProjectAPI, content_type: :json do include Rack::Test::Methods @@ -51,50 +51,50 @@ get path end - it "succeeds" do + it 'succeeds' do expect(subject.status).to eq 200 end - context "when not allowed to see the project" do + context 'when not allowed to see the project' do let(:current_user) { create(:user) } - it "fails with HTTP Not Found" do + it 'fails with HTTP Not Found' do expect(subject.status).to eq 404 end end - context "when not allowed to see work packages" do + context 'when not allowed to see work packages' do let(:permissions) { [:view_project] } - it "fails with HTTP Not Found" do + it 'fails with HTTP Not Found' do expect(subject.status).to eq 403 end end - describe "sorting" do + describe 'sorting' do let(:query) { { sortBy: '[["id", "desc"]]' } } let(:work_packages) { create_list(:work_package, 2, project:) } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { work_packages.reverse } end end - describe "filtering by priority" do + describe 'filtering by priority' do let(:query) do { filters: [ { priority: { - operator: "=", + operator: '=', values: [priority1.id.to_s] } } ].to_json } end - let(:priority1) { create(:priority, name: "Prio A") } - let(:priority2) { create(:priority, name: "Prio B") } + let(:priority1) { create(:priority, name: 'Prio A') } + let(:priority2) { create(:priority, name: 'Prio B') } let(:work_packages) do [ create(:work_package, project:, priority: priority1), @@ -102,18 +102,18 @@ ] end - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_packages.first] } end end - describe "filtering by project (one different from the project of the path)" do + describe 'filtering by project (one different from the project of the path)' do let(:query) do { filters: [ { project: { - operator: "=", + operator: '=', values: [other_project.id.to_s] } } @@ -125,15 +125,15 @@ let(:project_work_package) { create(:work_package, project:) } let(:other_project_work_package) { create(:work_package, project: other_project) } - it_behaves_like "API V3 collection response", 1, 1, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 1, 1, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [other_project_work_package] } end end - describe "grouping" do - let(:query) { { groupBy: "priority" } } - let(:priority1) { build(:priority, name: "Prio A", position: 2) } - let(:priority2) { build(:priority, name: "Prio B", position: 1) } + describe 'grouping' do + let(:query) { { groupBy: 'priority' } } + let(:priority1) { build(:priority, name: 'Prio A', position: 2) } + let(:priority2) { build(:priority, name: 'Prio B', position: 1) } let(:work_packages) do [ create(:work_package, @@ -157,8 +157,8 @@ href: api_v3_paths.priority(priority1.id) }], groupBy: { - href: api_v3_paths.query_group_by("priority"), - title: "Priority" + href: api_v3_paths.query_group_by('priority'), + title: 'Priority' } }, value: priority1.name, @@ -172,8 +172,8 @@ href: api_v3_paths.priority(priority2.id) }], groupBy: { - href: api_v3_paths.query_group_by("priority"), - title: "Priority" + href: api_v3_paths.query_group_by('priority'), + title: 'Priority' } }, value: priority2.name, @@ -181,18 +181,18 @@ } end - it_behaves_like "API V3 collection response", 3, 3, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 3, 3, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [work_packages.second, work_packages.first, work_packages.third] } end - it "contains group elements" do - expect(subject.body).to include_json(expected_group1.to_json).at_path("groups") - expect(subject.body).to include_json(expected_group2.to_json).at_path("groups") + it 'contains group elements' do + expect(subject.body).to include_json(expected_group1.to_json).at_path('groups') + expect(subject.body).to include_json(expected_group2.to_json).at_path('groups') end end - describe "displaying sums" do - let(:query) { { showSums: "true" } } + describe 'displaying sums' do + let(:query) { { showSums: 'true' } } let(:work_packages) do [ create(:work_package, project:, estimated_hours: 1), @@ -200,13 +200,13 @@ ] end - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { work_packages } end - it "contains the sum element" do + it 'contains the sum element' do expected = { - estimatedTime: "PT3H", + estimatedTime: 'PT3H', laborCosts: "0.00 EUR", materialCosts: "0.00 EUR", overallCosts: "0.00 EUR", @@ -214,7 +214,7 @@ storyPoints: nil } - expect(subject.body).to be_json_eql(expected.to_json).at_path("totalSums") + expect(subject.body).to be_json_eql(expected.to_json).at_path('totalSums') end end end diff --git a/spec/requests/api/v3/work_packages/create_form_resource_spec.rb b/spec/requests/api/v3/work_packages/create_form_resource_spec.rb index 030ae7fc5a30..bb6de3dff5fa 100644 --- a/spec/requests/api/v3/work_packages/create_form_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/create_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::WorkPackages::CreateProjectFormAPI do include Rack::Test::Methods @@ -42,44 +42,44 @@ before do login_as(user) - post path, parameters.to_json, "CONTENT_TYPE" => "application/json" + post path, parameters.to_json, 'CONTENT_TYPE' => 'application/json' end subject(:response) { last_response } - it "returns 200(OK)" do + it 'returns 200(OK)' do expect(response.status).to eq(200) end - it "is of type form" do - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + it 'is of type form' do + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') end - it "has the available_projects link for creation in the schema" do + it 'has the available_projects link for creation in the schema' do expect(response.body) .to be_json_eql(api_v3_paths.available_projects_on_create.to_json) - .at_path("_embedded/schema/project/_links/allowedValues/href") + .at_path('_embedded/schema/project/_links/allowedValues/href') end - describe "with empty parameters" do - it "has 3 validation errors" do - expect(subject.body).to have_json_size(3).at_path("_embedded/validationErrors") + describe 'with empty parameters' do + it 'has 3 validation errors' do + expect(subject.body).to have_json_size(3).at_path('_embedded/validationErrors') end - it "has a validation error on subject" do - expect(subject.body).to have_json_path("_embedded/validationErrors/subject") + it 'has a validation error on subject' do + expect(subject.body).to have_json_path('_embedded/validationErrors/subject') end - it "has a validation error on type" do - expect(subject.body).to have_json_path("_embedded/validationErrors/type") + it 'has a validation error on type' do + expect(subject.body).to have_json_path('_embedded/validationErrors/type') end - it "has a validation error on project" do - expect(subject.body).to have_json_path("_embedded/validationErrors/project") + it 'has a validation error on project' do + expect(subject.body).to have_json_path('_embedded/validationErrors/project') end end - describe "with all minimum parameters" do + describe 'with all minimum parameters' do let(:type) { project.types.first } let(:parameters) do { @@ -88,15 +88,15 @@ href: "/api/v3/projects/#{project.id}" } }, - subject: "lorem ipsum" + subject: 'lorem ipsum' } end - it "has 0 validation errors" do - expect(subject.body).to have_json_size(0).at_path("_embedded/validationErrors") + it 'has 0 validation errors' do + expect(subject.body).to have_json_size(0).at_path('_embedded/validationErrors') end - it "has the default type active in the project set" do + it 'has the default type active in the project set' do type_link = { href: "/api/v3/types/#{type.id}", title: type.name @@ -104,7 +104,7 @@ expect(subject.body) .to be_json_eql(type_link.to_json) - .at_path("_embedded/payload/_links/type") + .at_path('_embedded/payload/_links/type') end end end diff --git a/spec/requests/api/v3/work_packages/create_project_form_resource_spec.rb b/spec/requests/api/v3/work_packages/create_project_form_resource_spec.rb index 3510112baef7..47ebc50dd219 100644 --- a/spec/requests/api/v3/work_packages/create_project_form_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/create_project_form_resource_spec.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::WorkPackages::CreateProjectFormAPI, content_type: :json do include Rack::Test::Methods @@ -43,11 +43,11 @@ subject(:response) { last_response } - it "returns 200(OK)" do + it 'returns 200(OK)' do expect(response.status).to eq(200) end - it "is of type form" do - expect(response.body).to be_json_eql("Form".to_json).at_path("_type") + it 'is of type form' do + expect(response.body).to be_json_eql('Form'.to_json).at_path('_type') end end diff --git a/spec/requests/api/v3/work_packages/create_resource_spec.rb b/spec/requests/api/v3/work_packages/create_resource_spec.rb index 82026528d9c1..4389abf7a462 100644 --- a/spec/requests/api/v3/work_packages/create_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/create_resource_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Work package resource", +RSpec.describe 'API v3 Work package resource', content_type: :json do include API::V3::Utilities::PathHelper shared_let(:project) do - create(:project, identifier: "test_project", public: false) + create(:project, identifier: 'test_project', public: false) end let(:role) { create(:project_role, permissions:) } let(:permissions) { %i[add_work_packages view_project view_work_packages] + extra_permissions } @@ -44,7 +44,7 @@ create(:user, member_with_roles: { project => role }) end - describe "POST /api/v3/work_packages" do + describe 'POST /api/v3/work_packages' do let(:path) { api_v3_paths.work_packages } let(:other_user) { nil } let(:status) { build(:status, is_default: true) } @@ -52,7 +52,7 @@ let(:type) { project.types.first } let(:parameters) do { - subject: "new work packages", + subject: 'new work packages', _links: { type: { href: api_v3_paths.type(type.id) @@ -74,7 +74,7 @@ end end - describe "notifications" do + describe 'notifications' do let(:other_user) do create(:user, member_with_permissions: { project => permissions }, @@ -84,82 +84,82 @@ ]) end - it "creates a notification" do + it 'creates a notification' do expect(Notification.where(recipient: other_user, resource: WorkPackage.last)) .to exist end - context "without notifications" do + context 'without notifications' do let(:path) { "#{api_v3_paths.work_packages}?notify=false" } - it "creates no notification" do + it 'creates no notification' do expect(Notification) .not_to exist end end - context "with notifications" do + context 'with notifications' do let(:path) { "#{api_v3_paths.work_packages}?notify=true" } - it "creates a notification" do + it 'creates a notification' do expect(Notification.where(recipient: other_user, resource: WorkPackage.last)) .to exist end end end - it "returns Created(201)" do + it 'returns Created(201)' do expect(last_response.status).to eq(201) end - it "creates a work package" do + it 'creates a work package' do expect(WorkPackage.all.count).to eq(1) end - it "uses the given parameters" do + it 'uses the given parameters' do expect(WorkPackage.first.subject).to eq(parameters[:subject]) end - it "is associated with the provided project" do + it 'is associated with the provided project' do expect(WorkPackage.first.project).to eq(project) end - it "is associated with the provided type" do + it 'is associated with the provided type' do expect(WorkPackage.first.type).to eq(type) end - context "without any permissions" do + context 'without any permissions' do let(:current_user) { create(:user) } - it "hides the endpoint" do + it 'hides the endpoint' do expect(last_response.status).to eq(403) end end - context "when view_project permission is enabled" do + context 'when view_project permission is enabled' do # Note that this just removes the add_work_packages permission # view_project is actually provided by being a member of the project let(:permissions) { [:view_project] } - it "points out the missing permission" do + it 'points out the missing permission' do expect(last_response.status).to eq(403) end end - context "with empty parameters" do + context 'with empty parameters' do let(:parameters) { {} } - it_behaves_like "multiple errors", 422 + it_behaves_like 'multiple errors', 422 - it "does not create a work package" do + it 'does not create a work package' do expect(WorkPackage.all.count).to eq(0) end end - context "with bogus parameters" do + context 'with bogus parameters' do let(:parameters) do { - bogus: "bogus", + bogus: 'bogus', _links: { type: { href: api_v3_paths.type(project.types.first.id) @@ -171,43 +171,43 @@ } end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Subject can't be blank" } end - it "does not create a work package" do + it 'does not create a work package' do expect(WorkPackage.all.count).to eq(0) end end - context "when scheduled manually" do + context 'when scheduled manually' do let(:work_package) { WorkPackage.first } - context "with true" do + context 'with true' do # mind the () for the super call, those are required in rspec's super let(:parameters) { super().merge(scheduleManually: true) } - it "sets the scheduling mode to true" do + it 'sets the scheduling mode to true' do expect(work_package.schedule_manually).to be true end end - context "with false" do + context 'with false' do let(:parameters) { super().merge(scheduleManually: false) } - it "sets the scheduling mode to false" do + it 'sets the scheduling mode to false' do expect(work_package.schedule_manually).to be false end end - context "with scheduleManually absent" do - it "sets the scheduling mode to false (default)" do + context 'with scheduleManually absent' do + it 'sets the scheduling mode to false (default)' do expect(work_package.schedule_manually).to be false end end end - context "with invalid value" do + context 'with invalid value' do let(:parameters) do { subject: nil, @@ -222,20 +222,20 @@ } end - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Subject can't be blank" } end - it "does not create a work package" do + it 'does not create a work package' do expect(WorkPackage.all.count).to eq(0) end end - context "when attachments are being claimed" do + context 'when attachments are being claimed' do let(:attachment) { create(:attachment, container: nil, author: current_user) } let(:parameters) do { - subject: "subject", + subject: 'subject', _links: { type: { href: api_v3_paths.type(project.types.first.id) @@ -250,7 +250,7 @@ } end - it "creates the work package and assigns the attachments" do + it 'creates the work package and assigns the attachments' do expect(WorkPackage.count).to eq(1) work_package = WorkPackage.last @@ -260,7 +260,7 @@ end end - context "when file links are being claimed" do + context 'when file links are being claimed' do let(:storage) { create(:nextcloud_storage) } let(:file_link) do create(:file_link, @@ -271,7 +271,7 @@ end let(:parameters) do { - subject: "subject", + subject: 'subject', _links: { type: { href: api_v3_paths.type(project.types.first.id) @@ -289,28 +289,28 @@ %i[view_file_links] end - it "does not create a work packages and responds with an error " \ - "when user is not allowed to manage file links", :aggregate_failtures do + it 'does not create a work packages and responds with an error ' \ + 'when user is not allowed to manage file links', :aggregate_failtures do expect(WorkPackage.count).to eq(0) expect(last_response.body).to be_json_eql( - "urn:openproject-org:api:v3:errors:MissingPermission".to_json - ).at_path("errorIdentifier") + 'urn:openproject-org:api:v3:errors:MissingPermission'.to_json + ).at_path('errorIdentifier') end - context "when user is allowed to manage file links" do + context 'when user is allowed to manage file links' do let(:extra_permissions) do %i[view_file_links manage_file_links] end - it "creates a work package and assigns the file links", :aggregate_failtures do + it 'creates a work package and assigns the file links', :aggregate_failtures do expect(WorkPackage.count).to eq(1) work_package = WorkPackage.first expect(work_package.file_links).to eq([file_link]) - expect(work_package.file_links.first.container_type).to eq("WorkPackage") + expect(work_package.file_links.first.container_type).to eq('WorkPackage') expect(last_response.body).to be_json_eql( api_v3_paths.file_links(work_package.id).to_json - ).at_path("_links/fileLinks/href") - expect(last_response.body).to be_json_eql("1").at_path("_embedded/fileLinks/total") + ).at_path('_links/fileLinks/href') + expect(last_response.body).to be_json_eql("1").at_path('_embedded/fileLinks/total') end end end diff --git a/spec/requests/api/v3/work_packages/delete_resource_spec.rb b/spec/requests/api/v3/work_packages/delete_resource_spec.rb index ad1f45d1ef4a..21334685ce33 100644 --- a/spec/requests/api/v3/work_packages/delete_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/delete_resource_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Work package resource", +RSpec.describe 'API v3 Work package resource', content_type: :json do include API::V3::Utilities::PathHelper let(:work_package) do create(:work_package, project_id: project.id, - description: "lorem ipsum") + description: 'lorem ipsum') end let(:project) do - create(:project, identifier: "test_project", public: false) + create(:project, identifier: 'test_project', public: false) end let(:role) { create(:project_role, permissions:) } let(:permissions) { %i[view_work_packages edit_work_packages assign_versions] } @@ -52,7 +52,7 @@ user end - describe "DELETE /api/v3/work_packages/:id" do + describe 'DELETE /api/v3/work_packages/:id' do subject { last_response } let(:path) { api_v3_paths.work_package work_package.id } @@ -61,38 +61,38 @@ delete path end - context "with required permissions" do + context 'with required permissions' do let(:permissions) { %i[view_work_packages delete_work_packages] } - it "responds with HTTP No Content" do + it 'responds with HTTP No Content' do expect(subject.status).to eq 204 end - it "deletes the work package" do + it 'deletes the work package' do expect(WorkPackage.exists?(work_package.id)).to be_falsey end - context "for a non-existent work package" do + context 'for a non-existent work package' do let(:path) { api_v3_paths.work_package 1337 } - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end end - context "without permission to see work packages" do + context 'without permission to see work packages' do let(:permissions) { [] } - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end - context "without permission to delete work packages" do + context 'without permission to delete work packages' do let(:permissions) { %i[view_work_packages add_work_package_attachments] } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' - it "does not delete the work package" do + it 'does not delete the work package' do expect(WorkPackage.exists?(work_package.id)).to be_truthy end end diff --git a/spec/requests/api/v3/work_packages/form/work_package_form_resource_spec.rb b/spec/requests/api/v3/work_packages/form/work_package_form_resource_spec.rb index 9726818b86bf..1f5f69fa4e83 100644 --- a/spec/requests/api/v3/work_packages/form/work_package_form_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/form/work_package_form_resource_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Work package form resource" do +RSpec.describe 'API v3 Work package form resource' do include Rack::Test::Methods include Capybara::RSpecMatchers include API::V3::Utilities::PathHelper shared_let(:all_allowed_permissions) { %i[view_work_packages edit_work_packages assign_versions view_budgets] } shared_let(:assign_permissions) { %i[view_work_packages assign_versions] } - shared_let(:cf_all) { create(:work_package_custom_field, is_for_all: true, field_format: "text") } + shared_let(:cf_all) { create(:work_package_custom_field, is_for_all: true, field_format: 'text') } shared_let(:type) { create(:type_bug, custom_fields: [cf_all]) } shared_let(:project) { create(:project, public: false, types: [type]) } shared_let(:authorized_user) do @@ -54,327 +54,327 @@ end shared_let(:unauthorized_user) { create(:user) } - describe "#post" do + describe '#post' do let(:post_path) { api_v3_paths.work_package_form work_package.id } let(:valid_params) do { - _type: "WorkPackage", + _type: 'WorkPackage', lockVersion: work_package.lock_version } end subject(:response) { last_response } - shared_context "with post request" do + shared_context 'with post request' do before do login_as(current_user) - post post_path, (params ? params.to_json : nil), "CONTENT_TYPE" => "application/json" + post post_path, (params ? params.to_json : nil), 'CONTENT_TYPE' => 'application/json' end end - context "for a user without needed permissions" do + context 'for a user without needed permissions' do let(:params) { {} } - include_context "with post request" do + include_context 'with post request' do let(:current_user) { unauthorized_user } end - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end - context "for a user with all edit permissions" do + context 'for a user with all edit permissions' do let(:params) { nil } let(:current_user) { authorized_user } - context "with non-existing work package" do - let(:post_path) { api_v3_paths.work_package_form "eeek" } + context 'with non-existing work package' do + let(:post_path) { api_v3_paths.work_package_form 'eeek' } - include_context "with post request" + include_context 'with post request' - it_behaves_like "param validation error" do - let(:id) { "eeek" } - let(:type) { "WorkPackage" } + it_behaves_like 'param validation error' do + let(:id) { 'eeek' } + let(:type) { 'WorkPackage' } end end - context "with existing work package" do - shared_examples_for "valid payload" do + context 'with existing work package' do + shared_examples_for 'valid payload' do subject { last_response.body } it { expect(last_response.status).to eq(200) } - it { is_expected.to have_json_path("_embedded/payload") } + it { is_expected.to have_json_path('_embedded/payload') } - it { is_expected.to have_json_path("_embedded/payload/lockVersion") } + it { is_expected.to have_json_path('_embedded/payload/lockVersion') } - it { is_expected.to have_json_path("_embedded/payload/subject") } + it { is_expected.to have_json_path('_embedded/payload/subject') } - it_behaves_like "API V3 formattable", "_embedded/payload/description" do - let(:format) { "markdown" } + it_behaves_like 'API V3 formattable', '_embedded/payload/description' do + let(:format) { 'markdown' } let(:raw) { defined?(raw_value) ? raw_value : work_package.description.to_s } let(:html) do defined?(html_value) ? html_value : "

      #{work_package.description}

      " end end - it "denotes subject to be writable" do + it 'denotes subject to be writable' do expect(subject) .to be_json_eql(true) - .at_path("_embedded/schema/subject/writable") + .at_path('_embedded/schema/subject/writable') end - it "denotes version to be writable" do + it 'denotes version to be writable' do expect(subject) .to be_json_eql(true) - .at_path("_embedded/schema/version/writable") + .at_path('_embedded/schema/version/writable') end - it "denotes string custom_field to be writable" do + it 'denotes string custom_field to be writable' do expect(subject) .to be_json_eql(true) .at_path("_embedded/schema/#{cf_all.attribute_name.camelcase(:lower)}/writable") end end - shared_examples_for "valid payload with initial values" do + shared_examples_for 'valid payload with initial values' do it { expect(subject.body).to be_json_eql(work_package.lock_version.to_json) - .at_path("_embedded/payload/lockVersion") + .at_path('_embedded/payload/lockVersion') } it { expect(subject.body).to be_json_eql(work_package.subject.to_json) - .at_path("_embedded/payload/subject") + .at_path('_embedded/payload/subject') } end - shared_examples_for "having no errors" do + shared_examples_for 'having no errors' do it { expect(subject.body).to be_json_eql({}.to_json) - .at_path("_embedded/validationErrors") + .at_path('_embedded/validationErrors') } end - shared_examples_for "having an error" do |property| + shared_examples_for 'having an error' do |property| it { expect(subject.body).to have_json_path("_embedded/validationErrors/#{property}") } - describe "error body" do - let(:error_id) { "urn:openproject-org:api:v3:errors:PropertyConstraintViolation" } + describe 'error body' do + let(:error_id) { 'urn:openproject-org:api:v3:errors:PropertyConstraintViolation' } - let(:error_body) { parse_json(subject.body)["_embedded"]["validationErrors"][property] } + let(:error_body) { parse_json(subject.body)['_embedded']['validationErrors'][property] } - it { expect(error_body["errorIdentifier"]).to eq(error_id) } + it { expect(error_body['errorIdentifier']).to eq(error_id) } end end - describe "body" do - context "as empty" do - include_context "with post request" + describe 'body' do + context 'as empty' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "valid payload with initial values" + it_behaves_like 'valid payload with initial values' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' end - context "for filled" do + context 'for filled' do let(:valid_params) do { - _type: "WorkPackage", + _type: 'WorkPackage', lockVersion: work_package.lock_version } end - describe "no change" do + describe 'no change' do let(:params) { valid_params } - include_context "with post request" + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "valid payload with initial values" + it_behaves_like 'valid payload with initial values' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' end - context "for invalid content" do + context 'for invalid content' do before do allow(User).to receive(:current).and_return current_user - post post_path, "{ ,", "CONTENT_TYPE" => "application/json; charset=utf-8" + post post_path, '{ ,', 'CONTENT_TYPE' => 'application/json; charset=utf-8' end - it_behaves_like "parse error", - "unexpected comma (after ) at line 1, column 3" + it_behaves_like 'parse error', + 'unexpected comma (after ) at line 1, column 3' end - describe "lock version" do - context "with missing lock version" do + describe 'lock version' do + context 'with missing lock version' do let(:params) { valid_params.except(:lockVersion) } - include_context "with post request" + include_context 'with post request' - it_behaves_like "update conflict" + it_behaves_like 'update conflict' end - context "with stale object" do - let(:params) { valid_params.merge(subject: "Updated subject") } + context 'with stale object' do + let(:params) { valid_params.merge(subject: 'Updated subject') } before do params - work_package.subject = "I am the first!" + work_package.subject = 'I am the first!' work_package.save! end it { expect(valid_params[:lockVersion]).not_to eq(work_package.lock_version) } - include_context "with post request" + include_context 'with post request' it { expect(last_response.status).to eq(409) } - it_behaves_like "update conflict" + it_behaves_like 'update conflict' end end - describe "subject" do - include_context "with post request" + describe 'subject' do + include_context 'with post request' - context "for valid subject" do - let(:params) { valid_params.merge(subject: "Updated subject") } + context 'for valid subject' do + let(:params) { valid_params.merge(subject: 'Updated subject') } - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package subject" do - expect(subject.body).to be_json_eql("Updated subject".to_json) - .at_path("_embedded/payload/subject") + it 'responds with updated work package subject' do + expect(subject.body).to be_json_eql('Updated subject'.to_json) + .at_path('_embedded/payload/subject') end end - context "for invalid subject" do + context 'for invalid subject' do let(:params) { valid_params.merge(subject: nil) } - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having an error", "subject" + it_behaves_like 'having an error', 'subject' - it "responds with updated work package subject" do + it 'responds with updated work package subject' do expect(subject.body).to be_json_eql(nil.to_json) - .at_path("_embedded/payload/subject") + .at_path('_embedded/payload/subject') end end end - describe "description" do - let(:path) { "_embedded/payload/description/raw" } - let(:description) { "**Some text** *describing* **something**..." } + describe 'description' do + let(:path) { '_embedded/payload/description/raw' } + let(:description) { '**Some text** *describing* **something**...' } let(:params) { valid_params.merge(description: { raw: description }) } - include_context "with post request" + include_context 'with post request' - it_behaves_like "valid payload" do + it_behaves_like 'valid payload' do let(:raw_value) { description } let(:html_value) do '

      Some text describing ' \ - "something...

      " + 'something...

      ' end end - it_behaves_like "having no errors" + it_behaves_like 'having no errors' end - describe "start date" do - include_context "with post request" + describe 'start date' do + include_context 'with post request' - context "for valid date" do - let(:params) { valid_params.merge(startDate: "2015-01-31") } + context 'for valid date' do + let(:params) { valid_params.merge(startDate: '2015-01-31') } - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package" do - expect(subject.body).to be_json_eql("2015-01-31".to_json) - .at_path("_embedded/payload/startDate") + it 'responds with updated work package' do + expect(subject.body).to be_json_eql('2015-01-31'.to_json) + .at_path('_embedded/payload/startDate') end end - context "for invalid date" do - let(:params) { valid_params.merge(startDate: "not a date") } + context 'for invalid date' do + let(:params) { valid_params.merge(startDate: 'not a date') } - it_behaves_like "format error", - I18n.t("api_v3.errors.invalid_format", - property: "startDate", - expected_format: I18n.t("api_v3.errors.expected.date"), - actual: "not a date") + it_behaves_like 'format error', + I18n.t('api_v3.errors.invalid_format', + property: 'startDate', + expected_format: I18n.t('api_v3.errors.expected.date'), + actual: 'not a date') end end - describe "finish date" do - include_context "with post request" + describe 'finish date' do + include_context 'with post request' - context "for valid date" do - let(:params) { valid_params.merge(dueDate: "2015-01-31") } + context 'for valid date' do + let(:params) { valid_params.merge(dueDate: '2015-01-31') } - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package" do - expect(subject.body).to be_json_eql("2015-01-31".to_json) - .at_path("_embedded/payload/dueDate") + it 'responds with updated work package' do + expect(subject.body).to be_json_eql('2015-01-31'.to_json) + .at_path('_embedded/payload/dueDate') end end - context "for invalid date" do - let(:params) { valid_params.merge(dueDate: "not a date") } + context 'for invalid date' do + let(:params) { valid_params.merge(dueDate: 'not a date') } - it_behaves_like "format error", - I18n.t("api_v3.errors.invalid_format", - property: "dueDate", - expected_format: I18n.t("api_v3.errors.expected.date"), - actual: "not a date") + it_behaves_like 'format error', + I18n.t('api_v3.errors.invalid_format', + property: 'dueDate', + expected_format: I18n.t('api_v3.errors.expected.date'), + actual: 'not a date') end end - describe "remaining work" do - include_context "with post request" + describe 'remaining work' do + include_context 'with post request' - context "for valid duration" do - let(:params) { valid_params.merge(remainingTime: "PT12H45M") } + context 'for valid duration' do + let(:params) { valid_params.merge(remainingTime: 'PT12H45M') } - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package" do - expect(subject.body).to be_json_eql("PT12H45M".to_json) - .at_path("_embedded/payload/remainingTime") + it 'responds with updated work package' do + expect(subject.body).to be_json_eql('PT12H45M'.to_json) + .at_path('_embedded/payload/remainingTime') end end - context "for invalid duration" do - let(:params) { valid_params.merge(remainingTime: "not a duration") } + context 'for invalid duration' do + let(:params) { valid_params.merge(remainingTime: 'not a duration') } - it_behaves_like "format error", - I18n.t("api_v3.errors.invalid_format", - property: "remainingTime", - expected_format: I18n.t("api_v3.errors.expected.duration"), - actual: "not a duration") + it_behaves_like 'format error', + I18n.t('api_v3.errors.invalid_format', + property: 'remainingTime', + expected_format: I18n.t('api_v3.errors.expected.duration'), + actual: 'not a duration') end end - describe "status" do - let(:path) { "_embedded/payload/_links/status/href" } + describe 'status' do + let(:path) { '_embedded/payload/_links/status/href' } let(:target_status) { create(:status) } let(:status_link) { api_v3_paths.status target_status.id } let(:status_parameter) { { _links: { status: { href: status_link } } } } let(:params) { valid_params.merge(status_parameter) } - context "for valid status" do + context 'for valid status' do let!(:workflow) do create(:workflow, type_id: work_package.type.id, @@ -383,62 +383,62 @@ role: current_user.memberships[0].roles[0]) end - include_context "with post request" + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package status" do + it 'responds with updated work package status' do expect(subject.body).to be_json_eql(status_link.to_json).at_path(path) end - it "stills show the original allowed statuses" do + it 'stills show the original allowed statuses' do expect(subject.body).to be_json_eql(status_link.to_json) - .at_path("_embedded/schema/status/_links/allowedValues/1/href") + .at_path('_embedded/schema/status/_links/allowedValues/1/href') end end - context "for invalid status" do - context "when no transition" do - include_context "with post request" + context 'for invalid status' do + context 'when no transition' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having an error", "status" + it_behaves_like 'having an error', 'status' - it "responds with updated work package status" do + it 'responds with updated work package status' do expect(subject.body).to be_json_eql(status_link.to_json).at_path(path) end end - context "when status does not exist" do + context 'when status does not exist' do let(:error_id) do - "urn:openproject-org:api:v3:errors:MultipleErrors".to_json + 'urn:openproject-org:api:v3:errors:MultipleErrors'.to_json end let(:status_link) { api_v3_paths.status -1 } - include_context "with post request" + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having an error", "status" + it_behaves_like 'having an error', 'status' - it "responds with updated work package status" do + it 'responds with updated work package status' do expect(subject.body).to be_json_eql(status_link.to_json).at_path(path) end end - context "for wrong resource" do + context 'for wrong resource' do let(:status_link) { api_v3_paths.user authorized_user.id } - include_context "with post request" + include_context 'with post request' - it_behaves_like "invalid resource link" do + it_behaves_like 'invalid resource link' do let(:message) do - I18n.t("api_v3.errors.invalid_resource", - property: "status", - expected: "/api/v3/statuses/:id", + I18n.t('api_v3.errors.invalid_resource', + property: 'status', + expected: '/api/v3/statuses/:id', actual: status_link) end end @@ -446,8 +446,8 @@ end end - describe "assignee and responsible" do - shared_examples_for "handling people" do |property| + describe 'assignee and responsible' do + shared_examples_for 'handling people' do |property| let(:path) { "_embedded/payload/_links/#{property}/href" } let(:visible_user) do create(:user, @@ -456,36 +456,36 @@ let(:user_parameter) { { _links: { property => { href: user_link } } } } let(:params) { valid_params.merge(user_parameter) } - shared_examples_for "having updated work package principal" do + shared_examples_for 'having updated work package principal' do it "responds with updated work package #{property}" do expect(subject.body).to be_json_eql(user_link.to_json).at_path(path) end end context "valid #{property}" do - shared_examples_for "valid user assignment" do - include_context "with post request" + shared_examples_for 'valid user assignment' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it_behaves_like "having updated work package principal" + it_behaves_like 'having updated work package principal' end - context "for empty user" do + context 'for empty user' do let(:user_link) { nil } - it_behaves_like "valid user assignment" + it_behaves_like 'valid user assignment' end - context "for existing user" do + context 'for existing user' do let(:user_link) { api_v3_paths.user visible_user.id } - it_behaves_like "valid user assignment" + it_behaves_like 'valid user assignment' end - context "for existing group" do + context 'for existing group' do let(:user_link) { api_v3_paths.group group.id } let(:group) { create(:group) } let(:role) { create(:project_role, permissions: %i[work_package_assigned]) } @@ -500,41 +500,41 @@ group_member.save! end - it_behaves_like "valid user assignment" + it_behaves_like 'valid user assignment' end - context "for existing placeholder_user" do + context 'for existing placeholder_user' do let(:user_link) { api_v3_paths.placeholder_user placeholder_user.id } let(:placeholder_user) do create(:placeholder_user, member_with_permissions: { project => %i[work_package_assigned] }) end - it_behaves_like "valid user assignment" + it_behaves_like 'valid user assignment' end end context "invalid #{property}" do - context "for non-existing user" do + context 'for non-existing user' do let(:user_link) { api_v3_paths.user 4200 } - include_context "with post request" + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having an error", property + it_behaves_like 'having an error', property - it_behaves_like "having updated work package principal" + it_behaves_like 'having updated work package principal' end - context "for wrong resource" do + context 'for wrong resource' do let(:user_link) { api_v3_paths.status work_package.status.id } - include_context "with post request" + include_context 'with post request' - it_behaves_like "invalid resource link" do + it_behaves_like 'invalid resource link' do let(:message) do - I18n.t("api_v3.errors.invalid_resource", + I18n.t('api_v3.errors.invalid_resource', property:, expected: "/api/v3/groups/:id' or '/api/v3/users/:id' or '/api/v3/placeholder_users/:id", actual: user_link) @@ -544,27 +544,27 @@ end end - it_behaves_like "handling people", "assignee" + it_behaves_like 'handling people', 'assignee' - it_behaves_like "handling people", "responsible" + it_behaves_like 'handling people', 'responsible' end - describe "version" do - let(:path) { "_embedded/payload/_links/version/href" } + describe 'version' do + let(:path) { '_embedded/payload/_links/version/href' } let(:target_version) { create(:version, project:, start_date: Time.zone.today - 2.days) } let(:other_version) { create(:version, project:, start_date: Time.zone.today - 1.day) } let(:version_link) { api_v3_paths.version target_version.id } let(:version_parameter) { { _links: { version: { href: version_link } } } } let(:params) { valid_params.merge(version_parameter) } - describe "allowed values" do + describe 'allowed values' do before do other_version end - include_context "with post request" + include_context 'with post request' - it "lists all versions available for the project" do + it 'lists all versions available for the project' do [target_version, other_version].sort.each_with_index do |v, i| expect(subject.body).to be_json_eql(api_v3_paths.version(v.id).to_json) .at_path("_embedded/schema/version/_links/allowedValues/#{i}/href") @@ -572,36 +572,36 @@ end end - context "for valid version" do - include_context "with post request" + context 'for valid version' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package version" do + it 'responds with updated work package version' do expect(subject.body).to be_json_eql(version_link.to_json).at_path(path) end end end - describe "category" do - let(:path) { "_embedded/payload/_links/category/href" } - let(:links_path) { "_embedded/schema/category/_links" } + describe 'category' do + let(:path) { '_embedded/payload/_links/category/href' } + let(:links_path) { '_embedded/schema/category/_links' } let(:target_category) { create(:category, project:) } let(:other_category) { create(:category, project:) } let(:category_link) { api_v3_paths.category target_category.id } let(:category_parameter) { { _links: { category: { href: category_link } } } } let(:params) { valid_params.merge(category_parameter) } - describe "allowed values" do + describe 'allowed values' do before do other_category end - include_context "with post request" + include_context 'with post request' - it "lists the categories" do + it 'lists the categories' do [target_category, other_category].sort.each_with_index do |c, i| expect(subject.body).to be_json_eql(api_v3_paths.category(c.id).to_json) .at_path("#{links_path}/allowedValues/#{i}/href") @@ -609,22 +609,22 @@ end end - context "for valid category" do - include_context "with post request" + context 'for valid category' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package category" do + it 'responds with updated work package category' do expect(subject.body).to be_json_eql(category_link.to_json).at_path(path) end end end - describe "priority" do - let(:path) { "_embedded/payload/_links/priority/href" } - let(:links_path) { "_embedded/schema/priority/_links" } + describe 'priority' do + let(:path) { '_embedded/payload/_links/priority/href' } + let(:links_path) { '_embedded/schema/priority/_links' } let(:target_priority) { create(:priority) } let(:other_priority) { work_package.priority } let(:priority_link) { api_v3_paths.priority target_priority.id } @@ -632,14 +632,14 @@ let(:priority_parameter) { { _links: { priority: { href: priority_link } } } } let(:params) { valid_params.merge(priority_parameter) } - describe "allowed values" do + describe 'allowed values' do before do other_priority end - include_context "with post request" + include_context 'with post request' - it "lists the priorities" do + it 'lists the priorities' do expect(subject.body).to be_json_eql(priority_link.to_json) .at_path("#{links_path}/allowedValues/1/href") expect(subject.body).to be_json_eql(other_priority_link.to_json) @@ -647,22 +647,22 @@ end end - context "for valid priority" do - include_context "with post request" + context 'for valid priority' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package priority" do + it 'responds with updated work package priority' do expect(subject.body).to be_json_eql(priority_link.to_json).at_path(path) end end end - describe "type" do - let(:path) { "_embedded/payload/_links/type/href" } - let(:links_path) { "_embedded/schema/type/_links" } + describe 'type' do + let(:path) { '_embedded/payload/_links/type/href' } + let(:links_path) { '_embedded/schema/type/_links' } let(:target_type) { create(:type, custom_fields: [cf_all]) } let(:other_type) { work_package.type } let(:type_link) { api_v3_paths.type target_type.id } @@ -674,14 +674,14 @@ project.types << target_type # make sure we have a valid transition end - describe "allowed values" do + describe 'allowed values' do before do other_type end - include_context "with post request" + include_context 'with post request' - it "lists the types" do + it 'lists the types' do expect(subject.body).to be_json_eql(type_link.to_json) .at_path("#{links_path}/allowedValues/1/href") expect(subject.body).to be_json_eql(other_type_link.to_json) @@ -689,36 +689,36 @@ end end - context "for valid type" do - include_context "with post request" + context 'for valid type' do + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package type" do + it 'responds with updated work package type' do expect(subject.body).to be_json_eql(type_link.to_json).at_path(path) end end end - describe "budget" do - let(:path) { "_embedded/payload/_links/budget/href" } - let(:links_path) { "_embedded/schema/budget/_links" } + describe 'budget' do + let(:path) { '_embedded/payload/_links/budget/href' } + let(:links_path) { '_embedded/schema/budget/_links' } let(:target_budget) { create(:budget, project:) } let(:other_budget) { create(:budget, project:) } let(:budget_link) { api_v3_paths.budget target_budget.id } let(:budget_parameter) { { _links: { budget: { href: budget_link } } } } let(:params) { valid_params.merge(budget_parameter) } - describe "allowed values" do + describe 'allowed values' do before do other_budget end - include_context "with post request" + include_context 'with post request' - it "lists the budgets" do + it 'lists the budgets' do budgets = project.budgets budgets.each_with_index do |budget, index| @@ -728,30 +728,30 @@ end end - context "for valid budget" do - include_context "with post request" + context 'for valid budget' do + include_context 'with post request' - it_behaves_like "having no errors" + it_behaves_like 'having no errors' - it "responds with updated work package budget" do + it 'responds with updated work package budget' do expect(subject.body).to be_json_eql(budget_link.to_json).at_path(path) end end - context "for invalid budget" do + context 'for invalid budget' do let(:target_budget) { create(:budget) } - include_context "with post request" + include_context 'with post request' - it_behaves_like "having an error", "budget" + it_behaves_like 'having an error', 'budget' - it "responds with updated work package budget" do + it 'responds with updated work package budget' do expect(subject.body).to be_json_eql(budget_link.to_json).at_path(path) end end end - describe "multiple errors" do + describe 'multiple errors' do let(:user_link) { api_v3_paths.user 4200 } let(:status_link) { api_v3_paths.status -1 } let(:links) do @@ -765,28 +765,28 @@ end let(:params) { valid_params.merge(subject: nil).merge(links) } - include_context "with post request" + include_context 'with post request' - it_behaves_like "valid payload" + it_behaves_like 'valid payload' it { - expect(subject.body).to have_json_size(4).at_path("_embedded/validationErrors") + expect(subject.body).to have_json_size(4).at_path('_embedded/validationErrors') } - it { expect(subject.body).to have_json_path("_embedded/validationErrors/subject") } + it { expect(subject.body).to have_json_path('_embedded/validationErrors/subject') } - it { expect(subject.body).to have_json_path("_embedded/validationErrors/status") } + it { expect(subject.body).to have_json_path('_embedded/validationErrors/status') } - it { expect(subject.body).to have_json_path("_embedded/validationErrors/assignee") } + it { expect(subject.body).to have_json_path('_embedded/validationErrors/assignee') } it { - expect(subject.body).to have_json_path("_embedded/validationErrors/responsible") + expect(subject.body).to have_json_path('_embedded/validationErrors/responsible') } end - describe "formattable custom field set to nil" do + describe 'formattable custom field set to nil' do let(:custom_field) do - create(:work_package_custom_field, field_format: "text") + create(:work_package_custom_field, field_format: 'text') end let(:cf_param) { { custom_field.attribute_name(:camel_case) => nil } } @@ -799,10 +799,10 @@ work_package.save! login_as(current_user) - post post_path, (params ? params.to_json : nil), "CONTENT_TYPE" => "application/json" + post post_path, (params ? params.to_json : nil), 'CONTENT_TYPE' => 'application/json' end - it "responds with a valid body (Regression OP#37510)" do + it 'responds with a valid body (Regression OP#37510)' do expect(last_response.status).to eq(200) end end @@ -811,46 +811,46 @@ end end - context "for user with assign version permissions" do + context 'for user with assign version permissions' do let(:params) do { lockVersion: work_package.lock_version } end - include_context "with post request" do + include_context 'with post request' do let(:current_user) { authorized_assign_user } end subject { last_response.body } - shared_examples_for "valid payload" do + shared_examples_for 'valid payload' do it { expect(last_response.status).to eq(200) } - it { is_expected.to have_json_path("_embedded/payload") } + it { is_expected.to have_json_path('_embedded/payload') } - it { is_expected.to have_json_path("_embedded/payload/lockVersion") } + it { is_expected.to have_json_path('_embedded/payload/lockVersion') } - it { is_expected.to have_json_path("_embedded/payload/_links/version") } + it { is_expected.to have_json_path('_embedded/payload/_links/version') } - it { is_expected.not_to have_json_path("_embedded/payload/subject") } + it { is_expected.not_to have_json_path('_embedded/payload/subject') } end - it_behaves_like "valid payload" + it_behaves_like 'valid payload' - it "denotes subject to not be writable" do + it 'denotes subject to not be writable' do expect(subject) .to be_json_eql(false) - .at_path("_embedded/schema/subject/writable") + .at_path('_embedded/schema/subject/writable') end - it "denotes version to be writable" do + it 'denotes version to be writable' do expect(subject) .to be_json_eql(true) - .at_path("_embedded/schema/version/writable") + .at_path('_embedded/schema/version/writable') end - it "denotes custom_field to not be writable" do + it 'denotes custom_field to not be writable' do expect(subject) .to be_json_eql(false) .at_path("_embedded/schema/#{cf_all.attribute_name.camelcase(:lower)}/writable") diff --git a/spec/requests/api/v3/work_packages/index_resource_spec.rb b/spec/requests/api/v3/work_packages/index_resource_spec.rb index af5a2a60948c..e480b33eb543 100644 --- a/spec/requests/api/v3/work_packages/index_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/index_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Work package resource", +RSpec.describe 'API v3 Work package resource', content_type: :json do include API::V3::Utilities::PathHelper @@ -38,10 +38,10 @@ let(:work_package) do create(:work_package, project_id: project.id, - description: "lorem ipsum") + description: 'lorem ipsum') end let(:project) do - create(:project, identifier: "test_project", public: false) + create(:project, identifier: 'test_project', public: false) end let(:role) { create(:project_role, permissions:) } let(:permissions) { %i[view_work_packages edit_work_packages assign_versions] } @@ -50,7 +50,7 @@ create(:user, member_with_roles: { project => role }) end - describe "GET /api/v3/work_packages" do + describe 'GET /api/v3/work_packages' do subject do get path last_response @@ -64,21 +64,21 @@ work_packages end - it "succeeds" do + it 'succeeds' do expect(subject.status).to be 200 end - it "returns visible work packages" do - expect(subject.body).to be_json_eql(1.to_json).at_path("total") + it 'returns visible work packages' do + expect(subject.body).to be_json_eql(1.to_json).at_path('total') end - it "embeds the work package schemas" do + it 'embeds the work package schemas' do expect(subject.body) .to be_json_eql(api_v3_paths.work_package_schema(project.id, work_package.type.id).to_json) - .at_path("_embedded/schemas/_embedded/elements/0/_links/self/href") + .at_path('_embedded/schemas/_embedded/elements/0/_links/self/href') end - context "with filtering by typeahead" do + context 'with filtering by typeahead' do before { get path } subject { last_response } @@ -101,45 +101,45 @@ let(:other_lorem_work_package) { create(:work_package, subject: "lorem", project: lorem_project) } let(:work_packages) { [work_package, lorem_ipsum_work_package, ipsum_work_package, other_lorem_work_package] } - it_behaves_like "API V3 collection response", 2, 2, "WorkPackage", "WorkPackageCollection" do + it_behaves_like 'API V3 collection response', 2, 2, 'WorkPackage', 'WorkPackageCollection' do let(:elements) { [lorem_ipsum_work_package, ipsum_work_package] } end end - context "with a user not seeing any work packages" do + context 'with a user not seeing any work packages' do # Create a public project so that the non-member permission has something to attach to let!(:public_project) { create(:project, public: true, active: true) } let(:current_user) { create(:user) } let(:non_member_permissions) { [:view_work_packages] } - include_context "with non-member permissions from non_member_permissions" + include_context 'with non-member permissions from non_member_permissions' - it "succeeds" do + it 'succeeds' do expect(subject.status).to be 200 end - it "returns no work packages" do - expect(subject.body).to be_json_eql(0.to_json).at_path("total") + it 'returns no work packages' do + expect(subject.body).to be_json_eql(0.to_json).at_path('total') end - context "with the user not allowed to see work packages in general" do + context 'with the user not allowed to see work packages in general' do let(:non_member_permissions) { [] } before { get path } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - describe "encoded query props" do + describe 'encoded query props' do before { get path } subject { last_response } let(:props) do eprops = { - filters: [{ id: { operator: "=", values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, + filters: [{ id: { operator: '=', values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, sortBy: [%w(id asc)].to_json, pageSize: 1 }.to_json @@ -160,30 +160,30 @@ let(:work_packages) { [work_package, other_work_package, other_visible_work_package, another_visible_work_package] } - it "succeeds" do + it 'succeeds' do expect(subject.status) .to be 200 end - it "returns visible and filtered work packages" do + it 'returns visible and filtered work packages' do expect(subject.body) .to be_json_eql(2.to_json) - .at_path("total") + .at_path('total') # because of the page size expect(subject.body) .to be_json_eql(1.to_json) - .at_path("count") + .at_path('count') expect(subject.body) .to be_json_eql(work_package.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end - context "without zlibbed" do + context 'without zlibbed' do let(:props) do eprops = { - filters: [{ id: { operator: "=", values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, + filters: [{ id: { operator: '=', values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, sortBy: [%w(id asc)].to_json, pageSize: 1 }.to_json @@ -193,10 +193,10 @@ }.to_query end - it_behaves_like "param validation error" + it_behaves_like 'param validation error' end - context "non json encoded" do + context 'non json encoded' do let(:props) do eprops = "some non json string" @@ -205,13 +205,13 @@ }.to_query end - it_behaves_like "param validation error" + it_behaves_like 'param validation error' end - context "non base64 encoded" do + context 'non base64 encoded' do let(:props) do eprops = { - filters: [{ id: { operator: "=", values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, + filters: [{ id: { operator: '=', values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, sortBy: [%w(id asc)].to_json, pageSize: 1 }.to_json @@ -221,13 +221,13 @@ }.to_query end - it_behaves_like "param validation error" + it_behaves_like 'param validation error' end - context "non hash" do + context 'non hash' do let(:props) do eprops = [{ - filters: [{ id: { operator: "=", + filters: [{ id: { operator: '=', values: [work_package.id.to_s, other_visible_work_package.id.to_s] } }].to_json, sortBy: [%w(id asc)].to_json, pageSize: 1 @@ -238,18 +238,18 @@ }.to_query end - it_behaves_like "param validation error" + it_behaves_like 'param validation error' end end - context "when providing timestamps", with_ee: %i[baseline_comparison] do + context 'when providing timestamps', with_ee: %i[baseline_comparison] do subject do get path last_response end - let(:timestamps) { [Timestamp.parse("2015-01-01T00:00:00Z"), Timestamp.now] } - let(:timestamps_param) { CGI.escape(timestamps.join(",")) } + let(:timestamps) { [Timestamp.parse('2015-01-01T00:00:00Z'), Timestamp.now] } + let(:timestamps_param) { CGI.escape(timestamps.join(',')) } let(:path) { "#{api_v3_paths.work_packages}?timestamps=#{timestamps_param}" } let(:baseline_time) { timestamps.first.to_time } let(:created_at) { baseline_time - 1.day } @@ -268,7 +268,7 @@ let(:custom_field) do create(:string_wp_custom_field, - name: "String CF", + name: 'String CF', types: project.types, projects: [project]) end @@ -277,7 +277,7 @@ create(:custom_value, custom_field:, customized: work_package, - value: "This the current value") + value: 'This the current value') end let(:original_journal) { work_package.journals.first } @@ -290,11 +290,11 @@ def create_customizable_journal(journal:, custom_field:, value:) value:) end - it "succeeds" do + it 'succeeds' do expect(subject.status).to be 200 end - it "embeds the attributesByTimestamp" do + it 'embeds the attributesByTimestamp' do expect(subject.body) .to be_json_eql("The original work package".to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") @@ -302,80 +302,80 @@ def create_customizable_journal(journal:, custom_field:, value:) .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1") end - it "does not embed the attributes in attributesByTimestamp if they are the same as the current attributes" do + it 'does not embed the attributes in attributesByTimestamp if they are the same as the current attributes' do expect(subject.body) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/description") expect(subject.body) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/2/description") end - it "has the current attributes as attributes" do + it 'has the current attributes as attributes' do expect(subject.body) .to be_json_eql("The current work package".to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') end - it "has an embedded link to the baseline work package" do + it 'has an embedded link to the baseline work package' do expect(subject.body) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.first).to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/self/href") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/self/href') end - it "has the absolute timestamps within the self links of the elements" do + it 'has the absolute timestamps within the self links of the elements' do Timecop.freeze do expect(subject.body) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.map(&:absolute)).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end - it "has the absolute timestamps within the collection self link" do + it 'has the absolute timestamps within the collection self link' do Timecop.freeze do expect(subject.body) .to include_json({ timestamps: api_v3_paths.timestamps_to_param_value(timestamps.map(&:absolute)) }.to_query.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end - it "has no redundant timestamp attribute in the main section" do + it 'has no redundant timestamp attribute in the main section' do # The historic work packages have a timestamp attribute. But we do not expose that here # because the timestamp is already given in the _meta section. expect(subject.body) .not_to have_json_path("_embedded/elements/0/timestamp") end - it "has no redundant timestamp attribute in the attributesByTimestamp" do + it 'has no redundant timestamp attribute in the attributesByTimestamp' do # The historic work packages have a timestamp attribute. But we do not expose that here # because the timestamp is already given in the _meta section. expect(subject.body) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/timestamp") end - it "has the relative timestamps within the _meta timestamps" do + it 'has the relative timestamps within the _meta timestamps' do expect(subject.body) - .to be_json_eql("2015-01-01T00:00:00Z".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('2015-01-01T00:00:00Z'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') expect(subject.body) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') expect(subject.body) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/elements/0/_meta/timestamp') end - context "when a custom value changes" do + context 'when a custom value changes' do before do custom_value - create_customizable_journal(journal: original_journal, custom_field:, value: "Original value") + create_customizable_journal(journal: original_journal, custom_field:, value: 'Original value') create_customizable_journal(journal: current_journal, custom_field:, value: custom_value.value) end - it "embeds the custom fields in the attributesByTimestamp" do + it 'embeds the custom fields in the attributesByTimestamp' do expect(subject.body) - .to be_json_eql("Original value".to_json) + .to be_json_eql('Original value'.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/customField#{custom_field.id}") expect(subject.body) - .to be_json_eql("This the current value".to_json) + .to be_json_eql('This the current value'.to_json) .at_path("_embedded/elements/0/customField#{custom_field.id}") expect(subject.body) .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1") @@ -383,18 +383,18 @@ def create_customizable_journal(journal:, custom_field:, value:) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/customField#{custom_field.id}") end - it "includes a custom field description in the schema" do + it 'includes a custom field description in the schema' do expect(subject.body) .to be_json_eql(custom_field.name.to_json) .at_path("_embedded/schemas/_embedded/elements/0/customField#{custom_field.id}/name") end end - context "when a link type custom value changes" do + context 'when a link type custom value changes' do let(:original_user) { create(:user, member_with_roles: { project => role }) } let(:custom_field) do create(:user_wp_custom_field, - name: "User CF", + name: 'User CF', types: project.types, projects: [project]) end @@ -412,7 +412,7 @@ def create_customizable_journal(journal:, custom_field:, value:) create_customizable_journal(journal: current_journal, custom_field:, value: custom_value.value) end - it "embeds the custom fields in the attributesByTimestamp" do + it 'embeds the custom fields in the attributesByTimestamp' do expect(subject.body) .to be_json_eql(original_user.name.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/customField#{custom_field.id}/title") @@ -425,20 +425,20 @@ def create_customizable_journal(journal:, custom_field:, value:) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_links/customField#{custom_field.id}") end - it "includes a custom field description in the schema" do + it 'includes a custom field description in the schema' do expect(subject.body) .to be_json_eql(custom_field.name.to_json) .at_path("_embedded/schemas/_embedded/elements/0/customField#{custom_field.id}/name") end end - context "when there is a custom value in the past but not in the now as the custom field has been destroyed" do + context 'when there is a custom value in the past but not in the now as the custom field has been destroyed' do before do - create_customizable_journal(journal: original_journal, custom_field:, value: "Original value") + create_customizable_journal(journal: original_journal, custom_field:, value: 'Original value') custom_field.destroy end - it "does not embed the custom fields in the attributesByTimestamp" do + it 'does not embed the custom fields in the attributesByTimestamp' do expect(subject.body) .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0") expect(subject.body) @@ -450,14 +450,14 @@ def create_customizable_journal(journal:, custom_field:, value:) end end - context "when there is a custom value in the past but not in the now" \ - "as the custom field has been disabled for the project" do + context 'when there is a custom value in the past but not in the now' \ + 'as the custom field has been disabled for the project' do before do - create_customizable_journal(journal: original_journal, custom_field:, value: "Original value") + create_customizable_journal(journal: original_journal, custom_field:, value: 'Original value') project.update(work_package_custom_fields: []) end - it "does not embed the custom fields in the attributesByTimestamp" do + it 'does not embed the custom fields in the attributesByTimestamp' do expect(subject.body) .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0") expect(subject.body) @@ -469,13 +469,13 @@ def create_customizable_journal(journal:, custom_field:, value:) end end - context "when there is a custom value now but not in the past" do + context 'when there is a custom value now but not in the past' do before do custom_value create_customizable_journal(journal: current_journal, custom_field:, value: custom_value.value) end - it "has an empty value in the attributesByTimestamp of the past and no value in the now (since it is the current one)" do + it 'has an empty value in the attributesByTimestamp of the past and no value in the now (since it is the current one)' do expect(subject.body) .to be_json_eql(nil.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/customField#{custom_field.id}") @@ -485,21 +485,21 @@ def create_customizable_journal(journal:, custom_field:, value:) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/customField#{custom_field.id}") end - it "includes a custom field description in the schema" do + it 'includes a custom field description in the schema' do expect(subject.body) .to be_json_eql(custom_field.name.to_json) .at_path("_embedded/schemas/_embedded/elements/0/customField#{custom_field.id}/name") end end - context "when there is a custom value in the past but not now" do + context 'when there is a custom value in the past but not now' do before do - create_customizable_journal(journal: original_journal, custom_field:, value: "Original value") + create_customizable_journal(journal: original_journal, custom_field:, value: 'Original value') end - it "embeds the custom fields in the attributesByTimestamp of the past but not in the now" do + it 'embeds the custom fields in the attributesByTimestamp of the past but not in the now' do expect(subject.body) - .to be_json_eql("Original value".to_json) + .to be_json_eql('Original value'.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/customField#{custom_field.id}") expect(subject.body) .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1") @@ -507,7 +507,7 @@ def create_customizable_journal(journal:, custom_field:, value:) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/customField#{custom_field.id}") end - it "includes a custom field description in the schema" do + it 'includes a custom field description in the schema' do expect(subject.body) .to be_json_eql(custom_field.name.to_json) .at_path("_embedded/schemas/_embedded/elements/0/customField#{custom_field.id}/name") @@ -520,7 +520,7 @@ def create_customizable_journal(journal:, custom_field:, value:) [ { subject: { - operator: "~", + operator: '~', values: [search_term] } } @@ -528,26 +528,26 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "when the filters match the work package today" do - let(:search_term) { "current" } + let(:search_term) { 'current' } - it "finds the work package" do + it 'finds the work package' do expect(subject.body) .to be_json_eql(work_package.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters" do + it 'marks the work package as matching the filters' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_meta/matchesFilters') end - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/exists") + .at_path('_embedded/elements/0/_meta/exists') end end end @@ -555,18 +555,18 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "attributesByTimestamp/0 (baseline attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as not matching the filters at the baseline time" do + it 'marks the work package as not matching the filters at the baseline time' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing at the baseline time" do + it 'marks the work package as existing at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists') end end end @@ -575,18 +575,18 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "attributesByTimestamp/1 (current attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters today" do + it 'marks the work package as matching the filters today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists') end end end @@ -594,43 +594,43 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "when the filters match the work package at the baseline time" do - let(:search_term) { "original" } + let(:search_term) { 'original' } - it "finds the work package" do + it 'finds the work package' do expect(subject.body) .to be_json_eql(work_package.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end describe "_meta" do - it "marks the work package as not matching the filters in its current state" do + it 'marks the work package as not matching the filters in its current state' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_meta/matchesFilters') end - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/exists") + .at_path('_embedded/elements/0/_meta/exists') end end describe "attributesByTimestamp/0 (baseline attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters at the baseline time" do + it 'marks the work package as matching the filters at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing at the baseline time" do + it 'marks the work package as existing at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists') end end end @@ -639,18 +639,18 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "attributesByTimestamp/1 (current attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as not matching the filters today" do + it 'marks the work package as not matching the filters today' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists') end end end @@ -659,27 +659,27 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "when the work package has not been present at the baseline time" do - let(:timestamps) { [Timestamp.parse("2015-01-01T00:00:00Z"), Timestamp.now] } + let(:timestamps) { [Timestamp.parse('2015-01-01T00:00:00Z'), Timestamp.now] } let(:created_at) { 10.days.ago } describe "attributesByTimestamp" do describe "0 (baseline attributes)" do - it "has no attributes because the work package did not exist at the baseline time" do + it 'has no attributes because the work package did not exist at the baseline time' do expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") + .not_to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/subject') end describe "_meta" do describe "timestamp" do - it "has the baseline timestamp, which is the first timestmap" do + it 'has the baseline timestamp, which is the first timestmap' do expect(subject.body) .to be_json_eql(timestamps.first.to_s.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') end end describe "exists" do - it "marks the work package as not existing at the baseline time" do + it 'marks the work package as not existing at the baseline time' do expect(subject.body) .to be_json_eql(false.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists") @@ -687,7 +687,7 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "matchesFilters" do - it "marks the work package as not matching the filters at the baseline time" do + it 'marks the work package as not matching the filters at the baseline time' do expect(subject.body) .to be_json_eql(false.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") @@ -696,7 +696,7 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "_links" do - it "is not present" do + it 'is not present' do expect(subject.body) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links") end @@ -704,22 +704,22 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "1 (current attributes)" do - it "has no embedded attributes because they are the same as in the main object" do + it 'has no embedded attributes because they are the same as in the main object' do expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/subject") + .not_to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/subject') end describe "_meta" do describe "timestamp" do - it "has the current timestamp, which is the second timestamp" do + it 'has the current timestamp, which is the second timestamp' do expect(subject.body) .to be_json_eql(timestamps.last.to_s.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') end end describe "exists" do - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists") @@ -727,7 +727,7 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "matchesFilters" do - it "marks the work package as matching the filters today" do + it 'marks the work package as matching the filters today' do expect(subject.body) .to be_json_eql(true.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters") @@ -736,7 +736,7 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "_links" do - it "has a self link" do + it 'has a self link' do expect(subject.body) .to be_json_eql(api_v3_paths.work_package(work_package.id).to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_links/self/href") @@ -752,31 +752,31 @@ def create_customizable_journal(journal:, custom_field:, value:) it "has the attributes in the main object" do expect(subject.body) .to be_json_eql(work_package.subject.to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') end describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters today" do + it 'marks the work package as matching the filters today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/exists") + .at_path('_embedded/elements/0/_meta/exists') end end describe "timestamp" do - it "has the current timestamp, which is the second timestamp, in the same format as given in the request parameter" do + it 'has the current timestamp, which is the second timestamp, in the same format as given in the request parameter' do expect(subject.body) .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .at_path('_embedded/elements/0/_meta/timestamp') end end end @@ -784,16 +784,16 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "attributesByTimestamp" do it "has no attributes in the embedded objects because they are the same as in the main object" do expect(subject.body) - .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0") + .to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/0') expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") + .not_to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/subject') expect(subject.body) - .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1") + .to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/1') expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/subject") + .not_to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/subject') end - context "when the custom fields are not changed" do + context 'when the custom fields are not changed' do before do custom_field custom_value @@ -805,63 +805,63 @@ def create_customizable_journal(journal:, custom_field:, value:) value: custom_value.value) end - it "has no attributes in the embedded objects because they are the same as in the main object" do + it 'has no attributes in the embedded objects because they are the same as in the main object' do expect(subject.body) - .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0") + .to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/0') expect(subject.body) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/customField#{custom_field.id}") expect(subject.body) - .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1") + .to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp/1') expect(subject.body) .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/customField#{custom_field.id}") expect(subject.body) - .to be_json_eql("This the current value".to_json) + .to be_json_eql('This the current value'.to_json) .at_path("_embedded/elements/0/customField#{custom_field.id}") end end describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters today" do + it 'marks the work package as matching the filters today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters') end - it "marks the work package as matching the filters at the baseline time" do + it 'marks the work package as matching the filters at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists') end - it "marks the work package as existing at the baseline time" do + it 'marks the work package as existing at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists') end end describe "timestamp" do - it "has the current timestamp, which is the second timestamp, " \ - "in the same format as given in the request parameter" do + it 'has the current timestamp, which is the second timestamp, ' \ + 'in the same format as given in the request parameter' do expect(subject.body) .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') end - it "has the baseline timestamp, which is the first timestamp, " \ - "in the same format as given in the request parameter" do + it 'has the baseline timestamp, which is the first timestamp, ' \ + 'in the same format as given in the request parameter' do expect(subject.body) .to be_json_eql(timestamps.first.to_s.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') end end end @@ -874,21 +874,21 @@ def create_customizable_journal(journal:, custom_field:, value:) it "has the attributes in the main object" do expect(subject.body) .to be_json_eql(work_package.subject.to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') end it "has no _meta" do expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_meta/matchesFilters") + .not_to have_json_path('_embedded/elements/0/_meta/matchesFilters') expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_meta/exists") + .not_to have_json_path('_embedded/elements/0/_meta/exists') expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_meta/timestamp") + .not_to have_json_path('_embedded/elements/0/_meta/timestamp') end it "has no attributesByTimestamp" do expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp") + .not_to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp') end end @@ -901,48 +901,48 @@ def create_customizable_journal(journal:, custom_field:, value:) current_journal.data.update_column(:project_id, project2.id) end - it "finds the work package" do + it 'finds the work package' do expect(subject.body) .to be_json_eql(work_package.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end it "has no attributes in the main object" do expect(subject.body) - .not_to have_json_path("_embedded/elements/0/subject") + .not_to have_json_path('_embedded/elements/0/subject') expect(subject.body) - .not_to have_json_path("_embedded/elements/0/_links/project") + .not_to have_json_path('_embedded/elements/0/_links/project') end describe "_meta" do - it "marks the work package as not matching the filters" do + it 'marks the work package as not matching the filters' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_meta/matchesFilters') end - it "marks the work package as not existing today" do + it 'marks the work package as not existing today' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_meta/exists") + .at_path('_embedded/elements/0/_meta/exists') end end describe "attributesByTimestamp/0 (baseline attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters at the baseline time" do + it 'marks the work package as matching the filters at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing at the baseline time" do + it 'marks the work package as existing at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists') end end end @@ -950,31 +950,31 @@ def create_customizable_journal(journal:, custom_field:, value:) it "has all the supported attributes including those that did not change" do expect(subject.body) .to be_json_eql("The original work package".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/subject') expect(subject.body) .to be_json_eql(project.name.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/project/title") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/project/title') expect(subject.body) .to be_json_eql(current_user.name.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/assignee/title") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/assignee/title') end end describe "attributesByTimestamp/1 (current attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as not matching the filters today" do + it 'marks the work package as not matching the filters today' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as not existing today" do + it 'marks the work package as not existing today' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists') end end end @@ -990,39 +990,39 @@ def create_customizable_journal(journal:, custom_field:, value:) original_journal.data.update_columns(project_id: project2.id) end - it "finds the work package" do + it 'finds the work package' do expect(subject.body) .to be_json_eql(work_package.id.to_json) - .at_path("_embedded/elements/0/id") + .at_path('_embedded/elements/0/id') end it "has the current attributes in the main object" do expect(subject.body) .to be_json_eql(work_package.subject.to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') expect(subject.body) .to be_json_eql(api_v3_paths.project(project.id).to_json) - .at_path("_embedded/elements/0/_links/project/href") + .at_path('_embedded/elements/0/_links/project/href') end describe "_meta" do - it "marks the work package as matching the filters" do + it 'marks the work package as matching the filters' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_meta/matchesFilters') end - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_meta/exists") + .at_path('_embedded/elements/0/_meta/exists') end describe "timestamp" do - it "has the current timestamp, which is the second timestamp, in the same format as given in the request parameter" do + it 'has the current timestamp, which is the second timestamp, in the same format as given in the request parameter' do expect(subject.body) .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .at_path('_embedded/elements/0/_meta/timestamp') end end end @@ -1030,18 +1030,18 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "attributesByTimestamp/0 (baseline attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as not matching the filters at the baseline time" do + it 'marks the work package as not matching the filters at the baseline time' do expect(subject.body) .to be_json_eql(false.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing at the baseline time" do + it 'marks the work package as existing at the baseline time' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/exists') end end end @@ -1049,28 +1049,28 @@ def create_customizable_journal(journal:, custom_field:, value:) it "has all the supported attribute change" do expect(subject.body) .to be_json_eql("The original work package".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/subject') expect(subject.body) .to be_json_eql(project2.name.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/project/title") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/project/title') end end describe "attributesByTimestamp/1 (current attributes)" do describe "_meta" do describe "matchesFilters" do - it "marks the work package as matching the filters today" do + it 'marks the work package as matching the filters today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/matchesFilters') end end describe "exists" do - it "marks the work package as existing today" do + it 'marks the work package as existing today' do expect(subject.body) .to be_json_eql(true.to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/exists') end end end @@ -1089,25 +1089,25 @@ def create_customizable_journal(journal:, custom_field:, value:) it "has the current attributes of both work packages" do expect(subject.body) .to be_json_eql(work_package.subject.to_json) - .at_path("_embedded/elements/0/subject") + .at_path('_embedded/elements/0/subject') expect(subject.body) .to be_json_eql(work_package2.subject.to_json) - .at_path("_embedded/elements/1/subject") + .at_path('_embedded/elements/1/subject') end it "embeds the attributesByTimestamp for both work packages" do expect(subject.body) - .to have_json_path("_embedded/elements/0/_embedded/attributesByTimestamp") + .to have_json_path('_embedded/elements/0/_embedded/attributesByTimestamp') expect(subject.body) - .to have_json_path("_embedded/elements/1/_embedded/attributesByTimestamp") + .to have_json_path('_embedded/elements/1/_embedded/attributesByTimestamp') end it "has the attributes that are different from the current attributes in the embedded objects" do expect(subject.body) .to be_json_eql("The original work package".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/subject") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/subject') expect(subject.body) - .not_to have_json_path("_embedded/elements/1/_embedded/attributesByTimestamp/0/subject") + .not_to have_json_path('_embedded/elements/1/_embedded/attributesByTimestamp/0/subject') end end @@ -1129,49 +1129,49 @@ def create_customizable_journal(journal:, custom_field:, value:) }) end - it "displays the original date in the attributesByTimestamp" do + it 'displays the original date in the attributesByTimestamp' do expect(subject.body) .to be_json_eql(original_date.to_json) .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/date") end end - context "when the timestamps are relative date keywords" do - let(:timestamps) { [Timestamp.parse("oneWeekAgo@11:00+00:00"), Timestamp.parse("lastWorkingDay@12:00+00:00")] } + context 'when the timestamps are relative date keywords' do + let(:timestamps) { [Timestamp.parse('oneWeekAgo@11:00+00:00'), Timestamp.parse('lastWorkingDay@12:00+00:00')] } - it "has an embedded link to the baseline work package" do + it 'has an embedded link to the baseline work package' do expect(subject.body) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.first).to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/self/href") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_links/self/href') end - it "has the absolute timestamps within the self links of the elements" do + it 'has the absolute timestamps within the self links of the elements' do Timecop.freeze do expect(subject.body) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.map(&:absolute)).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end end - it "has the absolute timestamps within the collection self link" do + it 'has the absolute timestamps within the collection self link' do Timecop.freeze do expected_self_href = { timestamps: api_v3_paths.timestamps_to_param_value(timestamps.map(&:absolute)) }.to_query expect(subject.body) .to include_json(expected_self_href.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end - it "has the relative timestamps within the _meta timestamps" do + it 'has the relative timestamps within the _meta timestamps' do expect(subject.body) - .to be_json_eql("oneWeekAgo@11:00+00:00".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('oneWeekAgo@11:00+00:00'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') expect(subject.body) - .to be_json_eql("lastWorkingDay@12:00+00:00".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('lastWorkingDay@12:00+00:00'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') expect(subject.body) - .to be_json_eql("lastWorkingDay@12:00+00:00".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .to be_json_eql('lastWorkingDay@12:00+00:00'.to_json) + .at_path('_embedded/elements/0/_meta/timestamp') end describe "when the work package has not been present at the baseline time" do @@ -1181,10 +1181,10 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "0 (baseline attributes)" do describe "_meta" do describe "timestamp" do - it "has the baseline timestamp, which is the first timestmap" do + it 'has the baseline timestamp, which is the first timestmap' do expect(subject.body) - .to be_json_eql("oneWeekAgo@11:00+00:00".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('oneWeekAgo@11:00+00:00'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') end end end @@ -1193,10 +1193,10 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "1 (current attributes)" do describe "_meta" do describe "timestamp" do - it "has the current timestamp, which is the second timestamp" do + it 'has the current timestamp, which is the second timestamp' do expect(subject.body) - .to be_json_eql("lastWorkingDay@12:00+00:00".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('lastWorkingDay@12:00+00:00'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') end end end @@ -1205,15 +1205,15 @@ def create_customizable_journal(journal:, custom_field:, value:) end describe "when the work package has not changed at all between the baseline and today" do - let(:timestamps) { [Timestamp.parse("lastWorkingDay@12:00+00:00"), Timestamp.now] } + let(:timestamps) { [Timestamp.parse('lastWorkingDay@12:00+00:00'), Timestamp.now] } describe "_meta" do describe "timestamp" do - it "has the current timestamp, which is the second timestamp, " \ - "in the same format as given in the request parameter" do + it 'has the current timestamp, which is the second timestamp, ' \ + 'in the same format as given in the request parameter' do expect(subject.body) .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .at_path('_embedded/elements/0/_meta/timestamp') end end end @@ -1221,18 +1221,18 @@ def create_customizable_journal(journal:, custom_field:, value:) describe "attributesByTimestamp" do describe "_meta" do describe "timestamp" do - it "has the current timestamp, which is the second timestamp, " \ - "in the same format as given in the request parameter" do + it 'has the current timestamp, which is the second timestamp, ' \ + 'in the same format as given in the request parameter' do expect(subject.body) .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') end - it "has the baseline timestamp, which is the first timestamp, " \ - "in the same format as given in the request parameter" do + it 'has the baseline timestamp, which is the first timestamp, ' \ + 'in the same format as given in the request parameter' do expect(subject.body) - .to be_json_eql("lastWorkingDay@12:00+00:00".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('lastWorkingDay@12:00+00:00'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') end end end @@ -1243,7 +1243,7 @@ def create_customizable_journal(journal:, custom_field:, value:) context "with caching" do context "with relative timestamps" do let(:timestamps) { [Timestamp.parse("P-2D"), Timestamp.now] } - let(:created_at) { Date.parse("2015-01-01") } + let(:created_at) { Date.parse('2015-01-01') } describe "when the filter becomes outdated" do # The work package has been updated 1 day ago, which is after the baseline @@ -1257,26 +1257,26 @@ def create_customizable_journal(journal:, custom_field:, value:) [ { subject: { - operator: "~", + operator: '~', values: [search_term] } } ] end - let(:search_term) { "original" } + let(:search_term) { 'original' } - it "has the relative timestamps within the _meta timestamps" do - expect(timestamps.first.to_s).to eq("P-2D") + it 'has the relative timestamps within the _meta timestamps' do + expect(timestamps.first.to_s).to eq('P-2D') expect(timestamps.first).to be_relative expect(subject.body) - .to be_json_eql("P-2D".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('P-2D'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') expect(subject.body) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') expect(subject.body) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/elements/0/_meta/timestamp') end it "does not use an outdated cache" do @@ -1286,15 +1286,15 @@ def create_customizable_journal(journal:, custom_field:, value:) get path end end.to change { - JSON.parse(last_response.body).dig("_embedded", "elements").count + JSON.parse(last_response.body).dig('_embedded', 'elements').count }.from(1).to(0) end end end context "with relative date keyword timestamps" do - let(:timestamps) { [Timestamp.parse("oneWeekAgo@12:00+00:00"), Timestamp.now] } - let(:created_at) { Date.parse("2015-01-01") } + let(:timestamps) { [Timestamp.parse('oneWeekAgo@12:00+00:00'), Timestamp.now] } + let(:created_at) { Date.parse('2015-01-01') } describe "when the filter becomes outdated" do # The work package has been updated 1 day ago, which is after the baseline @@ -1308,26 +1308,26 @@ def create_customizable_journal(journal:, custom_field:, value:) [ { subject: { - operator: "~", + operator: '~', values: [search_term] } } ] end - let(:search_term) { "original" } + let(:search_term) { 'original' } - it "has the relative timestamps within the _meta timestamps" do - expect(timestamps.first.to_s).to eq("oneWeekAgo@12:00+00:00") + it 'has the relative timestamps within the _meta timestamps' do + expect(timestamps.first.to_s).to eq('oneWeekAgo@12:00+00:00') expect(timestamps.first).to be_relative expect(subject.body) - .to be_json_eql("oneWeekAgo@12:00+00:00".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('oneWeekAgo@12:00+00:00'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/0/_meta/timestamp') expect(subject.body) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/elements/0/_embedded/attributesByTimestamp/1/_meta/timestamp') expect(subject.body) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/elements/0/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/elements/0/_meta/timestamp') end it "does not use an outdated cache" do @@ -1337,7 +1337,7 @@ def create_customizable_journal(journal:, custom_field:, value:) get path end end.to change { - JSON.parse(last_response.body).dig("_embedded", "elements").count + JSON.parse(last_response.body).dig('_embedded', 'elements').count }.from(1).to(0) end end diff --git a/spec/requests/api/v3/work_packages/show_resource_spec.rb b/spec/requests/api/v3/work_packages/show_resource_spec.rb index 9fb934c6cb1f..05438fa1c49d 100644 --- a/spec/requests/api/v3/work_packages/show_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/show_resource_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Work package resource", +RSpec.describe 'API v3 Work package resource', content_type: :json do include Rack::Test::Methods include Capybara::RSpecMatchers include API::V3::Utilities::PathHelper - shared_let(:project) { create(:project, identifier: "test_project", public: false) } + shared_let(:project) { create(:project, identifier: 'test_project', public: false) } shared_let(:closed_status) { create(:closed_status) } shared_let(:priority) { create(:priority) } shared_let(:status) { create(:status) } @@ -55,24 +55,24 @@ let(:work_package) do create(:work_package, project_id: project.id, - description: "lorem ipsum") + description: 'lorem ipsum') end current_user { user } - describe "GET /api/v3/work_packages/:id" do + describe 'GET /api/v3/work_packages/:id' do let(:get_path) { api_v3_paths.work_package work_package.id } - context "when acting as a user with permission to view work package" do + context 'when acting as a user with permission to view work package' do before do get get_path end - it "responds with 200" do + it 'responds with 200' do expect(last_response.status).to eq(200) end - describe "response body" do + describe 'response body' do subject { last_response.body } shared_let(:other_wp) { create(:work_package, status: closed_status) } @@ -106,29 +106,29 @@ DESCRIPTION end - it "responds with work package in HAL+JSON format" do + it 'responds with work package in HAL+JSON format' do expect(subject) .to be_json_eql(work_package.id.to_json) - .at_path("id") + .at_path('id') end describe "description" do - subject { JSON.parse(last_response.body)["description"] } + subject { JSON.parse(last_response.body)['description'] } - it "renders to html" do - expect(subject).to have_css("h1") - expect(subject).to have_css("h2") + it 'renders to html' do + expect(subject).to have_css('h1') + expect(subject).to have_css('h2') # resolves links - expect(subject["html"]) + expect(subject['html']) .to have_css("opce-macro-wp-quickinfo[data-id='#{other_wp.id}']") # resolves macros, e.g. toc - expect(subject["html"]) - .to have_css(".op-uc-toc--list-item", text: "OpenProject Masterplan for 2015") + expect(subject['html']) + .to have_css('.op-uc-toc--list-item', text: "OpenProject Masterplan for 2015") end end - describe "derived dates" do + describe 'derived dates' do let(:children) do # This will be in another project but the user is still allowed to see the dates [create(:work_package, @@ -136,18 +136,18 @@ due_date: Time.zone.today + 5.days)] end - it "has derived dates" do + it 'has derived dates' do expect(subject) .to be_json_eql(Time.zone.today.to_json) - .at_path("derivedStartDate") + .at_path('derivedStartDate') expect(subject) .to be_json_eql((Time.zone.today + 5.days).to_json) - .at_path("derivedDueDate") + .at_path('derivedDueDate') end end - describe "relations" do + describe 'relations' do let(:directly_related_wp) do create(:work_package, project_id: project.id) end @@ -158,41 +158,41 @@ let(:work_package) do create(:work_package, project_id: project.id, - description: "lorem ipsum").tap do |wp| + description: 'lorem ipsum').tap do |wp| create(:relation, relation_type: Relation::TYPE_RELATES, from: wp, to: directly_related_wp) create(:relation, relation_type: Relation::TYPE_RELATES, from: directly_related_wp, to: transitively_related_wp) end end - it "embeds all direct relations" do + it 'embeds all direct relations' do expect(subject) .to be_json_eql(1.to_json) - .at_path("_embedded/relations/total") + .at_path('_embedded/relations/total') expect(subject) .to be_json_eql(api_v3_paths.work_package(directly_related_wp.id).to_json) - .at_path("_embedded/relations/_embedded/elements/0/_links/to/href") + .at_path('_embedded/relations/_embedded/elements/0/_links/to/href') end end - describe "remaining time" do - it { is_expected.to be_json_eql("PT5H".to_json).at_path("remainingTime") } + describe 'remaining time' do + it { is_expected.to be_json_eql('PT5H'.to_json).at_path('remainingTime') } end - describe "derived remaining time" do - it { is_expected.to be_json_eql(nil.to_json).at_path("derivedRemainingTime") } + describe 'derived remaining time' do + it { is_expected.to be_json_eql(nil.to_json).at_path('derivedRemainingTime') } end end - context "when requesting nonexistent work package" do + context 'when requesting nonexistent work package' do let(:get_path) { api_v3_paths.work_package 909090 } - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end end - context "when acting as a user without permission to view work package" do + context 'when acting as a user without permission to view work package' do shared_let(:unauthorized_user) { create(:user) } current_user { unauthorized_user } @@ -201,34 +201,34 @@ get get_path end - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end - context "when acting as an anonymous user" do + context 'when acting as an anonymous user' do current_user { User.anonymous } before do get get_path end - it_behaves_like "not found response based on login_required", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found response based on login_required', + I18n.t('api_v3.errors.not_found.work_package') end end - describe "GET /api/v3/work_packages/:id?timestamps=" do - let(:timestamps_param) { CGI.escape(timestamps.map(&:to_s).join(",")) } + describe 'GET /api/v3/work_packages/:id?timestamps=' do + let(:timestamps_param) { CGI.escape(timestamps.map(&:to_s).join(',')) } let(:get_path) { "#{api_v3_paths.work_package(work_package.id)}?timestamps=#{timestamps_param}" } - describe "response body" do + describe 'response body' do subject do get get_path last_response.body end - context "when providing timestamps" do - let(:timestamps) { [Timestamp.parse("2015-01-01T00:00:00Z"), Timestamp.now] } + context 'when providing timestamps' do + let(:timestamps) { [Timestamp.parse('2015-01-01T00:00:00Z'), Timestamp.now] } let(:baseline_time) { timestamps.first.to_time } let(:created_at) { baseline_time - 1.day } @@ -246,33 +246,33 @@ let(:original_journal) { work_package.journals.first } let(:current_journal) { work_package.journals.last } - context "with EE", with_ee: %i[baseline_comparison] do - it "responds with 200" do + context 'with EE', with_ee: %i[baseline_comparison] do + it 'responds with 200' do expect(subject && last_response.status).to eq(200) end - it "has the current attributes as attributes" do + it 'has the current attributes as attributes' do expect(subject) .to be_json_eql("The current work package".to_json) - .at_path("subject") + .at_path('subject') end - it "has an embedded link to the baseline work package" do + it 'has an embedded link to the baseline work package' do expect(subject) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.first).to_json) - .at_path("_embedded/attributesByTimestamp/0/_links/self/href") + .at_path('_embedded/attributesByTimestamp/0/_links/self/href') end - it "has the absolute timestamps within the self link" do + it 'has the absolute timestamps within the self link' do Timecop.freeze do expect(subject) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.map(&:absolute)).to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end describe "attributesByTimestamp" do - it "embeds the attributesByTimestamp" do + it 'embeds the attributesByTimestamp' do expect(subject) .to be_json_eql("The original work package".to_json) .at_path("_embedded/attributesByTimestamp/0/subject") @@ -280,29 +280,29 @@ .to have_json_path("_embedded/attributesByTimestamp/1") end - it "does not embed the attributes in attributesByTimestamp if they are the same as the current attributes" do + it 'does not embed the attributes in attributesByTimestamp if they are the same as the current attributes' do expect(subject) .not_to have_json_path("_embedded/attributesByTimestamp/0/description") expect(subject) .not_to have_json_path("_embedded/attributesByTimestamp/1/description") end - describe "_meta" do - describe "timestamp" do - it "has the relative timestamps" do + describe '_meta' do + describe 'timestamp' do + it 'has the relative timestamps' do expect(subject) - .to be_json_eql("2015-01-01T00:00:00Z".to_json) - .at_path("_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('2015-01-01T00:00:00Z'.to_json) + .at_path('_embedded/attributesByTimestamp/0/_meta/timestamp') expect(subject) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/attributesByTimestamp/1/_meta/timestamp') end end end end describe "when the work package has not been present at the baseline time" do - let(:timestamps) { [Timestamp.parse("2015-01-01T00:00:00Z"), Timestamp.now] } + let(:timestamps) { [Timestamp.parse('2015-01-01T00:00:00Z'), Timestamp.now] } let(:created_at) { 10.days.ago } describe "attributesByTimestamp" do @@ -333,7 +333,7 @@ end describe "when the work package does not exist at the only requested timestamp" do - let(:timestamps) { [Timestamp.parse("2015-01-01T00:00:00Z")] } + let(:timestamps) { [Timestamp.parse('2015-01-01T00:00:00Z')] } let(:created_at) { 10.days.ago } describe "attributesByTimestamp" do @@ -360,7 +360,7 @@ context "with caching" do context "with relative timestamps" do let(:timestamps) { [Timestamp.parse("P-2D"), Timestamp.now] } - let(:created_at) { Date.parse("2015-01-01") } + let(:created_at) { Date.parse('2015-01-01') } describe "attributesByTimestamp" do it "does not cache the self link" do @@ -409,33 +409,33 @@ end end - context "when the timestamps are relative date keywords" do - let(:timestamps) { [Timestamp.new("oneWeekAgo@12:00+00:00"), Timestamp.now] } + context 'when the timestamps are relative date keywords' do + let(:timestamps) { [Timestamp.new('oneWeekAgo@12:00+00:00'), Timestamp.now] } - it "has an embedded link to the baseline work package" do + it 'has an embedded link to the baseline work package' do expect(subject) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.first).to_json) - .at_path("_embedded/attributesByTimestamp/0/_links/self/href") + .at_path('_embedded/attributesByTimestamp/0/_links/self/href') end - it "has the absolute timestamps within the self link" do + it 'has the absolute timestamps within the self link' do Timecop.freeze do expect(subject) .to be_json_eql(api_v3_paths.work_package(work_package.id, timestamps: timestamps.map(&:absolute)).to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end describe "attributesByTimestamp" do - describe "_meta" do - describe "timestamp" do - it "has the relative timestamps" do + describe '_meta' do + describe 'timestamp' do + it 'has the relative timestamps' do expect(subject) - .to be_json_eql("oneWeekAgo@12:00+00:00".to_json) - .at_path("_embedded/attributesByTimestamp/0/_meta/timestamp") + .to be_json_eql('oneWeekAgo@12:00+00:00'.to_json) + .at_path('_embedded/attributesByTimestamp/0/_meta/timestamp') expect(subject) - .to be_json_eql("PT0S".to_json) - .at_path("_embedded/attributesByTimestamp/1/_meta/timestamp") + .to be_json_eql('PT0S'.to_json) + .at_path('_embedded/attributesByTimestamp/1/_meta/timestamp') end end end @@ -444,7 +444,7 @@ context "with caching" do context "with relative timestamps" do let(:timestamps) { [Timestamp.parse("oneDayAgo@00:00+00:00"), Timestamp.now] } - let(:created_at) { Date.parse("2015-01-01") } + let(:created_at) { Date.parse('2015-01-01') } describe "attributesByTimestamp" do it "does not cache the self link" do @@ -499,20 +499,20 @@ end end - context "without EE" do - shared_examples "success" do - it "responds with 200" do + context 'without EE' do + shared_examples 'success' do + it 'responds with 200' do expect(subject && last_response.status).to eq(200) end end - shared_examples "error" do - it "responds with 400" do + shared_examples 'error' do + it 'responds with 400' do expect(subject && last_response.status).to eq(400) end - it "has the invalid timestamps message" do - message = JSON.parse(subject)["message"] + it 'has the invalid timestamps message' do + message = JSON.parse(subject)['message'] expect(message) .to eq("Bad request: Timestamps contain forbidden values: #{timestamps.join(',')}") end @@ -521,44 +521,44 @@ context "when the 'oneDayAgo' value is provided" do let(:timestamps) { [Timestamp.parse("oneDayAgo@12:00+00:00")] } - it_behaves_like "success" + it_behaves_like 'success' end context "when the shortcut value 'now' is provided" do let(:timestamps) { [Timestamp.parse("now")] } - it_behaves_like "success" + it_behaves_like 'success' end context "when the 'PT0S' duration value is provided" do let(:timestamps) { [Timestamp.parse("PT0S")] } - it_behaves_like "success" + it_behaves_like 'success' end context "when the 'P-1D' duration value is provided" do let(:timestamps) { [Timestamp.parse("P-1D")] } - it_behaves_like "success" + it_behaves_like 'success' end context "when an iso8601 datetime value from yesterday is provided" do let(:timestamps) { [1.day.ago.beginning_of_day.iso8601] } - it_behaves_like "success" + it_behaves_like 'success' end context "when the 'lastWorkingDay' value is provided and it's yesterday" do let(:timestamps) { [Timestamp.parse("lastWorkingDay@00:00+00:00")] } - it_behaves_like "success" + it_behaves_like 'success' end Timestamp::ALLOWED_DATE_KEYWORDS[2..].each do |timestamp_date_keyword| context "when the '#{timestamp_date_keyword}' value is provided" do let(:timestamps) { [Timestamp.parse("#{timestamp_date_keyword}@12:00+00:00")] } - it_behaves_like "error" + it_behaves_like 'error' end end @@ -569,19 +569,19 @@ allow(Day).to receive(:last_working) { Day.new(date: 7.days.ago) } end - it_behaves_like "error" + it_behaves_like 'error' end context "when a duration value older than yesterday is provided" do let(:timestamps) { [Timestamp.parse("P-2D")] } - it_behaves_like "error" + it_behaves_like 'error' end context "when an iso8601 datetime value older than yesterday is provided" do let(:timestamps) { [2.days.ago.end_of_day.iso8601] } - it_behaves_like "error" + it_behaves_like 'error' end end end diff --git a/spec/requests/api/v3/work_packages/update_resource_spec.rb b/spec/requests/api/v3/work_packages/update_resource_spec.rb index 3d55cb6a288f..d16d6404850d 100644 --- a/spec/requests/api/v3/work_packages/update_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/update_resource_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "API v3 Work package resource", +RSpec.describe 'API v3 Work package resource', content_type: :json do include API::V3::Utilities::PathHelper @@ -37,13 +37,13 @@ shared_let(:closed_status) { create(:closed_status) } shared_let(:project) do - create(:project, identifier: "test_project", public: false) + create(:project, identifier: 'test_project', public: false) end let(:work_package) do create(:work_package, project:, - description: "lorem ipsum") + description: 'lorem ipsum') end let(:role) { create(:project_role, permissions:) } let(:permissions) { %i[view_work_packages edit_work_packages assign_versions work_package_assigned] } @@ -52,36 +52,36 @@ create(:user, member_with_roles: { project => role }) end - describe "PATCH /api/v3/work_packages/:id" do + describe 'PATCH /api/v3/work_packages/:id' do let(:patch_path) { api_v3_paths.work_package work_package.id } let(:valid_params) do { - _type: "WorkPackage", + _type: 'WorkPackage', lockVersion: work_package.lock_version } end subject(:response) { last_response } - shared_context "patch request" do + shared_context 'patch request' do before do patch patch_path, params.to_json end end - context "user without needed permissions" do - context "no permission to see the work package" do + context 'user without needed permissions' do + context 'no permission to see the work package' do let(:work_package) { create(:work_package) } let(:current_user) { create(:user) } let(:params) { valid_params } - include_context "patch request" + include_context 'patch request' - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') end - context "no permission to edit the work package" do + context 'no permission to edit the work package' do let(:role) { create(:project_role, permissions: %i[view_work_packages add_work_package_attachments]) } let(:current_user) do create(:user, @@ -89,23 +89,23 @@ end let(:params) { valid_params } - include_context "patch request" + include_context 'patch request' - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end - context "user with needed permissions" do - shared_examples_for "lock version updated" do + context 'user with needed permissions' do + shared_examples_for 'lock version updated' do it { expect(subject.body) .to be_json_eql(work_package.reload.lock_version) - .at_path("lockVersion") + .at_path('lockVersion') } end - describe "notification" do - let(:update_params) { valid_params.merge(subject: "Updated subject") } + describe 'notification' do + let(:update_params) { valid_params.merge(subject: 'Updated subject') } let(:other_user) do create(:user, member_with_permissions: { work_package.project => %i(view_work_packages) }, @@ -124,161 +124,161 @@ end end - context "without the parameter" do + context 'without the parameter' do let(:params) { update_params } - it "creates a notification" do + it 'creates a notification' do expect(Notification.where(recipient: other_user, resource: work_package)) .to exist end end - context "with the parameter disabling notifications" do + context 'with the parameter disabling notifications' do let(:patch_path) { "#{api_v3_paths.work_package work_package.id}?notify=false" } let(:params) { update_params } - it "creates no notification" do + it 'creates no notification' do expect(Notification) .not_to exist end end - context "with the parameter enabling notifications" do + context 'with the parameter enabling notifications' do let(:patch_path) { "#{api_v3_paths.work_package work_package.id}?notify=Something" } let(:params) { update_params } - it "creates a notification" do + it 'creates a notification' do expect(Notification.where(recipient: other_user, resource: work_package)) .to exist end end end - context "subject" do - let(:params) { valid_params.merge(subject: "Updated subject") } + context 'subject' do + let(:params) { valid_params.merge(subject: 'Updated subject') } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with updated work package subject" do - expect(subject.body).to be_json_eql("Updated subject".to_json).at_path("subject") + it 'responds with updated work package subject' do + expect(subject.body).to be_json_eql('Updated subject'.to_json).at_path('subject') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' - context "for a user having assign_versions but lacking edit_work_packages permission" do + context 'for a user having assign_versions but lacking edit_work_packages permission' do let(:permissions) { %i[view_work_packages assign_versions] } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(422) } - it "has a readonly error" do + it 'has a readonly error' do expect(response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyIsReadOnly".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyIsReadOnly'.to_json) + .at_path('errorIdentifier') end end end - context "description" do - shared_examples_for "description updated" do - it_behaves_like "API V3 formattable", "description" do - let(:format) { "markdown" } + context 'description' do + shared_examples_for 'description updated' do + it_behaves_like 'API V3 formattable', 'description' do + let(:format) { 'markdown' } subject { response.body } end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "w/o value (empty)" do + context 'w/o value (empty)' do let(:raw) { nil } - let(:html) { "" } + let(:html) { '' } let(:params) { valid_params.merge(description: { raw: nil }) } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it_behaves_like "description updated" + it_behaves_like 'description updated' end - context "with value" do - let(:raw) { "**Some text** *describing* **something**..." } + context 'with value' do + let(:raw) { '**Some text** *describing* **something**...' } let(:html) do '

      Some text describing something...

      ' end let(:params) { valid_params.merge(description: { raw: }) } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it_behaves_like "description updated" + it_behaves_like 'description updated' end end - context "schedule manually" do + context 'schedule manually' do let(:schedule_manually) { true } let(:params) { valid_params.merge(scheduleManually: schedule_manually) } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it "updates the scheduling mode" do - expect(subject.body).to be_json_eql(schedule_manually.to_json).at_path("scheduleManually") + it 'updates the scheduling mode' do + expect(subject.body).to be_json_eql(schedule_manually.to_json).at_path('scheduleManually') end end - context "start date" do + context 'start date' do let(:date_string) { Date.current.iso8601 } let(:params) { valid_params.merge(startDate: date_string) } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with updated start date" do - expect(subject.body).to be_json_eql(date_string.to_json).at_path("startDate") + it 'responds with updated start date' do + expect(subject.body).to be_json_eql(date_string.to_json).at_path('startDate') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "finish date" do + context 'finish date' do let(:date_string) { Date.current.iso8601 } let(:params) { valid_params.merge(dueDate: date_string) } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with updated finish date" do - expect(subject.body).to be_json_eql(date_string.to_json).at_path("dueDate") + it 'responds with updated finish date' do + expect(subject.body).to be_json_eql(date_string.to_json).at_path('dueDate') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - describe "remaining time" do - let(:duration) { "PT12H30M" } + describe 'remaining time' do + let(:duration) { 'PT12H30M' } let(:params) { valid_params.merge(remainingTime: duration) } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } # rubocop:disable RSpec/Rails/HaveHttpStatus - it "responds with updated finish date" do - expect(subject.body).to be_json_eql(duration.to_json).at_path("remainingTime") + it 'responds with updated finish date' do + expect(subject.body).to be_json_eql(duration.to_json).at_path('remainingTime') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "status" do + context 'status' do let(:target_status) { create(:status) } let(:status_link) { api_v3_paths.status target_status.id } let(:status_parameter) { { _links: { status: { href: status_link } } } } @@ -286,7 +286,7 @@ before { allow(User).to receive(:current).and_return current_user } - context "valid status" do + context 'valid status' do let!(:workflow) do create(:workflow, type_id: work_package.type.id, @@ -295,46 +295,46 @@ role: current_user.memberships[0].roles[0]) end - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with updated work package status" do + it 'responds with updated work package status' do expect(subject.body).to be_json_eql(target_status.name.to_json) - .at_path("_embedded/status/name") + .at_path('_embedded/status/name') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "invalid status" do - include_context "patch request" + context 'invalid status' do + include_context 'patch request' - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) do - "Status " + I18n.t("activerecord.errors.models." \ - "work_package.attributes.status_id.status_transition_invalid") + 'Status ' + I18n.t('activerecord.errors.models.' \ + 'work_package.attributes.status_id.status_transition_invalid') end end end - context "wrong resource" do + context 'wrong resource' do let(:status_link) { api_v3_paths.user current_user.id } - include_context "patch request" + include_context 'patch request' - it_behaves_like "invalid resource link" do + it_behaves_like 'invalid resource link' do let(:message) do - I18n.t("api_v3.errors.invalid_resource", - property: "status", - expected: "/api/v3/statuses/:id", + I18n.t('api_v3.errors.invalid_resource', + property: 'status', + expected: '/api/v3/statuses/:id', actual: status_link) end end end end - context "type" do + context 'type' do let(:target_type) { create(:type) } let(:type_link) { api_v3_paths.type target_type.id } let(:type_parameter) { { _links: { type: { href: type_link } } } } @@ -342,24 +342,24 @@ before { allow(User).to receive(:current).and_return current_user } - context "valid type" do + context 'valid type' do before do project.types << target_type end - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with updated work package type" do + it 'responds with updated work package type' do expect(subject.body).to be_json_eql(target_type.name.to_json) - .at_path("_embedded/type/name") + .at_path('_embedded/type/name') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "valid type changing custom fields" do + context 'valid type changing custom fields' do let(:custom_field) { create(:work_package_custom_field) } let(:custom_field_parameter) { { custom_field.attribute_name(:camel_case) => true } } let(:params) { valid_params.merge(type_parameter).merge(custom_field_parameter) } @@ -370,40 +370,40 @@ target_type.custom_fields << custom_field end - include_context "patch request" + include_context 'patch request' - it "responds with the new custom field having the desired value" do + it 'responds with the new custom field having the desired value' do expect(subject.body) .to be_json_eql(true.to_json) .at_path("customField#{custom_field.id}") end end - context "invalid type" do - include_context "patch request" + context 'invalid type' do + include_context 'patch request' - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Type #{I18n.t('activerecord.errors.messages.inclusion')}" } end end - context "wrong resource" do + context 'wrong resource' do let(:type_link) { api_v3_paths.user current_user.id } - include_context "patch request" + include_context 'patch request' - it_behaves_like "invalid resource link" do + it_behaves_like 'invalid resource link' do let(:message) do - I18n.t("api_v3.errors.invalid_resource", - property: "type", - expected: "/api/v3/types/:id", + I18n.t('api_v3.errors.invalid_resource', + property: 'type', + expected: '/api/v3/types/:id', actual: type_link) end end end end - context "project" do + context 'project' do let(:target_project) do create(:project, public: false) end @@ -421,25 +421,25 @@ allow(User).to receive(:current).and_return current_user end - context "is changed" do - include_context "patch request" + context 'is changed' do + include_context 'patch request' - it "is successful" do + it 'is successful' do expect(response.status).to eq(200) end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' - it "responds with the project changed" do + it 'responds with the project changed' do href = { href: project_link, title: target_project.name } - expect(response.body).to be_json_eql(href.to_json).at_path("_links/project") + expect(response.body).to be_json_eql(href.to_json).at_path('_links/project') end end - context "with a custom field defined on the target project" do + context 'with a custom field defined on the target project' do let(:member_permissions) { %i[move_work_packages edit_work_packages] } let(:custom_field) { create(:work_package_custom_field) } let(:custom_field_parameter) { { custom_field.attribute_name(:camel_case) => true } } @@ -450,9 +450,9 @@ work_package.type.custom_fields << custom_field end - include_context "patch request" + include_context 'patch request' - it "responds with the new custom field having the desired value" do + it 'responds with the new custom field having the desired value' do expect(subject.body) .to be_json_eql(true.to_json) .at_path("customField#{custom_field.id}") @@ -460,7 +460,7 @@ end end - context "assignee and responsible" do + context 'assignee and responsible' do let(:user) { create(:user, member_with_permissions: { project => %i[work_package_assigned] }) } let(:placeholder_user) do create(:placeholder_user, @@ -476,7 +476,7 @@ before { login_as current_user } - shared_context "setup group membership" do + shared_context 'setup group membership' do let(:group) { create(:group) } let(:group_role) { create(:project_role, permissions: %i[work_package_assigned]) } let!(:group_member) do @@ -487,24 +487,24 @@ end end - shared_examples_for "handling people" do |property| + shared_examples_for 'handling people' do |property| let(:user_parameter) { { _links: { property => { href: user_href } } } } let(:href_path) { "_links/#{property}/href" } - describe "nil" do + describe 'nil' do let(:user_href) { nil } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(200) } it { expect(response.body).to be_json_eql(nil.to_json).at_path(href_path) } - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - describe "valid" do - shared_examples_for "valid user assignment" do + describe 'valid' do + shared_examples_for 'valid user assignment' do let(:title) { assigned_user.name.to_s.to_json } it { expect(response.status).to eq(200) } @@ -515,76 +515,76 @@ .at_path("_links/#{property}/title") } - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "user" do + context 'user' do let(:user_href) { api_v3_paths.user user.id } - include_context "patch request" + include_context 'patch request' - it_behaves_like "valid user assignment" do + it_behaves_like 'valid user assignment' do let(:assigned_user) { user } end end - context "group" do + context 'group' do let(:user_href) { api_v3_paths.user group.id } - include_context "setup group membership", true - include_context "patch request" + include_context 'setup group membership', true + include_context 'patch request' - it_behaves_like "valid user assignment" do + it_behaves_like 'valid user assignment' do let(:assigned_user) { group } end end - context "placeholder user" do + context 'placeholder user' do let(:user_href) { api_v3_paths.placeholder_user placeholder_user.id } - include_context "patch request" + include_context 'patch request' - it_behaves_like "valid user assignment" do + it_behaves_like 'valid user assignment' do let(:assigned_user) { placeholder_user } end end end - describe "invalid" do - include_context "patch request" + describe 'invalid' do + include_context 'patch request' - context "user doesn't exist" do + context 'user doesn\'t exist' do let(:user_href) { api_v3_paths.user 909090 } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) do - I18n.t("api_v3.errors.validation." \ - "invalid_user_assigned_to_work_package", + I18n.t('api_v3.errors.validation.' \ + 'invalid_user_assigned_to_work_package', property: WorkPackage.human_attribute_name(property)) end end end - context "user is not visible" do + context 'user is not visible' do let(:invalid_user) { create(:user) } let(:user_href) { api_v3_paths.user invalid_user.id } - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) do - I18n.t("api_v3.errors.validation.invalid_user_assigned_to_work_package", + I18n.t('api_v3.errors.validation.invalid_user_assigned_to_work_package', property: WorkPackage.human_attribute_name(property)) end end end - context "wrong resource" do + context 'wrong resource' do let(:user_href) { api_v3_paths.status work_package.status.id } - include_context "patch request" + include_context 'patch request' - it_behaves_like "invalid resource link" do + it_behaves_like 'invalid resource link' do let(:message) do - I18n.t("api_v3.errors.invalid_resource", + I18n.t('api_v3.errors.invalid_resource', property:, expected: "/api/v3/groups/:id' or '/api/v3/users/:id' or '/api/v3/placeholder_users/:id", actual: user_href) @@ -594,16 +594,16 @@ end end - context "assingee" do - it_behaves_like "handling people", "assignee" + context 'assingee' do + it_behaves_like 'handling people', 'assignee' end - context "responsible" do - it_behaves_like "handling people", "responsible" + context 'responsible' do + it_behaves_like 'handling people', 'responsible' end end - context "version" do + context 'version' do let(:target_version) { create(:version, project:) } let(:version_link) { api_v3_paths.version target_version.id } let(:version_parameter) { { _links: { version: { href: version_link } } } } @@ -611,36 +611,36 @@ before { allow(User).to receive(:current).and_return current_user } - context "valid" do - include_context "patch request" + context 'valid' do + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with the work package assigned to the version" do + it 'responds with the work package assigned to the version' do expect(subject.body) .to be_json_eql(target_version.name.to_json) - .at_path("_embedded/version/name") + .at_path('_embedded/version/name') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end - context "for a user lacking the assign_versions permission" do + context 'for a user lacking the assign_versions permission' do let(:permissions) { %i[view_work_packages edit_work_packages] } - include_context "patch request" + include_context 'patch request' it { expect(response.status).to eq(422) } - it "has a readonly error" do + it 'has a readonly error' do expect(response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:PropertyIsReadOnly".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:PropertyIsReadOnly'.to_json) + .at_path('errorIdentifier') end end end - context "category" do + context 'category' do let(:target_category) { create(:category, project:) } let(:category_link) { api_v3_paths.category target_category.id } let(:category_parameter) { { _links: { category: { href: category_link } } } } @@ -648,22 +648,22 @@ before { allow(User).to receive(:current).and_return current_user } - context "valid" do - include_context "patch request" + context 'valid' do + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with the work package assigned to the category" do + it 'responds with the work package assigned to the category' do expect(subject.body) .to be_json_eql(target_category.name.to_json) - .at_path("_embedded/category/name") + .at_path('_embedded/category/name') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end end - context "priority" do + context 'priority' do let(:target_priority) { create(:priority) } let(:priority_link) { api_v3_paths.priority target_priority.id } let(:priority_parameter) { { _links: { priority: { href: priority_link } } } } @@ -671,22 +671,22 @@ before { allow(User).to receive(:current).and_return current_user } - context "valid" do - include_context "patch request" + context 'valid' do + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with the work package assigned to the priority" do + it 'responds with the work package assigned to the priority' do expect(subject.body) .to be_json_eql(target_priority.name.to_json) - .at_path("_embedded/priority/name") + .at_path('_embedded/priority/name') end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end end - context "budget" do + context 'budget' do let(:target_budget) { create(:budget, project:) } let(:budget_link) { api_v3_paths.budget target_budget.id } let(:budget_parameter) { { _links: { budget: { href: budget_link } } } } @@ -695,29 +695,29 @@ before { login_as(current_user) } - context "valid" do - include_context "patch request" + context 'valid' do + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with the work package and its new budget" do + it 'responds with the work package and its new budget' do expect(subject.body).to be_json_eql(target_budget.subject.to_json) - .at_path("_embedded/budget/subject") + .at_path('_embedded/budget/subject') end end - context "not valid" do + context 'not valid' do let(:target_budget) { create(:budget) } - include_context "patch request" + include_context 'patch request' - it_behaves_like "constraint violation" do - let(:message) { I18n.t("activerecord.errors.messages.inclusion") } + it_behaves_like 'constraint violation' do + let(:message) { I18n.t('activerecord.errors.messages.inclusion') } end end end - context "list custom field" do + context 'list custom field' do let(:custom_field) do create(:list_wp_custom_field) end @@ -739,74 +739,74 @@ work_package.type.custom_fields << custom_field end - context "valid" do - include_context "patch request" + context 'valid' do + include_context 'patch request' it { expect(response.status).to eq(200) } - it "responds with the work package assigned to the new value" do + it 'responds with the work package assigned to the new value' do expect(subject.body) .to be_json_eql(value_link.to_json) .at_path("_links/#{custom_field.attribute_name.camelize(:lower)}/href") end - it_behaves_like "lock version updated" + it_behaves_like 'lock version updated' end end - describe "update with read-only attributes" do - describe "single read-only violation" do - context "created and updated" do + describe 'update with read-only attributes' do + describe 'single read-only violation' do + context 'created and updated' do let(:tomorrow) { (DateTime.now + 1.day).utc.iso8601 } - include_context "patch request" + include_context 'patch request' - context "created_at" do + context 'created_at' do let(:params) { valid_params.merge(createdAt: tomorrow) } - it_behaves_like "read-only violation", "createdAt", WorkPackage, "Created on" + it_behaves_like 'read-only violation', 'createdAt', WorkPackage, 'Created on' end - context "updated_at" do + context 'updated_at' do let(:params) { valid_params.merge(updatedAt: tomorrow) } - it_behaves_like "read-only violation", "updatedAt", WorkPackage, "Updated on" + it_behaves_like 'read-only violation', 'updatedAt', WorkPackage, 'Updated on' end end end - context "multiple read-only attributes" do + context 'multiple read-only attributes' do let(:params) do valid_params.merge(createdAt: Date.today.iso8601, updatedAt: Date.today.iso8601) end - include_context "patch request" + include_context 'patch request' - it_behaves_like "multiple errors", 422 + it_behaves_like 'multiple errors', 422 - it_behaves_like "multiple errors of the same type", 2, "PropertyIsReadOnly" + it_behaves_like 'multiple errors of the same type', 2, 'PropertyIsReadOnly' - it_behaves_like "multiple errors of the same type with details", - "attribute", - "attribute" => ["createdAt", "updatedAt"] + it_behaves_like 'multiple errors of the same type with details', + 'attribute', + 'attribute' => ['createdAt', 'updatedAt'] end end - context "invalid update" do - context "single invalid attribute" do - let(:params) { valid_params.tap { |h| h[:subject] = "" } } + context 'invalid update' do + context 'single invalid attribute' do + let(:params) { valid_params.tap { |h| h[:subject] = '' } } - include_context "patch request" + include_context 'patch request' - it_behaves_like "constraint violation" do + it_behaves_like 'constraint violation' do let(:message) { "Subject can't be blank" } end end - context "multiple invalid attributes" do + context 'multiple invalid attributes' do let(:params) do valid_params - .tap { |h| h[:subject] = "" } + .tap { |h| h[:subject] = '' } .merge( _links: { parent: { @@ -820,44 +820,44 @@ role.add_permission!(:manage_subtasks) end - include_context "patch request" + include_context 'patch request' - it_behaves_like "multiple errors", 422 + it_behaves_like 'multiple errors', 422 - it_behaves_like "multiple errors of the same type", 3, "PropertyConstraintViolation" + it_behaves_like 'multiple errors of the same type', 3, 'PropertyConstraintViolation' - it_behaves_like "multiple errors of the same type with messages" do - let(:message) { ["Subject can't be blank.", "Parent does not exist.", "Parent may not be accessed."] } + it_behaves_like 'multiple errors of the same type with messages' do + let(:message) { ['Subject can\'t be blank.', 'Parent does not exist.', 'Parent may not be accessed.'] } end end - context "missing lock version" do + context 'missing lock version' do let(:params) { valid_params.except(:lockVersion) } - include_context "patch request" + include_context 'patch request' - it_behaves_like "update conflict" + it_behaves_like 'update conflict' end - context "stale object" do - let(:params) { valid_params.merge(subject: "Updated subject") } + context 'stale object' do + let(:params) { valid_params.merge(subject: 'Updated subject') } before do params - work_package.subject = "I am the first!" + work_package.subject = 'I am the first!' work_package.save! expect(valid_params[:lockVersion]).not_to eq(work_package.lock_version) end - include_context "patch request" + include_context 'patch request' - it_behaves_like "update conflict" + it_behaves_like 'update conflict' end end - context "claiming attachments" do + context 'claiming attachments' do let(:old_attachment) { create(:attachment, container: work_package) } let(:attachment) { create(:attachment, container: nil, author: current_user) } let(:params) do @@ -875,9 +875,9 @@ old_attachment end - include_context "patch request" + include_context 'patch request' - it "replaces the current with the provided attachments" do + it 'replaces the current with the provided attachments' do work_package.reload expect(work_package.attachments) diff --git a/spec/requests/api/v3/work_packages/work_packages_schemas_resource_spec.rb b/spec/requests/api/v3/work_packages/work_packages_schemas_resource_spec.rb index 1e7d94f58e82..590f5e15c27a 100644 --- a/spec/requests/api/v3/work_packages/work_packages_schemas_resource_spec.rb +++ b/spec/requests/api/v3/work_packages/work_packages_schemas_resource_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' RSpec.describe API::V3::WorkPackages::Schema::WorkPackageSchemasAPI do include Rack::Test::Methods @@ -40,12 +40,12 @@ create(:user, member_with_roles: { project => role }) end - describe "GET /api/v3/work_packages/schemas/filters=..." do + describe 'GET /api/v3/work_packages/schemas/filters=...' do let(:filter_values) { ["#{project.id}-#{type.id}"] } let(:schema_path) do - filter = [{ "id" => { - "operator" => "=", - "values" => filter_values + filter = [{ 'id' => { + 'operator' => '=', + 'values' => filter_values } }] "#{api_v3_paths.work_package_schemas}?#{{ filters: filter.to_json }.to_query}" @@ -56,96 +56,96 @@ get schema_path end - context "authorized" do - context "valid" do - it "returns HTTP 200" do + context 'authorized' do + context 'valid' do + it 'returns HTTP 200' do expect(last_response.status).to be(200) end - it "returns a collection of schemas" do + it 'returns a collection of schemas' do expect(last_response.body) .to be_json_eql(api_v3_paths.work_package_schema(project.id, type.id).to_json) - .at_path("_embedded/elements/0/_links/self/href") + .at_path('_embedded/elements/0/_links/self/href') end - it "has the self href set correctly" do + it 'has the self href set correctly' do expect(last_response.body) .to be_json_eql(schema_path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end end - context "for a non existing project" do + context 'for a non existing project' do let(:filter_values) { ["#{0}-#{type.id}"] } - it "returns HTTP 200" do + it 'returns HTTP 200' do expect(last_response.status).to be(200) end - it "returns an empty collection" do + it 'returns an empty collection' do expect(last_response.body) .to be_json_eql(0.to_json) - .at_path("count") + .at_path('count') end end - context "for a non existing type" do + context 'for a non existing type' do let(:filter_values) { ["#{project.id}-#{0}"] } - it "returns HTTP 200" do + it 'returns HTTP 200' do expect(last_response.status).to be(200) end - it "returns an empty collection" do + it 'returns an empty collection' do expect(last_response.body) .to be_json_eql(0.to_json) - .at_path("count") + .at_path('count') end end - context "for a non valid filter" do - let(:filter_values) { ["bogus"] } + context 'for a non valid filter' do + let(:filter_values) { ['bogus'] } - it "returns HTTP 400" do + it 'returns HTTP 400' do expect(last_response.status).to be(400) end - it "returns an error" do + it 'returns an error' do expect(last_response.body) - .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .to be_json_eql('urn:openproject-org:api:v3:errors:InvalidQuery'.to_json) + .at_path('errorIdentifier') end end end - context "not authorized" do + context 'not authorized' do let(:role) { create(:project_role, permissions: []) } - it "returns HTTP 403" do + it 'returns HTTP 403' do expect(last_response.status).to be(403) end end end - describe "GET /api/v3/work_packages/schemas/:id" do + describe 'GET /api/v3/work_packages/schemas/:id' do let(:schema_path) { api_v3_paths.work_package_schema project.id, type.id } - context "logged in" do + context 'logged in' do before do allow(User).to receive(:current).and_return(current_user) get schema_path end - context "valid schema" do - it "returns HTTP 200" do + context 'valid schema' do + it 'returns HTTP 200' do expect(last_response.status).to be(200) end - it "sets a weak ETag" do - expect(last_response.headers["ETag"]).to match(/W\/"\w+"/) + it 'sets a weak ETag' do + expect(last_response.headers['ETag']).to match(/W\/"\w+"/) end - it "caches the response" do + it 'caches the response' do schema_class = API::V3::WorkPackages::Schema::TypedWorkPackageSchema representer_class = API::V3::WorkPackages::Schema::WorkPackageSchemaRepresenter @@ -160,63 +160,63 @@ end end - context "id is too long" do - it_behaves_like "not found" do + context 'id is too long' do + it_behaves_like 'not found' do let(:schema_path) { "#{api_v3_paths.work_package_schema project.id, type.id}-1" } end end - context "id is too short" do - it_behaves_like "not found" do + context 'id is too short' do + it_behaves_like 'not found' do let(:schema_path) { "/api/v3/work_packages/schemas/#{project.id}" } end end end - context "not logged in" do + context 'not logged in' do before do get schema_path end - it_behaves_like "not found response based on login_required" + it_behaves_like 'not found response based on login_required' end end - describe "GET /api/v3/work_packages/schemas/sums" do + describe 'GET /api/v3/work_packages/schemas/sums' do let(:schema_path) { api_v3_paths.work_package_sums_schema } subject { last_response } - context "logged in" do + context 'logged in' do before do allow(User).to receive(:current).and_return(current_user) get schema_path end - context "valid schema" do - it "returns HTTP 200" do + context 'valid schema' do + it 'returns HTTP 200' do expect(last_response.status).to be(200) end # Further fields are tested in the representer specs - it "returns the schema for estimated_hours" do - expected = { type: "Duration", - name: "Work", + it 'returns the schema for estimated_hours' do + expected = { type: 'Duration', + name: 'Work', required: false, hasDefault: false, writable: false, options: {} } - expect(subject.body).to be_json_eql(expected.to_json).at_path("estimatedTime") + expect(subject.body).to be_json_eql(expected.to_json).at_path('estimatedTime') end end end - context "when not logged in" do + context 'when not logged in' do before do get schema_path end - it_behaves_like "not found response based on login_required" + it_behaves_like 'not found response based on login_required' end end end diff --git a/spec/requests/auth/auth_source_sso_spec.rb b/spec/requests/auth/auth_source_sso_spec.rb index c1bff6ec70b9..b6477d4f0953 100644 --- a/spec/requests/auth/auth_source_sso_spec.rb +++ b/spec/requests/auth/auth_source_sso_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AuthSourceSSO, :skip_2fa_stage, # Prevent redirects to 2FA stage type: :rails_request do @@ -43,58 +43,58 @@ .and_return(sso_config) end - include_context "with temporary LDAP" + include_context 'with temporary LDAP' - context "when LDAP is onthefly_register" do + context 'when LDAP is onthefly_register' do let(:onthefly_register) { true } - it "creates the user on the fly" do - expect(User.find_by(login: "aa729")).to be_nil + it 'creates the user on the fly' do + expect(User.find_by(login: 'aa729')).to be_nil expect do - get "/projects", headers: { "X-Remote-User" => "aa729" } + get '/projects', headers: { 'X-Remote-User' => 'aa729' } end.to change(User.not_builtin, :count).by(1) - user = User.find_by(login: "aa729") + user = User.find_by(login: 'aa729') expect(user).to be_present expect(user).to be_active expect(session[:user_id]).to eq user.id expect(session[:user_from_auth_header]).to eq true - expect(response).to redirect_to "/projects" + expect(response).to redirect_to '/projects' end end - context "when LDAP is not onthefly_register" do + context 'when LDAP is not onthefly_register' do let(:onthefly_register) { false } - it "returns an error when the user does not exist" do - get "/projects", headers: { "X-Remote-User" => "nonexistent" } + it 'returns an error when the user does not exist' do + get '/projects', headers: { 'X-Remote-User' => 'nonexistent' } - expect(response).to redirect_to "/sso" + expect(response).to redirect_to '/sso' expect(session[:auth_source_sso_failure]).to be_present end - context "when the user exists, but is outdated" do - let(:user) { create(:user, login: "ldap_admin", admin: false, ldap_auth_source:) } + context 'when the user exists, but is outdated' do + let(:user) { create(:user, login: 'ldap_admin', admin: false, ldap_auth_source:) } - it "redirects the user to that URL" do + it 'redirects the user to that URL' do expect(user).not_to be_admin - get "/projects?foo=bar", headers: { "X-Remote-User" => user.login } - expect(response).to redirect_to "/projects?foo=bar" + get '/projects?foo=bar', headers: { 'X-Remote-User' => user.login } + expect(response).to redirect_to '/projects?foo=bar' user.reload expect(user).to be_admin end end - context "when the user exists in another auth source that is inaccessible" do - let(:other_ldap) { create(:ldap_auth_source, name: "other_ldap") } - let(:user) { create(:user, login: "ldap_admin", admin: false, ldap_auth_source: other_ldap) } + context 'when the user exists in another auth source that is inaccessible' do + let(:other_ldap) { create(:ldap_auth_source, name: 'other_ldap') } + let(:user) { create(:user, login: 'ldap_admin', admin: false, ldap_auth_source: other_ldap) } - it "returns an error when the user does not exist" do - get "/projects", headers: { "X-Remote-User" => "nonexistent" } + it 'returns an error when the user does not exist' do + get '/projects', headers: { 'X-Remote-User' => 'nonexistent' } - expect(response).to redirect_to "/sso" + expect(response).to redirect_to '/sso' expect(session[:auth_source_sso_failure]).to be_present end end diff --git a/spec/requests/auth/ldap_sso_spec.rb b/spec/requests/auth/ldap_sso_spec.rb index 5d2858a013a6..06e7227c2f48 100644 --- a/spec/requests/auth/ldap_sso_spec.rb +++ b/spec/requests/auth/ldap_sso_spec.rb @@ -26,16 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "LDAP authentication", +RSpec.describe 'LDAP authentication', :skip_2fa_stage, :skip_csrf, type: :rails_request do - include_context "with temporary LDAP" - let(:username) { "aa729" } - let(:password) { "smada" } + include_context 'with temporary LDAP' + + let(:username) { 'aa729' } + let(:password) { 'smada' } let(:params) { { username:, password: } } subject do @@ -43,51 +44,51 @@ response end - context "when LDAP is onthefly_register" do + context 'when LDAP is onthefly_register' do let(:onthefly_register) { true } - it "creates the user on the fly" do - expect(User.find_by(login: "aa729")).to be_nil + it 'creates the user on the fly' do + expect(User.find_by(login: 'aa729')).to be_nil expect { subject }.to change(User.not_builtin.active, :count).by(1) - user = User.find_by(login: "aa729") + user = User.find_by(login: 'aa729') expect(user).to be_present expect(user).to be_active expect(session[:user_id]).to eq user.id - expect(subject).to redirect_to "/?first_time_user=true" + expect(subject).to redirect_to '/?first_time_user=true' end - context "when not all attributes present" do + context 'when not all attributes present' do let(:attr_mail) { nil } - it "does not save the user, but forwards to registration form" do - expect(User.find_by(login: "aa729")).to be_nil + it 'does not save the user, but forwards to registration form' do + expect(User.find_by(login: 'aa729')).to be_nil expect { subject }.not_to change(User.not_builtin.active, :count) - expect(subject).to render_template "account/register" + expect(subject).to render_template 'account/register' expect(subject.body).to have_text "Email can't be blank" end end - context "with user limit reached" do + context 'with user limit reached' do before do allow(OpenProject::Enterprise).to receive(:user_limit_reached?).and_return(true) end - it "shows the user limit error" do + it 'shows the user limit error' do expect(subject.body).to have_text "User limit reached" expect(subject.body).to include "/account/register" end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) end - describe "login" do - it "is not found" do + describe 'login' do + it 'is not found' do expect(subject).to have_http_status :not_found end end diff --git a/spec/requests/auth/oauth_login_csp_spec.rb b/spec/requests/auth/oauth_login_csp_spec.rb index 49a6ec64af93..032f351cdc53 100644 --- a/spec/requests/auth/oauth_login_csp_spec.rb +++ b/spec/requests/auth/oauth_login_csp_spec.rb @@ -26,35 +26,35 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "CSP appends on login form from oauth", +RSpec.describe 'CSP appends on login form from oauth', type: :rails_request do - let!(:redirect_uri) { "https://foobar.com" } + let!(:redirect_uri) { 'https://foobar.com' } let!(:oauth_app) { create(:oauth_application, redirect_uri:) } let(:oauth_path) do "/oauth/authorize?response_type=code&client_id=#{oauth_app.uid}&redirect_uri=#{CGI.escape(redirect_uri)}&scope=api_v3" end - context "when login required", with_settings: { login_required: true } do - it "appends given CSP appends from flash" do + context 'when login required', with_settings: { login_required: true } do + it 'appends given CSP appends from flash' do get oauth_path - csp = response.headers["Content-Security-Policy"] + csp = response.headers['Content-Security-Policy'] expect(csp).to include "form-action 'self' https://foobar.com/;" - location = response.headers["Location"] + location = response.headers['Location'] expect(location).to include("/login?back_url=#{CGI.escape(oauth_path)}") end end - context "with redirect-uri being a custom scheme" do - let(:redirect_uri) { "myscheme://custom-foobar" } + context 'with redirect-uri being a custom scheme' do + let(:redirect_uri) { 'myscheme://custom-foobar' } - it "appends given CSP appends from flash" do + it 'appends given CSP appends from flash' do get oauth_path - csp = response.headers["Content-Security-Policy"] + csp = response.headers['Content-Security-Policy'] expect(csp).to include "form-action 'self' myscheme:" end end diff --git a/spec/requests/auth/token_based_access_spec.rb b/spec/requests/auth/token_based_access_spec.rb index 32c5476df93f..5fb723ad9216 100644 --- a/spec/requests/auth/token_based_access_spec.rb +++ b/spec/requests/auth/token_based_access_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Token based access", type: :rails_request, with_settings: { login_required?: false } do +RSpec.describe 'Token based access', type: :rails_request, with_settings: { login_required?: false } do let(:work_package) { create(:work_package) } let(:user) do create(:user, @@ -36,7 +36,7 @@ end let(:rss_key) { user.rss_key } - it "grants access but does not login the user" do + it 'grants access but does not login the user' do # work_packages of a private project get "/work_packages/#{work_package.id}.atom" expect(response) diff --git a/spec/requests/oauth/client_credentials_flow_spec.rb b/spec/requests/oauth/client_credentials_flow_spec.rb index e697a470db53..d3ccc7aac11a 100644 --- a/spec/requests/oauth/client_credentials_flow_spec.rb +++ b/spec/requests/oauth/client_credentials_flow_spec.rb @@ -26,56 +26,56 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "OAuth client credentials flow" do +RSpec.describe 'OAuth client credentials flow' do include Rack::Test::Methods - let!(:application) { create(:oauth_application, client_credentials_user_id: user_id, name: "Cool API app!") } + let!(:application) { create(:oauth_application, client_credentials_user_id: user_id, name: 'Cool API app!') } let(:client_secret) { application.plaintext_secret } let(:access_token) do - response = post("/oauth/token", - grant_type: "client_credentials", scope: "api_v3", client_id: application.uid, client_secret:) + response = post('/oauth/token', + grant_type: 'client_credentials', scope: 'api_v3', client_id: application.uid, client_secret:) expect(response).to be_successful body = JSON.parse(response.body) - body["access_token"] + body['access_token'] end let(:make_request) do # Perform request with it - headers = { "HTTP_CONTENT_TYPE" => "application/json", "HTTP_AUTHORIZATION" => "Bearer #{access_token}" } - get "/api/v3", {}, headers + headers = { 'HTTP_CONTENT_TYPE' => 'application/json', 'HTTP_AUTHORIZATION' => "Bearer #{access_token}" } + get '/api/v3', {}, headers end subject { JSON.parse(make_request.body) } - describe "when application provides client credentials impersonator" do + describe 'when application provides client credentials impersonator' do let(:user) { create(:user) } let(:user_id) { user.id } - it "allows client credential flow as the user" do + it 'allows client credential flow as the user' do expect(make_request).to be_successful - expect(subject.dig("_links", "user", "href")).to eq("/api/v3/users/#{user.id}") + expect(subject.dig('_links', 'user', 'href')).to eq("/api/v3/users/#{user.id}") end end - describe "when application does not provide client credential impersonator" do + describe 'when application does not provide client credential impersonator' do let(:user_id) { nil } before do make_request end - context "when login_required", with_settings: { login_required: true } do - it_behaves_like "unauthenticated access" + context 'when login_required', with_settings: { login_required: true } do + it_behaves_like 'unauthenticated access' end - context "when not login_required", with_settings: { login_required: false } do - it "allows client credential flow as the anonymous user" do + context 'when not login_required', with_settings: { login_required: false } do + it 'allows client credential flow as the anonymous user' do expect(make_request).to be_successful - expect(subject.dig("_links", "user", "href")).to be_nil + expect(subject.dig('_links', 'user', 'href')).to be_nil end end end diff --git a/spec/requests/oauth/oauth_application_spec.rb b/spec/requests/oauth/oauth_application_spec.rb index d402a213a810..d7bcecd079fa 100644 --- a/spec/requests/oauth/oauth_application_spec.rb +++ b/spec/requests/oauth/oauth_application_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "API v3 oauth applications resource", content_type: :json do +RSpec.describe 'API v3 oauth applications resource', content_type: :json do include API::V3::Utilities::PathHelper let(:current_user) { create(:admin) } @@ -40,15 +40,15 @@ get path end - describe "GET /api/v3/oauth_applications/:oauth_application_id" do + describe 'GET /api/v3/oauth_applications/:oauth_application_id' do let(:path) { api_v3_paths.oauth_application(oauth_application.id) } - it_behaves_like "successful response" + it_behaves_like 'successful response' - context "as non-admin" do + context 'as non-admin' do let(:current_user) { create(:user) } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/oauth_clients/callback_flow_spec.rb b/spec/requests/oauth_clients/callback_flow_spec.rb index b184621a20b0..3018870bfb3c 100644 --- a/spec/requests/oauth_clients/callback_flow_spec.rb +++ b/spec/requests/oauth_clients/callback_flow_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "OAuthClient callback endpoint" do +RSpec.describe 'OAuthClient callback endpoint' do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -41,30 +41,30 @@ "mBf4v9hNA6hXXCWHd5mZggsAa2FSOXinx9jKx1yjSoDwOPOX4k6zGEgM2radqgg1nRwXCqvIe5xZsfwqMIaTdL" + "jYnl0OpYOc6ePblzQTmnlp7RYiHW09assYEJjv9zps" end - let(:state) { "asdf1234" } + let(:state) { 'asdf1234' } let(:redirect_uri) do File.join(API::V3::Utilities::PathHelper::ApiV3Path::root_url, "/my-path?and=some&query=params") end let(:oauth_client_token) { create(:oauth_client_token) } let(:oauth_client) do create(:oauth_client, - client_id: "kETWr2XsjPxhVbN7Q5jmPq83xribuUTRzgfXthpYT0vSqyJWm4dOnivKzHiZasf0", - client_secret: "J1sg4L5PYbM2RZL3pUyxTnamvfpcP5eUcCPmeCQHJO60Gy6CJIdDaF4yXOeC8BPS") + client_id: 'kETWr2XsjPxhVbN7Q5jmPq83xribuUTRzgfXthpYT0vSqyJWm4dOnivKzHiZasf0', + client_secret: 'J1sg4L5PYbM2RZL3pUyxTnamvfpcP5eUcCPmeCQHJO60Gy6CJIdDaF4yXOeC8BPS') end let(:rack_oauth2_client) { instance_double(Rack::OAuth2::Client) } let(:connection_manager) { instance_double(OAuthClients::ConnectionManager) } - let(:uri) { URI(File.join("oauth_clients", oauth_client.client_id, "callback")) } + let(:uri) { URI(File.join('oauth_clients', oauth_client.client_id, 'callback')) } subject(:response) { last_response } - context "when user is not logged in" do - it "requires login" do + context 'when user is not logged in' do + it 'requires login' do get uri.to_s expect(last_response.status).to eq(401) end end - context "when user is logged in" do + context 'when user is logged in' do before do login_as current_user @@ -72,118 +72,118 @@ allow(rack_oauth2_client) .to receive(:access_token!) .with(:body) - .and_return(Rack::OAuth2::AccessToken::Bearer.new(access_token: "xyzaccesstoken", - refresh_token: "xyzrefreshtoken")) + .and_return(Rack::OAuth2::AccessToken::Bearer.new(access_token: 'xyzaccesstoken', + refresh_token: 'xyzrefreshtoken')) allow(rack_oauth2_client).to receive(:authorization_code=) state_cookie = CGI.escape({ href: redirect_uri, storageId: oauth_client.integration_id }.to_json) set_cookie "oauth_state_asdf1234=#{state_cookie}" end # rubocop:disable RSpec/Rails/HaveHttpStatus - shared_examples "with errors and state param with cookie, not being admin" do - it "redirects to URI referenced in the state param and held in a cookie" do + shared_examples 'with errors and state param with cookie, not being admin' do + it 'redirects to URI referenced in the state param and held in a cookie' do expect(response.status).to eq(302) expect(response.location).to eq redirect_uri end end - shared_examples "with errors, being an admin" do - it "redirects to admin settings for the storage" do + shared_examples 'with errors, being an admin' do + it 'redirects to admin settings for the storage' do expect(response.status).to eq(302) expect(URI(response.location).path).to eq edit_admin_settings_storage_path(oauth_client.integration) end end - shared_examples "fallback redirect" do - it "redirects to home" do + shared_examples 'fallback redirect' do + it 'redirects to home' do expect(response.status).to eq(302) expect(URI(response.location).path).to eq API::V3::Utilities::PathHelper::ApiV3Path::root_path end end - context "with valid params" do - context "without errors" do + context 'with valid params' do + context 'without errors' do before do - uri.query = URI.encode_www_form([["code", code], ["state", state]]) + uri.query = URI.encode_www_form([['code', code], ['state', state]]) get uri.to_s end - it "redirects to the URL that was referenced by the state param and held by a cookie" do + it 'redirects to the URL that was referenced by the state param and held by a cookie' do expect(rack_oauth2_client).to have_received(:authorization_code=).with(code) expect(response.status).to eq 302 expect(response.location).to eq redirect_uri expect(OAuthClientToken.count).to eq 1 - expect(OAuthClientToken.last.access_token).to eq "xyzaccesstoken" - expect(OAuthClientToken.last.refresh_token).to eq "xyzrefreshtoken" + expect(OAuthClientToken.last.access_token).to eq 'xyzaccesstoken' + expect(OAuthClientToken.last.refresh_token).to eq 'xyzrefreshtoken' end end - context "with a OAuth state cookie containing a URL pointing to a different host" do + context 'with a OAuth state cookie containing a URL pointing to a different host' do let(:redirect_uri) { "https://some-other-domain.com/foo/bar" } before do - uri.query = URI.encode_www_form([["code", code], ["state", state]]) + uri.query = URI.encode_www_form([['code', code], ['state', state]]) get uri.to_s subject end - it_behaves_like "fallback redirect" + it_behaves_like 'fallback redirect' end - context "with some other error, having a state param" do + context 'with some other error, having a state param' do before do allow(OAuthClients::ConnectionManager) .to receive(:new).and_return(connection_manager) allow(connection_manager) .to receive(:code_to_token).with(code).and_return(ServiceResult.failure) - uri.query = URI.encode_www_form([["code", code], ["state", state]]) + uri.query = URI.encode_www_form([['code', code], ['state', state]]) get uri.to_s subject end - context "with current_user being an admin" do + context 'with current_user being an admin' do let(:current_user) { create(:admin) } - it_behaves_like "with errors, being an admin" + it_behaves_like 'with errors, being an admin' end - context "with current_user not being an admin" do - it_behaves_like "with errors and state param with cookie, not being admin" + context 'with current_user not being an admin' do + it_behaves_like 'with errors and state param with cookie, not being admin' end end end - context "without code param, but with state param," do + context 'without code param, but with state param,' do before do - uri.query = URI.encode_www_form([["state", state]]) + uri.query = URI.encode_www_form([['state', state]]) get uri.to_s subject end - context "with current_user not being an admin" do - it_behaves_like "with errors and state param with cookie, not being admin" + context 'with current_user not being an admin' do + it_behaves_like 'with errors and state param with cookie, not being admin' end - context "with current_user being an admin" do + context 'with current_user being an admin' do let(:current_user) { create(:admin) } - it_behaves_like "with errors, being an admin" + it_behaves_like 'with errors, being an admin' end end - context "without state param" do + context 'without state param' do before do - uri.query = URI.encode_www_form([["code", code]]) + uri.query = URI.encode_www_form([['code', code]]) get uri.to_s subject end - it_behaves_like "fallback redirect" + it_behaves_like 'fallback redirect' end # rubocop:enable RSpec/Rails/HaveHttpStatus end diff --git a/spec/requests/oauth_clients/ensure_connection_flow_spec.rb b/spec/requests/oauth_clients/ensure_connection_flow_spec.rb index fcc3b3fc854e..489b957b780d 100644 --- a/spec/requests/oauth_clients/ensure_connection_flow_spec.rb +++ b/spec/requests/oauth_clients/ensure_connection_flow_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' require_module_spec_helper RSpec.describe "/oauth_clients/:oauth_client_id/ensure_connection endpoint", :webmock do @@ -34,34 +34,34 @@ shared_let(:storage) { create(:nextcloud_storage, :with_oauth_client) } shared_let(:oauth_client) { storage.oauth_client } - describe "#ensure_connection" do - context "when user is not logged in" do - it "requires login" do + describe '#ensure_connection' do + context 'when user is not logged in' do + it 'requires login' do get oauth_clients_ensure_connection_url(oauth_client_id: oauth_client.client_id) expect(last_response.status).to eq(401) end end - context "when user is logged in" do + context 'when user is logged in' do before { login_as(user) } - it "responds with 400 when storage_id parameter is absent" do + it 'responds with 400 when storage_id parameter is absent' do get oauth_clients_ensure_connection_url(oauth_client_id: oauth_client.client_id) expect(last_response.status).to eq(400) expect(last_response.body).to eq("Required parameter missing: storage_id") end - context "when storage_id parameter is present" do + context 'when storage_id parameter is present' do context 'when user is not "connected"' do - let(:nonce) { "57a17c3f-b2ed-446e-9dd8-651ba3aec37d" } + let(:nonce) { '57a17c3f-b2ed-446e-9dd8-651ba3aec37d' } before do allow(SecureRandom).to receive(:uuid).and_call_original.ordered allow(SecureRandom).to receive(:uuid).and_return(nonce).ordered end - context "when destination_url parameter is absent" do - it "redirects to storage authorization_uri with oauth_state_* cookie set" do + context 'when destination_url parameter is absent' do + it 'redirects to storage authorization_uri with oauth_state_* cookie set' do get oauth_clients_ensure_connection_url(oauth_client_id: oauth_client.client_id, storage_id: storage.id) oauth_client = storage.oauth_client @@ -76,9 +76,9 @@ end end - context "when destination_url parameter is present" do - context "when destination_url is the same origin as OP" do - it "redirects to storage authorization_uri with oauth_state_* cookie set" do + context 'when destination_url parameter is present' do + context 'when destination_url is the same origin as OP' do + it 'redirects to storage authorization_uri with oauth_state_* cookie set' do get oauth_clients_ensure_connection_url(oauth_client_id: storage.oauth_client.client_id, storage_id: storage.id, destination_url: "#{root_url}123") @@ -95,8 +95,8 @@ end end - context "when destination_url is not the same origin as OP" do - it "redirects to storage authorization_uri with oauth_state_* cookie set" do + context 'when destination_url is not the same origin as OP' do + it 'redirects to storage authorization_uri with oauth_state_* cookie set' do get oauth_clients_ensure_connection_url(oauth_client_id: storage.oauth_client.client_id, storage_id: storage.id, destination_url: "#{storage.host}/index.php") @@ -124,15 +124,15 @@ stub_request(:get, "#{storage.host}/ocs/v1.php/cloud/user") .with( headers: { - "Accept" => "application/json", - "Authorization" => "Bearer #{oauth_client_token.access_token}", - "Ocs-Apirequest" => "true" + 'Accept' => 'application/json', + 'Authorization' => "Bearer #{oauth_client_token.access_token}", + 'Ocs-Apirequest' => 'true' } ).to_return(status: 200, body: "", headers: {}) end - context "when destination_url parameter is absent" do - it "redirects to root_url" do + context 'when destination_url parameter is absent' do + it 'redirects to root_url' do get oauth_clients_ensure_connection_url(oauth_client_id: oauth_client.client_id, storage_id: storage.id) expect(last_response.status).to eq(302) @@ -141,9 +141,9 @@ end end - context "when destination_url parameter is present" do - context "when destination_url is the same origin as OP" do - it "redirects to destination_url" do + context 'when destination_url parameter is present' do + context 'when destination_url is the same origin as OP' do + it 'redirects to destination_url' do get oauth_clients_ensure_connection_url(oauth_client_id: storage.oauth_client.client_id, storage_id: storage.id, destination_url: "#{root_url}123") @@ -155,8 +155,8 @@ end end - context "when destination_url is not the same origin as OP" do - it "redirects to root_url" do + context 'when destination_url is not the same origin as OP' do + it 'redirects to root_url' do get oauth_clients_ensure_connection_url(oauth_client_id: storage.oauth_client.client_id, storage_id: storage.id, destination_url: "#{storage.host}/index.php") diff --git a/spec/requests/oauth_clients/oauth_client_credentials_spec.rb b/spec/requests/oauth_clients/oauth_client_credentials_spec.rb index 20f1b0285e92..8cb5eb6e808f 100644 --- a/spec/requests/oauth_clients/oauth_client_credentials_spec.rb +++ b/spec/requests/oauth_clients/oauth_client_credentials_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "API v3 oauth applications resource", content_type: :json do +RSpec.describe 'API v3 oauth applications resource', content_type: :json do include API::V3::Utilities::PathHelper let(:oauth_client_credentials) { create(:oauth_client) } @@ -39,15 +39,15 @@ get path end - describe "GET /api/v3/oauth_client_credentials/:oauth_client_credentials_id" do + describe 'GET /api/v3/oauth_client_credentials/:oauth_client_credentials_id' do let(:path) { api_v3_paths.oauth_client_credentials(oauth_client_credentials.id) } - it_behaves_like "successful response" + it_behaves_like 'successful response' - context "as non-admin" do + context 'as non-admin' do current_user { create(:user) } - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/requests/openid_google_provider_callback_spec.rb b/spec/requests/openid_google_provider_callback_spec.rb index f43e346ef8b8..ba991a6333fe 100644 --- a/spec/requests/openid_google_provider_callback_spec.rb +++ b/spec/requests/openid_google_provider_callback_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "rack/test" +require 'spec_helper' +require 'rack/test' -RSpec.describe "OpenID Google provider callback", with_ee: %i[openid_providers] do +RSpec.describe 'OpenID Google provider callback', with_ee: %i[openid_providers] do include Rack::Test::Methods include API::V3::Utilities::PathHelper @@ -41,12 +41,12 @@ "prompt" => "none" } end let(:uri) do - uri = URI("/auth/google/callback") - uri.query = URI.encode_www_form([["code", auth_hash["code"]], - ["state", auth_hash["state"]], - ["scope", auth_hash["scope"]], - ["authuser", auth_hash["authuser"]], - ["prompt", auth_hash["prompt"]]]) + uri = URI('/auth/google/callback') + uri.query = URI.encode_www_form([['code', auth_hash['code']], + ['state', auth_hash['state']], + ['scope', auth_hash['scope']], + ['authuser', auth_hash['authuser']], + ['prompt', auth_hash['prompt']]]) uri end @@ -86,11 +86,11 @@ ) allow_any_instance_of(OmniAuth::Strategies::OpenIDConnect).to receive(:session) { - { "omniauth.state" => auth_hash["state"] } + { 'omniauth.state' => auth_hash['state'] } } end - it "redirects user without errors", :webmock, with_settings: { + it 'redirects user without errors', :webmock, with_settings: { plugin_openproject_openid_connect: { "providers" => { "google" => { "identifier" => "identifier", "secret" => "secret" } } } diff --git a/spec/requests/rate_limiting/api_v3_rate_limiting_spec.rb b/spec/requests/rate_limiting/api_v3_rate_limiting_spec.rb index 118f59eb379b..1d325a752a83 100644 --- a/spec/requests/rate_limiting/api_v3_rate_limiting_spec.rb +++ b/spec/requests/rate_limiting/api_v3_rate_limiting_spec.rb @@ -26,47 +26,47 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Rate limiting APIv3", +RSpec.describe 'Rate limiting APIv3', :with_rack_attack do include Rack::Test::Methods include API::V3::Utilities::PathHelper current_user { create(:admin) } - context "when enabled", with_config: { rate_limiting: { api_v3: true } } do - it "blocks post request to any form" do + context 'when enabled', with_config: { rate_limiting: { api_v3: true } } do + it 'blocks post request to any form' do # Need to reload rules again after config change OpenProject::RateLimiting.set_defaults! # First requests sets the cookie discriminator - get "/" + get '/' 6.times do - post "/api/v3/work_packages/form", + post '/api/v3/work_packages/form', nil, - "CONTENT_TYPE" => "application/json" + 'CONTENT_TYPE' => 'application/json' expect(last_response.status).to eq 200 end - post "/api/v3/work_packages/form", + post '/api/v3/work_packages/form', nil, - "CONTENT_TYPE" => "application/json" + 'CONTENT_TYPE' => 'application/json' expect(last_response.status).to eq 429 end end - context "when disabled", with_config: { rate_limiting: { api_v3: false } } do - it "does not block post request to any form" do + context 'when disabled', with_config: { rate_limiting: { api_v3: false } } do + it 'does not block post request to any form' do # Need to reload rules again after config change OpenProject::RateLimiting.set_defaults! 9.times do - post "/api/v3/work_packages/form", + post '/api/v3/work_packages/form', nil, - "CONTENT_TYPE" => "application/json" + 'CONTENT_TYPE' => 'application/json' expect(last_response.status).to eq 200 end diff --git a/spec/requests/rate_limiting/lost_password_rate_limiting_spec.rb b/spec/requests/rate_limiting/lost_password_rate_limiting_spec.rb index 771cf7bf8d54..1fc766924224 100644 --- a/spec/requests/rate_limiting/lost_password_rate_limiting_spec.rb +++ b/spec/requests/rate_limiting/lost_password_rate_limiting_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Rate limiting lost_password", +RSpec.describe 'Rate limiting lost_password', :with_rack_attack, type: :rails_request do before do @@ -37,35 +37,35 @@ .and_return(false) end - it "blocks the request on the fourth try to the same address" do + it 'blocks the request on the fourth try to the same address' do 3.times do post account_lost_password_path, - params: { mail: "foo@example.com" }, - headers: { "Content-Type": "multipart/form-data" } + params: { mail: 'foo@example.com' }, + headers: { 'Content-Type': 'multipart/form-data' } expect(response).to be_successful end post account_lost_password_path, - params: { mail: "foo@example.com" }, - headers: { "Content-Type": "multipart/form-data" } + params: { mail: 'foo@example.com' }, + headers: { 'Content-Type': 'multipart/form-data' } expect(response).to have_http_status :too_many_requests expect(response.body).to include "Your request has been throttled" post account_lost_password_path, - params: { mail: "corrected@example.com" }, - headers: { "Content-Type": "multipart/form-data" } + params: { mail: 'corrected@example.com' }, + headers: { 'Content-Type': 'multipart/form-data' } expect(response).to be_successful end - context "when disabled", with_config: { rate_limiting: { lost_password: false } } do - it "does not block post request to any form" do + context 'when disabled', with_config: { rate_limiting: { lost_password: false } } do + it 'does not block post request to any form' do # Need to reload rules again after config change OpenProject::RateLimiting.set_defaults! 4.times do post account_lost_password_path, - params: { mail: "foo@example.com" }, - headers: { "Content-Type": "multipart/form-data" } + params: { mail: 'foo@example.com' }, + headers: { 'Content-Type': 'multipart/form-data' } expect(response).to be_successful end end diff --git a/spec/routing/account_spec.rb b/spec/routing/account_spec.rb index 7510c93f106a..4c66dc1c4bbf 100644 --- a/spec/routing/account_spec.rb +++ b/spec/routing/account_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "account routes" do - it "/account/lost_password GET routes to account#lost_password" do - expect(get("/account/lost_password")).to route_to("account#lost_password") +RSpec.describe 'account routes' do + it '/account/lost_password GET routes to account#lost_password' do + expect(get('/account/lost_password')).to route_to('account#lost_password') end - it "/account/lost_password POST routes to account#lost_password" do - expect(post("/account/lost_password")).to route_to("account#lost_password") + it '/account/lost_password POST routes to account#lost_password' do + expect(post('/account/lost_password')).to route_to('account#lost_password') end - it "/accounts/register GET routes to account#register" do - expect(get("/account/register")).to route_to("account#register") + it '/accounts/register GET routes to account#register' do + expect(get('/account/register')).to route_to('account#register') end - it "/accounts/register POST routes to account#register" do - expect(post("/account/register")).to route_to("account#register") + it '/accounts/register POST routes to account#register' do + expect(post('/account/register')).to route_to('account#register') end end diff --git a/spec/routing/activities_spec.rb b/spec/routing/activities_spec.rb index a97f402878fe..342885be4545 100644 --- a/spec/routing/activities_spec.rb +++ b/spec/routing/activities_spec.rb @@ -26,43 +26,43 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe ActivitiesController, "routing" do +RSpec.describe ActivitiesController, 'routing' do it { - expect(get("/activity")).to route_to(controller: "activities", - action: "index") + expect(get('/activity')).to route_to(controller: 'activities', + action: 'index') } it { - expect(get("/activity.atom")).to route_to(controller: "activities", - action: "index", - format: "atom") + expect(get('/activity.atom')).to route_to(controller: 'activities', + action: 'index', + format: 'atom') } it { - expect(get("/activity/menu")).to route_to(controller: "activities", - action: "menu") + expect(get('/activity/menu')).to route_to(controller: 'activities', + action: 'menu') } - context "project scoped" do + context 'project scoped' do it { - expect(get("/projects/abc/activity")).to route_to(controller: "activities", - action: "index", - project_id: "abc") + expect(get('/projects/abc/activity')).to route_to(controller: 'activities', + action: 'index', + project_id: 'abc') } it { - expect(get("/projects/abc/activity.atom")).to route_to(controller: "activities", - action: "index", - project_id: "abc", - format: "atom") + expect(get('/projects/abc/activity.atom')).to route_to(controller: 'activities', + action: 'index', + project_id: 'abc', + format: 'atom') } it { - expect(get("/projects/abc/activity/menu")).to route_to(controller: "activities", - action: "menu", - project_id: "abc") + expect(get('/projects/abc/activity/menu')).to route_to(controller: 'activities', + action: 'menu', + project_id: 'abc') } end end diff --git a/spec/routing/admin/incoming_mails_spec.rb b/spec/routing/admin/incoming_mails_spec.rb index 50dccac1ec3c..2669c3a7012d 100644 --- a/spec/routing/admin/incoming_mails_spec.rb +++ b/spec/routing/admin/incoming_mails_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "admin incoming_mails routes" do +RSpec.describe 'admin incoming_mails routes' do it do - expect(get("admin/settings/incoming_mails")) - .to route_to("admin/settings/incoming_mails_settings#show") + expect(get('admin/settings/incoming_mails')) + .to route_to('admin/settings/incoming_mails_settings#show') end it do - expect(patch("admin/settings/incoming_mails")) - .to route_to("admin/settings/incoming_mails_settings#update") + expect(patch('admin/settings/incoming_mails')) + .to route_to('admin/settings/incoming_mails_settings#update') end end diff --git a/spec/routing/admin/mail_notifications_spec.rb b/spec/routing/admin/mail_notifications_spec.rb index d7c8079474d9..2f75e26caf3e 100644 --- a/spec/routing/admin/mail_notifications_spec.rb +++ b/spec/routing/admin/mail_notifications_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "admin mail_notifications routes" do +RSpec.describe 'admin mail_notifications routes' do it do - expect(get("admin/settings/mail_notifications")) - .to route_to("admin/settings/mail_notifications_settings#show") + expect(get('admin/settings/mail_notifications')) + .to route_to('admin/settings/mail_notifications_settings#show') end it do - expect(patch("admin/settings/mail_notifications")) - .to route_to("admin/settings/mail_notifications_settings#update") + expect(patch('admin/settings/mail_notifications')) + .to route_to('admin/settings/mail_notifications_settings#update') end end diff --git a/spec/routing/admin_spec.rb b/spec/routing/admin_spec.rb index 6cb4508cf253..9f78b7d8c711 100644 --- a/spec/routing/admin_spec.rb +++ b/spec/routing/admin_spec.rb @@ -26,31 +26,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "admin routes" do - it "connects GET /admin to admin#index" do - expect(get("/admin")) - .to route_to("admin#index") +RSpec.describe 'admin routes' do + it 'connects GET /admin to admin#index' do + expect(get('/admin')) + .to route_to('admin#index') end - it "connects GET /projects to projects#index" do - expect(get("/projects")) - .to route_to("projects#index") + it 'connects GET /projects to projects#index' do + expect(get('/projects')) + .to route_to('projects#index') end - it "connects GET /admin/plugins to admin#plugins" do - expect(get("/admin/plugins")) - .to route_to("admin#plugins") + it 'connects GET /admin/plugins to admin#plugins' do + expect(get('/admin/plugins')) + .to route_to('admin#plugins') end - it "connects GET /admin/info to admin#info" do - expect(get("/admin/info")) - .to route_to("admin#info") + it 'connects GET /admin/info to admin#info' do + expect(get('/admin/info')) + .to route_to('admin#info') end - it "connects POST /admin/test_email to admin#test_email" do - expect(post("/admin/test_email")) - .to route_to("admin#test_email") + it 'connects POST /admin/test_email to admin#test_email' do + expect(post('/admin/test_email')) + .to route_to('admin#test_email') end end diff --git a/spec/routing/attachments_spec.rb b/spec/routing/attachments_spec.rb index fa574c073af4..64374c2f9a5c 100644 --- a/spec/routing/attachments_spec.rb +++ b/spec/routing/attachments_spec.rb @@ -26,40 +26,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "attachments routing", type: :request do - describe "for backwards compatibility" do - it "redirects GET attachments/:id to api v3 attachments/:id/content" do +RSpec.describe 'attachments routing', type: :request do + describe 'for backwards compatibility' do + it 'redirects GET attachments/:id to api v3 attachments/:id/content' do get "/attachments/1" expect(last_response).to be_redirect expect(last_response.location).to end_with("/api/v3/attachments/1/content") end - it "redirects GET attachments/:id/filename.ext to api v3 attachments/:id/content" do + it 'redirects GET attachments/:id/filename.ext to api v3 attachments/:id/content' do get "/attachments/1/filename.ext" expect(last_response).to be_redirect expect(last_response.location).to end_with("/api/v3/attachments/1/content") end - it "redirects DELETE attachments/:id to api v3 attachments/:id" do + it 'redirects DELETE attachments/:id to api v3 attachments/:id' do delete "/attachments/1" expect(last_response).to be_redirect expect(last_response.location).to end_with("/api/v3/attachments/1") end - it "redirects GET /attachments/download with filename to attachments#download" do - get "/attachments/download/42/foo.png" + it 'redirects GET /attachments/download with filename to attachments#download' do + get '/attachments/download/42/foo.png' expect(last_response).to be_redirect - expect(last_response.location).to end_with "/attachments/42/foo.png" + expect(last_response.location).to end_with '/attachments/42/foo.png' end - it "redirects GET /attachments/download without filename to attachments#download" do - get "/attachments/download/42" + it 'redirects GET /attachments/download without filename to attachments#download' do + get '/attachments/download/42' expect(last_response).to be_redirect - expect(last_response.location).to end_with "/attachments/42" + expect(last_response.location).to end_with '/attachments/42' end end end diff --git a/spec/routing/attribute_help_text_spec.rb b/spec/routing/attribute_help_text_spec.rb index 3c56b661e88b..dbe472e78a0f 100644 --- a/spec/routing/attribute_help_text_spec.rb +++ b/spec/routing/attribute_help_text_spec.rb @@ -26,23 +26,23 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AttributeHelpTextsController do - it "routes CRUD to the controller" do - expect(get("/admin/attribute_help_texts")) - .to route_to(controller: "attribute_help_texts", action: "index") + it 'routes CRUD to the controller' do + expect(get('/admin/attribute_help_texts')) + .to route_to(controller: 'attribute_help_texts', action: 'index') - expect(get("/admin/attribute_help_texts/1/edit")) - .to route_to(controller: "attribute_help_texts", action: "edit", id: "1") + expect(get('/admin/attribute_help_texts/1/edit')) + .to route_to(controller: 'attribute_help_texts', action: 'edit', id: '1') - expect(post("/admin/attribute_help_texts")) - .to route_to(controller: "attribute_help_texts", action: "create") + expect(post('/admin/attribute_help_texts')) + .to route_to(controller: 'attribute_help_texts', action: 'create') - expect(put("/admin/attribute_help_texts/1")) - .to route_to(controller: "attribute_help_texts", action: "update", id: "1") + expect(put('/admin/attribute_help_texts/1')) + .to route_to(controller: 'attribute_help_texts', action: 'update', id: '1') - expect(delete("/admin/attribute_help_texts/1")) - .to route_to(controller: "attribute_help_texts", action: "destroy", id: "1") + expect(delete('/admin/attribute_help_texts/1')) + .to route_to(controller: 'attribute_help_texts', action: 'destroy', id: '1') end end diff --git a/spec/routing/categories_spec.rb b/spec/routing/categories_spec.rb index d0e048e81c9c..17de1260f26a 100644 --- a/spec/routing/categories_spec.rb +++ b/spec/routing/categories_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CategoriesController do - it "connects GET /projects/test/categories/new to categories#new" do - expect(get("/projects/test/categories/new")).to route_to(controller: "categories", - action: "new", - project_id: "test") + it 'connects GET /projects/test/categories/new to categories#new' do + expect(get('/projects/test/categories/new')).to route_to(controller: 'categories', + action: 'new', + project_id: 'test') end - it "connects POST /projects/test/categories to categories#create" do - expect(post("/projects/test/categories")).to route_to(controller: "categories", - action: "create", - project_id: "test") + it 'connects POST /projects/test/categories to categories#create' do + expect(post('/projects/test/categories')).to route_to(controller: 'categories', + action: 'create', + project_id: 'test') end - it "connects GET /categories/5/edit to categories#edit" do - expect(get("/categories/5/edit")).to route_to(controller: "categories", - action: "edit", - id: "5") + it 'connects GET /categories/5/edit to categories#edit' do + expect(get('/categories/5/edit')).to route_to(controller: 'categories', + action: 'edit', + id: '5') end - it "connects PUT /categories/5 to categories#update" do - expect(put("/categories/5")).to route_to(controller: "categories", - action: "update", - id: "5") + it 'connects PUT /categories/5 to categories#update' do + expect(put('/categories/5')).to route_to(controller: 'categories', + action: 'update', + id: '5') end - it "connects DELETE /categories/5 to categories#delete" do - expect(delete("/categories/5")).to route_to(controller: "categories", - action: "destroy", - id: "5") + it 'connects DELETE /categories/5 to categories#delete' do + expect(delete('/categories/5')).to route_to(controller: 'categories', + action: 'destroy', + id: '5') end end diff --git a/spec/routing/custom_actions_spec.rb b/spec/routing/custom_actions_spec.rb index 8e4ba2f01ae7..94091a5ce98f 100644 --- a/spec/routing/custom_actions_spec.rb +++ b/spec/routing/custom_actions_spec.rb @@ -26,48 +26,48 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "custom_actions routes" do - describe "index" do - it "links GET /admin/custom_actions" do - expect(get("/admin/custom_actions")) - .to route_to("custom_actions#index") +RSpec.describe 'custom_actions routes' do + describe 'index' do + it 'links GET /admin/custom_actions' do + expect(get('/admin/custom_actions')) + .to route_to('custom_actions#index') end end - describe "new" do - it "links GET /admin/custom_actions/new" do - expect(get("/admin/custom_actions/new")) - .to route_to("custom_actions#new") + describe 'new' do + it 'links GET /admin/custom_actions/new' do + expect(get('/admin/custom_actions/new')) + .to route_to('custom_actions#new') end end - describe "create" do - it "links POST /admin/custom_actions" do - expect(post("/admin/custom_actions")) - .to route_to("custom_actions#create") + describe 'create' do + it 'links POST /admin/custom_actions' do + expect(post('/admin/custom_actions')) + .to route_to('custom_actions#create') end end - describe "edit" do - it "links GET /admin/custom_actions/:id/edit" do - expect(get("/admin/custom_actions/42/edit")) - .to route_to("custom_actions#edit", id: "42") + describe 'edit' do + it 'links GET /admin/custom_actions/:id/edit' do + expect(get('/admin/custom_actions/42/edit')) + .to route_to('custom_actions#edit', id: "42") end end - describe "update" do - it "links PATCH /admin/custom_actions/:id" do - expect(patch("/admin/custom_actions/42")) - .to route_to("custom_actions#update", id: "42") + describe 'update' do + it 'links PATCH /admin/custom_actions/:id' do + expect(patch('/admin/custom_actions/42')) + .to route_to('custom_actions#update', id: "42") end end - describe "delete" do - it "links DELETE /admin/custom_actions/:id" do - expect(delete("/admin/custom_actions/42")) - .to route_to("custom_actions#destroy", id: "42") + describe 'delete' do + it 'links DELETE /admin/custom_actions/:id' do + expect(delete('/admin/custom_actions/42')) + .to route_to('custom_actions#destroy', id: "42") end end end diff --git a/spec/routing/enterprise_routing_spec.rb b/spec/routing/enterprise_routing_spec.rb index e85da5d66aed..4315243940b6 100644 --- a/spec/routing/enterprise_routing_spec.rb +++ b/spec/routing/enterprise_routing_spec.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe EnterprisesController do context "when `ee_manager_visible`" do - it "connects GET /admin/enterprise to enterprises#show" do + it 'connects GET /admin/enterprise to enterprises#show' do allow(OpenProject::Configuration).to receive(:ee_manager_visible?).and_return(true) - expect(get("/admin/enterprise")).to route_to(controller: "enterprises", - action: "show") + expect(get('/admin/enterprise')).to route_to(controller: 'enterprises', + action: 'show') end end context "when NOT `ee_manager_visible`" do - it "GET /admin/enterprise should not route to enterprise#show" do + it 'GET /admin/enterprise should not route to enterprise#show' do # With such a configuration and in case a token is present, the might be a # good reason not to reveal the enterpise token to the admin. # Think of cloud solutions for instance. allow(OpenProject::Configuration).to receive(:ee_manager_visible?).and_return(false) - expect(get("/admin/enterprise")).not_to route_to(controller: "enterprises", - action: "show") + expect(get('/admin/enterprise')).not_to route_to(controller: 'enterprises', + action: 'show') end end end diff --git a/spec/routing/enumerations_spec.rb b/spec/routing/enumerations_spec.rb index 27927e8c09a9..acd808eb0415 100644 --- a/spec/routing/enumerations_spec.rb +++ b/spec/routing/enumerations_spec.rb @@ -26,41 +26,41 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe EnumerationsController, "routing" do - context "admin scoped" do +RSpec.describe EnumerationsController, 'routing' do + context 'admin scoped' do it { - expect(subject).to route(:get, "admin/enumerations").to(controller: "enumerations", - action: "index") + expect(subject).to route(:get, 'admin/enumerations').to(controller: 'enumerations', + action: 'index') } it { - expect(subject).to route(:get, "admin/enumerations/new").to(controller: "enumerations", - action: "new") + expect(subject).to route(:get, 'admin/enumerations/new').to(controller: 'enumerations', + action: 'new') } it { - expect(subject).to route(:post, "admin/enumerations").to(controller: "enumerations", - action: "create") + expect(subject).to route(:post, 'admin/enumerations').to(controller: 'enumerations', + action: 'create') } it { - expect(subject).to route(:get, "admin/enumerations/1/edit").to(controller: "enumerations", - action: "edit", - id: "1") + expect(subject).to route(:get, 'admin/enumerations/1/edit').to(controller: 'enumerations', + action: 'edit', + id: '1') } it { - expect(subject).to route(:put, "admin/enumerations/1").to(controller: "enumerations", - action: "update", - id: "1") + expect(subject).to route(:put, 'admin/enumerations/1').to(controller: 'enumerations', + action: 'update', + id: '1') } it { - expect(subject).to route(:delete, "admin/enumerations/1").to(controller: "enumerations", - action: "destroy", - id: "1") + expect(subject).to route(:delete, 'admin/enumerations/1').to(controller: 'enumerations', + action: 'destroy', + id: '1') } end end diff --git a/spec/routing/errors_routing_spec.rb b/spec/routing/errors_routing_spec.rb index 236041eb47e6..953b9cb2e856 100644 --- a/spec/routing/errors_routing_spec.rb +++ b/spec/routing/errors_routing_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "errors routing" do - it { is_expected.to route(:get, "/404").to(controller: "errors", action: "not_found") } - it { is_expected.to route(:get, "/422").to(controller: "errors", action: "unacceptable") } - it { is_expected.to route(:get, "/500").to(controller: "errors", action: "internal_error") } +RSpec.describe 'errors routing' do + it { is_expected.to route(:get, '/404').to(controller: 'errors', action: 'not_found') } + it { is_expected.to route(:get, '/422').to(controller: 'errors', action: 'unacceptable') } + it { is_expected.to route(:get, '/500').to(controller: 'errors', action: 'internal_error') } end diff --git a/spec/routing/forums_routing_spec.rb b/spec/routing/forums_routing_spec.rb index 006f0f3962cd..95382946c583 100644 --- a/spec/routing/forums_routing_spec.rb +++ b/spec/routing/forums_routing_spec.rb @@ -26,75 +26,75 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ForumsController do it { - expect(subject).to route(:get, "/projects/world_domination/forums").to(controller: "forums", - action: "index", - project_id: "world_domination") + expect(subject).to route(:get, '/projects/world_domination/forums').to(controller: 'forums', + action: 'index', + project_id: 'world_domination') } it { - expect(subject).to route(:get, "/projects/world_domination/forums/new").to(controller: "forums", - action: "new", - project_id: "world_domination") + expect(subject).to route(:get, '/projects/world_domination/forums/new').to(controller: 'forums', + action: 'new', + project_id: 'world_domination') } it { - expect(subject).to route(:post, "/projects/world_domination/forums").to(controller: "forums", - action: "create", - project_id: "world_domination") + expect(subject).to route(:post, '/projects/world_domination/forums').to(controller: 'forums', + action: 'create', + project_id: 'world_domination') } it { - expect(subject).to route(:get, "/projects/world_domination/forums/44").to(controller: "forums", - action: "show", - project_id: "world_domination", - id: "44") + expect(subject).to route(:get, '/projects/world_domination/forums/44').to(controller: 'forums', + action: 'show', + project_id: 'world_domination', + id: '44') } it { - expect(get("/projects/abc/forums/1.atom")) - .to route_to(controller: "forums", - action: "show", - project_id: "abc", - id: "1", - format: "atom") + expect(get('/projects/abc/forums/1.atom')) + .to route_to(controller: 'forums', + action: 'show', + project_id: 'abc', + id: '1', + format: 'atom') } it { - expect(subject).to route(:get, "/projects/world_domination/forums/44/edit").to(controller: "forums", - action: "edit", - project_id: "world_domination", - id: "44") + expect(subject).to route(:get, '/projects/world_domination/forums/44/edit').to(controller: 'forums', + action: 'edit', + project_id: 'world_domination', + id: '44') } it { - expect(subject).to route(:put, "/projects/world_domination/forums/44").to(controller: "forums", - action: "update", - project_id: "world_domination", - id: "44") + expect(subject).to route(:put, '/projects/world_domination/forums/44').to(controller: 'forums', + action: 'update', + project_id: 'world_domination', + id: '44') } it { - expect(subject).to route(:delete, "/projects/world_domination/forums/44").to(controller: "forums", - action: "destroy", - project_id: "world_domination", - id: "44") + expect(subject).to route(:delete, '/projects/world_domination/forums/44').to(controller: 'forums', + action: 'destroy', + project_id: 'world_domination', + id: '44') } - it "connects GET /projects/:project/forums/:forum/move to forums#move" do - expect(get("/projects/1/forums/1/move")).to route_to(controller: "forums", - action: "move", - project_id: "1", - id: "1") + it 'connects GET /projects/:project/forums/:forum/move to forums#move' do + expect(get('/projects/1/forums/1/move')).to route_to(controller: 'forums', + action: 'move', + project_id: '1', + id: '1') end - it "connects POST /projects/:project/forums/:forum/move to forums#move" do - expect(post("/projects/1/forums/1/move")).to route_to(controller: "forums", - action: "move", - project_id: "1", - id: "1") + it 'connects POST /projects/:project/forums/:forum/move to forums#move' do + expect(post('/projects/1/forums/1/move')).to route_to(controller: 'forums', + action: 'move', + project_id: '1', + id: '1') end end diff --git a/spec/routing/groups_spec.rb b/spec/routing/groups_spec.rb index c1c8b8327440..3ac058284651 100644 --- a/spec/routing/groups_spec.rb +++ b/spec/routing/groups_spec.rb @@ -26,78 +26,78 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "groups routes" do +RSpec.describe 'groups routes' do it { - expect(subject).to route(:get, "/admin/groups").to(controller: "groups", - action: "index") + expect(subject).to route(:get, '/admin/groups').to(controller: 'groups', + action: 'index') } it { - expect(subject).to route(:get, "/admin/groups/new").to(controller: "groups", - action: "new") + expect(subject).to route(:get, '/admin/groups/new').to(controller: 'groups', + action: 'new') } it { - expect(subject).to route(:post, "/admin/groups").to(controller: "groups", - action: "create") + expect(subject).to route(:post, '/admin/groups').to(controller: 'groups', + action: 'create') } it { - expect(subject).to route(:get, "/groups/4").to(controller: "groups", - action: "show", - id: "4") + expect(subject).to route(:get, '/groups/4').to(controller: 'groups', + action: 'show', + id: '4') } it { - expect(subject).to route(:get, "/admin/groups/4/edit").to(controller: "groups", - action: "edit", - id: "4") + expect(subject).to route(:get, '/admin/groups/4/edit').to(controller: 'groups', + action: 'edit', + id: '4') } it { - expect(subject).to route(:put, "/admin/groups/4").to(controller: "groups", - action: "update", - id: "4") + expect(subject).to route(:put, '/admin/groups/4').to(controller: 'groups', + action: 'update', + id: '4') } it { - expect(subject).to route(:delete, "/admin/groups/4").to(controller: "groups", - action: "destroy", - id: "4") + expect(subject).to route(:delete, '/admin/groups/4').to(controller: 'groups', + action: 'destroy', + id: '4') } it { - expect(subject).to route(:post, "/admin/groups/4/members").to(controller: "groups", - action: "add_users", - id: "4") + expect(subject).to route(:post, '/admin/groups/4/members').to(controller: 'groups', + action: 'add_users', + id: '4') } it { - expect(subject).to route(:delete, "/admin/groups/4/members/5").to(controller: "groups", - action: "remove_user", - id: "4", - user_id: "5") + expect(subject).to route(:delete, '/admin/groups/4/members/5').to(controller: 'groups', + action: 'remove_user', + id: '4', + user_id: '5') } it { - expect(subject).to route(:post, "/admin/groups/4/memberships").to(controller: "groups", - action: "create_memberships", - id: "4") + expect(subject).to route(:post, '/admin/groups/4/memberships').to(controller: 'groups', + action: 'create_memberships', + id: '4') } it { - expect(subject).to route(:put, "/admin/groups/4/memberships/5").to(controller: "groups", - action: "edit_membership", - id: "4", - membership_id: "5") + expect(subject).to route(:put, '/admin/groups/4/memberships/5').to(controller: 'groups', + action: 'edit_membership', + id: '4', + membership_id: '5') } it { - expect(subject).to route(:delete, "/admin/groups/4/memberships/5").to(controller: "groups", - action: "destroy_membership", - id: "4", - membership_id: "5") + expect(subject).to route(:delete, '/admin/groups/4/memberships/5').to(controller: 'groups', + action: 'destroy_membership', + id: '4', + membership_id: '5') } end diff --git a/spec/routing/help_routing_spec.rb b/spec/routing/help_routing_spec.rb index a5fb8868c53f..0b70d5e7c7c5 100644 --- a/spec/routing/help_routing_spec.rb +++ b/spec/routing/help_routing_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe HelpController do - it "connects GET /help/keyboard_shortcuts to help#keyboard_shortcuts" do - expect(get("/help/keyboard_shortcuts")) - .to route_to(controller: "help", - action: "keyboard_shortcuts") + it 'connects GET /help/keyboard_shortcuts to help#keyboard_shortcuts' do + expect(get('/help/keyboard_shortcuts')) + .to route_to(controller: 'help', + action: 'keyboard_shortcuts') end end diff --git a/spec/routing/homescreen_spec.rb b/spec/routing/homescreen_spec.rb index 25fe6f445183..4b76d48e915f 100644 --- a/spec/routing/homescreen_spec.rb +++ b/spec/routing/homescreen_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "homescreen routes" do - it "/ routes to homscreen#index" do - expect(get("/")).to route_to("homescreen#index") +RSpec.describe 'homescreen routes' do + it '/ routes to homscreen#index' do + expect(get('/')).to route_to('homescreen#index') end end diff --git a/spec/routing/journals_spec.rb b/spec/routing/journals_spec.rb index 0f203eeeabc8..076c95ecfd5b 100644 --- a/spec/routing/journals_spec.rb +++ b/spec/routing/journals_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe JournalsController do - it "connects GET /journals/ to journals#index" do - expect(get("/journals/")).to route_to(controller: "journals", - action: "index") + it 'connects GET /journals/ to journals#index' do + expect(get('/journals/')).to route_to(controller: 'journals', + action: 'index') end - it "connects GET /journals/:id/diff to journals#idff" do - expect(get("/journals/123/diff/description")) - .to route_to(controller: "journals", - action: "diff", - field: "description", - id: "123") + it 'connects GET /journals/:id/diff to journals#idff' do + expect(get('/journals/123/diff/description')) + .to route_to(controller: 'journals', + action: 'diff', + field: 'description', + id: '123') end end diff --git a/spec/routing/language_settings_routing_spec.rb b/spec/routing/language_settings_routing_spec.rb index 8f8e652a1199..2217fde53412 100644 --- a/spec/routing/language_settings_routing_spec.rb +++ b/spec/routing/language_settings_routing_spec.rb @@ -29,18 +29,18 @@ # ++ # -require "spec_helper" +require 'spec_helper' -RSpec.describe "Language Settings routes" do +RSpec.describe 'Language Settings routes' do it do - expect(get("/admin/settings/languages")) - .to route_to(controller: "admin/settings/languages_settings", - action: "show") + expect(get('/admin/settings/languages')) + .to route_to(controller: 'admin/settings/languages_settings', + action: 'show') end it do - expect(patch("/admin/settings/languages")) - .to route_to(controller: "admin/settings/languages_settings", - action: "update") + expect(patch('/admin/settings/languages')) + .to route_to(controller: 'admin/settings/languages_settings', + action: 'update') end end diff --git a/spec/routing/messages_spec.rb b/spec/routing/messages_spec.rb index b8241014d2b5..a0072d6a4bca 100644 --- a/spec/routing/messages_spec.rb +++ b/spec/routing/messages_spec.rb @@ -26,56 +26,56 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe MessagesController, "routing" do - context "project scoped" do +RSpec.describe MessagesController, 'routing' do + context 'project scoped' do it { - expect(subject).to route(:get, "/forums/lala/topics/new").to(controller: "messages", - action: "new", - forum_id: "lala") + expect(subject).to route(:get, '/forums/lala/topics/new').to(controller: 'messages', + action: 'new', + forum_id: 'lala') } it { - expect(subject).to route(:post, "/forums/lala/topics").to(controller: "messages", - action: "create", - forum_id: "lala") + expect(subject).to route(:post, '/forums/lala/topics').to(controller: 'messages', + action: 'create', + forum_id: 'lala') } end it { - expect(subject).to route(:get, "/topics/2").to(controller: "messages", - action: "show", - id: "2") + expect(subject).to route(:get, '/topics/2').to(controller: 'messages', + action: 'show', + id: '2') } it { - expect(subject).to route(:get, "/topics/22/edit").to(controller: "messages", - action: "edit", - id: "22") + expect(subject).to route(:get, '/topics/22/edit').to(controller: 'messages', + action: 'edit', + id: '22') } it { - expect(subject).to route(:put, "/topics/22").to(controller: "messages", - action: "update", - id: "22") + expect(subject).to route(:put, '/topics/22').to(controller: 'messages', + action: 'update', + id: '22') } it { - expect(subject).to route(:delete, "/topics/555").to(controller: "messages", - action: "destroy", - id: "555") + expect(subject).to route(:delete, '/topics/555').to(controller: 'messages', + action: 'destroy', + id: '555') } it { - expect(subject).to route(:get, "/topics/22/quote").to(controller: "messages", - action: "quote", - id: "22") + expect(subject).to route(:get, '/topics/22/quote').to(controller: 'messages', + action: 'quote', + id: '22') } it { - expect(subject).to route(:post, "/topics/555/reply").to(controller: "messages", - action: "reply", - id: "555") + expect(subject).to route(:post, '/topics/555/reply').to(controller: 'messages', + action: 'reply', + id: '555') } end diff --git a/spec/routing/my_spec.rb b/spec/routing/my_spec.rb index b17d28065888..48bddc8916ba 100644 --- a/spec/routing/my_spec.rb +++ b/spec/routing/my_spec.rb @@ -26,47 +26,47 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "my routes" do - it "/my/account GET routes to my#account" do - expect(get("/my/account")).to route_to("my#account") +RSpec.describe 'my routes' do + it '/my/account GET routes to my#account' do + expect(get('/my/account')).to route_to('my#account') end - it "/my/account PATCH routes to my#update_account" do - expect(patch("/my/account")).to route_to("my#update_account") + it '/my/account PATCH routes to my#update_account' do + expect(patch('/my/account')).to route_to('my#update_account') end - it "/my/settings GET routes to my#settings" do - expect(get("/my/settings")).to route_to("my#settings") + it '/my/settings GET routes to my#settings' do + expect(get('/my/settings')).to route_to('my#settings') end - it "/my/settings PATCH routes to my#update_account" do - expect(patch("/my/settings")).to route_to("my#update_settings") + it '/my/settings PATCH routes to my#update_account' do + expect(patch('/my/settings')).to route_to('my#update_settings') end - it "/my/notifications GET routes to my#notifications" do - expect(get("/my/notifications")).to route_to("my#notifications") + it '/my/notifications GET routes to my#notifications' do + expect(get('/my/notifications')).to route_to('my#notifications') end - it "/my/reminders GET routes to my#notifications" do - expect(get("/my/reminders")).to route_to("my#reminders") + it '/my/reminders GET routes to my#notifications' do + expect(get('/my/reminders')).to route_to('my#reminders') end - it "/my/generate_rss_key POST routes to my#generate_rss_key" do - expect(post("/my/generate_rss_key")).to route_to("my#generate_rss_key") + it '/my/generate_rss_key POST routes to my#generate_rss_key' do + expect(post('/my/generate_rss_key')).to route_to('my#generate_rss_key') end - it "/my/generate_api_key POST routes to my#generate_api_key" do - expect(post("/my/generate_api_key")).to route_to("my#generate_api_key") + it '/my/generate_api_key POST routes to my#generate_api_key' do + expect(post('/my/generate_api_key')).to route_to('my#generate_api_key') end - it "/my/deletion_info GET routes to users#deletion_info" do - expect(get("/my/deletion_info")).to route_to(controller: "users", - action: "deletion_info") + it '/my/deletion_info GET routes to users#deletion_info' do + expect(get('/my/deletion_info')).to route_to(controller: 'users', + action: 'deletion_info') end - it "/my/revoke_ical_token DELETE routes to my#revoke_ical_token" do - expect(delete("/my/revoke_ical_token")).to route_to("my#revoke_ical_token") + it '/my/revoke_ical_token DELETE routes to my#revoke_ical_token' do + expect(delete('/my/revoke_ical_token')).to route_to('my#revoke_ical_token') end end diff --git a/spec/routing/news_comments_spec.rb b/spec/routing/news_comments_spec.rb index b996f59bc7c6..bea9835a61d0 100644 --- a/spec/routing/news_comments_spec.rb +++ b/spec/routing/news_comments_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe News::CommentsController, "routing" do - context "news scoped" do +RSpec.describe News::CommentsController, 'routing' do + context 'news scoped' do it { - expect(subject).to route(:post, "/news/567/comments").to(controller: "news/comments", - action: "create", - news_id: "567") + expect(subject).to route(:post, '/news/567/comments').to(controller: 'news/comments', + action: 'create', + news_id: '567') } end it { - expect(subject).to route(:delete, "/comments/15").to(controller: "news/comments", - action: "destroy", - id: "15") + expect(subject).to route(:delete, '/comments/15').to(controller: 'news/comments', + action: 'destroy', + id: '15') } end diff --git a/spec/routing/news_spec.rb b/spec/routing/news_spec.rb index fd767fdf0788..e59b81e13ff5 100644 --- a/spec/routing/news_spec.rb +++ b/spec/routing/news_spec.rb @@ -26,76 +26,76 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe NewsController, "routing" do - context "project scoped" do +RSpec.describe NewsController, 'routing' do + context 'project scoped' do it { - expect(subject).to route(:get, "/projects/567/news").to(controller: "news", - action: "index", - project_id: "567") + expect(subject).to route(:get, '/projects/567/news').to(controller: 'news', + action: 'index', + project_id: '567') } it do - expect(get("/projects/567/news.atom")) - .to route_to(controller: "news", - action: "index", - format: "atom", - project_id: "567") + expect(get('/projects/567/news.atom')) + .to route_to(controller: 'news', + action: 'index', + format: 'atom', + project_id: '567') end it { - expect(subject).to route(:get, "/projects/567/news/new").to(controller: "news", - action: "new", - project_id: "567") + expect(subject).to route(:get, '/projects/567/news/new').to(controller: 'news', + action: 'new', + project_id: '567') } it { - expect(subject).to route(:post, "/projects/567/news").to(controller: "news", - action: "create", - project_id: "567") + expect(subject).to route(:post, '/projects/567/news').to(controller: 'news', + action: 'create', + project_id: '567') } end it { - expect(subject).to route(:get, "/news").to(controller: "news", - action: "index") + expect(subject).to route(:get, '/news').to(controller: 'news', + action: 'index') } it do - expect(get("/news.atom")) - .to route_to(controller: "news", - action: "index", - format: "atom") + expect(get('/news.atom')) + .to route_to(controller: 'news', + action: 'index', + format: 'atom') end it { - expect(subject).to route(:get, "/news/2").to(controller: "news", - action: "show", - id: "2") + expect(subject).to route(:get, '/news/2').to(controller: 'news', + action: 'show', + id: '2') } it { - expect(subject).to route(:get, "/news/234").to(controller: "news", - action: "show", - id: "234") + expect(subject).to route(:get, '/news/234').to(controller: 'news', + action: 'show', + id: '234') } it { - expect(subject).to route(:get, "/news/567/edit").to(controller: "news", - action: "edit", - id: "567") + expect(subject).to route(:get, '/news/567/edit').to(controller: 'news', + action: 'edit', + id: '567') } it { - expect(subject).to route(:put, "/news/567").to(controller: "news", - action: "update", - id: "567") + expect(subject).to route(:put, '/news/567').to(controller: 'news', + action: 'update', + id: '567') } it { - expect(subject).to route(:delete, "/news/567").to(controller: "news", - action: "destroy", - id: "567") + expect(subject).to route(:delete, '/news/567').to(controller: 'news', + action: 'destroy', + id: '567') } end diff --git a/spec/routing/old_issue_2_wp_spec.rb b/spec/routing/old_issue_2_wp_spec.rb index 6b5022b0df58..b4b579b9d23c 100644 --- a/spec/routing/old_issue_2_wp_spec.rb +++ b/spec/routing/old_issue_2_wp_spec.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "routes for old issue uris", type: :request do +RSpec.describe 'routes for old issue uris', type: :request do # These are routing specs and should be moved to # spec/routing. # As redirect_to is not supported by routing specs they have # to be marked as type request. However, this breaks when # moving them to spec/routing. - describe "for index action" do + describe 'for index action' do before do - get("/issues") + get('/issues') end it do expect(last_response).to be_redirect - expect(last_response.location).to end_with "/work_packages" + expect(last_response.location).to end_with '/work_packages' end end - describe "with specific id" do + describe 'with specific id' do before do - get("/issues/1234") + get('/issues/1234') end it do expect(last_response).to be_redirect - expect(last_response.location).to end_with "/work_packages/1234" + expect(last_response.location).to end_with '/work_packages/1234' end end end diff --git a/spec/routing/project_menu_routing_spec.rb b/spec/routing/project_menu_routing_spec.rb index 47b6ca36165f..6930406b3fbe 100644 --- a/spec/routing/project_menu_routing_spec.rb +++ b/spec/routing/project_menu_routing_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Project menu routes" do - it "/projects/menu GET routes to projects/menus#show" do - expect(get("/projects/menu")).to route_to("projects/menus#show") +RSpec.describe 'Project menu routes' do + it '/projects/menu GET routes to projects/menus#show' do + expect(get('/projects/menu')).to route_to('projects/menus#show') end end diff --git a/spec/routing/project_queries_routing_spec.rb b/spec/routing/project_queries_routing_spec.rb index 42fb68c6238b..5afb3a77bf87 100644 --- a/spec/routing/project_queries_routing_spec.rb +++ b/spec/routing/project_queries_routing_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Project query routes" do - it "/projects/queries/new GET routes to projects/queries#new" do - expect(get("/projects/queries/new")).to route_to("projects/queries#new") +RSpec.describe 'Project query routes' do + it '/projects/queries/new GET routes to projects/queries#new' do + expect(get('/projects/queries/new')).to route_to('projects/queries#new') end - it "/projects/queries POST routes to projects/queries#create" do - expect(post("/projects/queries")).to route_to("projects/queries#create") + it '/projects/queries POST routes to projects/queries#create' do + expect(post('/projects/queries')).to route_to('projects/queries#create') end - it "/projects/queries/:id DELETE routes to projects/queries#destroy" do - expect(delete("/projects/queries/42")).to route_to("projects/queries#destroy", - id: "42") + it '/projects/queries/:id DELETE routes to projects/queries#destroy' do + expect(delete('/projects/queries/42')).to route_to('projects/queries#destroy', + id: '42') end end diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 48dcd876b731..1fbc02b3c4cc 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -26,95 +26,95 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ProjectsController do - describe "index" do + describe 'index' do it do - expect(get("/projects")).to route_to( - controller: "projects", action: "index" + expect(get('/projects')).to route_to( + controller: 'projects', action: 'index' ) end it do - expect(get("/projects.csv")).to route_to( - controller: "projects", action: "index", format: "csv" + expect(get('/projects.csv')).to route_to( + controller: 'projects', action: 'index', format: 'csv' ) end it do - expect(get("/projects.xls")).to route_to( - controller: "projects", action: "index", format: "xls" + expect(get('/projects.xls')).to route_to( + controller: 'projects', action: 'index', format: 'xls' ) end end - describe "new" do + describe 'new' do it do - expect(get("/projects/new")).to route_to( - controller: "projects", action: "new" + expect(get('/projects/new')).to route_to( + controller: 'projects', action: 'new' ) end end - describe "destroy_info" do + describe 'destroy_info' do it do - expect(get("/projects/123/destroy_info")).to route_to( - controller: "projects", action: "destroy_info", id: "123" + expect(get('/projects/123/destroy_info')).to route_to( + controller: 'projects', action: 'destroy_info', id: '123' ) end end - describe "delete" do + describe 'delete' do it do - expect(delete("/projects/123")).to route_to( - controller: "projects", action: "destroy", id: "123" + expect(delete('/projects/123')).to route_to( + controller: 'projects', action: 'destroy', id: '123' ) end it do - expect(delete("/projects/123.xml")).to route_to( - controller: "projects", action: "destroy", id: "123", format: "xml" + expect(delete('/projects/123.xml')).to route_to( + controller: 'projects', action: 'destroy', id: '123', format: 'xml' ) end end - describe "templated" do + describe 'templated' do it do - expect(delete("/projects/123/templated")) - .to route_to(controller: "projects/templated", action: "destroy", project_id: "123") + expect(delete('/projects/123/templated')) + .to route_to(controller: 'projects/templated', action: 'destroy', project_id: '123') end it do - expect(post("/projects/123/templated")) - .to route_to(controller: "projects/templated", action: "create", project_id: "123") + expect(post('/projects/123/templated')) + .to route_to(controller: 'projects/templated', action: 'create', project_id: '123') end end - describe "miscellaneous" do + describe 'miscellaneous' do it do - expect(post("projects/123/archive")).to route_to( - controller: "projects/archive", action: "create", project_id: "123" + expect(post('projects/123/archive')).to route_to( + controller: 'projects/archive', action: 'create', project_id: '123' ) end it do - expect(delete("projects/123/archive")).to route_to( - controller: "projects/archive", action: "destroy", project_id: "123" + expect(delete('projects/123/archive')).to route_to( + controller: 'projects/archive', action: 'destroy', project_id: '123' ) end it do - expect(get("projects/123/copy")).to route_to( - controller: "projects", action: "copy", id: "123" + expect(get('projects/123/copy')).to route_to( + controller: 'projects', action: 'copy', id: '123' ) end end - describe "types" do + describe 'types' do it do - expect(patch("/projects/123/types")).to route_to( - controller: "projects", action: "types", id: "123" + expect(patch('/projects/123/types')).to route_to( + controller: 'projects', action: 'types', id: '123' ) end end diff --git a/spec/routing/project_settings_routing_spec.rb b/spec/routing/project_settings_routing_spec.rb index 6cddb44c2043..8cd350d92b95 100644 --- a/spec/routing/project_settings_routing_spec.rb +++ b/spec/routing/project_settings_routing_spec.rb @@ -26,84 +26,84 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::SettingsController do - describe "show" do + describe 'show' do it do - expect(get("/projects/123/settings/general")) + expect(get('/projects/123/settings/general')) .to route_to( - controller: "projects/settings/general", action: "show", project_id: "123" + controller: 'projects/settings/general', action: 'show', project_id: '123' ) end it do - expect(get("/projects/123/settings/modules")) + expect(get('/projects/123/settings/modules')) .to route_to( - controller: "projects/settings/modules", action: "show", project_id: "123" + controller: 'projects/settings/modules', action: 'show', project_id: '123' ) end it do - expect(patch("/projects/123/settings/modules")) + expect(patch('/projects/123/settings/modules')) .to route_to( - controller: "projects/settings/modules", action: "update", project_id: "123" + controller: 'projects/settings/modules', action: 'update', project_id: '123' ) end it do - expect(get("/projects/123/settings/custom_fields")) + expect(get('/projects/123/settings/custom_fields')) .to route_to( - controller: "projects/settings/custom_fields", action: "show", project_id: "123" + controller: 'projects/settings/custom_fields', action: 'show', project_id: '123' ) end it do - expect(patch("/projects/123/settings/custom_fields")) + expect(patch('/projects/123/settings/custom_fields')) .to route_to( - controller: "projects/settings/custom_fields", action: "update", project_id: "123" + controller: 'projects/settings/custom_fields', action: 'update', project_id: '123' ) end it do - expect(get("/projects/123/settings/versions")) + expect(get('/projects/123/settings/versions')) .to route_to( - controller: "projects/settings/versions", action: "show", project_id: "123" + controller: 'projects/settings/versions', action: 'show', project_id: '123' ) end it do - expect(get("/projects/123/settings/categories")) + expect(get('/projects/123/settings/categories')) .to route_to( - controller: "projects/settings/categories", action: "show", project_id: "123" + controller: 'projects/settings/categories', action: 'show', project_id: '123' ) end it do - expect(get("/projects/123/settings/repository")) + expect(get('/projects/123/settings/repository')) .to route_to( - controller: "projects/settings/repository", action: "show", project_id: "123" + controller: 'projects/settings/repository', action: 'show', project_id: '123' ) end it do - expect(get("/projects/123/settings/time_entry_activities")) + expect(get('/projects/123/settings/time_entry_activities')) .to route_to( - controller: "projects/settings/time_entry_activities", action: "show", project_id: "123" + controller: 'projects/settings/time_entry_activities', action: 'show', project_id: '123' ) end it do - expect(get("/projects/123/settings/types")) + expect(get('/projects/123/settings/types')) .to route_to( - controller: "projects/settings/types", action: "show", project_id: "123" + controller: 'projects/settings/types', action: 'show', project_id: '123' ) end it do - expect(patch("/projects/123/settings/types")) + expect(patch('/projects/123/settings/types')) .to route_to( - controller: "projects/settings/types", action: "update", project_id: "123" + controller: 'projects/settings/types', action: 'update', project_id: '123' ) end end diff --git a/spec/routing/repositories_routing_spec.rb b/spec/routing/repositories_routing_spec.rb index e45e7cbfdd81..8f99035bd31c 100644 --- a/spec/routing/repositories_routing_spec.rb +++ b/spec/routing/repositories_routing_spec.rb @@ -26,334 +26,334 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe RepositoriesController do - describe "show" do + describe 'show' do it { - expect(get("/projects/testproject/repository")) - .to route_to(controller: "repositories", - action: "show", - format: "html", - project_id: "testproject") + expect(get('/projects/testproject/repository')) + .to route_to(controller: 'repositories', + action: 'show', + format: 'html', + project_id: 'testproject') } it { - expect(get("/projects/testproject/repository/path/to/file.c")) - .to route_to(controller: "repositories", - action: "show", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c") + expect(get('/projects/testproject/repository/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'show', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c') } it { - expect(get("/projects/testproject/repository/folder%20with%20spaces")) - .to route_to(controller: "repositories", - action: "show", - format: "html", - project_id: "testproject", - repo_path: "folder with spaces") + expect(get('/projects/testproject/repository/folder%20with%20spaces')) + .to route_to(controller: 'repositories', + action: 'show', + format: 'html', + project_id: 'testproject', + repo_path: 'folder with spaces') } it { - expect(get("/projects/testproject/repository/revisions/5")) - .to route_to(controller: "repositories", - action: "show", - format: "html", - rev: "5", - project_id: "testproject") + expect(get('/projects/testproject/repository/revisions/5')) + .to route_to(controller: 'repositories', + action: 'show', + format: 'html', + rev: '5', + project_id: 'testproject') } end - describe "changes with js file (regression #24960)" do + describe 'changes with js file (regression #24960)' do it { - expect(get("/projects/testproject/repository/revisions/my-branch/changes/assets/test.js")) - .to route_to(controller: "repositories", - action: "changes", - repo_path: "assets/test.js", - rev: "my-branch", - format: "html", - project_id: "testproject") + expect(get('/projects/testproject/repository/revisions/my-branch/changes/assets/test.js')) + .to route_to(controller: 'repositories', + action: 'changes', + repo_path: 'assets/test.js', + rev: 'my-branch', + format: 'html', + project_id: 'testproject') } end - describe "show with git tags (regression test #27230)" do + describe 'show with git tags (regression test #27230)' do it { - expect(get("/projects/testproject/repository/sub?rev=mytags%2Ffoo&branch=&tag=mytags%2Ffoo")) - .to route_to(controller: "repositories", - action: "show", - repo_path: "sub", - branch: "", - rev: "mytags/foo", - tag: "mytags/foo", - format: "html", - project_id: "testproject") + expect(get('/projects/testproject/repository/sub?rev=mytags%2Ffoo&branch=&tag=mytags%2Ffoo')) + .to route_to(controller: 'repositories', + action: 'show', + repo_path: 'sub', + branch: '', + rev: 'mytags/foo', + tag: 'mytags/foo', + format: 'html', + project_id: 'testproject') } it { - expect(get("/projects/testproject/repository?rev=FSubCommit-a&branch=master&tag=FSubCommit-a")) - .to route_to(controller: "repositories", - action: "show", - branch: "master", - rev: "FSubCommit-a", - tag: "FSubCommit-a", - format: "html", - project_id: "testproject") + expect(get('/projects/testproject/repository?rev=FSubCommit-a&branch=master&tag=FSubCommit-a')) + .to route_to(controller: 'repositories', + action: 'show', + branch: 'master', + rev: 'FSubCommit-a', + tag: 'FSubCommit-a', + format: 'html', + project_id: 'testproject') } it { - expect(get("/projects/testproject/repository/revisions/FSubCommit-a/sub")) - .to route_to(controller: "repositories", - action: "show", - repo_path: "sub", - rev: "FSubCommit-a", - format: "html", - project_id: "testproject") + expect(get('/projects/testproject/repository/revisions/FSubCommit-a/sub')) + .to route_to(controller: 'repositories', + action: 'show', + repo_path: 'sub', + rev: 'FSubCommit-a', + format: 'html', + project_id: 'testproject') } end - describe "create" do + describe 'create' do it { - expect(post("/projects/testproject/repository/")) - .to route_to(controller: "repositories", - action: "create", - project_id: "testproject") + expect(post('/projects/testproject/repository/')) + .to route_to(controller: 'repositories', + action: 'create', + project_id: 'testproject') } end - describe "update" do + describe 'update' do it { - expect(put("/projects/testproject/repository/")) - .to route_to(controller: "repositories", - action: "update", - project_id: "testproject") + expect(put('/projects/testproject/repository/')) + .to route_to(controller: 'repositories', + action: 'update', + project_id: 'testproject') } end - describe "revisions" do + describe 'revisions' do it { - expect(get("/projects/testproject/repository/revisions")) - .to route_to(controller: "repositories", - action: "revisions", - project_id: "testproject") + expect(get('/projects/testproject/repository/revisions')) + .to route_to(controller: 'repositories', + action: 'revisions', + project_id: 'testproject') } it { - expect(get("/projects/testproject/repository/revisions.atom")) - .to route_to(controller: "repositories", - action: "revisions", - project_id: "testproject", - format: "atom") + expect(get('/projects/testproject/repository/revisions.atom')) + .to route_to(controller: 'repositories', + action: 'revisions', + project_id: 'testproject', + format: 'atom') } end - describe "revision" do + describe 'revision' do it { - expect(get("/projects/testproject/repository/revision/2457")) - .to route_to(controller: "repositories", - action: "revision", - project_id: "testproject", - rev: "2457") + expect(get('/projects/testproject/repository/revision/2457')) + .to route_to(controller: 'repositories', + action: 'revision', + project_id: 'testproject', + rev: '2457') } it { - expect(get("/projects/testproject/repository/revision")) - .to route_to(controller: "repositories", - action: "revision", - project_id: "testproject") + expect(get('/projects/testproject/repository/revision')) + .to route_to(controller: 'repositories', + action: 'revision', + project_id: 'testproject') } end - describe "diff" do + describe 'diff' do it { - expect(get("/projects/testproject/repository/revisions/2457/diff")) - .to route_to(format: "html", - controller: "repositories", - action: "diff", - project_id: "testproject", - rev: "2457") + expect(get('/projects/testproject/repository/revisions/2457/diff')) + .to route_to(format: 'html', + controller: 'repositories', + action: 'diff', + project_id: 'testproject', + rev: '2457') } it { - expect(get("/projects/testproject/repository/revisions/2457/diff.diff")) - .to route_to(controller: "repositories", - action: "diff", - project_id: "testproject", - rev: "2457", - format: "diff") + expect(get('/projects/testproject/repository/revisions/2457/diff.diff')) + .to route_to(controller: 'repositories', + action: 'diff', + project_id: 'testproject', + rev: '2457', + format: 'diff') } it { - expect(get("/projects/testproject/repository/diff")) - .to route_to(format: "html", - controller: "repositories", - action: "diff", - project_id: "testproject") + expect(get('/projects/testproject/repository/diff')) + .to route_to(format: 'html', + controller: 'repositories', + action: 'diff', + project_id: 'testproject') } it { - expect(get("/projects/testproject/repository/diff/path/to/file.c")) - .to route_to(format: "html", - controller: "repositories", - action: "diff", - project_id: "testproject", - repo_path: "path/to/file.c") + expect(get('/projects/testproject/repository/diff/path/to/file.c')) + .to route_to(format: 'html', + controller: 'repositories', + action: 'diff', + project_id: 'testproject', + repo_path: 'path/to/file.c') } it { - expect(get("/projects/testproject/repository/revisions/2/diff/path/to/file.c")) - .to route_to(format: "html", - controller: "repositories", - action: "diff", - project_id: "testproject", - repo_path: "path/to/file.c", - rev: "2") + expect(get('/projects/testproject/repository/revisions/2/diff/path/to/file.c')) + .to route_to(format: 'html', + controller: 'repositories', + action: 'diff', + project_id: 'testproject', + repo_path: 'path/to/file.c', + rev: '2') } end - describe "browse" do + describe 'browse' do it { - expect(get("/projects/testproject/repository/browse/path/to/file.c")) - .to route_to(controller: "repositories", - action: "browse", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c") + expect(get('/projects/testproject/repository/browse/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'browse', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c') } end - describe "entry" do + describe 'entry' do it { - expect(get("/projects/testproject/repository/entry/path/to/file.c")) - .to route_to(controller: "repositories", - action: "entry", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c") + expect(get('/projects/testproject/repository/entry/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'entry', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c') } it { - expect(get("/projects/testproject/repository/revisions/2/entry/path/to/file.c")) - .to route_to(controller: "repositories", - action: "entry", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c", - rev: "2") + expect(get('/projects/testproject/repository/revisions/2/entry/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'entry', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c', + rev: '2') } it { - expect(get("/projects/testproject/repository/raw/path/to/file.c")) - .to route_to(controller: "repositories", - action: "entry", - project_id: "testproject", - repo_path: "path/to/file.c", - format: "raw") + expect(get('/projects/testproject/repository/raw/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'entry', + project_id: 'testproject', + repo_path: 'path/to/file.c', + format: 'raw') } it { - expect(get("/projects/testproject/repository/revisions/master/raw/path/to/file.c")) - .to route_to(controller: "repositories", - action: "entry", - project_id: "testproject", - repo_path: "path/to/file.c", - rev: "master", - format: "raw") + expect(get('/projects/testproject/repository/revisions/master/raw/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'entry', + project_id: 'testproject', + repo_path: 'path/to/file.c', + rev: 'master', + format: 'raw') } end - describe "annotate" do + describe 'annotate' do it { - expect(get("/projects/testproject/repository/annotate/path/to/file.c")) - .to route_to(controller: "repositories", - action: "annotate", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c") + expect(get('/projects/testproject/repository/annotate/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'annotate', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c') } it { - expect(get("/projects/testproject/repository/revisions/5/annotate/path/to/file.c")) - .to route_to(controller: "repositories", - action: "annotate", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c", - rev: "5") + expect(get('/projects/testproject/repository/revisions/5/annotate/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'annotate', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c', + rev: '5') } end - describe "changes" do + describe 'changes' do it { - expect(get("/projects/testproject/repository/changes/path/to/file.c")) - .to route_to(controller: "repositories", - action: "changes", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c") + expect(get('/projects/testproject/repository/changes/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'changes', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c') } it { - expect(get("/projects/testproject/repository/revisions/5/changes/path/to/file.c")) - .to route_to(controller: "repositories", - action: "changes", - format: "html", - project_id: "testproject", - repo_path: "path/to/file.c", - rev: "5") + expect(get('/projects/testproject/repository/revisions/5/changes/path/to/file.c')) + .to route_to(controller: 'repositories', + action: 'changes', + format: 'html', + project_id: 'testproject', + repo_path: 'path/to/file.c', + rev: '5') } end - describe "stats" do + describe 'stats' do it { - expect(get("/projects/testproject/repository/statistics")) - .to route_to(controller: "repositories", - action: "stats", - project_id: "testproject") + expect(get('/projects/testproject/repository/statistics')) + .to route_to(controller: 'repositories', + action: 'stats', + project_id: 'testproject') } end - describe "committers" do + describe 'committers' do it { - expect(get("/projects/testproject/repository/committers")) - .to route_to(controller: "repositories", - action: "committers", - project_id: "testproject") + expect(get('/projects/testproject/repository/committers')) + .to route_to(controller: 'repositories', + action: 'committers', + project_id: 'testproject') } it { - expect(post("/projects/testproject/repository/committers")) - .to route_to(controller: "repositories", - action: "committers", - project_id: "testproject") + expect(post('/projects/testproject/repository/committers')) + .to route_to(controller: 'repositories', + action: 'committers', + project_id: 'testproject') } end - describe "graph" do + describe 'graph' do it { - expect(get("/projects/testproject/repository/graph")) - .to route_to(controller: "repositories", - action: "graph", - project_id: "testproject") + expect(get('/projects/testproject/repository/graph')) + .to route_to(controller: 'repositories', + action: 'graph', + project_id: 'testproject') } end - describe "destroy" do + describe 'destroy' do it { - expect(delete("/projects/testproject/repository")) - .to route_to(controller: "repositories", - action: "destroy", - project_id: "testproject") + expect(delete('/projects/testproject/repository')) + .to route_to(controller: 'repositories', + action: 'destroy', + project_id: 'testproject') } end - describe "destroy_info" do + describe 'destroy_info' do it { - expect(get("/projects/testproject/repository/destroy_info")) - .to route_to(controller: "repositories", - action: "destroy_info", - project_id: "testproject") + expect(get('/projects/testproject/repository/destroy_info')) + .to route_to(controller: 'repositories', + action: 'destroy_info', + project_id: 'testproject') } end end diff --git a/spec/routing/roles_spec.rb b/spec/routing/roles_spec.rb index 539d98615aad..909c7bb3a1f9 100644 --- a/spec/routing/roles_spec.rb +++ b/spec/routing/roles_spec.rb @@ -26,51 +26,51 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "roles routes" do - context "admin scoped" do +RSpec.describe 'roles routes' do + context 'admin scoped' do it { - expect(subject).to route(:get, "admin/roles").to(controller: "roles", - action: "index") + expect(subject).to route(:get, 'admin/roles').to(controller: 'roles', + action: 'index') } it { - expect(subject).to route(:get, "admin/roles/new").to(controller: "roles", - action: "new") + expect(subject).to route(:get, 'admin/roles/new').to(controller: 'roles', + action: 'new') } it { - expect(subject).to route(:post, "admin/roles").to(controller: "roles", - action: "create") + expect(subject).to route(:post, 'admin/roles').to(controller: 'roles', + action: 'create') } it { - expect(subject).to route(:get, "admin/roles/1/edit").to(controller: "roles", - action: "edit", - id: "1") + expect(subject).to route(:get, 'admin/roles/1/edit').to(controller: 'roles', + action: 'edit', + id: '1') } it { - expect(subject).to route(:put, "admin/roles/1").to(controller: "roles", - action: "update", - id: "1") + expect(subject).to route(:put, 'admin/roles/1').to(controller: 'roles', + action: 'update', + id: '1') } it { - expect(subject).to route(:delete, "admin/roles/1").to(controller: "roles", - action: "destroy", - id: "1") + expect(subject).to route(:delete, 'admin/roles/1').to(controller: 'roles', + action: 'destroy', + id: '1') } it { - expect(subject).to route(:get, "admin/roles/report").to(controller: "roles", - action: "report") + expect(subject).to route(:get, 'admin/roles/report').to(controller: 'roles', + action: 'report') } it { - expect(subject).to route(:put, "admin/roles").to(controller: "roles", - action: "bulk_update") + expect(subject).to route(:put, 'admin/roles').to(controller: 'roles', + action: 'bulk_update') } end end diff --git a/spec/routing/search_spec.rb b/spec/routing/search_spec.rb index 584c8b5ef896..e790dc49bea0 100644 --- a/spec/routing/search_spec.rb +++ b/spec/routing/search_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe SearchController do - it "connects GET /search to search#index" do - expect(get("/search")).to route_to(controller: "search", - action: "index") + it 'connects GET /search to search#index' do + expect(get('/search')).to route_to(controller: 'search', + action: 'index') end end diff --git a/spec/routing/settings_spec.rb b/spec/routing/settings_spec.rb index 56475202e3bb..9c6316aa59a8 100644 --- a/spec/routing/settings_spec.rb +++ b/spec/routing/settings_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "settings routes" do +RSpec.describe 'settings routes' do it do - expect(get("/admin/settings/plugin/abc")) - .to route_to(controller: "admin/settings", - action: "show_plugin", - id: "abc") + expect(get('/admin/settings/plugin/abc')) + .to route_to(controller: 'admin/settings', + action: 'show_plugin', + id: 'abc') end it do - expect(post("/admin/settings/plugin/abc")) - .to route_to(controller: "admin/settings", - action: "update_plugin", - id: "abc") + expect(post('/admin/settings/plugin/abc')) + .to route_to(controller: 'admin/settings', + action: 'update_plugin', + id: 'abc') end end diff --git a/spec/routing/short_uri_wp_spec.rb b/spec/routing/short_uri_wp_spec.rb index ee9c058ec9fc..73d2a4bb6bb7 100644 --- a/spec/routing/short_uri_wp_spec.rb +++ b/spec/routing/short_uri_wp_spec.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "routes for old issue uris", type: :request do +RSpec.describe 'routes for old issue uris', type: :request do # These are routing specs and should be moved to # spec/routing. # As redirect_to is not supported by routing specs they have # to be marked as type request. However, this breaks when # moving them to spec/routing. - describe "for index action" do + describe 'for index action' do before do - get("/wp") + get('/wp') end it do expect(last_response).to be_redirect - expect(last_response.location).to end_with "/work_packages" + expect(last_response.location).to end_with '/work_packages' end end - describe "with specific id" do + describe 'with specific id' do before do - get("/wp/1234") + get('/wp/1234') end it do expect(last_response).to be_redirect - expect(last_response.location).to end_with "/work_packages/1234" + expect(last_response.location).to end_with '/work_packages/1234' end end end diff --git a/spec/routing/status_routing_spec.rb b/spec/routing/status_routing_spec.rb index 648cf9961a0a..86000f4b84aa 100644 --- a/spec/routing/status_routing_spec.rb +++ b/spec/routing/status_routing_spec.rb @@ -26,34 +26,34 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe StatusesController do - describe "index" do - it { expect(get("/statuses")).to route_to(controller: "statuses", action: "index") } + describe 'index' do + it { expect(get('/statuses')).to route_to(controller: 'statuses', action: 'index') } end - describe "new" do - it { expect(get("/statuses/new")).to route_to(controller: "statuses", action: "new") } + describe 'new' do + it { expect(get('/statuses/new')).to route_to(controller: 'statuses', action: 'new') } end - describe "create" do - it { expect(post("/statuses")).to route_to(controller: "statuses", action: "create") } + describe 'create' do + it { expect(post('/statuses')).to route_to(controller: 'statuses', action: 'create') } end - describe "update" do - it { expect(put("/statuses/123")).to route_to(controller: "statuses", action: "update", id: "123") } + describe 'update' do + it { expect(put('/statuses/123')).to route_to(controller: 'statuses', action: 'update', id: '123') } end - describe "delete" do - it { expect(delete("/statuses/123")).to route_to(controller: "statuses", action: "destroy", id: "123") } + describe 'delete' do + it { expect(delete('/statuses/123')).to route_to(controller: 'statuses', action: 'destroy', id: '123') } end - describe "update_work_package_done_ratio" do + describe 'update_work_package_done_ratio' do it do - expect(post("/statuses/update_work_package_done_ratio")).to route_to( - controller: "statuses", - action: "update_work_package_done_ratio" + expect(post('/statuses/update_work_package_done_ratio')).to route_to( + controller: 'statuses', + action: 'update_work_package_done_ratio' ) end end diff --git a/spec/routing/types_spec.rb b/spec/routing/types_spec.rb index 3251c7367e87..0f0894547e98 100644 --- a/spec/routing/types_spec.rb +++ b/spec/routing/types_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "types routes" do +RSpec.describe 'types routes' do it do - expect(post("/types/move/123")).to route_to(controller: "types", - action: "move", - id: "123") + expect(post('/types/move/123')).to route_to(controller: 'types', + action: 'move', + id: '123') end end diff --git a/spec/routing/user_memberships_routing_spec.rb b/spec/routing/user_memberships_routing_spec.rb index 20929890ed89..85e36ba34664 100644 --- a/spec/routing/user_memberships_routing_spec.rb +++ b/spec/routing/user_memberships_routing_spec.rb @@ -26,28 +26,28 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::MembershipsController do - describe "routing" do - it "connects DELETE users/:user_id/memberships/:id" do - expect(delete("/users/1/memberships/2")).to route_to(controller: "users/memberships", - action: "destroy", - user_id: "1", - id: "2") + describe 'routing' do + it 'connects DELETE users/:user_id/memberships/:id' do + expect(delete('/users/1/memberships/2')).to route_to(controller: 'users/memberships', + action: 'destroy', + user_id: '1', + id: '2') end - it "connects PATCH users/:user_id/memberships/:id" do - expect(patch("/users/1/memberships/2")).to route_to(controller: "users/memberships", - action: "update", - user_id: "1", - id: "2") + it 'connects PATCH users/:user_id/memberships/:id' do + expect(patch('/users/1/memberships/2')).to route_to(controller: 'users/memberships', + action: 'update', + user_id: '1', + id: '2') end - it "connects POST users/:user_id/memberships" do - expect(post("/users/1/memberships")).to route_to(controller: "users/memberships", - action: "create", - user_id: "1") + it 'connects POST users/:user_id/memberships' do + expect(post('/users/1/memberships')).to route_to(controller: 'users/memberships', + action: 'create', + user_id: '1') end end end diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb index bf08b937c333..29611370bfa7 100644 --- a/spec/routing/users_routing_spec.rb +++ b/spec/routing/users_routing_spec.rb @@ -26,110 +26,110 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe UsersController, "routing" do +RSpec.describe UsersController, 'routing' do it { - expect(subject).to route(:get, "/users").to(controller: "users", - action: "index") + expect(subject).to route(:get, '/users').to(controller: 'users', + action: 'index') } it { - expect(get("/users.xml")) - .to route_to controller: "users", - action: "index", - format: "xml" + expect(get('/users.xml')) + .to route_to controller: 'users', + action: 'index', + format: 'xml' } it { - expect(subject).to route(:get, "/users/44").to(controller: "users", - action: "show", - id: "44") + expect(subject).to route(:get, '/users/44').to(controller: 'users', + action: 'show', + id: '44') } it { - expect(get("/users/44.xml")) - .to route_to controller: "users", - action: "show", - id: "44", - format: "xml" + expect(get('/users/44.xml')) + .to route_to controller: 'users', + action: 'show', + id: '44', + format: 'xml' } it { - expect(subject).to route(:get, "/users/me").to(controller: "users", - action: "show", - id: "me") + expect(subject).to route(:get, '/users/me').to(controller: 'users', + action: 'show', + id: 'me') } it { - expect(get("/users/me.xml")) - .to route_to controller: "users", - action: "show", - id: "me", - format: "xml" + expect(get('/users/me.xml')) + .to route_to controller: 'users', + action: 'show', + id: 'me', + format: 'xml' } it { - expect(subject).to route(:get, "/users/new").to(controller: "users", - action: "new") + expect(subject).to route(:get, '/users/new').to(controller: 'users', + action: 'new') } it { - expect(subject).to route(:get, "/users/444/edit").to(controller: "users", - action: "edit", - id: "444") + expect(subject).to route(:get, '/users/444/edit').to(controller: 'users', + action: 'edit', + id: '444') } it { - expect(subject).to route(:get, "/users/222/edit/membership").to(controller: "users", - action: "edit", - id: "222", - tab: "membership") + expect(subject).to route(:get, '/users/222/edit/membership').to(controller: 'users', + action: 'edit', + id: '222', + tab: 'membership') } it { - expect(subject).to route(:post, "/users").to(controller: "users", - action: "create") + expect(subject).to route(:post, '/users').to(controller: 'users', + action: 'create') } it { - expect(post("/users.xml")) - .to route_to controller: "users", - action: "create", - format: "xml" + expect(post('/users.xml')) + .to route_to controller: 'users', + action: 'create', + format: 'xml' } it { - expect(subject).to route(:put, "/users/444").to(controller: "users", - action: "update", - id: "444") + expect(subject).to route(:put, '/users/444').to(controller: 'users', + action: 'update', + id: '444') } it { - expect(put("/users/444.xml")) - .to route_to controller: "users", - action: "update", - id: "444", - format: "xml" + expect(put('/users/444.xml')) + .to route_to controller: 'users', + action: 'update', + id: '444', + format: 'xml' } it { - expect(get("/users/1/change_status/foobar")) - .to route_to controller: "users", - action: "change_status_info", - id: "1", - change_action: "foobar" + expect(get('/users/1/change_status/foobar')) + .to route_to controller: 'users', + action: 'change_status_info', + id: '1', + change_action: 'foobar' } it { - expect(get("/users/1/deletion_info")).to route_to(controller: "users", - action: "deletion_info", - id: "1") + expect(get('/users/1/deletion_info')).to route_to(controller: 'users', + action: 'deletion_info', + id: '1') } it { - expect(delete("/users/1")).to route_to(controller: "users", - action: "destroy", - id: "1") + expect(delete('/users/1')).to route_to(controller: 'users', + action: 'destroy', + id: '1') } end diff --git a/spec/routing/versions_spec.rb b/spec/routing/versions_spec.rb index 972df1ee27fa..20084cc87384 100644 --- a/spec/routing/versions_spec.rb +++ b/spec/routing/versions_spec.rb @@ -26,62 +26,62 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "versions routing" do +RSpec.describe 'versions routing' do it { - expect(subject).to route(:get, "/versions/1").to(controller: "versions", - action: "show", - id: "1") + expect(subject).to route(:get, '/versions/1').to(controller: 'versions', + action: 'show', + id: '1') } it { - expect(subject).to route(:get, "/versions/1/edit").to(controller: "versions", - action: "edit", - id: "1") + expect(subject).to route(:get, '/versions/1/edit').to(controller: 'versions', + action: 'edit', + id: '1') } it { - expect(subject).to route(:patch, "/versions/1").to(controller: "versions", - action: "update", - id: "1") + expect(subject).to route(:patch, '/versions/1').to(controller: 'versions', + action: 'update', + id: '1') } it { - expect(subject).to route(:delete, "/versions/1").to(controller: "versions", - action: "destroy", - id: "1") + expect(subject).to route(:delete, '/versions/1').to(controller: 'versions', + action: 'destroy', + id: '1') } it { - expect(subject).to route(:get, "/versions/1/status_by").to(controller: "versions", - action: "status_by", - id: "1") + expect(subject).to route(:get, '/versions/1/status_by').to(controller: 'versions', + action: 'status_by', + id: '1') } - context "project scoped" do + context 'project scoped' do it { - expect(subject).to route(:get, "/projects/foo/versions/new").to(controller: "versions", - action: "new", - project_id: "foo") + expect(subject).to route(:get, '/projects/foo/versions/new').to(controller: 'versions', + action: 'new', + project_id: 'foo') } it { - expect(subject).to route(:post, "/projects/foo/versions").to(controller: "versions", - action: "create", - project_id: "foo") + expect(subject).to route(:post, '/projects/foo/versions').to(controller: 'versions', + action: 'create', + project_id: 'foo') } it { - expect(subject).to route(:put, "/projects/foo/versions/close_completed").to(controller: "versions", - action: "close_completed", - project_id: "foo") + expect(subject).to route(:put, '/projects/foo/versions/close_completed').to(controller: 'versions', + action: 'close_completed', + project_id: 'foo') } it { - expect(subject).to route(:get, "/projects/foo/roadmap").to(controller: "versions", - action: "index", - project_id: "foo") + expect(subject).to route(:get, '/projects/foo/roadmap').to(controller: 'versions', + action: 'index', + project_id: 'foo') } end end diff --git a/spec/routing/watchers_spec.rb b/spec/routing/watchers_spec.rb index fb674bfb7e68..cb645c53cb8e 100644 --- a/spec/routing/watchers_spec.rb +++ b/spec/routing/watchers_spec.rb @@ -26,34 +26,34 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WatchersController do - shared_examples_for "watched model routes" do + shared_examples_for 'watched model routes' do before do expect(OpenProject::Acts::Watchable::Routes).to receive(:matches?).and_return(true) end - it "connects POST /:object_type/:object_id/watch to watchers#watch" do - expect(post("/#{type}/1/watch")).to route_to(controller: "watchers", - action: "watch", + it 'connects POST /:object_type/:object_id/watch to watchers#watch' do + expect(post("/#{type}/1/watch")).to route_to(controller: 'watchers', + action: 'watch', object_type: type, - object_id: "1") + object_id: '1') end - it "connects DELETE /:object_type/:id/unwatch to watchers#unwatch" do - expect(delete("/#{type}/1/unwatch")).to route_to(controller: "watchers", - action: "unwatch", + it 'connects DELETE /:object_type/:id/unwatch to watchers#unwatch' do + expect(delete("/#{type}/1/unwatch")).to route_to(controller: 'watchers', + action: 'unwatch', object_type: type, - object_id: "1") + object_id: '1') end end - ["issues", "news", "boards", "messages", "wikis", "wiki_pages"].each do |type| + ['issues', 'news', 'boards', 'messages', 'wikis', 'wiki_pages'].each do |type| describe "routing #{type} watches" do let(:type) { type } - it_behaves_like "watched model routes" + it_behaves_like 'watched model routes' end end end diff --git a/spec/routing/wiki_routing_spec.rb b/spec/routing/wiki_routing_spec.rb index f80197df756d..9949de926087 100644 --- a/spec/routing/wiki_routing_spec.rb +++ b/spec/routing/wiki_routing_spec.rb @@ -26,179 +26,179 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiController do - describe "routing" do + describe 'routing' do it { - expect(subject).to route(:get, "/projects/567/wiki").to(controller: "wiki", - action: "show", - project_id: "567") + expect(subject).to route(:get, '/projects/567/wiki').to(controller: 'wiki', + action: 'show', + project_id: '567') } - it "connects GET /projects/:project_id/wiki/:name (without format) to wiki/show" do - expect(get("/projects/abc/wiki/blubs")).to route_to(controller: "wiki", - action: "show", - project_id: "abc", - id: "blubs") + it 'connects GET /projects/:project_id/wiki/:name (without format) to wiki/show' do + expect(get('/projects/abc/wiki/blubs')).to route_to(controller: 'wiki', + action: 'show', + project_id: 'abc', + id: 'blubs') end - it "connects GET /projects/:project_id/wiki/:name (with a dot in it) to wiki/show" do - expect(get("/projects/abc/wiki/blubs.blubs")).to route_to(controller: "wiki", - action: "show", - project_id: "abc", - id: "blubs.blubs") + it 'connects GET /projects/:project_id/wiki/:name (with a dot in it) to wiki/show' do + expect(get('/projects/abc/wiki/blubs.blubs')).to route_to(controller: 'wiki', + action: 'show', + project_id: 'abc', + id: 'blubs.blubs') end - it "connects GET /projects/:project_id/wiki/:name.html to wiki/show" do - expect(get("/projects/abc/wiki/blubs.markdown")).to route_to(controller: "wiki", - action: "show", - project_id: "abc", - id: "blubs", - format: "markdown") + it 'connects GET /projects/:project_id/wiki/:name.html to wiki/show' do + expect(get('/projects/abc/wiki/blubs.markdown')).to route_to(controller: 'wiki', + action: 'show', + project_id: 'abc', + id: 'blubs', + format: 'markdown') end - it "connects GET /projects/:project_id/wiki/new to wiki/new" do - expect(get("/projects/abc/wiki/new")).to route_to(controller: "wiki", - action: "new", - project_id: "abc") + it 'connects GET /projects/:project_id/wiki/new to wiki/new' do + expect(get('/projects/abc/wiki/new')).to route_to(controller: 'wiki', + action: 'new', + project_id: 'abc') end - it "connects GET /projects/:project_id/wiki/:id/new to wiki/new_child" do - expect(get("/projects/abc/wiki/def/new")).to route_to(controller: "wiki", - action: "new_child", - project_id: "abc", - id: "def") + it 'connects GET /projects/:project_id/wiki/:id/new to wiki/new_child' do + expect(get('/projects/abc/wiki/def/new')).to route_to(controller: 'wiki', + action: 'new_child', + project_id: 'abc', + id: 'def') end - it "connects POST /projects/:project_id/wiki/new to wiki/create" do - expect(post("/projects/abc/wiki/new")).to route_to(controller: "wiki", - action: "create", - project_id: "abc") + it 'connects POST /projects/:project_id/wiki/new to wiki/create' do + expect(post('/projects/abc/wiki/new')).to route_to(controller: 'wiki', + action: 'create', + project_id: 'abc') end it { - expect(subject).to route(:get, "/projects/567/wiki/my_page/edit").to(controller: "wiki", - action: "edit", - project_id: "567", - id: "my_page") + expect(subject).to route(:get, '/projects/567/wiki/my_page/edit').to(controller: 'wiki', + action: 'edit', + project_id: '567', + id: 'my_page') } it do - expect(get("/projects/abc/wiki/abc_wiki?version=3")).to route_to(controller: "wiki", - action: "show", - project_id: "abc", - id: "abc_wiki", - version: "3") + expect(get('/projects/abc/wiki/abc_wiki?version=3')).to route_to(controller: 'wiki', + action: 'show', + project_id: 'abc', + id: 'abc_wiki', + version: '3') end - it "connects GET /projects/:project_id/wiki/:id/parent_page to wiki/edit_parent_page" do - expect(get("/projects/abc/wiki/abc_wiki/parent_page")) - .to route_to(controller: "wiki", - action: "edit_parent_page", - project_id: "abc", - id: "abc_wiki") + it 'connects GET /projects/:project_id/wiki/:id/parent_page to wiki/edit_parent_page' do + expect(get('/projects/abc/wiki/abc_wiki/parent_page')) + .to route_to(controller: 'wiki', + action: 'edit_parent_page', + project_id: 'abc', + id: 'abc_wiki') end - it "connects PATCH /projects/:project_id/wiki/:id/parent_page to wiki/update_parent_page" do - expect(patch("/projects/abc/wiki/abc_wiki/parent_page")) - .to route_to(controller: "wiki", - action: "update_parent_page", - project_id: "abc", - id: "abc_wiki") + it 'connects PATCH /projects/:project_id/wiki/:id/parent_page to wiki/update_parent_page' do + expect(patch('/projects/abc/wiki/abc_wiki/parent_page')) + .to route_to(controller: 'wiki', + action: 'update_parent_page', + project_id: 'abc', + id: 'abc_wiki') end - it "connects GET /projects/:project_id/wiki/:id/toc to wiki#index" do - expect(get("/projects/abc/wiki/blubs/toc")).to route_to(controller: "wiki", - action: "index", - project_id: "abc", - id: "blubs") + it 'connects GET /projects/:project_id/wiki/:id/toc to wiki#index' do + expect(get('/projects/abc/wiki/blubs/toc')).to route_to(controller: 'wiki', + action: 'index', + project_id: 'abc', + id: 'blubs') end it { - expect(subject).to route(:get, "/projects/1/wiki/CookBook_documentation/history").to(controller: "wiki", - action: "history", - project_id: "1", - id: "CookBook_documentation") + expect(subject).to route(:get, '/projects/1/wiki/CookBook_documentation/history').to(controller: 'wiki', + action: 'history', + project_id: '1', + id: 'CookBook_documentation') } it { - expect(subject).to route(:get, "/projects/1/wiki/CookBook_documentation/diff").to(controller: "wiki", - action: "diff", - project_id: "1", - id: "CookBook_documentation") + expect(subject).to route(:get, '/projects/1/wiki/CookBook_documentation/diff').to(controller: 'wiki', + action: 'diff', + project_id: '1', + id: 'CookBook_documentation') } it { - expect(subject).to route(:get, "/projects/1/wiki/CookBook_documentation/diff/2").to(controller: "wiki", - action: "diff", - project_id: "1", - id: "CookBook_documentation", - version: "2") + expect(subject).to route(:get, '/projects/1/wiki/CookBook_documentation/diff/2').to(controller: 'wiki', + action: 'diff', + project_id: '1', + id: 'CookBook_documentation', + version: '2') } it { - expect(subject).to route(:get, "/projects/1/wiki/CookBook_documentation/diff/2/vs/1").to(controller: "wiki", - action: "diff", - project_id: "1", - id: "CookBook_documentation", - version: "2", - version_from: "1") + expect(subject).to route(:get, '/projects/1/wiki/CookBook_documentation/diff/2/vs/1').to(controller: 'wiki', + action: 'diff', + project_id: '1', + id: 'CookBook_documentation', + version: '2', + version_from: '1') } it { - expect(subject).to route(:get, "/projects/1/wiki/CookBook_documentation/annotate/2").to(controller: "wiki", - action: "annotate", - project_id: "1", - id: "CookBook_documentation", - version: "2") + expect(subject).to route(:get, '/projects/1/wiki/CookBook_documentation/annotate/2').to(controller: 'wiki', + action: 'annotate', + project_id: '1', + id: 'CookBook_documentation', + version: '2') } it { - expect(subject).to route(:get, "/projects/22/wiki/ladida/rename").to(controller: "wiki", - action: "rename", - project_id: "22", - id: "ladida") + expect(subject).to route(:get, '/projects/22/wiki/ladida/rename').to(controller: 'wiki', + action: 'rename', + project_id: '22', + id: 'ladida') } it { - expect(subject).to route(:get, "/projects/567/wiki/index").to(controller: "wiki", - action: "index", - project_id: "567") + expect(subject).to route(:get, '/projects/567/wiki/index').to(controller: 'wiki', + action: 'index', + project_id: '567') } it { - expect(subject).to route(:get, "/projects/567/wiki/export").to(controller: "wiki", - action: "export", - project_id: "567") + expect(subject).to route(:get, '/projects/567/wiki/export').to(controller: 'wiki', + action: 'export', + project_id: '567') } it { - expect(subject).to route(:patch, "/projects/22/wiki/ladida/rename").to(controller: "wiki", - action: "rename", - project_id: "22", - id: "ladida") + expect(subject).to route(:patch, '/projects/22/wiki/ladida/rename').to(controller: 'wiki', + action: 'rename', + project_id: '22', + id: 'ladida') } it { - expect(subject).to route(:post, "/projects/22/wiki/ladida/protect").to(controller: "wiki", - action: "protect", - project_id: "22", - id: "ladida") + expect(subject).to route(:post, '/projects/22/wiki/ladida/protect').to(controller: 'wiki', + action: 'protect', + project_id: '22', + id: 'ladida') } it { - expect(subject).to route(:put, "/projects/567/wiki/my_page").to(controller: "wiki", - action: "update", - project_id: "567", - id: "my_page") + expect(subject).to route(:put, '/projects/567/wiki/my_page').to(controller: 'wiki', + action: 'update', + project_id: '567', + id: 'my_page') } it { - expect(subject).to route(:delete, "/projects/22/wiki/ladida").to(controller: "wiki", - action: "destroy", - project_id: "22", - id: "ladida") + expect(subject).to route(:delete, '/projects/22/wiki/ladida').to(controller: 'wiki', + action: 'destroy', + project_id: '22', + id: 'ladida') } end end diff --git a/spec/routing/work_package/auto_completes_routing_spec.rb b/spec/routing/work_package/auto_completes_routing_spec.rb index 66bf6862494a..a5527d9603e4 100644 --- a/spec/routing/work_package/auto_completes_routing_spec.rb +++ b/spec/routing/work_package/auto_completes_routing_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::AutoCompletesController do - it "connects GET /work_packages/auto_completes to work_package/auto_complete#index" do - expect(get("/work_packages/auto_complete")).to route_to(controller: "work_packages/auto_completes", - action: "index") + it 'connects GET /work_packages/auto_completes to work_package/auto_complete#index' do + expect(get('/work_packages/auto_complete')).to route_to(controller: 'work_packages/auto_completes', + action: 'index') end - it "connects PUT /work_packages/auto_completes to work_package/auto_complete#index" do - expect(get("/work_packages/auto_complete")).to route_to(controller: "work_packages/auto_completes", - action: "index") + it 'connects PUT /work_packages/auto_completes to work_package/auto_complete#index' do + expect(get('/work_packages/auto_complete')).to route_to(controller: 'work_packages/auto_completes', + action: 'index') end end diff --git a/spec/routing/work_package/reports_routing_spec.rb b/spec/routing/work_package/reports_routing_spec.rb index 9e54db7f55e7..3a482192eb46 100644 --- a/spec/routing/work_package/reports_routing_spec.rb +++ b/spec/routing/work_package/reports_routing_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackagesController do - it "connects GET /project/1/work_packages/report to work_package/report#report" do - expect(get("/projects/1/work_packages/report")).to route_to(controller: "work_packages/reports", - action: "report", - project_id: "1") + it 'connects GET /project/1/work_packages/report to work_package/report#report' do + expect(get('/projects/1/work_packages/report')).to route_to(controller: 'work_packages/reports', + action: 'report', + project_id: '1') end - it "connects GET /project/1/work_packages/report/assigned_to to work_package/report#report_details" do - expect(get("/projects/1/work_packages/report/assigned_to")).to route_to(controller: "work_packages/reports", - action: "report_details", - project_id: "1", - detail: "assigned_to") + it 'connects GET /project/1/work_packages/report/assigned_to to work_package/report#report_details' do + expect(get('/projects/1/work_packages/report/assigned_to')).to route_to(controller: 'work_packages/reports', + action: 'report_details', + project_id: '1', + detail: 'assigned_to') end end diff --git a/spec/routing/work_package/shares/bulk_spec.rb b/spec/routing/work_package/shares/bulk_spec.rb index f4c44164d347..6db0452a3938 100644 --- a/spec/routing/work_package/shares/bulk_spec.rb +++ b/spec/routing/work_package/shares/bulk_spec.rb @@ -28,24 +28,24 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "Work package bulk sharing routing" do - describe "DELETE /work_packages/:work_package_id/shares" do - it "routes to work_packages/shares/bulk#destroy" do - expect(delete("/work_packages/1/shares/bulk")) - .to route_to(controller: "work_packages/shares/bulk", - action: "destroy", - work_package_id: "1") +RSpec.describe 'Work package bulk sharing routing' do + describe 'DELETE /work_packages/:work_package_id/shares' do + it 'routes to work_packages/shares/bulk#destroy' do + expect(delete('/work_packages/1/shares/bulk')) + .to route_to(controller: 'work_packages/shares/bulk', + action: 'destroy', + work_package_id: '1') end end - describe "PATCH /work_packages/:work_package_id/shares" do - it "routes to work_packages/shares/bulk#update" do - expect(patch("/work_packages/1/shares/bulk")) - .to route_to(controller: "work_packages/shares/bulk", - action: "update", - work_package_id: "1") + describe 'PATCH /work_packages/:work_package_id/shares' do + it 'routes to work_packages/shares/bulk#update' do + expect(patch('/work_packages/1/shares/bulk')) + .to route_to(controller: 'work_packages/shares/bulk', + action: 'update', + work_package_id: '1') end end end diff --git a/spec/routing/work_package/shares_spec.rb b/spec/routing/work_package/shares_spec.rb index 4231581980a8..11819d8e9359 100644 --- a/spec/routing/work_package/shares_spec.rb +++ b/spec/routing/work_package/shares_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "work package share routes" do - it "connects DELETE /work_packages/shares/:id to work_packages/shares#delete" do - expect(delete("/work_packages/shares/5")).to route_to(controller: "work_packages/shares", - action: "destroy", - id: "5") +RSpec.describe 'work package share routes' do + it 'connects DELETE /work_packages/shares/:id to work_packages/shares#delete' do + expect(delete('/work_packages/shares/5')).to route_to(controller: 'work_packages/shares', + action: 'destroy', + id: '5') end - it "connects PATCH /work_packages/shares/:id to work_packages/shares#update" do - expect(patch("/work_packages/shares/5")).to route_to(controller: "work_packages/shares", - action: "update", - id: "5") + it 'connects PATCH /work_packages/shares/:id to work_packages/shares#update' do + expect(patch('/work_packages/shares/5')).to route_to(controller: 'work_packages/shares', + action: 'update', + id: '5') end end diff --git a/spec/routing/work_package_bulk_spec.rb b/spec/routing/work_package_bulk_spec.rb index b98f644ac09c..17c9dea1879e 100644 --- a/spec/routing/work_package_bulk_spec.rb +++ b/spec/routing/work_package_bulk_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::BulkController do - it "connects GET /work_packages/bulk/edit to work_package_bulk/edit" do - expect(get("/work_packages/bulk/edit")).to route_to(controller: "work_packages/bulk", - action: "edit") + it 'connects GET /work_packages/bulk/edit to work_package_bulk/edit' do + expect(get('/work_packages/bulk/edit')).to route_to(controller: 'work_packages/bulk', + action: 'edit') end - it "connects PUT /work_packages/bulk/update to work_package_bulk#update" do - expect(put("/work_packages/bulk")).to route_to(controller: "work_packages/bulk", - action: "update") + it 'connects PUT /work_packages/bulk/update to work_package_bulk#update' do + expect(put('/work_packages/bulk')).to route_to(controller: 'work_packages/bulk', + action: 'update') end - it "connects DELETE /work_packages/bulk to work_package_bulk#destroy" do - expect(delete("/work_packages/bulk")).to route_to(controller: "work_packages/bulk", - action: "destroy") + it 'connects DELETE /work_packages/bulk to work_package_bulk#destroy' do + expect(delete('/work_packages/bulk')).to route_to(controller: 'work_packages/bulk', + action: 'destroy') end end diff --git a/spec/routing/work_packages_spec.rb b/spec/routing/work_packages_spec.rb index d80f95e60b2b..f5fef8edbe53 100644 --- a/spec/routing/work_packages_spec.rb +++ b/spec/routing/work_packages_spec.rb @@ -26,104 +26,104 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackagesController do - it "connects GET /work_packages to work_packages#index" do - expect(get("/work_packages")).to route_to(controller: "work_packages", - action: "index") + it 'connects GET /work_packages to work_packages#index' do + expect(get('/work_packages')).to route_to(controller: 'work_packages', + action: 'index') end - it "connects GET /projects/blubs/work_packages to work_packages#index" do - expect(get("/projects/blubs/work_packages")).to route_to(controller: "work_packages", - project_id: "blubs", - action: "index") + it 'connects GET /projects/blubs/work_packages to work_packages#index' do + expect(get('/projects/blubs/work_packages')).to route_to(controller: 'work_packages', + project_id: 'blubs', + action: 'index') end - it "connects GET /work_packages/new to work_packages#index" do - expect(get("/work_packages/new")) - .to route_to(controller: "work_packages", - action: "index", - state: "new") + it 'connects GET /work_packages/new to work_packages#index' do + expect(get('/work_packages/new')) + .to route_to(controller: 'work_packages', + action: 'index', + state: 'new') end - it "connects GET /projects/:project_id/work_packages/new to work_packages#index" do - expect(get("/projects/1/work_packages/new")) - .to route_to(controller: "work_packages", - action: "index", - project_id: "1", - state: "new") + it 'connects GET /projects/:project_id/work_packages/new to work_packages#index' do + expect(get('/projects/1/work_packages/new')) + .to route_to(controller: 'work_packages', + action: 'index', + project_id: '1', + state: 'new') end - it "connects GET /work_packages/:id/overview to work_packages#show" do - expect(get("/work_packages/1/overview")) - .to route_to(controller: "work_packages", - action: "show", id: "1", state: "overview") + it 'connects GET /work_packages/:id/overview to work_packages#show' do + expect(get('/work_packages/1/overview')) + .to route_to(controller: 'work_packages', + action: 'show', id: '1', state: 'overview') end - it "connects GET /projects/:project_id/work_packages/:id/overview to work_packages#index" do - expect(get("/projects/1/work_packages/2/overview")) - .to route_to(controller: "work_packages", - action: "index", - project_id: "1", - state: "2/overview") + it 'connects GET /projects/:project_id/work_packages/:id/overview to work_packages#index' do + expect(get('/projects/1/work_packages/2/overview')) + .to route_to(controller: 'work_packages', + action: 'index', + project_id: '1', + state: '2/overview') end - it "connects GET /work_packages/details/:state to work_packages#index" do - expect(get("/work_packages/details/5/overview")) - .to route_to(controller: "work_packages", - action: "index", - state: "5/overview") + it 'connects GET /work_packages/details/:state to work_packages#index' do + expect(get('/work_packages/details/5/overview')) + .to route_to(controller: 'work_packages', + action: 'index', + state: '5/overview') end - it "connects GET /projects/:project_id/work_packages/details/:id/:state" + - " to work_packages#index" do - expect(get("/projects/1/work_packages/details/2/overview")) - .to route_to(controller: "work_packages", - action: "index", - project_id: "1", - state: "details/2/overview") + it 'connects GET /projects/:project_id/work_packages/details/:id/:state' + + ' to work_packages#index' do + expect(get('/projects/1/work_packages/details/2/overview')) + .to route_to(controller: 'work_packages', + action: 'index', + project_id: '1', + state: 'details/2/overview') end - it "connects GET /work_packages/:id to work_packages#show" do - expect(get("/work_packages/1")).to route_to(controller: "work_packages", - action: "show", - id: "1") + it 'connects GET /work_packages/:id to work_packages#show' do + expect(get('/work_packages/1')).to route_to(controller: 'work_packages', + action: 'show', + id: '1') end - it "connects GET /work_packages/:id/share to work_packages/shares#index" do - expect(get("/work_packages/1/shares")).to route_to(controller: "work_packages/shares", - action: "index", - work_package_id: "1") + it 'connects GET /work_packages/:id/share to work_packages/shares#index' do + expect(get('/work_packages/1/shares')).to route_to(controller: 'work_packages/shares', + action: 'index', + work_package_id: '1') end - it "connects POST /work_packages/:id/share to work_packages/shares#create" do - expect(post("/work_packages/1/shares")).to route_to(controller: "work_packages/shares", - action: "create", - work_package_id: "1") + it 'connects POST /work_packages/:id/share to work_packages/shares#create' do + expect(post('/work_packages/1/shares')).to route_to(controller: 'work_packages/shares', + action: 'create', + work_package_id: '1') end - it "connects GET /work_packages/:work_package_id/moves/new to work_packages/moves#new" do - expect(get("/work_packages/1/move/new")).to route_to(controller: "work_packages/moves", - action: "new", - work_package_id: "1") + it 'connects GET /work_packages/:work_package_id/moves/new to work_packages/moves#new' do + expect(get('/work_packages/1/move/new')).to route_to(controller: 'work_packages/moves', + action: 'new', + work_package_id: '1') end - it "connects POST /work_packages/:work_package_id/moves to work_packages/moves#create" do - expect(post("/work_packages/1/move/")).to route_to(controller: "work_packages/moves", - action: "create", - work_package_id: "1") + it 'connects POST /work_packages/:work_package_id/moves to work_packages/moves#create' do + expect(post('/work_packages/1/move/')).to route_to(controller: 'work_packages/moves', + action: 'create', + work_package_id: '1') end - it "connects GET /work_packages/moves/new?ids=1,2,3 to work_packages/moves#new" do - expect(get("/work_packages/move/new?ids=1,2,3")).to route_to(controller: "work_packages/moves", - action: "new", - ids: "1,2,3") + it 'connects GET /work_packages/moves/new?ids=1,2,3 to work_packages/moves#new' do + expect(get('/work_packages/move/new?ids=1,2,3')).to route_to(controller: 'work_packages/moves', + action: 'new', + ids: '1,2,3') end - it "connects POST /work_packages/moves to work_packages/moves#create" do - expect(post("/work_packages/move?ids=1,2,3")).to route_to(controller: "work_packages/moves", - action: "create", - ids: "1,2,3") + it 'connects POST /work_packages/moves to work_packages/moves#create' do + expect(post('/work_packages/move?ids=1,2,3')).to route_to(controller: 'work_packages/moves', + action: 'create', + ids: '1,2,3') end end diff --git a/spec/routing/workflows_spec.rb b/spec/routing/workflows_spec.rb index 90cc43548240..ea12308791f8 100644 --- a/spec/routing/workflows_spec.rb +++ b/spec/routing/workflows_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "workflows routes" do - it { expect(get("/workflows")).to route_to("workflows#show") } +RSpec.describe 'workflows routes' do + it { expect(get('/workflows')).to route_to('workflows#show') } - it { expect(get("/workflows/edit")).to route_to("workflows#edit") } - it { expect(patch("/workflows")).to route_to("workflows#update") } + it { expect(get('/workflows/edit')).to route_to('workflows#edit') } + it { expect(patch('/workflows')).to route_to('workflows#update') } - it { expect(get("/workflows/copy")).to route_to("workflows#copy") } - it { expect(post("/workflows/copy")).to route_to("workflows#copy") } + it { expect(get('/workflows/copy')).to route_to('workflows#copy') } + it { expect(post('/workflows/copy')).to route_to('workflows#copy') } end diff --git a/spec/security/active_support_to_json_spec.rb b/spec/security/active_support_to_json_spec.rb index d82f694d965f..6877551f3bb1 100644 --- a/spec/security/active_support_to_json_spec.rb +++ b/spec/security/active_support_to_json_spec.rb @@ -34,7 +34,7 @@ # # It should be safe to remove this when OP is on rails >= 4.1 -require "spec_helper" +require 'spec_helper' RSpec.describe ActiveSupport do active_support_default = ActiveSupport.escape_html_entities_in_json @@ -43,10 +43,10 @@ ActiveSupport.escape_html_entities_in_json = active_support_default end - it "escapes html entities in json" do + it 'escapes html entities in json' do ActiveSupport.escape_html_entities_in_json = true expected_output = "{\"\\u003c\\u003e\":\"\\u003c\\u003e\"}" - expect(ActiveSupport::JSON.encode("<>" => "<>")).to eql(expected_output) + expect(ActiveSupport::JSON.encode('<>' => '<>')).to eql(expected_output) end end diff --git a/spec/seeders/admin_user_seeder_spec.rb b/spec/seeders/admin_user_seeder_spec.rb index 09ca98449217..7daaacf9dbc9 100644 --- a/spec/seeders/admin_user_seeder_spec.rb +++ b/spec/seeders/admin_user_seeder_spec.rb @@ -28,26 +28,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AdminUserSeeder do subject(:seeder) { described_class.new(seed_data) } let(:seed_data) { Source::SeedData.new({}) } - it "creates an admin user" do + it 'creates an admin user' do expect { seeder.seed! }.to change { User.admin.count }.by(1) end - context "when providing admin user seed variables", + context 'when providing admin user seed variables', :settings_reset, with_env: { - OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: "false", - OPENPROJECT_SEED_ADMIN_USER_PASSWORD: "foobar", - OPENPROJECT_SEED_ADMIN_USER_MAIL: "foobar@example.com", - OPENPROJECT_SEED_ADMIN_USER_NAME: "foo bar" + OPENPROJECT_SEED_ADMIN_USER_PASSWORD_RESET: 'false', + OPENPROJECT_SEED_ADMIN_USER_PASSWORD: 'foobar', + OPENPROJECT_SEED_ADMIN_USER_MAIL: 'foobar@example.com', + OPENPROJECT_SEED_ADMIN_USER_NAME: 'foo bar' } do - it "uses those variables" do + it 'uses those variables' do reset(:seed_admin_user_password) reset(:seed_admin_user_password_reset) reset(:seed_admin_user_name) @@ -56,55 +56,55 @@ seeder.seed! admin = User.admin.last - expect(admin.firstname).to eq "foo" - expect(admin.lastname).to eq "bar" - expect(admin.mail).to eq "foobar@example.com" + expect(admin.firstname).to eq 'foo' + expect(admin.lastname).to eq 'bar' + expect(admin.mail).to eq 'foobar@example.com' expect(admin.force_password_change).to be false - expect(admin.check_password?("admin")).to be false - expect(admin.check_password?("foobar")).to be true + expect(admin.check_password?('admin')).to be false + expect(admin.check_password?('foobar')).to be true end end - it "references the admin user as :openproject_admin in the seed_data" do + it 'references the admin user as :openproject_admin in the seed_data' do seeder.seed! expect(seed_data.find_reference(:openproject_admin)).to eq(User.admin.first) end - context "when a builtin admin user already exists" do + context 'when a builtin admin user already exists' do before do User.system end - it "creates a non-builtin admin user" do + it 'creates a non-builtin admin user' do expect(User.admin.count).to eq(1) expect { seeder.seed! }.to change { User.user.admin.count }.by(1) end end - context "when some admin users already exist" do + context 'when some admin users already exist' do before do User.system - create(:admin, firstname: "First existing admin") - create(:admin, firstname: "Second existing admin") + create(:admin, firstname: 'First existing admin') + create(:admin, firstname: 'Second existing admin') end - it "does not create another admin user" do + it 'does not create another admin user' do expect { seeder.seed! }.not_to change { User.admin.count } end - it "references the first non-builtin admin user as :openproject_admin in the seed_data" do + it 'references the first non-builtin admin user as :openproject_admin in the seed_data' do seeder.seed! expect(seed_data.find_reference(:openproject_admin)).to eq(User.user.admin.first) end end - context "when a non-admin user exists with the same email" do + context 'when a non-admin user exists with the same email' do before do User.system create(:user, mail: Setting.seed_admin_user_mail) end - it "does not create another admin user" do + it 'does not create another admin user' do expect { seeder.seed! }.not_to change { User.admin.count } end end diff --git a/spec/seeders/basic_data/global_role_seeder_spec.rb b/spec/seeders/basic_data/global_role_seeder_spec.rb index 12bbb56de061..b4e7b9354364 100644 --- a/spec/seeders/basic_data/global_role_seeder_spec.rb +++ b/spec/seeders/basic_data/global_role_seeder_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::GlobalRoleSeeder do subject(:seeder) { described_class.new(seed_data) } @@ -39,7 +39,7 @@ seeder.seed! end - context "with some global roles defined" do + context 'with some global roles defined' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML global_roles: @@ -51,21 +51,21 @@ SEEDING_DATA_YAML end - it "creates the corresponding global roles with the given attributes" do + it 'creates the corresponding global roles with the given attributes' do expect(GlobalRole.count).to eq(1) - expect(GlobalRole.find_by(name: "Staff manager")).to have_attributes( + expect(GlobalRole.find_by(name: 'Staff manager')).to have_attributes( builtin: Role::NON_BUILTIN, permissions: %i[hire_people give_feedback] ) end - it "references the role in the seed data" do - role = GlobalRole.find_by(name: "Staff manager") + it 'references the role in the seed data' do + role = GlobalRole.find_by(name: 'Staff manager') expect(seed_data.find_reference(:role_staff_manager)).to eq(role) end end - context "with permissions: :all_assignable_permissions" do + context 'with permissions: :all_assignable_permissions' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML global_roles: @@ -77,8 +77,8 @@ SEEDING_DATA_YAML end - it "gives all assignable permissions to the role" do - expect(GlobalRole.find_by(name: "Project admin").permissions) + it 'gives all assignable permissions to the role' do + expect(GlobalRole.find_by(name: 'Project admin').permissions) .to match_array(Roles::CreateContract.new(GlobalRole.new, nil).assignable_permissions.map { _1.name.to_sym }) end end diff --git a/spec/seeders/basic_data/model_seeder_spec.rb b/spec/seeders/basic_data/model_seeder_spec.rb index a388eb2ce448..d994ef4eaf9d 100644 --- a/spec/seeders/basic_data/model_seeder_spec.rb +++ b/spec/seeders/basic_data/model_seeder_spec.rb @@ -28,16 +28,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::ModelSeeder do subject(:seeder) { described_class.new } - describe "#true?" do + describe '#true?' do { - "true" => true, - "false" => false, - "" => false, + 'true' => true, + 'false' => false, + '' => false, nil => false }.each do |value, expected| it "returns #{expected} when value is #{value.inspect}" do diff --git a/spec/seeders/basic_data/project_role_seeder_spec.rb b/spec/seeders/basic_data/project_role_seeder_spec.rb index 99242be3af2e..ededacfea76b 100644 --- a/spec/seeders/basic_data/project_role_seeder_spec.rb +++ b/spec/seeders/basic_data/project_role_seeder_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::ProjectRoleSeeder do subject(:seeder) { described_class.new(seed_data) } @@ -40,7 +40,7 @@ seeder.seed! end - context "with some builtin roles defined" do + context 'with some builtin roles defined' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML project_roles: @@ -58,25 +58,25 @@ SEEDING_DATA_YAML end - it "creates the corresponding builtin roles with the given attributes" do + it 'creates the corresponding builtin roles with the given attributes' do expect(Role.count).to eq(2) - expect(Role.find_by(name: "Non member")).to have_attributes( + expect(Role.find_by(name: 'Non member')).to have_attributes( builtin: Role::BUILTIN_NON_MEMBER, permissions: %i[view_status view_presentations] + public_permissions ) - expect(Role.find_by(name: "Anonymous")).to have_attributes( + expect(Role.find_by(name: 'Anonymous')).to have_attributes( builtin: Role::BUILTIN_ANONYMOUS, permissions: %i[read_information] + public_permissions ) end - it "references the role in the seed data" do - role = Role.find_by(name: "Anonymous") + it 'references the role in the seed data' do + role = Role.find_by(name: 'Anonymous') expect(seed_data.find_reference(:role_anonymous)).to eq(role) end end - context "with some non-builtin roles defined" do + context 'with some non-builtin roles defined' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML project_roles: @@ -89,22 +89,22 @@ SEEDING_DATA_YAML end - it "creates the corresponding roles with the given attributes" do + it 'creates the corresponding roles with the given attributes' do expect(Role.count).to eq(1) - expect(Role.find_by(name: "Member")).to have_attributes( + expect(Role.find_by(name: 'Member')).to have_attributes( position: 5, builtin: Role::NON_BUILTIN, permissions: %i[view_movies eat_popcorn] + public_permissions ) end - it "references the role in the seed data" do - member_role = Role.find_by(name: "Member") + it 'references the role in the seed data' do + member_role = Role.find_by(name: 'Member') expect(seed_data.find_reference(:role_member)).to eq(member_role) end end - context "with permissions: :all_assignable_permissions" do + context 'with permissions: :all_assignable_permissions' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML project_roles: @@ -115,13 +115,13 @@ SEEDING_DATA_YAML end - it "gives all assignable permissions to the role" do - expect(Role.find_by(name: "Project admin").permissions) + it 'gives all assignable permissions to the role' do + expect(Role.find_by(name: 'Project admin').permissions) .to match_array(Roles::CreateContract.new(Role.new, nil).assignable_permissions(keep_public: true).map { _1.name.to_sym }) end end - context "with some permissions added and removed by modules in a modules_permissions section" do + context 'with some permissions added and removed by modules in a modules_permissions section' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML project_roles: @@ -149,8 +149,8 @@ SEEDING_DATA_YAML end - it "applies the permissions as specified" do - expect(Role.find_by(name: "Member").permissions) + it 'applies the permissions as specified' do + expect(Role.find_by(name: 'Member').permissions) .to match_array( %i[ view_movies diff --git a/spec/seeders/basic_data/type_configuration_seeder_spec.rb b/spec/seeders/basic_data/type_configuration_seeder_spec.rb index 006c065a7fe8..10d55882ccce 100644 --- a/spec/seeders/basic_data/type_configuration_seeder_spec.rb +++ b/spec/seeders/basic_data/type_configuration_seeder_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::TypeConfigurationSeeder do - include_context "with basic seed data", edition: "bim" + include_context 'with basic seed data', edition: 'bim' subject(:seeder) { described_class.new(seed_data) } @@ -39,8 +39,8 @@ let(:phase_type) { seed_data.find_reference(:default_type_phase).reload } let(:data_hash) { {} } - context "without any form_configuration for the given type" do - it "does not change attribute_groups" do + context 'without any form_configuration for the given type' do + it 'does not change attribute_groups' do attribute_groups_before = phase_type.attribute_groups.dup seeder.seed! attribute_groups_now = phase_type.attribute_groups @@ -48,7 +48,7 @@ end end - context "with a form_configuration entry in type_configuration in seed data" do + context 'with a form_configuration entry in type_configuration in seed data' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML type_configuration: @@ -60,15 +60,15 @@ query: :query__bugs_of_the_week SEEDING_DATA_YAML end - let(:query) { create(:query, name: "Children") } - let(:bugs_of_the_week_query) { create(:query, name: "Bugs of the week") } + let(:query) { create(:query, name: 'Children') } + let(:bugs_of_the_week_query) { create(:query, name: 'Bugs of the week') } before do seed_data.store_reference(:query__children, query) seed_data.store_reference(:query__bugs_of_the_week, bugs_of_the_week_query) end - it "adds the given query groups in the form configuration of the type" do + it 'adds the given query groups in the form configuration of the type' do attribute_groups_before = phase_type.attribute_groups.dup seeder.seed! attribute_groups_now = phase_type.attribute_groups diff --git a/spec/seeders/basic_data/work_package_role_seeder_spec.rb b/spec/seeders/basic_data/work_package_role_seeder_spec.rb index c6c0f9f12ad6..fc81012e3185 100644 --- a/spec/seeders/basic_data/work_package_role_seeder_spec.rb +++ b/spec/seeders/basic_data/work_package_role_seeder_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::WorkPackageRoleSeeder do subject(:seeder) { described_class.new(seed_data) } @@ -39,7 +39,7 @@ seeder.seed! end - context "with some work package roles defined" do + context 'with some work package roles defined' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML work_package_roles: @@ -65,33 +65,33 @@ SEEDING_DATA_YAML end - it "creates the corresponding work package roles with the given attributes", :aggregate_failures do + it 'creates the corresponding work package roles with the given attributes', :aggregate_failures do expect(WorkPackageRole.count) .to eq(3) - expect(WorkPackageRole.find_by(name: "Edit work package")) + expect(WorkPackageRole.find_by(name: 'Edit work package')) .to have_attributes( builtin: Role::BUILTIN_WORK_PACKAGE_EDITOR, permissions: %i[become_assignee log_time] ) - expect(WorkPackageRole.find_by(name: "Comment work package")) + expect(WorkPackageRole.find_by(name: 'Comment work package')) .to have_attributes( builtin: Role::BUILTIN_WORK_PACKAGE_COMMENTER, permissions: %i[add_comment] ) - expect(WorkPackageRole.find_by(name: "View work package")) + expect(WorkPackageRole.find_by(name: 'View work package')) .to have_attributes( builtin: Role::BUILTIN_WORK_PACKAGE_VIEWER, permissions: %i[view_work_packages] ) end - it "references the role in the seed data" do - role = WorkPackageRole.find_by(name: "Comment work package") + it 'references the role in the seed data' do + role = WorkPackageRole.find_by(name: 'Comment work package') expect(seed_data.find_reference(:role_work_package_comment)).to eq(role) end end - context "with permissions: :all_assignable_permissions" do + context 'with permissions: :all_assignable_permissions' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML work_package_roles: @@ -101,14 +101,14 @@ SEEDING_DATA_YAML end - it "gives all assignable permissions to the role" do - expect(Role.find_by(name: "Edit work package").permissions) + it 'gives all assignable permissions to the role' do + expect(Role.find_by(name: 'Edit work package').permissions) .to match_array(Roles::CreateContract.new(WorkPackageRole.new, nil) .assignable_permissions.map { _1.name.to_sym }) end end - context "with some permissions added and removed by modules in a modules_permissions section" do + context 'with some permissions added and removed by modules in a modules_permissions section' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML work_package_roles: @@ -136,8 +136,8 @@ SEEDING_DATA_YAML end - it "applies the permissions as specified" do - expect(Role.find_by(name: "Edit work package").permissions) + it 'applies the permissions as specified' do + expect(Role.find_by(name: 'Edit work package').permissions) .to match_array( %i[ view_movies diff --git a/spec/seeders/demo_data/global_query_seeder_spec.rb b/spec/seeders/demo_data/global_query_seeder_spec.rb index dbc42e8133b6..5c1e7bc69b04 100644 --- a/spec/seeders/demo_data/global_query_seeder_spec.rb +++ b/spec/seeders/demo_data/global_query_seeder_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DemoData::GlobalQuerySeeder do subject(:seeder) { described_class.new(seed_data) } @@ -39,7 +39,7 @@ AdminUserSeeder.new(seed_data).seed! end - context "with a global_queries defined" do + context 'with a global_queries defined' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML global_queries: @@ -61,11 +61,11 @@ SEEDING_DATA_YAML end - it "creates a global query" do + it 'creates a global query' do expect { seeder.seed! }.to change { Query.global.count }.by(1) end - it "references the query in the seed data" do + it 'references the query in the seed data' do seeder.seed! created_query = Query.global.first expect(seed_data.find_reference(:global_query__children)).to eq(created_query) diff --git a/spec/seeders/demo_data/group_seeder_spec.rb b/spec/seeders/demo_data/group_seeder_spec.rb index d14c4aa3930c..307e9700146f 100644 --- a/spec/seeders/demo_data/group_seeder_spec.rb +++ b/spec/seeders/demo_data/group_seeder_spec.rb @@ -28,14 +28,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DemoData::GroupSeeder do subject(:seeder) { described_class.new(seed_data) } let(:seed_data) { Source::SeedData.new(data_hash) } - context "with a group defined" do + context 'with a group defined' do let(:data_hash) do YAML.load <<~SEEDING_DATA_YAML groups: @@ -44,13 +44,13 @@ SEEDING_DATA_YAML end - it "creates the corresponding group with the given name as lastname" do + it 'creates the corresponding group with the given name as lastname' do seeder.seed! created_group = Group.last - expect(created_group).to have_attributes(lastname: "Architects") + expect(created_group).to have_attributes(lastname: 'Architects') end - it "references the group in the seed data" do + it 'references the group in the seed data' do seeder.seed! created_group = Group.last expect(seed_data.find_reference(:architects)).to eq(created_group) diff --git a/spec/seeders/demo_data/project_seeder_spec.rb b/spec/seeders/demo_data/project_seeder_spec.rb index 4b66af1b6e39..07aad50e3852 100644 --- a/spec/seeders/demo_data/project_seeder_spec.rb +++ b/spec/seeders/demo_data/project_seeder_spec.rb @@ -28,136 +28,136 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DemoData::ProjectSeeder do - include_context "with basic seed data" + include_context 'with basic seed data' - subject(:project_seeder) { described_class.new(seed_data.lookup("projects.my-project")) } + subject(:project_seeder) { described_class.new(seed_data.lookup('projects.my-project')) } let(:seed_data) do basic_seed_data.merge(Source::SeedData.new( - "projects" => { - "my-project" => project_data + 'projects' => { + 'my-project' => project_data } )) end let(:project_data) { project_data_with_a_version } let(:project_data_with_a_version) do { - "name" => "Some project", - "versions" => [ + 'name' => 'Some project', + 'versions' => [ { - "name" => "The product backlog", - "reference" => :product_backlog, - "sharing" => "none", - "status" => "open" + 'name' => 'The product backlog', + 'reference' => :product_backlog, + 'sharing' => 'none', + 'status' => 'open' } ] } end - it "stores references to created versions in the seed data" do + it 'stores references to created versions in the seed data' do project_seeder.seed! - created_version = Version.find_by(name: "The product backlog") + created_version = Version.find_by(name: 'The product backlog') expect(seed_data.find_reference(:product_backlog)).to eq(created_version) end - context "for a version with a wiki" do + context 'for a version with a wiki' do before do project_data.update( - "modules" => %w[work_package_tracking wiki], - "wiki" => "root wiki page content", - "versions" => [ + 'modules' => %w[work_package_tracking wiki], + 'wiki' => 'root wiki page content', + 'versions' => [ { - "name" => "First sprint", - "reference" => :first_sprint, - "sharing" => "none", - "status" => "open", - "wiki" => { - "title" => "Sprint 1", - "content" => "Please see the [Task board](##sprint:first_sprint)." + 'name' => 'First sprint', + 'reference' => :first_sprint, + 'sharing' => 'none', + 'status' => 'open', + 'wiki' => { + 'title' => 'Sprint 1', + 'content' => 'Please see the [Task board](##sprint:first_sprint).' } } ] ) end - it "can self-reference the version link in the wiki" do + it 'can self-reference the version link in the wiki' do project_seeder.seed! - created_version = Version.find_by!(name: "First sprint") + created_version = Version.find_by!(name: 'First sprint') expect(created_version.wiki_page.text) .to eq("Please see the [Task board](/projects/some-project/sprints/#{created_version.id}/taskboard).") end end - context "with work packages linking to a version by its reference" do + context 'with work packages linking to a version by its reference' do let(:project_data) do project_data_with_a_version.merge( - "work_packages" => [ + 'work_packages' => [ { - "subject" => "Some work package", - "status" => :default_status_new, - "type" => :default_type_task, - "version" => :product_backlog + 'subject' => 'Some work package', + 'status' => :default_status_new, + 'type' => :default_type_task, + 'version' => :product_backlog } ] ) end - it "creates the link" do + it 'creates the link' do project_seeder.seed! - version = Version.find_by!(name: "The product backlog") - work_package = WorkPackage.find_by!(subject: "Some work package") + version = Version.find_by!(name: 'The product backlog') + work_package = WorkPackage.find_by!(subject: 'Some work package') expect(work_package.version).to eq(version) end end - context "with query linking to a version by its reference" do + context 'with query linking to a version by its reference' do let(:project_data) do project_data_with_a_version.merge( - "queries" => [ + 'queries' => [ { - "name" => "Product Backlog query", - "status" => "open", - "version" => :product_backlog + 'name' => 'Product Backlog query', + 'status' => 'open', + 'version' => :product_backlog } ] ) end - it "creates the appropriate version filter" do + it 'creates the appropriate version filter' do project_seeder.seed! - version = Version.find_by(name: "The product backlog") - query = Query.find_by(name: "Product Backlog query") + version = Version.find_by(name: 'The product backlog') + query = Query.find_by(name: 'Product Backlog query') expect(query.filters) .to include(a_filter(Queries::WorkPackages::Filter::VersionFilter, values: [version.id.to_s])) end end - context "with query linking to an assignee by its reference" do + context 'with query linking to an assignee by its reference' do let(:project_data) do { - "name" => "Some project", - "queries" => [ + 'name' => 'Some project', + 'queries' => [ { - "name" => "Team planner", - "assigned_to" => :openproject_admin + 'name' => 'Team planner', + 'assigned_to' => :openproject_admin } ] } end - it "creates the appropriate assigned_to filter" do + it 'creates the appropriate assigned_to filter' do project_seeder.seed! user = User.admin.last - query = Query.find_by(name: "Team planner") + query = Query.find_by(name: 'Team planner') expect(query.filters) .to include(a_filter(Queries::WorkPackages::Filter::AssignedToFilter, values: [user.id.to_s])) end end - context "with query linking to a type by its reference" do + context 'with query linking to a type by its reference' do let(:project_data) do YAML.load <<~PROJECT_SEEDING_DATA_YAML name: Some project @@ -175,17 +175,17 @@ PROJECT_SEEDING_DATA_YAML end - it "creates the appropriate type filter" do + it 'creates the appropriate type filter' do project_seeder.seed! - query = Query.find_by(name: "Milestones") + query = Query.find_by(name: 'Milestones') milestone_type = seed_data.find_reference(:default_type_milestone) expect(query.filters) .to include(a_filter(Queries::WorkPackages::Filter::TypeFilter, values: [milestone_type.id.to_s])) end - it "accepts an array of types" do + it 'accepts an array of types' do project_seeder.seed! - query = Query.find_by(name: "Project plan") + query = Query.find_by(name: 'Project plan') milestone_type = seed_data.find_reference(:default_type_milestone) phase_type = seed_data.find_reference(:default_type_phase) expect(query.filters) diff --git a/spec/seeders/demo_data/work_package_seeder_spec.rb b/spec/seeders/demo_data/work_package_seeder_spec.rb index a9dd690a9bdb..3e4d4b1d3dde 100644 --- a/spec/seeders/demo_data/work_package_seeder_spec.rb +++ b/spec/seeders/demo_data/work_package_seeder_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe DemoData::WorkPackageSeeder do - include_context "with basic seed data" + include_context 'with basic seed data' shared_let(:work_week) { week_with_saturday_and_sunday_as_weekend } @@ -37,7 +37,7 @@ let(:new_project_role) { seed_data.find_reference(:default_role_project_admin) } let(:closed_status) { seed_data.find_reference(:default_status_closed) } let(:work_packages_data) { [] } - let(:seed_data) { basic_seed_data.merge(Source::SeedData.new("work_packages" => work_packages_data)) } + let(:seed_data) { basic_seed_data.merge(Source::SeedData.new('work_packages' => work_packages_data)) } def work_package_data(**attributes) { @@ -53,20 +53,20 @@ def work_package_data(**attributes) work_package_seeder.seed! end - context "with work package data with start: 0" do + context 'with work package data with start: 0' do let(:work_packages_data) do [ work_package_data(start: 0) ] end - it "start on the Monday of the current week" do + it 'start on the Monday of the current week' do current_week_monday = Date.current.monday expect(WorkPackage.first.start_date).to eq(current_week_monday) end end - context "with work package data with start: n" do + context 'with work package data with start: n' do let(:work_packages_data) do [ work_package_data(start: 2), @@ -74,14 +74,14 @@ def work_package_data(**attributes) ] end - it "starts n days after the Monday of the current week" do + it 'starts n days after the Monday of the current week' do current_week_monday = Date.current.monday expect(WorkPackage.first.start_date).to eq(current_week_monday + 2.days) expect(WorkPackage.second.start_date).to eq(current_week_monday + 42.days) end end - context "with work package data with start: -n" do + context 'with work package data with start: -n' do let(:work_packages_data) do [ work_package_data(start: -3), @@ -89,14 +89,14 @@ def work_package_data(**attributes) ] end - it "starts n days before the Monday of the current week" do + it 'starts n days before the Monday of the current week' do current_week_monday = Date.current.monday expect(WorkPackage.first.start_date).to eq(current_week_monday - 3.days) expect(WorkPackage.second.start_date).to eq(current_week_monday - 17.days) end end - context "with work package data with duration" do + context 'with work package data with duration' do let(:work_packages_data) do [ work_package_data(start: 0, duration: 1), # from Monday to Saturday @@ -105,7 +105,7 @@ def work_package_data(**attributes) ] end - it "has finish date calculated being start + duration - 1" do + it 'has finish date calculated being start + duration - 1' do current_week_monday = Date.current.monday expect(WorkPackage.first.due_date).to eq(current_week_monday) expect(WorkPackage.second.due_date).to eq(current_week_monday + 5.days) @@ -113,45 +113,45 @@ def work_package_data(**attributes) end end - context "with work package data without duration" do + context 'with work package data without duration' do let(:work_packages_data) do [ work_package_data(duration: nil) ] end - it "has no duration" do + it 'has no duration' do expect(WorkPackage.first.duration).to be_nil end - it "has no finish date" do + it 'has no finish date' do expect(WorkPackage.first.due_date).to be_nil end end - context "when both start date and due date are on a working day" do + context 'when both start date and due date are on a working day' do let(:work_packages_data) do [ work_package_data(start: 1, duration: 10) # from Tuesday to next Thursday ] end - it "has ignore_non_working_day set to true" do + it 'has ignore_non_working_day set to true' do expect(WorkPackage.first.ignore_non_working_days).to be(false) end - it "has finish date calculated from duration based on real days" do + it 'has finish date calculated from duration based on real days' do work_package = WorkPackage.first expect(work_package.due_date).to eq(work_package.start_date + 9.days) expect(work_package.due_date.wday).to eq(4) end - it "has duration adjusted to count only working days" do + it 'has duration adjusted to count only working days' do expect(WorkPackage.first.duration).to eq(8) end end - context "when either start date or finish date is on a non-working day" do + context 'when either start date or finish date is on a non-working day' do let(:work_packages_data) do [ work_package_data(start: -1, duration: 3), # start date non working: from Sunday to Tuesday @@ -159,102 +159,102 @@ def work_package_data(**attributes) ] end - it "has ignore_non_working_day set to true" do + it 'has ignore_non_working_day set to true' do expect(WorkPackage.first.ignore_non_working_days).to be(true) expect(WorkPackage.second.ignore_non_working_days).to be(true) end - it "has duration being the same as defined" do + it 'has duration being the same as defined' do expect(WorkPackage.first.duration).to eq(3) expect(WorkPackage.second.duration).to eq(7) end end - context "with work package data with estimated_hours" do + context 'with work package data with estimated_hours' do let(:work_packages_data) do [ work_package_data(estimated_hours: 3) ] end - it "sets estimated_hours to the given value" do + it 'sets estimated_hours to the given value' do expect(WorkPackage.first.estimated_hours).to eq(3) end end - context "with work package data without estimated_hours" do + context 'with work package data without estimated_hours' do let(:work_packages_data) do [ work_package_data(estimated_hours: nil) ] end - it "does not set estimated_hours" do + it 'does not set estimated_hours' do expect(WorkPackage.first.estimated_hours).to be_nil end end - context "with a parent relation by reference" do + context 'with a parent relation by reference' do let(:work_packages_data) do [ - work_package_data(subject: "Parent", reference: :wp_parent), - work_package_data(subject: "Child", parent: :wp_parent) + work_package_data(subject: 'Parent', reference: :wp_parent), + work_package_data(subject: 'Child', parent: :wp_parent) ] end - it "creates a parent-child relation between work packages" do + it 'creates a parent-child relation between work packages' do expect(WorkPackage.count).to eq(2) expect(WorkPackage.second.parent).to eq(WorkPackage.first) end end - context "with a parent relation by reference inside a nested children property" do + context 'with a parent relation by reference inside a nested children property' do let(:work_packages_data) do [ - work_package_data(subject: "Grand-parent", + work_package_data(subject: 'Grand-parent', children: [ - work_package_data(subject: "Parent", reference: :this_one) + work_package_data(subject: 'Parent', reference: :this_one) ]), - work_package_data(subject: "Child", parent: :this_one) + work_package_data(subject: 'Child', parent: :this_one) ] end - it "creates parent-child relations between work packages" do - expect(WorkPackage.find_by(subject: "Child").parent).to eq(WorkPackage.find_by(subject: "Parent")) - expect(WorkPackage.find_by(subject: "Parent").parent).to eq(WorkPackage.find_by(subject: "Grand-parent")) + it 'creates parent-child relations between work packages' do + expect(WorkPackage.find_by(subject: 'Child').parent).to eq(WorkPackage.find_by(subject: 'Parent')) + expect(WorkPackage.find_by(subject: 'Parent').parent).to eq(WorkPackage.find_by(subject: 'Grand-parent')) end end - context "with a parent relation by reference inside a nested children property with a bcf uuid" do + context 'with a parent relation by reference inside a nested children property with a bcf uuid' do let(:bcf_work_package) { create(:work_package, project:) } - let(:bcf_issue) { create(:bcf_issue, work_package: bcf_work_package, uuid: "fbbf9ecf-5721-4bf1-a08c-aed50dc19353") } + let(:bcf_issue) { create(:bcf_issue, work_package: bcf_work_package, uuid: 'fbbf9ecf-5721-4bf1-a08c-aed50dc19353') } let(:work_packages_data) do [ - work_package_data(subject: "Grand-parent", + work_package_data(subject: 'Grand-parent', children: [ - work_package_data(subject: "Parent", reference: :this_one) + work_package_data(subject: 'Parent', reference: :this_one) ]), work_package_data(bcf_issue_uuid: bcf_issue.uuid, parent: :this_one) ] end - it "creates parent-child relations between work packages" do - expect(bcf_work_package.reload.parent).to eq(WorkPackage.find_by(subject: "Parent")) - expect(WorkPackage.find_by(subject: "Parent").parent).to eq(WorkPackage.find_by(subject: "Grand-parent")) + it 'creates parent-child relations between work packages' do + expect(bcf_work_package.reload.parent).to eq(WorkPackage.find_by(subject: 'Parent')) + expect(WorkPackage.find_by(subject: 'Parent').parent).to eq(WorkPackage.find_by(subject: 'Grand-parent')) end end - context "with a work package description referencing a work package with ##wp:ref notation" do + context 'with a work package description referencing a work package with ##wp:ref notation' do let(:work_packages_data) do [ - work_package_data(subject: "Major thing to do", + work_package_data(subject: 'Major thing to do', reference: :major_thing), - work_package_data(subject: "Other thing", - description: "Check [this work package](##wp:major_thing) of id ##wp.id:major_thing.") + work_package_data(subject: 'Other thing', + description: 'Check [this work package](##wp:major_thing) of id ##wp.id:major_thing.') ] end - it "creates parent-child relations between work packages" do + it 'creates parent-child relations between work packages' do wp_major, wp_other = WorkPackage.order(:id).to_a expect(wp_other.description) .to eq("Check [this work package](/projects/#{project.identifier}/" \ @@ -262,78 +262,78 @@ def work_package_data(**attributes) end end - context "with a work package description referencing a query with ##query:ref notation" do + context 'with a work package description referencing a query with ##query:ref notation' do let(:seed_data) do - seed_data = basic_seed_data.merge(Source::SeedData.new("work_packages" => work_packages_data)) + seed_data = basic_seed_data.merge(Source::SeedData.new('work_packages' => work_packages_data)) seed_data.store_reference(:q_project_plan, query) seed_data end let(:query) { create(:query, project:) } let(:work_packages_data) do [ - work_package_data(subject: "Referencing query", - description: "The [query](##query:q_project_plan) of id ##query.id:q_project_plan.") + work_package_data(subject: 'Referencing query', + description: 'The [query](##query:q_project_plan) of id ##query.id:q_project_plan.') ] end - it "creates link to the query with the right id" do + it 'creates link to the query with the right id' do expect(WorkPackage.last.description) .to eq("The [query](/projects/#{project.identifier}/work_packages?query_id=#{query.id}) of id #{query.id}.") end end - context "with a work package description referencing a sprint with ##sprint:ref notation" do + context 'with a work package description referencing a sprint with ##sprint:ref notation' do let(:seed_data) do - seed_data = basic_seed_data.merge(Source::SeedData.new("work_packages" => work_packages_data)) + seed_data = basic_seed_data.merge(Source::SeedData.new('work_packages' => work_packages_data)) seed_data.store_reference(:sprint_backlog, sprint) seed_data end let(:sprint) { create(:sprint, project:) } let(:work_packages_data) do [ - work_package_data(subject: "Referencing sprint", - description: "The [sprint](##sprint:sprint_backlog) of id ##sprint.id:sprint_backlog.") + work_package_data(subject: 'Referencing sprint', + description: 'The [sprint](##sprint:sprint_backlog) of id ##sprint.id:sprint_backlog.') ] end - it "creates link to the sprint with the right id" do + it 'creates link to the sprint with the right id' do expect(WorkPackage.last.description) .to eq("The [sprint](/projects/#{project.identifier}/sprints/#{sprint.id}/taskboard) of id #{sprint.id}.") end end - describe "assigned_to" do + describe 'assigned_to' do let(:seed_data) do - seed_data = basic_seed_data.merge(Source::SeedData.new("work_packages" => work_packages_data)) + seed_data = basic_seed_data.merge(Source::SeedData.new('work_packages' => work_packages_data)) seed_data.store_reference(:user_bernard, a_user) seed_data end - let(:a_user) { create(:user, lastname: "Bernard") } + let(:a_user) { create(:user, lastname: 'Bernard') } let(:work_packages_data) do [ - work_package_data(subject: "without assigned_to"), - work_package_data(subject: "with assigned_to", assigned_to: :user_bernard) + work_package_data(subject: 'without assigned_to'), + work_package_data(subject: 'with assigned_to', assigned_to: :user_bernard) ] end - it "assigns work packages without assigned_to to the admin user" do - work_package = WorkPackage.find_by(subject: "without assigned_to") + it 'assigns work packages without assigned_to to the admin user' do + work_package = WorkPackage.find_by(subject: 'without assigned_to') expect(work_package.assigned_to).to eq(User.user.admin.last) end - it "assigns work packages with assigned_to referencing the user" do - work_package = WorkPackage.find_by(subject: "with assigned_to") + it 'assigns work packages with assigned_to referencing the user' do + work_package = WorkPackage.find_by(subject: 'with assigned_to') expect(work_package.assigned_to).to eq(a_user) end - context "with a BCF work package data" do + context 'with a BCF work package data' do let(:bcf_work_package_without_assigned_to) { create(:work_package, project:) } let(:bcf_issue_without_assigned_to) do - create(:bcf_issue, work_package: bcf_work_package_without_assigned_to, uuid: "aaaaaaaa-5721-4bf1-a08c-aed50dc19353") + create(:bcf_issue, work_package: bcf_work_package_without_assigned_to, uuid: 'aaaaaaaa-5721-4bf1-a08c-aed50dc19353') end let(:bcf_work_package_with_assigned_to) { create(:work_package, project:) } let(:bcf_issue_with_assigned_to) do - create(:bcf_issue, work_package: bcf_work_package_with_assigned_to, uuid: "bbbbbbbb-5721-4bf1-a08c-aed50dc19353") + create(:bcf_issue, work_package: bcf_work_package_with_assigned_to, uuid: 'bbbbbbbb-5721-4bf1-a08c-aed50dc19353') end let(:work_packages_data) do [ @@ -342,12 +342,12 @@ def work_package_data(**attributes) ] end - it "assigns work packages without assigned_to to the admin user" do + it 'assigns work packages without assigned_to to the admin user' do expect(bcf_work_package_without_assigned_to.reload.assigned_to) .to eq(User.user.admin.last) end - it "assigns work packages with assigned_to referencing the user lastname" do + it 'assigns work packages with assigned_to referencing the user lastname' do expect(bcf_work_package_with_assigned_to.reload.assigned_to) .to eq(a_user) end diff --git a/spec/seeders/env_data/ldap_seeder_spec.rb b/spec/seeders/env_data/ldap_seeder_spec.rb index e53d9a1f326e..97dfad6e40b8 100644 --- a/spec/seeders/env_data/ldap_seeder_spec.rb +++ b/spec/seeders/env_data/ldap_seeder_spec.rb @@ -28,20 +28,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe EnvData::LdapSeeder do let(:seed_data) { Source::SeedData.new({}) } subject(:seeder) { described_class.new(seed_data) } - context "when not provided" do - it "does nothing" do + context 'when not provided' do + it 'does nothing' do expect { seeder.seed! }.not_to change(LdapAuthSource, :count) end end - context "when providing seed variables", + context 'when providing seed variables', :settings_reset, with_env: { OPENPROJECT_SEED_LDAP_FOO_HOST: "localhost", @@ -64,7 +64,7 @@ OPENPROJECT_SEED_LDAP_FOO_GROUPFILTER_BAR_SYNC__USERS: "true", OPENPROJECT_SEED_LDAP_FOO_GROUPFILTER_BAR_GROUP__ATTRIBUTE: "dn" } do - it "uses those variables" do # rubocop:disable RSpec/MultipleExpectations, RSpec/ExampleLength + it 'uses those variables' do # rubocop:disable RSpec/MultipleExpectations, RSpec/ExampleLength reset(:seed_ldap) allow(LdapGroups::SynchronizationJob).to receive(:perform_now) @@ -74,34 +74,34 @@ expect(LdapGroups::SynchronizationJob).to have_received(:perform_now) ldap = LdapAuthSource.last - expect(ldap.name).to eq "foo" - expect(ldap.host).to eq "localhost" + expect(ldap.name).to eq 'foo' + expect(ldap.host).to eq 'localhost' expect(ldap.port).to eq 12389 - expect(ldap.tls_mode).to eq "plain_ldap" + expect(ldap.tls_mode).to eq 'plain_ldap' expect(ldap.read_ldap_certificates.first).to be_a(OpenSSL::X509::Certificate) expect(ldap.verify_peer).to be false - expect(ldap.account).to eq "uid=admin,ou=system" - expect(ldap.account_password).to eq "secret" - expect(ldap.base_dn).to eq "dc=example,dc=com" - expect(ldap.filter_string).to eq "(uid=*)" + expect(ldap.account).to eq 'uid=admin,ou=system' + expect(ldap.account_password).to eq 'secret' + expect(ldap.base_dn).to eq 'dc=example,dc=com' + expect(ldap.filter_string).to eq '(uid=*)' expect(ldap).to be_onthefly_register - expect(ldap.attr_login).to eq "uid" - expect(ldap.attr_firstname).to eq "givenName" - expect(ldap.attr_lastname).to eq "sn" - expect(ldap.attr_mail).to eq "mail" - expect(ldap.attr_admin).to eq "is_openproject_admin" + expect(ldap.attr_login).to eq 'uid' + expect(ldap.attr_firstname).to eq 'givenName' + expect(ldap.attr_lastname).to eq 'sn' + expect(ldap.attr_mail).to eq 'mail' + expect(ldap.attr_admin).to eq 'is_openproject_admin' expect(ldap.ldap_groups_synchronized_filters.count).to eq(1) filter = ldap.ldap_groups_synchronized_filters.first - expect(filter.name).to eq "bar" - expect(filter.base_dn).to eq "ou=groups,dc=example,dc=com" - expect(filter.filter_string).to eq "(cn=*)" + expect(filter.name).to eq 'bar' + expect(filter.base_dn).to eq 'ou=groups,dc=example,dc=com' + expect(filter.filter_string).to eq '(cn=*)' expect(filter.sync_users).to be true - expect(filter.group_name_attribute).to eq "dn" + expect(filter.group_name_attribute).to eq 'dn' end end - context "when removing a previously seeded filter", + context 'when removing a previously seeded filter', :settings_reset, with_env: { OPENPROJECT_SEED_LDAP_FOO_HOST: "localhost", @@ -118,13 +118,13 @@ OPENPROJECT_SEED_LDAP_FOO_LASTNAME__MAPPING: "sn", OPENPROJECT_SEED_LDAP_FOO_MAIL__MAPPING: "mail" } do - let!(:ldap) { create(:ldap_auth_source, name: "foo") } - let!(:filter) { create(:ldap_synchronized_filter, name: "bar", ldap_auth_source: ldap) } + let!(:ldap) { create(:ldap_auth_source, name: 'foo') } + let!(:filter) { create(:ldap_synchronized_filter, name: 'bar', ldap_auth_source: ldap) } - it "removes the other one" do # rubocop:disable RSpec/MultipleExpectations + it 'removes the other one' do # rubocop:disable RSpec/MultipleExpectations expect(ldap.ldap_groups_synchronized_filters.count).to eq(1) names = ldap.ldap_groups_synchronized_filters.pluck(:name) - expect(names).to contain_exactly("bar") + expect(names).to contain_exactly('bar') reset(:seed_ldap) @@ -135,27 +135,27 @@ expect(LdapGroups::SynchronizationJob).to have_received(:perform_now) ldap.reload - expect(ldap.name).to eq "foo" - expect(ldap.host).to eq "localhost" + expect(ldap.name).to eq 'foo' + expect(ldap.host).to eq 'localhost' expect(ldap.port).to eq 12389 - expect(ldap.tls_mode).to eq "plain_ldap" + expect(ldap.tls_mode).to eq 'plain_ldap' expect(ldap.verify_peer).to be false - expect(ldap.account).to eq "uid=admin,ou=system" - expect(ldap.account_password).to eq "secret" - expect(ldap.base_dn).to eq "dc=example,dc=com" - expect(ldap.filter_string).to eq "(uid=*)" + expect(ldap.account).to eq 'uid=admin,ou=system' + expect(ldap.account_password).to eq 'secret' + expect(ldap.base_dn).to eq 'dc=example,dc=com' + expect(ldap.filter_string).to eq '(uid=*)' expect(ldap).to be_onthefly_register - expect(ldap.attr_login).to eq "uid" - expect(ldap.attr_firstname).to eq "givenName" - expect(ldap.attr_lastname).to eq "sn" - expect(ldap.attr_mail).to eq "mail" + expect(ldap.attr_login).to eq 'uid' + expect(ldap.attr_firstname).to eq 'givenName' + expect(ldap.attr_lastname).to eq 'sn' + expect(ldap.attr_mail).to eq 'mail' expect(ldap.attr_admin).to be_nil expect(ldap.ldap_groups_synchronized_filters.count).to eq(0) end end - context "when removing a previously seeded filter and adding one", + context 'when removing a previously seeded filter and adding one', :settings_reset, with_env: { OPENPROJECT_SEED_LDAP_FOO_HOST: "localhost", @@ -177,13 +177,13 @@ OPENPROJECT_SEED_LDAP_FOO_GROUPFILTER_ANOTHER_SYNC__USERS: "true", OPENPROJECT_SEED_LDAP_FOO_GROUPFILTER_ANOTHER_GROUP__ATTRIBUTE: "dn" } do - let!(:ldap) { create(:ldap_auth_source, name: "foo") } - let!(:filter) { create(:ldap_synchronized_filter, name: "bar", ldap_auth_source: ldap) } + let!(:ldap) { create(:ldap_auth_source, name: 'foo') } + let!(:filter) { create(:ldap_synchronized_filter, name: 'bar', ldap_auth_source: ldap) } - it "removes the other one" do # rubocop:disable RSpec/MultipleExpectations, RSpec/ExampleLength + it 'removes the other one' do # rubocop:disable RSpec/MultipleExpectations, RSpec/ExampleLength expect(ldap.ldap_groups_synchronized_filters.count).to eq(1) names = ldap.ldap_groups_synchronized_filters.pluck(:name) - expect(names).to contain_exactly("bar") + expect(names).to contain_exactly('bar') reset(:seed_ldap) @@ -194,25 +194,25 @@ expect(LdapGroups::SynchronizationJob).to have_received(:perform_now) ldap.reload - expect(ldap.name).to eq "foo" - expect(ldap.host).to eq "localhost" + expect(ldap.name).to eq 'foo' + expect(ldap.host).to eq 'localhost' expect(ldap.port).to eq 12389 - expect(ldap.tls_mode).to eq "plain_ldap" + expect(ldap.tls_mode).to eq 'plain_ldap' expect(ldap.verify_peer).to be false - expect(ldap.account).to eq "uid=admin,ou=system" - expect(ldap.account_password).to eq "secret" - expect(ldap.base_dn).to eq "dc=example,dc=com" - expect(ldap.filter_string).to eq "(uid=*)" + expect(ldap.account).to eq 'uid=admin,ou=system' + expect(ldap.account_password).to eq 'secret' + expect(ldap.base_dn).to eq 'dc=example,dc=com' + expect(ldap.filter_string).to eq '(uid=*)' expect(ldap).to be_onthefly_register - expect(ldap.attr_login).to eq "uid" - expect(ldap.attr_firstname).to eq "givenName" - expect(ldap.attr_lastname).to eq "sn" - expect(ldap.attr_mail).to eq "mail" + expect(ldap.attr_login).to eq 'uid' + expect(ldap.attr_firstname).to eq 'givenName' + expect(ldap.attr_lastname).to eq 'sn' + expect(ldap.attr_mail).to eq 'mail' expect(ldap.attr_admin).to be_nil expect(ldap.ldap_groups_synchronized_filters.count).to eq(1) names = ldap.ldap_groups_synchronized_filters.pluck(:name) - expect(names).to contain_exactly("another") + expect(names).to contain_exactly('another') end end end diff --git a/spec/seeders/root_seeder_shared_examples.rb b/spec/seeders/root_seeder_shared_examples.rb index 023fcf6b8abd..6c1ca8cd1219 100644 --- a/spec/seeders/root_seeder_shared_examples.rb +++ b/spec/seeders/root_seeder_shared_examples.rb @@ -28,8 +28,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples "no email deliveries" do - it "does not perform any email deliveries" do +RSpec.shared_examples 'no email deliveries' do + it 'does not perform any email deliveries' do perform_enqueued_jobs expect(ActionMailer::Base.deliveries) @@ -37,7 +37,7 @@ end end -RSpec.shared_examples "it creates records" do |model:, expected_count:| +RSpec.shared_examples 'it creates records' do |model:, expected_count:| it "creates #{expected_count} records of #{model}" do expect(model.count).to eq(expected_count) end diff --git a/spec/seeders/root_seeder_standard_edition_spec.rb b/spec/seeders/root_seeder_standard_edition_spec.rb index 9ee7cf63033c..5c31928d51c0 100644 --- a/spec/seeders/root_seeder_standard_edition_spec.rb +++ b/spec/seeders/root_seeder_standard_edition_spec.rb @@ -28,31 +28,31 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "root_seeder_shared_examples" +require 'spec_helper' +require_relative 'root_seeder_shared_examples' RSpec.describe RootSeeder, - "standard edition", - with_config: { edition: "standard" } do + 'standard edition', + with_config: { edition: 'standard' } do include RootSeederTestHelpers - shared_examples "creates standard demo data" do - it "creates the system user" do + shared_examples 'creates standard demo data' do + it 'creates the system user' do expect(SystemUser.where(admin: true).count).to eq 1 end - it "creates an admin user" do + it 'creates an admin user' do expect(User.not_builtin.where(admin: true).count).to eq 1 end - it "creates the demo data" do + it 'creates the demo data' do expect(Project.count).to eq 2 expect(EnabledModule.count).to eq 13 expect(WorkPackage.count).to eq 36 expect(Wiki.count).to eq 2 expect(Query.having_views.count).to eq 8 - expect(View.where(type: "work_packages_table").count).to eq 7 - expect(View.where(type: "team_planner").count).to eq 1 + expect(View.where(type: 'work_packages_table').count).to eq 7 + expect(View.where(type: 'team_planner').count).to eq 1 expect(Query.count).to eq 26 expect(ProjectRole.count).to eq 5 expect(WorkPackageRole.count).to eq 3 @@ -64,8 +64,8 @@ expect(Boards::Grid.count { |grid| grid.options.has_key?(:filters) }).to eq 1 end - it "links work packages to their version" do - count_by_version = WorkPackage.joins(:version).group("versions.name").count + it 'links work packages to their version' do + count_by_version = WorkPackage.joins(:version).group('versions.name').count # testing with strings would fail for the German language test # 'Bug Backlog' => 1, # 'Sprint 1' => 8, @@ -73,7 +73,7 @@ expect(count_by_version.values).to contain_exactly(1, 8, 7) end - it "creates different types of queries" do + it 'creates different types of queries' do count_by_type = View.group(:type).count expect(count_by_type).to eq( "work_packages_table" => 7, @@ -81,7 +81,7 @@ ) end - it "adds additional permissions from modules" do + it 'adds additional permissions from modules' do # do not test for all permissions but only some of them to ensure each # module got processed for a standard edition work_package_editor_role = root_seeder.seed_data.find_reference(:default_role_work_package_editor) @@ -106,43 +106,43 @@ ) end - include_examples "it creates records", model: Color, expected_count: 144 - include_examples "it creates records", model: DocumentCategory, expected_count: 3 - include_examples "it creates records", model: GlobalRole, expected_count: 1 - include_examples "it creates records", model: WorkPackageRole, expected_count: 3 - include_examples "it creates records", model: Role, expected_count: 9 - include_examples "it creates records", model: IssuePriority, expected_count: 4 - include_examples "it creates records", model: Status, expected_count: 14 - include_examples "it creates records", model: TimeEntryActivity, expected_count: 6 - include_examples "it creates records", model: Workflow, expected_count: 1758 - include_examples "it creates records", model: Meeting, expected_count: 1 + include_examples 'it creates records', model: Color, expected_count: 144 + include_examples 'it creates records', model: DocumentCategory, expected_count: 3 + include_examples 'it creates records', model: GlobalRole, expected_count: 1 + include_examples 'it creates records', model: WorkPackageRole, expected_count: 3 + include_examples 'it creates records', model: Role, expected_count: 9 + include_examples 'it creates records', model: IssuePriority, expected_count: 4 + include_examples 'it creates records', model: Status, expected_count: 14 + include_examples 'it creates records', model: TimeEntryActivity, expected_count: 6 + include_examples 'it creates records', model: Workflow, expected_count: 1758 + include_examples 'it creates records', model: Meeting, expected_count: 1 end - describe "demo data" do + describe 'demo data' do shared_let(:root_seeder) { described_class.new } before_all do - with_edition("standard") do + with_edition('standard') do root_seeder.seed_data! end end - include_examples "creates standard demo data" + include_examples 'creates standard demo data' - include_examples "no email deliveries" + include_examples 'no email deliveries' - context "when run a second time" do + context 'when run a second time' do before_all do described_class.new.seed_data! end - it "does not create additional data" do + it 'does not create additional data' do expect(Project.count).to eq 2 expect(WorkPackage.count).to eq 36 expect(Wiki.count).to eq 2 expect(Query.having_views.count).to eq 8 - expect(View.where(type: "work_packages_table").count).to eq 7 - expect(View.where(type: "team_planner").count).to eq 1 + expect(View.where(type: 'work_packages_table').count).to eq 7 + expect(View.where(type: 'team_planner').count).to eq 1 expect(Query.count).to eq 26 expect(ProjectRole.count).to eq 5 expect(WorkPackageRole.count).to eq 3 @@ -155,29 +155,29 @@ end end - describe "demo data with work package role migration having been run" do + describe 'demo data with work package role migration having been run' do shared_let(:root_seeder) { described_class.new } before_all do # call the migration which will add data for work package roles. This # needs to be done manually as running tests automatically calls the # `db:test:purge` rake task. - require(Rails.root.join("db/migrate/20231128080650_add_work_package_roles")) + require(Rails.root.join('db/migrate/20231128080650_add_work_package_roles')) AddWorkPackageRoles.new.up - with_edition("standard") do + with_edition('standard') do root_seeder.seed_data! end end - include_examples "creates standard demo data" + include_examples 'creates standard demo data' end - describe "demo data mock-translated in another language" do + describe 'demo data mock-translated in another language' do shared_let(:root_seeder) { described_class.new } before_all do - with_edition("standard") do + with_edition('standard') do # simulate a translation by changing the returned string on `I18n#t` calls allow(I18n).to receive(:t).and_wrap_original do |m, *args, **kw| original_translation = m.call(*args, **kw) @@ -187,24 +187,24 @@ end end - include_examples "creates standard demo data" + include_examples 'creates standard demo data' - it "has all Query.name translated" do - expect(Query.pluck(:name)).to all(start_with("tr: ")) + it 'has all Query.name translated' do + expect(Query.pluck(:name)).to all(start_with('tr: ')) end end [ - "OPENPROJECT_SEED_LOCALE", - "OPENPROJECT_DEFAULT_LANGUAGE" + 'OPENPROJECT_SEED_LOCALE', + 'OPENPROJECT_DEFAULT_LANGUAGE' ].each do |env_var_name| describe "demo data with a non-English language set with #{env_var_name}", :settings_reset do shared_let(:root_seeder) { described_class.new } before_all do - with_env(env_var_name => "de") do - with_edition("standard") do + with_env(env_var_name => 'de') do + with_edition('standard') do reset(:default_language) # Settings are a pain to reset root_seeder.seed_data! ensure @@ -213,47 +213,47 @@ end end - it "seeds with the specified language" do - willkommen = I18n.t("#{Source::Translate::I18N_PREFIX}.standard.welcome.title", locale: "de") + it 'seeds with the specified language' do + willkommen = I18n.t("#{Source::Translate::I18N_PREFIX}.standard.welcome.title", locale: 'de') expect(Setting.welcome_title).to eq(willkommen) - expect(Status.where(name: "Neu")).to exist - expect(Type.where(name: "Meilenstein")).to exist - expect(Color.where(name: "Gelb")).to exist + expect(Status.where(name: 'Neu')).to exist + expect(Type.where(name: 'Meilenstein')).to exist + expect(Color.where(name: 'Gelb')).to exist end - it "sets Setting.default_language to the given language" do - expect(Setting.find_by(name: "default_language")).to have_attributes(value: "de") + it 'sets Setting.default_language to the given language' do + expect(Setting.find_by(name: 'default_language')).to have_attributes(value: 'de') end - include_examples "creates standard demo data" + include_examples 'creates standard demo data' end end - describe "demo data with development data" do + describe 'demo data with development data' do shared_let(:root_seeder) { described_class.new(seed_development_data: true) } before_all do root_seeder.seed_data! end - it "creates 1 additional admin user with German locale" do + it 'creates 1 additional admin user with German locale' do admins = User.not_builtin.where(admin: true) expect(admins.count).to eq 2 expect(admins.pluck(:language)).to match_array(%w[en de]) end - it "creates 5 additional projects for development" do + it 'creates 5 additional projects for development' do expect(Project.count).to eq 7 end - it "creates 4 additional work packages for development" do + it 'creates 4 additional work packages for development' do expect(WorkPackage.count).to eq 40 end - it "creates 1 project with custom fields" do + it 'creates 1 project with custom fields' do expect(CustomField.count).to eq 12 end - include_examples "no email deliveries" + include_examples 'no email deliveries' end end diff --git a/spec/seeders/seeder_spec.rb b/spec/seeders/seeder_spec.rb index 643cc2796fb4..c7daa52b6c7f 100644 --- a/spec/seeders/seeder_spec.rb +++ b/spec/seeders/seeder_spec.rb @@ -28,21 +28,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Seeder do subject(:seeder) { described_class.new } let(:seed_data) { Source::SeedData.new({}) } - describe "#admin_user" do - it "returns the admin created from the seeding" do + describe '#admin_user' do + it 'returns the admin created from the seeding' do expect(seeder.admin_user).to be_nil AdminUserSeeder.new(seed_data).seed! expect(seeder.admin_user).to be_a(User) end - it "does not return the system user" do + it 'does not return the system user' do expect { User.system }.to change { User.admin.count }.by(1) expect(seeder.admin_user).to be_nil end diff --git a/spec/seeders/setting_seeder_spec.rb b/spec/seeders/setting_seeder_spec.rb index f5ac088b7320..f62a35adc8a0 100644 --- a/spec/seeders/setting_seeder_spec.rb +++ b/spec/seeders/setting_seeder_spec.rb @@ -26,17 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BasicData::SettingSeeder do - include_context "with basic seed data" + include_context 'with basic seed data' subject(:setting_seeder) { described_class.new(basic_seed_data) } let(:new_project_role) { basic_seed_data.find_reference(:default_role_project_admin) } let(:closed_status) { basic_seed_data.find_reference(:default_status_closed) } - it "applies initial settings" do + before do + allow(ActionMailer::Base).to receive(:perform_deliveries).and_return(false) + allow(Delayed::Worker).to receive(:delay_jobs).and_return(false) + end + + it 'applies initial settings' do expect(setting_seeder).to be_applicable setting_seeder.seed! @@ -52,11 +57,11 @@ expect(Setting.new_project_user_role_id).to eq new_project_role.id end - it "does not override existing settings" do + it 'does not override existing settings' do setting_seeder.seed! Setting.commit_fix_status_id = 1337 - Setting.where(name: "new_project_user_role_id").delete_all + Setting.where(name: 'new_project_user_role_id').delete_all setting_seeder.seed! @@ -64,7 +69,7 @@ expect(Setting.new_project_user_role_id).to eq new_project_role.id end - it "does not seed settings whose default value is undefined" do + it 'does not seed settings whose default value is undefined' do setting_seeder.seed! names_of_undefined_settings = Settings::Definition.all.values.select { _1.value == nil }.map(&:name) @@ -73,19 +78,19 @@ expect(Setting.where(name: names_of_undefined_settings).pluck(:name)).to be_empty end - context "with I18n.locale set" do + context 'with I18n.locale set' do before do - I18n.with_locale "ja" do + I18n.with_locale 'ja' do setting_seeder.seed! end end - it "sets default language to the current locale" do - expect(Setting.default_language).to eq("ja") + it 'sets default language to the current locale' do + expect(Setting.default_language).to eq('ja') end - it "adds current locale to Setting.available_languages" do - expect(Setting.available_languages).to include("ja") + it 'adds current locale to Setting.available_languages' do + expect(Setting.available_languages).to include('ja') end end end diff --git a/spec/seeders/source/filter_translatables_spec.rb b/spec/seeders/source/filter_translatables_spec.rb index 41241032c580..1b9e25f2cd40 100644 --- a/spec/seeders/source/filter_translatables_spec.rb +++ b/spec/seeders/source/filter_translatables_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Source::FilterTranslatables do subject(:loader) do @@ -38,137 +38,137 @@ end.new end - describe "#filter_translatables" do - it "keeps only keys with t_ prefix" do + describe '#filter_translatables' do + it 'keeps only keys with t_ prefix' do hash = { - "t_title" => "Welcome to OpenProject", - "t_text" => "Learn how to plan projects efficiently.", - "icon" => ":smile:" + 't_title' => 'Welcome to OpenProject', + 't_text' => 'Learn how to plan projects efficiently.', + 'icon' => ':smile:' } expect(loader.filter_translatables(hash)).to eq( - "title" => "Welcome to OpenProject", - "text" => "Learn how to plan projects efficiently." + 'title' => 'Welcome to OpenProject', + 'text' => 'Learn how to plan projects efficiently.' ) end it 'does not alter names of keys having "t_" in their names' do hash = { - "welcome_at_home" => { - "t_title" => "Welcome to OpenProject", - "t_text" => "Learn how to plan projects efficiently.", - "icon" => ":smile:" + 'welcome_at_home' => { + 't_title' => 'Welcome to OpenProject', + 't_text' => 'Learn how to plan projects efficiently.', + 'icon' => ':smile:' } } expect(loader.filter_translatables(hash)).to eq( - "welcome_at_home" => { - "title" => "Welcome to OpenProject", - "text" => "Learn how to plan projects efficiently." + 'welcome_at_home' => { + 'title' => 'Welcome to OpenProject', + 'text' => 'Learn how to plan projects efficiently.' } ) end - it "replaces translatable arrays with hashes indexed by array position" do + it 'replaces translatable arrays with hashes indexed by array position' do hash = { - "t_categories" => [ - "First", - "Second", - "Third" + 't_categories' => [ + 'First', + 'Second', + 'Third' ], - "allowed_values" => ["yes", "no"] + 'allowed_values' => ['yes', 'no'] } expect(loader.filter_translatables(hash)).to eq( - "categories" => { - "item_0" => "First", - "item_1" => "Second", - "item_2" => "Third" + 'categories' => { + 'item_0' => 'First', + 'item_1' => 'Second', + 'item_2' => 'Third' } ) end - it "consider translatables only at the first level" do + it 'consider translatables only at the first level' do hash = { - "t_categories" => [ - { "name" => "discarded as it is not translatable" }, - { "t_name" => "kept as it is translatable" }, - "Kept too as the parent key is translatable" + 't_categories' => [ + { 'name' => 'discarded as it is not translatable' }, + { 't_name' => 'kept as it is translatable' }, + 'Kept too as the parent key is translatable' ] } expect(loader.filter_translatables(hash)).to eq( - "categories" => { - "item_1" => { "name" => "kept as it is translatable" }, - "item_2" => "Kept too as the parent key is translatable" + 'categories' => { + 'item_1' => { 'name' => 'kept as it is translatable' }, + 'item_2' => 'Kept too as the parent key is translatable' } ) end - it "replaces arrays of translatables with hashes indexed by array position" do + it 'replaces arrays of translatables with hashes indexed by array position' do hash = { - "categories" => [ + 'categories' => [ { - "t_name" => "First" + 't_name' => 'First' }, { - "t_name" => "Second" + 't_name' => 'Second' }, { - "name" => "This one is discarded as it is not translatable (no t_ prefix)" + 'name' => 'This one is discarded as it is not translatable (no t_ prefix)' }, { - "t_name" => "Fourth" + 't_name' => 'Fourth' } ] } expect(loader.filter_translatables(hash)).to eq( - "categories" => { - "item_0" => { "name" => "First" }, - "item_1" => { "name" => "Second" }, - "item_3" => { "name" => "Fourth" } + 'categories' => { + 'item_0' => { 'name' => 'First' }, + 'item_1' => { 'name' => 'Second' }, + 'item_3' => { 'name' => 'Fourth' } } ) end - it "discards empty arrays and hashes" do + it 'discards empty arrays and hashes' do hash = { - "categories" => [], - "main" => {}, - "work_packages" => [ + 'categories' => [], + 'main' => {}, + 'work_packages' => [ { - "custom_values" => {} + 'custom_values' => {} } ], - "meta" => { - "allowed_values" => [] + 'meta' => { + 'allowed_values' => [] } } expect(loader.filter_translatables(hash)).to eq({}) end - it "keeps nested structures having translatable keys inside it" do + it 'keeps nested structures having translatable keys inside it' do hash = { - "welcome" => { - "t_title" => "Welcome to OpenProject", - "t_text" => "Learn how to plan projects efficiently.", - "icon" => ":smile:" + 'welcome' => { + 't_title' => 'Welcome to OpenProject', + 't_text' => 'Learn how to plan projects efficiently.', + 'icon' => ':smile:' } } expect(loader.filter_translatables(hash)).to eq( - "welcome" => { - "title" => "Welcome to OpenProject", - "text" => "Learn how to plan projects efficiently." + 'welcome' => { + 'title' => 'Welcome to OpenProject', + 'text' => 'Learn how to plan projects efficiently.' } ) end - it "rejects nested structures without any translatable keys inside it" do + it 'rejects nested structures without any translatable keys inside it' do hash = { - "welcome" => { - "t_title" => "Welcome to OpenProject" + 'welcome' => { + 't_title' => 'Welcome to OpenProject' }, - "position" => { - "x" => 18, - "y" => 76 + 'position' => { + 'x' => 18, + 'y' => 76 } } expect(loader.filter_translatables(hash)).to eq( - "welcome" => { - "title" => "Welcome to OpenProject" + 'welcome' => { + 'title' => 'Welcome to OpenProject' } ) end diff --git a/spec/seeders/source/seed_data_loader_spec.rb b/spec/seeders/source/seed_data_loader_spec.rb index ccfc868a221a..c695afae15ef 100644 --- a/spec/seeders/source/seed_data_loader_spec.rb +++ b/spec/seeders/source/seed_data_loader_spec.rb @@ -28,10 +28,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Source::SeedDataLoader do - let(:seed_name) { "standard" } + let(:seed_name) { 'standard' } subject(:loader) { described_class.new(seed_name:) } @@ -43,123 +43,123 @@ def seed_file_double(name:, raw_content:) ) end - describe "#raw_content" do - it "merges the data from seed files matching the given seed name" do + describe '#raw_content' do + it 'merges the data from seed files matching the given seed name' do allow(Source::SeedFile).to receive(:all).and_return( [ seed_file_double(name: seed_name, raw_content: { - "data_from_file1" => "hello" + 'data_from_file1' => 'hello' }), seed_file_double(name: seed_name, raw_content: { - "data_from_file2" => "world" + 'data_from_file2' => 'world' }) ] ) expect(loader.translated_seed_files_content).to eq( { - "data_from_file1" => "hello", - "data_from_file2" => "world" + 'data_from_file1' => 'hello', + 'data_from_file2' => 'world' } ) end - it "merges also the data from all common seed files regardless of the given seed name" do + it 'merges also the data from all common seed files regardless of the given seed name' do allow(Source::SeedFile).to receive(:all).and_return( [ seed_file_double(name: seed_name, raw_content: { - "data_from_file1" => "hello" + 'data_from_file1' => 'hello' }), - seed_file_double(name: "common", + seed_file_double(name: 'common', raw_content: { - "data_from_common_file1" => "world" + 'data_from_common_file1' => 'world' }), - seed_file_double(name: "common", + seed_file_double(name: 'common', raw_content: { - "data_from_common_file2" => "!!!" + 'data_from_common_file2' => '!!!' }) ] ) expect(loader.translated_seed_files_content).to eq( { - "data_from_file1" => "hello", - "data_from_common_file1" => "world", - "data_from_common_file2" => "!!!" + 'data_from_file1' => 'hello', + 'data_from_common_file1' => 'world', + 'data_from_common_file2' => '!!!' } ) end - it "does not merge the data from seed files with a name different from the given name" do + it 'does not merge the data from seed files with a name different from the given name' do allow(Source::SeedFile).to receive(:all).and_return( [ seed_file_double(name: seed_name, raw_content: { - "data_from_standard_file" => "hello" + 'data_from_standard_file' => 'hello' }), - seed_file_double(name: "different", + seed_file_double(name: 'different', raw_content: { - "data_from_different_file" => "this data will not be merged" + 'data_from_different_file' => 'this data will not be merged' }), - seed_file_double(name: "bim", + seed_file_double(name: 'bim', raw_content: { - "data_from_bim_file" => "this data will not be merged either" + 'data_from_bim_file' => 'this data will not be merged either' }) ] ) expect(loader.translated_seed_files_content).to eq( { - "data_from_standard_file" => "hello" + 'data_from_standard_file' => 'hello' } ) end - it "deep merges hashes with identical paths" do + it 'deep merges hashes with identical paths' do allow(Source::SeedFile).to receive(:all).and_return( [ seed_file_double(name: seed_name, raw_content: { - "welcome" => { title: "welcome title" } + 'welcome' => { title: 'welcome title' } }), seed_file_double(name: seed_name, raw_content: { - "welcome" => { description: "welcome description" } + 'welcome' => { description: 'welcome description' } }) ] ) expect(loader.translated_seed_files_content).to eq( { - "welcome" => { - title: "welcome title", - description: "welcome description" + 'welcome' => { + title: 'welcome title', + description: 'welcome description' } } ) end - it "does not concat arrays with identical paths" do + it 'does not concat arrays with identical paths' do allow(Source::SeedFile).to receive(:all).and_return( [ seed_file_double(name: seed_name, raw_content: { - "project" => { "users" => ["Alice", "Bob"] } + 'project' => { 'users' => ['Alice', 'Bob'] } }), seed_file_double(name: seed_name, raw_content: { - "project" => { "users" => ["Caroline", "Devanshi"] } + 'project' => { 'users' => ['Caroline', 'Devanshi'] } }) ] ) expect(loader.translated_seed_files_content).to eq( { - "project" => { - "users" => ["Caroline", "Devanshi"] # last one wins... + 'project' => { + 'users' => ['Caroline', 'Devanshi'] # last one wins... } } ) diff --git a/spec/seeders/source/seed_data_spec.rb b/spec/seeders/source/seed_data_spec.rb index 5bdfd67b3ae0..8890626c3453 100644 --- a/spec/seeders/source/seed_data_spec.rb +++ b/spec/seeders/source/seed_data_spec.rb @@ -28,54 +28,54 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Source::SeedData do subject(:seed_data) { described_class.new({}) } - describe "#store_reference / find_reference" do - it "acts as a key store to register object by a symbol" do + describe '#store_reference / find_reference' do + it 'acts as a key store to register object by a symbol' do object = Object.new seed_data.store_reference(:ref, object) expect(seed_data.find_reference(:ref)).to be(object) end - it "stores nothing if reference is nil" do + it 'stores nothing if reference is nil' do object = Object.new seed_data.store_reference(nil, object) seed_data.store_reference(nil, object) end - it "returns nil if reference is nil" do + it 'returns nil if reference is nil' do expect(seed_data.find_reference(nil)).to be_nil object = Object.new seed_data.store_reference(nil, object) expect(seed_data.find_reference(nil)).to be_nil - expect(seed_data.find_reference(nil, default: "hello")).to be_nil + expect(seed_data.find_reference(nil, default: 'hello')).to be_nil end - it "raises an error when the reference is already used" do + it 'raises an error when the reference is already used' do seed_data.store_reference(:ref, Object.new) expect { seed_data.store_reference(:ref, Object.new) } .to raise_error(ArgumentError) end - it "raises an error if the reference is not found" do + it 'raises an error if the reference is not found' do expect { seed_data.find_reference(:ref) } - .to raise_error(ArgumentError, "Nothing registered with reference :ref") + .to raise_error(ArgumentError, 'Nothing registered with reference :ref') expect { seed_data.find_reference(:ref, :other_ref) } - .to raise_error(ArgumentError, "Nothing registered with references :ref and :other_ref") + .to raise_error(ArgumentError, 'Nothing registered with references :ref and :other_ref') expect { seed_data.find_reference(:ref, :other_ref, :yet_another_ref) } - .to raise_error(ArgumentError, "Nothing registered with references :ref, :other_ref, and :yet_another_ref") + .to raise_error(ArgumentError, 'Nothing registered with references :ref, :other_ref, and :yet_another_ref') end - it "returns the given default value if the reference is not found" do + it 'returns the given default value if the reference is not found' do expect(seed_data.find_reference(:ref, default: 42)).to eq(42) - expect(seed_data.find_reference(:ref, default: "hello")).to eq("hello") + expect(seed_data.find_reference(:ref, default: 'hello')).to eq('hello') expect(seed_data.find_reference(:ref, default: nil)).to be_nil end - it "tries with fallback references if the primary reference is not found" do + it 'tries with fallback references if the primary reference is not found' do object = Object.new seed_data.store_reference(:other_ref, object) expect(seed_data.find_reference(:other_ref)).to be(object) @@ -84,64 +84,64 @@ end end - describe "#only" do + describe '#only' do let(:original_seed_data) do described_class.new( - "cats" => ["Oreo", "Billy"], - "dogs" => ["Rex", "Volt"] + 'cats' => ['Oreo', 'Billy'], + 'dogs' => ['Rex', 'Volt'] ) end - it "creates a copy of the seeding with only the given top level keys" do - seed_data_dogs_only = original_seed_data.only("dogs") - expect(seed_data_dogs_only.lookup("cats")).to be_nil - expect(seed_data_dogs_only.lookup("dogs")).to eq(["Rex", "Volt"]) + it 'creates a copy of the seeding with only the given top level keys' do + seed_data_dogs_only = original_seed_data.only('dogs') + expect(seed_data_dogs_only.lookup('cats')).to be_nil + expect(seed_data_dogs_only.lookup('dogs')).to eq(['Rex', 'Volt']) end - it "creates a copy of the inner registry storing references" do - seed_data_dogs_only = original_seed_data.only("dogs") - seed_data_dogs_only.store_reference(:ref, "Puppy") - expect(seed_data_dogs_only.find_reference(:ref)).to eq "Puppy" - expect(original_seed_data.find_reference(:ref, default: nil)).not_to eq "Puppy" + it 'creates a copy of the inner registry storing references' do + seed_data_dogs_only = original_seed_data.only('dogs') + seed_data_dogs_only.store_reference(:ref, 'Puppy') + expect(seed_data_dogs_only.find_reference(:ref)).to eq 'Puppy' + expect(original_seed_data.find_reference(:ref, default: nil)).not_to eq 'Puppy' end end - describe "#merge" do + describe '#merge' do let(:dogs_seed_data) do - described_class.new("dogs" => ["Rex", "Volt"]) + described_class.new('dogs' => ['Rex', 'Volt']) end let(:cats_seed_data) do - described_class.new("cats" => ["Oreo", "Billy"]) + described_class.new('cats' => ['Oreo', 'Billy']) end - it "creates a new seed data instance with the data merged from both" do + it 'creates a new seed data instance with the data merged from both' do merged_seed_data = dogs_seed_data.merge(cats_seed_data) - merged_seed_data.lookup("cats") - expect(merged_seed_data.lookup("cats")).to eq(["Oreo", "Billy"]) - expect(merged_seed_data.lookup("dogs")).to eq(["Rex", "Volt"]) + merged_seed_data.lookup('cats') + expect(merged_seed_data.lookup('cats')).to eq(['Oreo', 'Billy']) + expect(merged_seed_data.lookup('dogs')).to eq(['Rex', 'Volt']) end - it "creates a new seed data instance with the registry merged from both" do - dogs_seed_data.store_reference(:best_dog, "Pitou") - cats_seed_data.store_reference(:best_cat, "Kuzco") + it 'creates a new seed data instance with the registry merged from both' do + dogs_seed_data.store_reference(:best_dog, 'Pitou') + cats_seed_data.store_reference(:best_cat, 'Kuzco') merged_seed_data = dogs_seed_data.merge(cats_seed_data) - expect(merged_seed_data.find_reference(:best_dog)).to eq "Pitou" - expect(merged_seed_data.find_reference(:best_cat)).to eq "Kuzco" + expect(merged_seed_data.find_reference(:best_dog)).to eq 'Pitou' + expect(merged_seed_data.find_reference(:best_cat)).to eq 'Kuzco' # no leaking in original data expect(dogs_seed_data.find_reference(:best_cat, default: nil)).to be_nil expect(cats_seed_data.find_reference(:best_dog, default: nil)).to be_nil end - it "on conflicts, the keys from the given seed data are used" do - dogs_seed_data.store_reference(:best_animal, "Balto the dog") - cats_seed_data.store_reference(:best_animal, "Figaro the cat") + it 'on conflicts, the keys from the given seed data are used' do + dogs_seed_data.store_reference(:best_animal, 'Balto the dog') + cats_seed_data.store_reference(:best_animal, 'Figaro the cat') merged_seed_data = dogs_seed_data.merge(cats_seed_data) - expect(merged_seed_data.find_reference(:best_animal)).to eq("Figaro the cat") + expect(merged_seed_data.find_reference(:best_animal)).to eq('Figaro the cat') - merged_seed_data = dogs_seed_data.merge(described_class.new("dogs" => ["Scooby-Doo", "Droopy"])) + merged_seed_data = dogs_seed_data.merge(described_class.new('dogs' => ['Scooby-Doo', 'Droopy'])) merged_seed_data.lookup(:dogs) - expect(merged_seed_data.lookup("dogs")).to eq(["Scooby-Doo", "Droopy"]) - expect(dogs_seed_data.lookup("dogs")).to eq(["Rex", "Volt"]) + expect(merged_seed_data.lookup('dogs')).to eq(['Scooby-Doo', 'Droopy']) + expect(dogs_seed_data.lookup('dogs')).to eq(['Rex', 'Volt']) end end end diff --git a/spec/seeders/source/translate_spec.rb b/spec/seeders/source/translate_spec.rb index ca997b520627..ff6cb5e35c47 100644 --- a/spec/seeders/source/translate_spec.rb +++ b/spec/seeders/source/translate_spec.rb @@ -28,14 +28,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Source::Translate do - let(:title_en) { "Welcome to OpenProject" } - let(:text_en) { "Learn how to plan projects efficiently." } - let(:title_fr) { "Bienvenue sur OpenProject" } - let(:text_fr) { "Apprenez à planifier des projets efficacement." } - let(:locale) { "fr" } + let(:title_en) { 'Welcome to OpenProject' } + let(:text_en) { 'Learn how to plan projects efficiently.' } + let(:title_fr) { 'Bienvenue sur OpenProject' } + let(:text_fr) { 'Apprenez à planifier des projets efficacement.' } + let(:locale) { 'fr' } # a class including the Translate module needs to provide locale subject(:translator) do @@ -62,7 +62,7 @@ def mock_translations(locale, translations_map) allow(I18n).to receive(:t).and_call_original end - describe "#translate" do + describe '#translate' do it 'translates keys with a "t_" prefix' do mock_translations( locale, @@ -70,17 +70,17 @@ def mock_translations(locale, translations_map) "i18n_key_prefix.welcome.text" => text_fr ) hash = { - "welcome" => { - "t_title" => title_en, - "t_text" => text_en, - "icon" => ":smile:" + 'welcome' => { + 't_title' => title_en, + 't_text' => text_en, + 'icon' => ':smile:' } } - translated = translator.translate(hash, "i18n_key_prefix") - expect(translated.dig("welcome", "title")).to eq(title_fr) - expect(translated.dig("welcome", "text")).to eq(text_fr) - expect(translated.dig("welcome", "icon")).to eq(":smile:") + translated = translator.translate(hash, 'i18n_key_prefix') + expect(translated.dig('welcome', 'title')).to eq(title_fr) + expect(translated.dig('welcome', 'text')).to eq(text_fr) + expect(translated.dig('welcome', 'icon')).to eq(':smile:') end it 'translates nothing if prefix "t_" is absent' do @@ -90,94 +90,94 @@ def mock_translations(locale, translations_map) "i18n_key_prefix.welcome.text" => text_fr ) hash = { - "welcome" => { - "title" => title_en, - "text" => text_en + 'welcome' => { + 'title' => title_en, + 'text' => text_en } } - translated = translator.translate(hash, "i18n_key_prefix") + translated = translator.translate(hash, 'i18n_key_prefix') expect(I18n).not_to have_received(:t) - expect(translated.dig("welcome", "title")).to eq(title_en) - expect(translated.dig("welcome", "text")).to eq(text_en) + expect(translated.dig('welcome', 'title')).to eq(title_en) + expect(translated.dig('welcome', 'text')).to eq(text_en) end - it "uses the original string if no translation exists" do + it 'uses the original string if no translation exists' do hash = { - "welcome" => { - "t_title" => title_en, - "t_text" => text_en + 'welcome' => { + 't_title' => title_en, + 't_text' => text_en } } - translated = translator.translate(hash, "i18n_key_prefix") + translated = translator.translate(hash, 'i18n_key_prefix') expect(I18n).to have_received(:t).at_least(:twice) - expect(translated.dig("welcome", "title")).to eq(title_en) - expect(translated.dig("welcome", "text")).to eq(text_en) + expect(translated.dig('welcome', 'title')).to eq(title_en) + expect(translated.dig('welcome', 'text')).to eq(text_en) end - it "removes the prefixed keys from the returned hash" do + it 'removes the prefixed keys from the returned hash' do hash = { - "welcome" => { - "t_title" => title_en, - "t_text" => text_en + 'welcome' => { + 't_title' => title_en, + 't_text' => text_en } } - translated = translator.translate(hash, "i18n_key_prefix") - expect(translated["welcome"]).to eq( - "title" => title_en, - "text" => text_en + translated = translator.translate(hash, 'i18n_key_prefix') + expect(translated['welcome']).to eq( + 'title' => title_en, + 'text' => text_en ) end - context "when the value to translate is an array" do - let(:locale) { "de" } + context 'when the value to translate is an array' do + let(:locale) { 'de' } - it "translates each values using indices" do + it 'translates each values using indices' do mock_translations( locale, - "i18n_key_prefix.categories.item_0" => "Erste Kategorie", - "i18n_key_prefix.categories.item_1" => "Zweite Kategorie" + "i18n_key_prefix.categories.item_0" => 'Erste Kategorie', + "i18n_key_prefix.categories.item_1" => 'Zweite Kategorie' ) hash = { - "t_categories" => [ - "First category", - "Second category", - "Missing translations are kept as-is" + 't_categories' => [ + 'First category', + 'Second category', + 'Missing translations are kept as-is' ] } - translated = translator.translate(hash, "i18n_key_prefix") - expect(translated["categories"]) - .to eq(["Erste Kategorie", "Zweite Kategorie", "Missing translations are kept as-is"]) + translated = translator.translate(hash, 'i18n_key_prefix') + expect(translated['categories']) + .to eq(['Erste Kategorie', 'Zweite Kategorie', 'Missing translations are kept as-is']) end end - context "when hash contains array of hashes" do - it "translates keys in the nested values if they have translatable keys" do + context 'when hash contains array of hashes' do + it 'translates keys in the nested values if they have translatable keys' do mock_translations( locale, - "i18n_key_prefix.queries.item_0.name" => "Plan projet", - "i18n_key_prefix.queries.item_1.name" => "Tâches" + "i18n_key_prefix.queries.item_0.name" => 'Plan projet', + "i18n_key_prefix.queries.item_1.name" => 'Tâches' ) translated = translator.translate( { - "queries" => [ - { "t_name" => "Project plan", "open" => true }, - { "t_name" => "Tasks", "open" => true }, - { "t_name" => "Missing translations are kept as-is", "open" => true } + 'queries' => [ + { 't_name' => 'Project plan', 'open' => true }, + { 't_name' => 'Tasks', 'open' => true }, + { 't_name' => 'Missing translations are kept as-is', 'open' => true } ] }, - "i18n_key_prefix" + 'i18n_key_prefix' ) - expect(translated["queries"]).to eq( + expect(translated['queries']).to eq( [ - { "name" => "Plan projet", "open" => true }, - { "name" => "Tâches", "open" => true }, - { "name" => "Missing translations are kept as-is", "open" => true } + { 'name' => 'Plan projet', 'open' => true }, + { 'name' => 'Tâches', 'open' => true }, + { 'name' => 'Missing translations are kept as-is', 'open' => true } ] ) end diff --git a/spec/services/add_work_package_note_service_spec.rb b/spec/services/add_work_package_note_service_spec.rb index 734a31e4beb5..5a06d7df8d63 100644 --- a/spec/services/add_work_package_note_service_spec.rb +++ b/spec/services/add_work_package_note_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe AddWorkPackageNoteService, type: :model do let(:user) { build_stubbed(:user) } @@ -36,13 +36,13 @@ work_package:) end - describe ".contract" do - it "uses the CreateNoteContract contract" do + describe '.contract' do + it 'uses the CreateNoteContract contract' do expect(instance.contract_class).to eql WorkPackages::CreateNoteContract end end - describe "call" do + describe 'call' do let(:mock_contract) do double(WorkPackages::CreateNoteContract, new: mock_contract_instance) @@ -54,7 +54,7 @@ end let(:valid_contract) { true } let(:contract_errors) do - double("contract errors") + double('contract errors') end let(:send_notifications) { false } @@ -69,37 +69,37 @@ allow(work_package).to receive(:save_journals).and_return true end - subject { instance.call("blubs", send_notifications:) } + subject { instance.call('blubs', send_notifications:) } - it "is successful" do + it 'is successful' do expect(subject).to be_success end - it "persists the value" do + it 'persists the value' do expect(work_package).to receive(:save_journals).and_return true subject end - it "has no errors" do + it 'has no errors' do expect(subject.errors).to be_empty end - context "when the contract does not validate" do + context 'when the contract does not validate' do let(:valid_contract) { false } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject.success?).to be_falsey end - it "does not persist the changes" do + it 'does not persist the changes' do expect(work_package).not_to receive(:save_journals) subject end it "exposes the contract's errors" do - errors = double("errors") + errors = double('errors') allow(mock_contract_instance).to receive(:errors).and_return(errors) subject @@ -108,24 +108,24 @@ end end - context "when the saving is unsuccessful" do + context 'when the saving is unsuccessful' do before do expect(work_package).to receive(:save_journals).and_return false end - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).not_to be_success end - it "leaves the value unchanged" do + it 'leaves the value unchanged' do subject - expect(work_package.journal_notes).to eql "blubs" + expect(work_package.journal_notes).to eql 'blubs' expect(work_package.journal_user).to eql user end it "exposes the work_packages's errors" do - errors = double("errors") + errors = double('errors') allow(work_package).to receive(:errors).and_return(errors) subject diff --git a/spec/services/api/parser_struct_spec.rb b/spec/services/api/parser_struct_spec.rb index f510fd5479b8..f42a9cff04f7 100644 --- a/spec/services/api/parser_struct_spec.rb +++ b/spec/services/api/parser_struct_spec.rb @@ -24,63 +24,63 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe API::ParserStruct do let(:instance) { described_class.new } - describe "assigning a value and method creation" do + describe 'assigning a value and method creation' do # Dynamically creating a method can be misused when allowing # those method are generated based on client input. # See "Symbol denial of service" at # https://ruby-doc.org/stdlib-3.0.0/libdoc/ostruct/rdoc/OpenStruct.html#class-OpenStruct-label-Caveats. - it "does not dynamically create a method" do - instance.some_method = "string" + it 'does not dynamically create a method' do + instance.some_method = 'string' expect(instance.methods.grep(/some_method/)) .to be_empty end end - describe "assigning an value and getting a hash" do - it "works for [value]=" do - instance.some_value = "string" + describe 'assigning an value and getting a hash' do + it 'works for [value]=' do + instance.some_value = 'string' expect(instance.to_h) - .to eql("some_value" => "string") + .to eql('some_value' => 'string') end - it "works for [value]_id=" do + it 'works for [value]_id=' do instance.some_value_id = 5 expect(instance.to_h) - .to eql("some_value_id" => 5) + .to eql('some_value_id' => 5) end - it "works for group_by=" do + it 'works for group_by=' do instance.group_by = 8 expect(instance.to_h) - .to eql("group_by" => 8) + .to eql('group_by' => 8) end end - describe "assigning an value and getting by hash key" do - it "works for [value]=" do - instance.some_value = "string" + describe 'assigning an value and getting by hash key' do + it 'works for [value]=' do + instance.some_value = 'string' expect(instance[:some_value]) - .to eq("string") + .to eq('string') end - it "works for [value]_id=" do + it 'works for [value]_id=' do instance.some_value_id = 5 expect(instance[:some_value_id]) .to eq(5) end - it "works for group_by=" do + it 'works for group_by=' do instance.group_by = 8 expect(instance[:group_by]) @@ -88,15 +88,15 @@ end end - describe "instantiating with a hash and fetching the value" do + describe 'instantiating with a hash and fetching the value' do let(:instance) do described_class - .new({ "some_value" => "string", "some_value_id" => 5, "group_by" => 8 }) + .new({ 'some_value' => 'string', 'some_value_id' => 5, 'group_by' => 8 }) end - it "allows fetching the value" do + it 'allows fetching the value' do expect(instance.to_h) - .to eql({ "some_value" => "string", "some_value_id" => 5, "group_by" => 8 }) + .to eql({ 'some_value' => 'string', 'some_value_id' => 5, 'group_by' => 8 }) end end end diff --git a/spec/services/api/v3/parse_query_params_service_spec.rb b/spec/services/api/v3/parse_query_params_service_spec.rb index 0dcb9b2be98a..2b28eeb912b5 100644 --- a/spec/services/api/v3/parse_query_params_service_spec.rb +++ b/spec/services/api/v3/parse_query_params_service_spec.rb @@ -26,166 +26,166 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::ParseQueryParamsService, type: :model do let(:instance) { described_class.new } let(:params) { {} } - describe "#call" do + describe '#call' do subject { instance.call(params) } - shared_examples_for "transforms" do - it "is success" do + shared_examples_for 'transforms' do + it 'is success' do expect(subject) .to be_success end - it "is transformed" do + it 'is transformed' do expect(subject.result) .to eql(expected) end end - context "with group by" do - context "as groupBy" do - it_behaves_like "transforms" do - let(:params) { { groupBy: "status" } } - let(:expected) { { group_by: "status" } } + context 'with group by' do + context 'as groupBy' do + it_behaves_like 'transforms' do + let(:params) { { groupBy: 'status' } } + let(:expected) { { group_by: 'status' } } end end - context "as group_by" do - it_behaves_like "transforms" do - let(:params) { { group_by: "status" } } - let(:expected) { { group_by: "status" } } + context 'as group_by' do + it_behaves_like 'transforms' do + let(:params) { { group_by: 'status' } } + let(:expected) { { group_by: 'status' } } end end context 'as "g"' do - it_behaves_like "transforms" do - let(:params) { { g: "status" } } - let(:expected) { { group_by: "status" } } + it_behaves_like 'transforms' do + let(:params) { { g: 'status' } } + let(:expected) { { group_by: 'status' } } end end - context "set to empty string" do - it_behaves_like "transforms" do - let(:params) { { g: "" } } + context 'set to empty string' do + it_behaves_like 'transforms' do + let(:params) { { g: '' } } let(:expected) { { group_by: nil } } end - it_behaves_like "transforms" do - let(:params) { { group_by: "" } } + it_behaves_like 'transforms' do + let(:params) { { group_by: '' } } let(:expected) { { group_by: nil } } end - it_behaves_like "transforms" do - let(:params) { { groupBy: "" } } + it_behaves_like 'transforms' do + let(:params) { { groupBy: '' } } let(:expected) { { group_by: nil } } end end - context "not given" do - let(:params) { { bla: "foo" } } + context 'not given' do + let(:params) { { bla: 'foo' } } - it "does not set group_by" do + it 'does not set group_by' do expect(subject).to be_success expect(subject.result).not_to have_key(:group_by) end end - context "with an attribute called differently in v3" do - it_behaves_like "transforms" do - let(:params) { { groupBy: "assignee" } } - let(:expected) { { group_by: "assigned_to" } } + context 'with an attribute called differently in v3' do + it_behaves_like 'transforms' do + let(:params) { { groupBy: 'assignee' } } + let(:expected) { { group_by: 'assigned_to' } } end end end - context "with columns" do - context "as columns" do - it_behaves_like "transforms" do + context 'with columns' do + context 'as columns' do + it_behaves_like 'transforms' do let(:params) { { columns: %w(status assignee) } } let(:expected) { { columns: %w(status assigned_to) } } end end context 'as "c"' do - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { c: %w(status assignee) } } let(:expected) { { columns: %w(status assigned_to) } } end end - context "as column_names" do - it_behaves_like "transforms" do + context 'as column_names' do + it_behaves_like 'transforms' do let(:params) { { column_names: %w(status assignee) } } let(:expected) { { columns: %w(status assigned_to) } } end end end - context "with highlighted_attributes" do - it_behaves_like "transforms" do + context 'with highlighted_attributes' do + it_behaves_like 'transforms' do let(:params) { { highlightedAttributes: %w(status type priority dueDate) } } # Please note, that dueDate is expected to get translated to due_date. let(:expected) { { highlighted_attributes: %w(status type priority due_date) } } end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { highlightedAttributes: %w(/api/v3/columns/status /api/v3/columns/type) } } # Please note, that dueDate is expected to get translated to due_date. let(:expected) { { highlighted_attributes: %w(status type) } } end end - context "without highlighted_attributes" do - it_behaves_like "transforms" do + context 'without highlighted_attributes' do + it_behaves_like 'transforms' do let(:params) { { highlightedAttributes: nil } } let(:expected) { {} } end end - context "with display_representation" do - it_behaves_like "transforms" do - let(:params) { { displayRepresentation: "cards" } } - let(:expected) { { display_representation: "cards" } } + context 'with display_representation' do + it_behaves_like 'transforms' do + let(:params) { { displayRepresentation: 'cards' } } + let(:expected) { { display_representation: 'cards' } } end end - context "without display_representation" do - it_behaves_like "transforms" do + context 'without display_representation' do + it_behaves_like 'transforms' do let(:params) { { displayRepresentation: nil } } let(:expected) { {} } end end - context "with sort" do - context "as sortBy in comma separated value" do - it_behaves_like "transforms" do + context 'with sort' do + context 'as sortBy in comma separated value' do + it_behaves_like 'transforms' do let(:params) { { sortBy: JSON::dump([%w(status desc)]) } } let(:expected) { { sort_by: [%w(status desc)] } } end end - context "as sortBy in colon concatenated value" do - it_behaves_like "transforms" do - let(:params) { { sortBy: JSON::dump(["status:desc"]) } } + context 'as sortBy in colon concatenated value' do + it_behaves_like 'transforms' do + let(:params) { { sortBy: JSON::dump(['status:desc']) } } let(:expected) { { sort_by: [%w(status desc)] } } end end - context "with an invalid JSON" do - let(:params) { { sortBy: "faulty" + JSON::dump(["status:desc"]) } } + context 'with an invalid JSON' do + let(:params) { { sortBy: 'faulty' + JSON::dump(['status:desc']) } } - it "is not success" do + it 'is not success' do expect(subject) .not_to be_success end - it "returns the error" do + it 'returns the error' do message = 'unexpected token at \'faulty["status:desc"]\'' expect(subject.errors.messages[:base].length) @@ -196,75 +196,75 @@ end end - context "with filters" do - context "as filters in dumped json" do - context "with a filter named internally" do - it_behaves_like "transforms" do + context 'with filters' do + context 'as filters in dumped json' do + context 'with a filter named internally' do + it_behaves_like 'transforms' do let(:params) do - { filters: JSON::dump([{ "status_id" => { "operator" => "=", - "values" => %w(1 2) } }]) } + { filters: JSON::dump([{ 'status_id' => { 'operator' => '=', + 'values' => %w(1 2) } }]) } end let(:expected) do - { filters: [{ field: "status_id", operator: "=", values: %w(1 2) }] } + { filters: [{ field: 'status_id', operator: '=', values: %w(1 2) }] } end end end - context "with a filter named according to v3" do - it_behaves_like "transforms" do + context 'with a filter named according to v3' do + it_behaves_like 'transforms' do let(:params) do - { filters: JSON::dump([{ "status" => { "operator" => "=", - "values" => %w(1 2) } }]) } + { filters: JSON::dump([{ 'status' => { 'operator' => '=', + 'values' => %w(1 2) } }]) } end let(:expected) do - { filters: [{ field: "status_id", operator: "=", values: %w(1 2) }] } + { filters: [{ field: 'status_id', operator: '=', values: %w(1 2) }] } end end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) do - { filters: JSON::dump([{ "subprojectId" => { "operator" => "=", - "values" => %w(1 2) } }]) } + { filters: JSON::dump([{ 'subprojectId' => { 'operator' => '=', + 'values' => %w(1 2) } }]) } end let(:expected) do - { filters: [{ field: "subproject_id", operator: "=", values: %w(1 2) }] } + { filters: [{ field: 'subproject_id', operator: '=', values: %w(1 2) }] } end end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) do - { filters: JSON::dump([{ "watcher" => { "operator" => "=", - "values" => %w(1 2) } }]) } + { filters: JSON::dump([{ 'watcher' => { 'operator' => '=', + 'values' => %w(1 2) } }]) } end let(:expected) do - { filters: [{ field: "watcher_id", operator: "=", values: %w(1 2) }] } + { filters: [{ field: 'watcher_id', operator: '=', values: %w(1 2) }] } end end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) do - { filters: JSON::dump([{ "custom_field_1" => { "operator" => "=", - "values" => %w(1 2) } }]) } + { filters: JSON::dump([{ 'custom_field_1' => { 'operator' => '=', + 'values' => %w(1 2) } }]) } end let(:expected) do - { filters: [{ field: "cf_1", operator: "=", values: %w(1 2) }] } + { filters: [{ field: 'cf_1', operator: '=', values: %w(1 2) }] } end end end - context "with an invalid JSON" do + context 'with an invalid JSON' do let(:params) do - { filters: "faulty" + JSON::dump([{ "status" => { "operator" => "=", - "values" => %w(1 2) } }]) } + { filters: 'faulty' + JSON::dump([{ 'status' => { 'operator' => '=', + 'values' => %w(1 2) } }]) } end - it "is not success" do + it 'is not success' do expect(subject) .not_to be_success end - it "returns the error" do - message = "unexpected token at " + + it 'returns the error' do + message = 'unexpected token at ' + "'faulty[{\"status\":{\"operator\":\"=\",\"values\":[\"1\",\"2\"]}}]'" expect(subject.errors.messages[:base].length) @@ -274,8 +274,8 @@ end end - context "with an empty array (in JSON)" do - it_behaves_like "transforms" do + context 'with an empty array (in JSON)' do + it_behaves_like 'transforms' do let(:params) do { filters: JSON::dump([]) } end @@ -287,66 +287,66 @@ end end - context "with showSums" do - it_behaves_like "transforms" do - let(:params) { { showSums: "true" } } + context 'with showSums' do + it_behaves_like 'transforms' do + let(:params) { { showSums: 'true' } } let(:expected) { { display_sums: true } } end - it_behaves_like "transforms" do - let(:params) { { showSums: "false" } } + it_behaves_like 'transforms' do + let(:params) { { showSums: 'false' } } let(:expected) { { display_sums: false } } end end - context "with timelineLabels" do - let(:input) { { left: "a", right: "b", farRight: "c" } } + context 'with timelineLabels' do + let(:input) { { left: 'a', right: 'b', farRight: 'c' } } - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { timelineLabels: input.to_json } } let(:expected) { { timeline_labels: input.stringify_keys } } end end - context "with includeSubprojects" do - it_behaves_like "transforms" do - let(:params) { { includeSubprojects: "true" } } + context 'with includeSubprojects' do + it_behaves_like 'transforms' do + let(:params) { { includeSubprojects: 'true' } } let(:expected) { { include_subprojects: true } } end - it_behaves_like "transforms" do - let(:params) { { includeSubprojects: "false" } } + it_behaves_like 'transforms' do + let(:params) { { includeSubprojects: 'false' } } let(:expected) { { include_subprojects: false } } end end - context "with timestamps" do - it_behaves_like "transforms" do + context 'with timestamps' do + it_behaves_like 'transforms' do let(:params) { { timestamps: "" } } let(:expected) { { timestamps: [] } } end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { timestamps: "P-0Y" } } let(:expected) { { timestamps: [Timestamp.parse("P-0Y")] } } end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { timestamps: "2022-10-29T23:01:23Z, P-0Y" } } let(:expected) { { timestamps: [Timestamp.parse("2022-10-29T23:01:23Z"), Timestamp.parse("P-0Y")] } } end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { timestamps: "-1y, now" } } let(:expected) { { timestamps: [Timestamp.new("P-1Y"), Timestamp.new("PT0S")] } } end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { timestamps: "oneMonthAgo@11:00+00:00, now" } } let(:expected) { { timestamps: [Timestamp.parse("oneMonthAgo@11:00+00:00"), Timestamp.new("PT0S")] } } end - it_behaves_like "transforms" do + it_behaves_like 'transforms' do let(:params) { { timestamps: "oneMonthAgo@11:00+00:00, oneWeekAgo@12:00+10:00" } } let(:expected) { { timestamps: [Timestamp.parse("oneMonthAgo@11:00+00:00"), Timestamp.parse("oneWeekAgo@12:00+10:00")] } } end @@ -354,11 +354,11 @@ describe "for invalid parameters" do let(:params) { { timestamps: "foo,bar" } } - it "is not success" do + it 'is not success' do expect(subject).not_to be_success end - it "returns the error" do + it 'returns the error' do expect(subject.errors.messages[:base].length).to be(1) expect(subject.errors.messages[:base][0]).to include "\"foo\"" end diff --git a/spec/services/api/v3/update_query_from_v3_params_service_spec.rb b/spec/services/api/v3/update_query_from_v3_params_service_spec.rb index 7bf11eb92477..4bfb3ad841b2 100644 --- a/spec/services/api/v3/update_query_from_v3_params_service_spec.rb +++ b/spec/services/api/v3/update_query_from_v3_params_service_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::UpdateQueryFromV3ParamsService, type: :model do let(:user) { build_stubbed(:user) } let(:query) { build_stubbed(:query) } - let(:params) { double("params") } - let(:parsed_params) { double("parsed_params") } + let(:params) { double('params') } + let(:parsed_params) { double('parsed_params') } let(:mock_parse_query_service) do - mock = double("ParseQueryParamsService") + mock = double('ParseQueryParamsService') allow(mock) .to receive(:call) @@ -58,7 +58,7 @@ let(:mock_parse_query_service_result) { parsed_params } let(:mock_update_query_service) do - mock = double("UpdateQueryFromParamsService") + mock = double('UpdateQueryFromParamsService') allow(mock) .to receive(:call) @@ -91,20 +91,20 @@ .and_return(mock_parse_query_service) end - describe "#call" do + describe '#call' do subject { instance.call(params) } - it "returns the update result" do + it 'returns the update result' do expect(subject) .to eql(mock_update_query_service_response) end - context "when parsing fails" do + context 'when parsing fails' do let(:mock_parse_query_service_success) { false } - let(:mock_parse_query_service_errors) { double "error" } + let(:mock_parse_query_service_errors) { double 'error' } let(:mock_parse_query_service_result) { nil } - it "returns the parse result" do + it 'returns the parse result' do expect(subject) .to eql(mock_parse_query_service_response) end diff --git a/spec/services/api/v3/work_package_collection_from_query_params_service_spec.rb b/spec/services/api/v3/work_package_collection_from_query_params_service_spec.rb index 18cf660a9812..479c3de5f092 100644 --- a/spec/services/api/v3/work_package_collection_from_query_params_service_spec.rb +++ b/spec/services/api/v3/work_package_collection_from_query_params_service_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackageCollectionFromQueryParamsService, type: :model do include API::V3::Utilities::PathHelper let(:mock_wp_collection_from_query_service) do - mock = double("WorkPackageCollectionFromQueryService") + mock = double('WorkPackageCollectionFromQueryService') allow(mock) .to receive(:call) @@ -50,7 +50,7 @@ let(:mock_wp_collection_service_success) { true } let(:mock_wp_collection_service_errors) { nil } - let(:mock_wp_collection_service_result) { double("result") } + let(:mock_wp_collection_service_result) { double('result') } let(:query) { build_stubbed(:query) } let(:project) { build_stubbed(:project) } @@ -59,7 +59,7 @@ let(:instance) { described_class.new(user) } before do - stub_const("::API::V3::WorkPackageCollectionFromQueryService", + stub_const('::API::V3::WorkPackageCollectionFromQueryService', mock_wp_collection_from_query_service) allow(API::V3::WorkPackageCollectionFromQueryService) @@ -68,7 +68,7 @@ .and_return(mock_wp_collection_from_query_service) end - describe "#call" do + describe '#call' do let(:params) { { project: } } subject { instance.call(params) } @@ -80,7 +80,7 @@ .and_return(query) end - it "is successful" do + it 'is successful' do expect(subject) .to eql(mock_wp_collection_service_response) end diff --git a/spec/services/api/v3/work_package_collection_from_query_service_spec.rb b/spec/services/api/v3/work_package_collection_from_query_service_spec.rb index 26d41620ad4a..f2ea84b3f928 100644 --- a/spec/services/api/v3/work_package_collection_from_query_service_spec.rb +++ b/spec/services/api/v3/work_package_collection_from_query_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe API::V3::WorkPackageCollectionFromQueryService, type: :model do @@ -46,7 +46,7 @@ let(:query_manually_sorted) { false } let(:results) do - results = double("results") + results = double('results') allow(results) .to receive(:work_packages) @@ -67,7 +67,7 @@ allow(results) .to receive(:query) - .and_return(double("query")) + .and_return(double('query')) results end @@ -138,7 +138,7 @@ def initialize(group, let(:params) { {} } let(:mock_update_query_service) do - mock = double("UpdateQueryFromV3ParamsService") + mock = double('UpdateQueryFromV3ParamsService') allow(mock) .to receive(:call) @@ -162,12 +162,12 @@ def initialize(group, let(:instance) { described_class.new(query, user) } - describe "#call" do + describe '#call' do subject { instance.call(params) } before do - stub_const("::API::V3::WorkPackages::WorkPackageCollectionRepresenter", mock_wp_representer) - stub_const("::API::V3::WorkPackages::WorkPackageAggregationGroup", mock_aggregation_representer) + stub_const('::API::V3::WorkPackages::WorkPackageCollectionRepresenter', mock_wp_representer) + stub_const('::API::V3::WorkPackages::WorkPackageAggregationGroup', mock_aggregation_representer) allow(API::V3::UpdateQueryFromV3ParamsService) .to receive(:new) @@ -175,86 +175,86 @@ def initialize(group, .and_return(mock_update_query_service) end - it "is successful" do + it 'is successful' do expect(subject).to be_success end - context "result" do + context 'result' do subject { instance.call(params).result } - it "is a WorkPackageCollectionRepresenter" do + it 'is a WorkPackageCollectionRepresenter' do expect(subject) .to be_a(API::V3::WorkPackages::WorkPackageCollectionRepresenter) end - context "work_packages" do + context 'work_packages' do it "has the query's work_package results set" do expect(subject.work_packages) .to contain_exactly(work_package) end end - context "current_user" do - it "has the provided user set" do + context 'current_user' do + it 'has the provided user set' do expect(subject.current_user) .to eq(user) end end - context "project" do - it "has the queries project set" do + context 'project' do + it 'has the queries project set' do expect(subject.project) .to eq(query.project) end end - context "self_link" do - context "if the project is nil" do + context 'self_link' do + context 'if the project is nil' do let(:query) { build_stubbed(:query, project: nil) } - it "is the global work_package link" do + it 'is the global work_package link' do expect(subject.self_link) .to eq(api_v3_paths.work_packages) end end - context "if the project is set" do + context 'if the project is set' do let(:query) { build_stubbed(:query, project:) } - it "is the global work_package link" do + it 'is the global work_package link' do expect(subject.self_link) .to eq(api_v3_paths.work_packages_by_project(project.id)) end end end - context "embed_schemas" do - it "is true" do + context 'embed_schemas' do + it 'is true' do expect(subject.embed_schemas) .to be_truthy end end - context "when timestamps are given" do + context 'when timestamps are given' do let(:timestamps) { [Timestamp.parse("P-1Y"), Timestamp.parse("oneWeekAgo@12:00+00:00"), Timestamp.now] } let(:query) { build_stubbed(:query, timestamps:) } - it "has the query timestamps" do + it 'has the query timestamps' do expect(subject.timestamps) .to match_array(timestamps) end end - context "when a _query object is given" do - it "has the query" do + context 'when a _query object is given' do + it 'has the query' do expect(subject.query) .to eq(query) end end - context "total_sums" do - context "with query.display_sums? being false" do - it "is nil" do + context 'total_sums' do + context 'with query.display_sums? being false' do + it 'is nil' do query.display_sums = false expect(subject.total_sums) @@ -262,8 +262,8 @@ def initialize(group, end end - context "with query.display_sums? being true" do - it "has a struct containing the sums and the available custom fields" do + context 'with query.display_sums? being true' do + it 'has a struct containing the sums and the available custom fields' do query.display_sums = true custom_fields = [build_stubbed(:text_wp_custom_field), @@ -281,9 +281,9 @@ def initialize(group, end end - context "groups" do - context "with query.grouped? being false" do - it "is nil" do + context 'groups' do + context 'with query.grouped? being false' do + it 'is nil' do query.group_by = nil expect(subject.groups) @@ -291,18 +291,18 @@ def initialize(group, end end - context "with query.group_by being empty" do - it "is nil" do - query.group_by = "" + context 'with query.group_by being empty' do + it 'is nil' do + query.group_by = '' expect(subject.groups) .to be_nil end end - context "with query.grouped? being true" do - it "has the groups" do - query.group_by = "status" + context 'with query.grouped? being true' do + it 'has the groups' do + query.group_by = 'status' expect(subject.groups[0].group) .to eq(1) @@ -316,9 +316,9 @@ def initialize(group, end end - context "query (in the url)" do - context "when displaying sums" do - it "is represented" do + context 'query (in the url)' do + context 'when displaying sums' do + it 'is represented' do query.display_sums = true expect(subject.query_params[:showSums]) @@ -326,8 +326,8 @@ def initialize(group, end end - context "when displaying hierarchies" do - it "is represented" do + context 'when displaying hierarchies' do + it 'is represented' do query.show_hierarchies = true expect(subject.query_params[:showHierarchies]) @@ -335,41 +335,41 @@ def initialize(group, end end - context "when grouping" do - it "is represented" do - query.group_by = "status_id" + context 'when grouping' do + it 'is represented' do + query.group_by = 'status_id' expect(subject.query_params[:groupBy]) - .to eq("status_id") + .to eq('status_id') end end - context "when sorting" do - it "is represented" do - query.sort_criteria = [["status_id", "desc"]] + context 'when sorting' do + it 'is represented' do + query.sort_criteria = [['status_id', 'desc']] - expected_sort = JSON::dump [["status", "desc"]] + expected_sort = JSON::dump [['status', 'desc']] expect(subject.query_params[:sortBy]) .to eq(expected_sort) end end - context "filters" do - it "is represented" do - query.add_filter("status_id", "=", ["1", "2"]) - query.add_filter("subproject_id", "=", ["3", "4"]) + context 'filters' do + it 'is represented' do + query.add_filter('status_id', '=', ['1', '2']) + query.add_filter('subproject_id', '=', ['3', '4']) expected_filters = JSON::dump([ - { status: { operator: "=", values: ["1", "2"] } }, - { subprojectId: { operator: "=", values: ["3", "4"] } } + { status: { operator: '=', values: ['1', '2'] } }, + { subprojectId: { operator: '=', values: ['3', '4'] } } ]) expect(subject.query_params[:filters]) .to eq(expected_filters) end - it "represents no filters" do + it 'represents no filters' do expected_filters = JSON::dump([]) expect(subject.query_params[:filters]) @@ -378,68 +378,68 @@ def initialize(group, end end - context "offset" do - it "is 1 as default" do + context 'offset' do + it 'is 1 as default' do expect(subject.query_params[:offset]) .to be(1) end - context "with a provided value" do + context 'with a provided value' do # It is imporant for the keys to be strings # as that is what will come from the client - let(:params) { { "offset" => 3 } } + let(:params) { { 'offset' => 3 } } - it "is that value" do + it 'is that value' do expect(subject.query_params[:offset]) .to be(3) end end end - context "pageSize" do + context 'pageSize' do before do allow(Setting) .to receive(:per_page_options_array) .and_return([25, 50]) end - it "is nil" do + it 'is nil' do expect(subject.query_params[:pageSize]) .to be(25) end - context "with a provided value" do + context 'with a provided value' do # It is imporant for the keys to be strings # as that is what will come from the client - let(:params) { { "pageSize" => 100 } } + let(:params) { { 'pageSize' => 100 } } - it "is that value" do + it 'is that value' do expect(subject.query_params[:pageSize]) .to be(100) end end - context "with the query sorted manually", with_settings: { forced_single_page_size: 42 } do + context 'with the query sorted manually', with_settings: { forced_single_page_size: 42 } do let(:query_manually_sorted) { true } - it "is the setting value" do + it 'is the setting value' do expect(subject.query_params[:pageSize]) .to be(42) end - context "with a provided value" do - let(:params) { { "pageSize" => 100 } } + context 'with a provided value' do + let(:params) { { 'pageSize' => 100 } } - it "is the setting value" do + it 'is the setting value' do expect(subject.query_params[:pageSize]) .to be(42) end end - context "with a provided value of 0" do - let(:params) { { "pageSize" => 0 } } + context 'with a provided value of 0' do + let(:params) { { 'pageSize' => 0 } } - it "is the provided value" do + it 'is the provided value' do expect(subject.query_params[:pageSize]) .to be(0) end @@ -448,12 +448,12 @@ def initialize(group, end end - context "when the update query service fails" do + context 'when the update query service fails' do let(:update_query_service_success) { false } - let(:update_query_service_errors) { double("errors") } + let(:update_query_service_errors) { double('errors') } let(:update_query_service_result) { nil } - it "returns the update service response" do + it 'returns the update service response' do expect(subject) .to eql(mock_update_query_service_response) end diff --git a/spec/services/attachments/create_service_integration_spec.rb b/spec/services/attachments/create_service_integration_spec.rb index dd6c69c323f2..f049cfe0cd24 100644 --- a/spec/services/attachments/create_service_integration_spec.rb +++ b/spec/services/attachments/create_service_integration_spec.rb @@ -25,58 +25,58 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe Attachments::CreateService, "integration", with_settings: { journal_aggregation_time_minutes: 0 } do - let(:description) { "a fancy description" } +RSpec.describe Attachments::CreateService, 'integration', with_settings: { journal_aggregation_time_minutes: 0 } do + let(:description) { 'a fancy description' } subject { described_class.new(user:) } - describe "#call" do + describe '#call' do def call_tested_method subject.call container:, - file: FileHelpers.mock_uploaded_file(name: "foobar.txt"), - filename: "foobar.txt", + file: FileHelpers.mock_uploaded_file(name: 'foobar.txt'), + filename: 'foobar.txt', description: end - context "when journalized" do + context 'when journalized' do shared_let(:container) { create(:work_package) } shared_let(:user) do create(:user, member_with_permissions: { container.project => %i[view_work_packages edit_work_packages] }) end - shared_examples "successful creation" do - it "saves the attachment" do + shared_examples 'successful creation' do + it 'saves the attachment' do attachment = Attachment.first - expect(attachment.filename).to eq "foobar.txt" + expect(attachment.filename).to eq 'foobar.txt' expect(attachment.description).to eq description end - it "adds the attachment to the container" do + it 'adds the attachment to the container' do container.reload expect(container.attachments).to include Attachment.first end - it "adds a journal entry on the container" do + it 'adds a journal entry on the container' do expect(container.journals.count).to eq 2 # 1 for WP creation + 1 for the attachment end - it "updates the timestamp on the container" do + it 'updates the timestamp on the container' do expect(container.reload.updated_at) .not_to eql timestamp_before end end - context "with a valid container" do + context 'with a valid container' do let!(:timestamp_before) { container.updated_at } before do call_tested_method end - it_behaves_like "successful creation" + it_behaves_like 'successful creation' end context "with an invalid container" do @@ -84,16 +84,16 @@ def call_tested_method before do # have an invalid work package - container.update_column(:subject, "") + container.update_column(:subject, '') call_tested_method end - it_behaves_like "successful creation" + it_behaves_like 'successful creation' end - context "with an invalid attachment", with_settings: { attachment_max_size: 0 } do - it "does not raise exceptions" do + context 'with an invalid attachment', with_settings: { attachment_max_size: 0 } do + it 'does not raise exceptions' do expect { call_tested_method } .not_to raise_exception ActiveRecord::RecordInvalid @@ -102,55 +102,55 @@ def call_tested_method end end - context "when not journalized" do + context 'when not journalized' do shared_let(:container) { create(:message) } shared_let(:user) do create(:user, member_with_permissions: { container.forum.project => %i[add_messages edit_messages] }) end - shared_examples "successful creation" do - it "saves the attachment" do + shared_examples 'successful creation' do + it 'saves the attachment' do attachment = Attachment.first - expect(attachment.filename).to eq "foobar.txt" + expect(attachment.filename).to eq 'foobar.txt' expect(attachment.description).to eq description end - it "adds the attachment to the container" do + it 'adds the attachment to the container' do container.reload expect(container.attachments).to include Attachment.first end - it "adds a journal entry on the container" do + it 'adds a journal entry on the container' do expect(container.journals.count).to eq 2 # 1 for WP creation + 1 for the attachment end - it "updates the timestamp on the container" do + it 'updates the timestamp on the container' do expect(container.reload.updated_at) .not_to eql timestamp_before end end - context "with a valid container" do + context 'with a valid container' do let!(:timestamp_before) { container.updated_at } before do call_tested_method end - it_behaves_like "successful creation" + it_behaves_like 'successful creation' end context "with an invalid container" do let!(:timestamp_before) { container.updated_at } before do - container.update_column(:subject, "") + container.update_column(:subject, '') call_tested_method end - it_behaves_like "successful creation" + it_behaves_like 'successful creation' end end @@ -162,9 +162,9 @@ def call_tested_method call_tested_method end - it "saves the attachment" do + it 'saves the attachment' do attachment = Attachment.first - expect(attachment.filename).to eq "foobar.txt" + expect(attachment.filename).to eq 'foobar.txt' expect(attachment.description).to eq description end end @@ -173,10 +173,10 @@ def call_tested_method let(:container) { nil } let(:user) { build_stubbed(:user) } - it "does not save an attachment" do + it 'does not save an attachment' do expect do expect(call_tested_method).to be_failure - expect(call_tested_method.errors[:base]).to include "may not be accessed." + expect(call_tested_method.errors[:base]).to include 'may not be accessed.' end.not_to change { Attachment.count } end end diff --git a/spec/services/attachments/delete_service_integration_spec.rb b/spec/services/attachments/delete_service_integration_spec.rb index 150d5d8837ef..cabccc0c6ec8 100644 --- a/spec/services/attachments/delete_service_integration_spec.rb +++ b/spec/services/attachments/delete_service_integration_spec.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe Attachments::DeleteService, "integration", with_settings: { journal_aggregation_time_minutes: 0 } do +RSpec.describe Attachments::DeleteService, 'integration', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) { described_class.new(model: attachment, user:).call } let(:user) do @@ -37,33 +37,33 @@ let(:attachment) { create(:attachment, container:, author:) } let(:author) { user } - describe "#call" do - context "when container is journalized" do + describe '#call' do + context 'when container is journalized' do let(:container) { create(:work_package, project:) } let(:permissions) { %i[edit_work_packages] } - shared_examples "successful deletion" do - it "is successful" do + shared_examples 'successful deletion' do + it 'is successful' do expect(call) .to be_success end - it "removes the attachment" do + it 'removes the attachment' do expect(Attachment.where(id: attachment.id)) .not_to exist end - it "adds a journal entry to the container" do + it 'adds a journal entry to the container' do expect(container.journals.reload.count).to eq 3 # 1 for WP creation + 1 for adding the attachment + 1 for deletion end - it "updates the timestamp on the container" do + it 'updates the timestamp on the container' do expect(container.reload.updated_at) .not_to eql timestamp_before end end - context "with a valid container" do + context 'with a valid container' do let!(:timestamp_before) { container.updated_at } before do @@ -75,7 +75,7 @@ call end - it_behaves_like "successful deletion" + it_behaves_like 'successful deletion' end context "with an invalid container" do @@ -84,49 +84,49 @@ before do # Force to have a journal for the attachment attachment - container.add_journal(user:, notes: "Some notes") + container.add_journal(user:, notes: 'Some notes') container.save! # have an invalid work package - container.update_column(:subject, "") + container.update_column(:subject, '') call end - it_behaves_like "successful deletion" + it_behaves_like 'successful deletion' end end - context "when not journalized" do + context 'when not journalized' do let(:container) { create(:message, forum:) } let(:forum) { create(:forum, project:) } let(:permissions) { %i[delete_messages edit_messages] } - shared_examples "successful deletion" do - it "is successful" do + shared_examples 'successful deletion' do + it 'is successful' do expect(call) .to be_success end - it "removes the attachment" do + it 'removes the attachment' do expect(Attachment.where(id: attachment.id)) .not_to exist end - it "updates the timestamp on the container" do + it 'updates the timestamp on the container' do expect(container.reload.updated_at) .not_to eql timestamp_before end end - context "with a valid container" do + context 'with a valid container' do let!(:timestamp_before) { container.updated_at } before do call end - it_behaves_like "successful deletion" + it_behaves_like 'successful deletion' end context "with an invalid container" do @@ -134,12 +134,12 @@ before do # have an invalid container - container.update_column(:subject, "") + container.update_column(:subject, '') call end - it_behaves_like "successful deletion" + it_behaves_like 'successful deletion' end end @@ -151,27 +151,27 @@ call end - context "when the user is the attachment author" do - it "is successful" do + context 'when the user is the attachment author' do + it 'is successful' do expect(call) .to be_success end - it "removes the attachment" do + it 'removes the attachment' do expect(Attachment.where(id: attachment.id)) .not_to exist end end - context "with the user not being the attachment author" do + context 'with the user not being the attachment author' do let(:author) { create(:user) } - it "fails" do + it 'fails' do expect(call) .to be_failure end - it "keeps the attachment" do + it 'keeps the attachment' do expect(Attachment.find(attachment.id)) .to eql attachment end diff --git a/spec/services/attachments/prepare_upload_service_integration_spec.rb b/spec/services/attachments/prepare_upload_service_integration_spec.rb index 31aa7cbf4959..9af9f8487214 100644 --- a/spec/services/attachments/prepare_upload_service_integration_spec.rb +++ b/spec/services/attachments/prepare_upload_service_integration_spec.rb @@ -25,10 +25,10 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe Attachments::PrepareUploadService, - "integration" do + 'integration' do shared_let(:container) { create(:work_package) } shared_let(:user) do create(:user, @@ -37,7 +37,7 @@ let(:instance) { described_class.new(user:) } let(:file_size) { 6 } - let(:file_name) { "document.png" } + let(:file_name) { 'document.png' } let(:content_type) { "application/octet-stream" } let(:call) do @@ -49,44 +49,44 @@ let(:attachment) { call.result } - it "returns the attachment" do + it 'returns the attachment' do expect(attachment) .to be_a(Attachment) end - it "sets the content_type" do + it 'sets the content_type' do expect(attachment.content_type) .to eql content_type end - it "sets the file_size" do + it 'sets the file_size' do expect(attachment.filesize) .to eql file_size end - it "sets the file for carrierwave" do + it 'sets the file for carrierwave' do expect(attachment.file.file.path) .to end_with "attachment/file/#{attachment.id}/#{file_name}" end - it "sets the author" do + it 'sets the author' do expect(attachment.author) .to eql user end - it "sets the digest to empty string" do + it 'sets the digest to empty string' do expect(attachment.digest) .to eql "" end - it "sets the status to prepared" do - expect(attachment.status).to eq "prepared" + it 'sets the status to prepared' do + expect(attachment.status).to eq 'prepared' end - context "with a special character in the filename" do + context 'with a special character in the filename' do let(:file_name) { "document=number 5.png" } - it "sets the file for carrierwave" do + it 'sets the file for carrierwave' do expect(attachment.file.file.path) .to end_with "attachment/file/#{attachment.id}/document_number_5.png" end diff --git a/spec/services/authentication/omniauth_service_spec.rb b/spec/services/authentication/omniauth_service_spec.rb index 08de351d4a9c..8813bf44827c 100644 --- a/spec/services/authentication/omniauth_service_spec.rb +++ b/spec/services/authentication/omniauth_service_spec.rb @@ -25,43 +25,43 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe Authentication::OmniauthService do - let(:strategy) { double("Omniauth Strategy", name: "saml") } + let(:strategy) { double('Omniauth Strategy', name: 'saml') } let(:additional_info) do {} end let(:auth_hash) do OmniAuth::AuthHash.new( - provider: "google", - uid: "123545", + provider: 'google', + uid: '123545', info: { - name: "foo", + name: 'foo', email: auth_email, - first_name: "foo", - last_name: "bar" + first_name: 'foo', + last_name: 'bar' }.merge(additional_info) ) end - let(:auth_email) { "foo@bar.com" } - let(:controller) { double("Controller", session: session_stub) } + let(:auth_email) { 'foo@bar.com' } + let(:controller) { double('Controller', session: session_stub) } let(:session_stub) { [] } let(:instance) { described_class.new(strategy:, auth_hash:, controller:) } let(:user_attributes) { instance.send :build_omniauth_hash_to_user_attributes } - describe "#contract" do + describe '#contract' do before do allow(instance.contract) .to(receive(:validate)) .and_return(valid) end - context "if valid" do + context 'if valid' do let(:valid) { true } - it "calls the registration service" do + it 'calls the registration service' do expect(Users::RegisterUserService) .to(receive(:new)) .with(kind_of(User)) @@ -71,31 +71,31 @@ end end - context "if invalid" do + context 'if invalid' do let(:valid) { false } - it "does not call the registration service" do + it 'does not call the registration service' do expect(Users::RegisterUserService) .not_to(receive(:new)) expect(instance.contract) .to(receive(:errors)) - .and_return(["foo"]) + .and_return(['foo']) call = instance.call expect(call).to be_failure - expect(call.errors).to eq ["foo"] + expect(call.errors).to eq ['foo'] end end end - describe "activation of users" do + describe 'activation of users' do let(:call) { instance.call } - context "with an active found user" do - shared_let(:user) { create(:user, login: "foo@bar.com", identity_url: "google:123545") } + context 'with an active found user' do + shared_let(:user) { create(:user, login: 'foo@bar.com', identity_url: 'google:123545') } - it "does not call register user service and logs in the user" do + it 'does not call register user service and logs in the user' do allow(Users::RegisterUserService).to receive(:new) expect(OpenProject::OmniAuth::Authorization) @@ -104,29 +104,29 @@ expect(call).to be_success expect(call.result).to eq user - expect(call.result.firstname).to eq "foo" - expect(call.result.lastname).to eq "bar" - expect(call.result.mail).to eq "foo@bar.com" + expect(call.result.firstname).to eq 'foo' + expect(call.result.lastname).to eq 'bar' + expect(call.result.mail).to eq 'foo@bar.com' expect(Users::RegisterUserService).not_to have_received(:new) end - context "if the user is to become admin" do + context 'if the user is to become admin' do let(:additional_info) { { admin: true } } - it "updates the user" do + it 'updates the user' do expect(user).not_to be_admin expect(call).to be_success expect(call.result).to eq user expect(call.result).to be_admin end - context "if the user cannot be updated for some reason" do + context 'if the user cannot be updated for some reason' do let(:stub) { instance_double(Users::UpdateService) } - it "fails the request" do + it 'fails the request' do allow(Users::UpdateService).to receive(:new).and_return(stub) - allow(stub).to receive(:call).and_return(ServiceResult.failure(message: "Oh noes!")) + allow(stub).to receive(:call).and_return(ServiceResult.failure(message: 'Oh noes!')) expect(call).not_to be_success expect(call.result).to be_nil @@ -135,10 +135,10 @@ end end - context "if the user is the last admin and is about to be revoked" do + context 'if the user is the last admin and is about to be revoked' do let(:additional_info) { { admin: false } } - it "does not revoke admin status" do + it 'does not revoke admin status' do user.update!(admin: true) expect(user).to be_admin @@ -149,11 +149,11 @@ end end - context "if the user is not the last admin and is about to be revoked" do + context 'if the user is not the last admin and is about to be revoked' do let!(:other_admin) { create(:admin) } let(:additional_info) { { admin: false } } - it "revokes admin status" do + it 'revokes admin status' do user.update!(admin: true) expect(user).to be_admin @@ -164,30 +164,30 @@ end end - context "without remapping allowed", + context 'without remapping allowed', with_settings: { oauth_allow_remapping_of_existing_users?: false } do - let!(:user) { create(:user, login: "foo@bar.com") } + let!(:user) { create(:user, login: 'foo@bar.com') } - it "does not look for the user by login" do + it 'does not look for the user by login' do allow(Users::RegisterUserService).to receive(:new).and_call_original expect(call).not_to be_success - expect(call.result.firstname).to eq "foo" - expect(call.result.lastname).to eq "bar" - expect(call.result.mail).to eq "foo@bar.com" + expect(call.result.firstname).to eq 'foo' + expect(call.result.lastname).to eq 'bar' + expect(call.result.mail).to eq 'foo@bar.com' expect(call.result).not_to eq user expect(call.result).to be_new_record - expect(call.result.errors[:login]).to eq ["has already been taken."] + expect(call.result.errors[:login]).to eq ['has already been taken.'] expect(Users::RegisterUserService).to have_received(:new) end end - context "with an active user remapped", + context 'with an active user remapped', with_settings: { oauth_allow_remapping_of_existing_users?: true } do - let!(:user) { create(:user, identity_url: "foo", login: auth_email.downcase) } + let!(:user) { create(:user, identity_url: 'foo', login: auth_email.downcase) } - shared_examples_for "a successful remapping of foo" do + shared_examples_for 'a successful remapping of foo' do before do allow(Users::RegisterUserService).to receive(:new) allow(OpenProject::OmniAuth::Authorization) @@ -195,25 +195,25 @@ .with(user, auth_hash, instance) end - it "does not call register user service and logs in the user" do - aggregate_failures "Service call" do + it 'does not call register user service and logs in the user' do + aggregate_failures 'Service call' do expect(call).to be_success expect(call.result).to eq user - expect(call.result.firstname).to eq "foo" - expect(call.result.lastname).to eq "bar" + expect(call.result.firstname).to eq 'foo' + expect(call.result.lastname).to eq 'bar' expect(call.result.login).to eq auth_email expect(call.result.mail).to eq auth_email end user.reload - aggregate_failures "User attributes" do - expect(user.firstname).to eq "foo" - expect(user.lastname).to eq "bar" - expect(user.identity_url).to eq "google:123545" + aggregate_failures 'User attributes' do + expect(user.firstname).to eq 'foo' + expect(user.lastname).to eq 'bar' + expect(user.identity_url).to eq 'google:123545' end - aggregate_failures "Message expectations" do + aggregate_failures 'Message expectations' do expect(OpenProject::OmniAuth::Authorization) .to(have_received(:after_login!)) @@ -222,28 +222,28 @@ end end - context "with an all lower case login on the IdP side" do - it_behaves_like "a successful remapping of foo" + context 'with an all lower case login on the IdP side' do + it_behaves_like 'a successful remapping of foo' end - context "with a partially upper case login on the IdP side" do - let(:auth_email) { "FoO@Bar.COM" } + context 'with a partially upper case login on the IdP side' do + let(:auth_email) { 'FoO@Bar.COM' } - it_behaves_like "a successful remapping of foo" + it_behaves_like 'a successful remapping of foo' end end - describe "assuming registration/activation worked" do + describe 'assuming registration/activation worked' do let(:register_call) { ServiceResult.new(success: register_success, message: register_message) } let(:register_success) { true } - let(:register_message) { "It worked!" } + let(:register_message) { 'It worked!' } before do expect(Users::RegisterUserService).to receive_message_chain(:new, :call).and_return(register_call) end - describe "with a new user" do - it "calls the register service" do + describe 'with a new user' do + it 'calls the register service' do expect(call).to be_success # The user might get activated in the register service @@ -256,26 +256,26 @@ end end - describe "assuming registration/activation failed" do + describe 'assuming registration/activation failed' do let(:register_success) { false } - let(:register_message) { "Oh noes :(" } + let(:register_message) { 'Oh noes :(' } end end - describe "#identity_url_from_omniauth" do - let(:auth_hash) { { provider: "developer", uid: "veryuniqueid", info: {} } } + describe '#identity_url_from_omniauth' do + let(:auth_hash) { { provider: 'developer', uid: 'veryuniqueid', info: {} } } subject { instance.send(:identity_url_from_omniauth) } - it "returns the correct identity_url" do - expect(subject).to eql("developer:veryuniqueid") + it 'returns the correct identity_url' do + expect(subject).to eql('developer:veryuniqueid') end - context "with uid mapped from info" do - let(:auth_hash) { { provider: "developer", uid: "veryuniqueid", info: { uid: "internal" } } } + context 'with uid mapped from info' do + let(:auth_hash) { { provider: 'developer', uid: 'veryuniqueid', info: { uid: 'internal' } } } - it "returns the correct identity_url" do - expect(subject).to eql("developer:internal") + it 'returns the correct identity_url' do + expect(subject).to eql('developer:internal') end end end diff --git a/spec/services/authorization/enterprise_service_spec.rb b/spec/services/authorization/enterprise_service_spec.rb index 0c07784d6652..04476620ae2e 100644 --- a/spec/services/authorization/enterprise_service_spec.rb +++ b/spec/services/authorization/enterprise_service_spec.rb @@ -26,49 +26,49 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::EnterpriseService do let(:token_object) do token = OpenProject::Token.new - token.subscriber = "Foobar" - token.mail = "foo@example.org" + token.subscriber = 'Foobar' + token.mail = 'foo@example.org' token.starts_at = Date.today token.expires_at = nil token end - let(:token) { double("EnterpriseToken", token_object:) } + let(:token) { double('EnterpriseToken', token_object:) } let(:instance) { described_class.new(token) } let(:result) { instance.call(action) } let(:action) { :an_action } - describe "#initialize" do - it "has the token" do + describe '#initialize' do + it 'has the token' do expect(instance.token).to eql token end end - describe "expiry" do + describe 'expiry' do before do allow(token).to receive(:expired?).and_return(expired) end - context "when expired" do + context 'when expired' do let(:expired) { true } - it "returns a false result" do + it 'returns a false result' do expect(result).to be_a ServiceResult expect(result.result).to be_falsey expect(result.success?).to be_falsey end end - context "when active" do + context 'when active' do let(:expired) { false } - context "invalid action" do - it "returns false" do + context 'invalid action' do + it 'returns false' do expect(result.result).to be_falsey end end @@ -93,7 +93,7 @@ context "guarded action #{guarded_action}" do let(:action) { guarded_action } - it "returns a true result" do + it 'returns a true result' do expect(result).to be_a ServiceResult expect(result.result).to be_truthy expect(result.success?).to be_truthy diff --git a/spec/services/authorization/query_transformation_spec.rb b/spec/services/authorization/query_transformation_spec.rb index b9629c196a4a..d1bb100b8f30 100644 --- a/spec/services/authorization/query_transformation_spec.rb +++ b/spec/services/authorization/query_transformation_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::QueryTransformation do - let(:on) { "on" } - let(:name) { "name" } - let(:after) { "after" } - let(:before) { "before" } + let(:on) { 'on' } + let(:name) { 'name' } + let(:after) { 'after' } + let(:before) { 'before' } let(:block) { ->(*args) { args } } let(:instance) do @@ -43,30 +43,30 @@ block end - context "initialSetup" do - it "sets on" do + context 'initialSetup' do + it 'sets on' do expect(instance.on).to eql on end - it "sets name" do + it 'sets name' do expect(instance.name).to eql name end - it "sets after" do + it 'sets after' do expect(instance.after).to eql after end - it "sets before" do + it 'sets before' do expect(instance.before).to eql before end - it "sets block" do + it 'sets block' do expect(instance.block).to eql block end end - context "apply" do - it "calls the block" do + context 'apply' do + it 'calls the block' do expect(instance.apply(1, 2, 3)).to contain_exactly(1, 2, 3) end end diff --git a/spec/services/authorization/query_transformations_spec.rb b/spec/services/authorization/query_transformations_spec.rb index 02a60e617052..5f4a3baf26c1 100644 --- a/spec/services/authorization/query_transformations_spec.rb +++ b/spec/services/authorization/query_transformations_spec.rb @@ -26,30 +26,30 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::QueryTransformations do let(:instance) { described_class.new } - context "registering a transformation" do + context 'registering a transformation' do before do instance.register(:on, :name) do |*args| args end end - describe "#for?" do - it "is true for the registered name" do + describe '#for?' do + it 'is true for the registered name' do expect(instance.for?(:on)).to be_truthy end - it "is false for another name" do + it 'is false for another name' do expect(instance.for?(:other_name)).to be_falsey end end - describe "#for" do - it "returns an array of transformations for the registered name" do + describe '#for' do + it 'returns an array of transformations for the registered name' do expect(instance.for(:on).length).to be 1 expect(instance.for(:on)[0].on).to be :on @@ -57,40 +57,40 @@ expect(instance.for(:on)[0].block.call(1, 2, 3)).to contain_exactly(1, 2, 3) end - it "is nil for another name" do + it 'is nil for another name' do expect(instance.for(:other_name)).to be_nil end end end - context "registering two transformations depending via after" do + context 'registering two transformations depending via after' do before do instance.register(:on, :transformation1, after: [:transformation2]) do |*args| args end instance.register(:on, :transformation2) do |*args| - args.join(", ") + args.join(', ') end end - describe "#for?" do - it "is true for the registered name" do + describe '#for?' do + it 'is true for the registered name' do expect(instance.for?(:on)).to be_truthy end - it "is false for another name" do + it 'is false for another name' do expect(instance.for?(:other_name)).to be_falsey end end - describe "#for" do - it "returns an array of transformations for the registered name" do + describe '#for' do + it 'returns an array of transformations for the registered name' do expect(instance.for(:on).length).to be 2 expect(instance.for(:on)[0].on).to be :on expect(instance.for(:on)[0].name).to be :transformation2 - expect(instance.for(:on)[0].block.call(1, 2, 3)).to eql "1, 2, 3" + expect(instance.for(:on)[0].block.call(1, 2, 3)).to eql '1, 2, 3' expect(instance.for(:on)[1].on).to be :on expect(instance.for(:on)[1].name).to be :transformation1 @@ -99,34 +99,34 @@ end end - context "registering two transformations depending via before" do + context 'registering two transformations depending via before' do before do instance.register(:on, :transformation1) do |*args| args end instance.register(:on, :transformation2, before: [:transformation1]) do |*args| - args.join(", ") + args.join(', ') end end - describe "#for?" do - it "is true for the registered name" do + describe '#for?' do + it 'is true for the registered name' do expect(instance.for?(:on)).to be_truthy end - it "is false for another name" do + it 'is false for another name' do expect(instance.for?(:other_name)).to be_falsey end end - describe "#for" do - it "returns an array of transformations for the registered name" do + describe '#for' do + it 'returns an array of transformations for the registered name' do expect(instance.for(:on).length).to be 2 expect(instance.for(:on)[0].on).to be :on expect(instance.for(:on)[0].name).to be :transformation2 - expect(instance.for(:on)[0].block.call(1, 2, 3)).to eql "1, 2, 3" + expect(instance.for(:on)[0].block.call(1, 2, 3)).to eql '1, 2, 3' expect(instance.for(:on)[1].on).to be :on expect(instance.for(:on)[1].name).to be :transformation1 @@ -135,8 +135,8 @@ end end - context "registering two mutually dependent transformations" do - it "fails" do + context 'registering two mutually dependent transformations' do + it 'fails' do instance.register(:on, :transformation1, before: [:transformation2]) do |*args| args end @@ -145,7 +145,7 @@ expect do instance.register(:on, :transformation2, before: [:transformation1]) do |*args| - args.join(", ") + args.join(', ') end end.to raise_error "Cannot sort #{expected_order} into the list of transformations" end diff --git a/spec/services/authorization/user_allowed_query_spec.rb b/spec/services/authorization/user_allowed_query_spec.rb index 1dc0cdfb2b74..0237efce4864 100644 --- a/spec/services/authorization/user_allowed_query_spec.rb +++ b/spec/services/authorization/user_allowed_query_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::UserAllowedQuery do - describe ".query" do + describe '.query' do let(:user) { member.principal } let(:anonymous) { build(:anonymous) } let(:project) { build(:project, public: false) } @@ -54,7 +54,7 @@ non_member_role.save! end - it "is an AR relation" do + it 'is an AR relation' do expect(described_class.query(action, project)).to be_a ActiveRecord::Relation end @@ -68,7 +68,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.query(action, project)).to contain_exactly(user) end end @@ -80,7 +80,7 @@ user.update_attribute(:admin, true) end - it "returns the user" do + it 'returns the user' do expect(described_class.query(action, project)).to contain_exactly(user) end end @@ -93,7 +93,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to be_empty end end @@ -106,7 +106,7 @@ role.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.query(action, project)).to be_empty end end @@ -123,7 +123,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to be_empty end end @@ -143,7 +143,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to be_empty end end @@ -161,7 +161,7 @@ project.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.query(action, project)).to contain_exactly(user) end end @@ -179,7 +179,7 @@ project.save! end - it "returns the anonymous user" do + it 'returns the anonymous user' do expect(described_class.query(action, project)).to contain_exactly(anonymous) end end @@ -197,7 +197,7 @@ project.save! end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to be_empty end end @@ -213,7 +213,7 @@ project.save! end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to be_empty end end @@ -234,7 +234,7 @@ non_member.save end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to be_empty end end @@ -247,7 +247,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.query(public_action, project)).to contain_exactly(user) end end @@ -261,7 +261,7 @@ project.save end - it "returns the user and anonymous" do + it 'returns the user and anonymous' do expect(described_class.query(public_action, project)).to contain_exactly(user, anonymous) end end @@ -281,7 +281,7 @@ member.save! end - it "is empty" do + it 'is empty' do expect(described_class.query(permission.name, project)).to eq [] end end @@ -301,7 +301,7 @@ member.save! end - it "returns the user" do + it 'returns the user' do expect(described_class.query(permission.name, project)).to eq [user] end end @@ -317,7 +317,7 @@ project.update(active: false) end - it "is empty" do + it 'is empty' do expect(described_class.query(action, project)).to eq [] end end diff --git a/spec/services/authorization/user_allowed_service_spec.rb b/spec/services/authorization/user_allowed_service_spec.rb index 850b2af7ae5c..4408068ad5dd 100644 --- a/spec/services/authorization/user_allowed_service_spec.rb +++ b/spec/services/authorization/user_allowed_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' # TODO: Fix tests here @@ -34,7 +34,7 @@ let(:user) { build_stubbed(:user) } let(:instance) { described_class.new(user) } let(:action) { :an_action } - let(:action_hash) { { controller: "/controller", action: "action" } } + let(:action_hash) { { controller: '/controller', action: 'action' } } let(:project) { build_stubbed(:project) } let(:other_project) { build_stubbed(:project) } let(:role) { build_stubbed(:project_role) } @@ -51,13 +51,13 @@ subject { instance.call(action, context) } - describe "#initialize" do - it "has the user" do + describe '#initialize' do + it 'has the user' do expect(instance.user).to eql user end end - shared_examples_for "allowed to checked" do + shared_examples_for 'allowed to checked' do before do Array(context).each do |project| project.active = true @@ -69,12 +69,12 @@ allow(role).to receive(:allowed_to?).with(action).and_return(role_grants_action) end - context "with the user having a granting role" do - it "is true" do + context 'with the user having a granting role' do + it 'is true' do expect(subject).to be_truthy end - it "does not call the db twice for a project" do + it 'does not call the db twice for a project' do Array(context).each do |project| allow(Authorization).to receive(:roles).with(user, project).and_return(user_roles_in_project) end @@ -90,21 +90,21 @@ end end - context "but the user not being active" do + context 'but the user not being active' do before do user.lock end - it "returns false", :aggregate_failures do + it 'returns false', :aggregate_failures do expect(instance.call(action, nil, global: true)).not_to be_truthy end end end - context "with the user having a nongranting role" do + context 'with the user having a nongranting role' do let(:role_grants_action) { false } - it "is false" do + it 'is false' do expect(subject).to be_falsey end end @@ -117,12 +117,12 @@ user.admin = true end - it "is true" do + it 'is true' do expect(subject).to be_truthy end end - context "with the project not being active" do + context 'with the project not being active' do before do Array(context).each do |project| project.active = false @@ -130,46 +130,46 @@ end end - it "is false" do + it 'is false' do expect(subject).to be_falsey end - it "is false even if the user is admin" do + it 'is false even if the user is admin' do user.admin = true expect(subject).to be_falsey end end - context "with the project being archived" do + context 'with the project being archived' do before do Array(context).each do |project| project.active = false end end - it "is true" do + it 'is true' do expect(subject).to be_truthy end end - context "with the project not having the action enabled" do + context 'with the project not having the action enabled' do let(:project_allows_to) { false } - it "is false" do + it 'is false' do expect(subject).to be_falsey end - it "is false even if the user is admin" do + it 'is false even if the user is admin' do user.admin = true expect(subject).to be_falsey end end - context "with having precached the results" do + context 'with having precached the results' do before do - auth_cache = double("auth_cache") + auth_cache = double('auth_cache') allow(Users::ProjectAuthorizationCache) .to receive(:new) @@ -194,11 +194,11 @@ instance.preload_projects_allowed_to(action) end - it "is true" do + it 'is true' do expect(subject).to be_truthy end - it "does not call the db" do + it 'does not call the db' do subject expect(Authorization) @@ -207,23 +207,23 @@ end end - describe "#call" do - context "for a project" do + describe '#call' do + context 'for a project' do let(:context) { project } - it_behaves_like "allowed to checked" + it_behaves_like 'allowed to checked' end - context "for an array of projects" do + context 'for an array of projects' do let(:context) { [project, other_project] } - it_behaves_like "allowed to checked" + it_behaves_like 'allowed to checked' - it "is false" do + it 'is false' do expect(instance.call(action, [])).to be_falsey end - context "with one project not allowing an action" do + context 'with one project not allowing an action' do before do allow(project) .to receive(:allows_to?) @@ -231,65 +231,65 @@ .and_return(false) end - it "is false" do + it 'is false' do expect(instance.call(action, [project, other_project])).to be_falsey end end end - context "for a relation of projects" do - let(:context) { double("relation", class: ActiveRecord::Relation, to_a: [project]) } + context 'for a relation of projects' do + let(:context) { double('relation', class: ActiveRecord::Relation, to_a: [project]) } - it_behaves_like "allowed to checked" + it_behaves_like 'allowed to checked' end - context "for anything else" do + context 'for anything else' do let(:context) { nil } - it "is false" do + it 'is false' do expect(subject).to be_falsey end end - context "for a global check" do - context "with the user being admin" do + context 'for a global check' do + context 'with the user being admin' do before do user.admin = true end - it "is true" do + it 'is true' do expect(instance.call(action, nil, global: true)).to be_truthy end end - context "with the user having a granting role" do + context 'with the user having a granting role' do before do allow(Authorization).to receive(:roles).with(user, nil).and_return(user_roles_in_project) allow(role).to receive(:allowed_to?).with(action).and_return(true) end - context "but the user not being active" do + context 'but the user not being active' do before do user.lock end - it "is unsuccessful", :aggregate_failures do + it 'is unsuccessful', :aggregate_failures do expect(instance.call(action, nil, global: true)).not_to be_truthy end end - it "is successful", :aggregate_failures do + it 'is successful', :aggregate_failures do expect(instance.call(action, nil, global: true)).to be_truthy end end - context "with the user not having a granting role" do + context 'with the user not having a granting role' do before do allow(Authorization).to receive(:roles).with(user, nil).and_return(user_roles_in_project) allow(role).to receive(:allowed_to?).with(action).and_return(false) end - it "is false" do + it 'is false' do expect(instance.call(action, nil, global: true)).to be_falsey end end diff --git a/spec/services/authorization/user_entity_roles_query_spec.rb b/spec/services/authorization/user_entity_roles_query_spec.rb index 5247a552ae5b..7d88cac0e17e 100644 --- a/spec/services/authorization/user_entity_roles_query_spec.rb +++ b/spec/services/authorization/user_entity_roles_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::UserEntityRolesQuery do let(:user) { build(:user) } @@ -41,48 +41,48 @@ let(:project_member) { build(:member, project:, roles: [role], principal: user) } let(:other_member) { build(:member, project:, roles: [other_wp_role], principal: user, entity: work_package2) } - describe ".query" do + describe '.query' do before do non_member.save! user.save! end - it "is a relation" do + it 'is a relation' do expect(described_class.query(user, work_package)).to be_a ActiveRecord::Relation end - context "with the user being a member of the work package" do + context 'with the user being a member of the work package' do before do member.save! end - it "returns the work package role" do + it 'returns the work package role' do expect(described_class.query(user, work_package)).to contain_exactly(wp_role) end - context "when the user also has a membership with a different role on another work package" do + context 'when the user also has a membership with a different role on another work package' do before do other_member.save! end - it "does not include the second role" do + it 'does not include the second role' do expect(described_class.query(user, work_package)).not_to include(other_wp_role) end end - context "when the user also has a membership with a different role on the project" do + context 'when the user also has a membership with a different role on the project' do before do project_member.save! end - it "does not include the second role" do + it 'does not include the second role' do expect(described_class.query(user, work_package)).not_to include(role) end end end - context "without the user being member in the work package" do - it "is empty" do + context 'without the user being member in the work package' do + it 'is empty' do expect(described_class.query(user, work_package)).to be_empty end end diff --git a/spec/services/authorization/user_global_roles_query_spec.rb b/spec/services/authorization/user_global_roles_query_spec.rb index b13ffba3ac23..17831ff237a8 100644 --- a/spec/services/authorization/user_global_roles_query_spec.rb +++ b/spec/services/authorization/user_global_roles_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::UserGlobalRolesQuery do let(:user) { build(:user) } @@ -65,79 +65,79 @@ build(:member, entity: work_package, project: work_package.project, roles: [work_package_editor_role], principal: user) end - describe ".query" do + describe '.query' do before do non_member.save! anonymous_role.save! user.save! end - it "is a user relation" do + it 'is a user relation' do expect(described_class.query(user, project)).to be_a ActiveRecord::Relation end - context "with the user being a member in a project" do + context 'with the user being a member in a project' do before do member.save! end - it "is the member and non member role" do + it 'is the member and non member role' do expect(described_class.query(user)).to contain_exactly(role, non_member) end end - context "with the user being a member in two projects" do + context 'with the user being a member in two projects' do before do member.save! member2.save! end - it "is both member and the non member role" do + it 'is both member and the non member role' do expect(described_class.query(user)).to contain_exactly(role, role2, non_member) end end - context "without the user being a member in a project" do - it "is the non member role" do + context 'without the user being a member in a project' do + it 'is the non member role' do expect(described_class.query(user)).to contain_exactly(non_member) end end - context "with the user being anonymous" do - it "is the anonymous role" do + context 'with the user being anonymous' do + it 'is the anonymous role' do expect(described_class.query(anonymous)).to contain_exactly(anonymous_role) end end - context "with the user having a global role" do + context 'with the user having a global role' do before do global_member.save! end - it "is the global role and non member role" do + it 'is the global role and non member role' do expect(described_class.query(user)).to contain_exactly(global_role, non_member) end end - context "with the user having a global role and a member role" do + context 'with the user having a global role and a member role' do before do member.save! global_member.save! end - it "is the global role, member role and non member role" do + it 'is the global role, member role and non member role' do expect(described_class.query(user)).to contain_exactly(global_role, role, non_member) end end - context "with the user having a global role, a member role and a work package role" do + context 'with the user having a global role, a member role and a work package role' do before do member.save! global_member.save! work_package_member.save! end - it "is the global role, member role and non member role" do + it 'is the global role, member role and non member role' do expect(described_class.query(user)).to contain_exactly(global_role, role, non_member) end end diff --git a/spec/services/authorization/user_permissible_service_spec.rb b/spec/services/authorization/user_permissible_service_spec.rb index 5ca25900434c..e270bcc4fd8a 100644 --- a/spec/services/authorization/user_permissible_service_spec.rb +++ b/spec/services/authorization/user_permissible_service_spec.rb @@ -1,4 +1,4 @@ -require "rails_helper" +require 'rails_helper' RSpec.describe Authorization::UserPermissibleService do shared_let(:user) { create(:user) } @@ -15,14 +15,14 @@ # The specs in this file do not cover all the various cases yet. Thus, # we rely on the Authorization.roles scope and the Project/WorkPackage.allowed_to scopes # to be called which is speced precisely. - shared_examples_for "the Authorization.roles scope used" do + shared_examples_for 'the Authorization.roles scope used' do before do allow(Authorization) .to receive(:roles) .and_call_original end - it "calls the Authorization.roles scope once (cached for the second request)" do + it 'calls the Authorization.roles scope once (cached for the second request)' do subject subject @@ -33,14 +33,14 @@ end end - shared_examples_for "the Project.allowed_to scope used" do + shared_examples_for 'the Project.allowed_to scope used' do before do allow(Project) .to receive(:allowed_to) .and_call_original end - it "calls the Project.allowed_to scope" do + it 'calls the Project.allowed_to scope' do subject expect(Project) @@ -52,14 +52,14 @@ end end - shared_examples_for "the WorkPackage.allowed_to scope used" do + shared_examples_for 'the WorkPackage.allowed_to scope used' do before do allow(WorkPackage) .to receive(:allowed_to) .and_call_original end - it "calls the WorkPackage.allowed_to scope" do + it 'calls the WorkPackage.allowed_to scope' do subject expect(WorkPackage) @@ -71,30 +71,30 @@ end end - describe "#allowed_globally?" do - context "when asking for a permission that is not defined" do + describe '#allowed_globally?' do + context 'when asking for a permission that is not defined' do let(:permission) { :not_defined } - it "raises an error" do + it 'raises an error' do expect { subject.allowed_globally?(permission) }.to raise_error(Authorization::UnknownPermissionError) end end - context "when asking for a permission that is defined" do + context 'when asking for a permission that is defined' do let(:permission) { :create_user } - context "and the user is a regular user" do - context "without a role granting the permission" do + context 'and the user is a regular user' do + context 'without a role granting the permission' do it { is_expected.not_to be_allowed_globally(permission) } end - context "with a role granting the permission" do + context 'with a role granting the permission' do let(:global_role) { create(:global_role, permissions: [permission]) } let!(:member) { create(:global_member, user:, roles: [global_role]) } it { is_expected.to be_allowed_globally(permission) } - context "and the account is locked" do + context 'and the account is locked' do before { user.locked! } it { is_expected.not_to be_allowed_globally(permission) } @@ -102,59 +102,59 @@ end end - context "and the user is an admin" do + context 'and the user is an admin' do let(:user) { create(:admin) } it { is_expected.to be_allowed_globally(permission) } - context "and the account is locked" do + context 'and the account is locked' do before { user.locked! } it { is_expected.not_to be_allowed_globally(permission) } end end - it_behaves_like "the Authorization.roles scope used" do + it_behaves_like 'the Authorization.roles scope used' do let(:context) { nil } subject { service.allowed_globally?(permission) } end end end - describe "#allowed_in_project?" do - context "when asking for a permission that is not defined" do + describe '#allowed_in_project?' do + context 'when asking for a permission that is not defined' do let(:permission) { :not_defined } - it "raises an error" do + it 'raises an error' do expect { subject.allowed_in_project?(permission, project) }.to raise_error(Authorization::UnknownPermissionError) end end - context "when asking for a permission that is defined" do + context 'when asking for a permission that is defined' do let(:permission) { :view_work_packages } - it_behaves_like "the Authorization.roles scope used" do + it_behaves_like 'the Authorization.roles scope used' do let(:context) { project } subject { service.allowed_in_project?(permission, project) } end - context "and the user is not a member of any work package or project" do + context 'and the user is not a member of any work package or project' do it { is_expected.not_to be_allowed_in_project(permission, project) } - context "and the project is public" do + context 'and the project is public' do before { project.update(public: true) } - context "when requesting a permission that is not granted to the non-member role" do + context 'when requesting a permission that is not granted to the non-member role' do it { is_expected.not_to be_allowed_in_project(permission, project) } end - context "when requesting a permission that is granted to the non-member role" do + context 'when requesting a permission that is granted to the non-member role' do let(:permission) { :view_news } it { is_expected.to be_allowed_in_project(permission, project) } end - context "when an anonymous user is requesting a permission that is granted to the anonymous role" do + context 'when an anonymous user is requesting a permission that is granted to the anonymous role' do let(:queried_user) { anonymous_user } let(:permission) { :view_meetings } @@ -163,20 +163,20 @@ end end - context "and the user is a member of a project" do + context 'and the user is a member of a project' do let(:role) { create(:project_role, permissions: [permission]) } let!(:project_member) { create(:member, user:, project:, roles: [role]) } it { is_expected.to be_allowed_in_project(permission, project) } - context "with the project being archived" do + context 'with the project being archived' do before { project.update(active: false) } it { is_expected.not_to be_allowed_in_project(permission, project) } end end - context "and the user is a member of a work package" do + context 'and the user is a member of a work package' do let(:role) { create(:work_package_role, permissions: [permission]) } let!(:wp_member) { create(:work_package_member, user:, project:, entity: work_package, roles: [role]) } @@ -185,42 +185,42 @@ end end - describe "#allowed_in_any_project?" do - context "when asking for a permission that is not defined" do + describe '#allowed_in_any_project?' do + context 'when asking for a permission that is not defined' do let(:permission) { :not_defined } - it "raises an error" do + it 'raises an error' do expect { subject.allowed_in_any_project?(permission) }.to raise_error(Authorization::UnknownPermissionError) end end - context "when asking for a permission that is defined" do + context 'when asking for a permission that is defined' do let(:permission) { :view_work_packages } - context "and the user is not a member of any work package or project" do + context 'and the user is not a member of any work package or project' do it { is_expected.not_to be_allowed_in_any_project(permission) } - context "and the project is public" do + context 'and the project is public' do before { project.update_column(:public, true) } - context "and a permission is requested that is not granted to the non-member role" do + context 'and a permission is requested that is not granted to the non-member role' do it { is_expected.not_to be_allowed_in_any_project(permission) } end - context "and a permission is requested that is granted to the non-member role" do + context 'and a permission is requested that is granted to the non-member role' do let(:permission) { :view_news } it { is_expected.to be_allowed_in_any_project(permission) } end - context "and the user is the anonymous user" do + context 'and the user is the anonymous user' do let(:queried_user) { anonymous_user } let(:permission) { :view_meetings } it { is_expected.to be_allowed_in_any_project(permission) } end - context "and the project is archived" do + context 'and the project is archived' do before { project.update_column(:active, false) } it { is_expected.not_to be_allowed_in_any_project(permission) } @@ -228,39 +228,39 @@ end end - context "and the user is a member of a project" do + context 'and the user is a member of a project' do let(:role) { create(:project_role, permissions: [permission]) } let!(:project_member) { create(:member, user:, project:, roles: [role]) } it { is_expected.to be_allowed_in_any_project(permission) } - context "and the project is archived" do + context 'and the project is archived' do before { project.update_column(:active, false) } it { is_expected.not_to be_allowed_in_any_project(permission) } end end - context "and the user is a member of a work package" do + context 'and the user is a member of a work package' do let(:role) { create(:work_package_role, permissions: [permission]) } let!(:wp_member) { create(:work_package_member, user:, project:, entity: work_package, roles: [role]) } it { is_expected.not_to be_allowed_in_any_project(permission) } - context "and the project is public" do + context 'and the project is public' do before { project.update_column(:public, true) } - context "and a permission is requested that is not granted to the non-member role" do + context 'and a permission is requested that is not granted to the non-member role' do it { is_expected.not_to be_allowed_in_any_project(permission) } end - context "and a permission is requested that is granted to the non-member role" do + context 'and a permission is requested that is granted to the non-member role' do let(:permission) { :view_news } it { is_expected.to be_allowed_in_any_project(permission) } end - context "and the project is archived" do + context 'and the project is archived' do before { project.update_column(:active, false) } it { is_expected.not_to be_allowed_in_any_project(permission) } @@ -268,73 +268,73 @@ end end - it_behaves_like "the Project.allowed_to scope used" do + it_behaves_like 'the Project.allowed_to scope used' do subject { service.allowed_in_any_project?(permission) } end end end - describe "#allowed_in_entity?" do - context "when asking for a permission that is not defined" do + describe '#allowed_in_entity?' do + context 'when asking for a permission that is not defined' do let(:permission) { :not_defined } - it "raises an error" do + it 'raises an error' do expect do subject.allowed_in_entity?(permission, work_package, WorkPackage) end.to raise_error(Authorization::UnknownPermissionError) end end - context "when asking for a permission that is defined" do + context 'when asking for a permission that is defined' do let(:permission) { :view_work_packages } - context "and the user is not a member of the project or the work package" do + context 'and the user is not a member of the project or the work package' do it { is_expected.not_to be_allowed_in_entity(permission, work_package, WorkPackage) } end - context "and the user is a member of the project" do + context 'and the user is a member of the project' do let(:role) { create(:project_role, permissions: [permission]) } let!(:project_member) { create(:member, user:, project:, roles: [role]) } it { is_expected.to be_allowed_in_entity(permission, work_package, WorkPackage) } - context "with the project being archived" do + context 'with the project being archived' do before { project.update(active: false) } it { is_expected.not_to be_allowed_in_entity(permission, work_package, WorkPackage) } end - context "without the module enabled in the project" do + context 'without the module enabled in the project' do before { project.enabled_module_names = project.enabled_modules - [:work_package_tracking] } it { is_expected.not_to be_allowed_in_entity(permission, work_package, WorkPackage) } end - it_behaves_like "the Authorization.roles scope used" do + it_behaves_like 'the Authorization.roles scope used' do let(:context) { project } subject { service.allowed_in_entity?(permission, work_package, WorkPackage) } end end - context "and the user is a member of the work package" do + context 'and the user is a member of the work package' do let(:role) { create(:work_package_role, permissions: [permission]) } let!(:wp_member) { create(:work_package_member, user:, project:, entity: work_package, roles: [role]) } it { is_expected.to be_allowed_in_entity(permission, work_package, WorkPackage) } - context "with the project being archived" do + context 'with the project being archived' do before { project.update(active: false) } it { is_expected.not_to be_allowed_in_entity(permission, work_package, WorkPackage) } end - it_behaves_like "the Authorization.roles scope used" do + it_behaves_like 'the Authorization.roles scope used' do let(:context) { work_package } subject { service.allowed_in_entity?(permission, work_package, WorkPackage) } end end - context "and user is member in the project (not granting the permission) and the work package (granting the permission)" do + context 'and user is member in the project (not granting the permission) and the work package (granting the permission)' do let(:permission) { :edit_work_packages } let(:role) { create(:project_role, permissions: [:view_work_packages]) } @@ -345,7 +345,7 @@ it { is_expected.to be_allowed_in_entity(permission, work_package, WorkPackage) } - it_behaves_like "the Authorization.roles scope used" do + it_behaves_like 'the Authorization.roles scope used' do let(:context) { work_package } subject { service.allowed_in_entity?(permission, work_package, WorkPackage) } end @@ -353,51 +353,51 @@ end end - describe "#allowed_in_any_entity?" do - context "when asking for a permission that is not defined" do + describe '#allowed_in_any_entity?' do + context 'when asking for a permission that is not defined' do let(:permission) { :not_defined } - it "raises an error" do + it 'raises an error' do expect { subject.allowed_in_any_entity?(permission, WorkPackage) }.to raise_error(Authorization::UnknownPermissionError) end end - context "when asking for a permission that is defined" do + context 'when asking for a permission that is defined' do let(:permission) { :view_work_packages } - context "and the user is not a member of any work package or project" do + context 'and the user is not a member of any work package or project' do it { is_expected.not_to be_allowed_in_any_entity(permission, WorkPackage) } end - context "and the user is a member of a project" do + context 'and the user is a member of a project' do let(:role) { create(:project_role, permissions: [permission]) } let!(:project_member) { create(:member, user:, project:, roles: [role]) } it { is_expected.to be_allowed_in_any_entity(permission, WorkPackage) } - context "when specifying the same project" do + context 'when specifying the same project' do it { is_expected.to be_allowed_in_any_entity(permission, WorkPackage, in_project: project) } end - context "when specifying a different project" do + context 'when specifying a different project' do let(:other_project) { create(:project) } it { is_expected.not_to be_allowed_in_any_entity(permission, WorkPackage, in_project: other_project) } end end - context "and the user is a member of a work package" do + context 'and the user is a member of a work package' do let(:role) { create(:work_package_role, permissions: [permission]) } let!(:wp_member) { create(:work_package_member, user:, project:, entity: work_package, roles: [role]) } it { is_expected.to be_allowed_in_any_entity(permission, WorkPackage) } end - it_behaves_like "the WorkPackage.allowed_to scope used" do + it_behaves_like 'the WorkPackage.allowed_to scope used' do subject { service.allowed_in_any_entity?(permission, WorkPackage) } end - it_behaves_like "the WorkPackage.allowed_to scope used" do + it_behaves_like 'the WorkPackage.allowed_to scope used' do subject { service.allowed_in_any_entity?(permission, WorkPackage, in_project: project) } end end diff --git a/spec/services/authorization/user_project_roles_query_spec.rb b/spec/services/authorization/user_project_roles_query_spec.rb index 269f6d4b2b61..64ea9c5de6be 100644 --- a/spec/services/authorization/user_project_roles_query_spec.rb +++ b/spec/services/authorization/user_project_roles_query_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization::UserProjectRolesQuery do let(:user) { build(:user) } @@ -44,74 +44,74 @@ let(:member2) { build(:member, project: project2, roles: [role2], principal: user) } let(:wp_member) { build(:member, project:, roles: [wp_role], principal: user, entity: work_package) } - describe ".query" do + describe '.query' do before do non_member.save! anonymous_role.save! user.save! end - it "is a user relation" do + it 'is a user relation' do expect(described_class.query(user, project)).to be_a ActiveRecord::Relation end - context "with the user being a member in the project" do + context 'with the user being a member in the project' do before do member.save! end - it "is the project roles" do + it 'is the project roles' do expect(described_class.query(user, project)).to match [role] end end - context "without the user being member in the project" do - context "with the project being private" do - it "is empty" do + context 'without the user being member in the project' do + context 'with the project being private' do + it 'is empty' do expect(described_class.query(user, project)).to be_empty end end - context "with the project being public" do - it "is the non member role" do + context 'with the project being public' do + it 'is the non member role' do expect(described_class.query(user, public_project)).to contain_exactly(non_member) end end end - context "with the user being anonymous" do - context "with the project being public" do - it "is empty" do + context 'with the user being anonymous' do + context 'with the project being public' do + it 'is empty' do expect(described_class.query(anonymous, public_project)).to contain_exactly(anonymous_role) end end - context "without the project being public" do - it "is empty" do + context 'without the project being public' do + it 'is empty' do expect(described_class.query(anonymous, project)).to be_empty end end end - context "with the user being a member in two projects" do + context 'with the user being a member in two projects' do before do member.save! member2.save! end - it "returns only the roles from the requested project" do + it 'returns only the roles from the requested project' do expect(described_class.query(user, project)).to contain_exactly(role) end end - context "with the user being a member of a work package of the project" do + context 'with the user being a member of a work package of the project' do before { wp_member.save! } - context "and not being a member of the project itself" do + context 'and not being a member of the project itself' do it { expect(described_class.query(user, project)).to be_empty } end - context "and being a member of the project as well" do + context 'and being a member of the project as well' do before { member.save! } it { expect(described_class.query(user, project)).to contain_exactly(role) } diff --git a/spec/services/authorization_spec.rb b/spec/services/authorization_spec.rb index f9c4bd487b7e..c4f493d0a3ac 100644 --- a/spec/services/authorization_spec.rb +++ b/spec/services/authorization_spec.rb @@ -26,76 +26,76 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Authorization do let(:user) { build_stubbed(:user) } let(:action) { :view_work_packages } - describe ".users" do - it "calls Authorization::UserAllowedQuery" do + describe '.users' do + it 'calls Authorization::UserAllowedQuery' do expect(Authorization::UserAllowedQuery).to receive(:query).with(action, user) described_class.users(action, user) end end - describe ".projects" do - it "uses the .allowed_to scope on Project" do + describe '.projects' do + it 'uses the .allowed_to scope on Project' do expect(Project).to receive(:allowed_to).with(user, action) described_class.projects(action, user) end end - describe ".work_packages" do - it "uses the .allowed_to scope on WorkPackage" do + describe '.work_packages' do + it 'uses the .allowed_to scope on WorkPackage' do expect(WorkPackage).to receive(:allowed_to).with(user, action) described_class.work_packages(action, user) end end - describe ".roles" do - context "with a project" do + describe '.roles' do + context 'with a project' do let(:context) { build_stubbed(:project) } - it "calls Authorization::UserProjectRolesQuery" do + it 'calls Authorization::UserProjectRolesQuery' do expect(Authorization::UserProjectRolesQuery).to receive(:query).with(user, context) described_class.roles(user, context) end end - context "with a WorkPackage" do + context 'with a WorkPackage' do let(:context) { build_stubbed(:work_package) } - it "calls Authorization::UserEntityRolesQuery" do + it 'calls Authorization::UserEntityRolesQuery' do expect(Authorization::UserEntityRolesQuery).to receive(:query).with(user, context) described_class.roles(user, context) end end - context "without a context" do + context 'without a context' do let(:context) { nil } - it "calls Authorization::UserGlobalRolesQuery" do + it 'calls Authorization::UserGlobalRolesQuery' do expect(Authorization::UserGlobalRolesQuery).to receive(:query).with(user) described_class.roles(user, context) end end end - describe ".permissions_for" do + describe '.permissions_for' do let(:raise_on_unknown) { false } subject { described_class.permissions_for(action, raise_on_unknown:) } - context "when called with a Permission object" do + context 'when called with a Permission object' do let(:action) { OpenProject::AccessControl.permission(:view_work_packages) } - it "returns the Permission object wrapped in an array" do + it 'returns the Permission object wrapped in an array' do expect(subject).to eq([action]) end end - context "when called with an array of Permission objects" do + context 'when called with an array of Permission objects' do let(:action) do [ OpenProject::AccessControl.permission(:view_work_packages), @@ -103,45 +103,45 @@ ] end - it "returns the Permission array" do + it 'returns the Permission array' do expect(subject).to eq(action) end end - context "when action is a Hash where controller starts with a slash" do + context 'when action is a Hash where controller starts with a slash' do let(:action) do - { controller: "/work_packages", action: "show" } + { controller: '/work_packages', action: 'show' } end - it "returns all permissions that grant the permission to this URL" do + it 'returns all permissions that grant the permission to this URL' do # there might be more permissions granting access to this URL, we check for a known one expect(subject).to include(OpenProject::AccessControl.permission(:view_work_packages)) end end - context "when action is a Hash where controller does not start with a slash" do + context 'when action is a Hash where controller does not start with a slash' do let(:action) do - { controller: "work_packages", action: "show" } + { controller: 'work_packages', action: 'show' } end - it "returns all permissions that grant the permission to this URL" do + it 'returns all permissions that grant the permission to this URL' do # there might be more permissions granting access to this URL, we check for a known one expect(subject).to include(OpenProject::AccessControl.permission(:view_work_packages)) end end - context "when action is a permission name" do + context 'when action is a permission name' do let(:action) { :view_work_packages } - it "returns the Permission object wrapped in an array" do + it 'returns the Permission object wrapped in an array' do expect(subject).to eq([OpenProject::AccessControl.permission(:view_work_packages)]) end end - context "when action is an array of permission names" do + context 'when action is an array of permission names' do let(:action) { %i[view_work_packages edit_work_packages] } - it "returns the Permission object wrapped in an array" do + it 'returns the Permission object wrapped in an array' do expect(subject).to eq([ OpenProject::AccessControl.permission(:view_work_packages), OpenProject::AccessControl.permission(:edit_work_packages) @@ -149,7 +149,7 @@ end end - context "when there is a permission but it is disabled" do + context 'when there is a permission but it is disabled' do let(:permission_object) { OpenProject::AccessControl.permission(:manage_user) } let(:action) { permission_object.name } @@ -162,7 +162,7 @@ OpenProject::AccessControl.clear_caches end - it "returns an empty array and does not warn or raise" do + it 'returns an empty array and does not warn or raise' do expect(Rails.logger).not_to receive(:debug) expect do expect(subject).to be_empty @@ -170,13 +170,13 @@ end end - context "when there is no permission" do + context 'when there is no permission' do let(:action) { :this_permission_does_not_exist } - context "and raise_on_unknown is false" do + context 'and raise_on_unknown is false' do let(:raise_on_unknown) { false } - it "warns and returns an empty array" do + it 'warns and returns an empty array' do allow(Rails.logger).to receive(:debug) expect(subject).to be_empty @@ -187,10 +187,10 @@ end end - context "and raise_on_unknown is true" do + context 'and raise_on_unknown is true' do let(:raise_on_unknown) { true } - it "warns and raises" do + it 'warns and raises' do allow(Rails.logger).to receive(:debug) expect { subject }.to raise_error(Authorization::UnknownPermissionError) @@ -202,7 +202,7 @@ end end - describe ".contextual_permissions" do + describe '.contextual_permissions' do subject { described_class.contextual_permissions(action, context, raise_on_unknown:) } let(:raise_on_unknown) { false } @@ -224,55 +224,55 @@ allow(described_class).to receive(:permissions_for).and_return(returned_permissions) end - context "with global context" do + context 'with global context' do let(:context) { :global } - context "when a global permission is part of the returned permissions" do - it "returns only the global permission" do + context 'when a global permission is part of the returned permissions' do + it 'returns only the global permission' do expect(subject).to eq([global_permission]) end end - context "when no global permission is part of the returned permissions" do + context 'when no global permission is part of the returned permissions' do let(:returned_permissions) { [project_permission, project_and_work_package_permission] } - it "raises an IllegalPermissionContextError" do + it 'raises an IllegalPermissionContextError' do expect { subject }.to raise_error(Authorization::IllegalPermissionContextError) end end end - context "with project context" do + context 'with project context' do let(:context) { :project } - context "when a project permission is part of the returned permissions" do - it "returns only the project permissions" do + context 'when a project permission is part of the returned permissions' do + it 'returns only the project permissions' do expect(subject).to eq([project_permission, project_and_work_package_permission]) end end - context "when no project permission is part of the returned permissions" do + context 'when no project permission is part of the returned permissions' do let(:returned_permissions) { [global_permission] } - it "raises an IllegalPermissionContextError" do + it 'raises an IllegalPermissionContextError' do expect { subject }.to raise_error(Authorization::IllegalPermissionContextError) end end end - context "with work package context" do + context 'with work package context' do let(:context) { :work_package } - context "when a work package permission is part of the returned permissions" do - it "returns only the work package permission" do + context 'when a work package permission is part of the returned permissions' do + it 'returns only the work package permission' do expect(subject).to eq([project_and_work_package_permission]) end end - context "when no work package permission is part of the returned permissions" do + context 'when no work package permission is part of the returned permissions' do let(:returned_permissions) { [global_permission, project_permission] } - it "raises an IllegalPermissionContextError" do + it 'raises an IllegalPermissionContextError' do expect { subject }.to raise_error(Authorization::IllegalPermissionContextError) end end diff --git a/spec/services/backups/create_service_spec.rb b/spec/services/backups/create_service_spec.rb index aff0b6952a33..bd8dc3a64933 100644 --- a/spec/services/backups/create_service_spec.rb +++ b/spec/services/backups/create_service_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Backups::CreateService, type: :model do let(:user) { create(:admin) } let(:service) { described_class.new user:, backup_token: backup_token.plain_value } let(:backup_token) { create(:backup_token, user:) } - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:instance) { service } let(:backup_token) { build_stubbed(:backup_token, user:) } let(:contract_options) { { backup_token: backup_token.plain_value } } diff --git a/spec/services/base/base_callable_spec.rb b/spec/services/base/base_callable_spec.rb index 77e1ce75f881..e2eeb8c3406f 100644 --- a/spec/services/base/base_callable_spec.rb +++ b/spec/services/base/base_callable_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe BaseServices::BaseCallable, type: :model do let(:test_service) do Class.new(BaseServices::BaseCallable) do def perform(*) - state.test = "foo" - ServiceResult.success(result: "something") + state.test = 'foo' + ServiceResult.success(result: 'something') end end end @@ -41,8 +41,8 @@ def perform(*) let(:test_service2) do Class.new(BaseServices::BaseCallable) do def perform(*) - state.test2 = "foo" - ServiceResult.success(result: "something") + state.test2 = 'foo' + ServiceResult.success(result: 'something') end end end @@ -51,22 +51,22 @@ def perform(*) subject { instance.call } - describe "state" do + describe 'state' do let(:result_state) { subject.state } - it "is returned from the call", :aggregate_failures do + it 'is returned from the call', :aggregate_failures do expect(result_state).to be_a(Shared::ServiceState) - expect(result_state.test).to eq "foo" + expect(result_state.test).to eq 'foo' expect(subject).to be_a ServiceResult end - describe "with state already passed into the service" do - let(:instance) { test_service.new.with_state(bar: "some value") } + describe 'with state already passed into the service' do + let(:instance) { test_service.new.with_state(bar: 'some value') } - it "keeps that value", :aggregate_failures do + it 'keeps that value', :aggregate_failures do expect(result_state).to be_a(Shared::ServiceState) - expect(result_state.test).to eq "foo" - expect(result_state.bar).to eq "some value" + expect(result_state.test).to eq 'foo' + expect(result_state.bar).to eq 'some value' end end end diff --git a/spec/services/base_services/behaves_like_create_service.rb b/spec/services/base_services/behaves_like_create_service.rb index 8ac453932734..ce549fe29bad 100644 --- a/spec/services/base_services/behaves_like_create_service.rb +++ b/spec/services/base_services/behaves_like_create_service.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "BaseServices create service" do +RSpec.shared_examples 'BaseServices create service' do let(:service_class) { described_class } let(:namespace) { service_class.to_s.deconstantize } let(:model_class) { namespace.singularize.constantize } @@ -42,12 +42,12 @@ let(:instance) do described_class.new(user:, contract_class:) end - let(:call_attributes) { { name: "Some name", identifier: "Some identifier" } } + let(:call_attributes) { { name: 'Some name', identifier: 'Some identifier' } } let(:set_attributes_success) do true end let(:set_attributes_errors) do - double("set_attributes_errors") + double('set_attributes_errors') end let(:set_attributes_result) do ServiceResult.new result: model_instance, @@ -56,7 +56,7 @@ end let!(:model_instance) { build_stubbed(factory) } let!(:set_attributes_service) do - service = double("set_attributes_service_instance") + service = double('set_attributes_service_instance') allow(set_attributes_class) .to(receive(:new)) @@ -83,47 +83,47 @@ subject { instance.call(call_attributes) } - describe "#user" do - it "exposes a user which is available as a getter" do + describe '#user' do + it 'exposes a user which is available as a getter' do expect(instance.user).to eql user end end - describe "#contract" do - it "uses the CreateContract contract" do + describe '#contract' do + it 'uses the CreateContract contract' do expect(instance.contract_class).to eql contract_class end end - describe "#call" do - context "if contract validates and the model saves" do - it "is successful" do + describe '#call' do + context 'if contract validates and the model saves' do + it 'is successful' do expect(subject).to be_success end - it "matches the set attributes errors" do + it 'matches the set attributes errors' do expect(subject.errors).to eq(set_attributes_errors) end - it "returns the model as a result" do + it 'returns the model as a result' do result = subject.result expect(result).to be_a model_class end end - context "if contract does not validate" do + context 'if contract does not validate' do let(:set_attributes_success) { false } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).not_to be_success end end - context "if model does not save" do + context 'if model does not save' do let(:model_save_result) { false } - let(:errors) { double("errors") } + let(:errors) { double('errors') } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).not_to be_success end diff --git a/spec/services/base_services/behaves_like_delete_service.rb b/spec/services/base_services/behaves_like_delete_service.rb index 80bdee19ff5c..af603f6baf5e 100644 --- a/spec/services/base_services/behaves_like_delete_service.rb +++ b/spec/services/base_services/behaves_like_delete_service.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "BaseServices delete service" do +RSpec.shared_examples 'BaseServices delete service' do subject(:service_call) { instance.call(call_attributes) } let(:service_class) { described_class } @@ -66,48 +66,48 @@ allow(model_instance).to receive(:destroy).and_return(model_destroy_result) end - describe "#contract" do - it "uses the DestroyContract contract" do + describe '#contract' do + it 'uses the DestroyContract contract' do expect(instance.contract_class).to eql contract_class end end - describe "#call" do - context "when contract validates and the model is destroyed successfully" do - it "is successful" do + describe '#call' do + context 'when contract validates and the model is destroyed successfully' do + it 'is successful' do expect(subject).to be_success end - it "returns the destroyed model as a result" do + it 'returns the destroyed model as a result' do result = subject.result expect(result).to eql model_instance end end - context "when contract does not validate" do + context 'when contract does not validate' do let(:contract_validate_result) { false } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).to be_failure end - it "returns the contract errors" do + it 'returns the contract errors' do expect(subject.errors) .to eql contract_errors end end - context "when model cannot be destroyed" do + context 'when model cannot be destroyed' do let(:model_destroy_result) { false } let(:model_errors) { ActiveModel::Errors.new(model_instance) } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject) .to be_failure end it "returns the user's errors" do - model_errors.add :base, "This is some error." + model_errors.add :base, 'This is some error.' allow(model_instance) .to(receive(:errors)) diff --git a/spec/services/base_services/behaves_like_update_service.rb b/spec/services/base_services/behaves_like_update_service.rb index 7682da76eee1..032aa729d791 100644 --- a/spec/services/base_services/behaves_like_update_service.rb +++ b/spec/services/base_services/behaves_like_update_service.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "BaseServices update service" do +RSpec.shared_examples 'BaseServices update service' do let(:service_class) { described_class } let(:namespace) { service_class.to_s.deconstantize } let(:model_class) { namespace.singularize.constantize } @@ -39,19 +39,19 @@ let(:user) { build_stubbed(:user) } let(:contract_class) do - double("contract_class", "<=": true) + double('contract_class', '<=': true) end let(:instance) do described_class.new(user:, model: model_instance, contract_class:) end - let(:call_attributes) { { some: "hash" } } + let(:call_attributes) { { some: 'hash' } } let(:set_attributes_success) do true end let(:set_attributes_errors) do - double("set_attributes_errors") + double('set_attributes_errors') end let(:set_attributes_result) do ServiceResult.new result: model_instance, @@ -60,7 +60,7 @@ end let!(:model_instance) { build_stubbed(factory) } let!(:set_attributes_service) do - service = double("set_attributes_service_instance") + service = double('set_attributes_service_instance') allow(set_attributes_class) .to receive(:new) @@ -83,31 +83,31 @@ subject(:instance_call) { instance.call(call_attributes) } - describe "#user" do - it "exposes a user which is available as a getter" do + describe '#user' do + it 'exposes a user which is available as a getter' do expect(instance.user).to eql user end end - describe "#contract" do - it "uses the UpdateContract contract" do + describe '#contract' do + it 'uses the UpdateContract contract' do expect(instance.contract_class).to eql contract_class end end describe "#call" do - context "when the model instance is valid" do - it "is a successful call", :aggregate_failures do + context 'when the model instance is valid' do + it 'is a successful call', :aggregate_failures do expect(subject).to be_success expect(subject).to eql set_attributes_result expect(subject.result).to eql model_instance end end - context "if the SetAttributeService is unsuccessful" do + context 'if the SetAttributeService is unsuccessful' do let(:set_attributes_success) { false } - it "is unsuccessful", :aggregate_failures do + it 'is unsuccessful', :aggregate_failures do expect(model_instance).not_to receive(:save) expect(subject).to be_failure @@ -119,10 +119,10 @@ end end - context "when the model instance is invalid" do + context 'when the model instance is invalid' do let(:model_save_result) { false } - it "is unsuccessful and returns the errors", :aggregate_failures do + it 'is unsuccessful and returns the errors', :aggregate_failures do expect(subject).to be_failure expect(subject.errors).to eql model_instance.errors end diff --git a/spec/services/create_type_service_spec.rb b/spec/services/create_type_service_spec.rb index b5e1c774c1e4..58511dbfa858 100644 --- a/spec/services/create_type_service_spec.rb +++ b/spec/services/create_type_service_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/shared_type_service" +require 'spec_helper' +require 'services/shared_type_service' RSpec.describe CreateTypeService do let(:type) { instance.type } let(:user) { build_stubbed(:admin) } let(:instance) { described_class.new(user) } - let(:service_call) { instance.call({ name: "foo" }.merge(params), {}) } + let(:service_call) { instance.call({ name: 'foo' }.merge(params), {}) } - it_behaves_like "type service" + it_behaves_like 'type service' end diff --git a/spec/services/custom_actions/update_service_spec.rb b/spec/services/custom_actions/update_service_spec.rb index d64c4f1653c7..29b135972ca9 100644 --- a/spec/services/custom_actions/update_service_spec.rb +++ b/spec/services/custom_actions/update_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomActions::UpdateService do let(:action) do @@ -41,13 +41,13 @@ let(:user) { build_stubbed(:user) } let(:save_success) { true } let(:contract_success) { true } - let(:contract_errors) { double("contract errors") } + let(:contract_errors) { double('contract errors') } let(:instance) do contract described_class.new(action:, user:) end let(:contract) do - contract_instance = double("contract instance") + contract_instance = double('contract instance') allow(CustomActions::CuContract) .to receive(:new) @@ -64,18 +64,18 @@ contract_instance end - describe "#call" do - it "is successful" do + describe '#call' do + it 'is successful' do expect(instance.call(attributes: {})) .to be_success end - it "is has the action in the result" do + it 'is has the action in the result' do expect(instance.call(attributes: {}).result) .to eql action end - it "yields the result" do + it 'yields the result' do yielded = false proc = Proc.new do |call| @@ -88,10 +88,10 @@ .to be_success end - context "unsuccessful saving" do + context 'unsuccessful saving' do let(:save_success) { false } - it "yields the result" do + it 'yields the result' do yielded = false proc = Proc.new do |call| @@ -105,10 +105,10 @@ end end - context "unsuccessful contract" do + context 'unsuccessful contract' do let(:contract_success) { false } - it "yields the result" do + it 'yields the result' do yielded = false proc = Proc.new do |call| @@ -122,17 +122,17 @@ end end - it "sets the name of the action" do - expect(instance.call(attributes: { name: "new name" }).result.name) - .to eql "new name" + it 'sets the name of the action' do + expect(instance.call(attributes: { name: 'new name' }).result.name) + .to eql 'new name' end - it "updates the actions" do - action.actions = [CustomActions::Actions::AssignedTo.new("1"), - CustomActions::Actions::Status.new("3")] + it 'updates the actions' do + action.actions = [CustomActions::Actions::AssignedTo.new('1'), + CustomActions::Actions::Status.new('3')] new_actions = instance - .call(attributes: { actions: { assigned_to: ["2"], priority: ["3"] } }) + .call(attributes: { actions: { assigned_to: ['2'], priority: ['3'] } }) .result .actions .map { |a| [a.key, a.values] } @@ -141,18 +141,18 @@ .to contain_exactly([:assigned_to, [2]], [:priority, [3]]) end - it "handles unknown actions" do + it 'handles unknown actions' do new_actions = instance - .call(attributes: { actions: { some_bogus_name: ["3"] } }) + .call(attributes: { actions: { some_bogus_name: ['3'] } }) .result .actions .map { |a| [a.key, a.values] } expect(new_actions) - .to contain_exactly([:inexistent, ["3"]]) + .to contain_exactly([:inexistent, ['3']]) end - it "updates the conditions" do + it 'updates the conditions' do old_status = create(:status) new_status = create(:status) @@ -168,9 +168,9 @@ .to contain_exactly([:status, [new_status.id]]) end - it "handles unknown conditions" do + it 'handles unknown conditions' do new_conditions = instance - .call(attributes: { conditions: { some_bogus_name: ["3"] } }) + .call(attributes: { conditions: { some_bogus_name: ['3'] } }) .result .conditions .map { |a| [a.key, a.values] } diff --git a/spec/services/custom_actions/update_work_package_service_spec.rb b/spec/services/custom_actions/update_work_package_service_spec.rb index 3612e278befa..5a6b11a528a9 100644 --- a/spec/services/custom_actions/update_work_package_service_spec.rb +++ b/spec/services/custom_actions/update_work_package_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomActions::UpdateWorkPackageService do let(:custom_action) do @@ -39,18 +39,18 @@ action end let(:alter_action1) do - action = double("custom actions action 1", key: "abc", priority: 100) + action = double('custom actions action 1', key: 'abc', priority: 100) allow(action) .to receive(:apply) .with(work_package) do - work_package.subject = "" + work_package.subject = '' end action end let(:alter_action2) do - action = double("custom actions action 2", key: "def", priority: 10) + action = double('custom actions action 2', key: 'def', priority: 10) allow(action) .to receive(:apply) @@ -88,7 +88,7 @@ end let(:validation_result) { true } let!(:contract) do - contract = double("contract") + contract = double('contract') allow(WorkPackages::UpdateContract) .to receive(:new) @@ -102,18 +102,18 @@ contract end - describe "#call" do + describe '#call' do let(:call) do instance.call(work_package:) end let(:subject) { call } - it "returns the update wp service result" do + it 'returns the update wp service result' do expect(call) .to eql result end - it "yields the result" do + it 'yields the result' do yielded = false proc = Proc.new do |call| @@ -126,7 +126,7 @@ .to be_success end - it "calls each registered action with the work package" do + it 'calls each registered action with the work package' do [alter_action1, alter_action2].each do |alter_action| expect(alter_action) .to receive(:apply) @@ -136,7 +136,7 @@ call end - it "calls the registered actions based on their priority" do + it 'calls the registered actions based on their priority' do call_order = [] [alter_action1, alter_action2].each do |alter_action| @@ -153,7 +153,7 @@ .to eql [alter_action2, alter_action1] end - context "on validation error" do + context 'on validation error' do before do allow(contract) .to receive(:validate) do @@ -174,7 +174,7 @@ # check that the work package retains only the valid changes # when passing it to the update service expect(work_package.subject) - .not_to eql "" + .not_to eql '' expect(work_package.status_id) .to be 100 @@ -186,13 +186,13 @@ end end - it "is successful" do + it 'is successful' do expect(subject) .to be_success end end - context "on unfixable validation error" do + context 'on unfixable validation error' do let(:result) do ServiceResult.failure(result: work_package) end @@ -227,7 +227,7 @@ subject end - it "is failure" do + it 'is failure' do expect(subject) .to be_failure end diff --git a/spec/services/custom_fields/create_service_spec.rb b/spec/services/custom_fields/create_service_spec.rb index 8f7aca6d2309..a169bc39205a 100644 --- a/spec/services/custom_fields/create_service_spec.rb +++ b/spec/services/custom_fields/create_service_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe CustomFields::CreateService, type: :model do - it_behaves_like "BaseServices create service" do - context "when creating a project cf", + it_behaves_like 'BaseServices create service' do + context 'when creating a project cf', with_ee: %i[custom_fields_in_projects_list] do let(:model_instance) { build_stubbed(:project_custom_field) } - it "modifies the settings on successful call" do + it 'modifies the settings on successful call' do subject expect(Setting.enabled_projects_columns).to include(model_instance.column_name) end diff --git a/spec/services/custom_fields/set_attributes_service_spec.rb b/spec/services/custom_fields/set_attributes_service_spec.rb index b4125b172916..79a297bd346b 100644 --- a/spec/services/custom_fields/set_attributes_service_spec.rb +++ b/spec/services/custom_fields/set_attributes_service_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CustomFields::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } let(:contract_instance) do - contract = double("contract_instance") + contract = double('contract_instance') allow(contract) .to receive(:validate) .and_return(contract_valid) @@ -41,7 +41,7 @@ contract end - let(:contract_errors) { double("contract_errors") } + let(:contract_errors) { double('contract_errors') } let(:contract_valid) { true } let(:cf_valid) { true } @@ -71,30 +71,30 @@ subject { instance.call(params) } - it "returns the cf instance as the result" do + it 'returns the cf instance as the result' do expect(subject.result) .to eql cf_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with params" do + context 'with params' do let(:params) do { - name: "Foobar" + name: 'Foobar' } end let(:expected) do { - name: "Foobar" + name: 'Foobar' }.with_indifferent_access end - it "assigns the params" do + it 'assigns the params' do subject attributes_of_interest = cf_instance @@ -106,14 +106,14 @@ end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } let(:expect_time_instance_save) do expect(cf_instance) .not_to receive(:save) end - it "returns failure" do + it 'returns failure' do expect(subject) .not_to be_success end diff --git a/spec/services/custom_fields/update_service_spec.rb b/spec/services/custom_fields/update_service_spec.rb index 43108ef84f7b..7c20286549a9 100644 --- a/spec/services/custom_fields/update_service_spec.rb +++ b/spec/services/custom_fields/update_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe CustomFields::UpdateService, type: :model do - it_behaves_like "BaseServices update service" + it_behaves_like 'BaseServices update service' end diff --git a/spec/services/groups/add_users_service_integration_spec.rb b/spec/services/groups/add_users_service_integration_spec.rb index c247a2749523..20aced011f58 100644 --- a/spec/services/groups/add_users_service_integration_spec.rb +++ b/spec/services/groups/add_users_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Groups::AddUsersService, "integration" do +RSpec.describe Groups::AddUsersService, 'integration' do subject(:service_call) { instance.call(ids: user_ids, message:) } let(:projects) { create_list(:project, 2) } @@ -42,7 +42,7 @@ let(:user1) { create(:user) } let(:user2) { create(:user) } let(:user_ids) { [user1.id, user2.id] } - let(:message) { "Some message" } + let(:message) { 'Some message' } let(:instance) do described_class.new(group, current_user:) @@ -53,8 +53,8 @@ .to receive(:perform_later) end - shared_examples_for "adds the users to the group and project" do - it "adds the users to the group and project" do + shared_examples_for 'adds the users to the group and project' do + it 'adds the users to the group and project' do expect(service_call).to be_success expect(group.users) @@ -66,8 +66,8 @@ end end - shared_examples_for "sends notification" do - it "on the updated membership" do + shared_examples_for 'sends notification' do + it 'on the updated membership' do service_call ids = defined?(members) ? members : Member.where(principal: user).pluck(:id) @@ -81,30 +81,30 @@ end end - context "when an admin user" do + context 'when an admin user' do let(:current_user) { admin } - it_behaves_like "adds the users to the group and project" + it_behaves_like 'adds the users to the group and project' - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end - context "when the group is invalid (e.g. required cf not set)" do + context 'when the group is invalid (e.g. required cf not set)' do before do group # The group is now invalid as it has no cv for this field - create(:custom_field, type: "GroupCustomField", is_required: true, field_format: "int") + create(:custom_field, type: 'GroupCustomField', is_required: true, field_format: 'int') end - it_behaves_like "adds the users to the group and project" + it_behaves_like 'adds the users to the group and project' - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end end - context "when the user was already a member in a project with the same role" do + context 'when the user was already a member in a project with the same role' do let(:previous_project) { projects.first } let!(:user_member) do create(:member, @@ -113,9 +113,9 @@ principal: user1) end - it_behaves_like "adds the users to the group and project" + it_behaves_like 'adds the users to the group and project' - it "does not update the timestamps on the preexisting membership" do + it 'does not update the timestamps on the preexisting membership' do # Need to reload so that the timestamps are set by the database user_member.reload @@ -125,14 +125,14 @@ .to eql(user_member.updated_at) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:members) do Member.where(user_id: user_ids).where.not(id: user_member).pluck(:id) end end end - context "when the user was already a member in a project with only one role the group adds" do + context 'when the user was already a member in a project with only one role the group adds' do let(:project) { create(:project) } let(:roles) { create_list(:project_role, 2) } let!(:group) do @@ -142,7 +142,7 @@ create(:member, project:, roles: [roles.first], principal: user1) end - it "adds the users to the group and project" do + it 'adds the users to the group and project' do expect(service_call).to be_success expect(group.users) @@ -153,19 +153,19 @@ expect(user2.memberships.map(&:roles).flatten).to match_array roles end - it "updates the timestamps on the preexisting membership" do + it 'updates the timestamps on the preexisting membership' do service_call expect(Member.find(user_member.id).updated_at) .not_to eql(user_member.updated_at) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end end - context "when the user was already a member in a project with a different role" do + context 'when the user was already a member in a project with a different role' do let(:other_role) { create(:project_role) } let(:previous_project) { projects.first } let!(:user_member) do @@ -175,7 +175,7 @@ principal: user1) end - it "adds the users to the group and project" do + it 'adds the users to the group and project' do expect(service_call).to be_success expect(group.users) @@ -188,25 +188,25 @@ expect(user2.memberships.map(&:roles).flatten).to contain_exactly(role, role) end - it "updates the timestamps on the preexisting membership" do + it 'updates the timestamps on the preexisting membership' do service_call expect(Member.find(user_member.id).updated_at) .not_to eql(user_member.updated_at) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end end - context "with global role" do + context 'with global role' do let(:role) { create(:global_role, permissions: [:add_project]) } let!(:group) do create(:group, global_roles: [role]) end - it "adds the users to the group and their membership to the global role" do + it 'adds the users to the group and their membership to the global role' do expect(service_call).to be_success expect(group.users).to contain_exactly(user1, user2) @@ -216,7 +216,7 @@ expect(user2.memberships.flat_map(&:roles)).to contain_exactly(role) end - context "when one user already has a global role that the group would add" do + context 'when one user already has a global role that the group would add' do let(:global_roles) { create_list(:global_role, 2) } let!(:group) do create(:group, global_roles:) @@ -225,7 +225,7 @@ create(:member, project: nil, roles: [global_roles.first], principal: user1) end - it "adds their membership to the global role" do + it 'adds their membership to the global role' do expect(service_call).to be_success expect(user1.memberships.where(project_id: nil).flat_map(&:roles)).to match_array global_roles @@ -235,10 +235,10 @@ end end - context "when not allowed" do + context 'when not allowed' do let(:current_user) { User.anonymous } - it "fails the request" do + it 'fails the request' do expect(service_call).to be_failure expect(service_call.message).to match /may not be accessed/ end diff --git a/spec/services/groups/cleanup_inherited_roles_service_integration_spec.rb b/spec/services/groups/cleanup_inherited_roles_service_integration_spec.rb index db8b7799dfd5..d11c9d1c81af 100644 --- a/spec/services/groups/cleanup_inherited_roles_service_integration_spec.rb +++ b/spec/services/groups/cleanup_inherited_roles_service_integration_spec.rb @@ -28,9 +28,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Groups::CleanupInheritedRolesService, "integration", type: :model do +RSpec.describe Groups::CleanupInheritedRolesService, 'integration', type: :model do subject(:service_call) do members.destroy_all instance.call(params) @@ -76,20 +76,20 @@ .to receive(:send) end - context "when having only the group provided roles" do - it "is successful" do + context 'when having only the group provided roles' do + it 'is successful' do expect(service_call) .to be_success end - it "removes all memberships the users have had by the group" do + it 'removes all memberships the users have had by the group' do service_call expect(Member.where(principal: users)) .to be_empty end - it "sends a notification for the destroyed members" do + it 'sends a notification for the destroyed members' do user_members = Member.where(principal: users).to_a service_call @@ -101,7 +101,7 @@ end end - it "sends no notifications" do + it 'sends no notifications' do service_call expect(Notifications::GroupMemberAlteredJob) @@ -109,7 +109,7 @@ end end - context "when also having own roles" do + context 'when also having own roles' do shared_let(:another_role) { create(:project_role) } shared_let(:another_work_package_role) { create(:comment_work_package_role) } shared_let(:another_global_role) { create(:global_role) } @@ -121,19 +121,19 @@ end end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "removes all memberships that users have had only by the group" do + it 'removes all memberships that users have had only by the group' do service_call expect(Member.where(principal: users.last)) .to be_empty end - it "keeps the memberships where group independent roles were assigned" do + it 'keeps the memberships where group independent roles were assigned' do service_call expect(first_user_member.updated_at) @@ -143,7 +143,7 @@ .to contain_exactly(another_role, another_work_package_role, another_global_role) end - it "sends a notification on the kept membership" do + it 'sends a notification on the kept membership' do service_call expect(Notifications::GroupMemberAlteredJob) @@ -155,7 +155,7 @@ end end - context "when the user has had the roles added by the group before" do + context 'when the user has had the roles added by the group before' do let!(:first_user_member) do Member.find_by(principal: users.first).tap do |m| m.member_roles.create(role:) @@ -164,19 +164,19 @@ end end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "removes all memberships the users have had only by the group" do + it 'removes all memberships the users have had only by the group' do service_call expect(Member.where(principal: users.last)) .to be_empty end - it "keeps the memberships where group independent roles were assigned" do + it 'keeps the memberships where group independent roles were assigned' do service_call expect(first_user_member.updated_at) @@ -186,7 +186,7 @@ .to contain_exactly(role, work_package_role, global_role) end - it "sends a notification on the kept membership" do + it 'sends a notification on the kept membership' do service_call expect(Notifications::GroupMemberAlteredJob) @@ -198,7 +198,7 @@ end end - context "when specifying the member_roles to be removed (e.g. when removing a user from a group)" do + context 'when specifying the member_roles to be removed (e.g. when removing a user from a group)' do let(:member_role_ids) do MemberRole .where(member_id: Member.where(principal: users.first)) @@ -206,26 +206,26 @@ end let(:params) { { member_role_ids: } } - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "removes memberships associated to the member roles" do + it 'removes memberships associated to the member roles' do service_call expect(Member.where(principal: users.first)) .to be_empty end - it "keeps the memberships not associated to the member roles" do + it 'keeps the memberships not associated to the member roles' do service_call expect(Member.find_by(principal: users.last).roles) .to contain_exactly(role) end - it "sends no notifications" do + it 'sends no notifications' do service_call expect(Notifications::GroupMemberAlteredJob) @@ -233,10 +233,10 @@ end end - context "when not allowed" do + context 'when not allowed' do let(:current_user) { User.anonymous } - it "fails the request" do + it 'fails the request' do expect(subject).to be_failure expect(subject.message).to match /may not be accessed/ end diff --git a/spec/services/groups/create_inherited_roles_service_integration_spec.rb b/spec/services/groups/create_inherited_roles_service_integration_spec.rb index 8885069a6f5b..a29477a6a295 100644 --- a/spec/services/groups/create_inherited_roles_service_integration_spec.rb +++ b/spec/services/groups/create_inherited_roles_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Groups::CreateInheritedRolesService, "integration" do +RSpec.describe Groups::CreateInheritedRolesService, 'integration' do # The setup for these specs are a bit weird. First, the group is set up with its users already # attached. Then, the memberships of the group are added afterwards. # That way, the inherited roles are not yet created which they would otherwise by the group factory. @@ -69,7 +69,7 @@ let(:user_ids) { group_users.map(&:id) } let(:project_ids) { group_projects.map(&:id) } - let(:message) { "Some message" } + let(:message) { 'Some message' } let(:current_user) { admin } let(:instance) do @@ -81,8 +81,8 @@ .to receive(:perform_later) end - shared_examples_for "inherits the roles of the group to the users" do - it "inherits the roles of the group to the users" do + shared_examples_for 'inherits the roles of the group to the users' do + it 'inherits the roles of the group to the users' do expect(service_call).to be_success user_ids.each do |user_id| @@ -94,8 +94,8 @@ end end - shared_examples_for "sends notification" do - it "on the updated membership" do + shared_examples_for 'sends notification' do + it 'on the updated membership' do service_call ids = defined?(members) ? members : Member.where(principal: user).pluck(:id) @@ -109,27 +109,27 @@ end end - it_behaves_like "inherits the roles of the group to the users" + it_behaves_like 'inherits the roles of the group to the users' - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end - context "when the group is invalid (e.g. required cf not set)" do + context 'when the group is invalid (e.g. required cf not set)' do before do group # The group is now invalid as it has no cv for this field - create(:custom_field, type: "GroupCustomField", is_required: true, field_format: "int") + create(:custom_field, type: 'GroupCustomField', is_required: true, field_format: 'int') end - it_behaves_like "inherits the roles of the group to the users" + it_behaves_like 'inherits the roles of the group to the users' - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end end - context "when the user was already a member in a project with the same role" do + context 'when the user was already a member in a project with the same role' do let(:previous_project) { group_projects.first } let!(:user_member) do create(:member, @@ -138,9 +138,9 @@ principal: user1) end - it_behaves_like "inherits the roles of the group to the users" + it_behaves_like 'inherits the roles of the group to the users' - it "does not update the timestamps on the preexisting membership" do + it 'does not update the timestamps on the preexisting membership' do # Need to reload so that the timestamps are set by the database user_member.reload @@ -150,7 +150,7 @@ .to eql(user_member.updated_at) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do # But only to the user that wasn't a member yet. let(:members) do Member.where(user_id: user_ids).where.not(id: user_member).pluck(:id) @@ -158,7 +158,7 @@ end end - context "when the user was already a member in a project with only one role the group adds" do + context 'when the user was already a member in a project with only one role the group adds' do let(:group_roles) { create_list(:project_role, 2) } let!(:user_member) do create(:member, @@ -167,21 +167,21 @@ principal: user1) end - it_behaves_like "inherits the roles of the group to the users" + it_behaves_like 'inherits the roles of the group to the users' - it "updates the timestamps on the preexisting membership" do + it 'updates the timestamps on the preexisting membership' do service_call expect(Member.find(user_member.id).updated_at) .not_to eql(user_member.updated_at) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end end - context "when a user was already a member in a project with a different role" do + context 'when a user was already a member in a project with a different role' do let(:other_role) { create(:project_role) } let(:previous_project) { group_projects.first } let!(:user_member) do @@ -191,7 +191,7 @@ principal: user1) end - it "inherits the roles of the group to the users" do + it 'inherits the roles of the group to the users' do expect(service_call).to be_success user_ids.each do |user_id| @@ -207,25 +207,25 @@ .to match_array group_projects.count.times.map { group_roles }.flatten end - it "updates the timestamps on the preexisting membership" do + it 'updates the timestamps on the preexisting membership' do service_call expect(Member.find(user_member.id).updated_at) .not_to eql(user_member.updated_at) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { user_ids } end end - context "with global role" do + context 'with global role' do let(:group_roles) { [create(:global_role)] } let(:group_projects) { [] } let(:project_ids) { nil } let!(:group_member) { create(:global_member, principal: group, roles: group_roles) } - it "inherits the roles of the group to the users" do + it 'inherits the roles of the group to the users' do expect(service_call).to be_success expect(user1.memberships.where(project_id: nil).count).to eq 1 @@ -235,7 +235,7 @@ end end - context "with limiting the user and project to create the roles in" do + context 'with limiting the user and project to create the roles in' do let(:added_project) { group_projects.first } let(:ignored_project) { group_projects.last } let(:added_user) { user_ids.first } @@ -243,7 +243,7 @@ subject(:service_call) { instance.call(user_ids: [added_user], message:, project_ids: added_project.id) } - it "adds the roles to users of the group for the project specified", :aggregate_failure do + it 'adds the roles to users of the group for the project specified', :aggregate_failure do expect(service_call).to be_success # Adds the role for the user and project specified @@ -261,23 +261,23 @@ end end - context "with a role that was granted to a specific entity" do + context 'with a role that was granted to a specific entity' do let(:project_ids) { nil } let(:group_projects) { [] } let(:work_package) { create(:work_package, project: project1) } let!(:group_membership) { create(:member, principal: group, project: project1, entity: work_package, roles: [role1]) } - it "inherits the roles of the group to the users also bound to the entity" do + it 'inherits the roles of the group to the users also bound to the entity' do expect do expect(service_call).to be_success end.to change(Member.where(project_id: work_package.project_id, entity: work_package), :count).by(user_ids.count) end end - context "when not an admin" do + context 'when not an admin' do let(:current_user) { User.anonymous } - it "fails the request" do + it 'fails the request' do expect(service_call).to be_failure expect(service_call.message).to match /may not be accessed/ end diff --git a/spec/services/groups/set_attributes_service_spec.rb b/spec/services/groups/set_attributes_service_spec.rb index d75bd47526b4..e7964b576da5 100644 --- a/spec/services/groups/set_attributes_service_spec.rb +++ b/spec/services/groups/set_attributes_service_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Groups::SetAttributesService, type: :model do subject(:service_call) { instance.call(call_attributes) } let(:user) { build_stubbed(:user) } let(:contract_class) do - contract = double("contract_class") + contract = double('contract_class') allow(contract) .to receive(:new) @@ -64,10 +64,10 @@ end end - describe "call" do + describe 'call' do let(:call_attributes) do { - name: "The name" + name: 'The name' } end @@ -81,29 +81,29 @@ .and_return(contract_valid) end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "sets the attributes" do + it 'sets the attributes' do service_call expect(group.lastname) .to eql call_attributes[:name] end - it "does not persist the group" do + it 'does not persist the group' do service_call expect(group) .not_to have_received(:save) end - context "with no changes to the users" do + context 'with no changes to the users' do let(:call_attributes) do { - name: "My new group name" + name: 'My new group name' } end let(:first_user) { build_stubbed(:user) } @@ -119,8 +119,8 @@ service_call.result end - it "does not change the users (Regression #38017)" do - expect(updated_group.name).to eq "My new group name" + it 'does not change the users (Regression #38017)' do + expect(updated_group.name).to eq 'My new group name' expect(updated_group.group_users.map(&:user_id)) .to eql [first_user.id, second_user.id] @@ -128,7 +128,7 @@ end end - context "with changes to the users do" do + context 'with changes to the users do' do let(:first_user) { build_stubbed(:user) } let(:second_user) { build_stubbed(:user) } let(:third_user) { build_stubbed(:user) } @@ -139,7 +139,7 @@ } end - shared_examples_for "updates the users" do + shared_examples_for 'updates the users' do let(:first_group_user) { build_stubbed(:group_user, user: first_user) } let(:second_group_user) { build_stubbed(:group_user, user: second_user) } @@ -147,58 +147,58 @@ build_stubbed(:group, group_users: [first_group_user, second_group_user]) end - it "adds the new users" do + it 'adds the new users' do expect(service_call.result.group_users.map(&:user_id)) .to eql [first_user.id, second_user.id, third_user.id] end - it "does not persist the new association" do + it 'does not persist the new association' do expect(service_call.result.group_users.find { |gu| gu.user_id == third_user.id }) .to be_new_record end - it "keeps the association already existing before" do + it 'keeps the association already existing before' do expect(service_call.result.group_users.find { |gu| gu.user_id == second_user.id }) .not_to be_marked_for_destruction end - it "marks not mentioned users to be removed" do + it 'marks not mentioned users to be removed' do expect(service_call.result.group_users.find { |gu| gu.user_id == first_user.id }) .to be_marked_for_destruction end end - context "with a persisted record and integer values" do + context 'with a persisted record and integer values' do let(:call_attributes) do { user_ids: [second_user.id, third_user.id] } end - it_behaves_like "updates the users" + it_behaves_like 'updates the users' end - context "with a persisted record and string values" do + context 'with a persisted record and string values' do let(:call_attributes) do { user_ids: [second_user.id.to_s, third_user.id.to_s] } end - it_behaves_like "updates the users" + it_behaves_like 'updates the users' end - context "with a new record" do + context 'with a new record' do let(:group) do Group.new end - it "sets the user" do + it 'sets the user' do expect(service_call.result.group_users.map(&:user_id)) .to eql [second_user.id, third_user.id] end - it "does not persist the association" do + it 'does not persist the association' do expect(service_call.result.group_users.all(&:new_record?)) .to be_truthy end diff --git a/spec/services/groups/update_roles_service_integration_spec.rb b/spec/services/groups/update_roles_service_integration_spec.rb index 2c76b86527f6..0e6d0a3bc7f5 100644 --- a/spec/services/groups/update_roles_service_integration_spec.rb +++ b/spec/services/groups/update_roles_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Groups::UpdateRolesService, "integration", type: :model do +RSpec.describe Groups::UpdateRolesService, 'integration', type: :model do subject(:service_call) { instance.call(member:, message:, send_notifications:) } shared_let(:project) { create(:project) } @@ -65,22 +65,22 @@ .to receive(:perform_later) end - shared_examples_for "keeps timestamp" do - specify "updated_at on member is unchanged" do + shared_examples_for 'keeps timestamp' do + specify 'updated_at on member is unchanged' do expect { service_call } .not_to(change { Member.find_by(principal: user).updated_at }) end end - shared_examples_for "updates timestamp" do - specify "updated_at on member is changed" do + shared_examples_for 'updates timestamp' do + specify 'updated_at on member is changed' do expect { service_call } .to(change { Member.find_by(principal: user).updated_at }) end end - shared_examples_for "sends notification" do - specify "on the updated membership" do + shared_examples_for 'sends notification' do + specify 'on the updated membership' do service_call expect(Notifications::GroupMemberAlteredJob) @@ -92,8 +92,8 @@ end end - shared_examples_for "sends no notification" do - specify "on the updated membership" do + shared_examples_for 'sends no notification' do + specify 'on the updated membership' do service_call expect(Notifications::GroupMemberAlteredJob) @@ -101,19 +101,19 @@ end end - context "when adding a role" do + context 'when adding a role' do shared_let(:added_role) { create(:project_role) } before do member.roles << added_role end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "adds the roles to all inherited memberships" do + it 'adds the roles to all inherited memberships' do service_call Member.where(principal: users).find_each do |member| @@ -122,18 +122,18 @@ end end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "with global membership" do + context 'with global membership' do shared_let(:role) { create(:global_role) } let!(:group) do create(:group, @@ -148,19 +148,19 @@ end end - context "when adding a global role" do + context 'when adding a global role' do shared_let(:added_role) { create(:global_role) } before do member.roles << added_role end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "adds the roles to all inherited memberships" do + it 'adds the roles to all inherited memberships' do service_call Member.where(principal: users).find_each do |member| @@ -169,18 +169,18 @@ end end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when removing a global role" do + context 'when removing a global role' do shared_let(:global_role) { create(:global_role) } let(:roles) { [role, global_role] } @@ -188,12 +188,12 @@ member.roles = [role] end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "removes the roles from all inherited memberships" do + it 'removes the roles from all inherited memberships' do service_call Member.where(principal: users).find_each do |member| @@ -202,19 +202,19 @@ end end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end end - context "when adding a role but with one user having had the role before (no inherited from)" do + context 'when adding a role but with one user having had the role before (no inherited from)' do shared_let(:added_role) { create(:project_role) } before do @@ -223,45 +223,45 @@ Member.where(principal: users.first).first.member_roles.create(role: added_role) end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "keeps the roles unchanged for those user that already had the role" do + it 'keeps the roles unchanged for those user that already had the role' do service_call expect(Member.find_by(principal: users.first).roles.uniq) .to contain_exactly(role, added_role) end - it "adds the roles to all inherited memberships" do + it 'adds the roles to all inherited memberships' do service_call expect(Member.find_by(principal: users.last).roles) .to contain_exactly(role, added_role) end - it_behaves_like "keeps timestamp" do + it_behaves_like 'keeps timestamp' do let(:user) { users.first } end - it_behaves_like "updates timestamp" do + it_behaves_like 'updates timestamp' do let(:user) { users.last } end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users.last } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when removing a role" do + context 'when removing a role' do shared_let(:role_to_remove) { create(:project_role) } let(:roles) { [role, role_to_remove] } @@ -269,12 +269,12 @@ member.roles = [role] end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "removes the roles from all inherited memberships" do + it 'removes the roles from all inherited memberships' do service_call Member.where(principal: users).find_each do |member| @@ -283,18 +283,18 @@ end end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when removing a role but with a user having had the role before (no inherited_from)" do + context 'when removing a role but with a user having had the role before (no inherited_from)' do shared_let(:role_to_remove) { create(:project_role) } let(:roles) { [role, role_to_remove] } @@ -305,57 +305,57 @@ Member.find_by(principal: users.first).member_roles.create(role: role_to_remove) end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "removes the inherited roles" do + it 'removes the inherited roles' do service_call expect(Member.find_by(principal: users.last).roles) .to contain_exactly(role) end - it "keeps the non inherited roles" do + it 'keeps the non inherited roles' do service_call expect(Member.find_by(principal: users.first).roles) .to contain_exactly(role, role_to_remove) end - it_behaves_like "keeps timestamp" do + it_behaves_like 'keeps timestamp' do let(:user) { users.first } end - it_behaves_like "updates timestamp" do + it_behaves_like 'updates timestamp' do let(:user) { users.last } end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users.last } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when replacing roles" do + context 'when replacing roles' do shared_let(:replacement_role) { create(:project_role) } before do member.roles = [replacement_role] end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "replaces the role in all user memberships" do + it 'replaces the role in all user memberships' do service_call Member.where(principal: users).find_each do |member| @@ -364,18 +364,18 @@ end end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when replacing a role but with a user having had the replaced role before (no inherited_from)" do + context 'when replacing a role but with a user having had the replaced role before (no inherited_from)' do shared_let(:replacement_role) { create(:project_role) } before do @@ -385,45 +385,45 @@ Member.where(principal: users.first).first.member_roles.create(role:) end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "replaces the inherited role" do + it 'replaces the inherited role' do service_call expect(Member.find_by(principal: users.last).roles) .to contain_exactly(replacement_role) end - it "keeps the non inherited roles" do + it 'keeps the non inherited roles' do service_call expect(Member.find_by(principal: users.first).roles) .to contain_exactly(role, replacement_role) end - it_behaves_like "updates timestamp" do + it_behaves_like 'updates timestamp' do let(:user) { users.first } end - it_behaves_like "updates timestamp" do + it_behaves_like 'updates timestamp' do let(:user) { users.last } end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when adding a role and the user has a role already granted by a different group" do + context 'when adding a role and the user has a role already granted by a different group' do shared_let(:other_role) { create(:project_role) } let!(:second_group) do @@ -447,33 +447,33 @@ member.roles << added_role end - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - it "keeps the roles the user already had before and adds the new one" do + it 'keeps the roles the user already had before and adds the new one' do service_call expect(Member.find_by(principal: users.first).roles.uniq) .to contain_exactly(role, other_role, added_role) end - it_behaves_like "sends notification" do + it_behaves_like 'sends notification' do let(:user) { users } end - context "when notifications are suppressed" do + context 'when notifications are suppressed' do let(:send_notifications) { false } - it_behaves_like "sends no notification" + it_behaves_like 'sends no notification' end end - context "when not allowed" do + context 'when not allowed' do shared_let(:current_user) { User.anonymous } - it "fails the request" do + it 'fails the request' do expect(subject).to be_failure expect(subject.message).to match /may not be accessed/ end diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index f7ed47ac78e6..efefd29002f0 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Groups::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:add_service_result) do ServiceResult.success end @@ -49,7 +49,7 @@ add_service end - context "with newly created group_users" do + context 'with newly created group_users' do let(:old_group_user) { build_stubbed(:group_user, user_id: 3) } let(:new_group_user) do build_stubbed(:group_user, user_id: 5).tap do |gu| @@ -66,12 +66,12 @@ .and_return(group_users) end - context "with the AddUsersService being successful" do - it "is successful" do + context 'with the AddUsersService being successful' do + it 'is successful' do expect(instance_call).to be_success end - it "calls the AddUsersService" do + it 'calls the AddUsersService' do instance_call expect(add_users_service) @@ -80,16 +80,16 @@ end end - context "with the AddUsersService being unsuccessful" do + context 'with the AddUsersService being unsuccessful' do let(:add_service_result) do ServiceResult.failure end - it "is failure" do + it 'is failure' do expect(instance_call).to be_failure end - it "calls the AddUsersService" do + it 'calls the AddUsersService' do instance_call expect(add_users_service) @@ -98,14 +98,14 @@ end end - context "without any new group_users" do + context 'without any new group_users' do let(:group_users) { [old_group_user] } - it "is successful" do + it 'is successful' do expect(instance_call).to be_success end - it "does not call the AddUsersService" do + it 'does not call the AddUsersService' do instance_call expect(add_users_service) diff --git a/spec/services/ldap/import_user_list_service_integration_spec.rb b/spec/services/ldap/import_user_list_service_integration_spec.rb index ef9f01314a74..45f8a57789a3 100644 --- a/spec/services/ldap/import_user_list_service_integration_spec.rb +++ b/spec/services/ldap/import_user_list_service_integration_spec.rb @@ -1,7 +1,7 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Ldap::ImportUsersFromListService do - include_context "with temporary LDAP" + include_context 'with temporary LDAP' subject do described_class.new(ldap_auth_source, user_list).call @@ -11,44 +11,44 @@ %w[aa729 bb459 cc414] end - it "adds all three users" do + it 'adds all three users' do subject - user_aa729 = User.find_by(login: "aa729") + user_aa729 = User.find_by(login: 'aa729') expect(user_aa729).to be_present - expect(user_aa729.firstname).to eq "Alexandra" - expect(user_aa729.lastname).to eq "Adams" + expect(user_aa729.firstname).to eq 'Alexandra' + expect(user_aa729.lastname).to eq 'Adams' - user_bb459 = User.find_by(login: "bb459") + user_bb459 = User.find_by(login: 'bb459') expect(user_bb459).to be_present - expect(user_bb459.firstname).to eq "Belle" - expect(user_bb459.lastname).to eq "Baldwin" + expect(user_bb459.firstname).to eq 'Belle' + expect(user_bb459.lastname).to eq 'Baldwin' - user_cc414 = User.find_by(login: "cc414") + user_cc414 = User.find_by(login: 'cc414') expect(user_cc414).to be_present - expect(user_cc414.firstname).to eq "Claire" - expect(user_cc414.lastname).to eq "Carpenter" + expect(user_cc414.firstname).to eq 'Claire' + expect(user_cc414.lastname).to eq 'Carpenter' end - context "when two users already exist" do - let!(:user_aa729) { create(:user, login: "aa729", firstname: "Foobar", ldap_auth_source:) } - let!(:user_bb459) { create(:user, login: "bb459", firstname: "Bla", ldap_auth_source:) } + context 'when two users already exist' do + let!(:user_aa729) { create(:user, login: 'aa729', firstname: 'Foobar', ldap_auth_source:) } + let!(:user_bb459) { create(:user, login: 'bb459', firstname: 'Bla', ldap_auth_source:) } - it "adds the third one, but does not update the other two" do + it 'adds the third one, but does not update the other two' do subject user_aa729.reload user_bb459.reload - expect(user_aa729.firstname).to eq "Foobar" - expect(user_aa729.lastname).to eq "Bobbit" - expect(user_bb459.firstname).to eq "Bla" - expect(user_bb459.lastname).to eq "Bobbit" + expect(user_aa729.firstname).to eq 'Foobar' + expect(user_aa729.lastname).to eq 'Bobbit' + expect(user_bb459.firstname).to eq 'Bla' + expect(user_bb459.lastname).to eq 'Bobbit' - user_cc414 = User.find_by(login: "cc414") + user_cc414 = User.find_by(login: 'cc414') expect(user_cc414).to be_present - expect(user_cc414.firstname).to eq "Claire" - expect(user_cc414.lastname).to eq "Carpenter" + expect(user_cc414.firstname).to eq 'Claire' + expect(user_cc414.lastname).to eq 'Carpenter' end end end diff --git a/spec/services/ldap/import_users_from_filter_service_integration_spec.rb b/spec/services/ldap/import_users_from_filter_service_integration_spec.rb index 32f4a57077c1..5ed8193ad79d 100644 --- a/spec/services/ldap/import_users_from_filter_service_integration_spec.rb +++ b/spec/services/ldap/import_users_from_filter_service_integration_spec.rb @@ -1,26 +1,26 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Ldap::ImportUsersFromFilterService do - include_context "with temporary LDAP" + include_context 'with temporary LDAP' subject do described_class.new(ldap_auth_source, filter).call end - let(:filter) { Net::LDAP::Filter.from_rfc2254 "(uid=aa729)" } + let(:filter) { Net::LDAP::Filter.from_rfc2254 '(uid=aa729)' } - it "adds only the matching user" do + it 'adds only the matching user' do subject - user_aa729 = User.find_by(login: "aa729") + user_aa729 = User.find_by(login: 'aa729') expect(user_aa729).to be_present - expect(user_aa729.firstname).to eq "Alexandra" - expect(user_aa729.lastname).to eq "Adams" + expect(user_aa729.firstname).to eq 'Alexandra' + expect(user_aa729.lastname).to eq 'Adams' - user_bb459 = User.find_by(login: "bb459") + user_bb459 = User.find_by(login: 'bb459') expect(user_bb459).not_to be_present - user_cc414 = User.find_by(login: "cc414") + user_cc414 = User.find_by(login: 'cc414') expect(user_cc414).not_to be_present end end diff --git a/spec/services/ldap/post_login_sync_service_spec.rb b/spec/services/ldap/post_login_sync_service_spec.rb index ba20f6d6f917..602342b00640 100644 --- a/spec/services/ldap/post_login_sync_service_spec.rb +++ b/spec/services/ldap/post_login_sync_service_spec.rb @@ -1,15 +1,15 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Ldap::PostLoginSyncService do let!(:ldap) { create(:ldap_auth_source) } let(:admin) { false } let(:attributes) do { - login: "aa729", + login: 'aa729', admin:, - firstname: "Alexandra", - lastname: "Adams", - mail: "a.adam@example.com", + firstname: 'Alexandra', + lastname: 'Adams', + mail: 'a.adam@example.com', ldap_auth_source_id: ldap.id } end @@ -18,27 +18,27 @@ described_class.new(ldap, user:, attributes:).call end - context "with an existing user" do - let!(:user) { create(:user, firstname: "Bob", lastname: "Bobbit", mail: "b@example.com", login: "aa729") } + context 'with an existing user' do + let!(:user) { create(:user, firstname: 'Bob', lastname: 'Bobbit', mail: 'b@example.com', login: 'aa729') } - it "syncs the attributes" do - expect(user.firstname).to eq "Bob" - expect(user.lastname).to eq "Bobbit" - expect(user.mail).to eq "b@example.com" + it 'syncs the attributes' do + expect(user.firstname).to eq 'Bob' + expect(user.lastname).to eq 'Bobbit' + expect(user.mail).to eq 'b@example.com' expect(subject).to be_success expect(subject.result).to be_a User expect(subject.result).to eq user.reload expect(subject.result).to be_valid - expect(subject.result.firstname).to eq "Alexandra" - expect(subject.result.lastname).to eq "Adams" - expect(subject.result.mail).to eq "a.adam@example.com" + expect(subject.result.firstname).to eq 'Alexandra' + expect(subject.result.lastname).to eq 'Adams' + expect(subject.result.mail).to eq 'a.adam@example.com' end - context "with nil attributes" do + context 'with nil attributes' do let(:attributes) { nil } - it "locks the user when enabled", with_config: { ldap_users_sync_status: true } do + it 'locks the user when enabled', with_config: { ldap_users_sync_status: true } do expect(user).to be_active subject @@ -46,17 +46,17 @@ expect(user.reload).to be_locked end - it "does nothing when not enabled", with_config: { ldap_users_sync_status: false } do + it 'does nothing when not enabled', with_config: { ldap_users_sync_status: false } do expect(user).to be_active expect { subject }.not_to change(user, :attributes) end end - context "with empty attributes" do + context 'with empty attributes' do let(:attributes) { {} } - it "locks the user when enabled", with_config: { ldap_users_sync_status: true } do + it 'locks the user when enabled', with_config: { ldap_users_sync_status: true } do expect(user).to be_active subject @@ -64,7 +64,7 @@ expect(user.reload).to be_locked end - it "does nothing when not enabled", with_config: { ldap_users_sync_status: false } do + it 'does nothing when not enabled', with_config: { ldap_users_sync_status: false } do expect(user).to be_active expect { subject }.not_to change(user, :attributes) @@ -72,21 +72,21 @@ end end - context "with a new user" do - let!(:user) { build(:user, firstname: "Bob", lastname: "Bobbit", mail: "b@example.com", login: "aa729") } + context 'with a new user' do + let!(:user) { build(:user, firstname: 'Bob', lastname: 'Bobbit', mail: 'b@example.com', login: 'aa729') } - it "creates the user" do - expect(user.firstname).to eq "Bob" - expect(user.lastname).to eq "Bobbit" - expect(user.mail).to eq "b@example.com" + it 'creates the user' do + expect(user.firstname).to eq 'Bob' + expect(user.lastname).to eq 'Bobbit' + expect(user.mail).to eq 'b@example.com' expect(user).to be_new_record expect(subject).to be_success expect(subject.result).to be_a User expect(subject.result).to be_valid - expect(subject.result.firstname).to eq "Alexandra" - expect(subject.result.lastname).to eq "Adams" - expect(subject.result.mail).to eq "a.adam@example.com" + expect(subject.result.firstname).to eq 'Alexandra' + expect(subject.result.lastname).to eq 'Adams' + expect(subject.result.mail).to eq 'a.adam@example.com' expect(subject.result).to be_persisted end end diff --git a/spec/services/ldap/synchronize_users_service_integration_spec.rb b/spec/services/ldap/synchronize_users_service_integration_spec.rb index 93d3f9ac9841..8c64e4ace888 100644 --- a/spec/services/ldap/synchronize_users_service_integration_spec.rb +++ b/spec/services/ldap/synchronize_users_service_integration_spec.rb @@ -1,16 +1,16 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe Ldap::SynchronizeUsersService do - include_context "with temporary LDAP" + include_context 'with temporary LDAP' subject do described_class.new(ldap_auth_source).call end - context "when updating an admin" do - let!(:user_aa729) { create(:user, login: "aa729", firstname: "Foobar", ldap_auth_source:, admin: true) } + context 'when updating an admin' do + let!(:user_aa729) { create(:user, login: 'aa729', firstname: 'Foobar', ldap_auth_source:, admin: true) } - it "does not update the admin attribute if not defined (Regression #42396)" do + it 'does not update the admin attribute if not defined (Regression #42396)' do expect(user_aa729).to be_admin subject @@ -19,28 +19,28 @@ end end - context "when updating users" do - let!(:user_aa729) { create(:user, login: "aa729", firstname: "Foobar", ldap_auth_source:) } - let!(:user_bb459) { create(:user, login: "bb459", firstname: "Bla", ldap_auth_source:) } + context 'when updating users' do + let!(:user_aa729) { create(:user, login: 'aa729', firstname: 'Foobar', ldap_auth_source:) } + let!(:user_bb459) { create(:user, login: 'bb459', firstname: 'Bla', ldap_auth_source:) } - context "when user sync status is enabled", + context 'when user sync status is enabled', with_config: { ldap_users_sync_status: true } do - it "updates the attributes of those users" do + it 'updates the attributes of those users' do subject user_aa729.reload user_bb459.reload - expect(user_aa729.firstname).to eq "Alexandra" - expect(user_aa729.lastname).to eq "Adams" - expect(user_aa729.mail).to eq "alexandra@example.org" + expect(user_aa729.firstname).to eq 'Alexandra' + expect(user_aa729.lastname).to eq 'Adams' + expect(user_aa729.mail).to eq 'alexandra@example.org' - expect(user_bb459.firstname).to eq "Belle" - expect(user_bb459.lastname).to eq "Baldwin" - expect(user_bb459.mail).to eq "belle@example.org" + expect(user_bb459.firstname).to eq 'Belle' + expect(user_bb459.lastname).to eq 'Baldwin' + expect(user_bb459.mail).to eq 'belle@example.org' end - it "updates one user if the other fails" do + it 'updates one user if the other fails' do allow(Users::UpdateService) .to receive(:new) .and_call_original @@ -55,15 +55,15 @@ user_aa729.reload user_bb459.reload - expect(user_aa729.firstname).to eq "Foobar" - expect(user_aa729.lastname).to eq "Bobbit" + expect(user_aa729.firstname).to eq 'Foobar' + expect(user_aa729.lastname).to eq 'Bobbit' - expect(user_bb459.firstname).to eq "Belle" - expect(user_bb459.lastname).to eq "Baldwin" - expect(user_bb459.mail).to eq "belle@example.org" + expect(user_bb459.firstname).to eq 'Belle' + expect(user_bb459.lastname).to eq 'Baldwin' + expect(user_bb459.mail).to eq 'belle@example.org' end - it "reactivates the account if it is locked" do + it 'reactivates the account if it is locked' do user_aa729.lock! expect(user_aa729.reload).to be_locked @@ -74,11 +74,11 @@ expect(user_aa729).to be_active end - context "with a user that is in another LDAP" do - let(:auth_source2) { create(:ldap_auth_source, name: "Another LDAP") } - let(:user_foo) { create(:user, login: "login", ldap_auth_source: auth_source2) } + context 'with a user that is in another LDAP' do + let(:auth_source2) { create(:ldap_auth_source, name: 'Another LDAP') } + let(:user_foo) { create(:user, login: 'login', ldap_auth_source: auth_source2) } - it "does not touch that user" do + it 'does not touch that user' do expect(user_foo).to be_active subject @@ -88,9 +88,9 @@ end end - context "when user sync status is disabled", + context 'when user sync status is disabled', with_config: { ldap_users_sync_status: false } do - it "does not reactivate the account if it is locked" do + it 'does not reactivate the account if it is locked' do user_aa729.lock! expect(user_aa729.reload).to be_locked @@ -102,40 +102,40 @@ end end - context "when requesting only a subset of users" do - let!(:user_cc414) { create(:user, login: "cc414", ldap_auth_source:) } + context 'when requesting only a subset of users' do + let!(:user_cc414) { create(:user, login: 'cc414', ldap_auth_source:) } subject do described_class.new(ldap_auth_source, %w[Aa729 cc414]).call end - it "syncs all case-insensitive users" do + it 'syncs all case-insensitive users' do subject user_aa729.reload user_bb459.reload user_cc414.reload - expect(user_aa729.firstname).to eq "Alexandra" - expect(user_aa729.lastname).to eq "Adams" - expect(user_aa729.mail).to eq "alexandra@example.org" + expect(user_aa729.firstname).to eq 'Alexandra' + expect(user_aa729.lastname).to eq 'Adams' + expect(user_aa729.mail).to eq 'alexandra@example.org' - expect(user_cc414.firstname).to eq "Claire" - expect(user_cc414.lastname).to eq "Carpenter" - expect(user_cc414.mail).to eq "claire@example.org" + expect(user_cc414.firstname).to eq 'Claire' + expect(user_cc414.lastname).to eq 'Carpenter' + expect(user_cc414.mail).to eq 'claire@example.org' - expect(user_bb459.firstname).to eq "Bla" - expect(user_bb459.lastname).to eq "Bobbit" + expect(user_bb459.firstname).to eq 'Bla' + expect(user_bb459.lastname).to eq 'Bobbit' end end end - context "with a user that is no longer in LDAP" do - let(:user_foo) { create(:user, login: "login", ldap_auth_source:) } + context 'with a user that is no longer in LDAP' do + let(:user_foo) { create(:user, login: 'login', ldap_auth_source:) } - context "when user sync status is enabled", + context 'when user sync status is enabled', with_config: { ldap_users_sync_status: true } do - it "locks that user" do + it 'locks that user' do expect(user_foo).to be_active subject @@ -144,9 +144,9 @@ end end - context "when user sync status is disabled", + context 'when user sync status is disabled', with_config: { ldap_users_sync_status: false } do - it "does not lock that user" do + it 'does not lock that user' do expect(user_foo).to be_active subject diff --git a/spec/services/members/cleanup_service_integration_spec.rb b/spec/services/members/cleanup_service_integration_spec.rb index f4ca6865b82b..e96b30d2ae27 100644 --- a/spec/services/members/cleanup_service_integration_spec.rb +++ b/spec/services/members/cleanup_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Members::CleanupService, "integration", type: :model do +RSpec.describe Members::CleanupService, 'integration', type: :model do subject(:service_call) { instance.call } let(:user) { create(:user) } @@ -39,21 +39,21 @@ described_class.new(users, projects) end - describe "category unassignment" do + describe 'category unassignment' do let!(:category) do build(:category, project:, assigned_to: user).tap do |c| c.save(validate: false) end end - it "sets assigned_to to nil" do + it 'sets assigned_to to nil' do service_call expect(category.reload.assigned_to) .to be_nil end - context "with the user having a membership with an assignable role" do + context 'with the user having a membership with an assignable role' do before do create(:member, principal: user, @@ -61,7 +61,7 @@ roles: [create(:project_role, permissions: %i[work_package_assigned])]) end - it "keeps assigned_to to the user" do + it 'keeps assigned_to to the user' do service_call expect(category.reload.assigned_to) @@ -69,7 +69,7 @@ end end - context "with the user having a membership with an unassignable role" do + context 'with the user having a membership with an unassignable role' do before do create(:member, principal: user, @@ -78,7 +78,7 @@ roles: [create(:project_role, permissions: [])]) end - it "sets assigned_to to nil" do + it 'sets assigned_to to nil' do service_call expect(category.reload.assigned_to) @@ -87,7 +87,7 @@ end end - describe "watcher pruning" do + describe 'watcher pruning' do let(:work_package) do create(:work_package, project:) @@ -100,14 +100,14 @@ end end - it "removes the watcher" do + it 'removes the watcher' do service_call expect { watcher.reload } .to raise_error ActiveRecord::RecordNotFound end - context "with the user having a membership granting the right to view the watchable" do + context 'with the user having a membership granting the right to view the watchable' do before do create(:member, principal: user, @@ -115,7 +115,7 @@ roles: [create(:project_role, permissions: [:view_work_packages])]) end - it "keeps the watcher" do + it 'keeps the watcher' do service_call expect { watcher.reload } @@ -123,7 +123,7 @@ end end - context "with the user having a membership not granting the right to view the watchable" do + context 'with the user having a membership not granting the right to view the watchable' do before do create(:member, principal: user, @@ -131,7 +131,7 @@ roles: [create(:project_role, permissions: [])]) end - it "keeps the watcher" do + it 'keeps the watcher' do service_call expect { watcher.reload } diff --git a/spec/services/members/create_service_integration_spec.rb b/spec/services/members/create_service_integration_spec.rb index a736ad7bf184..d937a45aa2c8 100644 --- a/spec/services/members/create_service_integration_spec.rb +++ b/spec/services/members/create_service_integration_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' -RSpec.describe Members::CreateService, "integration", type: :model do +RSpec.describe Members::CreateService, 'integration', type: :model do let(:user1) { create(:admin) } let(:user2) { create(:user) } let(:group) { create(:group, members: [user1, user2]) } @@ -37,7 +37,7 @@ subject { instance.call(params) } - describe "with a global membership" do + describe 'with a global membership' do let(:global_role) { create(:global_role) } let(:params) do { @@ -47,7 +47,7 @@ } end - it "inherits the membership to all users", :aggregate_failures do + it 'inherits the membership to all users', :aggregate_failures do expect { subject }.to change(MemberRole, :count).by(3) expect(subject).to be_success diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index e3000fbf4447..f94e85936de1 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Members::CreateService, type: :model do let(:user1) { build_stubbed(:user) } @@ -54,7 +54,7 @@ .to receive(:send) end - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:call_attributes) do { project_id: "1", @@ -65,8 +65,8 @@ } end - describe "if successful" do - it "sends a notification" do + describe 'if successful' do + it 'sends a notification' do subject expect(OpenProject::Notifications) @@ -77,7 +77,7 @@ send_notifications: true) end - describe "for a group" do + describe 'for a group' do let!(:model_instance) { build_stubbed(:member, principal: group) } it "generates the members and roles for the group's users" do @@ -98,17 +98,17 @@ end end - context "if the SetAttributeService is unsuccessful" do + context 'if the SetAttributeService is unsuccessful' do let(:set_attributes_success) { false } - it "sends no notification" do + it 'sends no notification' do subject expect(OpenProject::Notifications) .not_to have_received(:send) end - describe "for a group" do + describe 'for a group' do let!(:model_instance) { build_stubbed(:member, principal: group) } it "does not create any inherited roles" do @@ -120,17 +120,17 @@ end end - context "when the member is invalid" do + context 'when the member is invalid' do let(:model_save_result) { false } - it "sends no notification" do + it 'sends no notification' do subject expect(OpenProject::Notifications) .not_to have_received(:send) end - context "for a group" do + context 'for a group' do let!(:model_instance) { build_stubbed(:member, principal: group) } it "does not create any inherited roles" do diff --git a/spec/services/members/set_attributes_service_spec.rb b/spec/services/members/set_attributes_service_spec.rb index a2819cd37ef3..48fcc03db0a6 100644 --- a/spec/services/members/set_attributes_service_spec.rb +++ b/spec/services/members/set_attributes_service_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Members::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } let(:contract_class) do - contract = double("contract_class") + contract = double('contract_class') allow(contract) .to receive(:new) @@ -41,11 +41,11 @@ contract end let(:contract_instance) do - double("contract_instance", validate: contract_valid, errors: contract_errors) + double('contract_instance', validate: contract_valid, errors: contract_errors) end let(:contract_valid) { true } let(:contract_errors) do - double("contract_errors") + double('contract_errors') end let(:member_valid) { true } let(:instance) do @@ -58,7 +58,7 @@ build_stubbed(:member) end - describe "call" do + describe 'call' do let(:call_attributes) do { project_id: 5, @@ -78,25 +78,25 @@ subject { instance.call(call_attributes) } - it "is successful" do + it 'is successful' do expect(subject.success?).to be_truthy end - it "sets the attributes" do + it 'sets the attributes' do subject expect(member.attributes.slice(*member.changed).symbolize_keys) .to eql call_attributes end - it "does not persist the member" do + it 'does not persist the member' do expect(member) .not_to receive(:save) subject end - context "with changes to the roles do" do + context 'with changes to the roles do' do let(:first_role) { build_stubbed(:project_role) } let(:second_role) { build_stubbed(:project_role) } let(:third_role) { build_stubbed(:project_role) } @@ -107,34 +107,34 @@ } end - context "with a persisted record" do + context 'with a persisted record' do let(:member) do build_stubbed(:member, roles: [first_role, second_role]) end - it "adds the new role and marks the other for destruction" do + it 'adds the new role and marks the other for destruction' do expect(subject.result.member_roles.map(&:role_id)).to contain_exactly(first_role.id, second_role.id, third_role.id) expect(subject.result.member_roles.detect { _1.role_id == first_role.id }).to be_marked_for_destruction end end - context "with a new record" do + context 'with a new record' do let(:member) do Member.new end - it "adds the new role" do + it 'adds the new role' do expect(subject.result.member_roles.map(&:role_id)).to contain_exactly(second_role.id, third_role.id) end - context "with role_ids not all being present" do + context 'with role_ids not all being present' do let(:call_attributes) do { - role_ids: [nil, "", second_role.id, third_role.id] + role_ids: [nil, '', second_role.id, third_role.id] } end - it "ignores the empty values" do + it 'ignores the empty values' do expect(subject.result.member_roles.map(&:role_id)).to contain_exactly(second_role.id, third_role.id) end end diff --git a/spec/services/members/update_service_spec.rb b/spec/services/members/update_service_spec.rb index 7df33555e552..63ba90b0f733 100644 --- a/spec/services/members/update_service_spec.rb +++ b/spec/services/members/update_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Members::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:call_attributes) do { role_ids: ["2"], @@ -44,8 +44,8 @@ .to receive(:send) end - describe "if successful" do - it "sends a notification" do + describe 'if successful' do + it 'sends a notification' do subject expect(OpenProject::Notifications) @@ -57,10 +57,10 @@ end end - context "if the SetAttributeService is unsuccessful" do + context 'if the SetAttributeService is unsuccessful' do let(:set_attributes_success) { false } - it "sends no notifications" do + it 'sends no notifications' do subject expect(OpenProject::Notifications) @@ -68,10 +68,10 @@ end end - context "when the member is invalid" do + context 'when the member is invalid' do let(:model_save_result) { false } - it "sends no notifications" do + it 'sends no notifications' do subject expect(OpenProject::Notifications) diff --git a/spec/services/messages/create_service_spec.rb b/spec/services/messages/create_service_spec.rb index 37b8a052b278..940f4d8f5b6f 100644 --- a/spec/services/messages/create_service_spec.rb +++ b/spec/services/messages/create_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Messages::CreateService, type: :model do - it_behaves_like "BaseServices create service" + it_behaves_like 'BaseServices create service' end diff --git a/spec/services/messages/set_attributes_service_spec.rb b/spec/services/messages/set_attributes_service_spec.rb index 8982b1d26d78..82dab069a26f 100644 --- a/spec/services/messages/set_attributes_service_spec.rb +++ b/spec/services/messages/set_attributes_service_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Messages::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } let(:forum) { build_stubbed(:forum) } let(:contract_instance) do - contract = double("contract_instance") + contract = double('contract_instance') allow(contract) .to receive(:validate) .and_return(contract_valid) @@ -42,7 +42,7 @@ contract end - let(:contract_errors) { double("contract_errors") } + let(:contract_errors) { double('contract_errors') } let(:contract_valid) { true } let(:time_entry_valid) { true } @@ -72,12 +72,12 @@ subject { instance.call(params) } - it "returns the message instance as the result" do + it 'returns the message instance as the result' do expect(subject.result) .to eql message_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end @@ -89,14 +89,14 @@ .to eql user end - it "notes the author to be system changed" do + it 'notes the author to be system changed' do subject - expect(message_instance.changed_by_system["author_id"]) + expect(message_instance.changed_by_system['author_id']) .to eql [nil, user.id] end - context "with params" do + context 'with params' do let(:params) do { forum: @@ -110,7 +110,7 @@ }.with_indifferent_access end - it "assigns the params" do + it 'assigns the params' do subject attributes_of_interest = message_instance @@ -122,14 +122,14 @@ end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } let(:expect_time_instance_save) do expect(message_instance) .not_to receive(:save) end - it "returns failure" do + it 'returns failure' do expect(subject) .not_to be_success end diff --git a/spec/services/messages/update_service_spec.rb b/spec/services/messages/update_service_spec.rb index f92294037195..e52a87b17f44 100644 --- a/spec/services/messages/update_service_spec.rb +++ b/spec/services/messages/update_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Messages::UpdateService, type: :model do - it_behaves_like "BaseServices update service" + it_behaves_like 'BaseServices update service' end diff --git a/spec/services/notifications/create_from_journal_job_shared.rb b/spec/services/notifications/create_from_journal_job_shared.rb index bb4b9e78fa8f..41234362c772 100644 --- a/spec/services/notifications/create_from_journal_job_shared.rb +++ b/spec/services/notifications/create_from_journal_job_shared.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_context "with CreateFromJournalJob context" do +RSpec.shared_context 'with CreateFromJournalJob context' do shared_let(:project) { create(:project_with_types) } let(:permissions) { [] } let(:recipient) do @@ -64,7 +64,7 @@ end let(:send_notifications) { true } - shared_examples_for "creates notification" do + shared_examples_for 'creates notification' do let(:sender) { author } let(:notification_channel_reasons) do { @@ -75,7 +75,7 @@ end let(:notification) { build_stubbed(:notification) } - it "creates a notification and returns it" do + it 'creates a notification and returns it' do notifications_service = instance_double(Notifications::CreateService) allow(Notifications::CreateService) @@ -99,8 +99,8 @@ end end - shared_examples_for "creates no notification" do - it "creates no notification" do + shared_examples_for 'creates no notification' do + it 'creates no notification' do allow(Notifications::CreateService) .to receive(:new) .and_call_original diff --git a/spec/services/notifications/create_from_model_service_comment_spec.rb b/spec/services/notifications/create_from_model_service_comment_spec.rb index af4d98787029..981bd479bcab 100644 --- a/spec/services/notifications/create_from_model_service_comment_spec.rb +++ b/spec/services/notifications/create_from_model_service_comment_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "create_from_journal_job_shared" +require 'spec_helper' +require_relative 'create_from_journal_job_shared' -RSpec.describe Notifications::CreateFromModelService, "comment", with_settings: { journal_aggregation_time_minutes: 0 } do +RSpec.describe Notifications::CreateFromModelService, 'comment', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) do described_class.new(resource).call(send_notifications) end - include_context "with CreateFromJournalJob context" + include_context 'with CreateFromJournalJob context' shared_let(:project) { create(:project) } shared_let(:news) { create(:news, project:) } @@ -45,7 +45,7 @@ create(:comment, commented: news, author:, - comments: "Some text") + comments: 'Some text') end let(:journal) { nil } @@ -58,10 +58,10 @@ recipient end - describe "#perform" do - context "with a newly created comment" do - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + describe '#perform' do + context 'with a newly created comment' do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -73,37 +73,37 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the news" do + context 'with the user having registered for watcher notifications and watching the news' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -114,7 +114,7 @@ news.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -126,7 +126,7 @@ end end - context "with the user not having registered for watcher notifications and watching the news" do + context 'with the user not having registered for watcher notifications and watching the news' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -137,25 +137,25 @@ news.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and not watching the news" do + context 'with the user having registered for watcher notifications and not watching the news' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do before do recipient.members.destroy_all end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end end diff --git a/spec/services/notifications/create_from_model_service_message_spec.rb b/spec/services/notifications/create_from_model_service_message_spec.rb index 2070866f426d..b21702e52e8b 100644 --- a/spec/services/notifications/create_from_model_service_message_spec.rb +++ b/spec/services/notifications/create_from_model_service_message_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "create_from_journal_job_shared" +require 'spec_helper' +require_relative 'create_from_journal_job_shared' -RSpec.describe Notifications::CreateFromModelService, "message", with_settings: { journal_aggregation_time_minutes: 0 } do +RSpec.describe Notifications::CreateFromModelService, 'message', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) do described_class.new(journal).call(send_notifications) end - include_context "with CreateFromJournalJob context" + include_context 'with CreateFromJournalJob context' shared_let(:project) { create(:project) } shared_let(:forum) { create(:forum, project:) } @@ -59,10 +59,10 @@ recipient end - describe "#perform" do - context "with a newly created message" do - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + describe '#perform' do + context 'with a newly created message' do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -74,37 +74,37 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the forum" do + context 'with the user having registered for watcher notifications and watching the forum' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -115,7 +115,7 @@ forum.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -127,7 +127,7 @@ end end - context "with the user not having registered for watcher notifications and watching the forum" do + context 'with the user not having registered for watcher notifications and watching the forum' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -138,20 +138,20 @@ forum.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and not watching the forum nor root message" do + context 'with the user having registered for watcher notifications and not watching the forum nor root message' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the root" do + context 'with the user having registered for watcher notifications and watching the root' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -162,7 +162,7 @@ root_message.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -174,7 +174,7 @@ end end - context "with the user not having registered for watcher notifications and watching the root" do + context 'with the user not having registered for watcher notifications and watching the root' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -185,26 +185,26 @@ root_message.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do before do recipient.members.destroy_all end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "with an updated message" do + context 'with an updated message' do before do - resource.subject = "A new subject" + resource.subject = 'A new subject' resource.save! end - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -216,37 +216,37 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the forum" do + context 'with the user having registered for watcher notifications and watching the forum' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -257,7 +257,7 @@ forum.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -269,7 +269,7 @@ end end - context "with the user not having registered for watcher notifications and watching the forum" do + context 'with the user not having registered for watcher notifications and watching the forum' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -280,20 +280,20 @@ forum.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and not watching the forum nor root message" do + context 'with the user having registered for watcher notifications and not watching the forum nor root message' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the root" do + context 'with the user having registered for watcher notifications and watching the root' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -304,7 +304,7 @@ root_message.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -316,7 +316,7 @@ end end - context "with the user not having registered for watcher notifications and watching the root" do + context 'with the user not having registered for watcher notifications and watching the root' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -327,15 +327,15 @@ root_message.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do before do recipient.members.destroy_all end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end end diff --git a/spec/services/notifications/create_from_model_service_news_spec.rb b/spec/services/notifications/create_from_model_service_news_spec.rb index a5fb1c627a24..f99c6f78b46b 100644 --- a/spec/services/notifications/create_from_model_service_news_spec.rb +++ b/spec/services/notifications/create_from_model_service_news_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "create_from_journal_job_shared" +require 'spec_helper' +require_relative 'create_from_journal_job_shared' -RSpec.describe Notifications::CreateFromModelService, "news", with_settings: { journal_aggregation_time_minutes: 0 } do +RSpec.describe Notifications::CreateFromModelService, 'news', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) do described_class.new(journal).call(send_notifications) end - include_context "with CreateFromJournalJob context" + include_context 'with CreateFromJournalJob context' let(:journable) { build_stubbed(:news) } @@ -51,10 +51,10 @@ recipient end - describe "#call" do - context "with a newly created news do" do - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + describe '#call' do + context 'with a newly created news do' do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -66,45 +66,45 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "with an updated news" do + context 'with an updated news' do before do resource.description = "Some new text to create a journal" resource.save! end - context "with the user having registered for all notifications" do - it_behaves_like "creates no notification" + context 'with the user having registered for all notifications' do + it_behaves_like 'creates no notification' end end end diff --git a/spec/services/notifications/create_from_model_service_wiki_spec.rb b/spec/services/notifications/create_from_model_service_wiki_spec.rb index 239fbff04106..70efcc2b750d 100644 --- a/spec/services/notifications/create_from_model_service_wiki_spec.rb +++ b/spec/services/notifications/create_from_model_service_wiki_spec.rb @@ -25,15 +25,15 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "create_from_journal_job_shared" +require 'spec_helper' +require_relative 'create_from_journal_job_shared' -RSpec.describe Notifications::CreateFromModelService, "wiki", with_settings: { journal_aggregation_time_minutes: 0 } do +RSpec.describe Notifications::CreateFromModelService, 'wiki', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) do described_class.new(journal).call(send_notifications) end - include_context "with CreateFromJournalJob context" + include_context 'with CreateFromJournalJob context' shared_let(:project) { create(:project) } shared_let(:wiki) { create(:wiki, project:) } @@ -56,10 +56,10 @@ recipient end - describe "#perform" do - context "with a newly created wiki page" do - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + describe '#perform' do + context 'with a newly created wiki page' do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -71,37 +71,37 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the wiki" do + context 'with the user having registered for watcher notifications and watching the wiki' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -112,7 +112,7 @@ wiki.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -124,7 +124,7 @@ end end - context "with the user not having registered for watcher notifications and watching the wiki" do + context 'with the user not having registered for watcher notifications and watching the wiki' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -135,34 +135,34 @@ wiki.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and not watching the wiki" do + context 'with the user having registered for watcher notifications and not watching the wiki' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "with an updated wiki page" do + context 'with an updated wiki page' do before do resource.text = "Some new text to create a journal" resource.save! end - context "with the user having registered for all notifications" do - it_behaves_like "creates notification" do + context 'with the user having registered for all notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -174,37 +174,37 @@ end end - context "with the user having registered for assignee notifications" do + context 'with the user having registered for assignee notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for responsible notifications" do + context 'with the user having registered for responsible notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(responsible: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for no notifications" do + context 'with the user having registered for no notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the wiki" do + context 'with the user having registered for watcher notifications and watching the wiki' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -215,7 +215,7 @@ wiki.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -227,7 +227,7 @@ end end - context "with the user not having registered for watcher notifications and watching the wiki" do + context 'with the user not having registered for watcher notifications and watching the wiki' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -238,20 +238,20 @@ wiki.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and not watching the wiki nor the page" do + context 'with the user having registered for watcher notifications and not watching the wiki nor the page' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for watcher notifications and watching the page" do + context 'with the user having registered for watcher notifications and watching the page' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) @@ -262,7 +262,7 @@ wiki_page.watcher_users << recipient end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: nil, @@ -274,7 +274,7 @@ end end - context "with the user not having registered for watcher notifications and watching the page" do + context 'with the user not having registered for watcher notifications and watching the page' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) @@ -285,13 +285,13 @@ wiki_page.watcher_users << recipient end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with the user having registered for all notifications but lacking permissions" do + context 'with the user having registered for all notifications but lacking permissions' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end end diff --git a/spec/services/notifications/create_from_model_service_work_package_spec.rb b/spec/services/notifications/create_from_model_service_work_package_spec.rb index 6c28374eb004..668f432ca4c8 100644 --- a/spec/services/notifications/create_from_model_service_work_package_spec.rb +++ b/spec/services/notifications/create_from_model_service_work_package_spec.rb @@ -25,17 +25,17 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "create_from_journal_job_shared" +require 'spec_helper' +require_relative 'create_from_journal_job_shared' RSpec.describe Notifications::CreateFromModelService, - "work_package", + 'work_package', with_settings: { journal_aggregation_time_minutes: 0 } do subject(:call) do described_class.new(journal).call(send_notifications) end - include_context "with CreateFromJournalJob context" + include_context 'with CreateFromJournalJob context' let(:permissions) { [:view_work_packages] } let(:author) { user_property == :author ? recipient : other_user } @@ -76,7 +76,7 @@ let(:resource) { work_package } let(:journal) { work_package.journals.first } let(:journal_2_with_notes) do - work_package.add_journal user: author, notes: "something I have to say" + work_package.add_journal user: author, notes: 'something I have to say' work_package.save(validate: false) work_package.journals.last end @@ -108,7 +108,7 @@ login_as(author) end - context "when user is assignee" do + context 'when user is assignee' do let(:user_property) { :assigned_to } let(:recipient_notification_settings) do [ @@ -116,7 +116,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -127,14 +127,14 @@ end end - context "when assignee has all app notification reasons enabled" do + context 'when assignee has all app notification reasons enabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -146,24 +146,24 @@ end end - context "when assignee has all notifications disabled" do + context 'when assignee has all notifications disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when assignee has all in app notifications enabled but only assignee for mail" do + context 'when assignee has all in app notifications enabled but only assignee for mail' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(assignee: true)) ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -175,19 +175,19 @@ end end - context "when assignee is not allowed to view work packages" do + context 'when assignee is not allowed to view work packages' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when assignee is placeholder user" do + context 'when assignee is placeholder user' do let(:recipient) { create(:placeholder_user) } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when assignee has all notifications enabled but made the change himself" do + context 'when assignee has all notifications enabled but made the change himself' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) @@ -195,11 +195,11 @@ end let(:author) { recipient } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when user is responsible" do + context 'when user is responsible' do let(:user_property) { :responsible } let(:recipient_notification_settings) do [ @@ -207,7 +207,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -218,29 +218,29 @@ end end - context "when responsible has all notifications disabled" do + context 'when responsible has all notifications disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when responsible is not allowed to view work packages" do + context 'when responsible is not allowed to view work packages' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when responsible is placeholder user" do + context 'when responsible is placeholder user' do let(:recipient) { create(:placeholder_user) } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when responsible has all notifications enabled but made the change himself" do + context 'when responsible has all notifications enabled but made the change himself' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) @@ -248,11 +248,11 @@ end let(:author) { recipient } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when user is watcher" do + context 'when user is watcher' do let(:user_property) { :watcher } let(:recipient_notification_settings) do [ @@ -260,7 +260,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -271,14 +271,14 @@ end end - context "when watcher has in app notifications disabled" do + context 'when watcher has in app notifications disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(watched: true)) ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -290,23 +290,23 @@ end end - context "when watcher has all notifications disabled" do + context 'when watcher has all notifications disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when watcher is not allowed to view work packages" do + context 'when watcher is not allowed to view work packages' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when watcher has all notifications enabled but made the change himself" do + context 'when watcher has all notifications enabled but made the change himself' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) @@ -314,11 +314,11 @@ end let(:author) { recipient } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when user is notified about everything" do + context 'when user is notified about everything' do let(:user_property) { nil } let(:recipient_notification_settings) do @@ -327,7 +327,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -338,14 +338,14 @@ end end - context "with in app notifications disabled" do + context 'with in app notifications disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -357,17 +357,17 @@ end end - context "with all disabled" do + context 'with all disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "with all disabled as a default but enabled in the project" do + context 'with all disabled as a default but enabled in the project' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false), @@ -375,7 +375,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -387,7 +387,7 @@ end end - context "with all enabled as a default but disabled in the project" do + context 'with all enabled as a default but disabled in the project' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true), @@ -395,16 +395,16 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when not allowed to view work packages" do + context 'when not allowed to view work packages' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when recipient has all notifications enabled but made the change himself" do + context 'when recipient has all notifications enabled but made the change himself' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) @@ -412,11 +412,11 @@ end let(:author) { recipient } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the work package is shared with the user" do + context 'when the work package is shared with the user' do let(:user_property) { :shared } let(:recipient_notification_settings) do [ @@ -424,7 +424,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -435,23 +435,23 @@ end end - context "when the shared with user has all notifications disabled" do + context 'when the shared with user has all notifications disabled' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when the shared with user is not allowed to view work packages" do + context 'when the shared with user is not allowed to view work packages' do let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when the shared with user has all notifications enabled but made the change himself" do + context 'when the shared with user has all notifications enabled but made the change himself' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_true) @@ -459,12 +459,12 @@ end let(:author) { recipient } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when a work package is created" do - context "when the user configured to be notified on work package creation" do + context 'when a work package is created' do + context 'when the user configured to be notified on work package creation' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -472,7 +472,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -484,7 +484,7 @@ end end - context "when the user configured to be notified on work package status changes" do + context 'when the user configured to be notified on work package status changes' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -492,10 +492,10 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when the user configured to be notified on work package priority changes" do + context 'when the user configured to be notified on work package priority changes' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -503,24 +503,24 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when the user did not configure to be notified" do + context 'when the user did not configure to be notified' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has a note" do + context 'when the journal has a note' do let(:journal) { journal_2_with_notes } - context "when the user has commented notifications activated" do + context 'when the user has commented notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -528,7 +528,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -540,21 +540,21 @@ end end - context "when the user has commented notifications deactivated" do + context 'when the user has commented notifications deactivated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has no note" do + context 'when the journal has no note' do let(:journal) { journal_2_with_status } - context "with the user having commented notifications activated" do + context 'with the user having commented notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -562,14 +562,14 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has status update" do + context 'when the journal has status update' do let(:journal) { journal_2_with_status } - context "when the user has processed notifications activated" do + context 'when the user has processed notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -577,7 +577,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -589,21 +589,21 @@ end end - context "when the user has processed notifications deactivated" do + context 'when the user has processed notifications deactivated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has no status update" do + context 'when the journal has no status update' do let(:journal) { journal_2_with_notes } - context "with the user having processed notifications activated" do + context 'with the user having processed notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -611,14 +611,14 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has priority" do + context 'when the journal has priority' do let(:journal) { journal_2_with_priority } - context "when the user has prioritized notifications activated" do + context 'when the user has prioritized notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -626,7 +626,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -638,21 +638,21 @@ end end - context "when the user has prioritized notifications deactivated" do + context 'when the user has prioritized notifications deactivated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has no priority update" do + context 'when the journal has no priority update' do let(:journal) { journal_2_with_status } - context "with the user having prioritized notifications activated" do + context 'with the user having prioritized notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -660,14 +660,14 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has a start date update" do + context 'when the journal has a start date update' do let(:journal) { journal_2_with_start_date } - context "when the user has scheduled notifications activated" do + context 'when the user has scheduled notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -675,7 +675,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -687,21 +687,21 @@ end end - context "when the user has scheduled notifications deactivated" do + context 'when the user has scheduled notifications deactivated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has no start or due date update" do + context 'when the journal has no start or due date update' do let(:journal) { journal_2_with_notes } - context "with the user having scheduled notifications activated" do + context 'with the user having scheduled notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -709,14 +709,14 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the journal has a due date update" do + context 'when the journal has a due date update' do let(:journal) { journal_2_with_due_date } - context "when the user has scheduled notifications activated" do + context 'when the user has scheduled notifications activated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false @@ -724,7 +724,7 @@ ] end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -736,18 +736,18 @@ end end - context "when the user has scheduled notifications deactivated" do + context 'when the user has scheduled notifications deactivated' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "when the author has been deleted" do + context 'when the author has been deleted' do let!(:deleted_user) { DeletedUser.first } let(:user_property) { :assigned_to } @@ -756,7 +756,7 @@ author.destroy end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:sender) { deleted_user } let(:notification_channel_reasons) do { @@ -769,17 +769,17 @@ end end - context "when user is mentioned" do + context 'when user is mentioned' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(mentioned: true)) ] end - shared_examples_for "group mention" do - context "with a group member allowed to view the work package" do - context "when the user wants to receive notifications" do - it_behaves_like "creates notification" do + shared_examples_for 'group mention' do + context 'with a group member allowed to view the work package' do + context 'when the user wants to receive notifications' do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -791,27 +791,27 @@ end end - context "when the user disabled mention notifications" do + context 'when the user disabled mention notifications' do let(:recipient_notification_settings) do [ build(:notification_setting, **notification_settings_all_false.merge(mentioned: false)) ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end - context "with the group not allowed to view the work package" do + context 'with the group not allowed to view the work package' do let(:group_role) { create(:project_role, permissions: []) } let(:permissions) { [] } - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' - context "with the group member allowed individually" do + context 'with the group member allowed individually' do let(:permissions) { [:view_work_packages] } - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -825,12 +825,12 @@ end end - shared_examples_for "mentioned" do - context "with users" do + shared_examples_for 'mentioned' do + context 'with users' do context "when the added text contains a login name as a pretty normal word" do let(:note) { "Hello user:\"#{recipient_login}\"" } - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -846,7 +846,7 @@ let(:note) { "Hello user:\"#{recipient_login}\"" } let(:recipient_login) { "foo@bar.com" } - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -861,7 +861,7 @@ context "when the added text contains a user ID" do let(:note) { "Hello user##{recipient.id}" } - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -880,7 +880,7 @@ NOTE end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -899,7 +899,7 @@ NOTE end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -919,7 +919,7 @@ NOTE end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end context "when the added text contains a user mention tag inside an invalid quote" do @@ -930,7 +930,7 @@ NOTE end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -950,7 +950,7 @@ NOTE end - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -973,7 +973,7 @@ "Hello user:\"#{recipient.login}\", hey user##{recipient.id}" end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end context "with the mentioned user not being allowed to view the work package" do @@ -982,16 +982,16 @@ "Hello user:#{recipient.login}, hey user##{recipient.id}" end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end - context "when the mentioned user made the change himself" do + context 'when the mentioned user made the change himself' do let(:note) do "Hello user:#{recipient.login}, hey user##{recipient.id}" end let(:author) { recipient } - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -1003,15 +1003,15 @@ end end - context "when there is already a notification for the journal (because it was aggregated)" do + context 'when there is already a notification for the journal (because it was aggregated)' do let(:note) { "Hello user:\"#{recipient_login}\"" } let!(:existing_notification) do create(:notification, resource:, journal:, recipient:, reason: :mentioned, read_ian: true) end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' - it "resets the read_ian of the existing notification to false" do + it 'resets the read_ian of the existing notification to false' do call expect(existing_notification.reload.read_ian) @@ -1019,15 +1019,15 @@ end end - context "when there is already a notification for the journal (aggregation) but the user is no longer mentioned" do + context 'when there is already a notification for the journal (aggregation) but the user is no longer mentioned' do let(:note) { "Hello you" } let!(:existing_notification) do create(:notification, resource:, journal:, recipient:, reason: :mentioned, read_ian: true) end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' - it "removes the existing notification" do + it 'removes the existing notification' do call expect(Notification) @@ -1036,7 +1036,7 @@ end end - context "for groups" do + context 'for groups' do let(:group_role) { create(:project_role, permissions: %i[view_work_packages]) } let(:group) do create(:group, members: recipient) do |group| @@ -1046,35 +1046,35 @@ end end - context "with a hash/id based mention" do + context 'with a hash/id based mention' do let(:note) do "Hello group##{group.id}" end - it_behaves_like "group mention" + it_behaves_like 'group mention' end - context "with a tag based mention with the type after" do + context 'with a tag based mention with the type after' do let(:note) do <<~NOTE Hello @#{group.name} NOTE end - it_behaves_like "group mention" + it_behaves_like 'group mention' end - context "with a tag based mention with the type before" do + context 'with a tag based mention with the type before' do let(:note) do <<~NOTE Hello @#{group.name} NOTE end - it_behaves_like "group mention" + it_behaves_like 'group mention' end - context "with the group member making the change himself" do + context 'with the group member making the change himself' do let(:note) do <<~NOTE Hello @#{group.name} @@ -1082,7 +1082,7 @@ end let(:author) { recipient } - it_behaves_like "creates notification" do + it_behaves_like 'creates notification' do let(:notification_channel_reasons) do { read_ian: false, @@ -1095,7 +1095,7 @@ end end - context "with users and groups" do + context 'with users and groups' do let(:group_role) { create(:project_role, permissions: %i[view_work_packages]) } let(:group) do create(:group, members: recipient) do |group| @@ -1112,7 +1112,7 @@ let(:notification_group_recipient) { build_stubbed(:notification, recipient:) } let(:notification_other_recipient) { build_stubbed(:notification, recipient: other_recipient) } - context "with two tag based mention in the same line" do + context 'with two tag based mention in the same line' do let(:note) do <<~NOTE.squish Hello @@ -1139,7 +1139,7 @@ } end - it "creates two notification and returns them" do + it 'creates two notification and returns them' do notifications_service = instance_double(Notifications::CreateService) allow(Notifications::CreateService) @@ -1169,7 +1169,7 @@ end end - describe "in the journal notes" do + describe 'in the journal notes' do let(:journal) { journal_2_with_notes } let(:journal_2_with_notes) do work_package.add_journal user: author, notes: note @@ -1182,10 +1182,10 @@ NOTE end - it_behaves_like "mentioned" + it_behaves_like 'mentioned' end - describe "in the description" do + describe 'in the description' do let(:journal) { journal_2_with_description } let(:journal_2_with_description) do work_package.description = note @@ -1193,10 +1193,10 @@ work_package.journals.last end - it_behaves_like "mentioned" + it_behaves_like 'mentioned' end - describe "in the subject" do + describe 'in the subject' do let(:journal) { journal_2_with_subject } let(:journal_2_with_subject) do work_package.subject = note @@ -1204,11 +1204,11 @@ work_package.journals.last end - it_behaves_like "mentioned" + it_behaves_like 'mentioned' end end - context "when on aggregating the journal, sending of notifications is prevented" do + context 'when on aggregating the journal, sending of notifications is prevented' do let!(:existing_notification) do create(:notification, resource:, journal:, recipient:, reason: :mentioned, read_ian: true) end @@ -1220,9 +1220,9 @@ ] end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' - it "removes the existing notifications" do + it 'removes the existing notifications' do call expect(Notification) @@ -1230,11 +1230,11 @@ end end - context "when the journal is deleted" do + context 'when the journal is deleted' do before do journal.destroy end - it_behaves_like "creates no notification" + it_behaves_like 'creates no notification' end end diff --git a/spec/services/notifications/create_service_intergration_spec.rb b/spec/services/notifications/create_service_intergration_spec.rb index adf33810063e..fbae6c67130f 100644 --- a/spec/services/notifications/create_service_intergration_spec.rb +++ b/spec/services/notifications/create_service_intergration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Notifications::CreateService, "integration", type: :model do +RSpec.describe Notifications::CreateService, 'integration', type: :model do let(:work_package) { create(:work_package) } let(:project) { work_package.project } let(:journal) { work_package.journals.first } @@ -43,7 +43,7 @@ current_user { create(:user) } - describe "#call" do + describe '#call' do let(:attributes) do { recipient:, @@ -58,7 +58,7 @@ } end - it "creates a notification" do + it 'creates a notification' do # successful expect { service_result } .to change(Notification, :count) @@ -68,12 +68,12 @@ .to be_success end - context "with the journal being deleted in the meantime (e.g. via a different process)" do + context 'with the journal being deleted in the meantime (e.g. via a different process)' do before do Journal.where(id: journal.id).delete_all end - it "creates no notification" do + it 'creates no notification' do # successful expect { service_result } .not_to change(Notification, :count) diff --git a/spec/services/notifications/create_service_spec.rb b/spec/services/notifications/create_service_spec.rb index b21b53f21899..70a6befc1b7a 100644 --- a/spec/services/notifications/create_service_spec.rb +++ b/spec/services/notifications/create_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Notifications::CreateService, type: :model do - it_behaves_like "BaseServices create service" + it_behaves_like 'BaseServices create service' end diff --git a/spec/services/notifications/mail_service_mentioned_integration_spec.rb b/spec/services/notifications/mail_service_mentioned_integration_spec.rb index 22bb27e282ef..b31521b207a1 100644 --- a/spec/services/notifications/mail_service_mentioned_integration_spec.rb +++ b/spec/services/notifications/mail_service_mentioned_integration_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "mentioned_journals_shared" +require 'spec_helper' +require_relative 'mentioned_journals_shared' -RSpec.describe Notifications::MailService, "Mentioned integration", type: :model do - include_context "with a mentioned work package being updated again" +RSpec.describe Notifications::MailService, 'Mentioned integration', type: :model do + include_context 'with a mentioned work package being updated again' let(:assignee) do create(:user, @@ -56,7 +56,7 @@ def expect_mentioned_notification expect(mentioned_notification).to be_present mentioned_notification.reload expect(mentioned_notification.recipient).to eq recipient - expect(mentioned_notification.reason).to eq "mentioned" + expect(mentioned_notification.reason).to eq 'mentioned' expect(mentioned_notification.read_ian).to be false expect(mentioned_notification.mail_alert_sent).to be true end @@ -78,7 +78,7 @@ def expect_assigned_notification expect(assigned_notification.mail_alert_sent).to be false end - it "triggers only one mention notification mail when editing attributes afterwards" do + it 'triggers only one mention notification mail when editing attributes afterwards' do allow(WorkPackageMailer) .to receive(:mentioned) .and_call_original diff --git a/spec/services/notifications/mail_service_spec.rb b/spec/services/notifications/mail_service_spec.rb index a6e1125c3255..6b5550af8ded 100644 --- a/spec/services/notifications/mail_service_spec.rb +++ b/spec/services/notifications/mail_service_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::MailService, type: :model do - require_relative "mentioned_journals_shared" + require_relative 'mentioned_journals_shared' subject(:call) { instance.call } @@ -48,7 +48,7 @@ let(:instance) { described_class.new(notification) } let(:immediate_reminders_mentioned) { true } - context "with a work package journal notification" do + context 'with a work package journal notification' do let(:journal) do build_stubbed(:work_package_journal).tap do |j| allow(j) @@ -85,8 +85,8 @@ mail end - shared_examples_for "sends a mentioned mail" do - it "sends a mail" do + shared_examples_for 'sends a mentioned mail' do + it 'sends a mail' do call expect(WorkPackageMailer) @@ -99,8 +99,8 @@ end end - shared_examples_for "sends no mentioned mail" do - it "sends no mail" do + shared_examples_for 'sends no mentioned mail' do + it 'sends no mail' do call expect(WorkPackageMailer) @@ -108,24 +108,24 @@ end end - context "with the notification mentioning the user" do - it_behaves_like "sends a mentioned mail" + context 'with the notification mentioning the user' do + it_behaves_like 'sends a mentioned mail' end - context "with the notification not mentioning the user" do + context 'with the notification not mentioning the user' do let(:reason) { false } - it_behaves_like "sends no mentioned mail" + it_behaves_like 'sends no mentioned mail' end - context "with the notification mentioning the user but with the recipient having deactivated the mail" do + context 'with the notification mentioning the user but with the recipient having deactivated the mail' do let(:immediate_reminders_mentioned) { false } - it_behaves_like "sends no mentioned mail" + it_behaves_like 'sends no mentioned mail' end end - context "with a wiki_content journal notification" do + context 'with a wiki_content journal notification' do let(:journal) do build_stubbed(:wiki_page_journal, journable: build_stubbed(:wiki_page)).tap do |j| @@ -164,10 +164,10 @@ mail end - context "with the notification being for an initial journal" do + context 'with the notification being for an initial journal' do let(:journal_initial) { true } - it "sends a mail" do + it 'sends a mail' do call expect(UserMailer) @@ -180,10 +180,10 @@ end end - context "with the notification being for an update journal" do + context 'with the notification being for an update journal' do let(:journal_initial) { false } - it "sends a mail" do + it 'sends a mail' do call expect(UserMailer) @@ -196,10 +196,10 @@ end end - context "with the notification read in app already" do + context 'with the notification read in app already' do let(:read_ian) { true } - it "sends no mail" do + it 'sends no mail' do call expect(UserMailer) @@ -210,7 +210,7 @@ end end - context "with a news journal notification" do + context 'with a news journal notification' do let(:journal) do build_stubbed(:news_journal, journable: build_stubbed(:news)).tap do |j| @@ -243,10 +243,10 @@ mail end - context "with the notification being for an initial journal" do + context 'with the notification being for an initial journal' do let(:journal_initial) { true } - it "sends a mail" do + it 'sends a mail' do call expect(UserMailer) @@ -261,10 +261,10 @@ # This case should not happen as no notification is created in this case that would # trigger the NotificationJob. But as this might change, this test case is in place. - context "with the notification being for an update journal" do + context 'with the notification being for an update journal' do let(:journal_initial) { false } - it "sends no mail" do + it 'sends no mail' do call expect(UserMailer) @@ -273,7 +273,7 @@ end end - context "with a message journal notification" do + context 'with a message journal notification' do let(:journal) do build_stubbed(:message_journal, journable: build_stubbed(:message)) @@ -304,7 +304,7 @@ mail end - it "sends a mail" do + it 'sends a mail' do call expect(UserMailer) @@ -316,10 +316,10 @@ .to have_received(:deliver_now) end - context "with the notification read in app already" do + context 'with the notification read in app already' do let(:read_ian) { true } - it "sends no mail" do + it 'sends no mail' do call expect(UserMailer) @@ -328,7 +328,7 @@ end end - context "with a different journal notification" do + context 'with a different journal notification' do let(:journal) do build_stubbed(:journal, journable: build_stubbed(:work_package)) @@ -341,12 +341,12 @@ end # did that before - it "does nothing" do + it 'does nothing' do expect { call } .not_to raise_error(ArgumentError) end - it "does not send a mail" do + it 'does not send a mail' do expect { call } .not_to change(ActionMailer::Base.deliveries, :count) end diff --git a/spec/services/notifications/mentioned_journals_shared.rb b/spec/services/notifications/mentioned_journals_shared.rb index acce6710304d..dc4167644e76 100644 --- a/spec/services/notifications/mentioned_journals_shared.rb +++ b/spec/services/notifications/mentioned_journals_shared.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_context "with a mentioned work package being updated again" do +RSpec.shared_context 'with a mentioned work package being updated again' do let(:project) { create(:project) } let(:work_package) do diff --git a/spec/services/notifications/set_attributes_service_spec.rb b/spec/services/notifications/set_attributes_service_spec.rb index 673261eec66b..9bd08c3d1373 100644 --- a/spec/services/notifications/set_attributes_service_spec.rb +++ b/spec/services/notifications/set_attributes_service_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } let(:contract_class) do - contract = double("contract_class") + contract = double('contract_class') allow(contract) .to receive(:new) @@ -41,11 +41,11 @@ contract end let(:contract_instance) do - double("contract_instance", validate: contract_valid, errors: contract_errors) + double('contract_instance', validate: contract_valid, errors: contract_errors) end let(:contract_valid) { true } let(:contract_errors) do - double("contract_errors") + double('contract_errors') end let(:member_valid) { true } let(:instance) do @@ -59,10 +59,10 @@ let(:journal) { build_stubbed(:journal, journable:, data: journal_data) } let(:journable) { nil } let(:journal_data) { nil } - let(:event_subject) { "I find it important" } + let(:event_subject) { 'I find it important' } let(:recipient_id) { 1 } - describe "call" do + describe 'call' do let(:call_attributes) do { recipient_id:, @@ -76,23 +76,23 @@ subject { instance.call(call_attributes) } - context "for a new record" do + context 'for a new record' do let(:event) do Notification.new end - it "is successful" do + it 'is successful' do expect(subject) .to be_success end - it "sets the attributes add adds default values" do + it 'sets the attributes add adds default values' do subject expect(event.attributes.compact.symbolize_keys) .to eql({ project_id: project.id, - reason: "mentioned", + reason: 'mentioned', journal_id: journal.id, recipient_id: 1, subject: event_subject, @@ -101,7 +101,7 @@ }) end - context "with only the minimal set of attributes for a notification" do + context 'with only the minimal set of attributes for a notification' do let(:journable) do build_stubbed(:work_package, project:).tap do |wp| allow(wp) @@ -121,15 +121,15 @@ } end - it "sets the attributes and adds default values that are deduced" do + it 'sets the attributes and adds default values that are deduced' do subject expect(event.attributes.compact.symbolize_keys) .to eql({ project_id: project.id, - reason: "mentioned", + reason: 'mentioned', resource_id: journable.id, - resource_type: "WorkPackage", + resource_type: 'WorkPackage', journal_id: journal.id, recipient_id: 1, read_ian: false, @@ -138,7 +138,7 @@ end end - it "does not persist the notification" do + it 'does not persist the notification' do expect(event) .not_to receive(:save) diff --git a/spec/services/oauth_clients/create_service_spec.rb b/spec/services/oauth_clients/create_service_spec.rb index 3397138bb4ff..54128d630c7a 100644 --- a/spec/services/oauth_clients/create_service_spec.rb +++ b/spec/services/oauth_clients/create_service_spec.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe OAuthClients::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:factory) { :oauth_client } - context "if another oauth client for the given integration exists" do + context 'if another oauth client for the given integration exists' do let(:storage) { create(:nextcloud_storage) } let!(:existing_client) { create(:oauth_client, integration: storage) } let!(:model_instance) { build_stubbed(:oauth_client, integration: storage) } - let(:call_attributes) { { name: "Death Star", integration: storage } } + let(:call_attributes) { { name: 'Death Star', integration: storage } } - it "overwrites the existing oauth client" do + it 'overwrites the existing oauth client' do # Test setup still returns success, but `subject` must be initialized expect(subject).to be_success expect(OAuthClient.where(id: existing_client.id)).not_to exist diff --git a/spec/services/oauth_clients/delete_service_spec.rb b/spec/services/oauth_clients/delete_service_spec.rb index ff65fbdd375f..34d904f392dd 100644 --- a/spec/services/oauth_clients/delete_service_spec.rb +++ b/spec/services/oauth_clients/delete_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_delete_service" +require 'spec_helper' +require 'services/base_services/behaves_like_delete_service' RSpec.describe OAuthClients::DeleteService, type: :model do - it_behaves_like "BaseServices delete service" do + it_behaves_like 'BaseServices delete service' do let(:factory) { :oauth_client } end end diff --git a/spec/services/oauth_clients/one_drive_connection_manager_spec.rb b/spec/services/oauth_clients/one_drive_connection_manager_spec.rb index 9f530e21b350..8991e5f1d859 100644 --- a/spec/services/oauth_clients/one_drive_connection_manager_spec.rb +++ b/spec/services/oauth_clients/one_drive_connection_manager_spec.rb @@ -104,7 +104,7 @@ it 'always add the necessary scopes' do uri = connection_manager.get_authorization_uri(state: nil) - expect(uri).to include CGI.escape(storage.oauth_configuration.scope.join(' ')) + expect(uri).to include storage.oauth_configuration.scope.join('%20') end it 'adds the state if present' do diff --git a/spec/services/oauth_clients/redirect_uri_from_state_service_spec.rb b/spec/services/oauth_clients/redirect_uri_from_state_service_spec.rb index 1fd08f8761b7..d4b88ebb38c7 100644 --- a/spec/services/oauth_clients/redirect_uri_from_state_service_spec.rb +++ b/spec/services/oauth_clients/redirect_uri_from_state_service_spec.rb @@ -26,47 +26,47 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OAuthClients::RedirectUriFromStateService, type: :model do - let(:state) { "asdf123425" } - let(:redirect_uri) { File.join(API::V3::Utilities::PathHelper::ApiV3Path::root_url, "foo/bar") } + let(:state) { 'asdf123425' } + let(:redirect_uri) { File.join(API::V3::Utilities::PathHelper::ApiV3Path::root_url, 'foo/bar') } let(:cookies) { { "oauth_state_#{state}": { href: redirect_uri }.to_json }.with_indifferent_access } let(:instance) { described_class.new(state:, cookies:) } - describe "#call" do + describe '#call' do subject { instance.call } - shared_examples "failed service result" do - it "return a failed service result" do + shared_examples 'failed service result' do + it 'return a failed service result' do expect(subject).to be_failure end end - context "when cookie found" do - context "when redirect_uri has same origin" do - it "returns the redirect URL value from the cookie" do + context 'when cookie found' do + context 'when redirect_uri has same origin' do + it 'returns the redirect URL value from the cookie' do expect(subject).to be_success end end - context "when redirect_uri does not share same origin" do - let(:redirect_uri) { "https://some-other-origin.com/bla" } + context 'when redirect_uri does not share same origin' do + let(:redirect_uri) { 'https://some-other-origin.com/bla' } - it_behaves_like "failed service result" + it_behaves_like 'failed service result' end end - context "when no cookie present" do + context 'when no cookie present' do let(:cookies) { {} } - it_behaves_like "failed service result" + it_behaves_like 'failed service result' end - context "when no state present" do + context 'when no state present' do let(:state) { nil } - it_behaves_like "failed service result" + it_behaves_like 'failed service result' end end end diff --git a/spec/services/oauth_clients/set_attributes_service_spec.rb b/spec/services/oauth_clients/set_attributes_service_spec.rb index 5136b328b97b..c9346b51bc24 100644 --- a/spec/services/oauth_clients/set_attributes_service_spec.rb +++ b/spec/services/oauth_clients/set_attributes_service_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe OAuthClients::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:admin) } let(:contract_instance) do - contract = instance_double(OAuthClients::CreateContract, "contract_instance") + contract = instance_double(OAuthClients::CreateContract, 'contract_instance') allow(contract) .to receive(:validate) .and_return(contract_valid) @@ -42,7 +42,7 @@ contract end - let(:contract_errors) { instance_double(ActiveModel::Errors, "contract_errors") } + let(:contract_errors) { instance_double(ActiveModel::Errors, 'contract_errors') } let(:contract_valid) { true } let(:model_valid) { true } @@ -68,21 +68,21 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result) .to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with params" do + context 'with params' do let(:params) do { - client_id: "0123456789-client_id", - client_secret: "1234567890-client_secret" + client_id: '0123456789-client_id', + client_secret: '1234567890-client_secret' } end @@ -90,16 +90,16 @@ subject end - it "assigns the params" do - expect(model_instance.client_id).to eq "0123456789-client_id" - expect(model_instance.client_secret).to eq "1234567890-client_secret" + it 'assigns the params' do + expect(model_instance.client_id).to eq '0123456789-client_id' + expect(model_instance.client_secret).to eq '1234567890-client_secret' end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } - it "returns failure" do + it 'returns failure' do expect(subject).not_to be_success end diff --git a/spec/services/params_to_query_service_capability_query_spec.rb b/spec/services/params_to_query_service_capability_query_spec.rb index b394e0d0cdce..cfddd7a7d84d 100644 --- a/spec/services/params_to_query_service_capability_query_spec.rb +++ b/spec/services/params_to_query_service_capability_query_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe ParamsToQueryService, "capability query" do +RSpec.describe ParamsToQueryService, 'capability query' do # This spec does currently not cover the whole functionality. let(:user) { build_stubbed(:admin) } let(:model) { Capability } @@ -36,20 +36,20 @@ let(:instance) { described_class.new(model, user) } let(:service_call) { instance.call(params) } - context "for a new query" do - context "when applying filters" do + context 'for a new query' do + context 'when applying filters' do let(:params) do { filters: JSON.dump([{ principal: { operator: "=", values: ["4"] } }, { context: { operator: "=", values: ["g"] } }, { action: { operator: "=", values: ["projects/create"] } }]) } end - it "returns a new query" do + it 'returns a new query' do expect(service_call) .to be_a Queries::Capabilities::CapabilityQuery end - it "applies the filters" do + it 'applies the filters' do expect(service_call.filters.map { |f| { field: f.field, operator: f.operator, values: f.values } }) .to contain_exactly({ field: :principal_id, operator: "=", values: ["4"] }, { field: :context, operator: "=", values: ["g"] }, diff --git a/spec/services/params_to_query_service_project_query_spec.rb b/spec/services/params_to_query_service_project_query_spec.rb index 9fbf8351f625..5f3f771b6841 100644 --- a/spec/services/params_to_query_service_project_query_spec.rb +++ b/spec/services/params_to_query_service_project_query_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' -RSpec.describe ParamsToQueryService, "project query" do +RSpec.describe ParamsToQueryService, 'project query' do # This spec does currently not cover the whole functionality. let(:user) { build_stubbed(:admin) } @@ -37,42 +37,42 @@ let(:instance) { described_class.new(model, user) } let(:service_call) { instance.call(params) } - context "for a new query" do - context "when applying filters" do + context 'for a new query' do + context 'when applying filters' do let(:params) do { filters: JSON.dump([{ active: { operator: "=", values: ["t"] } }, { created_at: { operator: ">t-", values: ["4"] } }]) } end - it "returns a new query" do + it 'returns a new query' do expect(service_call) .to be_a Queries::Projects::ProjectQuery end - it "applies the filters" do + it 'applies the filters' do expect(service_call.filters.map { |f| { field: f.field, operator: f.operator, values: f.values } }) .to contain_exactly({ field: :active, operator: "=", values: ["t"] }, { field: :created_at, operator: ">t-", values: ["4"] }) end end - context "when sending neither filters nor orders props" do - it "returns a new query" do + context 'when sending neither filters nor orders props' do + it 'returns a new query' do expect(service_call) .to be_a Queries::Projects::ProjectQuery end - it "sets no name" do + it 'sets no name' do expect(service_call.name) .to be_blank end - it "applies no filter" do + it 'applies no filter' do expect(service_call.filters) .to be_empty end - it "does not apply sorting" do + it 'does not apply sorting' do expect(service_call.orders) .to be_empty end diff --git a/spec/services/parse_schema_filter_params_service_spec.rb b/spec/services/parse_schema_filter_params_service_spec.rb index de29a6321787..acd11fccd24a 100644 --- a/spec/services/parse_schema_filter_params_service_spec.rb +++ b/spec/services/parse_schema_filter_params_service_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe ParseSchemaFilterParamsService do let(:current_user) { build_stubbed(:user) } @@ -33,9 +33,9 @@ let(:project) { build_stubbed(:project) } let(:type) { build_stubbed(:type) } - describe "#call" do + describe '#call' do let(:filter) do - [{ "id" => { "values" => ["#{project.id}-#{type.id}"], "operator" => "=" } }] + [{ 'id' => { 'values' => ["#{project.id}-#{type.id}"], 'operator' => '=' } }] end let(:result) { instance.call(filter) } @@ -43,7 +43,7 @@ let(:found_types) { [type] } before do - visible_projects = double("visible_projects") + visible_projects = double('visible_projects') allow(Project) .to receive(:visible) @@ -61,91 +61,91 @@ .and_return(found_types) end - context "valid" do - it "is a success" do + context 'valid' do + it 'is a success' do expect(result).to be_success end - it "returns the [project, type] pair" do + it 'returns the [project, type] pair' do expect(result.result).to contain_exactly([project, type]) end end - context "for a non existing project" do + context 'for a non existing project' do let(:found_projects) { [] } - it "is a success" do + it 'is a success' do expect(result).to be_success end - it "returns an empty array" do + it 'returns an empty array' do expect(result.result).to be_empty end end - context "for a non existing type" do + context 'for a non existing type' do let(:found_types) { [] } - it "is a success" do + it 'is a success' do expect(result).to be_success end - it "returns an empty array" do + it 'returns an empty array' do expect(result.result).to be_empty end end context 'without the "=" operator' do let(:filter) do - [{ "id" => { "values" => ["#{project.id}-#{type.id}"], "operator" => "!" } }] + [{ 'id' => { 'values' => ["#{project.id}-#{type.id}"], 'operator' => '!' } }] end - it "is a failure" do + it 'is a failure' do expect(result).not_to be_success end - it "returns an empty array" do + it 'returns an empty array' do expect(result.result).to be_nil end - it "returns an error message" do - expect(result.errors.messages[:base]).to contain_exactly("The operator is not supported.") + it 'returns an error message' do + expect(result.errors.messages[:base]).to contain_exactly('The operator is not supported.') end end - context "with an invalid value" do + context 'with an invalid value' do let(:filter) do - [{ "id" => { "values" => ["bogus-1"], "operator" => "=" } }] + [{ 'id' => { 'values' => ["bogus-1"], 'operator' => "=" } }] end - it "is a failure" do + it 'is a failure' do expect(result).not_to be_success end - it "returns an empty array" do + it 'returns an empty array' do expect(result.result).to be_nil end - it "returns an error message" do - expect(result.errors.messages[:base]).to contain_exactly("A value is invalid.") + it 'returns an error message' do + expect(result.errors.messages[:base]).to contain_exactly('A value is invalid.') end end - context "without an id filter" do + context 'without an id filter' do let(:filter) do [{}] end - it "is a failure" do + it 'is a failure' do expect(result).not_to be_success end - it "returns an empty array" do + it 'returns an empty array' do expect(result.result).to be_nil end - it "returns an error message" do - expect(result.errors.messages[:base]).to contain_exactly("An 'id' filter is required.") + it 'returns an error message' do + expect(result.errors.messages[:base]).to contain_exactly('An \'id\' filter is required.') end end end diff --git a/spec/services/placeholder_users/create_service_spec.rb b/spec/services/placeholder_users/create_service_spec.rb index b5f32e286e54..adf66d7d236d 100644 --- a/spec/services/placeholder_users/create_service_spec.rb +++ b/spec/services/placeholder_users/create_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe PlaceholderUsers::CreateService, type: :model do - it_behaves_like "BaseServices create service" + it_behaves_like 'BaseServices create service' end diff --git a/spec/services/placeholder_users/delete_service_spec.rb b/spec/services/placeholder_users/delete_service_spec.rb index f1d4838bc1fa..24c1592a430e 100644 --- a/spec/services/placeholder_users/delete_service_spec.rb +++ b/spec/services/placeholder_users/delete_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe PlaceholderUsers::DeleteService, type: :model do let(:placeholder_user) { build_stubbed(:placeholder_user) } @@ -36,7 +36,7 @@ subject { instance.call } - shared_examples "deletes the user" do + shared_examples 'deletes the user' do it do expect(placeholder_user).to receive(:locked!) expect(Principals::DeleteJob).to receive(:perform_later).with(placeholder_user) @@ -44,7 +44,7 @@ end end - shared_examples "does not delete the user" do + shared_examples 'does not delete the user' do it do expect(placeholder_user).not_to receive(:locked!) expect(Principals::DeleteJob).not_to receive(:perform_later) @@ -52,13 +52,13 @@ end end - context "with admin user" do + context 'with admin user' do let(:actor) { build_stubbed(:admin) } - it_behaves_like "deletes the user" + it_behaves_like 'deletes the user' end - context "with global user" do + context 'with global user' do let(:actor) { build_stubbed(:user) } before do @@ -67,23 +67,23 @@ end end - it_behaves_like "deletes the user" + it_behaves_like 'deletes the user' end - context "with unprivileged system user" do + context 'with unprivileged system user' do let(:actor) { User.system } before do allow(actor).to receive(:admin?).and_return false end - it_behaves_like "does not delete the user" + it_behaves_like 'does not delete the user' end - context "with privileged system user" do + context 'with privileged system user' do let(:actor) { User.system } - it_behaves_like "deletes the user" do + it_behaves_like 'deletes the user' do around do |example| actor.run_given { example.run } end diff --git a/spec/services/placeholder_users/set_attributes_service_spec.rb b/spec/services/placeholder_users/set_attributes_service_spec.rb index a9c6267cb490..5e5cad922ea5 100644 --- a/spec/services/placeholder_users/set_attributes_service_spec.rb +++ b/spec/services/placeholder_users/set_attributes_service_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe PlaceholderUsers::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:user) } let(:contract_instance) do - contract = double("contract_instance") + contract = double('contract_instance') allow(contract) .to receive(:validate) .and_return(contract_valid) @@ -42,7 +42,7 @@ contract end - let(:contract_errors) { double("contract_errors") } + let(:contract_errors) { double('contract_errors') } let(:contract_valid) { true } let(:model_valid) { true } @@ -71,39 +71,39 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result) .to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with params" do + context 'with params' do let(:params) do { - name: "Foobar" + name: 'Foobar' } end - it "assigns the params" do + it 'assigns the params' do subject - expect(model_instance.name).to eq "Foobar" - expect(model_instance.lastname).to eq "Foobar" + expect(model_instance.name).to eq 'Foobar' + expect(model_instance.lastname).to eq 'Foobar' end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } let(:expect_time_instance_save) do expect(model_instance) .not_to receive(:save) end - it "returns failure" do + it 'returns failure' do expect(subject) .not_to be_success end diff --git a/spec/services/placeholder_users/update_service_spec.rb b/spec/services/placeholder_users/update_service_spec.rb index 8ccbf5a34300..2c694fea3ba5 100644 --- a/spec/services/placeholder_users/update_service_spec.rb +++ b/spec/services/placeholder_users/update_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe PlaceholderUsers::UpdateService, type: :model do - it_behaves_like "BaseServices update service" + it_behaves_like 'BaseServices update service' end diff --git a/spec/services/principals/replace_references_service_call_integration_spec.rb b/spec/services/principals/replace_references_service_call_integration_spec.rb index 299b9e724911..9ebf4a58d83c 100644 --- a/spec/services/principals/replace_references_service_call_integration_spec.rb +++ b/spec/services/principals/replace_references_service_call_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Principals::ReplaceReferencesService, "#call", type: :model do +RSpec.describe Principals::ReplaceReferencesService, '#call', type: :model do subject(:service_call) { instance.call(from: principal, to: to_principal) } shared_let(:other_user) { create(:user) } @@ -39,21 +39,21 @@ described_class.new end - context "with a user" do + context 'with a user' do let(:principal) { user } - it "is successful" do + it 'is successful' do expect(service_call) .to be_success end - context "with a Journal" do + context 'with a Journal' do let!(:journal) do create(:work_package_journal, user_id:) end - context "with the replaced user" do + context 'with the replaced user' do let(:user_id) { principal.id } before do @@ -61,13 +61,13 @@ journal.reload end - it "replaces user_id" do + it 'replaces user_id' do expect(journal.user_id) .to eql to_principal.id end end - context "with a different user" do + context 'with a different user' do let(:user_id) { other_user.id } before do @@ -75,14 +75,14 @@ journal.reload end - it "replaces user_id" do + it 'replaces user_id' do expect(journal.user_id) .to eql other_user.id end end end - shared_examples_for "rewritten record" do |factory, attribute, format = Integer| + shared_examples_for 'rewritten record' do |factory, attribute, format = Integer| let!(:model) do klass = FactoryBot.factories.find(factory).build_class all_attributes = other_attributes.merge(attribute => principal_id) @@ -95,7 +95,7 @@ RETURNING id SQL - klass.find(inserted["id"]) + klass.find(inserted['id']) end let(:other_attributes) do @@ -111,7 +111,7 @@ def expected(user, format) end context "for #{factory}" do - context "with the replaced user" do + context 'with the replaced user' do let(:principal_id) { principal.id } before do @@ -125,7 +125,7 @@ def expected(user, format) end end - context "with a different user" do + context 'with a different user' do let(:principal_id) { other_user.id } before do @@ -141,12 +141,12 @@ def expected(user, format) end end - context "with Attachment" do - it_behaves_like "rewritten record", + context 'with Attachment' do + it_behaves_like 'rewritten record', :attachment, :author_id - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_attachment_journal, :author_id do let(:attributes) do @@ -161,10 +161,10 @@ def expected(user, format) end end - context "with Comment" do + context 'with Comment' do shared_let(:news) { create(:news) } - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :comment, :author_id do let(:attributes) do @@ -176,10 +176,10 @@ def expected(user, format) end end - context "with CustomValue" do + context 'with CustomValue' do shared_let(:version) { create(:version) } - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :custom_value, :value, String do @@ -193,7 +193,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_customizable_journal, :value, String do @@ -207,8 +207,8 @@ def expected(user, format) end end - context "with Changeset" do - it_behaves_like "rewritten record", + context 'with Changeset' do + it_behaves_like 'rewritten record', :changeset, :user_id do let(:attributes) do @@ -218,7 +218,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_changeset_journal, :user_id do let(:attributes) do @@ -229,8 +229,8 @@ def expected(user, format) end end - context "with Message" do - it_behaves_like "rewritten record", + context 'with Message' do + it_behaves_like 'rewritten record', :message, :author_id do let(:attributes) do @@ -241,7 +241,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_message_journal, :author_id do let(:attributes) do @@ -253,28 +253,28 @@ def expected(user, format) end end - context "with MeetingContent" do - it_behaves_like "rewritten record", + context 'with MeetingContent' do + it_behaves_like 'rewritten record', :meeting_agenda, :author_id do let(:attributes) do { type: "'MeetingAgenda'", - created_at: "NOW()", - updated_at: "NOW()" } + created_at: 'NOW()', + updated_at: 'NOW()' } end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :meeting_minutes, :author_id do let(:attributes) do { type: "'MeetingMinutes'", - created_at: "NOW()", - updated_at: "NOW()" } + created_at: 'NOW()', + updated_at: 'NOW()' } end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_meeting_content_journal, :author_id do let(:attributes) do @@ -283,25 +283,25 @@ def expected(user, format) end end - context "with MeetingParticipant" do - it_behaves_like "rewritten record", + context 'with MeetingParticipant' do + it_behaves_like 'rewritten record', :meeting_participant, :user_id do let(:attributes) do { - created_at: "NOW()", - updated_at: "NOW()" + created_at: 'NOW()', + updated_at: 'NOW()' } end end end - context "with News" do - it_behaves_like "rewritten record", + context 'with News' do + it_behaves_like 'rewritten record', :news, :author_id - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_news_journal, :author_id do let(:attributes) do @@ -313,8 +313,8 @@ def expected(user, format) end end - context "with WikiPage" do - it_behaves_like "rewritten record", + context 'with WikiPage' do + it_behaves_like 'rewritten record', :wiki_page, :author_id do let(:attributes) do @@ -328,13 +328,13 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_wiki_page_journal, :author_id do end end - context "with WorkPackage" do + context 'with WorkPackage' do shared_let(:project) { create(:project) } shared_let(:type) { create(:type) } shared_let(:status) { create(:status) } @@ -353,19 +353,19 @@ def expected(user, format) } end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :work_package, :author_id - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :work_package, :assigned_to_id - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :work_package, :responsible_id - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_work_package_journal, :assigned_to_id do let(:attributes) do @@ -384,7 +384,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_work_package_journal, :responsible_id do let(:attributes) do @@ -404,8 +404,8 @@ def expected(user, format) end end - context "with TimeEntry" do - it_behaves_like "rewritten record", + context 'with TimeEntry' do + it_behaves_like 'rewritten record', :time_entry, :user_id do let(:attributes) do @@ -420,7 +420,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :time_entry, :logged_by_id do let(:attributes) do @@ -435,7 +435,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_time_entry_journal, :user_id do let(:attributes) do @@ -450,7 +450,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_time_entry_journal, :logged_by_id do let(:attributes) do @@ -466,8 +466,8 @@ def expected(user, format) end end - context "with Budget" do - it_behaves_like "rewritten record", + context 'with Budget' do + it_behaves_like 'rewritten record', :budget, :author_id do let(:attributes) do @@ -478,7 +478,7 @@ def expected(user, format) end end - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :journal_budget_journal, :author_id do let(:attributes) do @@ -489,8 +489,8 @@ def expected(user, format) end end - context "with Query" do - it_behaves_like "rewritten record", + context 'with Query' do + it_behaves_like 'rewritten record', :query, :user_id do let(:attributes) do @@ -502,10 +502,10 @@ def expected(user, format) end end - context "with CostQuery" do + context 'with CostQuery' do let(:query) { create(:cost_query, user: principal) } - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :cost_query, :user_id do let(:attributes) do @@ -515,10 +515,10 @@ def expected(user, format) end end - context "with Notification actor" do + context 'with Notification actor' do let(:recipient) { create(:user) } - it_behaves_like "rewritten record", + it_behaves_like 'rewritten record', :notification, :actor_id do let(:attributes) do @@ -526,15 +526,15 @@ def expected(user, format) recipient_id: user.id, resource_id: 1234, resource_type: "'WorkPackage'", - created_at: "NOW()", - updated_at: "NOW()" + created_at: 'NOW()', + updated_at: 'NOW()' } end end end - context "with OAuth application" do - it_behaves_like "rewritten record", + context 'with OAuth application' do + it_behaves_like 'rewritten record', :oauth_application, :owner_id do let(:attributes) do @@ -543,8 +543,8 @@ def expected(user, format) uid: "'bar'", secret: "'bar'", redirect_uri: "'urn:whatever'", - created_at: "NOW()", - updated_at: "NOW()" + created_at: 'NOW()', + updated_at: 'NOW()' } end end diff --git a/spec/services/projects/archive_service_spec.rb b/spec/services/projects/archive_service_spec.rb index 74132381fc87..e95a576d5b23 100644 --- a/spec/services/projects/archive_service_spec.rb +++ b/spec/services/projects/archive_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::ArchiveService do let(:project) { create(:project) } @@ -36,7 +36,7 @@ let(:user) { create(:admin) } let(:instance) { described_class.new(user:, model: project) } - it "sends the notification" do + it 'sends the notification' do allow(OpenProject::Notifications).to receive(:send) expect(instance.call).to be_truthy @@ -49,8 +49,8 @@ .with(OpenProject::Events::PROJECT_ARCHIVED, project:)) end - context "with project without any subprojects" do - it "archives the project" do + context 'with project without any subprojects' do + it 'archives the project' do expect(project.reload).not_to be_archived expect(instance.call).to be_truthy @@ -58,14 +58,14 @@ end end - context "with project having subprojects" do + context 'with project having subprojects' do before do project.update(children: [subproject1, subproject2, subproject3]) project.reload end - shared_examples "when archiving a project" do - it "archives the project" do + shared_examples 'when archiving a project' do + it 'archives the project' do # Baseline verification. expect(project.reload).not_to be_archived @@ -76,7 +76,7 @@ expect(project.reload).to be_archived end - it "archives all the subprojects" do + it 'archives all the subprojects' do # Baseline verification. expect(subproject1.reload).not_to be_archived expect(subproject2.reload).not_to be_archived @@ -92,9 +92,9 @@ end end - include_examples "when archiving a project" + include_examples 'when archiving a project' - context "with deep nesting" do + context 'with deep nesting' do before do project.update(children: [subproject1]) subproject1.update(children: [subproject2]) @@ -103,11 +103,11 @@ subproject1.reload end - include_examples "when archiving a project" + include_examples 'when archiving a project' end end - context "with project having an archived subproject" do + context 'with project having an archived subproject' do let(:subproject1) { create(:project, active: false) } before do @@ -115,8 +115,8 @@ project.reload end - context "while archiving the project" do - it "does not change timestamp of the already archived subproject" do + context 'while archiving the project' do + it 'does not change timestamp of the already archived subproject' do expect(subproject1.reload).to be_archived before_timestamp = subproject1.updated_at @@ -126,7 +126,7 @@ expect(before_timestamp).to eq(after_timestamp) end - it "changes timestamp of the active subproject" do + it 'changes timestamp of the active subproject' do expect(subproject2.reload).not_to be_archived before_timestamp = subproject2.updated_at @@ -138,11 +138,11 @@ end end - context "with the seeded demo project" do - let(:demo_project) { create(:project, name: "Demo project", identifier: "demo-project", public: true) } + context 'with the seeded demo project' do + let(:demo_project) { create(:project, name: 'Demo project', identifier: 'demo-project', public: true) } let(:instance) { described_class.new(user:, model: demo_project) } - it "saves in a Setting that the demo project was modified (regression #52826)" do + it 'saves in a Setting that the demo project was modified (regression #52826)' do # Archive the demo project expect(instance.call).to be_truthy expect(demo_project.reload).to be_archived diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb index 24cc058eac2d..65ddafc219b3 100644 --- a/spec/services/projects/create_service_spec.rb +++ b/spec/services/projects/create_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Projects::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:new_project_role) { build_stubbed(:project_role) } let(:create_member_instance) { instance_double(Members::CreateService) } @@ -48,7 +48,7 @@ .to(receive(:call)) end - it "adds the current user to the project" do + it 'adds the current user to the project' do subject expect(create_member_instance) @@ -58,8 +58,8 @@ roles: [new_project_role]) end - context "current user is admin" do - it "does not add the user to the project" do + context 'current user is admin' do + it 'does not add the user to the project' do allow(user) .to(receive(:admin?)) .and_return(true) diff --git a/spec/services/projects/delete_service_spec.rb b/spec/services/projects/delete_service_spec.rb index 9658c4435e39..12077a2d89e1 100644 --- a/spec/services/projects/delete_service_spec.rb +++ b/spec/services/projects/delete_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::DeleteService, type: :model do shared_let(:user) { create(:admin) } @@ -36,9 +36,9 @@ subject { instance.call } - context "if authorized" do - context "when destroy succeeds" do - it "destroys the projects" do + context 'if authorized' do + context 'when destroy succeeds' do + it 'destroys the projects' do allow(project).to receive(:archive) allow(Projects::DeleteProjectJob).to receive(:new) @@ -48,8 +48,8 @@ .not_to have_received(:new) end - context "when the file storages are involved", :webmock do - it "removes any remote storages defined for the project" do + context 'when the file storages are involved', :webmock do + it 'removes any remote storages defined for the project' do storage = create(:nextcloud_storage) project_storage = create(:project_storage, project:, storage:) work_package = create(:work_package, project:) @@ -63,10 +63,10 @@ end end - it "sends a success mail" do + it 'sends a success mail' do expect(subject).to be_success ActionMailer::Base.deliveries.last.tap do |mail| - expect(mail.subject).to eq(I18n.t("projects.delete.completed", name: project.name)) + expect(mail.subject).to eq(I18n.t('projects.delete.completed', name: project.name)) text_part = mail.text_part.to_s html_part = mail.html_part.to_s @@ -75,7 +75,7 @@ end end - context "with a hierarchy of projects" do + context 'with a hierarchy of projects' do let!(:children) { create_list(:project, 2, parent: project) } let!(:grand_children) { create_list(:project, 2, parent: children.first) } let(:all_children) { children + grand_children } @@ -84,15 +84,15 @@ project.reload end - it "destroys the projects" do + it 'destroys the projects' do expect { subject }.to change(Project, :count).by(-5) end - it "sends a success mail mentioning all the child projects" do + it 'sends a success mail mentioning all the child projects' do expect { subject }.to change(ActionMailer::Base.deliveries, :size).by(1) ActionMailer::Base.deliveries.last.tap do |mail| - expect(mail.subject).to eq(I18n.t("projects.delete.completed", name: project.name)) + expect(mail.subject).to eq(I18n.t('projects.delete.completed', name: project.name)) text_part = mail.text_part.to_s html_part = mail.html_part.to_s @@ -105,7 +105,7 @@ end end - it "sends a message on destroy failure" do + it 'sends a message on destroy failure' do expect(project).to receive(:destroy).and_return false expect(ProjectMailer) @@ -118,10 +118,10 @@ end end - context "if not authorized" do + context 'if not authorized' do let(:user) { build_stubbed(:user) } - it "returns an error" do + it 'returns an error' do allow(Projects::DeleteProjectJob).to receive(:new) expect(subject).to be_failure @@ -129,11 +129,11 @@ end end - context "with the seeded demo project" do - let(:demo_project) { create(:project, name: "Demo project", identifier: "demo-project", public: true) } + context 'with the seeded demo project' do + let(:demo_project) { create(:project, name: 'Demo project', identifier: 'demo-project', public: true) } let(:instance) { described_class.new(user:, model: demo_project) } - it "saves in a Setting that the demo project was deleted (regression #52826)" do + it 'saves in a Setting that the demo project was deleted (regression #52826)' do # Delete the demo project expect(subject).to be_success expect(demo_project.destroyed?).to be(true) diff --git a/spec/services/projects/gantt_query_generator_service_spec.rb b/spec/services/projects/gantt_query_generator_service_spec.rb index 6d648a183f20..f649abad125d 100644 --- a/spec/services/projects/gantt_query_generator_service_spec.rb +++ b/spec/services/projects/gantt_query_generator_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::GanttQueryGeneratorService, type: :model do let(:selected) { %w[1 2 3] } @@ -35,7 +35,7 @@ let(:json) { JSON.parse(subject) } let(:milestone_ids) { [123, 234] } let(:default_json) do - scope = double("scope") + scope = double('scope') allow(Type) .to receive(:milestone) .and_return(scope) @@ -47,51 +47,51 @@ JSON .parse(Projects::GanttQueryGeneratorService::DEFAULT_GANTT_QUERY) - .merge("f" => [{ "n" => "type", "o" => "=", "v" => milestone_ids.map(&:to_s) }]) + .merge('f' => [{ 'n' => 'type', 'o' => '=', 'v' => milestone_ids.map(&:to_s) }]) end def build_project_filter(ids) - { "n" => "project", "o" => "=", "v" => ids } + { 'n' => 'project', 'o' => '=', 'v' => ids } end - context "with empty setting" do + context 'with empty setting' do before do - Setting.project_gantt_query = "" + Setting.project_gantt_query = '' end - it "uses the default" do + it 'uses the default' do expected = default_json.deep_dup - expected["f"] << build_project_filter(selected) + expected['f'] << build_project_filter(selected) expect(json).to eq(expected) end - context "without configured milestones" do + context 'without configured milestones' do let(:milestone_ids) { [] } - it "uses the default but without the type filter" do + it 'uses the default but without the type filter' do expected = default_json .deep_dup - .merge("f" => [build_project_filter(selected)]) + .merge('f' => [build_project_filter(selected)]) expect(json).to eq(expected) end end end - context "with existing filter" do - it "overrides the filter" do - Setting.project_gantt_query = default_json.deep_dup.merge("f" => [build_project_filter(%w[other values])]).to_json + context 'with existing filter' do + it 'overrides the filter' do + Setting.project_gantt_query = default_json.deep_dup.merge('f' => [build_project_filter(%w[other values])]).to_json - expected = default_json.deep_dup.merge("f" => [build_project_filter(selected)]) + expected = default_json.deep_dup.merge('f' => [build_project_filter(selected)]) expect(json).to eq(expected) end end - context "with invalid json" do - it "returns the default" do - Setting.project_gantt_query = "invalid!1234" + context 'with invalid json' do + it 'returns the default' do + Setting.project_gantt_query = 'invalid!1234' expected = default_json.deep_dup - expected["f"] << build_project_filter(selected) + expected['f'] << build_project_filter(selected) expect(json).to eq(expected) end end diff --git a/spec/services/projects/schedule_deletion_service_spec.rb b/spec/services/projects/schedule_deletion_service_spec.rb index 76088d3b4a67..78efadc8b3eb 100644 --- a/spec/services/projects/schedule_deletion_service_spec.rb +++ b/spec/services/projects/schedule_deletion_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::ScheduleDeletionService, type: :model do let(:contract_class) do - contract = double("contract_class", "<=": true) + contract = double('contract_class', '<=': true) allow(contract) .to receive(:new) @@ -40,11 +40,11 @@ contract end let(:contract_instance) do - double("contract_instance", validate: contract_valid, errors: contract_errors) + double('contract_instance', validate: contract_valid, errors: contract_errors) end let(:contract_valid) { true } let(:contract_errors) do - double("contract_errors") + double('contract_errors') end let(:project_valid) { true } let(:project) { build_stubbed(:project) } @@ -57,7 +57,7 @@ true end let(:archive_errors) do - double("archive_errors") + double('archive_errors') end let(:archive_result) do ServiceResult.new result: project, @@ -65,7 +65,7 @@ errors: archive_errors end let!(:archive_service) do - service = double("archive_service_instance") + service = double('archive_service_instance') allow(Projects::ArchiveService) .to receive(:new) @@ -88,8 +88,8 @@ .to receive(:perform_later) end - context "if contract and archiving are successful" do - it "archives the project and creates a delayed job" do + context 'if contract and archiving are successful' do + it 'archives the project and creates a delayed job' do expect(subject).to be_success expect(archive_service) @@ -101,10 +101,10 @@ end end - context "if project is archived already" do + context 'if project is archived already' do let(:project) { build_stubbed(:project, active: false) } - it "does not call archive service" do + it 'does not call archive service' do expect(subject).to be_success expect(archive_service) @@ -116,19 +116,19 @@ end end - context "if contract fails" do + context 'if contract fails' do let(:contract_valid) { false } - it "is failure" do + it 'is failure' do expect(subject).to be_failure end - it "returns the contract errors" do + it 'returns the contract errors' do expect(subject.errors) .to eql contract_errors end - it "does not schedule a job" do + it 'does not schedule a job' do expect(Projects::DeleteProjectJob) .not_to receive(:new) @@ -136,19 +136,19 @@ end end - context "if archiving fails" do + context 'if archiving fails' do let(:archive_success) { false } - it "is failure" do + it 'is failure' do expect(subject).to be_failure end - it "returns the contract errors" do + it 'returns the contract errors' do expect(subject.errors) .to eql archive_errors end - it "does not schedule a job" do + it 'does not schedule a job' do expect(Projects::DeleteProjectJob) .not_to receive(:new) diff --git a/spec/services/projects/set_attributes_service_integration_spec.rb b/spec/services/projects/set_attributes_service_integration_spec.rb index ce3c3c1e1bce..4f87d001909f 100644 --- a/spec/services/projects/set_attributes_service_integration_spec.rb +++ b/spec/services/projects/set_attributes_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::SetAttributesService, "integration", type: :model do +RSpec.describe Projects::SetAttributesService, 'integration', type: :model do let(:user) do create(:user, global_permissions: %w[add_project]) end @@ -40,37 +40,37 @@ instance.call(attributes) end - describe "with a project name starting with numbers" do - let(:attributes) { { name: "100 Project A" } } + describe 'with a project name starting with numbers' do + let(:attributes) { { name: '100 Project A' } } - it "creates an identifier including the numbers" do + it 'creates an identifier including the numbers' do expect(service_result).to be_success - expect(service_result.result.identifier).to eq "100-project-a" + expect(service_result.result.identifier).to eq '100-project-a' end end - describe "with an existing project" do - let(:existing_identifier) { "my-new-project" } + describe 'with an existing project' do + let(:existing_identifier) { 'my-new-project' } let!(:existing) { create(:project, identifier: existing_identifier) } - context "and a new project with no identifier set" do - let(:project) { Project.new name: "My new project" } + context 'and a new project with no identifier set' do + let(:project) { Project.new name: 'My new project' } - it "auto-corrects the identifier" do + it 'auto-corrects the identifier' do expect(service_result).to be_success - expect(service_result.result.identifier).to eq "my-new-project-1" + expect(service_result.result.identifier).to eq 'my-new-project-1' end end - context "and a new project with the same identifier set" do - let(:project) { Project.new name: "My new project", identifier: "my-new-project" } + context 'and a new project with the same identifier set' do + let(:project) { Project.new name: 'My new project', identifier: 'my-new-project' } - it "results in an error" do + it 'results in an error' do expect(service_result).not_to be_success - expect(service_result.result.identifier).to eq "my-new-project" + expect(service_result.result.identifier).to eq 'my-new-project' errors = service_result.errors.full_messages - expect(errors).to eq ["Identifier has already been taken."] + expect(errors).to eq ['Identifier has already been taken.'] end end end diff --git a/spec/services/projects/set_attributes_service_spec.rb b/spec/services/projects/set_attributes_service_spec.rb index 639b6a50357e..ece4c41fb7cc 100644 --- a/spec/services/projects/set_attributes_service_spec.rb +++ b/spec/services/projects/set_attributes_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } @@ -58,7 +58,7 @@ build_stubbed(:project) end - describe "call" do + describe 'call' do let(:call_attributes) do {} end @@ -75,25 +75,25 @@ subject { instance.call(call_attributes) } - it "is successful" do + it 'is successful' do expect(subject).to be_success end - it "calls validation" do + it 'calls validation' do subject expect(contract_instance) .to have_received(:validate) end - it "sets the attributes" do + it 'sets the attributes' do subject expect(project.attributes.slice(*project.changed).symbolize_keys) .to eql call_attributes end - it "does not persist the project" do + it 'does not persist the project' do allow(project) .to receive(:save) @@ -103,44 +103,44 @@ .not_to have_received(:save) end - shared_examples "setting status attributes" do - let(:status_explanation) { "A magic dwells in each beginning." } + shared_examples 'setting status attributes' do + let(:status_explanation) { 'A magic dwells in each beginning.' } - it "sets the project status code" do + it 'sets the project status code' do expect(subject.result.status_code) .to eq status_code end - it "sets the project status explanation" do + it 'sets the project status explanation' do expect(subject.result.status_explanation) .to eq status_explanation end end - context "for a new record" do + context 'for a new record' do let(:project) do Project.new end - describe "identifier default value" do - context "with an identifier provided" do + describe 'identifier default value' do + context 'with an identifier provided' do let(:call_attributes) do { - identifier: "lorem" + identifier: 'lorem' } end - it "does not alter the identifier" do + it 'does not alter the identifier' do expect(subject.result.identifier) - .to eql "lorem" + .to eql 'lorem' end end - context "with no identifier provided" do - it "stays nil" do + context 'with no identifier provided' do + it 'stays nil' do allow(Project) .to receive(:next_identifier) - .and_return("ipsum") + .and_return('ipsum') expect(subject.result.identifier) .to be_nil @@ -148,62 +148,62 @@ end end - describe "public default value", with_settings: { default_projects_public: true } do - context "with a value for is_public provided" do + describe 'public default value', with_settings: { default_projects_public: true } do + context 'with a value for is_public provided' do let(:call_attributes) do { public: false } end - it "does not alter the public value" do + it 'does not alter the public value' do expect(subject.result) .not_to be_public end end - context "with no value for public provided" do - it "sets uses the default value" do + context 'with no value for public provided' do + it 'sets uses the default value' do expect(subject.result) .to be_public end end end - describe "enabled_module_names default value", with_settings: { default_projects_modules: ["lorem", "ipsum"] } do - context "with a value for enabled_module_names provided" do + describe 'enabled_module_names default value', with_settings: { default_projects_modules: ['lorem', 'ipsum'] } do + context 'with a value for enabled_module_names provided' do let(:call_attributes) do { enabled_module_names: %w(some other) } end - it "does not alter the enabled modules" do + it 'does not alter the enabled modules' do expect(subject.result.enabled_module_names) .to match_array %w(some other) end end - context "with no value for enabled_module_names provided" do - it "sets a default enabled modules" do + context 'with no value for enabled_module_names provided' do + it 'sets a default enabled modules' do expect(subject.result.enabled_module_names) .to match_array %w(lorem ipsum) end end - context "with the enabled modules being set before" do + context 'with the enabled modules being set before' do before do project.enabled_module_names = %w(some other) end - it "does not alter the enabled modules" do + it 'does not alter the enabled modules' do expect(subject.result.enabled_module_names) .to match_array %w(some other) end end end - describe "types default value" do + describe 'types default value' do let(:other_types) do [build_stubbed(:type)] end @@ -218,25 +218,25 @@ end shared_examples "setting custom field defaults" do - context "with custom fields" do + context 'with custom fields' do let!(:custom_field) { create(:text_wp_custom_field, types:) } let!(:custom_field_with_no_type) { create(:text_wp_custom_field) } - it "activates the type's custom fields" do + it 'activates the type\'s custom fields' do expect(subject.result.work_package_custom_fields) .to eq([custom_field]) end end end - context "with a value for types provided" do + context 'with a value for types provided' do let(:call_attributes) do { types: other_types } end - it "does not alter the types" do + it 'does not alter the types' do expect(subject.result.types) .to match_array other_types end @@ -247,8 +247,8 @@ end end - context "with no value for types provided" do - it "sets the default types" do + context 'with no value for types provided' do + it 'sets the default types' do expect(subject.result.types) .to match_array default_types end @@ -259,27 +259,27 @@ end end - context "with the types being set before" do - let(:types) { [build(:type, name: "lorem")] } + context 'with the types being set before' do + let(:types) { [build(:type, name: 'lorem')] } before do project.types = types end - it "does not alter the types modules" do + it 'does not alter the types modules' do expect(subject.result.types.map(&:name)) .to match_array %w(lorem) end include_examples "setting custom field defaults" do - let(:types) { [create(:type, name: "lorem")] } + let(:types) { [create(:type, name: 'lorem')] } end end end - describe "project status" do - context "with valid status attributes" do - let(:status_code) { "on_track" } + describe 'project status' do + context 'with valid status attributes' do + let(:status_code) { 'on_track' } let(:call_attributes) do { status_code:, @@ -287,11 +287,11 @@ } end - include_examples "setting status attributes" + include_examples 'setting status attributes' end - context "with an invalid status code provided" do - let(:status_code) { "wrong" } + context 'with an invalid status code provided' do + let(:status_code) { 'wrong' } let(:call_attributes) do { status_code:, @@ -299,20 +299,20 @@ } end - include_examples "setting status attributes" + include_examples 'setting status attributes' end end end - context "for an existing project" do - describe "project status" do + context 'for an existing project' do + describe 'project status' do let(:project) do build_stubbed(:project, :with_status) end - context "with a value provided" do - let(:status_code) { "at_risk" } - let(:status_explanation) { "Still some magic there." } + context 'with a value provided' do + let(:status_code) { 'at_risk' } + let(:status_explanation) { 'Still some magic there.' } let(:call_attributes) do { status_code:, @@ -320,7 +320,7 @@ } end - include_examples "setting status attributes" + include_examples 'setting status attributes' end end end diff --git a/spec/services/projects/unarchive_service_spec.rb b/spec/services/projects/unarchive_service_spec.rb index b3278ba61526..9d48062169c6 100644 --- a/spec/services/projects/unarchive_service_spec.rb +++ b/spec/services/projects/unarchive_service_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Projects::UnarchiveService do let(:project) { create(:project, active: false) } let(:user) { create(:admin) } let(:instance) { described_class.new(user:, model: project) } - it "unarchives and sends the notification" do + it 'unarchives and sends the notification' do allow(OpenProject::Notifications).to receive(:send) expect(project.active).to be(false) @@ -48,13 +48,13 @@ .with(OpenProject::Events::PROJECT_UNARCHIVED, project:)) end - context "with the seeded demo project" do + context 'with the seeded demo project' do let(:demo_project) do - create(:project, name: "Demo project", identifier: "demo-project", public: true, active: false) + create(:project, name: 'Demo project', identifier: 'demo-project', public: true, active: false) end let(:instance) { described_class.new(user:, model: demo_project) } - it "saves in a Setting that the demo project was modified (regression #52826)" do + it 'saves in a Setting that the demo project was modified (regression #52826)' do # Un-archive the demo project expect(instance.call).to be_truthy expect(demo_project.active).to be(true) diff --git a/spec/services/projects/update_service_integration_spec.rb b/spec/services/projects/update_service_integration_spec.rb index 283cce8e70a8..c6a7e95dfca9 100644 --- a/spec/services/projects/update_service_integration_spec.rb +++ b/spec/services/projects/update_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Projects::UpdateService, "integration", type: :model do +RSpec.describe Projects::UpdateService, 'integration', type: :model do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -56,13 +56,13 @@ .call(attributes) end - describe "#call" do - context "if only a custom field is updated" do + describe '#call' do + context 'if only a custom field is updated' do let(:attributes) do { custom_field.attribute_name => 8 } end - it "touches the project after saving" do + it 'touches the project after saving' do former_updated_at = Project.pluck(:updated_at).first service_result @@ -74,14 +74,14 @@ end end - context "if a new custom field gets a value assigned" do + context 'if a new custom field gets a value assigned' do let(:custom_field2) { create(:text_project_custom_field) } let(:attributes) do - { custom_field2.attribute_name => "some text" } + { custom_field2.attribute_name => 'some text' } end - it "touches the project after saving" do + it 'touches the project after saving' do former_updated_at = Project.pluck(:updated_at).first service_result @@ -93,19 +93,19 @@ end end - context "when saving the status as well as the parent" do + context 'when saving the status as well as the parent' do let(:parent_project) { create(:project, members: { user => parent_role }) } let(:parent_role) { create(:project_role, permissions: %i(add_subprojects)) } - let(:status_code) { "on_track" } - let(:status_explanation) { "some explanation" } + let(:status_code) { 'on_track' } + let(:status_explanation) { 'some explanation' } let(:attributes) do { parent_id: parent_project.id, - status_code: "off_track" + status_code: 'off_track' } end - it "updates both the status as well as the parent" do + it 'updates both the status as well as the parent' do service_result expect(project.parent) @@ -117,14 +117,14 @@ end end - context "with the seeded demo project" do - let(:demo_project) { create(:project, name: "Demo project", identifier: "demo-project", public: true) } + context 'with the seeded demo project' do + let(:demo_project) { create(:project, name: 'Demo project', identifier: 'demo-project', public: true) } let(:instance) { described_class.new(user:, model: demo_project) } let(:attributes) do { public: false } end - it "saves in a Setting that the demo project was made private (regression #52826)" do + it 'saves in a Setting that the demo project was made private (regression #52826)' do # Make the demo project private service_result expect(demo_project.public).to be(false) diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index 53c5bad035b8..2a9792dca84c 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Projects::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let!(:model_instance) do build_stubbed(:project, :with_status) end - it "sends an update notification" do + it 'sends an update notification' do expect(OpenProject::Notifications) .to(receive(:send)) .with(OpenProject::Events::PROJECT_UPDATED, project: model_instance) @@ -43,16 +43,16 @@ subject end - context "if the identifier is altered" do - let(:call_attributes) { { identifier: "Some identifier" } } + context 'if the identifier is altered' do + let(:call_attributes) { { identifier: 'Some identifier' } } before do allow(model_instance) .to(receive(:changes)) - .and_return("identifier" => %w(lorem ipsum)) + .and_return('identifier' => %w(lorem ipsum)) end - it "sends the notification" do + it 'sends the notification' do expect(OpenProject::Notifications) .to(receive(:send)) .with(OpenProject::Events::PROJECT_UPDATED, project: model_instance) @@ -64,14 +64,14 @@ end end - context "if the parent is altered" do + context 'if the parent is altered' do before do allow(model_instance) .to(receive(:changes)) - .and_return("parent_id" => [nil, 5]) + .and_return('parent_id' => [nil, 5]) end - it "updates the versions associated with the work packages" do + it 'updates the versions associated with the work packages' do expect(WorkPackage) .to(receive(:update_versions_from_hierarchy_change)) .with(model_instance) diff --git a/spec/services/queries/create_service_spec.rb b/spec/services/queries/create_service_spec.rb index e9834814a35d..1c0037f95b61 100644 --- a/spec/services/queries/create_service_spec.rb +++ b/spec/services/queries/create_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::CreateService do let(:user) { build_stubbed(:admin) } @@ -35,11 +35,11 @@ subject { instance.call(params).result } - describe "ordered work packages" do + describe 'ordered work packages' do let!(:work_package) { create(:work_package) } let(:params) do { - name: "My query", + name: 'My query', ordered_work_packages: { work_package.id => 0, 9999 => 1 @@ -47,7 +47,7 @@ } end - it "removes items for which work packages do not exist" do + it 'removes items for which work packages do not exist' do expect(subject).to be_valid expect(subject.ordered_work_packages.length).to eq 1 expect(subject.ordered_work_packages.first.work_package_id).to eq work_package.id diff --git a/spec/services/queries/filter_mappper_spec.rb b/spec/services/queries/filter_mappper_spec.rb index 95b0317968c3..cd7a52e43983 100644 --- a/spec/services/queries/filter_mappper_spec.rb +++ b/spec/services/queries/filter_mappper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Copy::FiltersMapper do let(:state) { Shared::ServiceState.new } @@ -34,88 +34,88 @@ subject { instance.map_filters! } - describe "with a query filters array" do + describe 'with a query filters array' do let(:query) do query = build(:query) - query.add_filter "parent", "=", ["1"] - query.add_filter "category_id", "=", ["2"] - query.add_filter "version_id", "=", ["3"] + query.add_filter 'parent', '=', ['1'] + query.add_filter 'category_id', '=', ['2'] + query.add_filter 'version_id', '=', ['3'] query end let(:filters) { query.filters } - context "when mapping state exists" do + context 'when mapping state exists' do before do state.work_package_id_lookup = { 1 => 11 } state.category_id_lookup = { 2 => 22 } state.version_id_lookup = { 3 => 33 } end - it "maps the filters" do - expect(subject[1].values).to eq(["11"]) - expect(subject[2].values).to eq(["22"]) - expect(subject[3].values).to eq(["33"]) + it 'maps the filters' do + expect(subject[1].values).to eq(['11']) + expect(subject[2].values).to eq(['22']) + expect(subject[3].values).to eq(['33']) end end - context "when mapping state does not exist" do - it "does not map the filters" do - expect(subject[1].values).to eq(["1"]) - expect(subject[2].values).to eq(["2"]) - expect(subject[3].values).to eq(["3"]) + context 'when mapping state does not exist' do + it 'does not map the filters' do + expect(subject[1].values).to eq(['1']) + expect(subject[2].values).to eq(['2']) + expect(subject[3].values).to eq(['3']) end end end - describe "with a filter hash array" do + describe 'with a filter hash array' do let(:filters) do [ - { "parent" => { "operator" => "=", "values" => ["1"] } }, - { "category_id" => { "operator" => "=", "values" => ["2"] } }, - { "version_id" => { "operator" => "=", "values" => ["3"] } } + { 'parent' => { 'operator' => '=', 'values' => ['1'] } }, + { 'category_id' => { 'operator' => '=', 'values' => ['2'] } }, + { 'version_id' => { 'operator' => '=', 'values' => ['3'] } } ] end - context "when mapping state exists" do + context 'when mapping state exists' do before do state.work_package_id_lookup = { 1 => 11 } state.category_id_lookup = { 2 => 22 } state.version_id_lookup = { 3 => 33 } end - it "maps the filters" do - expect(subject[0]["parent"]["values"]).to eq(["11"]) - expect(subject[1]["category_id"]["values"]).to eq(["22"]) - expect(subject[2]["version_id"]["values"]).to eq(["33"]) + it 'maps the filters' do + expect(subject[0]['parent']['values']).to eq(['11']) + expect(subject[1]['category_id']['values']).to eq(['22']) + expect(subject[2]['version_id']['values']).to eq(['33']) end end - context "when mapping state does not exist" do - it "does not map the filters" do - expect(subject[0]["parent"]["values"]).to eq(["1"]) - expect(subject[1]["category_id"]["values"]).to eq(["2"]) - expect(subject[2]["version_id"]["values"]).to eq(["3"]) + context 'when mapping state does not exist' do + it 'does not map the filters' do + expect(subject[0]['parent']['values']).to eq(['1']) + expect(subject[1]['category_id']['values']).to eq(['2']) + expect(subject[2]['version_id']['values']).to eq(['3']) end end end - describe "with a symbolized filter hash array" do + describe 'with a symbolized filter hash array' do let(:filters) do [ - { parent: { operator: "=", values: ["1"] } } + { parent: { operator: '=', values: ['1'] } } ] end - context "when mapping state exists" do + context 'when mapping state exists' do before do state.work_package_id_lookup = { 1 => 11 } state.category_id_lookup = { 2 => 22 } state.version_id_lookup = { 3 => 33 } end - it "maps the filters" do - expect(subject[0]["parent"]["values"]).to eq(["11"]) + it 'maps the filters' do + expect(subject[0]['parent']['values']).to eq(['11']) end end end diff --git a/spec/services/queries/projects/project_queries/create_service_spec.rb b/spec/services/queries/projects/project_queries/create_service_spec.rb index f3eca52e5fe8..67718f400755 100644 --- a/spec/services/queries/projects/project_queries/create_service_spec.rb +++ b/spec/services/queries/projects/project_queries/create_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Queries::Projects::ProjectQueries::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:factory) { :project_query } end end diff --git a/spec/services/queries/projects/project_queries/set_attributes_service_spec.rb b/spec/services/queries/projects/project_queries/set_attributes_service_spec.rb index 9f91c06434d8..76866cf7b541 100644 --- a/spec/services/queries/projects/project_queries/set_attributes_service_spec.rb +++ b/spec/services/queries/projects/project_queries/set_attributes_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Queries::Projects::ProjectQueries::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:user) } @@ -67,62 +67,62 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result) .to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject) .to be_success end - context "with params" do + context 'with params' do let(:params) do { - name: "Foobar", + name: 'Foobar', filters: [ { - attribute: "id", - operator: "=", + attribute: 'id', + operator: '=', values: %w[1 2 3] }, { - attribute: "active", - operator: "!", - values: ["t"] + attribute: 'active', + operator: '!', + values: ['t'] } ], orders: [ { - attribute: "id", - direction: "asc" + attribute: 'id', + direction: 'asc' }, { - attribute: "name", - direction: "desc" + attribute: 'name', + direction: 'desc' } ] } end - it "assigns the name param" do + it 'assigns the name param' do subject - expect(model_instance.name).to eq "Foobar" + expect(model_instance.name).to eq 'Foobar' end - it "assigns the filter param" do + it 'assigns the filter param' do subject expect(model_instance.filters) .to(be_all { |f| f.is_a?(Queries::Projects::Filters::ProjectFilter) }) expect(model_instance.filters.map { |f| [f.name, f.operator, f.values] }) - .to eql [[:id, "=", %w[1 2 3]], [:active, "!", ["t"]]] + .to eql [[:id, '=', %w[1 2 3]], [:active, '!', ['t']]] end - it "assigns the orders param" do + it 'assigns the orders param' do subject expect(model_instance.orders) @@ -133,12 +133,12 @@ end end - context "without params" do + context 'without params' do let(:params) do {} end - it "assigns a default orders" do + it 'assigns a default orders' do subject expect(model_instance.orders) @@ -148,17 +148,17 @@ .to eql [%i[lft asc]] end - it "assigns a default filter param" do + it 'assigns a default filter param' do subject expect(model_instance.filters) .to(be_all { |f| f.is_a?(Queries::Projects::Filters::ProjectFilter) }) expect(model_instance.filters.map { |f| [f.name, f.operator, f.values] }) - .to eql [[:active, "=", %w[t]]] + .to eql [[:active, '=', %w[t]]] end - it "assigns default selects including those for admin and ee if allowed", + it 'assigns default selects including those for admin and ee if allowed', with_ee: %i[custom_fields_in_projects_list], with_settings: { enabled_projects_columns: %w[name created_at cf_1] } do allow(User.current) @@ -171,7 +171,7 @@ .to eql Setting.enabled_projects_columns.map(&:to_sym) end - it "assigns default selects excluding those for admin and ee if not allowed", + it 'assigns default selects excluding those for admin and ee if not allowed', with_settings: { enabled_projects_columns: %w[name created_at cf_1] } do subject @@ -180,7 +180,7 @@ end end - context "with the query already having order and with order params" do + context 'with the query already having order and with order params' do let(:model_instance) do Queries::Projects::ProjectQuery.new.tap do |query| query.order(lft: :asc) @@ -191,18 +191,18 @@ { orders: [ { - attribute: "id", - direction: "asc" + attribute: 'id', + direction: 'asc' }, { - attribute: "name", - direction: "desc" + attribute: 'name', + direction: 'desc' } ] } end - it "assigns the orders param" do + it 'assigns the orders param' do subject expect(model_instance.orders) @@ -213,10 +213,10 @@ end end - context "with the query already having filters and with filter params" do + context 'with the query already having filters and with filter params' do let(:model_instance) do Queries::Projects::ProjectQuery.new.tap do |query| - query.where("active", "=", ["t"]) + query.where("active", '=', ['t']) end end @@ -224,26 +224,26 @@ { filters: [ { - attribute: "id", - operator: "=", + attribute: 'id', + operator: '=', values: %w[1 2 3] } ] } end - it "assigns the filter param" do + it 'assigns the filter param' do subject expect(model_instance.filters) .to(be_all { |f| f.is_a?(Queries::Projects::Filters::ProjectFilter) }) expect(model_instance.filters.map { |f| [f.name, f.operator, f.values] }) - .to eql [[:id, "=", %w[1 2 3]]] + .to eql [[:id, '=', %w[1 2 3]]] end end - context "with the query already having selects and with selects params" do + context 'with the query already having selects and with selects params' do let(:model_instance) do Queries::Projects::ProjectQuery.new.tap do |query| query.select(:id, :name) @@ -256,17 +256,17 @@ } end - it "assigns the select param" do + it 'assigns the select param' do subject expect(model_instance.selects.map(&:attribute)) .to eql %i[project_status created_at] end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } - it "returns failure" do + it 'returns failure' do expect(subject) .not_to be_success end diff --git a/spec/services/queries/update_from_params_service_spec.rb b/spec/services/queries/update_from_params_service_spec.rb index 5287d0b7ef6e..d409a11f5c7c 100644 --- a/spec/services/queries/update_from_params_service_spec.rb +++ b/spec/services/queries/update_from_params_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UpdateQueryFromParamsService, type: :model do @@ -37,50 +37,50 @@ let(:params) { {} } - describe "#call" do + describe '#call' do subject { instance.call(params) } - context "group_by" do - context "for an existing value" do - let(:params) { { group_by: "status" } } + context 'group_by' do + context 'for an existing value' do + let(:params) { { group_by: 'status' } } - it "sets the value" do + it 'sets the value' do subject - expect(query.group_by).to eql("status") + expect(query.group_by).to eql('status') end - context "when hierarchy was set previously" do - it "disables the mode when not given" do + context 'when hierarchy was set previously' do + it 'disables the mode when not given' do subject - expect(query.group_by).to eql("status") + expect(query.group_by).to eql('status') expect(query.show_hierarchies).to be(false) expect(subject).to be_success end end end - context "when passed along with hierarchy mode" do - let(:params) { { group_by: "status", show_hierarchies: true } } + context 'when passed along with hierarchy mode' do + let(:params) { { group_by: 'status', show_hierarchies: true } } - it "sets both values" do + it 'sets both values' do subject - expect(query.group_by).to eql("status") + expect(query.group_by).to eql('status') expect(query.show_hierarchies).to be(true) expect(subject).not_to be_success end end end - context "filters" do + context 'filters' do let(:params) do - { filters: [{ field: "status_id", operator: "=", values: ["1", "2"] }] } + { filters: [{ field: 'status_id', operator: '=', values: ['1', '2'] }] } end - context "for a valid filter" do - it "sets the filter" do + context 'for a valid filter' do + it 'sets the filter' do subject expect(query.filters.length) @@ -88,32 +88,32 @@ expect(query.filters[0].name) .to be(:status_id) expect(query.filters[0].operator) - .to eql("=") + .to eql('=') expect(query.filters[0].values) - .to eql(["1", "2"]) + .to eql(['1', '2']) end end end - context "sort_by" do + context 'sort_by' do let(:params) do - { sort_by: [["status_id", "desc"]] } + { sort_by: [['status_id', 'desc']] } end - it "sets the order" do + it 'sets the order' do subject expect(query.sort_criteria) - .to eql([["status_id", "desc"]]) + .to eql([['status_id', 'desc']]) end end - context "columns" do + context 'columns' do let(:params) do - { columns: ["assigned_to", "author", "category", "subject"] } + { columns: ['assigned_to', 'author', 'category', 'subject'] } end - it "sets the columns" do + it 'sets the columns' do subject expect(query.column_names) diff --git a/spec/services/queries/update_service_spec.rb b/spec/services/queries/update_service_spec.rb index 2097f7f8d772..095a4cc8bbc2 100644 --- a/spec/services/queries/update_service_spec.rb +++ b/spec/services/queries/update_service_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Queries::UpdateService do - it_behaves_like "BaseServices update service" + it_behaves_like 'BaseServices update service' end diff --git a/spec/services/relations/create_service_spec.rb b/spec/services/relations/create_service_spec.rb index 6d2371a621bc..439af235eeee 100644 --- a/spec/services/relations/create_service_spec.rb +++ b/spec/services/relations/create_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Relations::CreateService do let(:work_package1_start_date) { nil } @@ -70,7 +70,7 @@ let(:user) { build_stubbed(:user) } let(:model_valid) { true } let(:contract_valid) { true } - let(:contract) { double("contract") } + let(:contract) { double('contract') } let(:symbols_for_base) { [] } subject do @@ -95,8 +95,8 @@ .and_return(contract_valid) end - context "if all valid and it is a follows relation" do - let(:set_schedule_service) { double("set schedule service") } + context 'if all valid and it is a follows relation' do + let(:set_schedule_service) { double('set schedule service') } let(:set_schedule_work_package2_result) do ServiceResult.success result: work_package2, errors: work_package2.errors end @@ -130,37 +130,37 @@ .to receive(:success=) end - it "is successful" do + it 'is successful' do expect(subject) .to be_success end - it "returns the relation" do + it 'returns the relation' do expect(subject.result) .to eql relation end - it "has a dependent result for the from-work package" do + it 'has a dependent result for the from-work package' do expect(subject.dependent_results) .to contain_exactly(set_schedule_work_package2_result) end end - context "if all is valid and it is not a follows relation" do - it "is successful" do + context 'if all is valid and it is not a follows relation' do + it 'is successful' do expect(subject) .to be_success end - it "returns the relation" do + it 'returns the relation' do expect(subject.result) .to eql relation end end - context "if the contract is invalid" do + context 'if the contract is invalid' do let(:contract_valid) { false } - let(:contract_errors) { double("contract_errors") } + let(:contract_errors) { double('contract_errors') } before do allow(contract) @@ -172,7 +172,7 @@ .and_return(symbols_for_base) end - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject) .to be_failure end @@ -183,9 +183,9 @@ end end - context "if the model is invalid" do + context 'if the model is invalid' do let(:model_valid) { false } - let(:model_errors) { double("model_errors") } + let(:model_errors) { double('model_errors') } before do allow(relation) @@ -197,7 +197,7 @@ .and_return(symbols_for_base) end - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject) .to be_failure end diff --git a/spec/services/relations/update_service_spec.rb b/spec/services/relations/update_service_spec.rb index e008a6ef57fc..cb6e633f1899 100644 --- a/spec/services/relations/update_service_spec.rb +++ b/spec/services/relations/update_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Relations::UpdateService do let(:work_package1_start_date) { nil } @@ -70,7 +70,7 @@ let(:user) { build_stubbed(:user) } let(:model_valid) { true } let(:contract_valid) { true } - let(:contract) { double("contract") } + let(:contract) { double('contract') } let(:symbols_for_base) { [] } subject do @@ -91,8 +91,8 @@ .and_return(contract_valid) end - context "when all valid and it is a follows relation" do - let(:set_schedule_service) { double("set schedule service") } + context 'when all valid and it is a follows relation' do + let(:set_schedule_service) { double('set schedule service') } let(:set_schedule_work_package2_result) do ServiceResult.success result: work_package2, errors: work_package2.errors end @@ -126,37 +126,37 @@ .to receive(:success=) end - it "is successful" do + it 'is successful' do expect(subject) .to be_success end - it "returns the relation" do + it 'returns the relation' do expect(subject.result) .to eql relation end - it "has a dependent result for the from-work package" do + it 'has a dependent result for the from-work package' do expect(subject.dependent_results) .to contain_exactly(set_schedule_work_package2_result) end end - context "when all is valid and it is not a follows relation" do - it "is successful" do + context 'when all is valid and it is not a follows relation' do + it 'is successful' do expect(subject) .to be_success end - it "returns the relation" do + it 'returns the relation' do expect(subject.result) .to eql relation end end - context "when the contract is invalid" do + context 'when the contract is invalid' do let(:contract_valid) { false } - let(:contract_errors) { double("contract_errors") } + let(:contract_errors) { double('contract_errors') } before do allow(contract) @@ -168,7 +168,7 @@ .and_return(symbols_for_base) end - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject) .to be_failure end @@ -179,9 +179,9 @@ end end - context "when the model is invalid" do + context 'when the model is invalid' do let(:model_valid) { false } - let(:model_errors) { double("model_errors") } + let(:model_errors) { double('model_errors') } before do allow(relation) @@ -193,7 +193,7 @@ .and_return(symbols_for_base) end - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject) .to be_failure end diff --git a/spec/services/roles/delete_service_spec.rb b/spec/services/roles/delete_service_spec.rb index c59612e95503..ec1b84100887 100644 --- a/spec/services/roles/delete_service_spec.rb +++ b/spec/services/roles/delete_service_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_delete_service" +require 'spec_helper' +require 'services/base_services/behaves_like_delete_service' RSpec.describe Roles::DeleteService, type: :model do - it_behaves_like "BaseServices delete service" do + it_behaves_like 'BaseServices delete service' do let(:factory) { :project_role } end - it "sends a delete notification" do + it 'sends a delete notification' do allow(OpenProject::Notifications).to(receive(:send)) existing_permissions = %i[view_files view_work_packages view_calender] diff --git a/spec/services/roles/set_attributes_service_spec.rb b/spec/services/roles/set_attributes_service_spec.rb index a93823a58730..4b25b8aa837a 100644 --- a/spec/services/roles/set_attributes_service_spec.rb +++ b/spec/services/roles/set_attributes_service_spec.rb @@ -26,19 +26,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Roles::SetAttributesService, type: :model do let(:current_user) { build_stubbed(:admin) } let(:contract_instance) do - contract = instance_double(Roles::CreateContract, "contract_instance") + contract = instance_double(Roles::CreateContract, 'contract_instance') allow(contract).to receive(:validate).and_return(contract_valid) allow(contract).to receive(:errors).and_return(contract_errors) contract end - let(:contract_errors) { instance_double(ActiveModel::Errors, "contract_errors") } + let(:contract_errors) { instance_double(ActiveModel::Errors, 'contract_errors') } let(:contract_valid) { true } let(:model_valid) { true } @@ -61,15 +61,15 @@ subject { instance.call(params) } - it "returns the instance as the result" do + it 'returns the instance as the result' do expect(subject.result).to eql model_instance end - it "is a success" do + it 'is a success' do expect(subject).to be_success end - context "with params" do + context 'with params' do let(:params) do { permissions: @@ -81,57 +81,57 @@ subject end - context "with a ProjectRole" do - it "assigns the params with the public permissions" do + context 'with a ProjectRole' do + it 'assigns the params with the public permissions' do expect(model_instance.permissions).to match_array(OpenProject::AccessControl.public_permissions.map(&:name) + permissions) end - context "when no permissions are given" do + context 'when no permissions are given' do let(:permissions) { [] } - it "assigns the permissions the non member role has" do + it 'assigns the permissions the non member role has' do expect(model_instance.permissions).to match_array(ProjectRole.non_member.permissions) # public permissions are included via the factory end end end - context "with a GlobalRole" do + context 'with a GlobalRole' do let(:model_instance) { GlobalRole.new } - it "assigns the params" do + it 'assigns the params' do expect(model_instance.permissions).to match_array(permissions) end - context "when no permissions are given" do + context 'when no permissions are given' do let(:permissions) { [] } - it "assigns nothing" do + it 'assigns nothing' do expect(model_instance.permissions).to be_empty end end end - context "with a WorkPackageRole" do + context 'with a WorkPackageRole' do let(:model_instance) { WorkPackageRole.new } - it "assigns the params" do + it 'assigns the params' do expect(model_instance.permissions).to match_array(permissions) end - context "when no permissions are given" do + context 'when no permissions are given' do let(:permissions) { [] } - it "assigns nothing" do + it 'assigns nothing' do expect(model_instance.permissions).to be_empty end end end end - context "with an invalid contract" do + context 'with an invalid contract' do let(:contract_valid) { false } - it "returns failure" do + it 'returns failure' do expect(subject).not_to be_success end diff --git a/spec/services/roles/update_service_spec.rb b/spec/services/roles/update_service_spec.rb index 6a052e0b552d..d47203347b80 100644 --- a/spec/services/roles/update_service_spec.rb +++ b/spec/services/roles/update_service_spec.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Roles::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:factory) { :project_role } end - it "sends an update notification" do + it 'sends an update notification' do allow(OpenProject::Notifications).to receive(:send) existing_permissions = %i[view_files view_work_packages diff --git a/spec/services/scm/checkout_instructions_service_spec.rb b/spec/services/scm/checkout_instructions_service_spec.rb index 1a92276a5f24..02f4d9ae585d 100644 --- a/spec/services/scm/checkout_instructions_service_spec.rb +++ b/spec/services/scm/checkout_instructions_service_spec.rb @@ -25,28 +25,28 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe SCM::CheckoutInstructionsService do let(:user) { build(:user) } let(:project) { build(:project) } - let(:url) { "file:///tmp/some/svn/repo" } + let(:url) { 'file:///tmp/some/svn/repo' } let(:repository) do build(:repository_subversion, url:, project:) end - let(:base_url) { "http://example.org/svn/" } + let(:base_url) { 'http://example.org/svn/' } let(:path) { nil } - let(:text) { "foo" } + let(:text) { 'foo' } let(:checkout_hash) do { - "git" => { "enabled" => "0" }, - "subversion" => { "enabled" => "1", - "text" => text, - "base_url" => base_url } + 'git' => { 'enabled' => '0' }, + 'subversion' => { 'enabled' => '1', + 'text' => text, + 'base_url' => base_url } } end @@ -56,107 +56,107 @@ allow(Setting).to receive(:repository_checkout_data).and_return(checkout_hash) end - describe "#checkout_url" do - shared_examples "builds the correct URL" do - it "builds the correct URL" do + describe '#checkout_url' do + shared_examples 'builds the correct URL' do + it 'builds the correct URL' do expect(service.checkout_url) .to eq(URI("http://example.org/svn/#{project.identifier}")) end - shared_examples "valid checkout URL" do + shared_examples 'valid checkout URL' do it do expect(service.checkout_url(path)) .to eq(URI("http://example.org/svn/#{project.identifier}/#{expected_path}")) end end - it_behaves_like "valid checkout URL" do - let(:path) { "foo/bar" } + it_behaves_like 'valid checkout URL' do + let(:path) { 'foo/bar' } let(:expected_path) { path } end - it_behaves_like "valid checkout URL" do - let(:path) { "foo/bar with spaces" } - let(:expected_path) { "foo/bar%20with%20spaces" } + it_behaves_like 'valid checkout URL' do + let(:path) { 'foo/bar with spaces' } + let(:expected_path) { 'foo/bar%20with%20spaces' } end - it_behaves_like "valid checkout URL" do + it_behaves_like 'valid checkout URL' do let(:path) { 'foo/bar with §\"!??```' } - let(:expected_path) { "foo/%C2%A7%22!??%60%60%60" } + let(:expected_path) { 'foo/%C2%A7%22!??%60%60%60' } end end end - describe "#checkout_command" do - it "returns the SCM vendor command" do - expect(service.checkout_command).to eq("svn checkout") + describe '#checkout_command' do + it 'returns the SCM vendor command' do + expect(service.checkout_command).to eq('svn checkout') end end - describe "#instructions" do - it "returns the setting when defined" do - expect(service.instructions).to eq("foo") + describe '#instructions' do + it 'returns the setting when defined' do + expect(service.instructions).to eq('foo') end - context "no setting defined" do + context 'no setting defined' do let(:text) { nil } - it "returns the default translated instructions" do + it 'returns the default translated instructions' do expect(service.instructions) - .to eq(I18n.t("repositories.checkout.default_instructions.subversion")) + .to eq(I18n.t('repositories.checkout.default_instructions.subversion')) end end end - describe "#settings" do - it "svn is available for checkout" do + describe '#settings' do + it 'svn is available for checkout' do expect(service.available?).to be true expect(service.checkout_enabled?).to be true end - it "has the correct settings" do - expect(Setting.repository_checkout_data["subversion"]["enabled"]).to eq("1") - expect(service.instructions).to eq("foo") + it 'has the correct settings' do + expect(Setting.repository_checkout_data['subversion']['enabled']).to eq('1') + expect(service.instructions).to eq('foo') expect(service.checkout_base_url).to eq(base_url) end - context "missing checkout base URL" do - let(:base_url) { "" } + context 'missing checkout base URL' do + let(:base_url) { '' } - it "is not available for checkout even when enabled" do + it 'is not available for checkout even when enabled' do expect(service.checkout_base_url).to eq(base_url) expect(service.checkout_enabled?).to be true expect(service.available?).to be false end end - context "disabled repository" do + context 'disabled repository' do let(:repository) { build(:repository_git) } - it "git is not available for checkout" do + it 'git is not available for checkout' do expect(service.available?).to be false expect(service.checkout_enabled?).to be false end end end - describe "#permission" do - context "with no managed repository" do - it "is not applicable" do + describe '#permission' do + context 'with no managed repository' do + it 'is not applicable' do expect(service.manages_permissions?).to be false end end - context "with managed repository" do + context 'with managed repository' do before do allow(repository).to receive(:managed?).and_return(true) end - it "is applicable" do + it 'is applicable' do expect(service.manages_permissions?).to be true end - it "returns readwrite permission when user has commit_access permission" do + it 'returns readwrite permission when user has commit_access permission' do mock_permissions_for(user) do |mock| mock.allow_in_project :commit_access, project: end @@ -164,7 +164,7 @@ expect(service.permission).to eq(:readwrite) end - it "returns read permission when user has browse_repository permission" do + it 'returns read permission when user has browse_repository permission' do mock_permissions_for(user) do |mock| mock.allow_in_project :browse_repository, project: end @@ -172,13 +172,13 @@ expect(service.permission).to eq(:read) end - it "returns none permission when user has no permission" do + it 'returns none permission when user has no permission' do mock_permissions_for(user, &:forbid_everything) expect(service.permission).to eq(:none) end - it "returns the correct permissions for commit access" do + it 'returns the correct permissions for commit access' do mock_permissions_for(user) do |mock| mock.allow_in_project :commit_access, project: end @@ -187,7 +187,7 @@ expect(service.may_checkout?).to be true end - it "returns the correct permissions for read access" do + it 'returns the correct permissions for read access' do mock_permissions_for(user) do |mock| mock.allow_in_project :browse_repository, project: end @@ -196,7 +196,7 @@ expect(service.may_checkout?).to be true end - it "returns the correct permissions for no access" do + it 'returns the correct permissions for no access' do mock_permissions_for(user, &:forbid_everything) expect(service.may_commit?).to be false diff --git a/spec/services/scm/create_managed_repository_service_spec.rb b/spec/services/scm/create_managed_repository_service_spec.rb index 4f8100c1cd44..21b6dd34637a 100644 --- a/spec/services/scm/create_managed_repository_service_spec.rb +++ b/spec/services/scm/create_managed_repository_service_spec.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe SCM::CreateManagedRepositoryService, skip_if_command_unavailable: "svnadmin" do +RSpec.describe SCM::CreateManagedRepositoryService, skip_if_command_unavailable: 'svnadmin' do let(:user) { build(:user) } let(:config) { {} } let(:project) { build(:project) } @@ -38,21 +38,21 @@ before do allow(OpenProject::Configuration).to receive(:[]).and_call_original - allow(OpenProject::Configuration).to receive(:[]).with("scm").and_return(config) + allow(OpenProject::Configuration).to receive(:[]).with('scm').and_return(config) end - shared_examples "does not create a filesystem repository" do - it "does not create a filesystem repository" do + shared_examples 'does not create a filesystem repository' do + it 'does not create a filesystem repository' do expect(repository.managed?).to be false expect(service.call).to be false end end - context "with no managed configuration" do - it_behaves_like "does not create a filesystem repository" + context 'with no managed configuration' do + it_behaves_like 'does not create a filesystem repository' end - context "with managed repository" do + context 'with managed repository' do # Must not .create a managed repository, or it will call this service itself! let(:repository) do repo = Repository::Subversion.new(scm_type: :managed) @@ -60,20 +60,20 @@ repo end - context "but no managed config" do - it "does not create a filesystem repository" do + context 'but no managed config' do + it 'does not create a filesystem repository' do expect(repository.managed?).to be true expect(service.call).to be false end end end - context "with managed local config" do - include_context "with tmpdir" + context 'with managed local config' do + include_context 'with tmpdir' let(:config) do { - subversion: { manages: File.join(tmpdir, "svn") }, - git: { manages: File.join(tmpdir, "git") } + subversion: { manages: File.join(tmpdir, 'svn') }, + git: { manages: File.join(tmpdir, 'git') } } end @@ -95,54 +95,54 @@ .to receive(:repository).and_return(repository) end - it "creates the repository" do + it 'creates the repository' do expect(service.call).to be true perform_enqueued_jobs expect(File.directory?(repository.root_url)).to be true end - context "with pre-existing path on filesystem" do + context 'with pre-existing path on filesystem' do before do allow(File).to receive(:directory?).and_return(true) end - it "does not create the repository" do + it 'does not create the repository' do expect(service.call).to be false expect(service.localized_rejected_reason) - .to eq(I18n.t("repositories.errors.exists_on_filesystem")) + .to eq(I18n.t('repositories.errors.exists_on_filesystem')) end end - context "with a permission error occurring in the Job" do + context 'with a permission error occurring in the Job' do before do allow(SCM::CreateLocalRepositoryJob) .to receive(:new).and_raise(Errno::EACCES) end - it "returns the correct error" do + it 'returns the correct error' do expect(service.call).to be false expect(service.localized_rejected_reason) - .to eq(I18n.t("repositories.errors.path_permission_failed", + .to eq(I18n.t('repositories.errors.path_permission_failed', path: repository.root_url)) end end - context "with an OS error occurring in the Job" do + context 'with an OS error occurring in the Job' do before do allow(SCM::CreateLocalRepositoryJob) .to receive(:new).and_raise(Errno::ENOENT) end - it "returns the correct error" do + it 'returns the correct error' do expect(service.call).to be false expect(service.localized_rejected_reason) - .to include("An error occurred while accessing the repository in the filesystem") + .to include('An error occurred while accessing the repository in the filesystem') end end end - context "with managed remote config", :webmock do - let(:url) { "http://myreposerver.example.com/api/" } + context 'with managed remote config', :webmock do + let(:url) { 'http://myreposerver.example.com/api/' } let(:config) do { subversion: { manages: url } @@ -156,14 +156,14 @@ repo end - it "detects the remote config" do + it 'detects the remote config' do expect(repository.class.managed_remote.to_s).to eq(url) expect(repository.class).to be_manages_remote end - context "with a remote callback" do - let(:returned_url) { "file:///tmp/some/url/to/repo" } - let(:root_url) { "/tmp/some/url/to/repo" } + context 'with a remote callback' do + let(:returned_url) { 'file:///tmp/some/url/to/repo' } + let(:root_url) { '/tmp/some/url/to/repo' } before do stub_request(:post, url) @@ -173,7 +173,7 @@ ) end - shared_examples "calls the callback" do + shared_examples 'calls the callback' do before do # Avoid setting up a second call to the remote during save # since we only templated the repository, not created one! @@ -190,16 +190,16 @@ expect(WebMock) .to have_requested(:post, url) - .with(body: hash_including(action: "create")) + .with(body: hash_including(action: 'create')) end end - context "with http" do - it_behaves_like "calls the callback" + context 'with http' do + it_behaves_like 'calls the callback' end - context "with https" do - let(:url) { "https://myreposerver.example.com/api/" } + context 'with https' do + let(:url) { 'https://myreposerver.example.com/api/' } let(:config) do { subversion: { manages: url, insecure: } @@ -209,20 +209,20 @@ let(:instance) { SCM::CreateRemoteRepositoryJob.new } let(:job_call) { instance.perform(repository) } - context "with insecure option" do + context 'with insecure option' do let(:insecure) { true } - it_behaves_like "calls the callback" - it "uses the insecure option" do + it_behaves_like 'calls the callback' + it 'uses the insecure option' do job_call expect(instance.send(:configured_verification)).to eq(OpenSSL::SSL::VERIFY_NONE) end end - context "without insecure option" do + context 'without insecure option' do let(:insecure) { false } - it "uses the insecure option" do + it 'uses the insecure option' do job_call expect(instance.send(:configured_verification)).to eq(OpenSSL::SSL::VERIFY_PEER) end @@ -230,13 +230,13 @@ end end - context "with a faulty remote callback" do + context 'with a faulty remote callback' do before do stub_request(:post, url) - .to_return(status: 400, body: { success: false, message: "An error occurred" }.to_json) + .to_return(status: 400, body: { success: false, message: 'An error occurred' }.to_json) end - it "calls the callback" do + it 'calls the callback' do expect(SCM::CreateRemoteRepositoryJob) .to receive(:new).and_call_original @@ -245,7 +245,7 @@ .to eq("Calling the managed remote failed with message 'An error occurred' (Code: 400)") expect(WebMock) .to have_requested(:post, url) - .with(body: hash_including(action: "create")) + .with(body: hash_including(action: 'create')) end end end diff --git a/spec/services/scm/delete_managed_repository_service_spec.rb b/spec/services/scm/delete_managed_repository_service_spec.rb index 29fc66d185aa..9af99b6dc7aa 100644 --- a/spec/services/scm/delete_managed_repository_service_spec.rb +++ b/spec/services/scm/delete_managed_repository_service_spec.rb @@ -25,9 +25,9 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.describe SCM::DeleteManagedRepositoryService, skip_if_command_unavailable: "svnadmin" do +RSpec.describe SCM::DeleteManagedRepositoryService, skip_if_command_unavailable: 'svnadmin' do let(:user) { build(:user) } let(:config) { {} } let(:project) { build(:project) } @@ -38,36 +38,36 @@ before do allow(OpenProject::Configuration).to receive(:[]).and_call_original - allow(OpenProject::Configuration).to receive(:[]).with("scm").and_return(config) - allow(Setting).to receive(:enabled_scm).and_return(["subversion", "git"]) + allow(OpenProject::Configuration).to receive(:[]).with('scm').and_return(config) + allow(Setting).to receive(:enabled_scm).and_return(['subversion', 'git']) end - shared_examples "does not delete the repository" do - it "does not delete the repository" do + shared_examples 'does not delete the repository' do + it 'does not delete the repository' do expect(repository.managed?).to be false expect(service.call).to be false end end - context "with no managed configuration" do - it_behaves_like "does not delete the repository" + context 'with no managed configuration' do + it_behaves_like 'does not delete the repository' end - context "with managed repository, but no config" do + context 'with managed repository, but no config' do let(:repository) { build(:repository_subversion, scm_type: :managed) } - it "does allow to delete the repository" do + it 'does allow to delete the repository' do expect(repository.managed?).to be true expect(service.call).to be true end end - context "with managed repository and managed config" do - include_context "with tmpdir" + context 'with managed repository and managed config' do + include_context 'with tmpdir' let(:config) do { - subversion: { manages: File.join(tmpdir, "svn") }, - git: { manages: File.join(tmpdir, "git") } + subversion: { manages: File.join(tmpdir, 'svn') }, + git: { manages: File.join(tmpdir, 'git') } } end @@ -81,13 +81,13 @@ repo end - it "deletes the repository" do + it 'deletes the repository' do expect(File.directory?(repository.root_url)).to be true expect(service.call).to be true expect(File.directory?(repository.root_url)).to be false end - it "does not raise an exception upon permission errors" do + it 'does not raise an exception upon permission errors' do expect(File.directory?(repository.root_url)).to be true expect(SCM::DeleteLocalRepositoryJob) .to receive(:new).and_raise(Errno::EACCES) @@ -95,14 +95,14 @@ expect(service.call).to be false end - context "and parent project" do + context 'and parent project' do let(:parent) { create(:project) } let(:project) { create(:project, parent:) } let(:repo_path) do - Pathname.new(File.join(tmpdir, "svn", project.identifier)) + Pathname.new(File.join(tmpdir, 'svn', project.identifier)) end - it "does not delete anything but the repository itself" do + it 'does not delete anything but the repository itself' do expect(service.call).to be true path = Pathname.new(repository.root_url) @@ -115,8 +115,8 @@ end end - context "with managed remote config", :webmock do - let(:url) { "http://myreposerver.example.com/api/" } + context 'with managed remote config', :webmock do + let(:url) { 'http://myreposerver.example.com/api/' } let(:config) do { subversion: { manages: url } @@ -131,12 +131,12 @@ repo end - context "with a valid remote" do + context 'with a valid remote' do before do stub_request(:post, url).to_return(status: 200, body: {}.to_json) end - it "calls the callback" do + it 'calls the callback' do expect(SCM::DeleteRemoteRepositoryJob) .to receive(:perform_now) .and_call_original @@ -145,17 +145,17 @@ expect(WebMock) .to have_requested(:post, url) .with(body: hash_including(identifier: repository.repository_identifier, - action: "delete")) + action: 'delete')) end end - context "with a remote callback returning an error" do + context 'with a remote callback returning an error' do before do stub_request(:post, url) - .to_return(status: 400, body: { success: false, message: "An error occurred" }.to_json) + .to_return(status: 400, body: { success: false, message: 'An error occurred' }.to_json) end - it "calls the callback" do + it 'calls the callback' do expect(SCM::DeleteRemoteRepositoryJob) .to receive(:perform_now) .and_call_original @@ -166,7 +166,7 @@ .to eq("Calling the managed remote failed with message 'An error occurred' (Code: 400)") expect(WebMock) .to have_requested(:post, url) - .with(body: hash_including(action: "delete")) + .with(body: hash_including(action: 'delete')) end end end diff --git a/spec/services/scm/repository_factory_service_spec.rb b/spec/services/scm/repository_factory_service_spec.rb index f02339dc7486..8f5118367c93 100644 --- a/spec/services/scm/repository_factory_service_spec.rb +++ b/spec/services/scm/repository_factory_service_spec.rb @@ -25,13 +25,13 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe SCM::RepositoryFactoryService do let(:user) { build(:user) } let(:project) { build(:project) } - let(:enabled_scms) { ["subversion", "git"] } + let(:enabled_scms) { ['subversion', 'git'] } let(:params_hash) { {} } let(:params) { ActionController::Parameters.new params_hash } @@ -42,25 +42,25 @@ allow(Setting).to receive(:enabled_scm).and_return(enabled_scms) end - context "with empty hash" do - it "does not build a repository" do + context 'with empty hash' do + it 'does not build a repository' do expect { service.build_temporary } .to raise_error KeyError expect(service.repository).to be_nil end end - context "with valid vendor" do + context 'with valid vendor' do let(:params_hash) do - { scm_vendor: "subversion" } + { scm_vendor: 'subversion' } end - it "allows temporary build repository" do + it 'allows temporary build repository' do expect(service.build_temporary).to be true expect(service.repository).not_to be_nil end - it "does not allow to persist a repository" do + it 'does not allow to persist a repository' do expect { service.build_and_save } .to raise_error(ActionController::ParameterMissing) @@ -68,32 +68,32 @@ end end - context "with invalid vendor" do + context 'with invalid vendor' do let(:params_hash) do - { scm_vendor: "not_subversion", scm_type: "foo" } + { scm_vendor: 'not_subversion', scm_type: 'foo' } end - it "does not allow to temporary build repository" do + it 'does not allow to temporary build repository' do expect { service.build_temporary }.not_to raise_error expect(service.repository).to be_nil - expect(service.build_error).to include("The SCM vendor not_subversion is disabled") + expect(service.build_error).to include('The SCM vendor not_subversion is disabled') end - it "does not allow to persist a repository" do + it 'does not allow to persist a repository' do expect { service.build_temporary }.not_to raise_error expect(service.repository).to be_nil - expect(service.build_error).to include("The SCM vendor not_subversion is disabled") + expect(service.build_error).to include('The SCM vendor not_subversion is disabled') end end - context "with vendor and type" do + context 'with vendor and type' do let(:params_hash) do - { scm_vendor: "subversion", scm_type: "existing" } + { scm_vendor: 'subversion', scm_type: 'existing' } end - it "does not allow to persist a repository without URL" do + it 'does not allow to persist a repository without URL' do expect(service.build_and_save).not_to be true expect(service.repository).to be_nil @@ -101,31 +101,31 @@ end end - context "with invalid hash" do + context 'with invalid hash' do let(:params_hash) do { - scm_vendor: "subversion", scm_type: "existing", - repository: { url: "/tmp/foo.svn" } + scm_vendor: 'subversion', scm_type: 'existing', + repository: { url: '/tmp/foo.svn' } } end - it "does not allow to persist a repository URL" do + it 'does not allow to persist a repository URL' do expect(service.build_and_save).not_to be true expect(service.repository).to be_nil - expect(service.build_error).to include("URL is invalid") + expect(service.build_error).to include('URL is invalid') end end - context "with valid hash" do + context 'with valid hash' do let(:params_hash) do { - scm_vendor: "subversion", scm_type: "existing", - repository: { url: "file:///tmp/foo.svn" } + scm_vendor: 'subversion', scm_type: 'existing', + repository: { url: 'file:///tmp/foo.svn' } } end - it "allows to persist a repository without URL" do + it 'allows to persist a repository without URL' do expect(service.build_and_save).to be true expect(service.repository).to be_a(Repository::Subversion) end diff --git a/spec/services/service_result_spec.rb b/spec/services/service_result_spec.rb index 02c4cd0a76f1..2e16a5fdc262 100644 --- a/spec/services/service_result_spec.rb +++ b/spec/services/service_result_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ServiceResult, type: :model do let(:instance) { described_class.new } - describe "success" do - it "is what the service is initialized with" do + describe 'success' do + it 'is what the service is initialized with' do instance = described_class.new success: true expect(instance.success).to be_truthy @@ -44,7 +44,7 @@ expect(instance.success?).to be(false) end - it "returns what is provided" do + it 'returns what is provided' do instance.success = true expect(instance.success).to be_truthy @@ -56,25 +56,25 @@ expect(instance.success?).to be(false) end - it "is false by default" do + it 'is false by default' do expect(instance.success).to be_falsey expect(instance.success?).to be(false) end end - describe ".success" do - it "creates a ServiceResult with success: true" do + describe '.success' do + it 'creates a ServiceResult with success: true' do instance = described_class.success expect(instance.success).to be_truthy end - it "accepts the same set of parameters as the initializer" do - errors = ["errors"] - message = "message" + it 'accepts the same set of parameters as the initializer' do + errors = ['errors'] + message = 'message' message_type = :message_type state = instance_double(Shared::ServiceState) - dependent_results = ["dependent_results"] - result = instance_double(Object, "result") + dependent_results = ['dependent_results'] + result = instance_double(Object, 'result') instance = described_class.success( errors:, @@ -93,19 +93,19 @@ end end - describe ".failure" do - it "creates a ServiceResult with success: false" do + describe '.failure' do + it 'creates a ServiceResult with success: false' do instance = described_class.failure expect(instance.success).to be_falsy end - it "accepts the same set of parameters as the initializer" do - errors = ["errors"] - message = "message" + it 'accepts the same set of parameters as the initializer' do + errors = ['errors'] + message = 'message' message_type = :message_type state = instance_double(Shared::ServiceState) - dependent_results = ["dependent_results"] - result = instance_double(Object, "result") + dependent_results = ['dependent_results'] + result = instance_double(Object, 'result') instance = described_class.failure( errors:, @@ -124,77 +124,77 @@ end end - describe "errors" do - let(:errors) { ["errors"] } + describe 'errors' do + let(:errors) { ['errors'] } - it "is what has been provided" do + it 'is what has been provided' do instance.errors = errors expect(instance.errors).to eql errors end - it "is what the object is initialized with" do + it 'is what the object is initialized with' do instance = described_class.new(errors:) expect(instance.errors).to eql errors end - it "is an empty ActiveModel::Errors by default" do + it 'is an empty ActiveModel::Errors by default' do expect(instance.errors).to be_a ActiveModel::Errors end - context "when providing errors from user" do + context 'when providing errors from user' do let(:result) { build(:work_package) } - it "creates a new errors instance" do + it 'creates a new errors instance' do instance = described_class.new(result:) expect(instance.errors).not_to eq result.errors end end end - describe "result" do - let(:result) { instance_double(Object, "result") } + describe 'result' do + let(:result) { instance_double(Object, 'result') } - it "is what the object is initialized with" do + it 'is what the object is initialized with' do instance = described_class.new(result:) expect(instance.result).to eql result end - it "is what has been provided" do + it 'is what has been provided' do instance.result = result expect(instance.result).to eql result end - it "is nil by default" do + it 'is nil by default' do instance = described_class.new expect(instance.result).to be_nil end end - describe "apply_flash_message!" do - let(:message) { "some message" } + describe 'apply_flash_message!' do + let(:message) { 'some message' } subject(:flash) do {}.tap { service_result.apply_flash_message!(_1) } end - context "when successful" do + context 'when successful' do let(:service_result) { described_class.success(message:) } it { is_expected.to include(notice: message) } end - context "when failure" do + context 'when failure' do let(:service_result) { described_class.failure(message:) } it { is_expected.to include(error: message) } end - context "when setting message_type to :info" do + context 'when setting message_type to :info' do let(:service_result) { described_class.success(message:, message_type: :info) } it { is_expected.to include(info: message) } diff --git a/spec/services/services/create_service_spec.rb b/spec/services/services/create_service_spec.rb index 3c925f631761..52eb34d75152 100644 --- a/spec/services/services/create_service_spec.rb +++ b/spec/services/services/create_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Views::CreateService, type: :model do - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:call_attributes) do { type: "work_packages_table", diff --git a/spec/services/set_localization_service_spec.rb b/spec/services/set_localization_service_spec.rb index a5efab5953e1..5309ae92b41d 100644 --- a/spec/services/set_localization_service_spec.rb +++ b/spec/services/set_localization_service_spec.rb @@ -1,4 +1,4 @@ -require "spec_helper" +require 'spec_helper' RSpec.describe SetLocalizationService do let(:user) { build_stubbed(:user, language: user_language) } @@ -20,8 +20,8 @@ def expect_locale(locale) expect(I18n).to receive(:locale=).with(locale) end - shared_examples_for "falls back to the header" do - it "falls back to the header" do + shared_examples_for 'falls back to the header' do + it 'falls back to the header' do expect_locale(http_accept_language) instance.call @@ -36,15 +36,15 @@ def expect_locale(locale) end end - context "for a logged in user" do + context 'for a logged in user' do it "sets the language to the user's selected language" do expect_locale(user_language) instance.call end - context "with a language prefix being valid" do - let(:prefix) { "someprefix" } + context 'with a language prefix being valid' do + let(:prefix) { 'someprefix' } let(:user_language) { "#{prefix}-specific" } before do @@ -60,16 +60,16 @@ def expect_locale(locale) end end - context "with the language not being valid" do + context 'with the language not being valid' do before do allow(instance).to receive(:valid_languages).and_return [http_accept_language, default_language] end - it_behaves_like "falls back to the header" + it_behaves_like 'falls back to the header' - context "with a language prefix being valid" do - let(:prefix) { "someprefix" } + context 'with a language prefix being valid' do + let(:prefix) { 'someprefix' } let(:http_accept_header) { "#{prefix}-specific" } before do @@ -85,14 +85,14 @@ def expect_locale(locale) end end - context "with the user not having a language selected" do + context 'with the user not having a language selected' do before do user.language = nil end - it_behaves_like "falls back to the header" + it_behaves_like 'falls back to the header' - context "with the header not being valid" do + context 'with the header not being valid' do before do allow(instance).to receive(:valid_languages).and_return [user_language, default_language] @@ -101,33 +101,33 @@ def expect_locale(locale) it_behaves_like "falls back to the instane's default language" end - context "with no header set" do + context 'with no header set' do let(:http_accept_header) { nil } it_behaves_like "falls back to the instane's default language" end - context "with wildcard header set" do - let(:http_accept_language) { "*" } + context 'with wildcard header set' do + let(:http_accept_language) { '*' } it_behaves_like "falls back to the instane's default language" end end end - context "for an anonymous user" do + context 'for an anonymous user' do let(:user) { build_stubbed(:anonymous) } - it_behaves_like "falls back to the header" + it_behaves_like 'falls back to the header' - context "with no header set" do + context 'with no header set' do let(:http_accept_header) { nil } it_behaves_like "falls back to the instane's default language" end - context "with a wildcard header set" do - let(:http_accept_language) { "*" } + context 'with a wildcard header set' do + let(:http_accept_language) { '*' } it_behaves_like "falls back to the instane's default language" end diff --git a/spec/services/settings/language_update_service_spec.rb b/spec/services/settings/language_update_service_spec.rb index 7ebb27644d4d..67b8432f4120 100644 --- a/spec/services/settings/language_update_service_spec.rb +++ b/spec/services/settings/language_update_service_spec.rb @@ -29,7 +29,7 @@ # ++ # -require "spec_helper" +require 'spec_helper' RSpec.describe Settings::LanguageUpdateService do let(:service) do @@ -41,21 +41,21 @@ allow(service).to receive(:force_users_to_use_only_available_languages) end - it "sets language of users having a non-available language to the default language" do + it 'sets language of users having a non-available language to the default language' do service.call(available_languages:) expect(service) .to have_received(:force_users_to_use_only_available_languages) end - context "when the contract is not successfully validated" do + context 'when the contract is not successfully validated' do before do allow(service) .to receive(:validate_contract) - .and_return(ServiceResult.failure(message: "fake error")) + .and_return(ServiceResult.failure(message: 'fake error')) end - it "does not change language of any users" do + it 'does not change language of any users' do service.call(available_languages:) expect(service) diff --git a/spec/services/settings/shared/shared_call_examples.rb b/spec/services/settings/shared/shared_call_examples.rb index 4dde133a40d6..8fd56250104e 100644 --- a/spec/services/settings/shared/shared_call_examples.rb +++ b/spec/services/settings/shared/shared_call_examples.rb @@ -24,15 +24,15 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "successful call" do - it "is successful" do +RSpec.shared_examples 'successful call' do + it 'is successful' do expect(subject) .to be_success end - it "sets the setting value" do + it 'sets the setting value' do subject expect(Setting) @@ -41,13 +41,13 @@ end end -RSpec.shared_examples "unsuccessful call" do - it "is not successful" do +RSpec.shared_examples 'unsuccessful call' do + it 'is not successful' do expect(subject) .not_to be_success end - it "does not set the setting value" do + it 'does not set the setting value' do subject expect(Setting) diff --git a/spec/services/settings/shared/shared_setup_context.rb b/spec/services/settings/shared/shared_setup_context.rb index bdcdd9e23e7b..94f6a10c477b 100644 --- a/spec/services/settings/shared/shared_setup_context.rb +++ b/spec/services/settings/shared/shared_setup_context.rb @@ -29,9 +29,9 @@ # ++ # -require "spec_helper" +require 'spec_helper' -RSpec.shared_context "with update service setup" do +RSpec.shared_context 'with update service setup' do let(:instance) do described_class.new(user:) end @@ -46,8 +46,8 @@ instance_double(Settings::Definition) end let(:setting_name) { :a_setting_name } - let(:new_setting_value) { "a_new_setting_value" } - let(:previous_setting_value) { "the_previous_setting_value" } + let(:new_setting_value) { 'a_new_setting_value' } + let(:previous_setting_value) { 'the_previous_setting_value' } let(:params) { { setting_name => new_setting_value } } before do diff --git a/spec/services/settings/update_service_spec.rb b/spec/services/settings/update_service_spec.rb index b467c4a6c214..f29ab5722429 100644 --- a/spec/services/settings/update_service_spec.rb +++ b/spec/services/settings/update_service_spec.rb @@ -24,22 +24,22 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require_relative "shared/shared_call_examples" -require_relative "shared/shared_setup_context" +require 'spec_helper' +require_relative 'shared/shared_call_examples' +require_relative 'shared/shared_setup_context' RSpec.describe Settings::UpdateService do - include_context "with update service setup" + include_context 'with update service setup' - describe "#call" do + describe '#call' do subject { instance.call(params) } - include_examples "successful call" + include_examples 'successful call' - context "when the contract is not successfully validated" do + context 'when the contract is not successfully validated' do let(:contract_success) { false } - include_examples "unsuccessful call" + include_examples 'unsuccessful call' end end end diff --git a/spec/services/settings/working_days_update_service_spec.rb b/spec/services/settings/working_days_update_service_spec.rb index 597466215d65..7e0a6bfba6cd 100644 --- a/spec/services/settings/working_days_update_service_spec.rb +++ b/spec/services/settings/working_days_update_service_spec.rb @@ -24,8 +24,8 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require_relative "shared/shared_call_examples" +require 'spec_helper' +require_relative 'shared/shared_call_examples' RSpec.describe Settings::WorkingDaysUpdateService do let(:instance) do @@ -45,8 +45,8 @@ end let(:params_contract_success) { true } let(:setting_name) { :a_setting_name } - let(:new_setting_value) { "a_new_setting_value" } - let(:previous_setting_value) { "the_previous_setting_value" } + let(:new_setting_value) { 'a_new_setting_value' } + let(:previous_setting_value) { 'the_previous_setting_value' } let(:setting_params) { { setting_name => new_setting_value } } let(:non_working_days_params) { {} } let(:params) { setting_params.merge(non_working_days: non_working_days_params) } @@ -71,13 +71,13 @@ .and_return(params_contract) end - describe "#call" do + describe '#call' do subject { instance.call(params) } - shared_examples "successful working days settings call" do - include_examples "successful call" + shared_examples 'successful working days settings call' do + include_examples 'successful call' - it "calls the WorkPackages::ApplyWorkingDaysChangeJob" do + it 'calls the WorkPackages::ApplyWorkingDaysChangeJob' do previous_working_days = Setting[:working_days] previous_non_working_days = NonWorkingDay.pluck(:date) @@ -91,14 +91,14 @@ end end - shared_examples "unsuccessful working days settings call" do - include_examples "unsuccessful call" + shared_examples 'unsuccessful working days settings call' do + include_examples 'unsuccessful call' - it "does not persists the non working days" do + it 'does not persists the non working days' do expect { subject }.not_to change(NonWorkingDay, :count) end - it "does not calls the WorkPackages::ApplyWorkingDaysChangeJob" do + it 'does not calls the WorkPackages::ApplyWorkingDaysChangeJob' do allow(WorkPackages::ApplyWorkingDaysChangeJob).to receive(:perform_later) subject @@ -106,64 +106,64 @@ end end - include_examples "successful working days settings call" + include_examples 'successful working days settings call' - context "when non working days are present" do - let!(:existing_nwd) { create(:non_working_day, name: "Existing NWD") } - let!(:nwd_to_delete) { create(:non_working_day, name: "NWD to delete") } + context 'when non working days are present' do + let!(:existing_nwd) { create(:non_working_day, name: 'Existing NWD') } + let!(:nwd_to_delete) { create(:non_working_day, name: 'NWD to delete') } let(:non_working_days_params) do [ - { "name" => "Christmas Eve", "date" => "2022-12-24" }, - { "name" => "NYE", "date" => "2022-12-31" }, - { "id" => existing_nwd.id }, - { "id" => nwd_to_delete.id, "_destroy" => true } + { 'name' => 'Christmas Eve', 'date' => '2022-12-24' }, + { 'name' => 'NYE', 'date' => '2022-12-31' }, + { 'id' => existing_nwd.id }, + { 'id' => nwd_to_delete.id, '_destroy' => true } ] end - include_examples "successful working days settings call" + include_examples 'successful working days settings call' - it "persists (create/delete) the non working days" do + it 'persists (create/delete) the non working days' do expect { subject }.to change(NonWorkingDay, :count).by(1) expect { nwd_to_delete.reload }.to raise_error(ActiveRecord::RecordNotFound) expect(NonWorkingDay.all).to contain_exactly( - have_attributes(name: "Christmas Eve", date: Date.parse("2022-12-24")), - have_attributes(name: "NYE", date: Date.parse("2022-12-31")), + have_attributes(name: 'Christmas Eve', date: Date.parse('2022-12-24')), + have_attributes(name: 'NYE', date: Date.parse('2022-12-31')), have_attributes(existing_nwd.slice(:id, :name, :date)) ) end - context "when there are duplicates" do - context "with both within the params" do + context 'when there are duplicates' do + context 'with both within the params' do let(:non_working_days_params) do [ - { "name" => "Christmas Eve", "date" => "2022-12-24" }, - { "name" => "Christmas Eve", "date" => "2022-12-24" } + { 'name' => 'Christmas Eve', 'date' => '2022-12-24' }, + { 'name' => 'Christmas Eve', 'date' => '2022-12-24' } ] end - include_examples "unsuccessful working days settings call" + include_examples 'unsuccessful working days settings call' end - context "with one saved in the database" do + context 'with one saved in the database' do let(:non_working_days_params) do [existing_nwd.slice(:name, :date)] end - include_examples "unsuccessful working days settings call" + include_examples 'unsuccessful working days settings call' - context "when deleting and re-creating the duplicate non-working day" do + context 'when deleting and re-creating the duplicate non-working day' do let(:non_working_days_params) do [ - nwd_to_delete.slice(:id, :name, :date).merge("_destroy" => true), + nwd_to_delete.slice(:id, :name, :date).merge('_destroy' => true), nwd_to_delete.slice(:name, :date) ] end - include_examples "successful working days settings call" + include_examples 'successful working days settings call' - it "persists (create/delete) the non working days" do + it 'persists (create/delete) the non working days' do expect { subject }.not_to change(NonWorkingDay, :count) expect { nwd_to_delete.reload }.to raise_error(ActiveRecord::RecordNotFound) @@ -175,18 +175,18 @@ end end - context "with duplicate params when deleting and re-creating non-working days" do + context 'with duplicate params when deleting and re-creating non-working days' do let(:non_working_days_params) do [ - existing_nwd.slice(:id, :name, :date).merge("_destroy" => true), + existing_nwd.slice(:id, :name, :date).merge('_destroy' => true), existing_nwd.slice(:name, :date), existing_nwd.slice(:name, :date) ] end - include_examples "unsuccessful working days settings call" + include_examples 'unsuccessful working days settings call' - it "returns the unchanged results including the ones marked for destruction" do + it 'returns the unchanged results including the ones marked for destruction' do result = subject.result expect(result).to contain_exactly( @@ -202,26 +202,26 @@ end end - context "when the params contract is not successfully validated" do + context 'when the params contract is not successfully validated' do let(:params_contract_success) { false } - include_examples "unsuccessful working days settings call" + include_examples 'unsuccessful working days settings call' end - context "when the contract is not successfully validated" do + context 'when the contract is not successfully validated' do let(:contract_success) { false } - include_examples "unsuccessful working days settings call" + include_examples 'unsuccessful working days settings call' - context "when non working days are present" do + context 'when non working days are present' do let(:non_working_days_params) do [ - { "name" => "Christmas Eve", "date" => "2022-12-24" }, - { "name" => "NYE", "date" => "2022-12-31" } + { 'name' => 'Christmas Eve', 'date' => '2022-12-24' }, + { 'name' => 'NYE', 'date' => '2022-12-31' } ] end - include_examples "unsuccessful working days settings call" + include_examples 'unsuccessful working days settings call' end end end diff --git a/spec/services/shared/service_context_integration_spec.rb b/spec/services/shared/service_context_integration_spec.rb index 6ba273d378eb..813279a7951d 100644 --- a/spec/services/shared/service_context_integration_spec.rb +++ b/spec/services/shared/service_context_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Shared::ServiceContext, "integration", type: :model do +RSpec.describe Shared::ServiceContext, 'integration', type: :model do let(:user) { build_stubbed(:user) } let(:instance) do @@ -65,37 +65,37 @@ def test_method_success(model) end.new(user) end - describe "#in_context" do - context "with a model" do + describe '#in_context' do + context 'with a model' do let(:model) { User.new } # model implementation is irrelevant - context "with a failure result" do - it "reverts all database changes" do + context 'with a failure result' do + it 'reverts all database changes' do expect { instance.test_method_failure(model) } .not_to change { Setting.count } end end - context "with a success result" do - it "keeps database changes" do + context 'with a success result' do + it 'keeps database changes' do expect { instance.test_method_success(model) } .to change { Setting.count } end end end - context "without a model" do + context 'without a model' do let(:model) { nil } - context "with a failure result" do - it "reverts all database changes" do + context 'with a failure result' do + it 'reverts all database changes' do expect { instance.test_method_failure(model) } .not_to change { Setting.count } end end - context "with a success result" do - it "keeps database changes" do + context 'with a success result' do + it 'keeps database changes' do expect { instance.test_method_success(model) } .to change { Setting.count } end diff --git a/spec/services/shared_type_service.rb b/spec/services/shared_type_service.rb index 75a0a0879714..137f5e5ee72c 100644 --- a/spec/services/shared_type_service.rb +++ b/spec/services/shared_type_service.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "with custom field params" do - let(:cf1) { create(:work_package_custom_field, field_format: "text") } - let(:cf2) { create(:work_package_custom_field, field_format: "text") } - let!(:cf3) { create(:work_package_custom_field, field_format: "text") } +RSpec.shared_context 'with custom field params' do + let(:cf1) { create(:work_package_custom_field, field_format: 'text') } + let(:cf2) { create(:work_package_custom_field, field_format: 'text') } + let!(:cf3) { create(:work_package_custom_field, field_format: 'text') } let(:attribute_groups) do { attribute_groups: [ - { "type" => "attribute", - "name" => "group1", - "attributes" => [{ "key" => cf1.attribute_name }, { "key" => cf2.attribute_name }] }, - { "type" => "attribute", - "name" => "groups", - "attributes" => [{ "key" => cf2.attribute_name }] } + { 'type' => 'attribute', + 'name' => 'group1', + 'attributes' => [{ 'key' => cf1.attribute_name }, { 'key' => cf2.attribute_name }] }, + { 'type' => 'attribute', + 'name' => 'groups', + 'attributes' => [{ 'key' => cf2.attribute_name }] } ] } end @@ -47,7 +47,7 @@ let(:params) { attribute_groups } end -RSpec.shared_examples_for "type service" do +RSpec.shared_examples_for 'type service' do let(:success) { true } let(:params) { {} } let!(:contract) do @@ -66,41 +66,41 @@ let(:contract_errors) { instance_double(ActiveModel::Errors) } let(:contract_valid) { success } - describe "#call" do + describe '#call' do before do allow(type) .to receive(:save) .and_return(success) end - it "is successful" do + it 'is successful' do expect(service_call).to be_success end - it "yields the block with success" do + it 'yields the block with success' do expect(service_call(&:success?)).to be_truthy end - describe "with attributes" do - let(:params) { { name: "blubs blubs" } } + describe 'with attributes' do + let(:params) { { name: 'blubs blubs' } } - it "set the values provided on the call" do + it 'set the values provided on the call' do service_call expect(type.name).to eql params[:name] end end - describe "attribute groups" do + describe 'attribute groups' do before do allow(type).to receive(:reset_attribute_groups) allow(type).to receive(:attribute_groups=) end - context "when not given" do - let(:params) { { name: "blubs blubs" } } + context 'when not given' do + let(:params) { { name: 'blubs blubs' } } - it "set the values provided on the call" do + it 'set the values provided on the call' do service_call expect(type).not_to have_received(:reset_attribute_groups) @@ -109,10 +109,10 @@ end end - context "when empty" do + context 'when empty' do let(:params) { { attribute_groups: [] } } - it "set the values provided on the call" do + it 'set the values provided on the call' do service_call expect(type).to have_received(:reset_attribute_groups) @@ -120,10 +120,10 @@ end end - context "when other" do - let(:params) { { attribute_groups: [{ "type" => "attribute", "name" => "foo", "attributes" => [] }] } } + context 'when other' do + let(:params) { { attribute_groups: [{ 'type' => 'attribute', 'name' => 'foo', 'attributes' => [] }] } } - it "set the values provided on the call" do + it 'set the values provided on the call' do service_call expect(type).not_to have_received(:reset_attribute_groups) @@ -132,10 +132,10 @@ end end - describe "custom fields" do - include_context "with custom field params" + describe 'custom fields' do + include_context 'with custom field params' - it "enables the custom fields that are passed via attribute_groups" do + it 'enables the custom fields that are passed via attribute_groups' do allow(type) .to receive(:work_package_attributes) .and_return(cf1.attribute_name => {}, cf2.attribute_name => {}) @@ -149,24 +149,24 @@ expect(type).to have_received(:custom_field_ids=) end - context "when all the projects are associated with the type" do + context 'when all the projects are associated with the type' do before do type.projects = create_list :project, 2 end - it "enables the custom fields in the projects" do + it 'enables the custom fields in the projects' do expect { service_call } .to change { Project.where(id: type.project_ids).map(&:work_package_custom_fields) } .from([[], []]) .to([[cf1, cf2], [cf1, cf2]]) end - context "when a custom field is already associated with the type" do + context 'when a custom field is already associated with the type' do before do type.custom_field_ids = [cf1.id] end - it "enables the new custom field only" do + it 'enables the new custom field only' do expect { service_call } .to change { Project.where(id: type.project_ids).map(&:work_package_custom_fields) } .from([[], []]) @@ -174,12 +174,12 @@ end end - context "when all custom fields are already associated with the type" do + context 'when all custom fields are already associated with the type' do before do type.custom_field_ids = [cf1.id, cf2.id] end - it "enables no custom field" do + it 'enables no custom field' do expect { service_call } .not_to change { Project.where(id: type.project_ids).map(&:work_package_custom_field_ids) } .from([[], []]) @@ -187,7 +187,7 @@ end end - context "when a project is being set on the type" do + context 'when a project is being set on the type' do let(:projects) { create_list(:project, 2) } let(:active_project) { projects.first } let(:project_ids) { { project_ids: [*projects.map { |p| p.id.to_s }, ""] } } @@ -199,19 +199,19 @@ type.projects << active_project end - it "enables the custom fields for all the projects" do + it 'enables the custom fields for all the projects' do expect { service_call } .to change { Project.where(id: type.project_ids).map(&:work_package_custom_fields) } .from([[]]) .to([[cf1, cf2], [cf1, cf2]]) end - context "when a custom field is already associated with the type" do + context 'when a custom field is already associated with the type' do before do type.custom_field_ids = [cf1.id] end - it "enables the new cf for the existing project and enables both cfs for the new project" do + it 'enables the new cf for the existing project and enables both cfs for the new project' do expect { service_call } .to change { Project.where(id: type.project_ids).map(&:work_package_custom_fields) } .from([[]]) @@ -219,14 +219,14 @@ end end - context "when all custom fields are already associated with the type" do + context 'when all custom fields are already associated with the type' do let(:params) { project_ids } before do type.custom_field_ids = [cf1.id, cf2.id] end - it "enables the custom fields in the new project only" do + it 'enables the custom fields in the new project only' do expect { service_call } .to change { Project.where(id: type.project_ids).map(&:work_package_custom_fields) } .from([[]]) @@ -236,15 +236,15 @@ end end - describe "query group" do + describe 'query group' do let(:query_params) do - sort_by = JSON::dump(["status:desc"]) - filters = JSON::dump([{ "status_id" => { "operator" => "=", "values" => %w(1 2) } }]) + sort_by = JSON::dump(['status:desc']) + filters = JSON::dump([{ 'status_id' => { 'operator' => '=', 'values' => %w(1 2) } }]) - { "sortBy" => sort_by, "filters" => filters } + { 'sortBy' => sort_by, 'filters' => filters } end let(:query_group_params) do - { "type" => "query", "name" => "group1", "query" => JSON.dump(query_params) } + { 'type' => 'query', 'name' => 'group1', 'query' => JSON.dump(query_params) } end let(:params) { { attribute_groups: [query_group_params] } } let(:query) { Query.new } @@ -257,7 +257,7 @@ .and_return(query) end - it "assigns the fully parsed query to the type's attribute group with the system user as the querie's user" do + it 'assigns the fully parsed query to the type\'s attribute group with the system user as the querie\'s user' do expect(service_call).to be_success expect(type.attribute_groups[0].query) @@ -273,11 +273,11 @@ .to eq User.system end - context "when the query parse service reports an error" do + context 'when the query parse service reports an error' do let(:success) { false } let(:service_result) { ServiceResult.failure(result: nil) } - it "reports the error" do + it 'reports the error' do expect(service_call).to be_failure expect(type.attribute_groups[0].query) @@ -286,30 +286,30 @@ end end - describe "on failure" do + describe 'on failure' do let(:success) { false } let(:params) { { name: nil } } subject { service_call } - it "returns a failed service result" do + it 'returns a failed service result' do expect(subject).not_to be_success end - it "returns the errors of the type" do + it 'returns the errors of the type' do expect(subject.errors) .to eql contract_errors end - describe "custom fields" do - include_context "with custom field params" + describe 'custom fields' do + include_context 'with custom field params' - context "when the type is associated with projects" do + context 'when the type is associated with projects' do before do type.projects = create_list :project, 2 end - it "does not changes project custom fields" do + it 'does not changes project custom fields' do expect { service_call } .not_to change { Project.where(id: type.project_ids).map(&:work_package_custom_field_ids) } .from([[], []]) diff --git a/spec/services/update_projects_types_service_spec.rb b/spec/services/update_projects_types_service_spec.rb index 3ab4bceae061..6843c1b8734c 100644 --- a/spec/services/update_projects_types_service_spec.rb +++ b/spec/services/update_projects_types_service_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe UpdateProjectsTypesService do let(:project) { instance_double(Project, types_used_by_work_packages: []) } @@ -37,81 +37,81 @@ allow(Type).to receive(:standard_type).and_return standard_type end - describe ".call" do + describe '.call' do subject { instance.call(ids) } before do allow(project).to receive(:type_ids=) end - shared_examples "activating custom fields" do + shared_examples 'activating custom fields' do let(:project) { create(:project, no_types: true) } let!(:custom_field) { create(:text_wp_custom_field, types:) } - it "updates the active custom fields" do + it 'updates the active custom fields' do expect { subject } .to change { project.reload.work_package_custom_field_ids } .from([]) .to([custom_field.id]) end - it "does not activates the same custom field twice" do + it 'does not activates the same custom field twice' do expect { subject }.to change { project.reload.work_package_custom_field_ids } expect { subject }.not_to change { project.reload.work_package_custom_field_ids } end - context "for a project with already existing types" do + context 'for a project with already existing types' do let(:project) { create(:project, types:, work_package_custom_fields: [create(:text_wp_custom_field)]) } - it "does not change custom fields" do + it 'does not change custom fields' do expect { subject }.not_to change { project.reload.work_package_custom_field_ids } end end end - context "with ids provided" do + context 'with ids provided' do let(:ids) { [1, 2, 3] } - it "returns true and updates the ids" do + it 'returns true and updates the ids' do expect(subject).to be_truthy expect(project).to have_received(:type_ids=).with(ids) end - include_examples "activating custom fields" do + include_examples 'activating custom fields' do let(:types) { create_list(:type, 2) } let(:ids) { types.collect(&:id) } end end - context "with no id passed" do + context 'with no id passed' do let(:ids) { [] } - it "adds the id of the default type and returns true" do + it 'adds the id of the default type and returns true' do expect(subject).to be_truthy expect(project).to have_received(:type_ids=).with([standard_type.id]) end - include_examples "activating custom fields" do + include_examples 'activating custom fields' do let(:standard_type) { create(:type_standard) } let(:types) { [standard_type] } end end - context "with nil passed" do + context 'with nil passed' do let(:ids) { nil } - it "adds the id of the default type and returns true" do + it 'adds the id of the default type and returns true' do expect(subject).to be_truthy expect(project).to have_received(:type_ids=).with([standard_type.id]) end - include_examples "activating custom fields" do + include_examples 'activating custom fields' do let(:standard_type) { create(:type_standard) } let(:types) { [standard_type] } end end - context "when the id of a type in use is not provided" do + context 'when the id of a type in use is not provided' do let(:type) { build_stubbed(:type) } let(:ids) { [1] } @@ -120,7 +120,7 @@ allow(project).to receive(:work_package_custom_field_ids=).and_return([type]) end - it "returns false and sets an error message" do + it 'returns false and sets an error message' do errors = instance_double(ActiveModel::Errors) allow(errors).to receive(:add) allow(project).to receive(:errors).and_return(errors) diff --git a/spec/services/update_query_from_params_service_spec.rb b/spec/services/update_query_from_params_service_spec.rb index 1d87e86e5b39..6727f00c9d8b 100644 --- a/spec/services/update_query_from_params_service_spec.rb +++ b/spec/services/update_query_from_params_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe UpdateQueryFromParamsService, type: :model do @@ -37,25 +37,25 @@ let(:params) { {} } - describe "#call" do + describe '#call' do subject { instance.call(params) } - context "group_by" do - context "for an existing value" do - let(:params) { { group_by: "status" } } + context 'group_by' do + context 'for an existing value' do + let(:params) { { group_by: 'status' } } - it "sets the value" do + it 'sets the value' do subject expect(query.group_by) - .to eql("status") + .to eql('status') end end - context "for an explicitly nil value" do + context 'for an explicitly nil value' do let(:params) { { group_by: nil } } - it "sets the value" do + it 'sets the value' do subject expect(query.group_by) @@ -64,13 +64,13 @@ end end - context "filters" do + context 'filters' do let(:params) do - { filters: [{ field: "status_id", operator: "=", values: ["1", "2"] }] } + { filters: [{ field: 'status_id', operator: '=', values: ['1', '2'] }] } end - context "for a valid filter" do - it "sets the filter" do + context 'for a valid filter' do + it 'sets the filter' do subject expect(query.filters.length) @@ -78,32 +78,32 @@ expect(query.filters[0].name) .to be(:status_id) expect(query.filters[0].operator) - .to eql("=") + .to eql('=') expect(query.filters[0].values) - .to eql(["1", "2"]) + .to eql(['1', '2']) end end end - context "sort_by" do + context 'sort_by' do let(:params) do - { sort_by: [["status_id", "desc"]] } + { sort_by: [['status_id', 'desc']] } end - it "sets the order" do + it 'sets the order' do subject expect(query.sort_criteria) - .to eql([["status_id", "desc"]]) + .to eql([['status_id', 'desc']]) end end - context "columns" do + context 'columns' do let(:params) do - { columns: ["assigned_to", "author", "category", "subject"] } + { columns: ['assigned_to', 'author', 'category', 'subject'] } end - it "sets the columns" do + it 'sets the columns' do subject expect(query.column_names) @@ -111,25 +111,25 @@ end end - context "display representation" do + context 'display representation' do let(:params) do - { display_representation: "list" } + { display_representation: 'list' } end - it "sets the display_representation" do + it 'sets the display_representation' do subject expect(query.display_representation) - .to eq("list") + .to eq('list') end end - context "highlighting mode", with_ee: %i[conditional_highlighting] do + context 'highlighting mode', with_ee: %i[conditional_highlighting] do let(:params) do - { highlighting_mode: "status" } + { highlighting_mode: 'status' } end - it "sets the highlighting_mode" do + it 'sets the highlighting_mode' do subject expect(query.highlighting_mode) @@ -137,12 +137,12 @@ end end - context "default highlighting mode", with_ee: %i[conditional_highlighting] do + context 'default highlighting mode', with_ee: %i[conditional_highlighting] do let(:params) do {} end - it "sets the highlighting_mode" do + it 'sets the highlighting_mode' do subject expect(query.highlighting_mode) @@ -150,12 +150,12 @@ end end - context "highlighting mode without EE" do + context 'highlighting mode without EE' do let(:params) do - { highlighting_mode: "status" } + { highlighting_mode: 'status' } end - it "sets the highlighting_mode" do + it 'sets the highlighting_mode' do subject expect(query.highlighting_mode) @@ -163,15 +163,15 @@ end end - context "when using include subprojects" do + context 'when using include subprojects' do let(:params) do { include_subprojects: } end - context "when true" do + context 'when true' do let(:include_subprojects) { true } - it "sets the display_representation" do + it 'sets the display_representation' do subject expect(query.include_subprojects) @@ -179,10 +179,10 @@ end end - context "when false" do + context 'when false' do let(:include_subprojects) { false } - it "sets the display_representation" do + it 'sets the display_representation' do subject expect(query.include_subprojects) @@ -201,7 +201,7 @@ end let(:params) { { timestamps: } } - it "sets the timestamps" do + it 'sets the timestamps' do subject expect(query.timestamps).to eq timestamps diff --git a/spec/services/update_type_service_spec.rb b/spec/services/update_type_service_spec.rb index 38293dd61600..e48452693875 100644 --- a/spec/services/update_type_service_spec.rb +++ b/spec/services/update_type_service_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/shared_type_service" +require 'spec_helper' +require 'services/shared_type_service' RSpec.describe UpdateTypeService do let(:type) { create(:type) } @@ -36,42 +36,42 @@ let(:instance) { described_class.new(type, user) } let(:service_call) { instance.call(params) } - let(:valid_group) { { "type" => "attribute", "name" => "foo", "attributes" => ["date"] } } + let(:valid_group) { { 'type' => 'attribute', 'name' => 'foo', 'attributes' => ['date'] } } - it_behaves_like "type service" + it_behaves_like 'type service' describe "#validate_attribute_groups" do - let(:params) { { name: "blubs blubs" } } + let(:params) { { name: 'blubs blubs' } } - it "raises an exception for invalid structure" do + it 'raises an exception for invalid structure' do # Example for invalid structure: - result = instance.call(attribute_groups: ["foo"]) + result = instance.call(attribute_groups: ['foo']) expect(result.success?).to be_falsey # Example for invalid structure: result = instance.call(attribute_groups: [[]]) expect(result.success?).to be_falsey # Example for invalid group name: - result = instance.call(attribute_groups: [["", ["date"]]]) + result = instance.call(attribute_groups: [['', ['date']]]) expect(result.success?).to be_falsey end - it "fails for duplicate group names" do + it 'fails for duplicate group names' do result = instance.call(attribute_groups: [valid_group, valid_group]) expect(result.success?).to be_falsey - expect(result.errors[:attribute_groups].first).to include "used more than once." + expect(result.errors[:attribute_groups].first).to include 'used more than once.' end - it "passes validations for known attributes" do + it 'passes validations for known attributes' do expect(type).to receive(:save).and_return(true) result = instance.call(attribute_groups: [valid_group]) expect(result.success?).to be_truthy end - it "passes validation for defaults" do + it 'passes validation for defaults' do expect(type).to be_valid end - it "passes validation for reset" do + it 'passes validation for reset' do # A reset is to save an empty Array expect(type).to receive(:save).and_return(true) result = instance.call(attribute_groups: []) @@ -79,10 +79,10 @@ expect(type).to be_valid end - context "with an invalid query" do - let(:params) { { attribute_groups: [{ "type" => "query", name: "some name", query: "wat" }] } } + context 'with an invalid query' do + let(:params) { { attribute_groups: [{ 'type' => 'query', name: 'some name', query: 'wat' }] } } - it "is invalid" do + it 'is invalid' do expect(service_call.success?).to be_falsey end end diff --git a/spec/services/user_preferences/update_service_integration_spec.rb b/spec/services/user_preferences/update_service_integration_spec.rb index e7b2ec3b0273..3912fbfa51d7 100644 --- a/spec/services/user_preferences/update_service_integration_spec.rb +++ b/spec/services/user_preferences/update_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe UserPreferences::UpdateService, "integration", type: :model do +RSpec.describe UserPreferences::UpdateService, 'integration', type: :model do shared_let(:current_user) do create(:user).tap do |u| u.pref.save @@ -50,10 +50,10 @@ service_result.result end - describe "notification_settings" do + describe 'notification_settings' do subject { updated_pref.notification_settings } - context "with a partial update" do + context 'with a partial update' do let(:attributes) do { notification_settings: [ @@ -72,7 +72,7 @@ } end - it "updates the existing one, removes the email one" do + it 'updates the existing one, removes the email one' do default_ian = current_user.notification_settings.first expect(default_ian.watched).to be true @@ -103,7 +103,7 @@ end end - context "with a full replacement" do + context 'with a full replacement' do let(:project) { create(:project) } let(:attributes) do { @@ -113,7 +113,7 @@ } end - it "inserts the setting, removing the old one" do + it 'inserts the setting, removing the old one' do default = current_user.notification_settings.to_a expect(default.count).to eq 1 diff --git a/spec/services/user_preferences/update_service_spec.rb b/spec/services/user_preferences/update_service_spec.rb index dbdaa083ba42..3763b5525f7d 100644 --- a/spec/services/user_preferences/update_service_spec.rb +++ b/spec/services/user_preferences/update_service_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe UserPreferences::UpdateService, type: :model do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:params_success) { true } let(:params_errors) { ActiveModel::Errors.new({}) } let(:params_contract) do @@ -41,10 +41,10 @@ allow(UserPreferences::ParamsContract).to receive(:new).and_return(params_contract) end - context "when the params contract is invalid" do + context 'when the params contract is invalid' do let(:params_success) { false } - it "returns that error" do + it 'returns that error' do expect(subject).to be_failure expect(subject.errors).to eq(params_errors) end diff --git a/spec/services/users/change_password_service_spec.rb b/spec/services/users/change_password_service_spec.rb index f3e00ecd2db1..10845d2a85c3 100644 --- a/spec/services/users/change_password_service_spec.rb +++ b/spec/services/users/change_password_service_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe Users::ChangePasswordService do let(:user) do @@ -33,8 +33,8 @@ password: old_password, password_confirmation: old_password) end - let(:old_password) { "AdminAdmin42" } - let(:new_password) { "SoreThroat33" } + let(:old_password) { 'AdminAdmin42' } + let(:new_password) { 'SoreThroat33' } let(:session) { ActionController::TestSession.new } let(:instance) { described_class.new current_user: user, session: } @@ -42,7 +42,7 @@ instance.call new_password:, new_password_confirmation: new_password end - it "is successful" do + it 'is successful' do expect(result).to be_success end @@ -52,9 +52,9 @@ expect(user.check_password?(new_password)).to be true end - describe "activating the user" do + describe 'activating the user' do context 'when the user is "invited"' do - it "activates the user" do + it 'activates the user' do result expect(user).to be_active end @@ -67,26 +67,26 @@ password_confirmation: old_password) end - it "does not activate the user" do + it 'does not activate the user' do result expect(user).not_to be_active end end end - context "with existing invitation tokens" do + context 'with existing invitation tokens' do let!(:invitation_token) { create(:invitation_token, user:) } - it "invalidates the existing token" do + it 'invalidates the existing token' do expect(result).to be_success expect(Token::Invitation.where(user:)).to be_empty end end - context "with existing password recovery tokens" do + context 'with existing password recovery tokens' do let!(:recovery_token) { create(:recovery_token, user:) } - it "invalidates the existing tokens" do + it 'invalidates the existing tokens' do expect(result).to be_success expect(Token::Recovery.where(user:)).to be_empty end diff --git a/spec/services/users/create_service_spec.rb b/spec/services/users/create_service_spec.rb index 7257de7deaba..4df2c4af5371 100644 --- a/spec/services/users/create_service_spec.rb +++ b/spec/services/users/create_service_spec.rb @@ -25,36 +25,36 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe Users::CreateService do - it_behaves_like "BaseServices create service" do - context "when the user being invited" do + it_behaves_like 'BaseServices create service' do + context 'when the user being invited' do let(:model_instance) { build(:invited_user) } - context "and the mail is present" do - let(:model_instance) { build(:invited_user, mail: "foo@example.com") } + context 'and the mail is present' do + let(:model_instance) { build(:invited_user, mail: 'foo@example.com') } - it "calls UserInvitation" do + it 'calls UserInvitation' do expect(UserInvitation).to receive(:invite_user!).with(model_instance).and_return(model_instance) expect(subject).to be_success end end - context "and the user has no names set" do - let(:model_instance) { build(:invited_user, firstname: nil, lastname: nil, mail: "foo@example.com") } + context 'and the user has no names set' do + let(:model_instance) { build(:invited_user, firstname: nil, lastname: nil, mail: 'foo@example.com') } - it "calls UserInvitation" do + it 'calls UserInvitation' do expect(UserInvitation).to receive(:invite_user!).with(model_instance).and_return(model_instance) expect(subject).to be_success end end - context "and the mail is empty" do + context 'and the mail is empty' do let(:model_instance) { build(:invited_user, mail: nil) } - it "calls not call UserInvitation" do + it 'calls not call UserInvitation' do expect(UserInvitation).not_to receive(:invite_user!) expect(subject).not_to be_success expect(subject.errors.details[:mail]).to eq [{ error: :blank }] diff --git a/spec/services/users/delete_service_integration_spec.rb b/spec/services/users/delete_service_integration_spec.rb index 0eed07f88a1e..aef0224f920e 100644 --- a/spec/services/users/delete_service_integration_spec.rb +++ b/spec/services/users/delete_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Users::DeleteService, "Integration", type: :model do +RSpec.describe Users::DeleteService, 'Integration', type: :model do let(:input_user) { create(:user) } let(:actor) { build_stubbed(:admin) } @@ -36,13 +36,13 @@ subject { instance.call } - context "when input user is invalid", + context 'when input user is invalid', with_settings: { users_deletable_by_admins: true } do before do - input_user.update_column(:mail, "") + input_user.update_column(:mail, '') end - it "can still delete the user" do + it 'can still delete the user' do expect(input_user).not_to be_valid expect(subject).to be_success diff --git a/spec/services/users/delete_service_spec.rb b/spec/services/users/delete_service_spec.rb index c06e9dc91fd7..2ce8738a3c2b 100644 --- a/spec/services/users/delete_service_spec.rb +++ b/spec/services/users/delete_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::DeleteService, type: :model do let(:input_user) { build_stubbed(:user) } @@ -36,7 +36,7 @@ subject { instance.call } - shared_examples "deletes the user" do + shared_examples 'deletes the user' do it do allow(input_user).to receive(:update_column).with(:status, 3) expect(Principals::DeleteJob).to receive(:perform_later).with(input_user) @@ -45,7 +45,7 @@ end end - shared_examples "does not delete the user" do + shared_examples 'does not delete the user' do it do allow(input_user).to receive(:update_column).with(:status, 3) expect(Principals::DeleteJob).not_to receive(:perform_later) @@ -54,41 +54,41 @@ end end - context "if deletion by admins allowed", with_settings: { users_deletable_by_admins: true } do - context "with admin user" do + context 'if deletion by admins allowed', with_settings: { users_deletable_by_admins: true } do + context 'with admin user' do let(:actor) { build_stubbed(:admin) } - it_behaves_like "deletes the user" + it_behaves_like 'deletes the user' end - context "with unprivileged system user" do + context 'with unprivileged system user' do let(:actor) { User.system } before do allow(actor).to receive(:admin?).and_return false end - it_behaves_like "does not delete the user" + it_behaves_like 'does not delete the user' end - context "with privileged system user" do + context 'with privileged system user' do let(:actor) { User.system } - it_behaves_like "deletes the user" + it_behaves_like 'deletes the user' end end - context "if deletion by admins NOT allowed", with_settings: { users_deletable_by_admins: false } do - context "with admin user" do + context 'if deletion by admins NOT allowed', with_settings: { users_deletable_by_admins: false } do + context 'with admin user' do let(:actor) { build_stubbed(:admin) } - it_behaves_like "does not delete the user" + it_behaves_like 'does not delete the user' end - context "with system user" do + context 'with system user' do let(:actor) { User.system } - it_behaves_like "does not delete the user" + it_behaves_like 'does not delete the user' end end end diff --git a/spec/services/users/login_service_spec.rb b/spec/services/users/login_service_spec.rb index b5b0be2ce55e..844e07a946f8 100644 --- a/spec/services/users/login_service_spec.rb +++ b/spec/services/users/login_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::LoginService, type: :model do shared_let(:input_user) { create(:user) } @@ -34,9 +34,9 @@ let(:session) { {} } let(:browser) do instance_double(Browser::Safari, - name: "Safari", - version: "13.2", - platform: instance_double(Browser::Platform::Linux, name: "Linux")) + name: 'Safari', + version: '13.2', + platform: instance_double(Browser::Platform::Linux, name: 'Linux')) end let(:cookies) { {} } let(:flash) { ActionDispatch::Flash::FlashHash.new } @@ -57,11 +57,11 @@ .to receive(:log_successful_login) end - describe "session" do - context "with an SSO provider" do + describe 'session' do + context 'with an SSO provider' do let(:sso_provider) do { - name: "saml", + name: 'saml', retain_from_session: %i[foo bar] } end @@ -69,17 +69,17 @@ before do allow(OpenProject::Plugins::AuthPlugin) .to(receive(:find_provider_by_name)) - .with("provider_name") + .with('provider_name') .and_return sso_provider end - context "if provider retains session values" do + context 'if provider retains session values' do let(:retained_values) { %i[foo bar] } - it "retains present session values" do - session[:omniauth_provider] = "provider_name" - session[:foo] = "foo value" - session[:what] = "should be cleared" + it 'retains present session values' do + session[:omniauth_provider] = 'provider_name' + session[:foo] = 'foo value' + session[:what] = 'should be cleared' subject @@ -88,16 +88,16 @@ expect(session[:user_id]).to eq input_user.id end - context "if provider retains oidc session values" do + context 'if provider retains oidc session values' do let(:retained_values) { %w[omniauth.oidc_sid] } let(:sso_provider) do { - name: "oidc", + name: 'oidc', retain_from_session: %w[omniauth.oidc_sid] } end - it "retains an oidc session token (Regression #52185)" do + it 'retains an oidc session token (Regression #52185)' do expect(OpenProject::Hook) .to receive(:call_hook) # rubocop:disable RSpec/MessageSpies .with( @@ -105,91 +105,91 @@ { request: {}, user: input_user, - session: hash_including("omniauth.oidc_sid" => "1234", user_id: input_user.id) + session: hash_including('omniauth.oidc_sid' => '1234', user_id: input_user.id) } ) - session[:omniauth_provider] = "provider_name" - session["omniauth.oidc_sid"] = "1234" + session[:omniauth_provider] = 'provider_name' + session['omniauth.oidc_sid'] = '1234' subject - expect(session["omniauth.oidc_sid"]).to eq "1234" + expect(session['omniauth.oidc_sid']).to eq '1234' end end end - it "retains present flash values" do - flash[:notice] = "bar" # rubocop:disable Rails/I18nLocaleTexts + it 'retains present flash values' do + flash[:notice] = 'bar' # rubocop:disable Rails/I18nLocaleTexts subject - expect(controller.flash[:notice]).to eq "bar" + expect(controller.flash[:notice]).to eq 'bar' end end end - describe "autologin cookie" do + describe 'autologin cookie' do before do session[:autologin_requested] = true if autologin_requested end - shared_examples "does not set autologin cookie" do - it "does not set a cookie" do + shared_examples 'does not set autologin cookie' do + it 'does not set a cookie' do subject expect(Token::AutoLogin.exists?(user: input_user)).to be false - expect(cookies[OpenProject::Configuration["autologin_cookie_name"]]).to be_nil + expect(cookies[OpenProject::Configuration['autologin_cookie_name']]).to be_nil end end - context "when not requested and disabled", with_settings: { autologin: 0 } do + context 'when not requested and disabled', with_settings: { autologin: 0 } do let(:autologin_requested) { false } - it_behaves_like "does not set autologin cookie" + it_behaves_like 'does not set autologin cookie' end - context "when not requested and enabled", with_settings: { autologin: 1 } do + context 'when not requested and enabled', with_settings: { autologin: 1 } do let(:autologin_requested) { false } - it_behaves_like "does not set autologin cookie" + it_behaves_like 'does not set autologin cookie' end - context "when requested, but disabled", with_settings: { autologin: 0 } do + context 'when requested, but disabled', with_settings: { autologin: 0 } do let(:autologin_requested) { true } - it_behaves_like "does not set autologin cookie" + it_behaves_like 'does not set autologin cookie' end - context "when requested and enabled", with_settings: { autologin: 1 } do + context 'when requested and enabled', with_settings: { autologin: 1 } do let(:autologin_requested) { true } - it "sets a cookie" do + it 'sets a cookie' do subject tokens = Token::AutoLogin.where(user: input_user) expect(tokens.count).to eq 1 expect(tokens.first.user_id).to eq input_user.id - autologin_cookie = cookies[OpenProject::Configuration["autologin_cookie_name"]] + autologin_cookie = cookies[OpenProject::Configuration['autologin_cookie_name']] expect(autologin_cookie).to be_present expect(autologin_cookie[:value]).to be_present expect(autologin_cookie[:expires]).to eq (Time.zone.today + 1.day).beginning_of_day - expect(autologin_cookie[:path]).to eq "/" + expect(autologin_cookie[:path]).to eq '/' expect(autologin_cookie[:httponly]).to be true expect(autologin_cookie[:secure]).to eq Setting.https? expect(Token::AutoLogin.find_by_plaintext_value(autologin_cookie[:value])).to eq tokens.first end end - context "when requested and enabled with https", + context 'when requested and enabled with https', with_config: { https: true }, with_settings: { autologin: 1 } do let(:autologin_requested) { true } - it "sets a secure cookie" do + it 'sets a secure cookie' do subject - autologin_cookie = cookies[OpenProject::Configuration["autologin_cookie_name"]] + autologin_cookie = cookies[OpenProject::Configuration['autologin_cookie_name']] expect(autologin_cookie[:secure]).to be true end end diff --git a/spec/services/users/logout_service_spec.rb b/spec/services/users/logout_service_spec.rb index 95af0f7fa0b1..bf8996a7aa3b 100644 --- a/spec/services/users/logout_service_spec.rb +++ b/spec/services/users/logout_service_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Users::LogoutService, type: :model do shared_let(:user) { create(:user) } let(:request) { {} } let(:browser) do instance_double(Browser::Safari, - name: "Safari", - version: "13.2", - platform: instance_double(Browser::Platform::Linux, name: "Linux")) + name: 'Safari', + version: '13.2', + platform: instance_double(Browser::Platform::Linux, name: 'Linux')) end let(:cookies) { {} } let(:controller) { instance_double(ApplicationController, browser:, cookies:) } @@ -48,8 +48,8 @@ allow(controller).to(receive(:reset_session)) end - describe "User.current" do - it "resets it" do + describe 'User.current' do + it 'resets it' do User.current = user subject @@ -58,13 +58,13 @@ end end - describe "delete other sessions on destroy" do + describe 'delete other sessions on destroy' do let!(:sessions) { create_list(:user_session, 2, user:) } let!(:other_session) { create(:user_session) } - context "when config is enabled", + context 'when config is enabled', with_config: { drop_old_sessions_on_logout: true } do - it "destroys both sessions" do + it 'destroys both sessions' do expect(Sessions::UserSession.count).to eq(3) expect(Sessions::UserSession.for_user(user).count).to eq(2) @@ -74,11 +74,11 @@ expect(Sessions::UserSession.for_user(user).count).to eq(0) end - describe "autologin cookie" do + describe 'autologin cookie' do let!(:token) { create(:autologin_token, user:) } let!(:other_token) { create(:autologin_token, user:) } - it "removes all autologin tokens" do + it 'removes all autologin tokens' do cookies[OpenProject::Configuration.autologin_cookie_name] = token.plain_value subject @@ -91,9 +91,9 @@ end end - context "when config is disabled", + context 'when config is disabled', with_config: { drop_old_sessions_on_logout: false } do - it "destroys none of the existing sessions" do + it 'destroys none of the existing sessions' do expect(Sessions::UserSession.count).to eq(3) expect(Sessions::UserSession.for_user(user).count).to eq(2) @@ -103,11 +103,11 @@ expect(Sessions::UserSession.for_user(user).count).to eq(2) end - describe "autologin cookie" do + describe 'autologin cookie' do let!(:token) { create(:autologin_token, user:) } let!(:other_token) { create(:autologin_token, user:) } - it "removes the matching autologin cookie and token" do + it 'removes the matching autologin cookie and token' do cookies[OpenProject::Configuration.autologin_cookie_name] = token.plain_value subject diff --git a/spec/services/users/register_user_service_spec.rb b/spec/services/users/register_user_service_spec.rb index 1f25a7981bf8..5881c3225a71 100644 --- a/spec/services/users/register_user_service_spec.rb +++ b/spec/services/users/register_user_service_spec.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe Users::RegisterUserService do let(:user) { build(:user) } @@ -41,8 +41,8 @@ def with_all_registration_options(except: []) end end - describe "#register_invited_user" do - it "tries to activate that user regardless of settings" do + describe '#register_invited_user' do + it 'tries to activate that user regardless of settings' do with_all_registration_options do |_type| user = User.new(status: Principal.statuses[:invited]) instance = described_class.new(user) @@ -58,8 +58,8 @@ def with_all_registration_options(except: []) end end - describe "#register_ldap_user" do - it "tries to activate that user regardless of settings" do + describe '#register_ldap_user' do + it 'tries to activate that user regardless of settings' do with_all_registration_options do |_type| user = User.new(status: Principal.statuses[:registered]) instance = described_class.new(user) @@ -76,8 +76,8 @@ def with_all_registration_options(except: []) end end - describe "#register_omniauth_user" do - let(:user) { User.new(status: Principal.statuses[:registered], identity_url: "azure:1234") } + describe '#register_omniauth_user' do + let(:user) { User.new(status: Principal.statuses[:registered], identity_url: 'azure:1234') } let(:instance) { described_class.new(user) } before do @@ -88,7 +88,7 @@ def with_all_registration_options(except: []) allow(EnterpriseToken).to receive(:show_banners?).and_return false end - it "tries to activate that user regardless of settings" do + it 'tries to activate that user regardless of settings' do with_all_registration_options do |_type| call = instance.call expect(call).to be_success @@ -97,7 +97,7 @@ def with_all_registration_options(except: []) end end - context "with limit_self_registration enabled and self_registration disabled", + context 'with limit_self_registration enabled and self_registration disabled', with_settings: { self_registration: 0, plugin_openproject_openid_connect: { @@ -106,15 +106,15 @@ def with_all_registration_options(except: []) } } } do - it "fails to activate due to disabled self registration" do + it 'fails to activate due to disabled self registration' do call = instance.call expect(call).not_to be_success expect(call.result).to eq user - expect(call.message).to eq I18n.t("account.error_self_registration_limited_provider", name: "azure") + expect(call.message).to eq I18n.t('account.error_self_registration_limited_provider', name: 'azure') end end - context "with limit_self_registration enabled and self_registration manual", + context 'with limit_self_registration enabled and self_registration manual', with_settings: { self_registration: 2, plugin_openproject_openid_connect: { @@ -123,7 +123,7 @@ def with_all_registration_options(except: []) } } } do - it "registers the user, but does not activate it" do + it 'registers the user, but does not activate it' do call = instance.call expect(call).to be_success expect(call.result).to eq user @@ -133,7 +133,7 @@ def with_all_registration_options(except: []) end end - context "with limit_self_registration enabled and self_registration email", + context 'with limit_self_registration enabled and self_registration email', with_settings: { self_registration: 1, plugin_openproject_openid_connect: { @@ -142,7 +142,7 @@ def with_all_registration_options(except: []) } } } do - it "registers the user, but does not activate it" do + it 'registers the user, but does not activate it' do call = instance.call expect(call).to be_success expect(call.result).to eq user @@ -152,7 +152,7 @@ def with_all_registration_options(except: []) end end - context "with limit_self_registration enabled and self_registration automatic", + context 'with limit_self_registration enabled and self_registration automatic', with_settings: { self_registration: 3, plugin_openproject_openid_connect: { @@ -161,7 +161,7 @@ def with_all_registration_options(except: []) } } } do - it "activates the user" do + it 'activates the user' do call = instance.call expect(call).to be_success expect(call.result).to eq user @@ -171,8 +171,8 @@ def with_all_registration_options(except: []) end end - describe "#ensure_registration_allowed!" do - it "returns an error for disabled" do + describe '#ensure_registration_allowed!' do + it 'returns an error for disabled' do allow(Setting).to receive(:self_registration).and_return(0) user = User.new @@ -184,10 +184,10 @@ def with_all_registration_options(except: []) call = instance.call expect(call.result).to eq user - expect(call.message).to eq I18n.t("account.error_self_registration_disabled") + expect(call.message).to eq I18n.t('account.error_self_registration_disabled') end - it "does not return an error for all cases except disabled" do + it 'does not return an error for all cases except disabled' do with_all_registration_options(except: :disabled) do |_type| user = User.new instance = described_class.new(user) @@ -195,19 +195,19 @@ def with_all_registration_options(except: []) # Assuming the next returns a result expect(instance) .to(receive(:ensure_user_limit_not_reached!)) - .and_return(ServiceResult.failure(result: user, message: "test stop")) + .and_return(ServiceResult.failure(result: user, message: 'test stop')) expect(user).not_to receive(:activate) expect(user).not_to receive(:save) call = instance.call expect(call.result).to eq user - expect(call.message).to eq "test stop" + expect(call.message).to eq 'test stop' end end end - describe "ensure_user_limit_not_reached!", + describe 'ensure_user_limit_not_reached!', with_settings: { self_registration: 1 } do before do expect(OpenProject::Enterprise) @@ -215,34 +215,34 @@ def with_all_registration_options(except: []) .and_return(limit_reached) end - context "when limited" do + context 'when limited' do let(:limit_reached) { true } - it "returns an error at that step" do + it 'returns an error at that step' do expect(call).to be_failure expect(call.result).to eq user expect(call.message).to eq I18n.t(:error_enterprise_activation_user_limit) end end - context "when not limited" do + context 'when not limited' do let(:limit_reached) { false } - it "returns no error" do + it 'returns no error' do # Assuming the next returns a result expect(instance) .to(receive(:register_by_email_activation)) - .and_return(ServiceResult.failure(result: user, message: "test stop")) + .and_return(ServiceResult.failure(result: user, message: 'test stop')) call = instance.call expect(call.result).to eq user - expect(call.message).to eq "test stop" + expect(call.message).to eq 'test stop' end end end - describe "#register_by_email_activation" do - it "activates the user with mail" do + describe '#register_by_email_activation' do + it 'activates the user with mail' do allow(Setting).to receive(:self_registration).and_return(1) user = User.new @@ -260,7 +260,7 @@ def with_all_registration_options(except: []) expect(call.message).to eq I18n.t(:notice_account_register_done) end - it "does not return an error for all cases except disabled" do + it 'does not return an error for all cases except disabled' do with_all_registration_options(except: %i[disabled activation_by_email]) do user = User.new instance = described_class.new(user) @@ -268,20 +268,20 @@ def with_all_registration_options(except: []) # Assuming the next returns a result expect(instance) .to(receive(:register_automatically)) - .and_return(ServiceResult.failure(result: user, message: "test stop")) + .and_return(ServiceResult.failure(result: user, message: 'test stop')) expect(user).not_to receive(:activate) expect(user).not_to receive(:save) call = instance.call expect(call.result).to eq user - expect(call.message).to eq "test stop" + expect(call.message).to eq 'test stop' end end end - describe "#register_automatically" do - it "activates the user with mail" do + describe '#register_automatically' do + it 'activates the user with mail' do allow(Setting).to receive(:self_registration).and_return(3) user = User.new @@ -297,7 +297,7 @@ def with_all_registration_options(except: []) expect(call.message).to eq I18n.t(:notice_account_activated) end - it "does not return an error if manual" do + it 'does not return an error if manual' do allow(Setting).to receive(:self_registration).and_return(2) user = User.new @@ -306,21 +306,21 @@ def with_all_registration_options(except: []) # Assuming the next returns a result expect(instance) .to(receive(:register_manually)) - .and_return(ServiceResult.failure(result: user, message: "test stop")) + .and_return(ServiceResult.failure(result: user, message: 'test stop')) expect(user).not_to receive(:activate) expect(user).not_to receive(:save) call = instance.call expect(call.result).to eq user - expect(call.message).to eq "test stop" + expect(call.message).to eq 'test stop' end end - describe "#register_manually" do + describe '#register_manually' do let(:admin_stub) { build_stubbed(:admin) } - it "activates the user with mail" do + it 'activates the user with mail' do allow(User).to receive_message_chain(:admin, :active).and_return([admin_stub]) allow(Setting).to receive(:self_registration).and_return(2) @@ -331,7 +331,7 @@ def with_all_registration_options(except: []) expect(user).not_to receive(:activate) expect(user).to receive(:save).and_return true - mail_stub = double("Mail", deliver_later: true) + mail_stub = double('Mail', deliver_later: true) expect(UserMailer) .to(receive(:account_activation_requested)) .with(admin_stub, user) @@ -346,9 +346,9 @@ def with_all_registration_options(except: []) end end - describe "error handling" do - it "turns it into a service result" do - allow(instance).to receive(:ensure_registration_allowed!).and_raise "FOO!" + describe 'error handling' do + it 'turns it into a service result' do + allow(instance).to receive(:ensure_registration_allowed!).and_raise 'FOO!' expect(call).to be_failure # Does not include the internal error message itself @@ -356,6 +356,6 @@ def with_all_registration_options(except: []) end end - describe "#with_saved_user_result" do + describe '#with_saved_user_result' do end end diff --git a/spec/services/users/replace_mentions_service_integration_spec.rb b/spec/services/users/replace_mentions_service_integration_spec.rb index ec3aa33611c9..f36d94bbeb5e 100644 --- a/spec/services/users/replace_mentions_service_integration_spec.rb +++ b/spec/services/users/replace_mentions_service_integration_spec.rb @@ -26,26 +26,26 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Users::ReplaceMentionsService, "integration" do +RSpec.describe Users::ReplaceMentionsService, 'integration' do subject(:service_call) { instance.call(from: principal, to: to_user) } - shared_let(:other_user) { create(:user, firstname: "Frank", lastname: "Herbert") } - shared_let(:user) { create(:user, firstname: "Isaac", lastname: "Asimov") } - shared_let(:group) { create(:group, lastname: "Sci-Fi") } - shared_let(:to_user) { create(:user, firstname: "Philip K.", lastname: "Dick") } + shared_let(:other_user) { create(:user, firstname: 'Frank', lastname: 'Herbert') } + shared_let(:user) { create(:user, firstname: 'Isaac', lastname: 'Asimov') } + shared_let(:group) { create(:group, lastname: 'Sci-Fi') } + shared_let(:to_user) { create(:user, firstname: 'Philip K.', lastname: 'Dick') } let(:principal) { user } - shared_examples_for "successful service call" do - it "is successful" do + shared_examples_for 'successful service call' do + it 'is successful' do expect(service_call) .to be_success end end - shared_examples_for "text replacement" do |attribute| + shared_examples_for 'text replacement' do |attribute| before do service_call model.reload @@ -57,16 +57,16 @@ end end - shared_examples_for "rewritten mention" do |factory, attribute| + shared_examples_for 'rewritten mention' do |factory, attribute| let(:additional_properties) { {} } let!(:model) do create(factory, attribute => text, **additional_properties) end - context "with the replaced user in mention tags" do + context 'with the replaced user in mention tags' do let(:principal) { user } - it_behaves_like "text replacement", attribute do + it_behaves_like 'text replacement', attribute do let(:text) do <<~TEXT 30 characters)" do - email = "hallowurstsalatgetraenkebuechse@veryopensuchproject.openproject.com" + it 'trims names if they are too long (> 30 characters)' do + email = 'hallowurstsalatgetraenkebuechse@veryopensuchproject.openproject.com' first, last = instance.send(:placeholder_name, email) - expect(first).to eq "hallowurstsalatgetraenkebue..." - expect(last).to eq "@veryopensuchproject.openpro..." + expect(first).to eq 'hallowurstsalatgetraenkebue...' + expect(last).to eq '@veryopensuchproject.openpro...' end end end diff --git a/spec/services/users/update_service_spec.rb b/spec/services/users/update_service_spec.rb index 5967dea979fc..9162d627a8c7 100644 --- a/spec/services/users/update_service_spec.rb +++ b/spec/services/users/update_service_spec.rb @@ -25,110 +25,110 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe Users::UpdateService do - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do # The user service also tries to save the preferences before do allow(model_instance.pref).to receive(:save).and_return(true) end end - describe "updating attributes" do + describe 'updating attributes' do let(:instance) { described_class.new(model: update_user, user: current_user) } let(:current_user) { create(:admin) } - let(:update_user) { create(:user, mail: "correct@example.org") } + let(:update_user) { create(:user, mail: 'correct@example.org') } subject { instance.call(attributes:) } - context "when invalid" do - let(:attributes) { { mail: "invalid" } } + context 'when invalid' do + let(:attributes) { { mail: 'invalid' } } - it "fails to update" do + it 'fails to update' do expect(subject).not_to be_success update_user.reload - expect(update_user.mail).to eq("correct@example.org") + expect(update_user.mail).to eq('correct@example.org') expect(subject.errors.symbols_for(:mail)).to match_array(%i[email]) end end - context "when valid" do - let(:attributes) { { mail: "new@example.org" } } + context 'when valid' do + let(:attributes) { { mail: 'new@example.org' } } - it "updates the user" do + it 'updates the user' do expect(subject).to be_success update_user.reload - expect(update_user.mail).to eq("new@example.org") + expect(update_user.mail).to eq('new@example.org') end - context "if current_user is no admin" do + context 'if current_user is no admin' do let(:current_user) { build_stubbed(:user) } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).not_to be_success end end end - context "when valid status" do + context 'when valid status' do let(:attributes) { { status: Principal.statuses[:locked] } } - it "updates the user" do + it 'updates the user' do expect(subject).to be_success update_user.reload expect(update_user).to be_locked end - context "if current_user is no admin" do + context 'if current_user is no admin' do let(:current_user) { build_stubbed(:user) } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).not_to be_success end end end - describe "updating prefs" do + describe 'updating prefs' do let(:attributes) { {} } before do allow(update_user).to receive(:save).and_return(user_save_result) end - context "if the user was updated calls the prefs" do + context 'if the user was updated calls the prefs' do let(:user_save_result) { true } before do expect(update_user.pref).to receive(:save).and_return(pref_save_result) end - context "and the prefs can be saved" do + context 'and the prefs can be saved' do let(:pref_save_result) { true } - it "returns a successful call" do + it 'returns a successful call' do expect(subject).to be_success end end - context "and the prefs can not be saved" do + context 'and the prefs can not be saved' do let(:pref_save_result) { false } - it "returns an erroneous call" do + it 'returns an erroneous call' do expect(subject).not_to be_success end end end - context "if the user was not saved" do + context 'if the user was not saved' do let(:user_save_result) { false } - it "does not call #prefs.save" do + it 'does not call #prefs.save' do expect(update_user.pref).not_to receive(:save) expect(subject).not_to be_success end diff --git a/spec/services/wiki_pages/copy_service_integration_spec.rb b/spec/services/wiki_pages/copy_service_integration_spec.rb index 1757d6aaf0ae..0bc66ca3fbb7 100644 --- a/spec/services/wiki_pages/copy_service_integration_spec.rb +++ b/spec/services/wiki_pages/copy_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WikiPages::CopyService, "integration", type: :model do +RSpec.describe WikiPages::CopyService, 'integration', type: :model do let(:user) do create(:user) do |user| create(:member, @@ -76,34 +76,34 @@ login_as(user) end - describe "#call" do - shared_examples_for "copied wiki page" do - it "is a success" do + describe '#call' do + shared_examples_for 'copied wiki page' do + it 'is a success' do expect(service_result) .to be_success end - it "is a new, persisted wiki page" do + it 'is a new, persisted wiki page' do expect(copy).to be_persisted expect(copy.id).not_to eq(wiki_page.id) end - it "copies the text" do + it 'copies the text' do expect(copy.text).to eq(wiki_page.text) end - it "sets the author to be the current user" do + it 'sets the author to be the current user' do expect(copy.author).to eq(user) end - context "with attachments" do + context 'with attachments' do let!(:attachment) do create(:attachment, container: wiki_page) end - context "when specifying to copy attachments (default)" do - it "copies the attachment" do + context 'when specifying to copy attachments (default)' do + it 'copies the attachment' do expect(copy.attachments.length) .to eq 1 @@ -115,7 +115,7 @@ end end - context "when referencing the attachment in the wiki text" do + context 'when referencing the attachment in the wiki text' do let(:text) do <<~MARKDOWN # Some text here @@ -128,7 +128,7 @@ wiki_page.update!(text:) end - it "updates the attachment reference" do + it 'updates the attachment reference' do expect(wiki_page.text).to include "/api/v3/attachments/#{attachment.id}/content" expect(copy.attachments.length).to eq 1 @@ -139,10 +139,10 @@ end end - context "when specifying to not copy attachments" do + context 'when specifying to not copy attachments' do let(:attributes) { { copy_attachments: false } } - it "copies the attachment" do + it 'copies the attachment' do expect(copy.attachments.length) .to eq 0 end @@ -150,10 +150,10 @@ end end - describe "to a different wiki" do + describe 'to a different wiki' do let(:attributes) { { wiki: sink_wiki } } - it_behaves_like "copied wiki page" + it_behaves_like 'copied wiki page' end end end diff --git a/spec/services/wiki_pages/set_attributes_service_spec.rb b/spec/services/wiki_pages/set_attributes_service_spec.rb index 1e0801f44fc3..20dda5649628 100644 --- a/spec/services/wiki_pages/set_attributes_service_spec.rb +++ b/spec/services/wiki_pages/set_attributes_service_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WikiPages::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } let(:contract_class) do - contract = double("contract_class") + contract = double('contract_class') allow(contract) .to receive(:new) @@ -41,11 +41,11 @@ contract end let(:contract_instance) do - double("contract_instance", validate: contract_valid, errors: contract_errors) + double('contract_instance', validate: contract_valid, errors: contract_errors) end let(:contract_valid) { true } let(:contract_errors) do - double("contract_errors") + double('contract_errors') end let(:wiki_page_valid) { true } let(:instance) do @@ -58,13 +58,13 @@ build_stubbed(:wiki_page) end - describe "call" do + describe 'call' do let(:call_attributes) do { - text: "some new text", - title: "a new title", - slug: "a new slug", - journal_notes: "the journal notes" + text: 'some new text', + title: 'a new title', + slug: 'a new slug', + journal_notes: 'the journal notes' } end @@ -80,12 +80,12 @@ subject { instance.call(call_attributes) } - it "is successful" do + it 'is successful' do expect(subject).to be_success end - context "for an existing wiki page" do - it "sets the attributes" do + context 'for an existing wiki page' do + it 'sets the attributes' do subject expect(wiki_page.attributes.slice(*wiki_page.changed).symbolize_keys) @@ -95,7 +95,7 @@ .to eql call_attributes[:journal_notes] end - it "does not persist the wiki_page" do + it 'does not persist the wiki_page' do expect(wiki_page) .not_to receive(:save) @@ -103,12 +103,12 @@ end end - context "for a new wiki page" do + context 'for a new wiki page' do let(:wiki_page) do WikiPage.new end - it "sets the attributes with the user being the author" do + it 'sets the attributes with the user being the author' do subject expect(wiki_page.attributes.slice(*wiki_page.changed).symbolize_keys) @@ -118,10 +118,10 @@ .to eql call_attributes[:journal_notes] end - it "marks the author to be system changed" do + it 'marks the author to be system changed' do subject - expect(wiki_page.changed_by_system["author_id"]) + expect(wiki_page.changed_by_system['author_id']) .to eql [nil, user.id] end end diff --git a/spec/services/work_package_members/create_or_update_service_spec.rb b/spec/services/work_package_members/create_or_update_service_spec.rb index 5ea7609054d7..fbd6a5aad1d2 100644 --- a/spec/services/work_package_members/create_or_update_service_spec.rb +++ b/spec/services/work_package_members/create_or_update_service_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackageMembers::CreateOrUpdateService do let(:user) { build_stubbed(:user) } @@ -48,11 +48,11 @@ .and_return(existing_member) end - context "when the user has no work_package_member for that work package" do + context 'when the user has no work_package_member for that work package' do let(:create_instance) { instance_double(WorkPackageMembers::CreateService) } let(:existing_member) { nil } - it "calls the WorkPackageMembers::CreateService" do + it 'calls the WorkPackageMembers::CreateService' do allow(WorkPackageMembers::CreateService).to receive(:new).and_return(create_instance) allow(create_instance).to receive(:call).and_return(service_result) @@ -64,11 +64,11 @@ end end - context "when the user already has a work_package_member for that work package" do + context 'when the user already has a work_package_member for that work package' do let(:update_instance) { instance_double(WorkPackageMembers::UpdateService) } let(:existing_member) { build_stubbed(:work_package_member) } - it "calls the WorkPackageMembers::UpdateService" do + it 'calls the WorkPackageMembers::UpdateService' do allow(WorkPackageMembers::UpdateService).to receive(:new).and_return(update_instance) allow(update_instance).to receive(:call).and_return(service_result) diff --git a/spec/services/work_package_members/create_service_spec.rb b/spec/services/work_package_members/create_service_spec.rb index a137bafbf06c..9af94ffcec3f 100644 --- a/spec/services/work_package_members/create_service_spec.rb +++ b/spec/services/work_package_members/create_service_spec.rb @@ -28,8 +28,8 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "services/base_services/behaves_like_create_service" +require 'spec_helper' +require 'services/base_services/behaves_like_create_service' RSpec.describe WorkPackageMembers::CreateService, type: :model do subject(:service_call) { instance.call(call_attributes) } @@ -69,13 +69,13 @@ def stub_notifications before { stub_notifications } - it_behaves_like "BaseServices create service" do + it_behaves_like 'BaseServices create service' do let(:model_class) { Member } let(:principal) { richard } let(:call_attributes) { { principal:, roles: [role], entity: work_package, project: work_package.project } } - context "when successful" do - it "sends a notification" do + context 'when successful' do + it 'sends a notification' do service_call expect(OpenProject::Notifications) @@ -85,8 +85,8 @@ def stub_notifications send_notifications: true) end - context "for a User" do - it "does not create any inherited roles" do + context 'for a User' do + it 'does not create any inherited roles' do service_call expect(Groups::CreateInheritedRolesService) @@ -94,7 +94,7 @@ def stub_notifications end end - context "for a Group" do + context 'for a Group' do let(:principal) { cool_group } let(:model_instance) { build_stubbed(:member, principal:) } diff --git a/spec/services/work_package_members/set_attributes_service_spec.rb b/spec/services/work_package_members/set_attributes_service_spec.rb index b7111e67fe8d..be23e01d1fcf 100644 --- a/spec/services/work_package_members/set_attributes_service_spec.rb +++ b/spec/services/work_package_members/set_attributes_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackageMembers::SetAttributesService, type: :model do let(:user) { build_stubbed(:user) } @@ -58,7 +58,7 @@ contract_class:) end - describe "call" do + describe 'call' do let(:call_attributes) do { user_id: 3, @@ -78,64 +78,64 @@ subject { instance.call(call_attributes) } - it "is successful" do + it 'is successful' do expect(subject).to be_success end - it "does not persist the member" do + it 'does not persist the member' do subject expect(member) .not_to have_received(:save) end - context "for a new record" do - it "sets the attributes and also takes the project_id from the work package" do + context 'for a new record' do + it 'sets the attributes and also takes the project_id from the work package' do subject expect(member.attributes.slice(*member.changed).symbolize_keys) - .to eql(user_id: 3, entity_id: work_package.id, entity_type: "WorkPackage", project_id: work_package.project_id) + .to eql(user_id: 3, entity_id: work_package.id, entity_type: 'WorkPackage', project_id: work_package.project_id) end - it "marks the project_id to be changed by the system" do + it 'marks the project_id to be changed by the system' do subject expect(member.changed_by_system) - .to eql("project_id" => [nil, member.project_id]) + .to eql('project_id' => [nil, member.project_id]) end end # Changing the entity should not really happen in reality but if it does, this is what happens. - context "for a persisted record" do + context 'for a persisted record' do let(:member) { existing_member } - it "sets the attributes and also takes the project_id from the work package" do + it 'sets the attributes and also takes the project_id from the work package' do subject expect(member.attributes.slice(*member.changed).symbolize_keys) .to eql(user_id: 3, entity_id: work_package.id, project_id: work_package.project_id) end - it "marks the project_id to be changed by the system" do + it 'marks the project_id to be changed by the system' do subject expect(member.changed_by_system) - .to eql("project_id" => [member.project_id_was, member.project_id]) + .to eql('project_id' => [member.project_id_was, member.project_id]) end end - context "if the contract is invalid" do + context 'if the contract is invalid' do let(:contract_valid) { false } - it "is unsuccessful" do + it 'is unsuccessful' do expect(subject).not_to be_success end - it "returns the errors of the contract" do + it 'returns the errors of the contract' do expect(subject.errors).to eql contract_errors end - it "does not persist the member" do + it 'does not persist the member' do subject expect(member) @@ -143,7 +143,7 @@ end end - context "with changes to the roles" do + context 'with changes to the roles' do let(:first_role) { build_stubbed(:project_role) } let(:second_role) { build_stubbed(:project_role) } let(:third_role) { build_stubbed(:project_role) } @@ -154,17 +154,17 @@ } end - context "with a persisted record" do + context 'with a persisted record' do let(:member) do build_stubbed(:work_package_member, roles: [first_role, second_role]) end - it "adds the new role and marks the other for destruction" do + it 'adds the new role and marks the other for destruction' do expect(subject.result.member_roles.map(&:role_id)).to contain_exactly(first_role.id, second_role.id, third_role.id) expect(subject.result.member_roles.detect { _1.role_id == first_role.id }).to be_marked_for_destruction end - context "when a role being assigned is already inherited via a group" do + context 'when a role being assigned is already inherited via a group' do let(:member) do build_stubbed(:work_package_member, roles: [first_role, second_role, third_role]) end @@ -175,7 +175,7 @@ .and_return(true) end - it "still adds the role and marks the ones not added for destruction" do + it 'still adds the role and marks the ones not added for destruction' do membership = subject.result expect(membership.member_roles.map(&:role_id)) @@ -190,51 +190,51 @@ end end - context "with a new record" do + context 'with a new record' do let(:member) do Member.new end - it "adds the new role" do + it 'adds the new role' do expect(subject.result.member_roles.map(&:role_id)).to contain_exactly(second_role.id, third_role.id) end - context "with role_ids not all being present" do + context 'with role_ids not all being present' do let(:call_attributes) do { - role_ids: [nil, "", second_role.id, third_role.id] + role_ids: [nil, '', second_role.id, third_role.id] } end - it "ignores the empty values" do + it 'ignores the empty values' do expect(subject.result.member_roles.map(&:role_id)).to contain_exactly(second_role.id, third_role.id) end end end - context "with attempting to sent `roles`" do + context 'with attempting to sent `roles`' do let(:call_attributes) do { roles: [second_role, third_role] } end - context "with a new record" do + context 'with a new record' do let(:member) do Member.new end - it "sets the new role" do + it 'sets the new role' do expect(subject.result.roles).to contain_exactly(second_role, third_role) end end - context "with a persisted record" do + context 'with a persisted record' do let(:member) do build_stubbed(:work_package_member, roles: [second_role]) end - it "raises an error" do + it 'raises an error' do expect { subject } .to raise_error(ArgumentError) end diff --git a/spec/services/work_package_members/update_service_spec.rb b/spec/services/work_package_members/update_service_spec.rb index d2ffd4fd663a..626955264fd8 100644 --- a/spec/services/work_package_members/update_service_spec.rb +++ b/spec/services/work_package_members/update_service_spec.rb @@ -28,8 +28,8 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe WorkPackageMembers::UpdateService do let!(:groups_update_roles_service) do @@ -43,15 +43,15 @@ end end - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do let(:model_class) { Member } let!(:model_instance) { build_stubbed(:work_package_member, principal:) } let(:principal) { build_stubbed(:user) } let(:role) { build_stubbed(:view_work_package_role) } let(:call_attributes) { { roles: [role] } } - context "when successful" do - context "when the member being updates is a User" do + context 'when successful' do + context 'when the member being updates is a User' do it "doesn't attempt any group member post-processing" do instance_call @@ -60,7 +60,7 @@ end end - context "when the member being updated is a Group" do + context 'when the member being updated is a Group' do let(:principal) { build_stubbed(:group) } it "updates the group member's roles" do diff --git a/spec/services/work_packages/copy_service_integration_spec.rb b/spec/services/work_packages/copy_service_integration_spec.rb index 39376dd8a41e..cde3bb89f09f 100644 --- a/spec/services/work_packages/copy_service_integration_spec.rb +++ b/spec/services/work_packages/copy_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::CopyService, "integration", type: :model do +RSpec.describe WorkPackages::CopyService, 'integration', type: :model do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -73,24 +73,24 @@ current_user { user } - describe "#call" do - shared_examples_for "copied work package" do + describe '#call' do + shared_examples_for 'copied work package' do subject { copy } it { expect(subject.id).not_to eq(work_package.id) } it { is_expected.to be_persisted } end - context "with the same project" do - it_behaves_like "copied work package" + context 'with the same project' do + it_behaves_like 'copied work package' - describe "#project" do + describe '#project' do subject { copy.project } it { is_expected.to eq(source_project) } end - describe "copied watchers" do + describe 'copied watchers' do let(:watcher_user) do create(:user, member_with_permissions: { source_project => %i(view_work_packages) }) @@ -100,14 +100,14 @@ work_package.add_watcher(watcher_user) end - it "copies the watcher and does not add the copying user as a watcher" do + it 'copies the watcher and does not add the copying user as a watcher' do expect(copy.watcher_users) .to contain_exactly(watcher_user) end end end - describe "to a different project" do + describe 'to a different project' do let(:target_type) { create(:type, custom_fields: target_custom_fields) } let(:target_project) do p = create(:project, @@ -126,21 +126,21 @@ let(:target_permissions) { %i(add_work_packages manage_subtasks) } let(:attributes) { { project: target_project, type: target_type } } - it_behaves_like "copied work package" + it_behaves_like 'copied work package' - context "project" do + context 'project' do subject { copy.project_id } it { is_expected.to eq(target_project.id) } end - context "type" do + context 'type' do subject { copy.type_id } it { is_expected.to eq(target_type.id) } end - context "custom_fields" do + context 'custom_fields' do before do custom_value end @@ -150,28 +150,28 @@ it { is_expected.to be_nil } end - context "required custom field in the target project" do + context 'required custom field in the target project' do let(:custom_field) do create( :work_package_custom_field, - field_format: "text", + field_format: 'text', is_required: true, is_for_all: false ) end let(:target_custom_fields) { [custom_field] } - it "does not copy the work package" do + it 'does not copy the work package' do expect(service_result).to be_failure end end - describe "#attributes" do + describe '#attributes' do before do target_project.types << work_package.type end - context "assigned_to" do + context 'assigned_to' do let(:target_user) { create(:user) } let(:target_project_member) do create(:member, @@ -185,41 +185,41 @@ target_project_member end - it_behaves_like "copied work package" + it_behaves_like 'copied work package' subject { copy.assigned_to_id } it { is_expected.to eq(target_user.id) } end - context "status" do + context 'status' do let(:target_status) { create(:status) } let(:attributes) { { project: target_project, status_id: target_status.id } } - it_behaves_like "copied work package" + it_behaves_like 'copied work package' subject { copy.status_id } it { is_expected.to eq(target_status.id) } end - context "date" do + context 'date' do let(:target_date) { Date.today + 14 } - context "start" do + context 'start' do let(:attributes) { { project: target_project, start_date: target_date } } - it_behaves_like "copied work package" + it_behaves_like 'copied work package' subject { copy.start_date } it { is_expected.to eq(target_date) } end - context "end" do + context 'end' do let(:attributes) { { project: target_project, due_date: target_date } } - it_behaves_like "copied work package" + it_behaves_like 'copied work package' subject { copy.due_date } @@ -228,7 +228,7 @@ end end - describe "with children" do + describe 'with children' do let(:instance) { described_class.new(work_package: child, user:) } let!(:child) do create(:work_package, parent: work_package, project: source_project) @@ -237,7 +237,7 @@ create(:work_package, parent: child, project: source_project) end - context "cross project relations deactivated" do + context 'cross project relations deactivated' do before do allow(Setting) .to receive(:cross_project_work_package_relations?) @@ -252,7 +252,7 @@ expect(child.reload.project).to eql(source_project) end - describe "grandchild" do + describe 'grandchild' do before do grandchild end @@ -261,17 +261,17 @@ end end - context "cross project relations activated" do + context 'cross project relations activated' do before do allow(Setting).to receive(:cross_project_work_package_relations?).and_return(true) end - it "is success" do + it 'is success' do expect(service_result) .to be_success end - it "has the original parent as its parent" do + it 'has the original parent as its parent' do expect(copy.parent).to eql(child.parent) end @@ -279,7 +279,7 @@ expect(copy.project).to eql(target_project) end - describe "grandchild" do + describe 'grandchild' do before do grandchild end @@ -291,20 +291,20 @@ end end - describe "with start and due dates overwritten but not duration" do + describe 'with start and due dates overwritten but not duration' do let(:attributes) { { start_date: Time.zone.today - 5.days, due_date: Time.zone.today + 5.days } } - it_behaves_like "copied work package" + it_behaves_like 'copied work package' end - context "with attachments" do + context 'with attachments' do let!(:attachment) do create(:attachment, container: work_package) end - context "when specifying to copy attachments (default)" do - it "copies the attachment" do + context 'when specifying to copy attachments (default)' do + it 'copies the attachment' do expect(copy.attachments.length) .to eq 1 @@ -316,7 +316,7 @@ end end - context "when referencing the attachment in the description" do + context 'when referencing the attachment in the description' do let(:text) do <<~MARKDOWN # Some text here @@ -329,7 +329,7 @@ work_package.update_column(:description, text) end - it "updates the attachment reference" do + it 'updates the attachment reference' do expect(work_package.description).to include "/api/v3/attachments/#{attachment.id}/content" expect(copy.attachments.length).to eq 1 @@ -340,10 +340,10 @@ end end - context "when specifying to not copy attachments" do + context 'when specifying to not copy attachments' do let(:attributes) { { copy_attachments: false } } - it "copies the attachment" do + it 'copies the attachment' do expect(copy.attachments.length) .to eq 0 end diff --git a/spec/services/work_packages/create_service_integration_spec.rb b/spec/services/work_packages/create_service_integration_spec.rb index 7c9b1373706c..529903920b38 100644 --- a/spec/services/work_packages/create_service_integration_spec.rb +++ b/spec/services/work_packages/create_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::CreateService, "integration", type: :model do +RSpec.describe WorkPackages::CreateService, 'integration', type: :model do let(:user) do create(:user, member_with_roles: { project => role }) end @@ -47,7 +47,7 @@ let(:project) { create(:project, types: [type, default_type]) } let(:parent) do create(:work_package, - subject: "parent", + subject: 'parent', project:, type:) end @@ -77,45 +77,45 @@ login_as(user) end - context "when the only type of the project is a milestone" do + context 'when the only type of the project is a milestone' do let(:default_type) do create(:type_milestone) end let(:project) { create(:project, types: [default_type]) } - describe "call without date attributes" do + describe 'call without date attributes' do let(:attributes) do - { subject: "blubs", project: } + { subject: 'blubs', project: } end - it "creates the default type without errors" do + it 'creates the default type without errors' do expect(service_result).to be_success expect(service_result.errors).to be_empty end end - describe "call with a parent non-milestone with dates" do + describe 'call with a parent non-milestone with dates' do let(:parent) do create(:work_package, project:, - start_date: "2024-01-01", - due_date: "2024-01-10", + start_date: '2024-01-01', + due_date: '2024-01-10', type: create(:type)) end let(:attributes) do - { subject: "blubs", project:, parent: } + { subject: 'blubs', project:, parent: } end - it "creates the default type without errors" do + it 'creates the default type without errors' do expect(service_result).to be_success expect(service_result.errors).to be_empty end end end - describe "#call" do + describe '#call' do let(:attributes) do - { subject: "blubs", + { subject: 'blubs', project:, done_ratio: 50, parent:, @@ -123,7 +123,7 @@ due_date: Date.today + 3.days } end - it "creates the work_package with the provided attributes and sets the user as a watcher" do + it 'creates the work_package with the provided attributes and sets the user as a watcher' do # successful expect(service_result) .to be_success @@ -164,7 +164,7 @@ .to contain_exactly(user) end - describe "setting the attachments" do + describe 'setting the attachments' do let!(:other_users_attachment) do create(:attachment, container: nil, author: create(:user)) end @@ -172,7 +172,7 @@ create(:attachment, container: nil, author: user) end - it "reports on invalid attachments and sets the new if everything is valid" do + it 'reports on invalid attachments and sets the new if everything is valid' do result = instance.call(**attributes.merge(attachment_ids: [other_users_attachment.id])) expect(result) @@ -201,12 +201,12 @@ end end - describe "with a child creation with both dates and work" do + describe 'with a child creation with both dates and work' do let(:start_date) { Date.current } let(:due_date) { start_date + 3.days } let(:attributes) do { - subject: "child", + subject: 'child', project:, parent:, estimated_hours: 5, @@ -215,7 +215,7 @@ } end - it "correctly updates the parent values" do + it 'correctly updates the parent values' do expect(service_result) .to be_success @@ -225,46 +225,5 @@ expect(parent.due_date).to eq(due_date) end end - - describe "writing timestamps" do - shared_let(:user) { create(:admin) } - shared_let(:other_user) { create(:user) } - - let(:created_at) { 11.days.ago } - let(:updated_at) { 10.days.ago } - - let(:attributes) do - { - subject: "child", - project:, - author: other_user, - created_at:, - updated_at: - } - end - - context "when enabled", with_settings: { apiv3_write_readonly_attributes: true } do - it "updates the timestamps correctly" do - expect(service_result) - .to be_success - - expect(new_work_package.created_at).to be_within(1.second).of(created_at) - expect(new_work_package.updated_at).to be_within(1.second).of(updated_at) - end - end - - context "when disabled", with_settings: { apiv3_write_readonly_attributes: false } do - it "rejects the creation" do - expect(service_result) - .not_to be_success - - expect(new_work_package.errors.symbols_for(:created_at)) - .to contain_exactly(:error_readonly) - - expect(new_work_package.errors.symbols_for(:updated_at)) - .to contain_exactly(:error_readonly) - end - end - end end end diff --git a/spec/services/work_packages/delete_service_integration_spec.rb b/spec/services/work_packages/delete_service_integration_spec.rb index cde517d194e6..bf4e216ecd2a 100644 --- a/spec/services/work_packages/delete_service_integration_spec.rb +++ b/spec/services/work_packages/delete_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::DeleteService, "integration", type: :model do +RSpec.describe WorkPackages::DeleteService, 'integration', type: :model do shared_let(:project) { create(:project) } shared_let(:role) do create(:project_role, @@ -38,13 +38,13 @@ create(:user, member_with_roles: { project => role }) end - describe "deleting a child with estimated_hours set" do - let(:parent) { create(:work_package, project:, subject: "parent") } + describe 'deleting a child with estimated_hours set' do + let(:parent) { create(:work_package, project:, subject: 'parent') } let(:child) do create(:work_package, project:, parent:, - subject: "child", + subject: 'child', estimated_hours: 123) end @@ -61,7 +61,7 @@ parent.reload end - it "updates the parent estimated_hours" do + it 'updates the parent estimated_hours' do expect(child.estimated_hours).to eq 123 expect(parent.derived_estimated_hours).to eq 123 expect(parent.estimated_hours).to be_nil @@ -75,7 +75,7 @@ end end - describe "with a stale work package reference" do + describe 'with a stale work package reference' do let!(:work_package) { create(:work_package, project:) } let(:instance) do @@ -85,7 +85,7 @@ subject { instance.call } - it "still destroys it" do + it 'still destroys it' do # Cause lock version changes WorkPackage.where(id: work_package.id).update_all(lock_version: work_package.lock_version + 1) @@ -94,7 +94,7 @@ end end - describe "with a notification" do + describe 'with a notification' do let!(:work_package) { create(:work_package, project:) } let!(:notification) do create(:notification, @@ -111,7 +111,7 @@ subject { instance.call } - it "deletes the notification" do + it 'deletes the notification' do expect(subject).to be_success expect { work_package.reload }.to raise_error(ActiveRecord::RecordNotFound) expect { notification.reload }.to raise_error(ActiveRecord::RecordNotFound) diff --git a/spec/services/work_packages/delete_service_spec.rb b/spec/services/work_packages/delete_service_spec.rb index 965ecf961e70..39c2c1ebdb4d 100644 --- a/spec/services/work_packages/delete_service_spec.rb +++ b/spec/services/work_packages/delete_service_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::DeleteService do let(:user) do @@ -55,35 +55,35 @@ end end - it "destroys the work package" do + it 'destroys the work package' do subject end - it "is successful" do + it 'is successful' do expect(subject) .to be_success end - it "returns the destroyed work package" do + it 'returns the destroyed work package' do expect(subject.result) .to eql work_package end - it "returns an empty errors array" do + it 'returns an empty errors array' do expect(subject.errors) .to be_empty end - context "when the work package could not be destroyed" do + context 'when the work package could not be destroyed' do let(:destroyed_result) { false } - it "is no success" do + it 'is no success' do expect(subject) .not_to be_success end end - context "with ancestors" do + context 'with ancestors' do let(:parent) do build_stubbed(:work_package) end @@ -114,16 +114,16 @@ .not_to receive(:new) end - it "calls the inherit attributes service for each ancestor" do + it 'calls the inherit attributes service for each ancestor' do expect_inherited_attributes_service_calls subject end - context "when the work package could not be destroyed" do + context 'when the work package could not be destroyed' do let(:destroyed_result) { false } - it "does not call inherited attributes service" do + it 'does not call inherited attributes service' do expect_no_inherited_attributes_service_calls subject @@ -131,7 +131,7 @@ end end - context "with descendants" do + context 'with descendants' do let(:child) do build_stubbed(:work_package) end @@ -153,7 +153,7 @@ end end - it "destroys the descendants" do + it 'destroys the descendants' do descendants.each do |descendant| expect(descendant) .to receive(:destroy) @@ -162,17 +162,17 @@ subject end - it "returns the descendants as part of the result" do + it 'returns the descendants as part of the result' do subject expect(subject.all_results) .to match_array [work_package] + descendants end - context "if the work package could not be destroyed" do + context 'if the work package could not be destroyed' do let(:destroyed_result) { false } - it "does not destroy the descendants" do + it 'does not destroy the descendants' do descendants.each do |descendant| expect(descendant) .not_to receive(:destroy) diff --git a/spec/services/work_packages/schedule_dependency/dependency_spec.rb b/spec/services/work_packages/schedule_dependency/dependency_spec.rb index 3b87d5bae3b2..3257d03eb10b 100644 --- a/spec/services/work_packages/schedule_dependency/dependency_spec.rb +++ b/spec/services/work_packages/schedule_dependency/dependency_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" +require 'rails_helper' # Scenario: a work package has been moved on the calendar. The moved work # package has children, parents, followers, and/or predecessors. The @@ -38,7 +38,7 @@ create_shared_association_defaults_for_work_package_factory - shared_let(:work_package) { create(:work_package, subject: "moved") } + shared_let(:work_package) { create(:work_package, subject: 'moved') } let(:schedule_dependency) { WorkPackages::ScheduleDependency.new(work_package) } @@ -75,135 +75,135 @@ def create_child_of(work_package) create(:work_package, subject: "child of #{work_package.subject}", parent: work_package) end - describe "#dependent_ids" do - context "when the work_package has a follower" do + describe '#dependent_ids' do + context 'when the work_package has a follower' do let!(:follower) { create_follower_of(work_package) } - context "for dependency of the follower" do + context 'for dependency of the follower' do let(:work_package_used_in_dependency) { follower } - it "returns an array with the work package id" do + it 'returns an array with the work package id' do expect(subject.dependent_ids).to eq([work_package.id]) end end end - context "when the work_package has a parent" do + context 'when the work_package has a parent' do let!(:parent) { create_parent_of(work_package) } - context "for dependency of the parent" do + context 'for dependency of the parent' do let(:work_package_used_in_dependency) { parent } - it "returns an array with the work package id" do + it 'returns an array with the work package id' do expect(subject.dependent_ids).to eq([work_package.id]) end end end - context "when the work_package has a follower which has a child" do + context 'when the work_package has a follower which has a child' do let!(:follower) { create_follower_of(work_package) } let!(:follower_child) { create_child_of(follower) } - context "for dependency of the child" do + context 'for dependency of the child' do let(:work_package_used_in_dependency) { follower_child } - it "returns an array with the work_package id" do + it 'returns an array with the work_package id' do expect(subject.dependent_ids).to eq([work_package.id]) end end - context "for dependency of the follower" do + context 'for dependency of the follower' do let(:work_package_used_in_dependency) { follower } - it "returns an array with the work_package id and the follower child id" do + it 'returns an array with the work_package id and the follower child id' do expect(subject.dependent_ids).to contain_exactly(work_package.id, follower_child.id) end end end - context "when the work_package has multiple parents and followers" do + context 'when the work_package has multiple parents and followers' do let!(:first_follower) { create_follower_of(work_package) } let!(:second_follower) { create_follower_of(work_package) } let!(:first_follower_parent) { create_parent_of(first_follower) } let!(:first_follower_grandparent) { create_parent_of(first_follower_parent) } - context "for dependency of the first follower parent" do + context 'for dependency of the first follower parent' do let(:work_package_used_in_dependency) { first_follower_parent } - it "returns an array with the work_package and the first follower ids" do + it 'returns an array with the work_package and the first follower ids' do expect(subject.dependent_ids).to contain_exactly(work_package.id, first_follower.id) end end - context "for dependency of the first follower grandparent" do + context 'for dependency of the first follower grandparent' do let(:work_package_used_in_dependency) { first_follower_grandparent } - it "returns an array with the work_package, the first follower, and the first follower parent ids" do + it 'returns an array with the work_package, the first follower, and the first follower parent ids' do expect(subject.dependent_ids).to contain_exactly(work_package.id, first_follower.id, first_follower_parent.id) end end - context "for dependency of the second follower" do + context 'for dependency of the second follower' do let(:work_package_used_in_dependency) { second_follower } - it "returns an array with the work_package id" do + it 'returns an array with the work_package id' do expect(subject.dependent_ids).to contain_exactly(work_package.id) end end end - context "with more complex relations" do - context "when has two consecutive followers" do + context 'with more complex relations' do + context 'when has two consecutive followers' do let!(:follower) { create_follower_of(work_package) } let!(:follower_follower) { create_follower_of(follower) } - context "for dependency of the first follower" do + context 'for dependency of the first follower' do let(:work_package_used_in_dependency) { follower } - it "returns an array with the work_package id" do + it 'returns an array with the work_package id' do expect(subject.dependent_ids).to contain_exactly(work_package.id) end end - context "for dependency of the second follower" do + context 'for dependency of the second follower' do let(:work_package_used_in_dependency) { follower_follower } - it "returns an array with only the first follower id" do + it 'returns an array with only the first follower id' do expect(subject.dependent_ids).to contain_exactly(follower.id) end end end - context "when has a follower which has a predecessor" do + context 'when has a follower which has a predecessor' do let!(:follower) { create_follower_of(work_package) } let!(:follower_predecessor) { create_predecessor_of(follower) } - context "for dependency of the follower" do + context 'for dependency of the follower' do let(:work_package_used_in_dependency) { follower } - it "returns an array with the work_package id" do + it 'returns an array with the work_package id' do expect(subject.dependent_ids).to contain_exactly(work_package.id) end end end - context "when has a predecessor which has a parent and a child" do + context 'when has a predecessor which has a parent and a child' do let!(:follower) { create_follower_of(work_package) } let!(:follower_parent) { create_parent_of(follower) } let!(:follower_child) { create_child_of(follower) } - context "for dependency of the follower child" do + context 'for dependency of the follower child' do let(:work_package_used_in_dependency) { follower_child } - it "returns an array with the work_package id" do + it 'returns an array with the work_package id' do expect(subject.dependent_ids).to contain_exactly(work_package.id) end end - context "for dependency of the follower parent" do + context 'for dependency of the follower parent' do let(:work_package_used_in_dependency) { follower_parent } - it "returns an array with the work_package, the follower, and the follower child ids" do + it 'returns an array with the work_package, the follower, and the follower child ids' do expect(subject.dependent_ids).to contain_exactly(work_package.id, follower.id, follower_child.id) end end @@ -211,32 +211,32 @@ def create_child_of(work_package) end end - describe "#soonest_start_date" do + describe '#soonest_start_date' do let(:work_package_used_in_dependency) { work_package } before do work_package.update(due_date: Time.zone.today) end - context "with a moved predecessor" do - it "returns the soonest start date from the predecessors" do + context 'with a moved predecessor' do + it 'returns the soonest start date from the predecessors' do follower = create_follower_of(work_package) expect(dependency_for(follower).soonest_start_date).to eq(work_package.due_date + 1.day) end end - context "with an unmoved predecessor" do - it "returns the soonest start date from the predecessors" do + context 'with an unmoved predecessor' do + it 'returns the soonest start date from the predecessors' do follower = create_follower_of(work_package) unmoved_follower_predecessor = create_predecessor_of(follower, due_date: Time.zone.today + 4.days) expect(dependency_for(follower).soonest_start_date).to eq(unmoved_follower_predecessor.due_date + 1.day) end end - context "with non working days" do + context 'with non working days' do let!(:tomorrow_we_do_not_work!) { create(:non_working_day, date: Time.zone.tomorrow) } - it "returns the soonest start date being a working day" do + it 'returns the soonest start date being a working day' do follower = create_follower_of(work_package) expect(dependency_for(follower).soonest_start_date).to eq(work_package.due_date + 2.days) end diff --git a/spec/services/work_packages/set_schedule_service_working_days_spec.rb b/spec/services/work_packages/set_schedule_service_working_days_spec.rb index 2d7f1a9f1b9c..5506af6e7fc1 100644 --- a/spec/services/work_packages/set_schedule_service_working_days_spec.rb +++ b/spec/services/work_packages/set_schedule_service_working_days_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe WorkPackages::SetScheduleService, "working days" do +RSpec.describe WorkPackages::SetScheduleService, 'working days' do create_shared_association_defaults_for_work_package_factory shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } @@ -40,8 +40,8 @@ subject { instance.call(changed_attributes) } - context "with a single successor" do - context "when moving successor will cover non-working days" do + context 'with a single successor' do + context 'when moving successor will cover non-working days' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -55,7 +55,7 @@ CHART end - it "extends to a later due date to keep the same duration" do + it 'extends to a later due date to keep the same duration' do expect_schedule(subject.all_results, <<~CHART) days | MTWTFSS | work_package | XXXX | @@ -65,7 +65,7 @@ end end - context "when moved predecessor covers non-working days" do + context 'when moved predecessor covers non-working days' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -79,7 +79,7 @@ CHART end - it "extends to a later due date to keep the same duration" do + it 'extends to a later due date to keep the same duration' do expect_schedule(subject.all_results, <<~CHART) days | MTWTFSS | work_package | XX..XX | @@ -89,8 +89,8 @@ end end - context "when predecessor moved forward" do - context "on a day in the middle on working days with the follower having only start date" do + context 'when predecessor moved forward' do + context 'on a day in the middle on working days with the follower having only start date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -104,7 +104,7 @@ CHART end - it "reschedules follower to start the next day after its predecessor due date" do + it 'reschedules follower to start the next day after its predecessor due date' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | XXXX | @@ -113,7 +113,7 @@ end end - context "on a day just before non working days with the follower having only start date" do + context 'on a day just before non working days with the follower having only start date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -127,7 +127,7 @@ CHART end - it "reschedules follower to start after the non working days" do + it 'reschedules follower to start after the non working days' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | XXXXX | @@ -136,7 +136,7 @@ end end - context "on a day in the middle of working days with the follower having only due date and no space in between" do + context 'on a day in the middle of working days with the follower having only due date and no space in between' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -150,7 +150,7 @@ CHART end - it "reschedules follower to start and end right after its predecessor with a default duration of 1 day" do + it 'reschedules follower to start and end right after its predecessor with a default duration of 1 day' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | ] | @@ -159,7 +159,7 @@ end end - context "on a day in the middle of working days with the follower having only due date and much space in between" do + context 'on a day in the middle of working days with the follower having only due date and much space in between' do let_schedule(<<~CHART) days | MTWTFSSmt | work_package | ] | @@ -173,7 +173,7 @@ CHART end - it "reschedules follower to start after its predecessor without needing to change the end date" do + it 'reschedules follower to start after its predecessor without needing to change the end date' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | ] | @@ -182,7 +182,7 @@ end end - context "on a day just before non-working day with the follower having only due date" do + context 'on a day just before non-working day with the follower having only due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -196,7 +196,7 @@ CHART end - it "reschedules follower to start and end after the non working days with a default duration of 1 day" do + it 'reschedules follower to start and end after the non working days with a default duration of 1 day' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | ] | @@ -205,7 +205,7 @@ end end - context "with the follower having some space left" do + context 'with the follower having some space left' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -219,7 +219,7 @@ CHART end - it "reschedules follower to start the next working day after its predecessor due date" do + it 'reschedules follower to start the next working day after its predecessor due date' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | XXXXX | @@ -228,7 +228,7 @@ end end - context "with the follower having enough space left to not be moved at all" do + context 'with the follower having enough space left to not be moved at all' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -242,7 +242,7 @@ CHART end - it "does not move follower" do + it 'does not move follower' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSS | work_package | XXXXX..X | @@ -254,7 +254,7 @@ end end - context "with the follower having some space left and a delay" do + context 'with the follower having some space left and a delay' do let_schedule(<<~CHART) days | MTWTFSSmtwtfss | work_package | X | @@ -268,7 +268,7 @@ CHART end - it "reschedules the follower to start after the delay" do + it 'reschedules the follower to start after the delay' do expect_schedule(subject.all_results, <<~CHART) | MTWTFSSmtwtfss | work_package | XXXXX..X | @@ -277,7 +277,7 @@ end end - context "with the follower having a delay overlapping non-working days" do + context 'with the follower having a delay overlapping non-working days' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -291,7 +291,7 @@ CHART end - it "reschedules the follower to start after the non-working days and the delay" do + it 'reschedules the follower to start after the non-working days and the delay' do expect(subject.all_results).to match_schedule(<<~CHART) | MTWTFSSmtwt | work_package | X | @@ -301,8 +301,8 @@ end end - context "when predecessor moved backwards" do - context "on a day right before some non-working days" do + context 'when predecessor moved backwards' do + context 'on a day right before some non-working days' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -316,7 +316,7 @@ CHART end - it "does not move the follower" do + it 'does not move the follower' do expect(subject.all_results).to match_schedule(<<~CHART) | MTWTFSS | work_package | X | @@ -324,7 +324,7 @@ end end - context "on a day before non-working days the follower having space between" do + context 'on a day before non-working days the follower having space between' do let_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -338,7 +338,7 @@ CHART end - it "does not move the follower" do + it 'does not move the follower' do expect(subject.all_results).to match_schedule(<<~CHART) | MTWTFSS | work_package | X | @@ -346,7 +346,7 @@ end end - context "with the follower having another relation limiting movement" do + context 'with the follower having another relation limiting movement' do let_schedule(<<~CHART) days | mtwtfssmtwtfssMTWTFSS | work_package | X | @@ -361,7 +361,7 @@ CHART end - it "does not move the follower" do + it 'does not move the follower' do expect(subject.all_results).to match_schedule(<<~CHART) days | mtwtfssmtwtfssMTWTFSS | work_package | X | @@ -370,8 +370,8 @@ end end - context "when removing the dates on the moved predecessor" do - context "with the follower having start and due dates" do + context 'when removing the dates on the moved predecessor' do + context 'with the follower having start and due dates' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -385,7 +385,7 @@ CHART end - it "does not reschedule and follower keeps its dates" do + it 'does not reschedule and follower keeps its dates' do expect_schedule(subject.all_results, <<~CHART) days | MTWTFSS | work_package | | @@ -397,7 +397,7 @@ end end - context "with the follower having only a due date" do + context 'with the follower having only a due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -411,7 +411,7 @@ CHART end - it "does not reschedule and follower keeps its dates" do + it 'does not reschedule and follower keeps its dates' do expect_schedule(subject.all_results, <<~CHART) days | MTWTFSS | work_package | | @@ -424,8 +424,8 @@ end end - context "when only creating the relation between predecessor and follower" do - context "with follower having no dates" do + context 'when only creating the relation between predecessor and follower' do + context 'with follower having no dates' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -436,7 +436,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "schedules follower to start right after its predecessor and does not set the due date" do + it 'schedules follower to start right after its predecessor and does not set the due date' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -445,7 +445,7 @@ end end - context "with follower having only due date before predecessor due date" do + context 'with follower having only due date before predecessor due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -456,7 +456,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "reschedules follower to start right after its predecessor and end the same day" do + it 'reschedules follower to start right after its predecessor and end the same day' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -465,7 +465,7 @@ end end - context "with follower having only start date before predecessor due date" do + context 'with follower having only start date before predecessor due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -476,7 +476,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "reschedules follower to start right after its predecessor and leaves the due date unset" do + it 'reschedules follower to start right after its predecessor and leaves the due date unset' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -485,7 +485,7 @@ end end - context "with follower having both start and due dates before predecessor due date" do + context 'with follower having both start and due dates before predecessor due date' do let_schedule(<<~CHART) days | mtwtfssMTWTFSS | work_package | XX | @@ -496,7 +496,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "reschedules follower to start right after its predecessor and keeps the duration" do + it 'reschedules follower to start right after its predecessor and keeps the duration' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -505,7 +505,7 @@ end end - context "with follower having due date long after predecessor due date" do + context 'with follower having due date long after predecessor due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -516,7 +516,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "reschedules follower to start right after its predecessor and end the same day" do + it 'reschedules follower to start right after its predecessor and end the same day' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -525,7 +525,7 @@ end end - context "with predecessor and follower having no dates" do + context 'with predecessor and follower having no dates' do let_schedule(<<~CHART) days | MTWTFSS | work_package | | @@ -536,7 +536,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "does not reschedule any work package" do + it 'does not reschedule any work package' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | | @@ -545,8 +545,8 @@ end end - context "with the successor having another predecessor which has no dates" do - context "when moved forward" do + context 'with the successor having another predecessor which has no dates' do + context 'when moved forward' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -561,7 +561,7 @@ CHART end - it "reschedules follower without influence from the other predecessor" do + it 'reschedules follower without influence from the other predecessor' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -570,7 +570,7 @@ end end - context "when moved backwards" do + context 'when moved backwards' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -585,7 +585,7 @@ CHART end - it "does not move the follower" do + it 'does not move the follower' do expect(subject.all_results).to match_schedule(<<~CHART) days | mtwtfssMTWTFSS | work_package | ] | @@ -594,8 +594,8 @@ end end - context "with successor having only duration" do - context "when setting dates on predecessor" do + context 'with successor having only duration' do + context 'when setting dates on predecessor' do let_schedule(<<~CHART) days | MTWTFSS | work_package | | @@ -609,7 +609,7 @@ CHART end - it "schedules successor to start after predecessor and keeps the duration (#44479)" do + it 'schedules successor to start after predecessor and keeps the duration (#44479)' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -620,7 +620,7 @@ end end - context "with a parent" do + context 'with a parent' do let_schedule(<<~CHART) days | MTWTFSS | parent | | @@ -634,7 +634,7 @@ CHART end - it "reschedules parent to have the same dates as the child" do + it 'reschedules parent to have the same dates as the child' do expect(subject.all_results).to match_schedule(<<~CHART) days | mtwtfssMTWTFSS | parent | XXX..X | @@ -643,7 +643,7 @@ end end - context "with a parent having a follower" do + context 'with a parent having a follower' do let_schedule(<<~CHART) days | MTWTFSS | parent | XX | @@ -658,7 +658,7 @@ CHART end - it "reschedules parent to have the same dates as the child, and parent follower to start right after parent" do + it 'reschedules parent to have the same dates as the child, and parent follower to start right after parent' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | parent | XXXXX | @@ -668,8 +668,8 @@ end end - context "with a single successor having a parent" do - context "when moving forward" do + context 'with a single successor having a parent' do + context 'when moving forward' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -684,7 +684,7 @@ CHART end - it "reschedules follower and follower parent to start right after the moved predecessor" do + it 'reschedules follower and follower parent to start right after the moved predecessor' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -694,7 +694,7 @@ end end - context "when moving forward with the parent having another child not being moved" do + context 'when moving forward with the parent having another child not being moved' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -710,7 +710,7 @@ CHART end - it "reschedules follower to start right after the moved predecessor, and follower parent spans on its two children" do + it 'reschedules follower to start right after the moved predecessor, and follower parent spans on its two children' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -720,7 +720,7 @@ end end - context "when moving backwards" do + context 'when moving backwards' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -735,7 +735,7 @@ CHART end - it "does not reschedule the followers" do + it 'does not reschedule the followers' do expect(subject.all_results).to match_schedule(<<~CHART) days | mtwtfssMTWTFSS | work_package | ] | @@ -743,7 +743,7 @@ end end - context "when moving backwards with the parent having another child not being moved" do + context 'when moving backwards with the parent having another child not being moved' do let_schedule(<<~CHART) days | mtwtfssMTWTFSS | work_package | ] | @@ -759,7 +759,7 @@ CHART end - it "does not rechedule the followers or the other child" do + it 'does not rechedule the followers or the other child' do expect(subject.all_results).to match_schedule(<<~CHART) days | mtwtfssMTWTFSS | work_package | ] | @@ -768,8 +768,8 @@ end end - context "with a single successor having a child" do - context "when moving forward" do + context 'with a single successor having a child' do + context 'when moving forward' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -784,7 +784,7 @@ CHART end - it "reschedules follower and follower child to start right after the moved predecessor" do + it 'reschedules follower and follower child to start right after the moved predecessor' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -795,8 +795,8 @@ end end - context "with a single successor having two children" do - context "when creating the follows relation while follower starts 1 day after moved due date" do + context 'with a single successor having two children' do + context 'when creating the follows relation while follower starts 1 day after moved due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -809,7 +809,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "does not need to reschedule anything" do + it 'does not need to reschedule anything' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -817,7 +817,7 @@ end end - context "when creating the follows relation while follower starts 3 days after moved due date" do + context 'when creating the follows relation while follower starts 3 days after moved due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -830,7 +830,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "does not need to reschedule anything" do + it 'does not need to reschedule anything' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -838,7 +838,7 @@ end end - context "when creating the follows relation and follower first child starts before moved due date" do + context 'when creating the follows relation and follower first child starts before moved due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -851,7 +851,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "reschedules first child and reduces follower parent duration as the children can be executed at the same time" do + it 'reschedules first child and reduces follower parent duration as the children can be executed at the same time' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -861,7 +861,7 @@ end end - context "when creating the follows relation and both follower children start before moved due date" do + context 'when creating the follows relation and both follower children start before moved due date' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -874,7 +874,7 @@ create(:follows_relation, from: follower, to: work_package) end - it "reschedules both children and reduces follower parent duration" do + it 'reschedules both children and reduces follower parent duration' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -886,8 +886,8 @@ end end - context "with a chain of followers" do - context "when moving forward" do + context 'with a chain of followers' do + context 'when moving forward' do let_schedule(<<~CHART) days | MTWTFSSm sm sm | work_package | ] | @@ -904,7 +904,7 @@ CHART end - it "reschedules each follower forward by the same delta" do + it 'reschedules each follower forward by the same delta' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSSm sm sm | work_package | ] | @@ -916,7 +916,7 @@ end end - context "when moving forward with some space between the followers" do + context 'when moving forward with some space between the followers' do let_schedule(<<~CHART) days | MTWTFSSm sm sm | work_package | ] | @@ -933,7 +933,7 @@ CHART end - it "reschedules only the first followers as the others don't need to move" do + it 'reschedules only the first followers as the others don\'t need to move' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSSm sm | work_package | ] | @@ -943,7 +943,7 @@ end end - context "when moving forward with some delay and spaces between the followers" do + context 'when moving forward with some delay and spaces between the followers' do let_schedule(<<~CHART) days | MTWTFSSm sm sm | work_package | ] | @@ -960,7 +960,7 @@ CHART end - it "reschedules all the followers keeping the delay and compacting the extra spaces" do + it 'reschedules all the followers keeping the delay and compacting the extra spaces' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSSm sm sm sm | work_package | ] | @@ -972,7 +972,7 @@ end end - context "when moving forward due to days and predecessor due date now being non-working days" do + context 'when moving forward due to days and predecessor due date now being non-working days' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -987,14 +987,14 @@ # # Below instructions reproduce the conditions in which such scheduling # must happen. - set_non_working_week_days("tuesday", "thursday", "friday") + set_non_working_week_days('tuesday', 'thursday', 'friday') change_schedule([work_package], <<~CHART) days | MTWTFSS | work_package | X.X | CHART end - it "reschedules all the followers keeping the delay and compacting the extra spaces" do + it 'reschedules all the followers keeping the delay and compacting the extra spaces' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSSm w m | work_package | X.X | @@ -1004,7 +1004,7 @@ end end - context "when moving forward due to days and predecessor start date now being non-working days" do + context 'when moving forward due to days and predecessor start date now being non-working days' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -1019,14 +1019,14 @@ # # Below instructions reproduce the conditions in which such scheduling # must happen. - set_non_working_week_days("monday", "thursday", "friday") + set_non_working_week_days('monday', 'thursday', 'friday') change_schedule([work_package], <<~CHART) days | MTWTFSS | work_package | XX | CHART end - it "reschedules all the followers without crossing each other" do + it 'reschedules all the followers without crossing each other' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS tw tw | work_package | XX | @@ -1036,7 +1036,7 @@ end end - context "when moving backwards" do + context 'when moving backwards' do let_schedule(<<~CHART) days | MTWTFSSm sm sm | work_package | ] | @@ -1053,7 +1053,7 @@ CHART end - it "does not reschedule any followers" do + it 'does not reschedule any followers' do expect(subject.all_results).to match_schedule(<<~CHART) days | m sMTWTFSS | work_package | ] | @@ -1062,8 +1062,8 @@ end end - context "with a chain of followers with two paths leading to the same follower in the end" do - context "when moving forward" do + context 'with a chain of followers with two paths leading to the same follower in the end' do + context 'when moving forward' do let_schedule(<<~CHART) days | MTWTFSSm sm | work_package | ] | @@ -1080,7 +1080,7 @@ CHART end - it "reschedules followers while satisfying all constraints" do + it 'reschedules followers while satisfying all constraints' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSSm sm sm | work_package | ] | @@ -1092,7 +1092,7 @@ end end - context "when moving backwards" do + context 'when moving backwards' do let_schedule(<<~CHART) days | MTWTFSSm sm | work_package | ] | @@ -1109,7 +1109,7 @@ CHART end - it "does not reschedule any followers" do + it 'does not reschedule any followers' do expect(subject.all_results).to match_schedule(<<~CHART) days | m sMTWTFSS | work_package | ] | @@ -1118,10 +1118,10 @@ end end - context "when setting the parent" do + context 'when setting the parent' do let(:changed_attributes) { [:parent] } - context "without dates and with the parent being restricted in its ability to be moved" do + context 'without dates and with the parent being restricted in its ability to be moved' do let_schedule(<<~CHART) days | MTWTFSS | work_package | | @@ -1134,7 +1134,7 @@ work_package.save end - it "schedules parent to start and end at soonest working start date and the child to start at the parent start" do + it 'schedules parent to start and end at soonest working start date and the child to start at the parent start' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | [ | @@ -1143,7 +1143,7 @@ end end - context "without dates, with a duration and with the parent being restricted in its ability to be moved" do + context 'without dates, with a duration and with the parent being restricted in its ability to be moved' do let_schedule(<<~CHART) days | MTWTFSS | work_package | | duration 4 @@ -1156,8 +1156,8 @@ work_package.save end - it "schedules the moved work package to start at the parent soonest date and sets due date to keep the same duration " \ - "and schedules the parent dates to match the child dates" do + it 'schedules the moved work package to start at the parent soonest date and sets due date to keep the same duration ' \ + 'and schedules the parent dates to match the child dates' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XXXX | @@ -1166,7 +1166,7 @@ end end - context "with the parent being restricted in its ability to be moved and with a due date before parent constraint" do + context 'with the parent being restricted in its ability to be moved and with a due date before parent constraint' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -1179,7 +1179,7 @@ work_package.save end - it "schedules the moved work package to start and end at the parent soonest working start date" do + it 'schedules the moved work package to start and end at the parent soonest working start date' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | X | @@ -1188,7 +1188,7 @@ end end - context "with the parent being restricted in its ability to be moved and with a due date after parent constraint" do + context 'with the parent being restricted in its ability to be moved and with a due date after parent constraint' do let_schedule(<<~CHART) days | MTWTFSS | work_package | ] | @@ -1201,7 +1201,7 @@ work_package.save end - it "schedules the moved work package to start at the parent soonest working start date and keep the due date" do + it 'schedules the moved work package to start at the parent soonest working start date and keep the due date' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | X..XX | @@ -1210,7 +1210,7 @@ end end - context "with the parent being restricted but work package already has both dates set" do + context 'with the parent being restricted but work package already has both dates set' do let_schedule(<<~CHART) days | MTWTFSS | work_package | XX | @@ -1223,7 +1223,7 @@ work_package.save end - it "does not reschedule the moved work package, and sets new parent dates to child dates" do + it 'does not reschedule the moved work package, and sets new parent dates to child dates' do expect(subject.all_results).to match_schedule(<<~CHART) days | MTWTFSS | work_package | XX | diff --git a/spec/services/work_packages/shared/all_days_spec.rb b/spec/services/work_packages/shared/all_days_spec.rb index b131e1214821..5e3b72365599 100644 --- a/spec/services/work_packages/shared/all_days_spec.rb +++ b/spec/services/work_packages/shared/all_days_spec.rb @@ -26,147 +26,147 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" -require_relative "shared_examples_days" +require 'rails_helper' +require_relative 'shared_examples_days' RSpec.describe WorkPackages::Shared::AllDays do subject { described_class.new } sunday_2022_07_31 = Date.new(2022, 7, 31) - describe "#duration" do - context "without any week days created" do - it "considers all days as working days and returns the number of days between two dates, inclusive" do + describe '#duration' do + context 'without any week days created' do + it 'considers all days as working days and returns the number of days between two dates, inclusive' do expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 6)).to eq(7) expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 50)).to eq(51) end end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - it "considers all days as working days and returns the number of days between two dates, inclusive" do + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + it 'considers all days as working days and returns the number of days between two dates, inclusive' do expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 6)).to eq(7) expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 50)).to eq(51) end end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "it returns duration", 365, Date.new(2022, 1, 1), Date.new(2022, 12, 31) - include_examples "it returns duration", 365 * 2, Date.new(2022, 1, 1), Date.new(2023, 12, 31) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'it returns duration', 365, Date.new(2022, 1, 1), Date.new(2022, 12, 31) + include_examples 'it returns duration', 365 * 2, Date.new(2022, 1, 1), Date.new(2023, 12, 31) end - context "without start date" do - it "returns nil" do + context 'without start date' do + it 'returns nil' do expect(subject.duration(nil, sunday_2022_07_31)).to be_nil end end - context "without due date" do - it "returns nil" do + context 'without due date' do + it 'returns nil' do expect(subject.duration(sunday_2022_07_31, nil)).to be_nil end end end - describe "#start_date" do - it "returns the start date for a due date and a duration" do + describe '#start_date' do + it 'returns the start date for a due date and a duration' do expect(subject.start_date(sunday_2022_07_31, 1)).to eq(sunday_2022_07_31) expect(subject.start_date(sunday_2022_07_31 + 9.days, 10)).to eq(sunday_2022_07_31) end - it "raises an error if duration is 0 or negative" do + it 'raises an error if duration is 0 or negative' do expect { subject.start_date(sunday_2022_07_31, 0) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' expect { subject.start_date(sunday_2022_07_31, -10) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' end - it "returns nil if due_date is nil" do + it 'returns nil if due_date is nil' do expect(subject.start_date(nil, 1)).to be_nil end - it "returns nil if duration is nil" do + it 'returns nil if duration is nil' do expect(subject.start_date(sunday_2022_07_31, nil)).to be_nil end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - include_examples "start_date", due_date: sunday_2022_07_31, duration: 1, expected: sunday_2022_07_31 - include_examples "start_date", due_date: sunday_2022_07_31, duration: 5, expected: sunday_2022_07_31 - 4.days - include_examples "start_date", due_date: sunday_2022_07_31, duration: 10, expected: sunday_2022_07_31 - 9.days + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + include_examples 'start_date', due_date: sunday_2022_07_31, duration: 1, expected: sunday_2022_07_31 + include_examples 'start_date', due_date: sunday_2022_07_31, duration: 5, expected: sunday_2022_07_31 - 4.days + include_examples 'start_date', due_date: sunday_2022_07_31, duration: 10, expected: sunday_2022_07_31 - 9.days end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "start_date", due_date: Date.new(2022, 12, 31), duration: 365, expected: Date.new(2022, 1, 1) - include_examples "start_date", due_date: Date.new(2023, 12, 31), duration: 365 * 2, expected: Date.new(2022, 1, 1) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'start_date', due_date: Date.new(2022, 12, 31), duration: 365, expected: Date.new(2022, 1, 1) + include_examples 'start_date', due_date: Date.new(2023, 12, 31), duration: 365 * 2, expected: Date.new(2022, 1, 1) end end - describe "#due_date" do - it "returns the due date for a start date and a duration" do + describe '#due_date' do + it 'returns the due date for a start date and a duration' do expect(subject.due_date(sunday_2022_07_31, 1)).to eq(sunday_2022_07_31) expect(subject.due_date(sunday_2022_07_31, 10)).to eq(sunday_2022_07_31 + 9.days) end - it "raises an error if duration is 0 or negative" do + it 'raises an error if duration is 0 or negative' do expect { subject.due_date(sunday_2022_07_31, 0) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' expect { subject.due_date(sunday_2022_07_31, -10) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' end - it "returns nil if start_date is nil" do + it 'returns nil if start_date is nil' do expect(subject.due_date(nil, 1)).to be_nil end - it "returns nil if duration is nil" do + it 'returns nil if duration is nil' do expect(subject.due_date(sunday_2022_07_31, nil)).to be_nil end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - include_examples "due_date", start_date: sunday_2022_07_31, duration: 1, expected: sunday_2022_07_31 - include_examples "due_date", start_date: sunday_2022_07_31, duration: 5, expected: sunday_2022_07_31 + 4.days - include_examples "due_date", start_date: sunday_2022_07_31, duration: 10, expected: sunday_2022_07_31 + 9.days + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + include_examples 'due_date', start_date: sunday_2022_07_31, duration: 1, expected: sunday_2022_07_31 + include_examples 'due_date', start_date: sunday_2022_07_31, duration: 5, expected: sunday_2022_07_31 + 4.days + include_examples 'due_date', start_date: sunday_2022_07_31, duration: 10, expected: sunday_2022_07_31 + 9.days end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "due_date", start_date: Date.new(2022, 1, 1), duration: 365, expected: Date.new(2022, 12, 31) - include_examples "due_date", start_date: Date.new(2022, 1, 1), duration: 365 * 2, expected: Date.new(2023, 12, 31) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'due_date', start_date: Date.new(2022, 1, 1), duration: 365, expected: Date.new(2022, 12, 31) + include_examples 'due_date', start_date: Date.new(2022, 1, 1), duration: 365 * 2, expected: Date.new(2023, 12, 31) end end - describe "#soonest_working_day" do - it "returns the given day" do + describe '#soonest_working_day' do + it 'returns the given day' do expect(subject.soonest_working_day(sunday_2022_07_31)).to eq(sunday_2022_07_31) end - it "returns nil if given date is nil" do + it 'returns nil if given date is nil' do expect(subject.soonest_working_day(nil)).to be_nil end - context "with delay" do - it "returns the soonest working day from the given day, after a configurable delay of working days" do + context 'with delay' do + it 'returns the soonest working day from the given day, after a configurable delay of working days' do expect(subject.soonest_working_day(sunday_2022_07_31, delay: nil)).to eq(sunday_2022_07_31) expect(subject.soonest_working_day(sunday_2022_07_31, delay: 0)).to eq(sunday_2022_07_31) expect(subject.soonest_working_day(sunday_2022_07_31, delay: 1)).to eq(Date.new(2022, 8, 1)) end end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - it "returns the given day" do + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + it 'returns the given day' do expect(subject.soonest_working_day(sunday_2022_07_31)).to eq(sunday_2022_07_31) end - context "with delay" do - include_examples "soonest working day with delay", date: Date.new(2022, 1, 1), delay: 30, expected: Date.new(2022, 1, 31) + context 'with delay' do + include_examples 'soonest working day with delay', date: Date.new(2022, 1, 1), delay: 30, expected: Date.new(2022, 1, 31) end end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - it "returns the given day" do + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + it 'returns the given day' do expect(subject.soonest_working_day(Date.new(2022, 12, 25))).to eq(Date.new(2022, 12, 25)) end - context "with delay" do - include_examples "soonest working day with delay", date: Date.new(2022, 12, 24), delay: 7, + context 'with delay' do + include_examples 'soonest working day with delay', date: Date.new(2022, 12, 24), delay: 7, expected: Date.new(2022, 12, 31) end end diff --git a/spec/services/work_packages/shared/days_spec.rb b/spec/services/work_packages/shared/days_spec.rb index 6d026a612387..8ce62125d99d 100644 --- a/spec/services/work_packages/shared/days_spec.rb +++ b/spec/services/work_packages/shared/days_spec.rb @@ -26,24 +26,24 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" +require 'rails_helper' RSpec.describe WorkPackages::Shared::Days do subject { described_class.new } - describe ".for" do - context "for a work_package ignoring non working days" do + describe '.for' do + context 'for a work_package ignoring non working days' do let(:work_package) { build_stubbed(:work_package, ignore_non_working_days: true) } - it "returns an AllDays instance" do + it 'returns an AllDays instance' do expect(described_class.for(work_package)).to be_an_instance_of(WorkPackages::Shared::AllDays) end end - context "for a work_package respecting non working days" do + context 'for a work_package respecting non working days' do let(:work_package) { build_stubbed(:work_package) } - it "returns a WorkingDays instance" do + it 'returns a WorkingDays instance' do expect(described_class.for(work_package)).to be_an_instance_of(WorkPackages::Shared::WorkingDays) end end diff --git a/spec/services/work_packages/shared/shared_examples_days.rb b/spec/services/work_packages/shared/shared_examples_days.rb index 0f652d74615d..36c337606935 100644 --- a/spec/services/work_packages/shared/shared_examples_days.rb +++ b/spec/services/work_packages/shared/shared_examples_days.rb @@ -26,25 +26,25 @@ # See COPYRIGHT and LICENSE files for more details. #++ -Date::DATE_FORMATS[:wday_date] = "%a %-d %b %Y" # Fri 5 Aug 2022 +Date::DATE_FORMATS[:wday_date] = '%a %-d %b %Y' # Fri 5 Aug 2022 -RSpec.shared_context "with weekend days Saturday and Sunday" do +RSpec.shared_context 'with weekend days Saturday and Sunday' do shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } end -RSpec.shared_context "with non working days from this and next year" do +RSpec.shared_context 'with non working days from this and next year' do shared_let(:first_of_may) { create(:non_working_day, date: Date.new(Date.current.year, 5, 1)) } shared_let(:christmas) { create(:non_working_day, date: Date.new(Date.current.year, 12, 25)) } shared_let(:new_year_day) { create(:non_working_day, date: Date.new(Date.current.year + 1, 1, 1)) } end -RSpec.shared_context "with non working days Christmas 2022 and new year 2023" do +RSpec.shared_context 'with non working days Christmas 2022 and new year 2023' do shared_let(:christmas) { create(:non_working_day, date: Date.new(2022, 12, 25)) } shared_let(:new_year_day) { create(:non_working_day, date: Date.new(2023, 1, 1)) } end -RSpec.shared_context "with no working days" do - include_context "with weekend days Saturday and Sunday" +RSpec.shared_context 'with no working days' do + include_context 'with weekend days Saturday and Sunday' before do week_with_no_working_days @@ -52,16 +52,16 @@ end RSpec.configure do |rspec| - rspec.include_context "with weekend days Saturday and Sunday", :weekend_saturday_sunday - rspec.include_context "with non working days Christmas 2022 and new year 2023", :christmas_2022_new_year_2023 - rspec.include_context "with non working days from this and next year", :non_working_days_from_this_and_next_year - rspec.include_context "with no working days", :no_working_days + rspec.include_context 'with weekend days Saturday and Sunday', :weekend_saturday_sunday + rspec.include_context 'with non working days Christmas 2022 and new year 2023', :christmas_2022_new_year_2023 + rspec.include_context 'with non working days from this and next year', :non_working_days_from_this_and_next_year + rspec.include_context 'with no working days', :no_working_days end -RSpec.shared_examples "it returns duration" do |expected_duration, start_date, due_date| - from_date_format = "%a %-d" - from_date_format += " %b" if [start_date.month, start_date.year] != [due_date.month, due_date.year] - from_date_format += " %Y" if start_date.year != due_date.year +RSpec.shared_examples 'it returns duration' do |expected_duration, start_date, due_date| + from_date_format = '%a %-d' + from_date_format += ' %b' if [start_date.month, start_date.year] != [due_date.month, due_date.year] + from_date_format += ' %Y' if start_date.year != due_date.year it "from #{start_date.strftime(from_date_format)} " \ "to #{due_date.to_fs(:wday_date)} " \ @@ -71,25 +71,25 @@ end end -RSpec.shared_examples "start_date" do |due_date:, duration:, expected:| +RSpec.shared_examples 'start_date' do |due_date:, duration:, expected:| it "start_date(#{due_date.to_fs(:wday_date)}, #{duration}) => #{expected.to_fs(:wday_date)}" do expect(subject.start_date(due_date, duration)).to eq(expected) end end -RSpec.shared_examples "due_date" do |start_date:, duration:, expected:| +RSpec.shared_examples 'due_date' do |start_date:, duration:, expected:| it "due_date(#{start_date.to_fs(:wday_date)}, #{duration}) => #{expected.to_fs(:wday_date)}" do expect(subject.due_date(start_date, duration)).to eq(expected) end end -RSpec.shared_examples "soonest working day" do |date:, expected:| +RSpec.shared_examples 'soonest working day' do |date:, expected:| it "soonest_working_day(#{date.to_fs(:wday_date)}) => #{expected.to_fs(:wday_date)}" do expect(subject.soonest_working_day(date)).to eq(expected) end end -RSpec.shared_examples "soonest working day with delay" do |date:, delay:, expected:| +RSpec.shared_examples 'soonest working day with delay' do |date:, delay:, expected:| it "soonest_working_day(#{date.to_fs(:wday_date)}, delay: #{delay.inspect}) => #{expected.to_fs(:wday_date)}" do expect(subject.soonest_working_day(date, delay:)).to eq(expected) end diff --git a/spec/services/work_packages/shared/working_days_spec.rb b/spec/services/work_packages/shared/working_days_spec.rb index 3835cd505291..ba0a9ebfbe05 100644 --- a/spec/services/work_packages/shared/working_days_spec.rb +++ b/spec/services/work_packages/shared/working_days_spec.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" -require_relative "shared_examples_days" +require 'rails_helper' +require_relative 'shared_examples_days' RSpec.describe WorkPackages::Shared::WorkingDays do subject { described_class.new } @@ -38,205 +38,205 @@ monday_2022_08_01 = Date.new(2022, 8, 1) wednesday_2022_08_03 = Date.new(2022, 8, 3) - describe "#duration" do - it "returns the duration for a given start date and due date" do + describe '#duration' do + it 'returns the duration for a given start date and due date' do expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 6)).to eq(7) end - context "without any week days created" do - it "considers all days as working days and returns the number of days between two dates, inclusive" do + context 'without any week days created' do + it 'considers all days as working days and returns the number of days between two dates, inclusive' do expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 6)).to eq(7) expect(subject.duration(sunday_2022_07_31, sunday_2022_07_31 + 50)).to eq(51) end end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - include_examples "it returns duration", 0, sunday_2022_07_31, sunday_2022_07_31 - include_examples "it returns duration", 5, sunday_2022_07_31, Date.new(2022, 8, 5) - include_examples "it returns duration", 5, sunday_2022_07_31, Date.new(2022, 8, 6) - include_examples "it returns duration", 5, sunday_2022_07_31, Date.new(2022, 8, 7) - include_examples "it returns duration", 6, sunday_2022_07_31, Date.new(2022, 8, 8) - include_examples "it returns duration", 7, sunday_2022_07_31, Date.new(2022, 8, 9) + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + include_examples 'it returns duration', 0, sunday_2022_07_31, sunday_2022_07_31 + include_examples 'it returns duration', 5, sunday_2022_07_31, Date.new(2022, 8, 5) + include_examples 'it returns duration', 5, sunday_2022_07_31, Date.new(2022, 8, 6) + include_examples 'it returns duration', 5, sunday_2022_07_31, Date.new(2022, 8, 7) + include_examples 'it returns duration', 6, sunday_2022_07_31, Date.new(2022, 8, 8) + include_examples 'it returns duration', 7, sunday_2022_07_31, Date.new(2022, 8, 9) - include_examples "it returns duration", 1, monday_2022_08_01, monday_2022_08_01 - include_examples "it returns duration", 5, monday_2022_08_01, Date.new(2022, 8, 5) - include_examples "it returns duration", 5, monday_2022_08_01, Date.new(2022, 8, 6) - include_examples "it returns duration", 5, monday_2022_08_01, Date.new(2022, 8, 7) - include_examples "it returns duration", 6, monday_2022_08_01, Date.new(2022, 8, 8) - include_examples "it returns duration", 7, monday_2022_08_01, Date.new(2022, 8, 9) + include_examples 'it returns duration', 1, monday_2022_08_01, monday_2022_08_01 + include_examples 'it returns duration', 5, monday_2022_08_01, Date.new(2022, 8, 5) + include_examples 'it returns duration', 5, monday_2022_08_01, Date.new(2022, 8, 6) + include_examples 'it returns duration', 5, monday_2022_08_01, Date.new(2022, 8, 7) + include_examples 'it returns duration', 6, monday_2022_08_01, Date.new(2022, 8, 8) + include_examples 'it returns duration', 7, monday_2022_08_01, Date.new(2022, 8, 9) - include_examples "it returns duration", 3, wednesday_2022_08_03, Date.new(2022, 8, 5) - include_examples "it returns duration", 3, wednesday_2022_08_03, Date.new(2022, 8, 6) - include_examples "it returns duration", 3, wednesday_2022_08_03, Date.new(2022, 8, 7) - include_examples "it returns duration", 4, wednesday_2022_08_03, Date.new(2022, 8, 8) - include_examples "it returns duration", 5, wednesday_2022_08_03, Date.new(2022, 8, 9) + include_examples 'it returns duration', 3, wednesday_2022_08_03, Date.new(2022, 8, 5) + include_examples 'it returns duration', 3, wednesday_2022_08_03, Date.new(2022, 8, 6) + include_examples 'it returns duration', 3, wednesday_2022_08_03, Date.new(2022, 8, 7) + include_examples 'it returns duration', 4, wednesday_2022_08_03, Date.new(2022, 8, 8) + include_examples 'it returns duration', 5, wednesday_2022_08_03, Date.new(2022, 8, 9) end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "it returns duration", 0, Date.new(2022, 12, 25), Date.new(2022, 12, 25) - include_examples "it returns duration", 1, Date.new(2022, 12, 24), Date.new(2022, 12, 25) - include_examples "it returns duration", 8, Date.new(2022, 12, 24), Date.new(2023, 1, 2) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'it returns duration', 0, Date.new(2022, 12, 25), Date.new(2022, 12, 25) + include_examples 'it returns duration', 1, Date.new(2022, 12, 24), Date.new(2022, 12, 25) + include_examples 'it returns duration', 8, Date.new(2022, 12, 24), Date.new(2023, 1, 2) end - context "without start date" do - it "returns nil" do + context 'without start date' do + it 'returns nil' do expect(subject.duration(nil, sunday_2022_07_31)).to be_nil end end - context "without due date" do - it "returns nil" do + context 'without due date' do + it 'returns nil' do expect(subject.duration(sunday_2022_07_31, nil)).to be_nil end end end - describe "#start_date" do - it "returns the start date for a due date and a duration" do + describe '#start_date' do + it 'returns the start date for a due date and a duration' do expect(subject.start_date(monday_2022_08_01, 1)).to eq(monday_2022_08_01) end - it "raises an error if duration is 0 or negative" do + it 'raises an error if duration is 0 or negative' do expect { subject.start_date(monday_2022_08_01, 0) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' expect { subject.start_date(monday_2022_08_01, -10) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' end - it "returns nil if due_date is nil" do + it 'returns nil if due_date is nil' do expect(subject.start_date(nil, 1)).to be_nil end - it "returns nil if duration is nil" do + it 'returns nil if duration is nil' do expect(subject.start_date(monday_2022_08_01, nil)).to be_nil end - context "without any week days created" do - it "returns the due date considering all days as working days" do + context 'without any week days created' do + it 'returns the due date considering all days as working days' do expect(subject.start_date(monday_2022_08_01, 1)).to eq(monday_2022_08_01) expect(subject.start_date(monday_2022_08_01, 7)).to eq(monday_2022_08_01 - 6) # Tuesday of previous week end end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - include_examples "start_date", due_date: monday_2022_08_01, duration: 1, expected: monday_2022_08_01 - include_examples "start_date", due_date: monday_2022_08_01, duration: 5, expected: monday_2022_08_01 - 6.days - include_examples "start_date", due_date: wednesday_2022_08_03, duration: 10, expected: wednesday_2022_08_03 - 13.days + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + include_examples 'start_date', due_date: monday_2022_08_01, duration: 1, expected: monday_2022_08_01 + include_examples 'start_date', due_date: monday_2022_08_01, duration: 5, expected: monday_2022_08_01 - 6.days + include_examples 'start_date', due_date: wednesday_2022_08_03, duration: 10, expected: wednesday_2022_08_03 - 13.days # contrived one... But can happen when date is coming from an external entity, like soonest start. - include_examples "start_date", due_date: saturday_2022_07_30, duration: 1, expected: friday_2022_07_29 - include_examples "start_date", due_date: saturday_2022_07_30, duration: 2, expected: friday_2022_07_29 - 1.day - include_examples "start_date", due_date: saturday_2022_07_30, duration: 6, expected: friday_2022_07_29 - 7.days + include_examples 'start_date', due_date: saturday_2022_07_30, duration: 1, expected: friday_2022_07_29 + include_examples 'start_date', due_date: saturday_2022_07_30, duration: 2, expected: friday_2022_07_29 - 1.day + include_examples 'start_date', due_date: saturday_2022_07_30, duration: 6, expected: friday_2022_07_29 - 7.days end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "start_date", due_date: Date.new(2022, 12, 26), duration: 2, expected: Date.new(2022, 12, 24) - include_examples "start_date", due_date: Date.new(2023, 1, 2), duration: 8, expected: Date.new(2022, 12, 24) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'start_date', due_date: Date.new(2022, 12, 26), duration: 2, expected: Date.new(2022, 12, 24) + include_examples 'start_date', due_date: Date.new(2023, 1, 2), duration: 8, expected: Date.new(2022, 12, 24) end end - describe "#due_date" do - it "returns the due date for a start date and a duration" do + describe '#due_date' do + it 'returns the due date for a start date and a duration' do expect(subject.due_date(monday_2022_08_01, 1)).to eq(monday_2022_08_01) end - it "raises an error if duration is 0 or negative" do + it 'raises an error if duration is 0 or negative' do expect { subject.due_date(monday_2022_08_01, 0) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' expect { subject.due_date(monday_2022_08_01, -10) } - .to raise_error ArgumentError, "duration must be strictly positive" + .to raise_error ArgumentError, 'duration must be strictly positive' end - it "returns nil if start_date is nil" do + it 'returns nil if start_date is nil' do expect(subject.due_date(nil, 1)).to be_nil end - it "returns nil if duration is nil" do + it 'returns nil if duration is nil' do expect(subject.due_date(monday_2022_08_01, nil)).to be_nil end - context "without any week days created" do - it "returns the due date considering all days as working days" do + context 'without any week days created' do + it 'returns the due date considering all days as working days' do expect(subject.due_date(monday_2022_08_01, 1)).to eq(monday_2022_08_01) expect(subject.due_date(monday_2022_08_01, 7)).to eq(monday_2022_08_01 + 6) # Sunday of same week end end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - include_examples "due_date", start_date: monday_2022_08_01, duration: 1, expected: monday_2022_08_01 - include_examples "due_date", start_date: monday_2022_08_01, duration: 5, expected: monday_2022_08_01 + 4.days - include_examples "due_date", start_date: wednesday_2022_08_03, duration: 10, expected: wednesday_2022_08_03 + 13.days + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + include_examples 'due_date', start_date: monday_2022_08_01, duration: 1, expected: monday_2022_08_01 + include_examples 'due_date', start_date: monday_2022_08_01, duration: 5, expected: monday_2022_08_01 + 4.days + include_examples 'due_date', start_date: wednesday_2022_08_03, duration: 10, expected: wednesday_2022_08_03 + 13.days # contrived one... But can happen when date is coming from an external entity, like soonest start. - include_examples "due_date", start_date: saturday_2022_07_30, duration: 1, expected: monday_2022_08_01 - include_examples "due_date", start_date: saturday_2022_07_30, duration: 2, expected: monday_2022_08_01 + 1.day - include_examples "due_date", start_date: saturday_2022_07_30, duration: 6, expected: monday_2022_08_01 + 7.days + include_examples 'due_date', start_date: saturday_2022_07_30, duration: 1, expected: monday_2022_08_01 + include_examples 'due_date', start_date: saturday_2022_07_30, duration: 2, expected: monday_2022_08_01 + 1.day + include_examples 'due_date', start_date: saturday_2022_07_30, duration: 6, expected: monday_2022_08_01 + 7.days end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "due_date", start_date: Date.new(2022, 12, 24), duration: 2, expected: Date.new(2022, 12, 26) - include_examples "due_date", start_date: Date.new(2022, 12, 24), duration: 8, expected: Date.new(2023, 1, 2) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'due_date', start_date: Date.new(2022, 12, 24), duration: 2, expected: Date.new(2022, 12, 26) + include_examples 'due_date', start_date: Date.new(2022, 12, 24), duration: 8, expected: Date.new(2023, 1, 2) end end - describe "#soonest_working_day" do - it "returns the soonest working day from the given day" do + describe '#soonest_working_day' do + it 'returns the soonest working day from the given day' do expect(subject.soonest_working_day(sunday_2022_07_31)).to eq(sunday_2022_07_31) end - it "returns nil if given date is nil" do + it 'returns nil if given date is nil' do expect(subject.soonest_working_day(nil)).to be_nil end - context "with delay" do - it "returns the soonest working day from the given day, after a configurable delay of working days" do + context 'with delay' do + it 'returns the soonest working day from the given day, after a configurable delay of working days' do expect(subject.soonest_working_day(sunday_2022_07_31, delay: nil)).to eq(sunday_2022_07_31) expect(subject.soonest_working_day(sunday_2022_07_31, delay: 0)).to eq(sunday_2022_07_31) expect(subject.soonest_working_day(sunday_2022_07_31, delay: 1)).to eq(monday_2022_08_01) end - it "works with big delay value like 100_000" do + it 'works with big delay value like 100_000' do # First implementation was recursive and failed with SystemStackError: stack level too deep expect { subject.soonest_working_day(sunday_2022_07_31, delay: 100_000) } .not_to raise_error end end - context "with weekend days (Saturday and Sunday)", :weekend_saturday_sunday do - include_examples "soonest working day", date: friday_2022_07_29, expected: friday_2022_07_29 - include_examples "soonest working day", date: saturday_2022_07_30, expected: monday_2022_08_01 - include_examples "soonest working day", date: sunday_2022_07_31, expected: monday_2022_08_01 - include_examples "soonest working day", date: monday_2022_08_01, expected: monday_2022_08_01 + context 'with weekend days (Saturday and Sunday)', :weekend_saturday_sunday do + include_examples 'soonest working day', date: friday_2022_07_29, expected: friday_2022_07_29 + include_examples 'soonest working day', date: saturday_2022_07_30, expected: monday_2022_08_01 + include_examples 'soonest working day', date: sunday_2022_07_31, expected: monday_2022_08_01 + include_examples 'soonest working day', date: monday_2022_08_01, expected: monday_2022_08_01 - context "with delay" do - include_examples "soonest working day with delay", date: friday_2022_07_29, delay: 0, expected: friday_2022_07_29 - include_examples "soonest working day with delay", date: saturday_2022_07_30, delay: 0, expected: monday_2022_08_01 - include_examples "soonest working day with delay", date: sunday_2022_07_31, delay: 0, expected: monday_2022_08_01 - include_examples "soonest working day with delay", date: monday_2022_08_01, delay: 0, expected: monday_2022_08_01 + context 'with delay' do + include_examples 'soonest working day with delay', date: friday_2022_07_29, delay: 0, expected: friday_2022_07_29 + include_examples 'soonest working day with delay', date: saturday_2022_07_30, delay: 0, expected: monday_2022_08_01 + include_examples 'soonest working day with delay', date: sunday_2022_07_31, delay: 0, expected: monday_2022_08_01 + include_examples 'soonest working day with delay', date: monday_2022_08_01, delay: 0, expected: monday_2022_08_01 - include_examples "soonest working day with delay", date: friday_2022_07_29, delay: 1, expected: monday_2022_08_01 - include_examples "soonest working day with delay", date: saturday_2022_07_30, delay: 1, expected: Date.new(2022, 8, 2) - include_examples "soonest working day with delay", date: sunday_2022_07_31, delay: 1, expected: Date.new(2022, 8, 2) - include_examples "soonest working day with delay", date: monday_2022_08_01, delay: 1, expected: Date.new(2022, 8, 2) + include_examples 'soonest working day with delay', date: friday_2022_07_29, delay: 1, expected: monday_2022_08_01 + include_examples 'soonest working day with delay', date: saturday_2022_07_30, delay: 1, expected: Date.new(2022, 8, 2) + include_examples 'soonest working day with delay', date: sunday_2022_07_31, delay: 1, expected: Date.new(2022, 8, 2) + include_examples 'soonest working day with delay', date: monday_2022_08_01, delay: 1, expected: Date.new(2022, 8, 2) - include_examples "soonest working day with delay", date: friday_2022_07_29, delay: 8, expected: Date.new(2022, 8, 10) + include_examples 'soonest working day with delay', date: friday_2022_07_29, delay: 8, expected: Date.new(2022, 8, 10) end end - context "with some non working days (Christmas 2022-12-25 and new year's day 2023-01-01)", :christmas_2022_new_year_2023 do - include_examples "soonest working day", date: Date.new(2022, 12, 25), expected: Date.new(2022, 12, 26) - include_examples "soonest working day", date: Date.new(2022, 12, 31), expected: Date.new(2022, 12, 31) - include_examples "soonest working day", date: Date.new(2023, 1, 1), expected: Date.new(2023, 1, 2) + context 'with some non working days (Christmas 2022-12-25 and new year\'s day 2023-01-01)', :christmas_2022_new_year_2023 do + include_examples 'soonest working day', date: Date.new(2022, 12, 25), expected: Date.new(2022, 12, 26) + include_examples 'soonest working day', date: Date.new(2022, 12, 31), expected: Date.new(2022, 12, 31) + include_examples 'soonest working day', date: Date.new(2023, 1, 1), expected: Date.new(2023, 1, 2) - context "with delay" do - include_examples "soonest working day with delay", date: Date.new(2022, 12, 24), delay: 7, expected: Date.new(2023, 1, 2) + context 'with delay' do + include_examples 'soonest working day with delay', date: Date.new(2022, 12, 24), delay: 7, expected: Date.new(2023, 1, 2) end end - context "with no working days", :no_working_days do - it "prevents looping infinitely by raising a runtime error" do + context 'with no working days', :no_working_days do + it 'prevents looping infinitely by raising a runtime error' do expect { subject.soonest_working_day(sunday_2022_07_31) } - .to raise_error(RuntimeError, "cannot have all week days as non-working days") + .to raise_error(RuntimeError, 'cannot have all week days as non-working days') end end end diff --git a/spec/services/work_packages/update_ancestors/loader_spec.rb b/spec/services/work_packages/update_ancestors/loader_spec.rb index 0b4f7c70bd24..ef7137bc9f9a 100644 --- a/spec/services/work_packages/update_ancestors/loader_spec.rb +++ b/spec/services/work_packages/update_ancestors/loader_spec.rb @@ -24,41 +24,41 @@ # # See COPYRIGHT and LICENSE files for more details. -require "spec_helper" +require 'spec_helper' RSpec.describe WorkPackages::UpdateAncestors::Loader, type: :model do shared_let(:grandgrandparent) do create(:work_package, - subject: "grandgrandparent") + subject: 'grandgrandparent') end shared_let(:grandparent_sibling) do create(:work_package, - subject: "grandparent sibling", + subject: 'grandparent sibling', parent: grandgrandparent) end shared_let(:grandparent) do create(:work_package, - subject: "grandparent", + subject: 'grandparent', parent: grandgrandparent) end shared_let(:parent) do create(:work_package, - subject: "parent", + subject: 'parent', parent: grandparent) end shared_let(:sibling) do create(:work_package, - subject: "sibling", + subject: 'sibling', parent:) end shared_let(:work_package, refind: true) do create(:work_package, - subject: "work package", + subject: 'work package', parent:) end shared_let(:child) do create(:work_package, - subject: "child", + subject: 'child', parent: work_package) end @@ -69,7 +69,7 @@ .new(work_package, include_former_ancestors) end - describe "#select" do + describe '#select' do subject do work_package.parent = new_parent work_package.save! @@ -77,153 +77,153 @@ instance end - context "when switching the hierarchy" do + context 'when switching the hierarchy' do let!(:new_grandgrandparent) do create(:work_package, - subject: "new grandgrandparent") + subject: 'new grandgrandparent') end let!(:new_grandparent) do create(:work_package, parent: new_grandgrandparent, - subject: "new grandparent") + subject: 'new grandparent') end let!(:new_parent) do create(:work_package, - subject: "new parent", + subject: 'new parent', parent: new_grandparent) end let!(:new_sibling) do create(:work_package, - subject: "new sibling", + subject: 'new sibling', parent: new_parent) end - it "iterates over the initiator work package, and both its current and former ancestors" do + it 'iterates over the initiator work package, and both its current and former ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, new_parent, new_grandparent, new_grandgrandparent, parent, grandparent, grandgrandparent] end end - context "when switching the hierarchy and not including the former ancestors" do + context 'when switching the hierarchy and not including the former ancestors' do let!(:new_grandgrandparent) do create(:work_package, - subject: "new grandgrandparent") + subject: 'new grandgrandparent') end let!(:new_grandparent) do create(:work_package, parent: new_grandgrandparent, - subject: "new grandparent") + subject: 'new grandparent') end let!(:new_parent) do create(:work_package, - subject: "new parent", + subject: 'new parent', parent: new_grandparent) end let!(:new_sibling) do create(:work_package, - subject: "new sibling", + subject: 'new sibling', parent: new_parent) end let(:include_former_ancestors) { false } - it "iterates over the initiator work package and the current ancestors" do + it 'iterates over the initiator work package and the current ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, new_parent, new_grandparent, new_grandgrandparent] end end - context "when destroying the initiator" do + context 'when destroying the initiator' do subject do work_package.destroy! instance end - it "iterates over the former ancestors" do + it 'iterates over the former ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [parent, grandparent, grandgrandparent] end end - context "when removing the parent" do + context 'when removing the parent' do let(:new_parent) { nil } - it "iterates over the initiator work package and the former ancestors" do + it 'iterates over the initiator work package and the former ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, parent, grandparent, grandgrandparent] end end - context "when removing the parent and not including the former ancestors" do + context 'when removing the parent and not including the former ancestors' do let(:new_parent) { nil } let(:include_former_ancestors) { false } - it "loads only the initiator" do + it 'loads only the initiator' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package] end end - context "when changing the parent within the same hierarchy upwards" do + context 'when changing the parent within the same hierarchy upwards' do let(:new_parent) { grandgrandparent } - it "iterates over the initiator and the former ancestors" do + it 'iterates over the initiator and the former ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, parent, grandparent, grandgrandparent] end end - context "when changing the parent within the same hierarchy upwards and not loading former ancestors" do + context 'when changing the parent within the same hierarchy upwards and not loading former ancestors' do let(:new_parent) { grandgrandparent } let(:include_former_ancestors) { false } - it "iterates over the initiator and the current ancestors" do + it 'iterates over the initiator and the current ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, grandgrandparent] end end - context "when changing the parent within the same hierarchy sideways" do + context 'when changing the parent within the same hierarchy sideways' do let(:new_parent) { sibling } - it "iterates over the initiator and the current ancestors" do + it 'iterates over the initiator and the current ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, sibling, parent, grandparent, grandgrandparent] end end - context "when changing the parent within the same hierarchy sideways and not loading former ancestors" do + context 'when changing the parent within the same hierarchy sideways and not loading former ancestors' do let(:new_parent) { sibling } let(:include_former_ancestors) { false } - it "iterates over the initiator and the current ancestors" do + it 'iterates over the initiator and the current ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, sibling, parent, grandparent, grandgrandparent] end end - context "when changing the parent within the same hierarchy sideways but to a different level" do + context 'when changing the parent within the same hierarchy sideways but to a different level' do let(:new_parent) { grandparent_sibling } - it "iterates over the initiator and its former and current ancestors" do + it 'iterates over the initiator and its former and current ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, grandparent_sibling, parent, grandparent, grandgrandparent] end end - context "when changing the parent within the same hierarchy sideways but to a different level and not loading ancestors" do + context 'when changing the parent within the same hierarchy sideways but to a different level and not loading ancestors' do let(:new_parent) { grandparent_sibling } let(:include_former_ancestors) { false } - it "iterates over the initiator and its former and current ancestors" do + it 'iterates over the initiator and its former and current ancestors' do expect(subject.select { |ancestor| ancestor }) .to eq [work_package, grandparent_sibling, grandgrandparent] end end end - describe "#descendants_of" do + describe '#descendants_of' do def descendants_of_hash(hashed_work_package) { "estimated_hours" => nil, "id" => hashed_work_package.id, @@ -233,29 +233,29 @@ def descendants_of_hash(hashed_work_package) "schedule_manually" => false } end - context "for the work_package" do - it "is its child (as a hash)" do + context 'for the work_package' do + it 'is its child (as a hash)' do expect(instance.descendants_of(work_package)) .to contain_exactly(descendants_of_hash(child)) end end - context "for the parent" do - it "is the work package, its child (as a hash) and its sibling (as a hash)" do + context 'for the parent' do + it 'is the work package, its child (as a hash) and its sibling (as a hash)' do expect(instance.descendants_of(parent)) .to contain_exactly(descendants_of_hash(child), work_package, descendants_of_hash(sibling)) end end - context "for the grandparent" do - it "is the parent, the work package, its child (as a hash) and its sibling (as a hash)" do + context 'for the grandparent' do + it 'is the parent, the work package, its child (as a hash) and its sibling (as a hash)' do expect(instance.descendants_of(grandparent)) .to contain_exactly(parent, work_package, descendants_of_hash(child), descendants_of_hash(sibling)) end end - context "for the grandgrandparent (the root)" do - it "is the complete tree, partly as a hash and partly as the preloaded work packages" do + context 'for the grandgrandparent (the root)' do + it 'is the complete tree, partly as a hash and partly as the preloaded work packages' do expect(instance.descendants_of(grandgrandparent)) .to contain_exactly(descendants_of_hash(grandparent_sibling), grandparent, parent, work_package, descendants_of_hash(child), descendants_of_hash(sibling)) @@ -263,7 +263,7 @@ def descendants_of_hash(hashed_work_package) end end - describe "#children_of" do + describe '#children_of' do def children_of_hash(hashed_work_package) { "estimated_hours" => nil, "id" => hashed_work_package.id, @@ -273,29 +273,29 @@ def children_of_hash(hashed_work_package) "schedule_manually" => false } end - context "for the work_package" do - it "is its child (as a hash)" do + context 'for the work_package' do + it 'is its child (as a hash)' do expect(instance.children_of(work_package)) .to contain_exactly(children_of_hash(child)) end end - context "for the parent" do - it "is the work package and its sibling (as a hash)" do + context 'for the parent' do + it 'is the work package and its sibling (as a hash)' do expect(instance.children_of(parent)) .to contain_exactly(work_package, children_of_hash(sibling)) end end - context "for the grandparent" do - it "is the parent" do + context 'for the grandparent' do + it 'is the parent' do expect(instance.children_of(grandparent)) .to contain_exactly(parent) end end - context "for the grandgrandparent" do - it "is the grandparent and its sibling (as a hash)" do + context 'for the grandgrandparent' do + it 'is the grandparent and its sibling (as a hash)' do expect(instance.children_of(grandgrandparent)) .to contain_exactly(children_of_hash(grandparent_sibling), grandparent) end diff --git a/spec/services/work_packages/update_service_spec.rb b/spec/services/work_packages/update_service_spec.rb index a32f104bbf95..9f2203f9d337 100644 --- a/spec/services/work_packages/update_service_spec.rb +++ b/spec/services/work_packages/update_service_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require "services/base_services/behaves_like_update_service" +require 'spec_helper' +require 'services/base_services/behaves_like_update_service' RSpec.describe WorkPackages::UpdateService, type: :model do # This is now only a very basic test testing the structure of the service. # The domain tests are in the update_service_integration_spec.rb - it_behaves_like "BaseServices update service" do + it_behaves_like 'BaseServices update service' do before do allow(set_attributes_errors) .to receive(:merge!) diff --git a/spec/services/workflows/bulk_update_service_integration_spec.rb b/spec/services/workflows/bulk_update_service_integration_spec.rb index 658eeceab188..19ce622fcdee 100644 --- a/spec/services/workflows/bulk_update_service_integration_spec.rb +++ b/spec/services/workflows/bulk_update_service_integration_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Workflows::BulkUpdateService, "integration", type: :model do +RSpec.describe Workflows::BulkUpdateService, 'integration', type: :model do let(:type) do create(:type) end @@ -55,21 +55,21 @@ described_class.new(role:, type:) end - describe "#call" do + describe '#call' do let(:params) { {} } let(:subject) do instance.call(params) end - context "with status transitions for everybody" do + context 'with status transitions for everybody' do let(:params) do { - status4.id => { status5.id => ["always"] }, - status3.id => { status1.id => ["always"], status2.id => ["always"] } + status4.id => { status5.id => ['always'] }, + status3.id => { status1.id => ['always'], status2.id => ['always'] } } end - it "sets the workflows" do + it 'sets the workflows' do subject expect(Workflow.where(type_id: type.id, role_id: role.id).count) @@ -86,15 +86,15 @@ end end - context "with additional transitions" do + context 'with additional transitions' do let(:params) do { - status4.id => { status5.id => ["always"] }, - status3.id => { status1.id => ["author"], status2.id => ["assignee"], status4.id => %w(author assignee) } + status4.id => { status5.id => ['always'] }, + status3.id => { status1.id => ['author'], status2.id => ['assignee'], status4.id => %w(author assignee) } } end - it "sets the workflows" do + it 'sets the workflows' do subject expect(Workflow.where(type_id: type.id, role_id: role.id).count) @@ -115,7 +115,7 @@ end end - context "without transitions" do + context 'without transitions' do let(:params) do {} end @@ -124,7 +124,7 @@ Workflow.create!(role_id: role.id, type_id: type.id, old_status_id: status3.id, new_status_id: status2.id) end - it "clears all workflows" do + it 'clears all workflows' do subject expect(Workflow.where(type_id: type.id, role_id: role.id).count) @@ -132,7 +132,7 @@ end end - context "with no params" do + context 'with no params' do let(:params) do nil end @@ -141,7 +141,7 @@ Workflow.create!(role_id: role.id, type_id: type.id, old_status_id: status3.id, new_status_id: status2.id) end - it "clears all workflows" do + it 'clears all workflows' do subject expect(Workflow.where(type_id: type.id, role_id: role.id).count) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d358e768cc4c..e721da981b9b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -46,7 +46,7 @@ # We currently require spec_helper here, since we loaded # the environment at all times before and have no specs that may run outside -require_relative "rails_helper" +require_relative 'rails_helper' RSpec.configure do |config| config.expect_with :rspec do |expectations| @@ -91,10 +91,10 @@ # Use the documentation formatter for detailed output, # unless a formatter has already been configured # (e.g. via a command-line flag). - config.default_formatter = "doc" + config.default_formatter = 'doc' else # Otherwise, use the Fuubar formatter if we're not on the CI - unless ENV["TEST_ENV_NUMBER"] || ENV["CI"] + unless ENV['TEST_ENV_NUMBER'] || ENV['CI'] config.default_formatter = Fuubar end end @@ -103,7 +103,7 @@ # end of the spec run, to help surface which specs are running # particularly slow. # Disabled on CI to have a cleaner log output. - config.profile_examples = 10 unless ENV["CI"] + config.profile_examples = 10 unless ENV['CI'] # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing diff --git a/spec/support/a11y.rb b/spec/support/a11y.rb index d5af4463d54a..1c38e8f4cf43 100644 --- a/spec/support/a11y.rb +++ b/spec/support/a11y.rb @@ -28,4 +28,4 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "axe-rspec" +require 'axe-rspec' diff --git a/spec/support/angular.rb b/spec/support/angular.rb index fd40c232e803..e1aa5a96d1da 100644 --- a/spec/support/angular.rb +++ b/spec/support/angular.rb @@ -29,5 +29,5 @@ ## # Wait for the angular bootstrap to have happened def expect_angular_frontend_initialized - expect(page).to have_css(".__ng2-bootstrap-has-run", wait: 20) + expect(page).to have_css('.__ng2-bootstrap-has-run', wait: 20) end diff --git a/spec/support/api/v3/shared_available_principals_examples.rb b/spec/support/api/v3/shared_available_principals_examples.rb index 0934e3f7977c..413f80c8e252 100644 --- a/spec/support/api/v3/shared_available_principals_examples.rb +++ b/spec/support/api/v3/shared_available_principals_examples.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rack/test" +require 'rack/test' -RSpec.shared_examples_for "available principals" do |principals, work_package_scope: false| +RSpec.shared_examples_for 'available principals' do |principals, work_package_scope: false| include API::V3::Utilities::PathHelper current_user do @@ -60,23 +60,23 @@ before { get href } end - describe "response" do + describe 'response' do shared_examples_for "returns available #{principals}" do |total, count, klass| include_context "request available #{principals}" - it_behaves_like "API V3 collection response", total, count, klass + it_behaves_like 'API V3 collection response', total, count, klass end - describe "users" do + describe 'users' do let(:permissions) { base_permissions + assignable_permissions } - context "for a single user" do + context 'for a single user' do # The current user - it_behaves_like "returns available #{principals}", 1, 1, "User" + it_behaves_like "returns available #{principals}", 1, 1, 'User' end - context "for multiple users" do + context 'for multiple users' do before do other_user shared_with_user @@ -84,43 +84,43 @@ end if work_package_scope - it_behaves_like "returns available #{principals}", 3, 3, "User" + it_behaves_like "returns available #{principals}", 3, 3, 'User' else - it_behaves_like "returns available #{principals}", 2, 2, "User" + it_behaves_like "returns available #{principals}", 2, 2, 'User' end end - context "if the user lacks the assignable permission" do + context 'if the user lacks the assignable permission' do let(:permissions) { base_permissions } - it_behaves_like "returns available #{principals}", 0, 0, "User" + it_behaves_like "returns available #{principals}", 0, 0, 'User' end end - describe "groups" do + describe 'groups' do let!(:users) { [group] } - it_behaves_like "returns available #{principals}", 1, 1, "Group" + it_behaves_like "returns available #{principals}", 1, 1, 'Group' end - describe "placeholder users" do + describe 'placeholder users' do let!(:users) { [placeholder_user] } - it_behaves_like "returns available #{principals}", 1, 1, "PlaceholderUser" + it_behaves_like "returns available #{principals}", 1, 1, 'PlaceholderUser' end end - describe "if not allowed" do + describe 'if not allowed' do include Rack::Test::Methods let(:permissions) { [] } before { get href } if work_package_scope - it_behaves_like "not found", - I18n.t("api_v3.errors.not_found.work_package") + it_behaves_like 'not found', + I18n.t('api_v3.errors.not_found.work_package') else - it_behaves_like "unauthorized access" + it_behaves_like 'unauthorized access' end end end diff --git a/spec/support/api/v3/work_packages/work_package_representer_eager_loading.rb b/spec/support/api/v3/work_packages/work_package_representer_eager_loading.rb index 3638c9a40e47..5242918151a6 100644 --- a/spec/support/api/v3/work_packages/work_package_representer_eager_loading.rb +++ b/spec/support/api/v3/work_packages/work_package_representer_eager_loading.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "eager loaded work package representer" do +RSpec.shared_context 'eager loaded work package representer' do before do allow(API::V3::WorkPackages::WorkPackageEagerLoadingWrapper) .to receive(:wrap_one) do |work_package, _user| diff --git a/spec/support/authentication_helpers.rb b/spec/support/authentication_helpers.rb index 3785fd179b52..43ce2386c5d1 100644 --- a/spec/support/authentication_helpers.rb +++ b/spec/support/authentication_helpers.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rack_session_access/capybara" +require 'rack_session_access/capybara' module AuthenticationHelpers def self.included(base) @@ -41,7 +41,7 @@ def login_as(user) # as they will login AnonymousUser if using_cuprite? && js_enabled? page.driver.set_cookie( - OpenProject::Configuration["session_cookie_name"], + OpenProject::Configuration['session_cookie_name'], session_value_for(user).to_s ) else @@ -56,12 +56,12 @@ def login_as(user) def login_with(login, password, autologin: false, visit_signin_path: true) visit signin_path if visit_signin_path - within(".user-login--form") do - fill_in "username", with: login - fill_in "password", with: password + within('.user-login--form') do + fill_in 'username', with: login + fill_in 'password', with: password if autologin - autologin_label = I18n.t("users.autologins.prompt", - num_days: I18n.t("datetime.distance_in_words.x_days", count: Setting.autologin)) + autologin_label = I18n.t('users.autologins.prompt', + num_days: I18n.t('datetime.distance_in_words.x_days', count: Setting.autologin)) check autologin_label end click_button I18n.t(:button_login) diff --git a/spec/support/browsers/chrome.rb b/spec/support/browsers/chrome.rb index 380c43a8aa6d..0aff91f896a1 100644 --- a/spec/support/browsers/chrome.rb +++ b/spec/support/browsers/chrome.rb @@ -1,38 +1,38 @@ # rubocop:disable Metrics/PerceivedComplexity -def register_chrome(language, name: :"chrome_#{language}", headless: "old", override_time_zone: nil) +def register_chrome(language, name: :"chrome_#{language}", headless: 'old', override_time_zone: nil) Capybara.register_driver name do |app| options = Selenium::WebDriver::Chrome::Options.new - if ActiveRecord::Type::Boolean.new.cast(ENV.fetch("OPENPROJECT_TESTING_NO_HEADLESS", nil)) + if ActiveRecord::Type::Boolean.new.cast(ENV.fetch('OPENPROJECT_TESTING_NO_HEADLESS', nil)) # Maximize the window however large the available space is - options.add_argument("--start-maximized") + options.add_argument('--start-maximized') # Open dev tools for quick access - if ActiveRecord::Type::Boolean.new.cast(ENV.fetch("OPENPROJECT_TESTING_AUTO_DEVTOOLS", nil)) - options.add_argument("--auto-open-devtools-for-tabs") + if ActiveRecord::Type::Boolean.new.cast(ENV.fetch('OPENPROJECT_TESTING_AUTO_DEVTOOLS', nil)) + options.add_argument('--auto-open-devtools-for-tabs') end else - options.add_argument("--window-size=1920,1080") + options.add_argument('--window-size=1920,1080') options.add_argument("--headless=#{headless}") end - options.add_argument("--no-sandbox") - options.add_argument("--disable-gpu") - options.add_argument("--disable-popup-blocking") + options.add_argument('--no-sandbox') + options.add_argument('--disable-gpu') + options.add_argument('--disable-popup-blocking') options.add_argument("--lang=#{language}") - options.add_preference("intl.accept_languages", language) + options.add_preference('intl.accept_languages', language) # This is REQUIRED for running in a docker container # https://github.com/grosser/parallel_tests/issues/658 - options.add_argument("--disable-dev-shm-usage") - options.add_argument("--disable-smooth-scrolling") + options.add_argument('--disable-dev-shm-usage') + options.add_argument('--disable-smooth-scrolling') options.add_preference(:download, directory_upgrade: true, prompt_for_download: false, default_directory: DownloadList::SHARED_PATH.to_s) - options.add_preference(:browser, set_download_behavior: { behavior: "allow" }) + options.add_preference(:browser, set_download_behavior: { behavior: 'allow' }) - options.logging_prefs = { browser: "ALL" } + options.logging_prefs = { browser: 'ALL' } yield(options) if block_given? @@ -40,7 +40,7 @@ def register_chrome(language, name: :"chrome_#{language}", headless: "old", over client.read_timeout = 180 client.open_timeout = 180 - is_grid = ENV["SELENIUM_GRID_URL"].present? + is_grid = ENV['SELENIUM_GRID_URL'].present? driver_opts = { browser: is_grid ? :remote : :chrome, @@ -49,10 +49,10 @@ def register_chrome(language, name: :"chrome_#{language}", headless: "old", over } if is_grid - driver_opts[:url] = ENV.fetch("SELENIUM_GRID_URL", nil) + driver_opts[:url] = ENV.fetch('SELENIUM_GRID_URL', nil) else driver_opts[:service] = Selenium::WebDriver::Service.chrome( - args: ["--verbose", "--log-path=/tmp/chromedriver.log"] + args: ['--verbose', '--log-path=/tmp/chromedriver.log'] ) end @@ -65,13 +65,13 @@ def register_chrome(language, name: :"chrome_#{language}", headless: "old", over bridge.http.call :post, "/session/#{bridge.session_id}/chromium/send_command", - cmd: "Page.setDownloadBehavior", - params: { behavior: "allow", downloadPath: DownloadList::SHARED_PATH.to_s } + cmd: 'Page.setDownloadBehavior', + params: { behavior: 'allow', downloadPath: DownloadList::SHARED_PATH.to_s } if override_time_zone bridge.http.call :post, "/session/#{bridge.session_id}/chromium/send_command", - cmd: "Emulation.setTimezoneOverride", + cmd: 'Emulation.setTimezoneOverride', params: { timezoneId: override_time_zone } end end @@ -85,9 +85,9 @@ def register_chrome(language, name: :"chrome_#{language}", headless: "old", over end # rubocop:enable Metrics/PerceivedComplexity -register_chrome "en" +register_chrome 'en' # Register german locale for custom field decimal test -register_chrome "de" +register_chrome 'de' Billy.configure do |c| c.proxy_host = Capybara.server_host @@ -107,10 +107,10 @@ def register_chrome(language, name: :"chrome_#{language}", headless: "old", over # # In the meantime, registering a :chrome_headless_new driver which uses the # `headless=new` flag for tests that need it. -register_chrome "en", name: :chrome_headless_new, headless: "new" +register_chrome 'en', name: :chrome_headless_new, headless: 'new' # Register mocking proxy driver -register_chrome "en", name: :chrome_billy do |options| +register_chrome 'en', name: :chrome_billy do |options| options.add_argument("proxy-server=#{Billy.proxy.host}:#{Billy.proxy.port}") options.add_argument("proxy-bypass-list=127.0.0.1;localhost;#{Capybara.server_host}") @@ -118,8 +118,8 @@ def register_chrome(language, name: :"chrome_#{language}", headless: "old", over end # Register Revit add in -register_chrome "en", name: :chrome_revit_add_in do |options| +register_chrome 'en', name: :chrome_revit_add_in do |options| options.add_argument("user-agent='foo bar Revit'") end -register_chrome "en", name: :chrome_new_york_time_zone, override_time_zone: "America/New_York" +register_chrome 'en', name: :chrome_new_york_time_zone, override_time_zone: 'America/New_York' diff --git a/spec/support/browsers/firefox.rb b/spec/support/browsers/firefox.rb index 158385d6c2cc..3b3b0fb0e2fc 100644 --- a/spec/support/browsers/firefox.rb +++ b/spec/support/browsers/firefox.rb @@ -1,46 +1,46 @@ -require "socket" +require 'socket' def register_firefox(language, name: :"firefox_#{language}") - require "selenium/webdriver" + require 'selenium/webdriver' Capybara.register_driver name do |app| - client = if ENV["CI"] + client = if ENV['CI'] Selenium::WebDriver::Remote::Http::Default.new(open_timeout: 180, read_timeout: 180) end profile = Selenium::WebDriver::Firefox::Profile.new - profile["intl.accept_languages"] = language - profile["browser.download.dir"] = DownloadList::SHARED_PATH.to_s - profile["browser.download.folderList"] = 2 - profile["browser.helperApps.neverAsk.saveToDisk"] = "text/csv" + profile['intl.accept_languages'] = language + profile['browser.download.dir'] = DownloadList::SHARED_PATH.to_s + profile['browser.download.folderList'] = 2 + profile['browser.helperApps.neverAsk.saveToDisk'] = 'text/csv' # prevent stale firefoxCP processes - profile["browser.tabs.remote.autostart"] = false - profile["browser.tabs.remote.autostart.2"] = false + profile['browser.tabs.remote.autostart'] = false + profile['browser.tabs.remote.autostart.2'] = false # only one FF process - profile["dom.ipc.processCount"] = 1 + profile['dom.ipc.processCount'] = 1 - profile["general.smoothScroll"] = false + profile['general.smoothScroll'] = false options = Selenium::WebDriver::Firefox::Options.new(profile:) yield(profile, options) if block_given? - unless ActiveRecord::Type::Boolean.new.cast(ENV.fetch("OPENPROJECT_TESTING_NO_HEADLESS", nil)) + unless ActiveRecord::Type::Boolean.new.cast(ENV.fetch('OPENPROJECT_TESTING_NO_HEADLESS', nil)) options.args << "--headless" end - if ActiveRecord::Type::Boolean.new.cast(ENV.fetch("OPENPROJECT_TESTING_AUTO_DEVTOOLS", nil)) + if ActiveRecord::Type::Boolean.new.cast(ENV.fetch('OPENPROJECT_TESTING_AUTO_DEVTOOLS', nil)) options.args << "--devtools" end - is_grid = ENV["SELENIUM_GRID_URL"].present? + is_grid = ENV['SELENIUM_GRID_URL'].present? driver_opts = { browser: is_grid ? :remote : :firefox, - url: ENV.fetch("SELENIUM_GRID_URL", nil), + url: ENV.fetch('SELENIUM_GRID_URL', nil), http_client: client, options: } @@ -55,6 +55,6 @@ def register_firefox(language, name: :"firefox_#{language}") end end -register_firefox "en" +register_firefox 'en' # Register german locale for custom field decimal test -register_firefox "de" +register_firefox 'de' diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb index 146c1a299fd2..3017c4ddee47 100644 --- a/spec/support/capybara.rb +++ b/spec/support/capybara.rb @@ -1,11 +1,11 @@ -require "socket" -require "capybara/rspec" -require "capybara-screenshot" -require "capybara-screenshot/rspec" -require "rack_session_access/capybara" -require "action_dispatch" - -RSpec.shared_context "with default_url_options and host name set to Capybara test server" do +require 'socket' +require 'capybara/rspec' +require 'capybara-screenshot' +require 'capybara-screenshot/rspec' +require 'rack_session_access/capybara' +require 'action_dispatch' + +RSpec.shared_context 'with default_url_options and host name set to Capybara test server' do around do |example| original_host = default_url_options[:host] original_port = default_url_options[:port] @@ -25,23 +25,23 @@ Capybara.default_max_wait_time = 4 Capybara.javascript_driver = :chrome_en - port = ENV.fetch("CAPYBARA_SERVER_PORT", ParallelHelper.port_for_app).to_i + port = ENV.fetch('CAPYBARA_SERVER_PORT', ParallelHelper.port_for_app).to_i if port > 0 Capybara.server_port = port end Capybara.always_include_port = true - if ENV["CAPYBARA_DYNAMIC_BIND_IP"] + if ENV['CAPYBARA_DYNAMIC_BIND_IP'] ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address - hostname = ENV.fetch("CAPYBARA_APP_HOSTNAME", ip_address) + hostname = ENV.fetch('CAPYBARA_APP_HOSTNAME', ip_address) Capybara.server_host = ip_address Capybara.app_host = "http://#{hostname}" else - Capybara.server_host = ENV.fetch("CAPYBARA_APP_HOSTNAME", "localhost") + Capybara.server_host = ENV.fetch('CAPYBARA_APP_HOSTNAME', 'localhost') end # Set the default options - config.include_context "with default_url_options and host name set to Capybara test server", type: :feature + config.include_context 'with default_url_options and host name set to Capybara test server', type: :feature # Make it possible to match on value attribute. # diff --git a/spec/support/capybara/additional_accessible_selectors.rb b/spec/support/capybara/additional_accessible_selectors.rb index a70634d772f7..335bee8158ca 100644 --- a/spec/support/capybara/additional_accessible_selectors.rb +++ b/spec/support/capybara/additional_accessible_selectors.rb @@ -33,7 +33,7 @@ end Capybara.add_selector(:list_item) do - label "list item" + label 'list item' xpath { ".//li" } diff --git a/spec/support/capybara_browser_screenshots.rb b/spec/support/capybara_browser_screenshots.rb index b56780e08190..57ab7b680a4d 100644 --- a/spec/support/capybara_browser_screenshots.rb +++ b/spec/support/capybara_browser_screenshots.rb @@ -1,23 +1,23 @@ # frozen_string_literal: true -require "capybara-screenshot" -require "capybara-screenshot/rspec" +require 'capybara-screenshot' +require 'capybara-screenshot/rspec' # Remove old images automatically Capybara::Screenshot.prune_strategy = :keep_last_run # Set up S3 uploads if desired -if ENV["CAPYBARA_AWS_ACCESS_KEY_ID"].present? +if ENV['CAPYBARA_AWS_ACCESS_KEY_ID'].present? Capybara::Screenshot.s3_configuration = { s3_client_credentials: { - access_key_id: ENV.fetch("CAPYBARA_AWS_ACCESS_KEY_ID"), - secret_access_key: ENV.fetch("CAPYBARA_AWS_SECRET_ACCESS_KEY"), - region: ENV.fetch("CAPYBARA_AWS_REGION", "eu-west-1") + access_key_id: ENV.fetch('CAPYBARA_AWS_ACCESS_KEY_ID'), + secret_access_key: ENV.fetch('CAPYBARA_AWS_SECRET_ACCESS_KEY'), + region: ENV.fetch('CAPYBARA_AWS_REGION', 'eu-west-1') }, - bucket_name: ENV.fetch("CAPYBARA_AWS_BUCKET", "openproject-ci-public-logs") + bucket_name: ENV.fetch('CAPYBARA_AWS_BUCKET', 'openproject-ci-public-logs') } Capybara::Screenshot.s3_object_configuration = { - acl: "public-read" + acl: 'public-read' } end @@ -44,7 +44,7 @@ def output_screenshot_info(example) return unless screenshot = example.metadata[:screenshot] info = { - message: "Screenshot captured for failed feature test", + message: 'Screenshot captured for failed feature test', test_id: example.id, test_location: example.location }.merge(screenshot) diff --git a/spec/support/carrierwave.rb b/spec/support/carrierwave.rb index fad4292f43f1..b1f586def6e4 100644 --- a/spec/support/carrierwave.rb +++ b/spec/support/carrierwave.rb @@ -40,15 +40,15 @@ def apply end def bucket - "test-bucket" + 'test-bucket' end def credentials { - provider: "AWS", - aws_access_key_id: "someaccesskeyid", - aws_secret_access_key: "someprivateaccesskey", - region: "us-east-1" + provider: 'AWS', + aws_access_key_id: 'someaccesskeyid', + aws_secret_access_key: 'someprivateaccesskey', + region: 'us-east-1' } end end diff --git a/spec/support/clean_feature_decisions.rb b/spec/support/clean_feature_decisions.rb index b104163a1c40..ab53bb509389 100644 --- a/spec/support/clean_feature_decisions.rb +++ b/spec/support/clean_feature_decisions.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "with clean feature decisions" do +RSpec.shared_context 'with clean feature decisions' do let!(:decisions_before) { OpenProject::FeatureDecisions.all.dup } before do diff --git a/spec/support/components/admin/type_configuration_form.rb b/spec/support/components/admin/type_configuration_form.rb index a5763d06e150..e88407a96a4f 100644 --- a/spec/support/components/admin/type_configuration_form.rb +++ b/spec/support/components/admin/type_configuration_form.rb @@ -34,38 +34,38 @@ class TypeConfigurationForm include RSpec::Matchers def add_button_dropdown - page.find ".form-configuration--add-group", text: "Group" + page.find '.form-configuration--add-group', text: 'Group' end def add_attribute_group_button - page.find "button", text: I18n.t("js.admin.type_form.add_group") + page.find 'button', text: I18n.t('js.admin.type_form.add_group') end def add_table_button - page.find "button", text: I18n.t("js.admin.type_form.add_table") + page.find 'button', text: I18n.t('js.admin.type_form.add_table') end def reset_button - page.find ".form-configuration--reset" + page.find '.form-configuration--reset' end def inactive_group - page.find_by_id "type-form-conf-inactive-group" + page.find_by_id 'type-form-conf-inactive-group' end def inactive_drop - page.find "#type-form-conf-inactive-group .attributes" + page.find '#type-form-conf-inactive-group .attributes' end def expect_empty - expect(page).to have_no_css("#draggable-groups .group-head") + expect(page).to have_no_css('#draggable-groups .group-head') end def find_group(name) - head = page.find(".group-head", text: name.upcase) + head = page.find('.group-head', text: name.upcase) # Return the parent of the group-head - head.find(:xpath, "..") + head.find(:xpath, '..') end def checkbox_selector(attribute) @@ -88,7 +88,7 @@ def expect_attribute(key:, translation: nil) attribute = page.find(attribute_selector(key)) unless translation.nil? - expect(attribute).to have_css(".attribute-name", text: translation) + expect(attribute).to have_css('.attribute-name', text: translation) end end @@ -101,11 +101,11 @@ def move_to(attribute, group_label) def remove_attribute(attribute) attribute = page.find(attribute_selector(attribute)) - attribute.find(".delete-attribute").click + attribute.find('.delete-attribute').click end def drag_and_drop(handle, group) - target = group.find(".attributes") + target = group.find('.attributes') scroll_to_element(group) page @@ -134,7 +134,7 @@ def add_query_group(name, relation_filter, expect: true) modal = ::Components::WorkPackages::TableConfigurationModal.new - within ".relation-filter-selector" do + within '.relation-filter-selector' do select I18n.t("js.relation_labels.#{relation_filter}") # While we are here, let's check that all relation filters are present. @@ -159,7 +159,7 @@ def add_query_group(name, relation_filter, expect: true) end modal.save - input = find(".group-edit-in-place--input") + input = find('.group-edit-in-place--input') input.set(name) expect_group(name, name) if expect @@ -169,7 +169,7 @@ def edit_query_group(name) SeleniumHubWaiter.wait unless using_cuprite? group = find_group(name) - group.find(".type-form-query-group--edit-button").click + group.find('.type-form-query-group--edit-button').click wait_for_reload if using_cuprite? end @@ -177,7 +177,7 @@ def add_attribute_group(name, expect: true) add_button_dropdown.click add_attribute_group_button.click - input = find(".group-edit-in-place--input") + input = find('.group-edit-in-place--input') input.set(name) input.send_keys(:return) @@ -187,26 +187,26 @@ def add_attribute_group(name, expect: true) def save_changes # Save configuration # click_button doesn't seem to work when the button is out of view!? - scroll_to_and_click find(".form-configuration--save") + scroll_to_and_click find('.form-configuration--save') end def rename_group(from, to) - find(".group-edit-handler", text: from.upcase).click + find('.group-edit-handler', text: from.upcase).click - input = find(".group-edit-in-place--input") + input = find('.group-edit-in-place--input') input.click input.set(to) input.send_keys(:return) - expect(page).to have_css(".group-edit-handler", text: to.upcase) + expect(page).to have_css('.group-edit-handler', text: to.upcase) end def remove_group(name) - container = find(".group-head", text: name.upcase) + container = find('.group-head', text: name.upcase) - container.find(".delete-group").click + container.find('.delete-group').click - expect(page).to have_no_css(".group-head", text: name.upcase) + expect(page).to have_no_css('.group-head', text: name.upcase) end def expect_no_attribute(attribute, group) diff --git a/spec/support/components/attachments/attachments.rb b/spec/support/components/attachments/attachments.rb index 02dbd709b9f9..c3d2ef9c3be7 100644 --- a/spec/support/components/attachments/attachments.rb +++ b/spec/support/components/attachments/attachments.rb @@ -14,7 +14,7 @@ def drag_and_drop_file(target, path, position = :center, stopover = nil, cancel_ JS if stopover.is_a?(Array) && !stopover.all?(String) - raise ArgumentError, "In case the stopover is an array, it must contain only string selectors." + raise ArgumentError, 'In case the stopover is an array, it must contain only string selectors.' end element = @@ -29,24 +29,24 @@ def drag_and_drop_file(target, path, position = :center, stopover = nil, cancel_ page.execute_script( js_drop_files, element, - "temporary_attachment_files", + 'temporary_attachment_files', position.to_s, stopover, cancel_drop, delay_dragleave ) - attach_file_on_input(path, "temporary_attachment_files") + attach_file_on_input(path, 'temporary_attachment_files') end ## # Attach a file to the hidden file input - def attach_file_on_input(path, name = "attachment_files") + def attach_file_on_input(path, name = 'attachment_files') page.attach_file(name, path, visible: :all) end def js_drop_files - @js_file ||= File.read(File.expand_path("attachments_input.js", __dir__)) + @js_file ||= File.read(File.expand_path('attachments_input.js', __dir__)) end end end diff --git a/spec/support/components/attachments_list.rb b/spec/support/components/attachments_list.rb index 84653a9afeb4..4e55a507b6b8 100644 --- a/spec/support/components/attachments_list.rb +++ b/spec/support/components/attachments_list.rb @@ -7,7 +7,7 @@ class AttachmentsList attr_reader :context_selector - def initialize(context = "#content") + def initialize(context = '#content') @context_selector = context end diff --git a/spec/support/components/autocompleter/autocomplete_helpers.rb b/spec/support/components/autocompleter/autocomplete_helpers.rb index 6de76be14c35..acb7a01d6a6c 100644 --- a/spec/support/components/autocompleter/autocomplete_helpers.rb +++ b/spec/support/components/autocompleter/autocomplete_helpers.rb @@ -40,7 +40,7 @@ def search_autocomplete(element, query:, results_selector: nil) ## # Find the open dropdown list = - page.find(results_selector || ".ng-dropdown-panel-items", wait: 10) + page.find(results_selector || '.ng-dropdown-panel-items', wait: 10) scroll_to_element(list) list @@ -58,7 +58,7 @@ def select_autocomplete(element, query:, results_selector: nil, item_selector: n query_element = if item_selector target_dropdown.find(item_selector, text:) else - target_dropdown.find(".ng-option", text:) + target_dropdown.find('.ng-option', text:) end query_element.click end diff --git a/spec/support/components/autocompleter/ng_select_autocomplete_helpers.rb b/spec/support/components/autocompleter/ng_select_autocomplete_helpers.rb index e5fa1aba7b74..63c903797303 100644 --- a/spec/support/components/autocompleter/ng_select_autocomplete_helpers.rb +++ b/spec/support/components/autocompleter/ng_select_autocomplete_helpers.rb @@ -10,7 +10,7 @@ def search_autocomplete(element, query:, results_selector: nil, wait_dropdown_op # Wait for autocompleter options to be loaded (data fetching is debounced by 250ms after creation or typing) wait_for_network_idle if using_cuprite? && wait_for_fetched_options - expect(element).to have_no_css(".ng-spinner-loader") + expect(element).to have_no_css('.ng-spinner-loader') # Insert the text to find within(element) do @@ -18,7 +18,7 @@ def search_autocomplete(element, query:, results_selector: nil, wait_dropdown_op end # Wait for options to be refreshed after having entered some text. - expect(element).to have_no_css(".ng-spinner-loader") + expect(element).to have_no_css('.ng-spinner-loader') # probably not necessary anymore sleep(0.5) unless using_cuprite? @@ -32,11 +32,11 @@ def search_autocomplete(element, query:, results_selector: nil, wait_dropdown_op def ng_find_dropdown(element, results_selector: nil) retry_block do if results_selector - results_selector = "#{results_selector} .ng-dropdown-panel" if results_selector == "body" + results_selector = "#{results_selector} .ng-dropdown-panel" if results_selector == 'body' page.find(results_selector) else within(element) do - page.find("ng-select .ng-dropdown-panel") + page.find('ng-select .ng-dropdown-panel') end end rescue StandardError => e @@ -47,20 +47,20 @@ def ng_find_dropdown(element, results_selector: nil) def expect_ng_option(element, option, results_selector: nil, present: true) within(ng_find_dropdown(element, results_selector:)) do - expect(page).to have_conditional_selector(present, ".ng-option", text: option) + expect(page).to have_conditional_selector(present, '.ng-option', text: option) end end def expect_no_ng_option(element, option, results_selector: nil) within(ng_find_dropdown(element, results_selector:)) do - expect(page).to have_no_css(".ng-option", text: option) + expect(page).to have_no_css('.ng-option', text: option) end end ## # Insert the query, typing def ng_enter_query(element, query, wait_for_fetched_options: true) - input = element.find("input[type=text]", visible: :all).native + input = element.find('input[type=text]', visible: :all).native if using_cuprite? clear_input_field_contents(input) else @@ -89,13 +89,13 @@ def ng_enter_query(element, query, wait_for_fetched_options: true) ## # Get the ng_select input element def ng_select_input(from_element = page) - from_element.find(".ng-input input") + from_element.find('.ng-input input') end ## # clear the ng select field def ng_select_clear(from_element) - from_element.find(".ng-clear-wrapper", visible: :all).click + from_element.find('.ng-clear-wrapper', visible: :all).click end def select_autocomplete(element, @@ -116,7 +116,7 @@ def select_autocomplete(element, text = select_text.presence || query # click the element to select it - target_dropdown.find(".ng-option", text:, match: :first, wait: 15).click + target_dropdown.find('.ng-option', text:, match: :first, wait: 15).click end end end diff --git a/spec/support/components/common/sidemenu.rb b/spec/support/components/common/sidemenu.rb index fcaacd5c40df..7a0be6b48ecd 100644 --- a/spec/support/components/common/sidemenu.rb +++ b/spec/support/components/common/sidemenu.rb @@ -67,11 +67,11 @@ def finished_loading private def expect_count(count) - expect(page).to have_css(".op-bubble", text: count) + expect(page).to have_css('.op-bubble', text: count) end def expect_no_count - expect(page).to have_no_css(".op-bubble") + expect(page).to have_no_css('.op-bubble') end def item_action_selector(item) diff --git a/spec/support/components/confirmation_dialog.rb b/spec/support/components/confirmation_dialog.rb index 7dfadb27a04a..cfa2e000fec7 100644 --- a/spec/support/components/confirmation_dialog.rb +++ b/spec/support/components/confirmation_dialog.rb @@ -33,7 +33,7 @@ class ConfirmationDialog include RSpec::Matchers def container - ".spot-modal" + '.spot-modal' end def expect_open diff --git a/spec/support/components/datepicker/basic_datepicker.rb b/spec/support/components/datepicker/basic_datepicker.rb index 08198fccd8b1..fcdbe2ab42a8 100644 --- a/spec/support/components/datepicker/basic_datepicker.rb +++ b/spec/support/components/datepicker/basic_datepicker.rb @@ -1,4 +1,4 @@ -require_relative "datepicker" +require_relative 'datepicker' module Components class BasicDatepicker < Datepicker @@ -16,7 +16,7 @@ def self.update_field(trigger, date) end date = Date.parse(date) unless date.is_a?(Date) - datepicker.set_date(date.strftime("%Y-%m-%d")) + datepicker.set_date(date.strftime('%Y-%m-%d')) end def flatpickr_container diff --git a/spec/support/components/datepicker/datepicker.rb b/spec/support/components/datepicker/datepicker.rb index f16a4de86abd..d075465ec01f 100644 --- a/spec/support/components/datepicker/datepicker.rb +++ b/spec/support/components/datepicker/datepicker.rb @@ -19,12 +19,12 @@ def self.update_field(trigger, date) end date = Date.parse(date) unless date.is_a?(Date) - datepicker.set_date(date.strftime("%Y-%m-%d")) + datepicker.set_date(date.strftime('%Y-%m-%d')) datepicker.expect_current_date(date) datepicker.save! end - def initialize(context = "body") + def initialize(context = 'body') @context_selector = context end @@ -39,16 +39,16 @@ def flatpickr_container ## # Clear all values def clear! - set_field(container.find_field("startDate"), "", wait_for_changes_to_be_applied: false) - set_field(container.find_field("endDate"), "", wait_for_changes_to_be_applied: false) + set_field(container.find_field('startDate'), '', wait_for_changes_to_be_applied: false) + set_field(container.find_field('endDate'), '', wait_for_changes_to_be_applied: false) end def expect_visible - expect(container).to have_css(".flatpickr-calendar .flatpickr-current-month", wait: 10) + expect(container).to have_css('.flatpickr-calendar .flatpickr-current-month', wait: 10) end def expect_not_visible - expect(container).to have_no_css(".flatpickr-calendar .flatpickr-current-month", wait: 10) + expect(container).to have_no_css('.flatpickr-calendar .flatpickr-current-month', wait: 10) end ## @@ -56,7 +56,7 @@ def expect_not_visible def select_year(value) retry_block do flatpickr_container - .first(".numInput.cur-year") + .first('.numInput.cur-year') .set value end end @@ -67,7 +67,7 @@ def select_month(month) month_name = month.is_a?(Integer) ? I18n.t("date.month_names")[month] : month flatpickr_container - .first(".flatpickr-monthDropdown-months option", text: month_name, visible: :all) + .first('.flatpickr-monthDropdown-months option', text: month_name, visible: :all) .select_option end @@ -82,7 +82,7 @@ def select_day(value) retry_block do flatpickr_container - .first(".flatpickr-days .flatpickr-day:not(.nextMonthDay):not(.prevMonthDay)", + .first('.flatpickr-days .flatpickr-day:not(.nextMonthDay):not(.prevMonthDay)', text: value) .click end @@ -117,20 +117,20 @@ def expect_month(month) month = Date::MONTHNAMES.index(month) if month.is_a?(String) # Month is 0-index in select - field = flatpickr_container.find(".flatpickr-monthDropdown-months") + field = flatpickr_container.find('.flatpickr-monthDropdown-months') expect(field.value.to_i).to eq(month - 1) end ## # Expect the selected day def expect_day(value) - expect(flatpickr_container).to have_css(".flatpickr-day.selected", text: value) + expect(flatpickr_container).to have_css('.flatpickr-day.selected', text: value) end ## # Expect the selected year def expect_year(value) - expect(flatpickr_container).to have_css(".cur-year") { |field| + expect(flatpickr_container).to have_css('.cur-year') { |field| field.value.to_i == value.to_i } end @@ -149,7 +149,7 @@ def expect_current_date(date) ## # Expect the given date to be non working def expect_non_working(date) - label = date.strftime("%B %-d, %Y") + label = date.strftime('%B %-d, %Y') expect(page).to have_css(".flatpickr-day.flatpickr-non-working-day[aria-label='#{label}']", wait: 20) end @@ -157,7 +157,7 @@ def expect_non_working(date) ## # Expect the given date to be non working def expect_working(date) - label = date.strftime("%B %-d, %Y") + label = date.strftime('%B %-d, %Y') expect(page).to have_css(".flatpickr-day:not(.flatpickr-non-working-day)[aria-label='#{label}']", wait: 20) end @@ -165,7 +165,7 @@ def expect_working(date) ## # Expect the given date to be non working def expect_disabled(date) - label = date.strftime("%B %-d, %Y") + label = date.strftime('%B %-d, %Y') expect(page).to have_css(".flatpickr-day.flatpickr-disabled[aria-label='#{label}']", wait: 20) end @@ -173,7 +173,7 @@ def expect_disabled(date) ## # Expect the given date to be non working def expect_not_disabled(date) - label = date.strftime("%B %-d, %Y") + label = date.strftime('%B %-d, %Y') expect(page).to have_css(".flatpickr-day:not(.flatpickr-disabled)[aria-label='#{label}']", wait: 20) end diff --git a/spec/support/components/datepicker/month_range_selection.rb b/spec/support/components/datepicker/month_range_selection.rb index daa817a0494b..3843e1bc88e8 100644 --- a/spec/support/components/datepicker/month_range_selection.rb +++ b/spec/support/components/datepicker/month_range_selection.rb @@ -6,22 +6,22 @@ def select_month(month) month = Date::MONTHNAMES.index(month) if month.is_a?(String) retry_block do # This is for a double-month datepicker - current_month_element = flatpickr_container.all(".cur-month", wait: 0).first + current_month_element = flatpickr_container.all('.cur-month', wait: 0).first current_month = if current_month_element Date::MONTHNAMES.index(current_month_element.text) else # This is for a single-month datepicker - flatpickr_container.first(".flatpickr-monthDropdown-months").value.to_i + 1 + flatpickr_container.first('.flatpickr-monthDropdown-months').value.to_i + 1 end if current_month < month month_difference = month - current_month - month_difference.times { flatpickr_container.find(".flatpickr-next-month").click } - flatpickr_container.first(".flatpickr-monthDropdown-months").value.to_i + 1 + month_difference.times { flatpickr_container.find('.flatpickr-next-month').click } + flatpickr_container.first('.flatpickr-monthDropdown-months').value.to_i + 1 elsif current_month > month month_difference = current_month - month - month_difference.times { flatpickr_container.find(".flatpickr-prev-month").click } - flatpickr_container.first(".flatpickr-monthDropdown-months").value.to_i + 1 + month_difference.times { flatpickr_container.find('.flatpickr-prev-month').click } + flatpickr_container.first('.flatpickr-monthDropdown-months').value.to_i + 1 end end end diff --git a/spec/support/components/datepicker/range_datepicker.rb b/spec/support/components/datepicker/range_datepicker.rb index 98dbc0668c5d..c3d4698218fd 100644 --- a/spec/support/components/datepicker/range_datepicker.rb +++ b/spec/support/components/datepicker/range_datepicker.rb @@ -1,4 +1,4 @@ -require_relative "basic_datepicker" +require_relative 'basic_datepicker' module Components class RangeDatepicker < BasicDatepicker diff --git a/spec/support/components/datepicker/work_package_datepicker.rb b/spec/support/components/datepicker/work_package_datepicker.rb index be15ddb1279a..7dae71dc6348 100644 --- a/spec/support/components/datepicker/work_package_datepicker.rb +++ b/spec/support/components/datepicker/work_package_datepicker.rb @@ -1,4 +1,4 @@ -require_relative "datepicker" +require_relative 'datepicker' module Components class WorkPackageDatepicker < Datepicker @@ -7,13 +7,13 @@ class WorkPackageDatepicker < Datepicker def clear! super - set_field(duration_field, "", wait_for_changes_to_be_applied: false) + set_field(duration_field, '', wait_for_changes_to_be_applied: false) end ## # Expect the selected month def expect_month(month) - field = flatpickr_container.first(".cur-month") + field = flatpickr_container.first('.cur-month') expect(field.text).to eq(month) end @@ -23,25 +23,25 @@ def expect_duration(value) value = if value.is_a?(Regexp) value - elsif value.nil? || value == "" - "" + elsif value.nil? || value == '' + '' else - I18n.t("js.units.day", count: value) + I18n.t('js.units.day', count: value) end - expect(container).to have_field("duration", with: value, wait: 10) + expect(container).to have_field('duration', with: value, wait: 10) end def milestone_date_field - container.find_field "date" + container.find_field 'date' end def start_date_field - container.find_field "startDate" + container.find_field 'startDate' end def due_date_field - container.find_field "endDate" + container.find_field 'endDate' end def focus_milestone_date @@ -59,19 +59,19 @@ def focus_due_date ## # Expect date (milestone type) def expect_milestone_date(value) - expect(container).to have_field("date", with: value, wait: 20) + expect(container).to have_field('date', with: value, wait: 20) end ## # Expect start date def expect_start_date(value) - expect(container).to have_field("startDate", with: value, wait: 20) + expect(container).to have_field('startDate', with: value, wait: 20) end ## # Expect due date def expect_due_date(value) - expect(container).to have_field("endDate", with: value, wait: 20) + expect(container).to have_field('endDate', with: value, wait: 20) end def set_milestone_date(value) @@ -95,7 +95,7 @@ def expect_due_highlighted end def duration_field - container.find_field "duration" + container.find_field 'duration' end def focus_duration @@ -105,14 +105,14 @@ def focus_duration def set_today(date) key = case date.to_s - when "due" - "end" + when 'due' + 'end' else date end page.within("[data-test-selector='datepicker-#{key}-date']") do - find("button", text: "Today").click + find('button', text: 'Today').click end end @@ -133,46 +133,46 @@ def expect_duration_highlighted def expect_scheduling_mode(manually) if manually - expect(container).to have_checked_field("scheduling", visible: :all) + expect(container).to have_checked_field('scheduling', visible: :all) else - expect(container).to have_unchecked_field("scheduling", visible: :all) + expect(container).to have_unchecked_field('scheduling', visible: :all) end end def toggle_scheduling_mode - find("label", text: "Manual scheduling").click + find('label', text: 'Manual scheduling').click end def scheduling_mode_input - container.find_field "scheduling", visible: :all + container.find_field 'scheduling', visible: :all end def ignore_non_working_days_input - container.find_field "weekdays_only", visible: :all + container.find_field 'weekdays_only', visible: :all end def expect_ignore_non_working_days_disabled - expect(container).to have_field("weekdays_only", disabled: true) + expect(container).to have_field('weekdays_only', disabled: true) end def expect_ignore_non_working_days_enabled - expect(container).to have_field("weekdays_only", disabled: false) + expect(container).to have_field('weekdays_only', disabled: false) end def expect_ignore_non_working_days(val, disabled: false) if val - expect(container).to have_unchecked_field("weekdays_only", disabled:) + expect(container).to have_unchecked_field('weekdays_only', disabled:) else - expect(container).to have_checked_field("weekdays_only", disabled:) + expect(container).to have_checked_field('weekdays_only', disabled:) end end def toggle_ignore_non_working_days - find("label", text: "Working days only").click + find('label', text: 'Working days only').click end def clear_duration - set_duration("") + set_duration('') end def clear_duration_with_icon diff --git a/spec/support/components/global_search.rb b/spec/support/components/global_search.rb index e30be81b054f..e9cefdeadb20 100644 --- a/spec/support/components/global_search.rb +++ b/spec/support/components/global_search.rb @@ -5,19 +5,19 @@ class GlobalSearch include RSpec::Matchers def container - page.find(".top-menu-search--input") + page.find('.top-menu-search--input') end def selector - ".top-menu-search--input" + '.top-menu-search--input' end def input - container.find "input" + container.find 'input' end def dropdown - container.find(".ng-dropdown-panel") + container.find('.ng-dropdown-panel') end def click_input @@ -27,7 +27,7 @@ def click_input def search(query, submit: false) SeleniumHubWaiter.wait - input.set "" + input.set '' click_input input.set query @@ -69,22 +69,22 @@ def expect_in_project_and_subproject_scope_marked def expect_scope(text) expect(page) - .to have_css(".global-search--project-scope", text:, wait: 10) + .to have_css('.global-search--project-scope', text:, wait: 10) end def expect_work_package_marked(wp) expect(page) - .to have_css(".ng-option-marked", text: wp.subject.to_s, wait: 10) + .to have_css('.ng-option-marked', text: wp.subject.to_s, wait: 10) end def expect_work_package_option(wp) expect(page) - .to have_css(".global-search--option", text: wp.subject.to_s, wait: 10) + .to have_css('.global-search--option', text: wp.subject.to_s, wait: 10) end def expect_no_work_package_option(wp) expect(page) - .to have_no_css(".global-search--option", text: wp.subject.to_s) + .to have_no_css('.global-search--option', text: wp.subject.to_s) end def click_work_package(wp) @@ -96,8 +96,8 @@ def find_work_package(wp) end def find_option(text) - expect(page).to have_css(".global-search--wp-subject", text:, wait: 10) - find(".global-search--wp-subject", text:) + expect(page).to have_css('.global-search--wp-subject', text:, wait: 10) + find('.global-search--wp-subject', text:) end def cancel diff --git a/spec/support/components/grids/grid_area.rb b/spec/support/components/grids/grid_area.rb index cbdaaaa9b1bd..e779d7f0c444 100644 --- a/spec/support/components/grids/grid_area.rb +++ b/spec/support/components/grids/grid_area.rb @@ -14,12 +14,12 @@ def initialize(*selector) def resize_to(row, column) area.hover - area.find(".grid--resizer").drag_to self.class.of(row * 2, column * 2).area + area.find('.grid--resizer').drag_to self.class.of(row * 2, column * 2).area end def open_menu area.hover - area.find("icon-triggered-context-menu").click + area.find('icon-triggered-context-menu').click end def click_menu_item(text) @@ -38,17 +38,17 @@ def expect_menu_item(text) open_menu - within("ul.dropdown-menu") do |element| - expect(element).to have_css("span", text:) + within('ul.dropdown-menu') do |element| + expect(element).to have_css('span', text:) end end def remove - click_menu_item(I18n.t("js.grid.remove")) + click_menu_item(I18n.t('js.grid.remove')) end def configure_wp_table - click_menu_item(I18n.t("js.toolbar.settings.configure_view")) + click_menu_item(I18n.t('js.toolbar.settings.configure_view')) end def drag_to(row, column) @@ -75,10 +75,10 @@ def expect_to_exist end def expect_to_span(startRow, startColumn, endRow, endColumn) - [["grid-row-start", startRow * 2], - ["grid-column-start", startColumn * 2], - ["grid-row-end", (endRow * 2) - 1], - ["grid-column-end", (endColumn * 2) - 1]].each do |style, expected| + [['grid-row-start', startRow * 2], + ['grid-column-start', startColumn * 2], + ['grid-row-end', (endRow * 2) - 1], + ['grid-column-end', (endColumn * 2) - 1]].each do |style, expected| actual = area.native.style(style) expect(actual) @@ -89,7 +89,7 @@ def expect_to_span(startRow, startColumn, endRow, endColumn) def expect_not_resizable within area do expect(page) - .to have_no_css(".grid--area.-widgeted resizer") + .to have_no_css('.grid--area.-widgeted resizer') end end @@ -124,7 +124,7 @@ def area def drag_handle area.hover - area.find(".cdk-drag-handle") + area.find('.cdk-drag-handle') end def self.of(row_number, column_number) @@ -146,11 +146,11 @@ def move_to(element) end def dismiss_toaster! - if page.has_selector?(".op-toast--close") - page.find(".op-toast--close").click + if page.has_selector?('.op-toast--close') + page.find('.op-toast--close').click end - expect(page).to have_no_css(".op-toast") + expect(page).to have_no_css('.op-toast') end end end diff --git a/spec/support/components/menu/dropdown.rb b/spec/support/components/menu/dropdown.rb index e6a21fd7a0ca..95f42498c74a 100644 --- a/spec/support/components/menu/dropdown.rb +++ b/spec/support/components/menu/dropdown.rb @@ -37,15 +37,15 @@ def toggle end def expect_closed - expect(page).to have_no_css(".op-app-menu--dropdown") + expect(page).to have_no_css('.op-app-menu--dropdown') end def expect_open - expect(page).to have_css(".op-app-menu--dropdown") + expect(page).to have_css('.op-app-menu--dropdown') end def within_dropdown(&) - page.within(".op-app-menu--dropdown", &) + page.within('.op-app-menu--dropdown', &) end def trigger_element diff --git a/spec/support/components/menu/quick_add_menu.rb b/spec/support/components/menu/quick_add_menu.rb index b21ef61e4324..0524a5aee9e1 100644 --- a/spec/support/components/menu/quick_add_menu.rb +++ b/spec/support/components/menu/quick_add_menu.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "dropdown" +require_relative 'dropdown' module Components class QuickAddMenu < Dropdown @@ -38,16 +38,16 @@ def expect_invisible end def expect_add_project(present: true) - expect_link "New project", present: + expect_link 'New project', present: end def expect_user_invite(present: true) - expect_link "Invite user", present: + expect_link 'Invite user', present: end def expect_work_package_type(*names, present: true) within_dropdown do - expect(page).to have_text "WORK PACKAGES" + expect(page).to have_text 'WORK PACKAGES' end names.each do |name| @@ -57,7 +57,7 @@ def expect_work_package_type(*names, present: true) def expect_no_work_package_types within_dropdown do - expect(page).to have_no_text "Work packages" + expect(page).to have_no_text 'Work packages' end end diff --git a/spec/support/components/password_confirmation_dialog.rb b/spec/support/components/password_confirmation_dialog.rb index ff0907c0c48d..71482c8a0357 100644 --- a/spec/support/components/password_confirmation_dialog.rb +++ b/spec/support/components/password_confirmation_dialog.rb @@ -36,7 +36,7 @@ def confirm_flow_with(password, with_keyboard: false, should_fail: false) expect_open expect(submit_button).to be_disabled - fill_in "request_for_confirmation_password", with: password + fill_in 'request_for_confirmation_password', with: password expect(submit_button).not_to be_disabled submit(should_fail:, with_keyboard:) @@ -57,21 +57,21 @@ def submit_button private def selector - ".password-confirm-dialog--modal" + '.password-confirm-dialog--modal' end def submit(should_fail:, with_keyboard:) if with_keyboard - find_field("request_for_confirmation_password").send_keys :enter + find_field('request_for_confirmation_password').send_keys :enter else submit_button.click end if should_fail - expect(page).to have_css(".op-toast.-error", + expect(page).to have_css('.op-toast.-error', text: I18n.t(:notice_password_confirmation_failed)) else - expect(page).to have_no_css(".op-toast.-error") + expect(page).to have_no_css('.op-toast.-error') end end end diff --git a/spec/support/components/project_include_component.rb b/spec/support/components/project_include_component.rb index 39462cb79524..552ff1ca0fb5 100644 --- a/spec/support/components/project_include_component.rb +++ b/spec/support/components/project_include_component.rb @@ -60,7 +60,7 @@ def toggle_checkbox(project_id) def set_filter_selected(filter) within_body do - page.find("[data-test-selector='spot-toggle--option']", text: filter ? "Only selected" : "All projects").click + page.find("[data-test-selector='spot-toggle--option']", text: filter ? 'Only selected' : 'All projects').click end end @@ -94,7 +94,7 @@ def expect_closed def click_button(text) within_body do - page.find("button:not([disabled])", text:).click + page.find('button:not([disabled])', text:).click end end @@ -107,11 +107,11 @@ def body_element end def body_selector - ".spot-drop-modal-portal .spot-drop-modal--body" + '.spot-drop-modal-portal .spot-drop-modal--body' end def selector - ".op-project-include" + '.op-project-include' end def no_loading_indicator diff --git a/spec/support/components/projects/top_menu.rb b/spec/support/components/projects/top_menu.rb index 40462ab1c8cd..f8cba3c4eba9 100644 --- a/spec/support/components/projects/top_menu.rb +++ b/spec/support/components/projects/top_menu.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "support/components/autocompleter/autocomplete_helpers" +require 'support/components/autocompleter/autocomplete_helpers' module Components module Projects @@ -36,7 +36,7 @@ class TopMenu include ::Components::Autocompleter::AutocompleteHelpers def toggle - page.find_by_id("projects-menu").click + page.find_by_id('projects-menu').click wait_for_network_idle(timeout: 10) if using_cuprite? end @@ -51,7 +51,7 @@ def open? end def expect_current_project(name) - page.find_by_id("projects-menu", text: name) + page.find_by_id('projects-menu', text: name) end def expect_open @@ -67,7 +67,7 @@ def search(query) end def clear_search - autocompleter.set "" + autocompleter.set '' autocompleter.send_keys :backspace end @@ -103,12 +103,12 @@ def expect_no_result(name) end def expect_blankslate - expect(page).not_to have_test_selector("op-project-list-modal--no-results", wait: 0) + expect(page).not_to have_test_selector('op-project-list-modal--no-results', wait: 0) end def expect_item_with_hierarchy_level(hierarchy_level:, item_name:) within search_results do - hierarchy_selector = hierarchy_level.times.collect { autocompleter_item_selector }.join(" ") + hierarchy_selector = hierarchy_level.times.collect { autocompleter_item_selector }.join(' ') expect(page) .to have_css("#{hierarchy_selector} #{autocompleter_item_title_selector}", text: item_name) end diff --git a/spec/support/components/table_pagination.rb b/spec/support/components/table_pagination.rb index 5672474104d4..1906d5908674 100644 --- a/spec/support/components/table_pagination.rb +++ b/spec/support/components/table_pagination.rb @@ -35,21 +35,21 @@ class TablePagination def expect_range(from, to, total) within_pagination do expect(page) - .to have_css(".op-pagination--range", text: "(#{from} - #{to}/#{total})") + .to have_css('.op-pagination--range', text: "(#{from} - #{to}/#{total})") end end def expect_no_per_page_options within_pagination do expect(page) - .to have_no_css(".op-pagination--options") + .to have_no_css('.op-pagination--options') end end protected def within_pagination(&) - within(".op-pagination", &) + within('.op-pagination', &) end end end diff --git a/spec/support/components/timelines/configuration_modal.rb b/spec/support/components/timelines/configuration_modal.rb index 438f8ec6e133..5871db54b5b5 100644 --- a/spec/support/components/timelines/configuration_modal.rb +++ b/spec/support/components/timelines/configuration_modal.rb @@ -40,7 +40,7 @@ def initialize end def open! - @modal.open_and_switch_to "Gantt chart" + @modal.open_and_switch_to 'Gantt chart' end def get_select(position) @@ -48,18 +48,18 @@ def get_select(position) end def expect_labels!(left:, right:, farRight:) - expect(page).to have_select("modal-timelines-label-left", selected: left) - expect(page).to have_select("modal-timelines-label-right", selected: right) - expect(page).to have_select("modal-timelines-label-farRight", selected: farRight) + expect(page).to have_select('modal-timelines-label-left', selected: left) + expect(page).to have_select('modal-timelines-label-right', selected: right) + expect(page).to have_select('modal-timelines-label-farRight', selected: farRight) end def update_labels(left:, right:, farRight:) - get_select(:left).find("option", text: left).select_option - get_select(:right).find("option", text: right).select_option - get_select(:farRight).find("option", text: farRight).select_option + get_select(:left).find('option', text: left).select_option + get_select(:right).find('option', text: right).select_option + get_select(:farRight).find('option', text: farRight).select_option - page.within ".spot-modal" do - click_on "Apply" + page.within '.spot-modal' do + click_on 'Apply' end end end diff --git a/spec/support/components/timelines/timeline_row.rb b/spec/support/components/timelines/timeline_row.rb index 517dbcaefbd6..3aa050dd374a 100644 --- a/spec/support/components/timelines/timeline_row.rb +++ b/spec/support/components/timelines/timeline_row.rb @@ -40,7 +40,7 @@ def initialize(container) end def hover! - @container.find(".timeline-element").hover + @container.find('.timeline-element').hover end def expect_hovered_labels(left:, right:) @@ -93,7 +93,7 @@ def expect_hovered_bar(duration: 1) def expect_bar(duration: 1) loading_indicator_saveguard expected_length = duration * 30 - expect(container).to have_css(".timeline-element", style: { width: "#{expected_length}px" }) + expect(container).to have_css('.timeline-element', style: { width: "#{expected_length}px" }) end def expect_no_hovered_bar @@ -102,7 +102,7 @@ def expect_no_hovered_bar def expect_no_bar loading_indicator_saveguard - expect(container).to have_no_css(".timeline-element") + expect(container).to have_no_css('.timeline-element') end def drag_and_drop(offset_days: 0, days: 1) @@ -119,7 +119,7 @@ def wait_until_hoverable # The timeline element and the mouse handlers are lazily loaded and can # be hidden if no dates are set. Finding it waits until the lazy loading # has completed. - container.find(".timeline-element", visible: :all) + container.find('.timeline-element', visible: :all) end private diff --git a/spec/support/components/users/invite_user_modal.rb b/spec/support/components/users/invite_user_modal.rb index 7377de716aa8..7639a8798120 100644 --- a/spec/support/components/users/invite_user_modal.rb +++ b/spec/support/components/users/invite_user_modal.rb @@ -25,8 +25,8 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../common/modal" -require_relative "../autocompleter/ng_select_autocomplete_helpers" +require_relative '../common/modal' +require_relative '../autocompleter/ng_select_autocomplete_helpers' module Components module Users @@ -35,7 +35,7 @@ class InviteUserModal < ::Components::Common::Modal attr_accessor :project, :principal, :role, :invite_message - def initialize(project:, principal:, role:, invite_message: "Welcome!") + def initialize(project:, principal:, role:, invite_message: 'Welcome!') self.project = project self.principal = principal self.role = role @@ -57,7 +57,7 @@ def run_all_steps(skip_project_autocomplete: false) confirmation_step # Step 4: Perform invite - click_modal_button "Send invitation" + click_modal_button 'Send invitation' expect_text "#{principal_name} was invited!" @@ -76,24 +76,24 @@ def run_all_steps(skip_project_autocomplete: false) expect_text text # Close - click_modal_button "Continue" + click_modal_button 'Continue' expect_closed end def project_step(next_step: true, skip_autocomplete: false) - expect_title "Invite user" - autocomplete ".ng-select-container", project.name unless skip_autocomplete + expect_title 'Invite user' + autocomplete '.ng-select-container', project.name unless skip_autocomplete select_type type click_next if next_step end - def open_select_in_step(selector, query = "") + def open_select_in_step(selector, query = '') select_field = modal_element.find(selector) search_autocomplete select_field, query:, - results_selector: "body" + results_selector: 'body' end def principal_step(next_step: true) @@ -102,22 +102,22 @@ def principal_step(next_step: true) autocomplete "op-ium-principal-search", principal_name, select_text: "Invite: #{principal_name}" end else - autocomplete "op-ium-principal-search", principal_name + autocomplete 'op-ium-principal-search', principal_name end - autocomplete "op-ium-role-search", role.name + autocomplete 'op-ium-role-search', role.name invitation_message invite_message unless placeholder? click_next if next_step end def role_step(next_step: true) - autocomplete "op-ium-role-search", role.name + autocomplete 'op-ium-role-search', role.name click_next if next_step end def invitation_step(next_step: true) invitation_message invite_message - click_modal_button "Review invitation" if next_step + click_modal_button 'Review invitation' if next_step end def confirmation_step @@ -135,23 +135,23 @@ def autocomplete(selector, query, select_text: query) select_autocomplete select_field, query:, select_text:, - results_selector: "body" + results_selector: 'body' end def select_type(type) within_modal do - page.find(".op-option-list--item", text: type).click + page.find('.op-option-list--item', text: type).click end end def click_next - click_modal_button "Next" + click_modal_button 'Next' wait_for_reload end def invitation_message(text) within_modal do - find("textarea").set text + find('textarea').set text end end @@ -178,7 +178,7 @@ def type def expect_error_displayed(message) within_modal do expect(page) - .to have_css(".spot-form-field--error", text: message) + .to have_css('.spot-form-field--error', text: message) end end diff --git a/spec/support/components/work_packages/activities.rb b/spec/support/components/work_packages/activities.rb index 0757b07b1da0..0b6bb814d271 100644 --- a/spec/support/components/work_packages/activities.rb +++ b/spec/support/components/work_packages/activities.rb @@ -37,7 +37,7 @@ class Activities def initialize(work_package) @work_package = work_package - @container = ".work-package-details-activities-list" + @container = '.work-package-details-activities-list' end def expect_wp_has_been_created_activity(work_package) diff --git a/spec/support/components/work_packages/baseline.rb b/spec/support/components/work_packages/baseline.rb index e050b91cd1dc..bebb55984025 100644 --- a/spec/support/components/work_packages/baseline.rb +++ b/spec/support/components/work_packages/baseline.rb @@ -34,30 +34,30 @@ class Baseline include RSpec::Matchers def expect_active - expect(page).to have_css(".wp-table--baseline-th") + expect(page).to have_css('.wp-table--baseline-th') end def expect_legends - expect(page).to have_css(".op-baseline-legends") + expect(page).to have_css('.op-baseline-legends') end def expect_legend_text(text) - expect(page).to have_css(".op-baseline-legends--filter", text:) + expect(page).to have_css('.op-baseline-legends--filter', text:) end def expect_legend_tooltip(text) expect(page).to have_css('[data-test-selector="baseline-legend-time-offset"]', visible: :all) { |node| - node["title"] == text + node['title'] == text } end def expect_no_legends - expect(page).to have_no_css(".op-baseline-legends") + expect(page).to have_no_css('.op-baseline-legends') end def expect_inactive - expect(page).to have_no_css(".wp-table--baseline-th") - expect(page).to have_no_css(".op-table-baseline--column-cell") + expect(page).to have_no_css('.wp-table--baseline-th') + expect(page).to have_no_css('.op-table-baseline--column-cell') end def expect_changed(work_package) @@ -90,8 +90,8 @@ def expect_changed_attributes(work_package, **changes) base_selector = ".op-table-baseline--container.#{attribute}" expect(page).to have_css("#{base_selector} .op-table-baseline--old-field", text: old_value) - if new_value == "" - expect(page).to have_css("#{base_selector} .op-table-baseline--new-field", text: "", visible: :all) + if new_value == '' + expect(page).to have_css("#{base_selector} .op-table-baseline--new-field", text: '', visible: :all) else expect(page).to have_css("#{base_selector} .op-table-baseline--new-field", text: new_value) end diff --git a/spec/support/components/work_packages/baseline_modal.rb b/spec/support/components/work_packages/baseline_modal.rb index ae8acf155840..441ca4f171a5 100644 --- a/spec/support/components/work_packages/baseline_modal.rb +++ b/spec/support/components/work_packages/baseline_modal.rb @@ -38,40 +38,40 @@ def toggle_drop_modal end def expect_closed - expect(page).to have_no_css("op-baseline") + expect(page).to have_no_css('op-baseline') end def expect_open - expect(page).to have_css("op-baseline") - expect(page).to have_field("op-baseline-filter") + expect(page).to have_css('op-baseline') + expect(page).to have_field('op-baseline-filter') end def expect_selected(option) - expect(page).to have_select("op-baseline-filter", selected: option) + expect(page).to have_select('op-baseline-filter', selected: option) end def expect_selected_time(value) - expect(page).to have_field("op-baseline-time", with: value) + expect(page).to have_field('op-baseline-time', with: value) end def expect_no_time_field - expect(page).to have_no_field("op-baseline-time") + expect(page).to have_no_field('op-baseline-time') end def select_filter(option) - page.select(option, from: "op-baseline-filter") + page.select(option, from: 'op-baseline-filter') expect_selected(option) end def expect_offset(value, count: 1) - expect(page).to have_css(".op-baseline--time-help", text: value, count:) + expect(page).to have_css('.op-baseline--time-help', text: value, count:) end def expect_time_help_text(text) - expect(page).to have_css(".spot-form-field--description", text:) + expect(page).to have_css('.spot-form-field--description', text:) end - def set_time(value, selector = "op-baseline-time") + def set_time(value, selector = 'op-baseline-time') page.execute_script <<~JS const el = document.getElementsByName('#{selector}')[0]; el.value = '#{value}'; @@ -80,29 +80,29 @@ def set_time(value, selector = "op-baseline-time") end def set_date(value) - fill_in "op-baseline-date", with: value + fill_in 'op-baseline-date', with: value end def set_between_dates(from:, from_time:, to:, to_time:) - fill_in "op-baseline-from-date", with: from + fill_in 'op-baseline-from-date', with: from sleep 0.5 - fill_in "op-baseline-to-date", with: to + fill_in 'op-baseline-to-date', with: to - set_time from_time, "op-baseline-from-time" - set_time to_time, "op-baseline-to-time" + set_time from_time, 'op-baseline-from-time' + set_time to_time, 'op-baseline-to-time' end def expect_between_dates(from:, from_time:, to:, to_time:) - expect(page).to have_field("op-baseline-from-time", with: from_time) - expect(page).to have_field("op-baseline-to-time", with: to_time) + expect(page).to have_field('op-baseline-from-time', with: from_time) + expect(page).to have_field('op-baseline-to-time', with: to_time) - expect(page).to have_field("op-baseline-from-date", with: from) - expect(page).to have_field("op-baseline-to-date", with: to) + expect(page).to have_field('op-baseline-from-date', with: from) + expect(page).to have_field('op-baseline-to-date', with: to) end def apply - page.within("op-baseline") do - click_button "Apply" + page.within('op-baseline') do + click_button 'Apply' end end end diff --git a/spec/support/components/work_packages/columns.rb b/spec/support/components/work_packages/columns.rb index 7a75b4863ed6..4d53d63f90a6 100644 --- a/spec/support/components/work_packages/columns.rb +++ b/spec/support/components/work_packages/columns.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../autocompleter/ng_select_autocomplete_helpers" +require_relative '../autocompleter/ng_select_autocomplete_helpers' module Components module WorkPackages @@ -43,22 +43,22 @@ def initialize(trigger_parent = nil) end def column_autocompleter - find(".columns-modal--content .op-draggable-autocomplete--input") + find('.columns-modal--content .op-draggable-autocomplete--input') end def close_autocompleter - find(".columns-modal--content .op-draggable-autocomplete--input input").send_keys :escape + find('.columns-modal--content .op-draggable-autocomplete--input input').send_keys :escape end def column_item(name) - find(".op-draggable-autocomplete--item", text: name) + find('.op-draggable-autocomplete--item', text: name) end def expect_column_not_available(name) modal_open? or open_modal column_autocompleter.click - expect(page).to have_no_css(".ng-option", text: name, visible: :all) + expect(page).to have_no_css('.ng-option', text: name, visible: :all) close_autocompleter end @@ -66,19 +66,19 @@ def expect_column_available(name) modal_open? or open_modal column_autocompleter.click - expect(page).to have_css(".ng-option", text: name, visible: :all) + expect(page).to have_css('.ng-option', text: name, visible: :all) close_autocompleter end def expect_alternative_available_column(search_term, displayed_name) column_autocompleter.click - autocompleter_input = column_autocompleter.find("input") + autocompleter_input = column_autocompleter.find('input') autocompleter_input.set(search_term) expect(page) - .to have_css(".ng-dropdown-panel .ng-option-label", text: displayed_name) + .to have_css('.ng-dropdown-panel .ng-option-label', text: displayed_name) autocompleter_input.set(search_term) end @@ -87,7 +87,7 @@ def add(name, save_changes: true) open_modal unless modal_open? select_autocomplete column_autocompleter, - results_selector: ".ng-dropdown-panel-items", + results_selector: '.ng-dropdown-panel-items', query: name if save_changes @@ -103,7 +103,7 @@ def remove(name, save_changes: true) within_modal do container = column_item(name) - container.find(".op-draggable-autocomplete--remove-item").click + container.find('.op-draggable-autocomplete--remove-item').click end apply if save_changes @@ -111,13 +111,13 @@ def remove(name, save_changes: true) def expect_checked(name) within_modal do - expect(page).to have_css(".op-draggable-autocomplete--item", text: name) + expect(page).to have_css('.op-draggable-autocomplete--item', text: name) end end def expect_unchecked(name) within_modal do - expect(page).to have_no_css(".op-draggable-autocomplete--item", text: name) + expect(page).to have_no_css('.op-draggable-autocomplete--item', text: name) end end @@ -125,8 +125,8 @@ def uncheck_all(save_changes: true) open_modal unless modal_open? within_modal do - expect(page).to have_css(".op-draggable-autocomplete--item", minimum: 1) - page.all(".op-draggable-autocomplete--remove-item").each(&:click) + expect(page).to have_css('.op-draggable-autocomplete--item', minimum: 1) + page.all('.op-draggable-autocomplete--remove-item').each(&:click) end apply if save_changes @@ -135,12 +135,12 @@ def uncheck_all(save_changes: true) def apply @opened = false - click_button("Apply") + click_button('Apply') end def open_modal @opened = true - ::Components::WorkPackages::TableConfigurationModal.new(trigger_parent).open_and_switch_to "Columns" + ::Components::WorkPackages::TableConfigurationModal.new(trigger_parent).open_and_switch_to 'Columns' end def assume_opened @@ -150,7 +150,7 @@ def assume_opened private def within_modal(&) - page.within(".wp-table--configuration-modal", &) + page.within('.wp-table--configuration-modal', &) end def modal_open? diff --git a/spec/support/components/work_packages/context_menu.rb b/spec/support/components/work_packages/context_menu.rb index b6a498c3ef83..242533dd7fe5 100644 --- a/spec/support/components/work_packages/context_menu.rb +++ b/spec/support/components/work_packages/context_menu.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../../toasts/expectations" +require_relative '../../toasts/expectations' module Components module WorkPackages @@ -38,7 +38,7 @@ class ContextMenu def open_for(work_package, card_view: nil) # Close - find("body").send_keys :escape + find('body').send_keys :escape sleep 0.5 unless using_cuprite? if card_view @@ -65,10 +65,10 @@ def choose(target) end def choose_delete_and_confirm_deletion - choose "Delete" + choose 'Delete' # only handle the case where the modal does _not_ ask for descendants deletion confirmation - within_modal(I18n.t("js.modals.destroy_work_package.title", label: "work package")) do - click_button "Delete" + within_modal(I18n.t('js.modals.destroy_work_package.title', label: 'work package')) do + click_button 'Delete' end expect_and_dismiss_toaster end @@ -98,7 +98,7 @@ def within_menu(&) end def work_package_context_menu_label - I18n.t("js.label_work_package_context_menu") + I18n.t('js.label_work_package_context_menu') end end end diff --git a/spec/support/components/work_packages/destroy_modal.rb b/spec/support/components/work_packages/destroy_modal.rb index 0da93290f8d9..26849110f5c1 100644 --- a/spec/support/components/work_packages/destroy_modal.rb +++ b/spec/support/components/work_packages/destroy_modal.rb @@ -34,19 +34,19 @@ class DestroyModal include RSpec::Matchers def container - "#wp_destroy_modal" + '#wp_destroy_modal' end def expect_listed(*wps) page.within(container) do if wps.length == 1 wp = wps.first - expect(page).to have_css("strong", text: "#{wp.subject} ##{wp.id}") + expect(page).to have_css('strong', text: "#{wp.subject} ##{wp.id}") else - expect(page).to have_css(".danger-zone--warning", - text: "Are you sure you want to delete the following work packages?") + expect(page).to have_css('.danger-zone--warning', + text: 'Are you sure you want to delete the following work packages?') wps.each do |wp| - expect(page).to have_css("li", text: "##{wp.id} #{wp.subject}") + expect(page).to have_css('li', text: "##{wp.id} #{wp.subject}") end end end @@ -54,19 +54,19 @@ def expect_listed(*wps) def confirm_children_deletion page.within(container) do - check "confirm-children-deletion" + check 'confirm-children-deletion' end end def confirm_deletion page.within(container) do - click_button "Delete" + click_button 'Delete' end end def cancel_deletion page.within(container) do - click_button "Cancel" + click_button 'Cancel' end end end diff --git a/spec/support/components/work_packages/filters.rb b/spec/support/components/work_packages/filters.rb index cd9ea1a520cd..4a0506326940 100644 --- a/spec/support/components/work_packages/filters.rb +++ b/spec/support/components/work_packages/filters.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../../shared/selenium_workarounds" -require_relative "../autocompleter/ng_select_autocomplete_helpers" +require_relative '../../shared/selenium_workarounds' +require_relative '../autocompleter/ng_select_autocomplete_helpers' module Components module WorkPackages @@ -54,7 +54,7 @@ def open! end def expect_filter_count(num) - expect(filter_button).to have_css(".badge", text: num, wait: 10) + expect(filter_button).to have_css('.badge', text: num, wait: 10) end def expect_open @@ -66,11 +66,11 @@ def expect_closed end def expect_quick_filter(text) - expect(page).to have_field("filter-by-text-input", with: text) + expect(page).to have_field('filter-by-text-input', with: text) end def quick_filter(text) - input = page.find_by_id("filter-by-text-input") + input = page.find_by_id('filter-by-text-input') input.hover input.click SeleniumHubWaiter.wait @@ -78,7 +78,7 @@ def quick_filter(text) end def open_available_filter_list - input = page.find(".advanced-filters--add-filter-value input") + input = page.find('.advanced-filters--add-filter-value input') input.hover input.click end @@ -88,38 +88,38 @@ def expect_available_filter(name, present: true) # some filter options will not be rendered, thus the specs fail falsely. # We narrow the filter list by searching for the filter, thus we can be sure the # the option we are looking for is rendered. - input = page.find(".advanced-filters--add-filter-value input") + input = page.find('.advanced-filters--add-filter-value input') input.set name # The selector here is rather unspecific. Sometimes, we need ng-select to render the options outside of the # current element tree. However this means that the selector loses all feature specificity, as it's rendered # somewhere in the html body. This test assumes that only one ng-select can be opened at one time. # If you find errors with your specs related to the filter options, it might be coming from here. - expect(page).to have_conditional_selector(present, ".ng-dropdown-panel .ng-option-label", text: name) + expect(page).to have_conditional_selector(present, '.ng-dropdown-panel .ng-option-label', text: name) # Reset the filter search input input.set "" end def expect_alternative_available_filter(search_term, displayed_name) - input = page.find(".advanced-filters--add-filter-value input") + input = page.find('.advanced-filters--add-filter-value input') input.set(search_term) expect(page) - .to have_css(".ng-dropdown-panel .ng-option-label", text: displayed_name) + .to have_css('.ng-dropdown-panel .ng-option-label', text: displayed_name) - input.set("") + input.set('') end def expect_loaded SeleniumHubWaiter.wait - expect(filter_button).to have_css(".badge", wait: 2, visible: :all) + expect(filter_button).to have_css('.badge', wait: 2, visible: :all) end def add_filter(name) - select_autocomplete page.find(".advanced-filters--add-filter-value"), + select_autocomplete page.find('.advanced-filters--add-filter-value'), query: name, - results_selector: ".ng-dropdown-panel-items" + results_selector: '.ng-dropdown-panel-items' end def add_filter_by(name, operator, value, selector = nil) @@ -149,12 +149,12 @@ def set_filter(name, operator, value, selector = nil) end def expect_missing_filter(name) - target_dropdown = search_autocomplete(page.find(".advanced-filters--add-filter-value"), + target_dropdown = search_autocomplete(page.find('.advanced-filters--add-filter-value'), query: name, - results_selector: ".ng-dropdown-panel-items") + results_selector: '.ng-dropdown-panel-items') within target_dropdown do - expect(page).to have_no_css(".ng-option", text: name) + expect(page).to have_no_css('.ng-option', text: name) end end @@ -245,11 +245,11 @@ def filter_button end def button_selector - "#work-packages-filter-toggle-button" + '#work-packages-filter-toggle-button' end def filters_selector - ".work-packages--filters-optional-container" + '.work-packages--filters-optional-container' end def set_value(id, value, operator) @@ -258,7 +258,7 @@ def set_value(id, value, operator) filter_element = page.find("#filter_#{id}") if filter_element.has_selector?("[data-test-selector='op-basic-range-date-picker']", wait: false) insert_date_range(filter_element, value) - elsif operator == "between" + elsif operator == 'between' insert_two_single_dates(id, value) elsif filter_element.has_selector?(".ng-select-container", wait: false) insert_autocomplete_item(filter_element, value) @@ -272,13 +272,13 @@ def insert_autocomplete_item(filter_element, value) Array(value).each do |val| select_autocomplete filter_element.find("ng-select"), query: val, - results_selector: ".ng-dropdown-panel-items" + results_selector: '.ng-dropdown-panel-items' end end def insert_plain_value(id, value) within_values(id) do - page.all("input").each_with_index do |input, index| + page.all('input').each_with_index do |input, index| # Wait a bit to insert the values ensure_value_is_input_correctly input, value: value[index] end @@ -295,7 +295,7 @@ def insert_two_single_dates(id, value) def insert_date_range(filter_element, value) date_input = filter_element.find("[data-test-selector='op-basic-range-date-picker']") - ensure_value_is_input_correctly date_input, value: Array(value).join(" - ") + ensure_value_is_input_correctly date_input, value: Array(value).join(' - ') end def autocomplete_dropdown_value(id:, value:, present: true) @@ -305,8 +305,8 @@ def autocomplete_dropdown_value(id:, value:, present: true) Array(value).each do |val| dropdown = search_autocomplete filter_element.find("ng-select"), query: val, - results_selector: ".ng-dropdown-panel-items" - expect(dropdown).to have_conditional_selector(present, ".ng-option", text: val) + results_selector: '.ng-dropdown-panel-items' + expect(dropdown).to have_conditional_selector(present, '.ng-option', text: val) end end end @@ -314,7 +314,7 @@ def autocomplete_dropdown_value(id:, value:, present: true) def expect_value_placeholder(id) filter_element = page.find("#filter_#{id}") if filter_element.has_selector?(".ng-select-container", wait: false) - expect(filter_element).to have_css(".ng-placeholder", text: I18n.t("js.placeholders.selection")) + expect(filter_element).to have_css(".ng-placeholder", text: I18n.t('js.placeholders.selection')) else raise "Non ng-select may not have placeholders currently" end @@ -338,7 +338,7 @@ def expect_value(id, value) input = page.find("#filter_#{id} [data-test-selector='op-basic-range-date-picker']") expect(input.value).to eql(expected_value) else - page.all("input").each_with_index do |input, index| + page.all('input').each_with_index do |input, index| expect(input.value).to eql(value[index]) end end @@ -347,7 +347,7 @@ def expect_value(id, value) def within_values(id) page.within("#filter_#{id} .advanced-filters--filter-value", wait: 10) do - yield page.has_selector?(".ng-select-container", wait: false) + yield page.has_selector?('.ng-select-container', wait: false) end end end diff --git a/spec/support/components/work_packages/group_by.rb b/spec/support/components/work_packages/group_by.rb index 02f279629e68..eed434451757 100644 --- a/spec/support/components/work_packages/group_by.rb +++ b/spec/support/components/work_packages/group_by.rb @@ -37,22 +37,22 @@ def enable_via_header(name) open_table_column_context_menu(name) within_column_context_menu do - click_button("Group by") + click_button('Group by') end end def enable - set_display_mode("grouped") + set_display_mode('grouped') end def enable_via_menu(name) - set_display_mode("grouped") do - select name, from: "selected_grouping" + set_display_mode('grouped') do + select name, from: 'selected_grouping' end end def disable_via_menu - set_display_mode("default") + set_display_mode('default') end def expect_number_of_groups(count) @@ -71,7 +71,7 @@ def expect_not_grouped_by(name) open_table_column_context_menu(name) within_column_context_menu do - expect(page).to have_content("Group by") + expect(page).to have_content('Group by') end end @@ -90,7 +90,7 @@ def open_table_column_context_menu(name) end def within_column_context_menu(&) - page.within("#column-context-menu", &) + page.within('#column-context-menu', &) end end end diff --git a/spec/support/components/work_packages/hierarchies.rb b/spec/support/components/work_packages/hierarchies.rb index 627574f7428e..59bbe02d72b7 100644 --- a/spec/support/components/work_packages/hierarchies.rb +++ b/spec/support/components/work_packages/hierarchies.rb @@ -48,11 +48,11 @@ def enable_hierarchy alias_method :enable_via_menu, :enable_hierarchy def enable_via_header - page.find(".wp-table--table-header .icon-no-hierarchy").click + page.find('.wp-table--table-header .icon-no-hierarchy').click end def disable_via_header - page.find(".wp-table--table-header .icon-hierarchy").click + page.find('.wp-table--table-header .icon-hierarchy').click end def disable_hierarchy @@ -62,39 +62,39 @@ def disable_hierarchy end def expect_no_hierarchies - expect(page).to have_no_css(".wp-table--hierarchy-span") + expect(page).to have_no_css('.wp-table--hierarchy-span') end alias_method :expect_mode_disabled, :expect_no_hierarchies def expect_mode_enabled - expect(page).to have_css(".wp-table--table-header .icon-hierarchy") + expect(page).to have_css('.wp-table--table-header .icon-hierarchy') end def expect_mode_disabled - expect(page).to have_css(".wp-table--table-header .icon-no-hierarchy") + expect(page).to have_css('.wp-table--table-header .icon-no-hierarchy') end def expect_indent(work_package, indent: true, outdent: true, card_view: false) context_menu.open_for(work_package, card_view:) if indent - context_menu.expect_options "Indent hierarchy" + context_menu.expect_options 'Indent hierarchy' end if outdent - context_menu.expect_options "Outdent hierarchy" + context_menu.expect_options 'Outdent hierarchy' end end def indent!(work_package) context_menu.open_for work_package - context_menu.choose "Indent hierarchy" + context_menu.choose 'Indent hierarchy' end def outdent!(work_package) context_menu.open_for work_package - context_menu.choose "Outdent hierarchy" + context_menu.choose 'Outdent hierarchy' end def expect_leaf_at(*work_packages) diff --git a/spec/support/components/work_packages/query_menu.rb b/spec/support/components/work_packages/query_menu.rb index 10f541c862ba..417bcc85e626 100644 --- a/spec/support/components/work_packages/query_menu.rb +++ b/spec/support/components/work_packages/query_menu.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "support/components/autocompleter/autocomplete_helpers" +require 'support/components/autocompleter/autocomplete_helpers' module Components module WorkPackages @@ -47,15 +47,15 @@ def autocompleter end def autocompleter_results_selector - ".op-view-select--search-results" + '.op-view-select--search-results' end def autocompleter_item_selector - ".op-sidemenu--item-title" + '.op-sidemenu--item-title' end def autocompleter_selector - "#query-title-filter" + '#query-title-filter' end def click_item(name) diff --git a/spec/support/components/work_packages/query_title.rb b/spec/support/components/work_packages/query_title.rb index bc39c5e80679..9b9e5ec9cd28 100644 --- a/spec/support/components/work_packages/query_title.rb +++ b/spec/support/components/work_packages/query_title.rb @@ -34,29 +34,29 @@ class QueryTitle include RSpec::Matchers def expect_changed - expect(page).to have_css ".editable-toolbar-title--save" - expect(page).to have_css ".editable-toolbar-title--input.-changed" + expect(page).to have_css '.editable-toolbar-title--save' + expect(page).to have_css '.editable-toolbar-title--input.-changed' end def expect_not_changed - expect(page).to have_no_css ".editable-toolbar-title--save" - expect(page).to have_no_css ".editable-toolbar-title--input.-changed" + expect(page).to have_no_css '.editable-toolbar-title--save' + expect(page).to have_no_css '.editable-toolbar-title--input.-changed' end def input_field - find(".editable-toolbar-title--input") + find('.editable-toolbar-title--input') end def expect_title(name) - expect(page).to have_field("editable-toolbar-title", with: name) + expect(page).to have_field('editable-toolbar-title', with: name) end def press_save_button - find(".editable-toolbar-title--save").click + find('.editable-toolbar-title--save').click end def rename(name, save: true) - fill_in "editable-toolbar-title", with: name + fill_in 'editable-toolbar-title', with: name if save input_field.send_keys :return diff --git a/spec/support/components/work_packages/relations.rb b/spec/support/components/work_packages/relations.rb index b95d0a1c63e9..b3dbb96610c9 100644 --- a/spec/support/components/work_packages/relations.rb +++ b/spec/support/components/work_packages/relations.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'support/components/autocompleter/ng_select_autocomplete_helpers' module Components module WorkPackages @@ -54,10 +54,10 @@ def click_relation(relatable) def edit_relation_type(relatable, to_type:) row = find_row(relatable) SeleniumHubWaiter.wait - row.find(".relation-row--type").click + row.find('.relation-row--type').click - expect(row).to have_css("select.inline-edit--field") - row.find(".inline-edit--field option", text: to_type).select_option + expect(row).to have_css('select.inline-edit--field') + row.find('.inline-edit--field option', text: to_type).select_option end def hover_action(relatable, action) @@ -72,9 +72,9 @@ def hover_action(relatable, action) row = find_row(relatable) case action when :delete - row.find(".relation-row--remove-btn").click + row.find('.relation-row--remove-btn').click when :info - row.find(".wp-relations--description-btn").click + row.find('.wp-relations--description-btn').click end end end @@ -90,24 +90,24 @@ def remove_relation(relatable) def add_relation(type:, to:) # Open create form SeleniumHubWaiter.wait - find_by_id("relation--add-relation").click + find_by_id('relation--add-relation').click # Select relation type - container = find(".wp-relations-create--form", wait: 10) + container = find('.wp-relations-create--form', wait: 10) # Labels to expect relation_label = I18n.t("js.relation_labels.#{type}") - select relation_label, from: "relation-type--select" + select relation_label, from: 'relation-type--select' # Enter the query and select the child autocomplete = container.find("[data-test-selector='wp-relations-autocomplete']") select_autocomplete autocomplete, - results_selector: ".ng-dropdown-panel-items", + results_selector: '.ng-dropdown-panel-items', query: to.subject, select_text: to.subject - expect(page).to have_css(".relation-group--header", + expect(page).to have_css('.relation-group--header', text: relation_label.upcase, wait: 10) @@ -137,14 +137,14 @@ def expect_no_relation(relatable) def add_parent(query, work_package) # Open the parent edit SeleniumHubWaiter.wait - find(".wp-relation--parent-change").click + find('.wp-relation--parent-change').click # Enter the query and select the child SeleniumHubWaiter.wait autocomplete = find("[data-test-selector='wp-relations-autocomplete']") select_autocomplete autocomplete, query:, - results_selector: ".ng-dropdown-panel-items", + results_selector: '.ng-dropdown-panel-items', select_text: work_package.id end @@ -160,28 +160,28 @@ def expect_no_parent def remove_parent SeleniumHubWaiter.wait - find(".wp-relation--parent-remove").click + find('.wp-relation--parent-remove').click end def inline_create_child(subject_text) - container = find(".wp-relations--children") + container = find('.wp-relations--children') scroll_to_and_click(container.find('[data-test-selector="op-wp-inline-create"]')) - subject = ::EditField.new(container, "subject") + subject = ::EditField.new(container, 'subject') subject.expect_active! subject.update subject_text end def open_children_autocompleter retry_block do - next if page.has_selector?(".wp-relations--children .ng-input input") + next if page.has_selector?('.wp-relations--children .ng-input input') SeleniumHubWaiter.wait find('[data-test-selector="op-wp-inline-create-reference"]', - text: I18n.t("js.relation_buttons.add_existing_child")).click + text: I18n.t('js.relation_buttons.add_existing_child')).click # Security check to be sure that the autocompleter has finished loading - page.find ".wp-relations--children .ng-input input" + page.find '.wp-relations--children .ng-input input' end end @@ -190,21 +190,21 @@ def add_existing_child(work_package) autocomplete = page.find(".wp-relations--add-form [data-test-selector='wp-relations-autocomplete']") select_autocomplete autocomplete, query: work_package.id, - results_selector: ".ng-dropdown-panel-items", + results_selector: '.ng-dropdown-panel-items', select_text: work_package.subject end def expect_child(work_package) - container = find("wp-relations-hierarchy wp-children-query") + container = find('wp-relations-hierarchy wp-children-query') within container do expect(page) - .to have_css(".wp-table--cell-td.subject", text: work_package.subject, wait: 10) + .to have_css('.wp-table--cell-td.subject', text: work_package.subject, wait: 10) end end def expect_not_child(work_package) - page.within("wp-relations-tab .work-packages-embedded-view--container") do + page.within('wp-relations-tab .work-packages-embedded-view--container') do row = ".wp-row-#{work_package.id}-table" expect(page).to have_no_selector(row) @@ -212,15 +212,15 @@ def expect_not_child(work_package) end def children_table - ::Pages::EmbeddedWorkPackagesTable.new find("wp-relations-tab .work-packages-embedded-view--container") + ::Pages::EmbeddedWorkPackagesTable.new find('wp-relations-tab .work-packages-embedded-view--container') end def relations_group - find("wp-relations-tab wp-relations-group") + find('wp-relations-tab wp-relations-group') end def remove_child(work_package) - page.within(".work-packages-embedded-view--container") do + page.within('.work-packages-embedded-view--container') do row = ".wp-row-#{work_package.id}-table" SeleniumHubWaiter.wait diff --git a/spec/support/components/work_packages/settings_menu.rb b/spec/support/components/work_packages/settings_menu.rb index 05b9024545fc..924fedffdb9c 100644 --- a/spec/support/components/work_packages/settings_menu.rb +++ b/spec/support/components/work_packages/settings_menu.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../../toasts/expectations" +require_relative '../../toasts/expectations' module Components module WorkPackages @@ -37,12 +37,12 @@ class SettingsMenu include Toasts::Expectations def open_and_save_query(name) - open_and_choose("Save") + open_and_choose('Save') within_modal_fill_in_and_save(name:) end def open_and_save_query_as(name) - open_and_choose("Save as") + open_and_choose('Save as') within_modal_fill_in_and_save(name:) end @@ -54,7 +54,7 @@ def open_and_choose(name) end def open! - click_on "work-packages-settings-button" + click_on 'work-packages-settings-button' dropdown_menu end @@ -84,13 +84,13 @@ def expect_options(*options) private def selector - "#settingsDropdown" + '#settingsDropdown' end def within_modal_fill_in_and_save(name:) modal.within_modal do - fill_in "save-query-name", with: name - click_button "Save" + fill_in 'save-query-name', with: name + click_button 'Save' end wait_for_save_completion end diff --git a/spec/support/components/work_packages/share_modal.rb b/spec/support/components/work_packages/share_modal.rb index e2b4954fe23c..13192b89ac4f 100644 --- a/spec/support/components/work_packages/share_modal.rb +++ b/spec/support/components/work_packages/share_modal.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "support/components/common/modal" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'support/components/common/modal' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' module Components module WorkPackages @@ -40,7 +40,7 @@ def initialize(work_package) super() @work_package = work_package - @title = I18n.t("js.work_packages.sharing.title") + @title = I18n.t('js.work_packages.sharing.title') end def expect_open @@ -76,10 +76,10 @@ def expect_not_selectable(*principals) def toggle_select_all within shares_header do - if page.find_field("toggle_all").checked? - uncheck "toggle_all" + if page.find_field('toggle_all').checked? + uncheck 'toggle_all' else - check "toggle_all" + check 'toggle_all' end end end @@ -107,43 +107,43 @@ def expect_selected_count_of(count) def expect_select_all_available expect(shares_header) - .to have_field("toggle_all") + .to have_field('toggle_all') end def expect_select_all_not_available expect(shares_header) - .to have_no_field("toggle_all", wait: 0) + .to have_no_field('toggle_all', wait: 0) end def expect_select_all_toggled within shares_header do - expect(page).to have_checked_field("toggle_all") + expect(page).to have_checked_field('toggle_all') end end def expect_select_all_untoggled within shares_header do - expect(page).to have_unchecked_field("toggle_all") + expect(page).to have_unchecked_field('toggle_all') end end def expect_bulk_actions_available within shares_header do - expect(page).to have_button "Remove" - expect(page).to have_test_selector("op-share-wp-bulk-update-role") + expect(page).to have_button 'Remove' + expect(page).to have_test_selector('op-share-wp-bulk-update-role') end end def expect_bulk_actions_not_available within shares_header do - expect(page).to have_no_button("Remove", wait: 0) - expect(page).not_to have_test_selector("op-share-wp-bulk-update-role", wait: 0) + expect(page).to have_no_button('Remove', wait: 0) + expect(page).not_to have_test_selector('op-share-wp-bulk-update-role', wait: 0) end end def bulk_remove within shares_header do - click_button "Remove" + click_button 'Remove' end end @@ -151,7 +151,7 @@ def bulk_update(role_name) within shares_header do find('[data-test-selector="op-share-wp-bulk-update-role"]').click - find(".ActionListContent", text: role_name).click + find('.ActionListContent', text: role_name).click end end @@ -160,7 +160,7 @@ def expect_bulk_update_label(label_text) expect(page) .to have_css('[data-test-selector="op-share-wp-bulk-update-role"] .Button-label', text: label_text) - if label_text == "Mixed" + if label_text == 'Mixed' %w[View Comment Edit].each do |permission_name| within bulk_update_form(permission_name) do expect(page) @@ -181,7 +181,7 @@ def bulk_update_form(permission_name) end def checked_permission - "button[type=submit][aria-checked=true]" + 'button[type=submit][aria-checked=true]' end def unchecked_permission @@ -190,13 +190,13 @@ def unchecked_permission def expect_blankslate within_modal do - expect(page).to have_text(I18n.t("work_package.sharing.text_empty_state_description")) + expect(page).to have_text(I18n.t('work_package.sharing.text_empty_state_description')) end end def expect_empty_search_blankslate within_modal do - expect(page).to have_text(I18n.t("work_package.sharing.text_empty_search_description")) + expect(page).to have_text(I18n.t('work_package.sharing.text_empty_search_description')) end end @@ -213,7 +213,7 @@ def invite_user(users, role_name) select_invite_role(role_name) within_modal do - click_button "Share" + click_button 'Share' end end @@ -233,21 +233,21 @@ def invite_user!(user, role_name) def search_user(search_string) search_autocomplete page.find('[data-test-selector="op-share-wp-invite-autocomplete"]'), query: search_string, - results_selector: "body" + results_selector: 'body' end def remove_user(user) within user_row(user) do - click_button "Remove" + click_button 'Remove' end end def select_invite_role(role_name) within modal_element.find('[data-test-selector="op-share-wp-invite-role"]') do # Open the ActionMenu - click_button "View" + click_button 'View' - find(".ActionListContent", text: role_name).click + find('.ActionListContent', text: role_name).click end end @@ -255,7 +255,7 @@ def change_role(user, role_name) within user_row(user) do find('[data-test-selector="op-share-wp-update-role"]').click - within ".ActionListWrap" do + within '.ActionListWrap' do click_button role_name end end @@ -270,7 +270,7 @@ def filter(filter_name, value) find("[data-test-selector='op-share-wp-filter-#{filter_name}-button']").click # Open the ActionMenu - find(".ActionListContent", text: value).click + find('.ActionListContent', text: value).click end end @@ -285,7 +285,7 @@ def close def click_share within_modal do - click_button "Share" + click_button 'Share' end end @@ -318,13 +318,13 @@ def expect_not_shared_with(*principals) def expect_shared_count_of(count) expect(shares_header) - .to have_text(I18n.t("work_package.sharing.count", count:)) + .to have_text(I18n.t('work_package.sharing.count', count:)) end def expect_no_invite_option within_modal do expect(page) - .to have_text(I18n.t("work_package.sharing.permissions.denied")) + .to have_text(I18n.t('work_package.sharing.permissions.denied')) end end @@ -361,21 +361,21 @@ def shares_counter end def shares_list - find_by_id("op-share-wp-active-shares") + find_by_id('op-share-wp-active-shares') end def select_existing_user(user) select_autocomplete page.find('[data-test-selector="op-share-wp-invite-autocomplete"]'), query: user.firstname, select_text: user.name, - results_selector: "body" + results_selector: 'body' end def select_not_existing_user_option(email) select_autocomplete page.find('[data-test-selector="op-share-wp-invite-autocomplete"]'), query: email, select_text: "Send invite to\"#{email}\"", - results_selector: "body" + results_selector: 'body' end def expect_upsale_banner @@ -388,14 +388,14 @@ def expect_upsale_banner def expect_no_user_limit_warning within modal_element do expect(page) - .to have_no_text(I18n.t("work_package.sharing.warning_user_limit_reached"), wait: 0) + .to have_no_text(I18n.t('work_package.sharing.warning_user_limit_reached'), wait: 0) end end def expect_user_limit_warning within modal_element do expect(page) - .to have_text(I18n.t("work_package.sharing.warning_user_limit_reached")) + .to have_text(I18n.t('work_package.sharing.warning_user_limit_reached')) end end diff --git a/spec/support/components/work_packages/sort_by.rb b/spec/support/components/work_packages/sort_by.rb index c666c616e5dd..8190221af51f 100644 --- a/spec/support/components/work_packages/sort_by.rb +++ b/spec/support/components/work_packages/sort_by.rb @@ -34,7 +34,7 @@ class SortBy include RSpec::Matchers def sort_via_header(name, selector: nil, descending: false) - text = descending ? "Sort descending" : "Sort ascending" + text = descending ? 'Sort descending' : 'Sort ascending' SeleniumHubWaiter.wait unless using_cuprite? open_table_column_context_menu(name, selector) @@ -71,7 +71,7 @@ def expect_criteria(first, second = nil, third = nil) column, direction = entry page.within(".modal-sorting-row-#{i}") do expect(page).to have_css("#modal-sorting-attribute-#{i} option", text: column) - checked_radio = (descending?(direction) ? "Descending" : "Ascending") + checked_radio = (descending?(direction) ? 'Descending' : 'Ascending') expect(page.find_field(checked_radio)).to be_checked end end @@ -82,39 +82,39 @@ def expect_criteria(first, second = nil, third = nil) def update_nth_criteria(i, column, descending: false) page.within(".modal-sorting-row-#{i}") do select column, from: "modal-sorting-attribute-#{i}" - choose(descending ? "Descending" : "Ascending") + choose(descending ? 'Descending' : 'Ascending') end end def update_sorting_mode(mode) - if mode === "manual" - choose("sorting_mode_switch", option: "manual") + if mode === 'manual' + choose('sorting_mode_switch', option: 'manual') else - choose("sorting_mode_switch", option: "automatic") + choose('sorting_mode_switch', option: 'automatic') end end def open_modal modal = TableConfigurationModal.new - modal.open_and_switch_to "Sort by" + modal.open_and_switch_to 'Sort by' end def cancel_changes - page.within(".spot-modal") do - click_on "Cancel" + page.within('.spot-modal') do + click_on 'Cancel' end end def apply_changes - page.within(".spot-modal") do - click_on "Apply" + page.within('.spot-modal') do + click_on 'Apply' end end private def descending?(direction) - ["desc", "descending"].include?(direction.to_s) + ['desc', 'descending'].include?(direction.to_s) end def open_table_column_context_menu(name, id) @@ -123,7 +123,7 @@ def open_table_column_context_menu(name, id) end def within_column_context_menu(&) - page.within("#column-context-menu", &) + page.within('#column-context-menu', &) end end end diff --git a/spec/support/components/work_packages/table_configuration/filters.rb b/spec/support/components/work_packages/table_configuration/filters.rb index 9e6a900dd427..991bb86a0772 100644 --- a/spec/support/components/work_packages/table_configuration/filters.rb +++ b/spec/support/components/work_packages/table_configuration/filters.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../filters" +require_relative '../filters' module Components module WorkPackages @@ -39,7 +39,7 @@ def initialize end def open - modal.open_and_switch_to "Filters" + modal.open_and_switch_to 'Filters' expect_open end @@ -47,13 +47,13 @@ def open def expect_filter_count(count) within(modal.selector) do - expect(page).to have_css(".advanced-filters--filter", count:) + expect(page).to have_css('.advanced-filters--filter', count:) end end def expect_open modal.expect_open - expect(page).to have_css(".op-tab-row--link_selected", text: "FILTERS") + expect(page).to have_css('.op-tab-row--link_selected', text: 'FILTERS') end delegate :expect_closed, to: :modal diff --git a/spec/support/components/work_packages/table_configuration/graph_general.rb b/spec/support/components/work_packages/table_configuration/graph_general.rb index 2bf398a08b4b..2bcd6ed418f5 100644 --- a/spec/support/components/work_packages/table_configuration/graph_general.rb +++ b/spec/support/components/work_packages/table_configuration/graph_general.rb @@ -62,14 +62,14 @@ def expect_axis(name) def apply within_modal do - click_button("Apply") + click_button('Apply') end end private def within_modal(&) - page.within(".wp-table--configuration-modal", &) + page.within('.wp-table--configuration-modal', &) end end end diff --git a/spec/support/components/work_packages/table_configuration/highlighting.rb b/spec/support/components/work_packages/table_configuration/highlighting.rb index d49f0ad39fc0..d7114cf8a74b 100644 --- a/spec/support/components/work_packages/table_configuration/highlighting.rb +++ b/spec/support/components/work_packages/table_configuration/highlighting.rb @@ -46,9 +46,9 @@ def switch_entire_row_highlight(label) # Open select field within(page.all(".form--field")[1]) do - page.find(".ng-input input").click + page.find('.ng-input input').click end - page.find(".ng-dropdown-panel .ng-option", text: label).click + page.find('.ng-dropdown-panel .ng-option', text: label).click apply end @@ -58,14 +58,14 @@ def switch_inline_attribute_highlight(*labels) # Open select field within(page.all(".form--field")[0]) do - page.find(".ng-input input").click + page.find('.ng-input input').click end # Delete all previously selected options - page.all(".ng-dropdown-panel .ng-option-selected").each { |option| option.click } + page.all('.ng-dropdown-panel .ng-option-selected').each { |option| option.click } labels.each do |label| - page.find(".ng-dropdown-panel .ng-option", text: label).click + page.find('.ng-dropdown-panel .ng-option', text: label).click end apply @@ -74,15 +74,15 @@ def switch_inline_attribute_highlight(*labels) def apply @opened = false - click_button("Apply") + click_button('Apply') end def open_modal @opened = true - ::Components::WorkPackages::SettingsMenu.new.open_and_choose "Configure view" + ::Components::WorkPackages::SettingsMenu.new.open_and_choose 'Configure view' retry_block do - find(".op-tab-row--link", text: "HIGHLIGHTING", wait: 10).click + find(".op-tab-row--link", text: 'HIGHLIGHTING', wait: 10).click end end @@ -93,7 +93,7 @@ def assume_opened private def within_modal(&) - page.within(".wp-table--configuration-modal", &) + page.within('.wp-table--configuration-modal', &) end def modal_open? diff --git a/spec/support/components/work_packages/table_configuration_modal.rb b/spec/support/components/work_packages/table_configuration_modal.rb index ce903c221998..e371a53149c3 100644 --- a/spec/support/components/work_packages/table_configuration_modal.rb +++ b/spec/support/components/work_packages/table_configuration_modal.rb @@ -52,7 +52,7 @@ def open_and_switch_to(name) end def open_and_set_display_mode(mode) - open_and_switch_to "Display settings" + open_and_switch_to 'Display settings' choose("display_mode_switch", option: mode) end @@ -67,12 +67,12 @@ def open! end def set_display_sums(enable: true) - open_and_switch_to "Display settings" + open_and_switch_to 'Display settings' if enable - check "display_sums_switch" + check 'display_sums_switch' else - uncheck "display_sums_switch" + uncheck 'display_sums_switch' end save end @@ -82,7 +82,7 @@ def save end def cancel - find("#{selector} .button", text: "Cancel").click + find("#{selector} .button", text: 'Cancel').click end def expect_open @@ -90,7 +90,7 @@ def expect_open end def open? - page.has_selector?(".wp-table--configuration-modal", wait: 1) + page.has_selector?('.wp-table--configuration-modal', wait: 1) end def expect_closed @@ -118,7 +118,7 @@ def switch_to(target) end def selector - ".spot-modal" + '.spot-modal' end private @@ -126,10 +126,10 @@ def selector def trigger if trigger_parent within trigger_parent do - find(".wp-table--configuration-modal--trigger") + find('.wp-table--configuration-modal--trigger') end else - find(".wp-table--configuration-modal--trigger") + find('.wp-table--configuration-modal--trigger') end end end diff --git a/spec/support/components/work_packages/timer_button.rb b/spec/support/components/work_packages/timer_button.rb index cf95a8eb2725..e01fceaf7cea 100644 --- a/spec/support/components/work_packages/timer_button.rb +++ b/spec/support/components/work_packages/timer_button.rb @@ -47,21 +47,21 @@ def expect_time(text) def expect_visible(visible: true) if visible - expect(page).to have_css("op-wp-timer-button") + expect(page).to have_css('op-wp-timer-button') else - expect(page).to have_no_css("op-wp-timer-button") + expect(page).to have_no_css('op-wp-timer-button') end end def start close_dropdown - page.within("op-wp-timer-button") do + page.within('op-wp-timer-button') do find('[data-test-selector="timer-inactive"]').click end end def stop - page.within("op-wp-timer-button") do + page.within('op-wp-timer-button') do find('[data-test-selector="timer-active"]').click end end diff --git a/spec/support/components/wysiwyg/wysiwyg_editor.rb b/spec/support/components/wysiwyg/wysiwyg_editor.rb index afee2036c5bf..57ce75c2d460 100644 --- a/spec/support/components/wysiwyg/wysiwyg_editor.rb +++ b/spec/support/components/wysiwyg/wysiwyg_editor.rb @@ -6,7 +6,7 @@ class WysiwygEditor attr_reader :context_selector, :attachments, :attachments_list - def initialize(context = "#content", attachment_list_selector = "ckeditor-augmented-textarea") + def initialize(context = '#content', attachment_list_selector = 'ckeditor-augmented-textarea') @context_selector = context @attachments = ::Components::Attachments.new @attachments_list = ::Components::AttachmentsList.new("#{context} #{attachment_list_selector}") @@ -25,13 +25,13 @@ def in_editor end def input_selector - "div.ck-content" + 'div.ck-content' end def set_markdown(text) wait_until_loaded - textarea = container.find(".op-ckeditor-source-element", visible: :all) + textarea = container.find('.op-ckeditor-source-element', visible: :all) page.execute_script( 'jQuery(arguments[0]).trigger("op:ckeditor:setData", arguments[1])', textarea.native, @@ -40,7 +40,7 @@ def set_markdown(text) end def clear - textarea = container.find(".op-ckeditor-source-element", visible: :all) + textarea = container.find('.op-ckeditor-source-element', visible: :all) page.execute_script( 'jQuery(arguments[0]).trigger("op:ckeditor:clear")', textarea.native @@ -48,11 +48,11 @@ def clear end def expect_button(label) - expect(container).to have_css(".ck-button", visible: :all, text: label) + expect(container).to have_css('.ck-button', visible: :all, text: label) end def expect_no_button(label) - expect(container).to have_no_css(".ck-button", visible: :all, text: label) + expect(container).to have_no_css('.ck-button', visible: :all, text: label) end def expect_value(value) @@ -61,34 +61,34 @@ def expect_value(value) def expect_supports_no_macros expect(container) - .to have_no_css(".ck-button", visible: :all, text: "Macros") + .to have_no_css('.ck-button', visible: :all, text: 'Macros') end def within_enabled_preview - click_toolbar_button "Toggle preview mode" + click_toolbar_button 'Toggle preview mode' begin - yield container.find(".ck-editor__preview") + yield container.find('.ck-editor__preview') ensure - click_toolbar_button "Toggle preview mode" + click_toolbar_button 'Toggle preview mode' end end ## # Create an image fixture with the optional caption from inside the ckeditor - def drag_attachment(image_fixture, caption = "Some caption") + def drag_attachment(image_fixture, caption = 'Some caption') in_editor do |_container, editable| # Click the latest figure, if any # Do not wait more than 1 second to check if there is an image - images = editable.all("figure.image", wait: 1) + images = editable.all('figure.image', wait: 1) if images.count > 0 images.last.click # Click the "move below figure" button - selected = page.all(".ck-widget_selected .ck-widget__type-around__button_after") + selected = page.all('.ck-widget_selected .ck-widget__type-around__button_after') selected.first&.click end - editable.base.send_keys(:enter, "some text", :enter, :enter) + editable.base.send_keys(:enter, 'some text', :enter, :enter) attachments.drag_and_drop_file(editable, image_fixture, :bottom) @@ -104,27 +104,27 @@ def drag_attachment(image_fixture, caption = "Some caption") image = find("img[src^=\"/api/v3/attachments/#{last_id}\"]") # Besides testing caption functionality this also slows down clicking on the submit button # so that the image is properly embedded - figure = image.find(:xpath, "../..") + figure = image.find(:xpath, '../..') retry_block do # Toggle caption with button since newer version of ckeditor - click_hover_toolbar_button "Toggle caption on" + click_hover_toolbar_button 'Toggle caption on' # Locate figcaption to create comment - @figure_find = figure.find("figcaption") + @figure_find = figure.find('figcaption') figcaption = @figure_find figcaption.click sleep(0.2) figcaption.send_keys(caption) # Expect caption set - figure.find("figcaption", text: caption) + figure.find('figcaption', text: caption) end end end def wait_until_upload_progress_toaster_cleared - page.has_no_selector?("op-toasters-upload-progress") + page.has_no_selector?('op-toasters-upload-progress') end def wait_until_loaded @@ -132,20 +132,20 @@ def wait_until_loaded end def refocus - editor_element.first("*").click + editor_element.first('*').click rescue StandardError => e warn "Failed to refocus on first editor element #{e}" end def insert_link(link) click_toolbar_button "Link" - page.find(".ck-input-text").set link - page.find(".ck-button-save").click + page.find('.ck-input-text').set link + page.find('.ck-button-save').click end def click_toolbar_button(label) # strangely, we need visible: :all here - container.find(".ck-button", visible: :all, text: label).click + container.find('.ck-button', visible: :all, text: label).click end def type_slowly(*) @@ -162,31 +162,31 @@ def click_and_type_slowly(*) end def click_hover_toolbar_button(label) - page.find(".ck-toolbar .ck-button", text: label, visible: :all).click + page.find('.ck-toolbar .ck-button', text: label, visible: :all).click end def insert_macro(label) - container.find(".ck-button", visible: :all, text: "Macros").click - container.find(".ck-button", visible: :all, text: label).click + container.find('.ck-button', visible: :all, text: 'Macros').click + container.find('.ck-button', visible: :all, text: label).click end def click_autocomplete(text) - page.find(".mention-list-item", text:).click + page.find('.mention-list-item', text:).click end def align_table_by_label(editor, table, label) # Style first td in table table - .find(".op-uc-table--row:first-of-type .op-uc-table--cell:first-of-type") + .find('.op-uc-table--row:first-of-type .op-uc-table--cell:first-of-type') .click # Click table toolbar - editor.click_hover_toolbar_button "Table properties" + editor.click_hover_toolbar_button 'Table properties' # Set alignment left editor.click_hover_toolbar_button label - find(".ck-button-save").click + find('.ck-button-save').click end end end diff --git a/spec/support/contracts/shared.rb b/spec/support/contracts/shared.rb index 723437179453..aac3dfe1341f 100644 --- a/spec/support/contracts/shared.rb +++ b/spec/support/contracts/shared.rb @@ -1,22 +1,22 @@ -RSpec.shared_context "model contract" do - shared_examples_for "is not writable" do +RSpec.shared_context 'model contract' do + shared_examples_for 'is not writable' do before do instance.model.attributes = { attribute => value } end - it "explains the not writable error" do + it 'explains the not writable error' do instance.validate expect(instance.errors.details[attribute]) .to contain_exactly({ error: :error_readonly }) end end - shared_examples_for "is writable" do + shared_examples_for 'is writable' do before do instance.model.attributes = { attribute => value } end - it "is writable" do + it 'is writable' do instance.validate expect(instance.errors.details[attribute]) diff --git a/spec/support/cuprite_setup.rb b/spec/support/cuprite_setup.rb index 76c680dbfa9a..ebc84fc23bea 100644 --- a/spec/support/cuprite_setup.rb +++ b/spec/support/cuprite_setup.rb @@ -29,10 +29,10 @@ # ++ # -require "capybara/cuprite" +require 'capybara/cuprite' def headful_mode? - ActiveRecord::Type::Boolean.new.cast(ENV.fetch("OPENPROJECT_TESTING_NO_HEADLESS", nil)) + ActiveRecord::Type::Boolean.new.cast(ENV.fetch('OPENPROJECT_TESTING_NO_HEADLESS', nil)) end def headless_mode? @@ -40,7 +40,7 @@ def headless_mode? end module WindowResolutionManagement - DIMENSION_SEPARATOR = "x" + DIMENSION_SEPARATOR = 'x' class << self # @param [String] resolution, "1920x1080" @@ -74,30 +74,30 @@ def register_better_cuprite(language, name: :"better_cuprite_#{language}") window_size: [1920, 1080] } - if headful_mode? && ENV["CAPYBARA_WINDOW_RESOLUTION"] - window_size = WindowResolutionManagement.extract_dimensions(ENV["CAPYBARA_WINDOW_RESOLUTION"]) + if headful_mode? && ENV['CAPYBARA_WINDOW_RESOLUTION'] + window_size = WindowResolutionManagement.extract_dimensions(ENV['CAPYBARA_WINDOW_RESOLUTION']) options = options.merge(window_size:) end - if headful_mode? && ENV["OPENPROJECT_TESTING_SLOWDOWN_FACTOR"] - options = options.merge(slowmo: ENV["OPENPROJECT_TESTING_SLOWDOWN_FACTOR"]) + if headful_mode? && ENV['OPENPROJECT_TESTING_SLOWDOWN_FACTOR'] + options = options.merge(slowmo: ENV['OPENPROJECT_TESTING_SLOWDOWN_FACTOR']) end - if ENV["CHROME_URL"].present? - options = options.merge(url: ENV["CHROME_URL"]) + if ENV['CHROME_URL'].present? + options = options.merge(url: ENV['CHROME_URL']) end browser_options = { - "disable-dev-shm-usage": nil, - "disable-gpu": nil, - "disable-popup-blocking": nil, + 'disable-dev-shm-usage': nil, + 'disable-gpu': nil, + 'disable-popup-blocking': nil, lang: language, - "no-sandbox": nil, - "disable-smooth-scrolling": true + 'no-sandbox': nil, + 'disable-smooth-scrolling': true } - if ENV["OPENPROJECT_TESTING_AUTO_DEVTOOLS"].present? - browser_options = browser_options.merge("auto-open-devtools-for-tabs": nil) + if ENV['OPENPROJECT_TESTING_AUTO_DEVTOOLS'].present? + browser_options = browser_options.merge('auto-open-devtools-for-tabs': nil) end driver_options = options.merge(browser_options:) @@ -110,7 +110,7 @@ def register_better_cuprite(language, name: :"better_cuprite_#{language}") end end -register_better_cuprite "en" +register_better_cuprite 'en' MODULES_WITH_CUPRITE_ENABLED = %w[ avatars diff --git a/spec/support/download_list.rb b/spec/support/download_list.rb index 5706747b98e5..f18a0f126fac 100644 --- a/spec/support/download_list.rb +++ b/spec/support/download_list.rb @@ -1,8 +1,8 @@ class DownloadList SHARED_PATH = Pathname.new( - ENV.fetch("CAPYBARA_DOWNLOADED_FILE_DIR", Rails.root.join("tmp/test/downloads")) + ENV.fetch("CAPYBARA_DOWNLOADED_FILE_DIR", Rails.root.join('tmp/test/downloads')) ).join( - ENV.fetch("TEST_ENV_NUMBER", "1") + ENV.fetch('TEST_ENV_NUMBER', '1') ).tap(&:mkpath) def initialize diff --git a/spec/support/edit_fields/date_edit_field.rb b/spec/support/edit_fields/date_edit_field.rb index 0fb84dfa5b36..e187c10469d2 100644 --- a/spec/support/edit_fields/date_edit_field.rb +++ b/spec/support/edit_fields/date_edit_field.rb @@ -1,4 +1,4 @@ -require_relative "edit_field" +require_relative 'edit_field' class DateEditField < EditField attr_accessor :milestone, :is_table @@ -41,7 +41,7 @@ def modal_selector end def input_selector - if property_name == "combinedDate" + if property_name == 'combinedDate' "input[name=startDate]" else "input[name=#{property_name}]" @@ -50,7 +50,7 @@ def input_selector def property_name if milestone - "date" + 'date' else super end diff --git a/spec/support/edit_fields/edit_field.rb b/spec/support/edit_fields/edit_field.rb index 910e85b167e9..e159972abac6 100644 --- a/spec/support/edit_fields/edit_field.rb +++ b/spec/support/edit_fields/edit_field.rb @@ -44,7 +44,7 @@ def field_container end def display_selector - ".inline-edit--display-field" + '.inline-edit--display-field' end def display_element @@ -61,7 +61,7 @@ def label_element def clear(with_backspace: false) if with_backspace - input_element.set(" ", fill_options: { clear: :backspace }) + input_element.set(' ', fill_options: { clear: :backspace }) else input_element.native.clear end @@ -161,7 +161,7 @@ def save! end def submit_by_dashboard - field_container.find(".inplace-edit--control--save").click + field_container.find('.inplace-edit--control--save').click wait_for_reload if using_cuprite? end @@ -183,18 +183,18 @@ def set_value(content) end end - def autocomplete(query, select: true, select_text: query) - raise ArgumentError.new("Is not an autocompleter field") unless autocompleter_field? + def autocomplete(query, select: true) + raise ArgumentError.new('Is not an autocompleter field') unless autocompleter_field? if select - select_autocomplete field_container, query:, select_text:, results_selector: "body" + select_autocomplete field_container, query:, results_selector: 'body' else - search_autocomplete field_container, query:, results_selector: "body" + search_autocomplete field_container, query:, results_selector: 'body' end end def autocompleter_field? - field_type.end_with?("-autocompleter") + field_type.end_with?('-autocompleter') end ## @@ -206,12 +206,12 @@ def unset_value(content = nil, multi: false) if autocompleter_field? if multi - page.find(".ng-value-label", visible: :all, text: content).sibling(".ng-value-icon").click + page.find('.ng-value-label', visible: :all, text: content).sibling('.ng-value-icon').click else ng_select_clear(field_container) end else - input_element.set("") + input_element.set('') end end @@ -219,9 +219,9 @@ def unset_value(content = nil, multi: false) # Use option of ng-select field to create new element from within the autocompleter def set_new_value(content) scroll_to_element(input_element) - input_element.find("input").set content + input_element.find('input').set content - page.find(".ng-option", text: "Create: #{content}").click + page.find('.ng-option', text: "Create: #{content}").click end def type(text) @@ -270,31 +270,31 @@ def editable? end def input_selector - if property_name == "description" - ".op-ckeditor--wrapper" + if property_name == 'description' + '.op-ckeditor--wrapper' else - ".inline-edit--field" + '.inline-edit--field' end end def autocomplete_selector - field_container.find(".ng-input input") + field_container.find('.ng-input input') end def derive_field_type case property_name.to_sym when :version - "version-autocompleter" + 'version-autocompleter' when :assignee, :responsible, :user - "op-user-autocompleter" + 'op-user-autocompleter' when :priority, :status, :type, :category, :workPackage, :parent - "create-autocompleter" + 'create-autocompleter' when :project - "op-project-autocompleter" + 'op-project-autocompleter' when :activity - "activity-autocompleter" + 'activity-autocompleter' else - "input" + 'input' end end end diff --git a/spec/support/edit_fields/project_status_field.rb b/spec/support/edit_fields/project_status_field.rb index b39a49f1e495..d2aa17157b18 100644 --- a/spec/support/edit_fields/project_status_field.rb +++ b/spec/support/edit_fields/project_status_field.rb @@ -1,11 +1,11 @@ -require "support/components/autocompleter/ng_select_autocomplete_helpers" -require_relative "edit_field" +require 'support/components/autocompleter/ng_select_autocomplete_helpers' +require_relative 'edit_field' class ProjectStatusField < EditField include ::Components::Autocompleter::NgSelectAutocompleteHelpers def input_selector - ".ng-select.project-status" + '.ng-select.project-status' end def field_type @@ -13,6 +13,6 @@ def field_type end def set_to(status_name) - page.find(".ng-input input").set("#{status_name}\n") + page.find('.ng-input input').set("#{status_name}\n") end end diff --git a/spec/support/edit_fields/select_edit_field.rb b/spec/support/edit_fields/select_edit_field.rb index d7dbd3e09224..41ec5f28e691 100644 --- a/spec/support/edit_fields/select_edit_field.rb +++ b/spec/support/edit_fields/select_edit_field.rb @@ -1,12 +1,12 @@ -require_relative "edit_field" +require_relative 'edit_field' class SelectField < EditField def expect_value(value) - input = context.find(input_selector + " .ng-value-label") + input = context.find(input_selector + ' .ng-value-label') expect(input.text).to eq(value) end def field_type - "create-autocompleter" + 'create-autocompleter' end end diff --git a/spec/support/edit_fields/spent_time_edit_field.rb b/spec/support/edit_fields/spent_time_edit_field.rb index 4826993f8582..99ad4605de76 100644 --- a/spec/support/edit_fields/spent_time_edit_field.rb +++ b/spec/support/edit_fields/spent_time_edit_field.rb @@ -1,4 +1,4 @@ -require_relative "edit_field" +require_relative 'edit_field' class SpentTimeEditField < EditField def time_log_icon_visible(visible) @@ -16,6 +16,6 @@ def open_time_log_modal private def icon - ".icon-time" + '.icon-time' end end diff --git a/spec/support/edit_fields/text_area_field.rb b/spec/support/edit_fields/text_area_field.rb index 969911388d99..e6ded427446b 100644 --- a/spec/support/edit_fields/text_area_field.rb +++ b/spec/support/edit_fields/text_area_field.rb @@ -1,8 +1,8 @@ -require_relative "edit_field" +require_relative 'edit_field' class TextAreaField < EditField def input_selector - "textarea" + 'textarea' end def expect_save_button(enabled: true) @@ -34,11 +34,11 @@ def cancel_by_click end def field_type - "textarea" + 'textarea' end def control_link(action = :save) - raise "Invalid link" unless %i[save cancel].include?(action) + raise 'Invalid link' unless %i[save cancel].include?(action) ".inplace-edit--control--#{action}" end diff --git a/spec/support/edit_fields/text_editor_field.rb b/spec/support/edit_fields/text_editor_field.rb index 0629c8119666..0917279fc403 100644 --- a/spec/support/edit_fields/text_editor_field.rb +++ b/spec/support/edit_fields/text_editor_field.rb @@ -1,4 +1,4 @@ -require_relative "edit_field" +require_relative 'edit_field' class TextEditorField < EditField def ckeditor @@ -6,7 +6,7 @@ def ckeditor end def input_selector - ".ck-content" + '.ck-content' end def expect_save_button(enabled: true) @@ -64,7 +64,7 @@ def field_type end def control_link(action = :save) - raise "Invalid link" unless %i[save cancel].include?(action) + raise 'Invalid link' unless %i[save cancel].include?(action) ".inplace-edit--control--#{action}:not([disabled])" end diff --git a/spec/support/edit_fields/work_package_status_field.rb b/spec/support/edit_fields/work_package_status_field.rb index 712aec2f46a6..d22b552eaf24 100644 --- a/spec/support/edit_fields/work_package_status_field.rb +++ b/spec/support/edit_fields/work_package_status_field.rb @@ -1,4 +1,4 @@ -require_relative "edit_field" +require_relative 'edit_field' class WorkPackageStatusField < EditField def initialize(context) @@ -7,7 +7,7 @@ def initialize(context) end def input_selector - "#wp-status-context-menu" + '#wp-status-context-menu' end def input_element @@ -37,7 +37,7 @@ def update(value, save: true, expect_failure: false) end def set_value(content) - input_element.find("button", text: content).click + input_element.find('button', text: content).click end def active? diff --git a/spec/support/file_helpers.rb b/spec/support/file_helpers.rb index ab7b10209957..27a5ba0d7fda 100644 --- a/spec/support/file_helpers.rb +++ b/spec/support/file_helpers.rb @@ -29,9 +29,9 @@ module FileHelpers module_function - def mock_uploaded_file(name: "test.txt", - content_type: "text/plain", - content: "test content", + def mock_uploaded_file(name: 'test.txt', + content_type: 'text/plain', + content: 'test content', binary: false) tmp = ::OpenProject::Files.create_temp_file(name:, content:, binary:) diff --git a/spec/support/finders/test_selector.rb b/spec/support/finders/test_selector.rb index cf2db8586355..d3f709363767 100644 --- a/spec/support/finders/test_selector.rb +++ b/spec/support/finders/test_selector.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "capybara/rspec" +require 'capybara/rspec' module TestSelectorFinders def test_selector(value) @@ -47,7 +47,7 @@ def have_test_selector(value, **) end RSpec.configure do |config| - Capybara.test_id = "data-test-selector" + Capybara.test_id = 'data-test-selector' Capybara.add_selector(:test_id) do xpath do |locator| XPath.descendant[XPath.attr(Capybara.test_id) == locator] diff --git a/spec/support/form_fields/editor_form_field.rb b/spec/support/form_fields/editor_form_field.rb index 7907d99721ce..d34bddaa6d20 100644 --- a/spec/support/form_fields/editor_form_field.rb +++ b/spec/support/form_fields/editor_form_field.rb @@ -1,4 +1,4 @@ -require_relative "form_field" +require_relative 'form_field' module FormFields class EditorFormField < FormField diff --git a/spec/support/form_fields/form_field.rb b/spec/support/form_fields/form_field.rb index dc9bf4b028df..0166973fd1eb 100644 --- a/spec/support/form_fields/form_field.rb +++ b/spec/support/form_fields/form_field.rb @@ -17,7 +17,7 @@ def expect_visible def expect_required expect(field_container) - .to have_css ".spot-form-field--label-indicator", text: "*" + .to have_css '.spot-form-field--label-indicator', text: '*' end def field_container diff --git a/spec/support/form_fields/input_form_field.rb b/spec/support/form_fields/input_form_field.rb index 6fa9926f0301..632df32d5cb0 100644 --- a/spec/support/form_fields/input_form_field.rb +++ b/spec/support/form_fields/input_form_field.rb @@ -1,14 +1,14 @@ -require_relative "form_field" +require_relative 'form_field' module FormFields class InputFormField < FormField def expect_value(value) scroll_to_element(field_container) - expect(field_container).to have_css("input") { |el| el.value == value } + expect(field_container).to have_css('input') { |el| el.value == value } end def expect_visible - expect(field_container).to have_css("input") + expect(field_container).to have_css('input') end ## @@ -33,7 +33,7 @@ def send_keys(*) end def input_element - field_container.find "input" + field_container.find 'input' end end end diff --git a/spec/support/form_fields/select_form_field.rb b/spec/support/form_fields/select_form_field.rb index 07156acbf31c..030359699f87 100644 --- a/spec/support/form_fields/select_form_field.rb +++ b/spec/support/form_fields/select_form_field.rb @@ -1,34 +1,34 @@ -require_relative "form_field" +require_relative 'form_field' module FormFields class SelectFormField < FormField def expect_selected(*values) values.each do |val| - expect(field_container).to have_css(".ng-value", text: val) + expect(field_container).to have_css('.ng-value', text: val) end end def expect_no_option(option) - field_container.find(".ng-select-container").click + field_container.find('.ng-select-container').click expect(page) - .to have_no_css(".ng-option", text: option, visible: :all) + .to have_no_css('.ng-option', text: option, visible: :all) end def expect_visible - expect(field_container).to have_css("ng-select") + expect(field_container).to have_css('ng-select') end def select_option(*values) values.each do |val| - field_container.find(".ng-select-container").click - page.find(".ng-option", text: val, visible: :all).click + field_container.find('.ng-select-container').click + page.find('.ng-option', text: val, visible: :all).click sleep 1 end end def search(text) - field_container.find(".ng-select-container input").set text + field_container.find('.ng-select-container input').set text end end end diff --git a/spec/support/identical_ext.rb b/spec/support/identical_ext.rb index 4f171c9c84a9..966d2b84e935 100644 --- a/spec/support/identical_ext.rb +++ b/spec/support/identical_ext.rb @@ -33,10 +33,10 @@ def identical?(o) original = attributes recreated = o.attributes - original.except!("created_at") - details.except!("created_on") - recreated.except!("created_at") - o.details.except!("created_on") + original.except!('created_at') + details.except!('created_on') + recreated.except!('created_at') + o.details.except!('created_on') original.identical?(recreated) end diff --git a/spec/support/local_storage_cleanup.rb b/spec/support/local_storage_cleanup.rb index 4a98f666293b..25c8802585fc 100644 --- a/spec/support/local_storage_cleanup.rb +++ b/spec/support/local_storage_cleanup.rb @@ -28,7 +28,7 @@ RSpec.configure do |config| config.after(:each, :js) do - Capybara.current_session.driver.execute_script("window.localStorage.clear()") + Capybara.current_session.driver.execute_script('window.localStorage.clear()') rescue StandardError nil end diff --git a/spec/support/matchers/be_html_eql.rb b/spec/support/matchers/be_html_eql.rb index 1927521a35d3..52c92ce7b25e 100644 --- a/spec/support/matchers/be_html_eql.rb +++ b/spec/support/matchers/be_html_eql.rb @@ -52,15 +52,15 @@ def html(html) end chain :within_path do |path| - @path = path + " > *" + @path = path + ' > *' end should_message = ->(actual) do - ["expected:", expected.to_s, "got:", actual.to_s].join("\n") + ['expected:', expected.to_s, 'got:', actual.to_s].join("\n") end should_not_message = ->(actual) do - ["expected:", actual.to_s, "not to be equivalent to:", expected.to_s].join("\n") + ['expected:', actual.to_s, 'not to be equivalent to:', expected.to_s].join("\n") end failure_message &should_message diff --git a/spec/support/notifications/navigation_helper.rb b/spec/support/notifications/navigation_helper.rb index 5a338dbc6fe1..e83f1158e760 100644 --- a/spec/support/notifications/navigation_helper.rb +++ b/spec/support/notifications/navigation_helper.rb @@ -27,7 +27,7 @@ def open_center_and_navigate_within center.click_item notification split_screen = ::Pages::SplitWorkPackage.new work_package split_screen.expect_tab :activity - split_screen.switch_to_tab tab: "relations" + split_screen.switch_to_tab tab: 'relations' center.close end diff --git a/spec/support/onboarding_helper.rb b/spec/support/onboarding_helper.rb index 3837fee9ab86..87187a8416a1 100644 --- a/spec/support/onboarding_helper.rb +++ b/spec/support/onboarding_helper.rb @@ -26,50 +26,50 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' module OnboardingHelper def step_through_onboarding_wp_tour(project, wp) - expect(page).to have_no_css(".op-loading-indicator") - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wp.list")), normalize_ws: true + expect(page).to have_no_css('.op-loading-indicator') + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wp.list')), normalize_ws: true next_button.click - expect(page).to have_current_path project_work_package_path(project, wp.id, "activity") - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wp.full_view")), normalize_ws: true + expect(page).to have_current_path project_work_package_path(project, wp.id, 'activity') + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wp.full_view')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wp.back_button")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wp.back_button')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wp.create_button")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wp.create_button')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wp.gantt_menu")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wp.gantt_menu')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wp.timeline")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wp.timeline')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.sidebar_arrow")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.sidebar_arrow')), normalize_ws: true end def step_through_onboarding_main_menu_tour(has_full_capabilities:) if has_full_capabilities next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.members")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.members')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.wiki")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.wiki')), normalize_ws: true next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.quick_add_button")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.quick_add_button')), normalize_ws: true end next_button.click - expect(page).to have_text sanitize_string(I18n.t("js.onboarding.steps.help_menu")), normalize_ws: true + expect(page).to have_text sanitize_string(I18n.t('js.onboarding.steps.help_menu')), normalize_ws: true next_button.click - expect(page).to have_no_css ".enjoy_hint_label" + expect(page).to have_no_css '.enjoy_hint_label' end def sanitize_string(string) diff --git a/spec/support/pages/admin/custom_actions/edit.rb b/spec/support/pages/admin/custom_actions/edit.rb index cea34bb14b44..80c0b0b07f00 100644 --- a/spec/support/pages/admin/custom_actions/edit.rb +++ b/spec/support/pages/admin/custom_actions/edit.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' -require_relative "form" +require_relative 'form' module Pages module Admin @@ -46,7 +46,7 @@ def path def save sleep 2 - click_button "Save" + click_button 'Save' end end end diff --git a/spec/support/pages/admin/custom_actions/form.rb b/spec/support/pages/admin/custom_actions/form.rb index 867f21eb42d1..d7db9d04babf 100644 --- a/spec/support/pages/admin/custom_actions/form.rb +++ b/spec/support/pages/admin/custom_actions/form.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'support/pages/page' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' module Pages module Admin @@ -36,39 +36,39 @@ class Form < ::Pages::Page include ::Components::Autocompleter::NgSelectAutocompleteHelpers def set_name(name) - fill_in "Name", with: name + fill_in 'Name', with: name end def set_description(description) - fill_in "Description", with: description + fill_in 'Description', with: description end def add_action(name, value) ignore_ferrum_javascript_error do - select name, from: "Add action" + select name, from: 'Add action' end set_action_value(name, value) - within "#custom-actions-form--active-actions" do - expect(page).to have_css(".form--label", text: name) + within '#custom-actions-form--active-actions' do + expect(page).to have_css('.form--label', text: name) end end def remove_action(name) - within "#custom-actions-form--active-actions" do - find(".form--field", text: name) - .find(".icon-close") + within '#custom-actions-form--active-actions' do + find('.form--field', text: name) + .find('.icon-close') .click end end def expect_selected_option(value) - expect(page).to have_css(".ng-value-label", text: value) + expect(page).to have_css('.ng-value-label', text: value) end def expect_action(name, value) - value = "null" if value.nil? + value = 'null' if value.nil? - within "#custom-actions-form--actions" do + within '#custom-actions-form--actions' do if value.is_a?(Array) value.each { |name| expect_selected_option(name.to_s) } else @@ -89,7 +89,7 @@ def set_condition(name, value) retry_block do set_condition_value(name, val) - within "#custom-actions-form--conditions" do + within '#custom-actions-form--conditions' do expect_selected_option val end end @@ -99,13 +99,13 @@ def set_condition(name, value) private def set_action_value(name, value) - field = find("#custom-actions-form--active-actions .form--field", text: name, wait: 5) + field = find('#custom-actions-form--active-actions .form--field', text: name, wait: 5) set_field_value(field, name, value) end def set_condition_value(name, value) - field = find("#custom-actions-form--conditions .form--field", text: name, wait: 5) + field = find('#custom-actions-form--conditions .form--field', text: name, wait: 5) set_field_value(field, name, value) end @@ -115,21 +115,21 @@ def set_field_value(field, name, value) Array(value).each do |val| within field do - if has_selector?(".form--selected-value--container", wait: 0) - find(".form--selected-value--container").click + if has_selector?('.form--selected-value--container', wait: 0) + find('.form--selected-value--container').click autocomplete = true - elsif has_selector?(".autocomplete-select-decoration--wrapper", wait: 0) + elsif has_selector?('.autocomplete-select-decoration--wrapper', wait: 0) autocomplete = true end target = page.find_field(name) - has_no_css?(".ng-spinner-loader") # wait for possible async loading of options for ng-select + has_no_css?('.ng-spinner-loader') # wait for possible async loading of options for ng-select target.send_keys val end if autocomplete - has_no_css?(".ng-spinner-loader") # wait for possible async loading of options for ng-select - dropdown_el = find(".ng-option", text: val, wait: 5) + has_no_css?('.ng-spinner-loader') # wait for possible async loading of options for ng-select + dropdown_el = find('.ng-option', text: val, wait: 5) scroll_to_and_click(dropdown_el) end end diff --git a/spec/support/pages/admin/custom_actions/index.rb b/spec/support/pages/admin/custom_actions/index.rb index 6b15fd0505aa..98e49f5b2300 100644 --- a/spec/support/pages/admin/custom_actions/index.rb +++ b/spec/support/pages/admin/custom_actions/index.rb @@ -26,15 +26,15 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Admin module CustomActions class Index < ::Pages::Page def new - within ".toolbar-items" do - click_link "Custom action" + within '.toolbar-items' do + click_link 'Custom action' end wait_for_reload @@ -44,7 +44,7 @@ def new def edit(name) within_buttons_of name do - find(".icon-edit").click + find('.icon-edit').click end custom_action = CustomAction.find_by!(name:) @@ -54,13 +54,13 @@ def edit(name) def delete(name) accept_alert do within_buttons_of name do - find(".icon-delete").click + find('.icon-delete').click end end end def expect_listed(*names) - within "table" do + within 'table' do Array(names).each do |name| expect(page) .to have_content name @@ -70,25 +70,25 @@ def expect_listed(*names) def move_top(name) within_row_of(name) do - find("a[title='Move to top']").trigger("click") + find("a[title='Move to top']").trigger('click') end end def move_bottom(name) within_row_of(name) do - find("a[title='Move to bottom']").trigger("click") + find("a[title='Move to bottom']").trigger('click') end end def move_up(name) within_row_of(name) do - find("a[title='Move up']").trigger("click") + find("a[title='Move up']").trigger('click') end end def move_down(name) within_row_of(name) do - find("a[title='Move down']").trigger("click") + find("a[title='Move down']").trigger('click') end end @@ -99,14 +99,14 @@ def path private def within_row_of(name, &) - within "table" do - within(find("tr", text: name), &) + within 'table' do + within(find('tr', text: name), &) end end def within_buttons_of(name, &) within_row_of(name) do - within(find(".buttons"), &) + within(find('.buttons'), &) end end end diff --git a/spec/support/pages/admin/custom_actions/new.rb b/spec/support/pages/admin/custom_actions/new.rb index e47dcbf93b7a..1c45c861066e 100644 --- a/spec/support/pages/admin/custom_actions/new.rb +++ b/spec/support/pages/admin/custom_actions/new.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' -require_relative "form" +require_relative 'form' module Pages module Admin module CustomActions class New < Form def create - click_button "Create" + click_button 'Create' end def path diff --git a/spec/support/pages/admin/individual_principals/edit.rb b/spec/support/pages/admin/individual_principals/edit.rb index a8ca6fc2420d..d733655b0b19 100644 --- a/spec/support/pages/admin/individual_principals/edit.rb +++ b/spec/support/pages/admin/individual_principals/edit.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'support/pages/page' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' module Pages module Admin @@ -47,8 +47,8 @@ def path end def open_projects_tab! - within(".content--tabs") do - click_on "Projects" + within('.content--tabs') do + click_on 'Projects' end end @@ -56,64 +56,64 @@ def add_to_project!(project_name, as:) open_projects_tab! select_project! project_name Array(as).each { |role| check role } - click_on "Add" + click_on 'Add' expect_project(project_name) end def remove_from_project!(name) open_projects_tab! - find_project(name).find("a[data-method=delete]").click + find_project(name).find('a[data-method=delete]').click end def edit_roles!(membership, roles) find("#member-#{membership.id} .memberships--edit-button").click page.within("#member-#{membership.id}-roles-form") do - page.all(".form--check-box").each do |f| + page.all('.form--check-box').each do |f| f.set false rescue Selenium::WebDriver::Error::InvalidElementStateError # Happens if an element is disabled end Array(roles).each { |role| page.check role } - page.find(".memberships--edit-submit-button").click + page.find('.memberships--edit-submit-button').click end end def expect_project(project_name) - expect(page).to have_css("tr", text: project_name, wait: 10) + expect(page).to have_css('tr', text: project_name, wait: 10) end def expect_no_membership(project_name) - expect(page).to have_no_css("tr", text: project_name) + expect(page).to have_no_css('tr', text: project_name) end def expect_roles(project_name, roles) - row = page.find("tr", text: project_name, wait: 10) + row = page.find('tr', text: project_name, wait: 10) roles.each do |role| - expect(row).to have_css("span", text: role) + expect(row).to have_css('span', text: role) end end def find_project(name) - find("tr", text: name) + find('tr', text: name) end def has_project?(name) - has_selector? "tr", text: name + has_selector? 'tr', text: name end def select_project!(project_name) select_autocomplete page.find('[data-test-selector="membership_project_id"]'), query: project_name, select_text: project_name, - results_selector: "body" + results_selector: 'body' end def activate! - within ".toolbar-items" do - click_button "Activate" + within '.toolbar-items' do + click_button 'Activate' end end end diff --git a/spec/support/pages/admin/ldap_auth_sources/index.rb b/spec/support/pages/admin/ldap_auth_sources/index.rb index 730116eaa03f..7979f0007282 100644 --- a/spec/support/pages/admin/ldap_auth_sources/index.rb +++ b/spec/support/pages/admin/ldap_auth_sources/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Admin diff --git a/spec/support/pages/admin/placeholder_users/index.rb b/spec/support/pages/admin/placeholder_users/index.rb index 8dc71b3d72af..de7663d002ad 100644 --- a/spec/support/pages/admin/placeholder_users/index.rb +++ b/spec/support/pages/admin/placeholder_users/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Admin @@ -37,56 +37,56 @@ def path end def expect_listed(*placeholder_users) - rows = page.all "td.name" + rows = page.all 'td.name' expect(rows.map(&:text)).to include(*placeholder_users.map(&:name)) end def expect_ordered(*placeholder_users) - rows = page.all "td.name" + rows = page.all 'td.name' expect(rows.map(&:text)).to eq(placeholder_users.map(&:name)) end def expect_not_listed(*users) - rows = page.all "td.name" + rows = page.all 'td.name' expect(rows.map(&:text)).not_to include(*users.map(&:name)) end def expect_non_listed expect(page) - .to have_no_css("tr.placeholder-user") + .to have_no_css('tr.placeholder-user') expect(page) - .to have_css("tr.generic-table--empty-row", text: "There is currently nothing to display.") + .to have_css('tr.generic-table--empty-row', text: 'There is currently nothing to display.') end def filter_by_name(value) - fill_in "Name", with: value - click_button "Apply" + fill_in 'Name', with: value + click_button 'Apply' end def clear_filters - click_link "Clear" + click_link 'Clear' end def order_by(key) - within "thead" do + within 'thead' do click_link key end end def expect_no_delete_button_for_all_rows - expect(page).to have_css("i.icon-help2") + expect(page).to have_css('i.icon-help2') end def expect_no_delete_button(placeholder_user) within_placeholder_user_row(placeholder_user) do - expect(page).to have_css("i.icon-help2") + expect(page).to have_css('i.icon-help2') end end def expect_delete_button(placeholder_user) within_placeholder_user_row(placeholder_user) do - expect(page).to have_css("i.icon-delete") + expect(page).to have_css('i.icon-delete') end end @@ -99,7 +99,7 @@ def click_placeholder_user_button(placeholder_user, text) private def within_placeholder_user_row(placeholder_user, &) - row = find("tr.placeholder_user td.name", text: placeholder_user.name).ancestor("tr") + row = find('tr.placeholder_user td.name', text: placeholder_user.name).ancestor('tr') within(row, &) end end diff --git a/spec/support/pages/admin/system_settings/general.rb b/spec/support/pages/admin/system_settings/general.rb index 164cda947ca9..04214e8a558e 100644 --- a/spec/support/pages/admin/system_settings/general.rb +++ b/spec/support/pages/admin/system_settings/general.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/admin/system_settings/page" +require 'support/pages/admin/system_settings/page' module Pages::Admin::SystemSettings class General < Page diff --git a/spec/support/pages/admin/system_settings/languages.rb b/spec/support/pages/admin/system_settings/languages.rb index 93d666517cbd..dca398acd9bd 100644 --- a/spec/support/pages/admin/system_settings/languages.rb +++ b/spec/support/pages/admin/system_settings/languages.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/admin/system_settings/page" +require 'support/pages/admin/system_settings/page' module Pages::Admin::SystemSettings class Languages < Page diff --git a/spec/support/pages/admin/system_settings/page.rb b/spec/support/pages/admin/system_settings/page.rb index d66649d93957..5df610f6bc66 100644 --- a/spec/support/pages/admin/system_settings/page.rb +++ b/spec/support/pages/admin/system_settings/page.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages::Admin::SystemSettings class Page < ::Pages::Page @@ -38,7 +38,7 @@ def toast_type def press_save_button scroll_to(:bottom) - click_button("Save") + click_button('Save') self end end diff --git a/spec/support/pages/admin/users/edit.rb b/spec/support/pages/admin/users/edit.rb index 23abae8920f3..c48d97c78d6a 100644 --- a/spec/support/pages/admin/users/edit.rb +++ b/spec/support/pages/admin/users/edit.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Admin @@ -43,8 +43,8 @@ def path end def open_projects_tab! - within(".content--tabs") do - click_on "Projects" + within('.content--tabs') do + click_on 'Projects' end end @@ -52,61 +52,61 @@ def add_to_project!(project_name, as:) open_projects_tab! select_project! project_name Array(as).each { |role| check role } - click_on "Add" + click_on 'Add' expect_project(project_name) end def remove_from_project!(name) open_projects_tab! - find_project(name).find("a[data-method=delete]").click + find_project(name).find('a[data-method=delete]').click end def edit_roles!(membership, roles) find("#member-#{membership.id} .user-memberships--edit-button").click page.within("#member-#{membership.id}-roles-form") do - page.all(".form--check-box").each do |f| + page.all('.form--check-box').each do |f| f.set false rescue Selenium::WebDriver::Error::InvalidElementStateError # Happens if an element is disabled end Array(roles).each { |role| page.check role } - page.find(".user-memberships--edit-submit-button").click + page.find('.user-memberships--edit-submit-button').click end end def expect_project(project_name) - expect(page).to have_css("tr", text: project_name, wait: 10) + expect(page).to have_css('tr', text: project_name, wait: 10) end def expect_no_membership(project_name) - expect(page).to have_no_css("tr", text: project_name) + expect(page).to have_no_css('tr', text: project_name) end def expect_roles(project_name, roles) - row = page.find("tr", text: project_name, wait: 10) + row = page.find('tr', text: project_name, wait: 10) roles.each do |role| - expect(row).to have_css("span", text: role) + expect(row).to have_css('span', text: role) end end def find_project(name) - find("tr", text: name) + find('tr', text: name) end def has_project?(name) - has_selector? "tr", text: name + has_selector? 'tr', text: name end def select_project!(project_name) - select(project_name, from: "membership_project_id") + select(project_name, from: 'membership_project_id') end def activate! - within ".toolbar-items" do - click_button "Activate" + within '.toolbar-items' do + click_button 'Activate' end end end diff --git a/spec/support/pages/admin/users/index.rb b/spec/support/pages/admin/users/index.rb index d97db59a552d..10837724eafb 100644 --- a/spec/support/pages/admin/users/index.rb +++ b/spec/support/pages/admin/users/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Admin @@ -37,66 +37,66 @@ def path end def expect_listed(*users) - rows = page.all "td.username a" + rows = page.all 'td.username a' expect(rows.map(&:text)).to include(*users.map(&:login)) end def expect_order(*users) - rows = page.all "td.username a" + rows = page.all 'td.username a' expect(rows.map(&:text)).to eq(users.map(&:login)) end def expect_non_listed expect(page) - .to have_no_css("tr.user") + .to have_no_css('tr.user') expect(page) - .to have_css("tr.generic-table--empty-row", text: "There is currently nothing to display.") + .to have_css('tr.generic-table--empty-row', text: 'There is currently nothing to display.') end def expect_user_locked(user) expect(page) - .to have_css("tr.user.locked td.username", text: user.login) + .to have_css('tr.user.locked td.username', text: user.login) end def filter_by_status(value) - select value, from: "Status:" - click_button "Apply" + select value, from: 'Status:' + click_button 'Apply' end def filter_by_name(value) - fill_in "Name", with: value - click_button "Apply" + fill_in 'Name', with: value + click_button 'Apply' end def clear_filters - click_link "Clear" + click_link 'Clear' end def order_by(key) - within "thead" do + within 'thead' do click_link key end end def lock_user(user) - click_user_button(user, "Lock permanently") + click_user_button(user, 'Lock permanently') end def activate_user(user) - click_user_button(user, "Activate") + click_user_button(user, 'Activate') end def reset_failed_logins(user) - click_user_button(user, "Reset failed logins") + click_user_button(user, 'Reset failed logins') end def unlock_user(user) - click_user_button(user, "Unlock") + click_user_button(user, 'Unlock') end def unlock_and_reset_user(user) - click_user_button(user, "Unlock and reset failed logins") + click_user_button(user, 'Unlock and reset failed logins') end def click_user_button(user, text) @@ -108,7 +108,7 @@ def click_user_button(user, text) private def within_user_row(user, &) - row = find("tr.user", text: user.login) + row = find('tr.user', text: user.login) within(row, &) end end diff --git a/spec/support/pages/custom_fields.rb b/spec/support/pages/custom_fields.rb index 8487c69a8cb9..9f0d078d88e0 100644 --- a/spec/support/pages/custom_fields.rb +++ b/spec/support/pages/custom_fields.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class CustomFields < Page def path - "/custom_fields" + '/custom_fields' end def visit_tab(name) visit! - within("content-tabs") do + within('content-tabs') do click_link name.to_s end end @@ -46,15 +46,15 @@ def select_format(label) end def set_name(name) - find_by_id("custom_field_name").set name + find_by_id('custom_field_name').set name end def set_default_value(value) - fill_in "custom_field[default_value]", with: value + fill_in 'custom_field[default_value]', with: value end def set_all_projects(value) - find_by_id("custom_field_is_for_all").set value + find_by_id('custom_field_is_for_all').set value end def has_form_element?(name) diff --git a/spec/support/pages/form_filler.rb b/spec/support/pages/form_filler.rb index 70484f907ebb..7cddc43319be 100644 --- a/spec/support/pages/form_filler.rb +++ b/spec/support/pages/form_filler.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages ## diff --git a/spec/support/pages/groups.rb b/spec/support/pages/groups.rb index 40bfbd13272c..3f53136f5460 100644 --- a/spec/support/pages/groups.rb +++ b/spec/support/pages/groups.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'support/pages/page' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' module Pages class Groups < Page def path - "/admin/groups" + '/admin/groups' end def edit_group!(group_name) @@ -52,16 +52,16 @@ def add_user_to_group!(user_name, group_name) def delete_group!(name) accept_alert do - find_group(name).find("a[data-method=delete]").click + find_group(name).find('a[data-method=delete]').click end end def find_group(name) - find("tr", text: name) + find('tr', text: name) end def has_group?(name) - has_selector? "tr", text: name + has_selector? 'tr', text: name end def group(group_name) @@ -82,14 +82,14 @@ def path end def open_users_tab! - within(".content--tabs") do - click_on "Users" + within('.content--tabs') do + click_on 'Users' end end def open_projects_tab! - within(".content--tabs") do - click_on "Projects" + within('.content--tabs') do + click_on 'Projects' end end @@ -98,59 +98,59 @@ def add_to_project!(project_name, as:) SeleniumHubWaiter.wait select_project! project_name Array(as).each { |role| check role } - click_on "Add" + click_on 'Add' end def remove_from_project!(name) open_projects_tab! SeleniumHubWaiter.wait - find_project(name).find("a[data-method=delete]").click + find_project(name).find('a[data-method=delete]').click end def search_for_project(query) autocomplete = page.find('[data-test-selector="membership_project_id"]') search_autocomplete autocomplete, query:, - results_selector: "body" + results_selector: 'body' end def find_project(name) - find("tr", text: name) + find('tr', text: name) end def has_project?(name) - has_selector? "tr", text: name + has_selector? 'tr', text: name end def select_project!(project_name) select_autocomplete page.find('[data-test-selector="membership_project_id"]'), query: project_name, select_text: project_name, - results_selector: "body" + results_selector: 'body' end def add_user!(user_name) open_users_tab! SeleniumHubWaiter.wait - select_autocomplete page.find(".new-group-members--autocomplete"), + select_autocomplete page.find('.new-group-members--autocomplete'), query: user_name - click_on "Add" + click_on 'Add' end def remove_user!(user_name) open_users_tab! SeleniumHubWaiter.wait - find_user(user_name).find("a[data-method=delete]").click + find_user(user_name).find('a[data-method=delete]').click end def find_user(user_name) - find("tr", text: user_name) + find('tr', text: user_name) end def has_user?(user_name) - has_selector? "tr", text: user_name + has_selector? 'tr', text: user_name end end end diff --git a/spec/support/pages/home.rb b/spec/support/pages/home.rb index 197ea00b131d..4e8de3735201 100644 --- a/spec/support/pages/home.rb +++ b/spec/support/pages/home.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class Home < Page diff --git a/spec/support/pages/messages/base.rb b/spec/support/pages/messages/base.rb index 90e8aaeed1d1..0d02f82ff4a8 100644 --- a/spec/support/pages/messages/base.rb +++ b/spec/support/pages/messages/base.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages::Messages class Base < ::Pages::Page diff --git a/spec/support/pages/messages/create.rb b/spec/support/pages/messages/create.rb index 708ee4e60bdf..816730eac165 100644 --- a/spec/support/pages/messages/create.rb +++ b/spec/support/pages/messages/create.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/messages/base" +require 'support/pages/messages/base' module Pages::Messages class Create < ::Pages::Messages::Base @@ -37,15 +37,15 @@ def initialize(forum) end def set_subject(subject) - fill_in "Subject", with: subject + fill_in 'Subject', with: subject end def add_text(text) - find(".ck-content").base.send_keys text + find('.ck-content').base.send_keys text end def click_save - click_button "Create" + click_button 'Create' end def created_message diff --git a/spec/support/pages/messages/index.rb b/spec/support/pages/messages/index.rb index 46c77ebc7583..5b6c16d42d5b 100644 --- a/spec/support/pages/messages/index.rb +++ b/spec/support/pages/messages/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/messages/base" +require 'support/pages/messages/base' module Pages::Messages class Index < ::Pages::Messages::Base @@ -41,24 +41,24 @@ def path end def click_create_message - click_on "Message" + click_on 'Message' ::Pages::Messages::Create.new(project.forums.first) end def expect_listed(subject:, replies: nil, last_message: nil) - subject = find("table tr td.subject", text: subject) + subject = find('table tr td.subject', text: subject) - row = subject.find(:xpath, "..") + row = subject.find(:xpath, '..') within(row) do - expect(page).to have_css("td.replies", text: replies) if replies - expect(page).to have_css("td.last_message", text: last_message) if last_message + expect(page).to have_css('td.replies', text: replies) if replies + expect(page).to have_css('td.last_message', text: last_message) if last_message end end def expect_num_replies(amount) - expect(page).to have_css("td.replies", text: amount) + expect(page).to have_css('td.replies', text: amount) end end end diff --git a/spec/support/pages/messages/show.rb b/spec/support/pages/messages/show.rb index f799008b6a38..708680bbbc7b 100644 --- a/spec/support/pages/messages/show.rb +++ b/spec/support/pages/messages/show.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/messages/base" +require 'support/pages/messages/base' module Pages::Messages class Show < Pages::Messages::Base @@ -37,15 +37,15 @@ def initialize(message) end def expect_subject(subject) - expect(page).to have_css(".title-container", text: subject) + expect(page).to have_css('.title-container', text: subject) end def expect_content(content) - expect(page).to have_css(".forum-message .wiki", text: content) + expect(page).to have_css('.forum-message .wiki', text: content) end def expect_no_replies - expect(page).to have_no_content("Replies") + expect(page).to have_no_content('Replies') end def expect_num_replies(num) @@ -53,11 +53,11 @@ def expect_num_replies(num) end def reply(text) - find(".ck-content").base.send_keys text + find('.ck-content').base.send_keys text - click_button "Submit" + click_button 'Submit' - expect(page).to have_css(".forum-message--comments", text:) + expect(page).to have_css('.forum-message--comments', text:) Message.last end @@ -65,36 +65,36 @@ def reply(text) def quote(content:, quoted_message: nil, subject: nil) if quoted_message within "#message-#{quoted_message.id} .contextual" do - click_on "Quote" + click_on 'Quote' end else within ".toolbar-items" do - click_on "Quote" + click_on 'Quote' end end sleep 1 - scroll_to_element find(".ck-content") - fill_in "reply_subject", with: subject if subject + scroll_to_element find('.ck-content') + fill_in 'reply_subject', with: subject if subject - editor = find(".ck-content") + editor = find('.ck-content') editor.base.send_keys content # For some reason, capybara will click on # the button to add another attachment when being told to click on "Submit". # Therefor, submitting by enter key. - subject_field = find_by_id("reply_subject") + subject_field = find_by_id('reply_subject') subject_field.native.send_keys(:return) text = (quoted_message || Message.first).content - expect(page).to have_css(".forum-message--comments blockquote", text:) + expect(page).to have_css('.forum-message--comments blockquote', text:) Message.last end def expect_reply(subject:, content:, reply: nil) - selector = ".comment" + selector = '.comment' selector += "#message-#{reply.id}" if reply within(selector) do @@ -109,7 +109,7 @@ def expect_current_path(reply = nil) end def click_save - click_button "Save" + click_button 'Save' end def path diff --git a/spec/support/pages/my/notifications.rb b/spec/support/pages/my/notifications.rb index d8b2a2bbcdaf..95dae9e59106 100644 --- a/spec/support/pages/my/notifications.rb +++ b/spec/support/pages/my/notifications.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/notifications/settings" +require 'support/pages/notifications/settings' module Pages module My diff --git a/spec/support/pages/my/password_page.rb b/spec/support/pages/my/password_page.rb index 7a9fda759d03..0b5a010414ff 100644 --- a/spec/support/pages/my/password_page.rb +++ b/spec/support/pages/my/password_page.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module My class PasswordPage < ::Pages::Page def path - "/my/password" + '/my/password' end def change_password(old_password, new_password, confirmation = new_password) SeleniumHubWaiter.wait - page.fill_in("password", with: old_password, match: :prefer_exact) - page.fill_in("new_password", with: new_password) - page.fill_in("new_password_confirmation", with: confirmation) + page.fill_in('password', with: old_password, match: :prefer_exact) + page.fill_in('new_password', with: new_password) + page.fill_in('new_password_confirmation', with: confirmation) - page.click_link_or_button "Save" + page.click_link_or_button 'Save' end def expect_password_reuse_error_message(count) expect_toast(type: :error, - message: I18n.t(:"activerecord.errors.models.user.attributes.password.reused", count:)) + message: I18n.t(:'activerecord.errors.models.user.attributes.password.reused', count:)) end def expect_password_weak_error_message @@ -56,7 +56,7 @@ def expect_password_weak_error_message def expect_password_updated_message expect(page) - .to have_css(".op-toast.-info", text: I18n.t(:notice_account_password_updated)) + .to have_css('.op-toast.-info', text: I18n.t(:notice_account_password_updated)) end private diff --git a/spec/support/pages/my/reminders.rb b/spec/support/pages/my/reminders.rb index b4d5bd5a4b9d..aeae97ebc16b 100644 --- a/spec/support/pages/my/reminders.rb +++ b/spec/support/pages/my/reminders.rb @@ -26,7 +26,7 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "support/pages/reminders/settings" +require 'support/pages/reminders/settings' module Pages module My diff --git a/spec/support/pages/new_placeholder_user.rb b/spec/support/pages/new_placeholder_user.rb index 15ae29d4ceee..6634f9d2724d 100644 --- a/spec/support/pages/new_placeholder_user.rb +++ b/spec/support/pages/new_placeholder_user.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class NewPlaceholderUser < Page def path - "/placeholder_users/new" + '/placeholder_users/new' end ## @@ -39,11 +39,11 @@ def path def fill_in!(fields = {}) form = FormFiller.new fields - form.fill! "Name", :name + form.fill! 'Name', :name end def submit! - click_button "Create" + click_button 'Create' end end end diff --git a/spec/support/pages/new_user.rb b/spec/support/pages/new_user.rb index affc7355ee8c..aea50dfbc32d 100644 --- a/spec/support/pages/new_user.rb +++ b/spec/support/pages/new_user.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class NewUser < Page def path - "/users/new" + '/users/new' end ## @@ -39,18 +39,18 @@ def path def fill_in!(fields = {}) form = FormFiller.new fields - form.fill! "First name", :first_name - form.fill! "Last name", :last_name - form.fill! "Email", :email + form.fill! 'First name', :first_name + form.fill! 'Last name', :last_name + form.fill! 'Email', :email - form.select! "Authentication source", :ldap_auth_source - form.fill! "Username", :login + form.select! 'Authentication source', :ldap_auth_source + form.fill! 'Username', :login - form.set_checked! "Administrator", :admin + form.set_checked! 'Administrator', :admin end def submit! - click_button "Create" + click_button 'Create' end end end diff --git a/spec/support/pages/notifications/settings.rb b/spec/support/pages/notifications/settings.rb index a0ee4d151c53..3cbecb3f8c95 100644 --- a/spec/support/pages/notifications/settings.rb +++ b/spec/support/pages/notifications/settings.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Notifications @@ -68,13 +68,13 @@ def expect_global_represented(setting) end def expect_project(project) - expect(page).to have_css("th", text: project.name) + expect(page).to have_css('th', text: project.name) end def add_project(project) - click_button "Add setting for project" + click_button 'Add setting for project' container = page.find('[data-test-selector="notification-setting-inline-create"] ng-select') - select_autocomplete container, query: project.name, results_selector: "body" + select_autocomplete container, query: project.name, results_selector: 'body' wait_for_network_idle if using_cuprite? expect_project project end @@ -127,8 +127,8 @@ def expect_no_project_date_alert_setting(label, project) end def save - click_button "Save" - expect_toast message: "Successful update." + click_button 'Save' + expect_toast message: 'Successful update.' end end end diff --git a/spec/support/pages/notifications/split_screen.rb b/spec/support/pages/notifications/split_screen.rb index 1b7a9aa02f2e..ff1690bf2365 100644 --- a/spec/support/pages/notifications/split_screen.rb +++ b/spec/support/pages/notifications/split_screen.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/split_work_package" +require 'support/pages/page' +require 'support/pages/work_packages/split_work_package' module Pages module Notifications @@ -36,7 +36,7 @@ class SplitScreen < ::Pages::SplitWorkPackage def initialize(work_package, project = nil) super(work_package, project) - @selector = ".work-packages--details" + @selector = '.work-packages--details' end end end diff --git a/spec/support/pages/page.rb b/spec/support/pages/page.rb index 150ecd08785e..890172bcdbaf 100644 --- a/spec/support/pages/page.rb +++ b/spec/support/pages/page.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../toasts/expectations" +require_relative '../toasts/expectations' module Pages class Page @@ -41,7 +41,7 @@ def current_page? end def visit! - raise "No path defined" unless path + raise 'No path defined' unless path visit path @@ -95,7 +95,7 @@ def expect_current_path(query_params = nil) end def click_to_sort_by(header_name) - within ".generic-table thead" do + within '.generic-table thead' do click_link header_name end end @@ -156,7 +156,7 @@ def path def navigate_to_modules_menu_item(link_title) visit root_path - within "#more-menu", visible: false do + within '#more-menu', visible: false do click_on link_title, visible: false end end diff --git a/spec/support/pages/projects/destroy.rb b/spec/support/pages/projects/destroy.rb index 8fb2b8d24c45..02a4244870ab 100644 --- a/spec/support/pages/projects/destroy.rb +++ b/spec/support/pages/projects/destroy.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "../page" +require_relative '../page' module Pages module Projects diff --git a/spec/support/pages/projects/index.rb b/spec/support/pages/projects/index.rb index 90c541f239c8..ef86fb6831b3 100644 --- a/spec/support/pages/projects/index.rb +++ b/spec/support/pages/projects/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Projects @@ -38,7 +38,7 @@ def path end def expect_listed(*users) - rows = page.all "td.username" + rows = page.all 'td.username' expect(rows.map(&:text)).to eq(users.map(&:login)) end @@ -77,42 +77,42 @@ def expect_title(name) end def expect_sidebar_filter(filter_name, selected: false) - within "#main-menu" do + within '#main-menu' do expect(page).to have_css(".op-sidemenu--item-action#{selected ? '.selected' : ''}", text: filter_name) end end def expect_no_sidebar_filter(filter_name) - within "#main-menu" do + within '#main-menu' do expect(page).to have_no_css(".op-sidemenu--item-action", text: filter_name) end end def expect_current_page_number(number) expect(page) - .to have_css(".op-pagination--item_current", text: number) + .to have_css('.op-pagination--item_current', text: number) end def expect_total_pages(number) expect(page) - .to have_css(".op-pagination--item", text: number) + .to have_css('.op-pagination--item', text: number) expect(page) - .to have_no_css(".op-pagination--item", text: number + 1) + .to have_no_css('.op-pagination--item', text: number + 1) end def set_sidebar_filter(filter_name) - within "#main-menu" do + within '#main-menu' do click_link text: filter_name end end def expect_filters_container_toggled - expect(page).to have_css(".op-filters-form") + expect(page).to have_css('.op-filters-form') end def expect_filters_container_hidden - expect(page).to have_css(".op-filters-form", visible: :hidden) + expect(page).to have_css('.op-filters-form', visible: :hidden) end def expect_filter_set(filter_name) @@ -126,79 +126,79 @@ def expect_no_project_create_button def expect_gantt_menu_entry(visible: false) if visible - expect(page).to have_link("Open as Gantt view") + expect(page).to have_link('Open as Gantt view') else - expect(page).to have_no_link("Open as Gantt view") + expect(page).to have_no_link('Open as Gantt view') end end def expect_columns(*column_names) column_names.each do |column_name| - expect(page).to have_css("th", text: column_name.upcase) + expect(page).to have_css('th', text: column_name.upcase) end end def expect_no_columns(*column_names) column_names.each do |column_name| - expect(page).to have_no_css("th", text: column_name.upcase) + expect(page).to have_no_css('th', text: column_name.upcase) end end def expect_no_save_as_notification expect(page) - .to have_no_link("Save as") + .to have_no_link('Save as') end def expect_save_as_notification expect(page) - .to have_link("Save as") + .to have_link('Save as') end def filter_by_active(value) - set_filter("active", - "Active", - "is", + set_filter('active', + 'Active', + 'is', [value]) - click_button "Apply" + click_button 'Apply' end def filter_by_public(value) - set_filter("public", - "Public", - "is", + set_filter('public', + 'Public', + 'is', [value]) - click_button "Apply" + click_button 'Apply' end def filter_by_membership(value) - set_filter("member_of", - "I am member", - "is", + set_filter('member_of', + 'I am member', + 'is', [value]) - click_button "Apply" + click_button 'Apply' end def set_filter(name, human_name, human_operator = nil, values = []) - select human_name, from: "add_filter_select" + select human_name, from: 'add_filter_select' selected_filter = page.find("li[filter-name='#{name}']") - select(human_operator, from: "operator") unless boolean_filter?(name) + select(human_operator, from: 'operator') unless boolean_filter?(name) within(selected_filter) do return unless values.any? - if name == "name_and_identifier" + if name == 'name_and_identifier' set_name_and_identifier_filter(values) elsif boolean_filter?(name) set_toggle_filter(values) - elsif name == "created_at" - select(human_operator, from: "operator") + elsif name == 'created_at' + select(human_operator, from: 'operator') set_created_at_filter(human_operator, values) elsif /cf_\d+/.match?(name) - select(human_operator, from: "operator") + select(human_operator, from: 'operator') set_custom_field_filter(selected_filter, human_operator, values) end end @@ -209,13 +209,13 @@ def remove_filter(name) end def apply_filters - within(".advanced-filters--filters") do - click_on "Apply" + within('.advanced-filters--filters') do + click_on 'Apply' end end def set_toggle_filter(values) - should_active = values.first == "yes" + should_active = values.first == 'yes' is_active = page.has_selector? '[data-test-selector="spot-switch-handle"][data-qa-active]' if should_active != is_active @@ -230,28 +230,28 @@ def set_toggle_filter(values) end def set_name_and_identifier_filter(values) - fill_in "value", with: values.first + fill_in 'value', with: values.first end def set_created_at_filter(human_operator, values) case human_operator - when "on", "less than days ago", "more than days ago", "days ago" - fill_in "value", with: values.first - when "between" - fill_in "from_value", with: values.first - fill_in "to_value", with: values.second + when 'on', 'less than days ago', 'more than days ago', 'days ago' + fill_in 'value', with: values.first + when 'between' + fill_in 'from_value', with: values.first + fill_in 'to_value', with: values.second end end def set_custom_field_filter(selected_filter, human_operator, values) - if selected_filter[:"filter-type"] == "list_optional" + if selected_filter[:'filter-type'] == 'list_optional' if values.size == 1 value_select = find('.single-select select[name="value"]') value_select.select values.first end - elsif selected_filter[:"filter-type"] == "date" - if human_operator == "on" - fill_in "value", with: values.first + elsif selected_filter[:'filter-type'] == 'date' + if human_operator == 'on' + fill_in 'value', with: values.first end end end @@ -259,43 +259,43 @@ def set_custom_field_filter(selected_filter, human_operator, values) def open_filters retry_block do page.find('[data-test-selector="filter-component-toggle"]').click - page.find_field("Add filter", visible: true) + page.find_field('Add filter', visible: true) end end def set_columns(*columns) - click_more_menu_item(I18n.t(:"queries.configure_view.heading")) + click_more_menu_item(I18n.t(:'queries.configure_view.heading')) # Assumption: there is always one item selected, the 'Name' column # That column can currently not be removed. # Serves as a safeguard - page.find(".op-draggable-autocomplete--item", text: "Name") + page.find('.op-draggable-autocomplete--item', text: 'Name') not_protected_columns = Regexp.new("^(?!#{(columns + ['Name']).join('$|')}$).*$") - while (item = page.all(".op-draggable-autocomplete--item", text: not_protected_columns)[0]) - item.find(".op-draggable-autocomplete--remove-item").click + while (item = page.all('.op-draggable-autocomplete--item', text: not_protected_columns)[0]) + item.find('.op-draggable-autocomplete--remove-item').click end - remaining_columns = page.all(".op-draggable-autocomplete--item").map { |i| i.text.downcase } + remaining_columns = page.all('.op-draggable-autocomplete--item').map { |i| i.text.downcase } columns.each do |column| next if remaining_columns.include?(column.downcase) - select_autocomplete find(".op-draggable-autocomplete--input"), - results_selector: ".ng-dropdown-panel-items", + select_autocomplete find('.op-draggable-autocomplete--input'), + results_selector: '.ng-dropdown-panel-items', query: column end - within "dialog" do - click_on "Apply" + within 'dialog' do + click_on 'Apply' end end def click_more_menu_item(item) page.find('[data-test-selector="project-more-dropdown-menu"]').click - page.find(".ActionListItem", text: item, exact_text: true).click + page.find('.ActionListItem', text: item, exact_text: true).click end def click_menu_item_of(title, project) @@ -307,10 +307,10 @@ def click_menu_item_of(title, project) def activate_menu_of(project) within_row(project) do |row| row.hover - menu = find("ul.project-actions") + menu = find('ul.project-actions') menu.click wait_for_network_idle if using_cuprite? - expect(page).to have_css(".menu-drop-down-container") + expect(page).to have_css('.menu-drop-down-container') yield menu end end @@ -320,43 +320,43 @@ def navigate_to_new_project_page_from_toolbar_items end def save_query(name) - click_more_menu_item("Save as") + click_more_menu_item('Save as') within '[data-test-selector="project-query-name"]' do - fill_in "Name", with: name + fill_in 'Name', with: name end - click_on "Save" + click_on 'Save' end def delete_query - click_more_menu_item("Delete") + click_more_menu_item('Delete') within '[data-test-selector="op-project-list-delete-dialog"]' do - click_on "Delete" + click_on 'Delete' end end def sort_by(column_name) - find(".generic-table--sort-header a", text: column_name.upcase).click + find('.generic-table--sort-header a', text: column_name.upcase).click end def set_page_size(size) - find(".op-pagination--options .op-pagination--item", text: size).click + find('.op-pagination--options .op-pagination--item', text: size).click end def go_to_page(page_number) - within ".op-pagination--pages" do - find(".op-pagination--item-link", text: page_number).click + within '.op-pagination--pages' do + find('.op-pagination--item-link', text: page_number).click end end def within_table(&) - within "#project-table", & + within '#project-table', & end def within_row(project) - row = page.find("#project-table tr", text: project.name) + row = page.find('#project-table tr', text: project.name) within row do yield row diff --git a/spec/support/pages/projects/settings.rb b/spec/support/pages/projects/settings.rb index f6b2b67ece0d..8ddf6e7aac10 100644 --- a/spec/support/pages/projects/settings.rb +++ b/spec/support/pages/projects/settings.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Projects @@ -74,7 +74,7 @@ def activate_wp_custom_field(custom_field) end def save! - click_button "Save" + click_button 'Save' end def expect_wp_custom_field(custom_field, active = true) @@ -83,7 +83,7 @@ def expect_wp_custom_field(custom_field, active = true) end def fieldset_label - find "fieldset#project_issue_custom_fields label" + find 'fieldset#project_issue_custom_fields label' end private diff --git a/spec/support/pages/reminders/settings.rb b/spec/support/pages/reminders/settings.rb index c309f964d9d8..3e2ff886009f 100644 --- a/spec/support/pages/reminders/settings.rb +++ b/spec/support/pages/reminders/settings.rb @@ -26,7 +26,7 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Reminders @@ -43,7 +43,7 @@ def path end def add_time - click_button "Add time" + click_button 'Add time' end def set_time(label, time) @@ -110,9 +110,9 @@ def set_workdays(days) def expect_paused(paused, first: nil, last: nil) if paused - expect(page).to have_checked_field "Temporarily pause daily email reminders" + expect(page).to have_checked_field 'Temporarily pause daily email reminders' else - expect(page).to have_no_checked_field "Temporarily pause daily email reminders" + expect(page).to have_no_checked_field 'Temporarily pause daily email reminders' end if first && last @@ -123,20 +123,20 @@ def expect_paused(paused, first: nil, last: nil) def set_paused(paused, first: nil, last: nil) if paused - check "Temporarily pause daily email reminders" + check 'Temporarily pause daily email reminders' - page.find("op-basic-range-date-picker input").click + page.find('op-basic-range-date-picker input').click datepicker = ::Components::RangeDatepicker.new datepicker.set_date first datepicker.set_date last else - uncheck "Temporarily pause daily email reminders" + uncheck 'Temporarily pause daily email reminders' end end def save - click_button I18n.t("js.button_save") + click_button I18n.t('js.button_save') end end end diff --git a/spec/support/pages/types/index.rb b/spec/support/pages/types/index.rb index 140bcf1f7485..46a5e4fd6828 100644 --- a/spec/support/pages/types/index.rb +++ b/spec/support/pages/types/index.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages module Types @@ -36,7 +36,7 @@ def path end def expect_listed(*types) - rows = page.all "td.timelines-pet-name" + rows = page.all 'td.timelines-pet-name' expected = types.map { |t| canonical_name(t) } @@ -52,8 +52,8 @@ def expect_successful_update end def click_new - within ".toolbar-items" do - click_link "Type" + within '.toolbar-items' do + click_link 'Type' end end @@ -66,7 +66,7 @@ def click_edit(type) def delete(type) accept_alert do within_row(type) do - find(".icon-delete").click + find('.icon-delete').click end end end @@ -74,7 +74,7 @@ def delete(type) private def within_row(type) - row = page.find("table tr", text: canonical_name(type)) + row = page.find('table tr', text: canonical_name(type)) within row do yield row diff --git a/spec/support/pages/versions/roadmap.rb b/spec/support/pages/versions/roadmap.rb index f416f2e157e7..3739523dea8c 100644 --- a/spec/support/pages/versions/roadmap.rb +++ b/spec/support/pages/versions/roadmap.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "support/pages/page" +require 'support/pages/page' module Pages module Versions @@ -42,33 +42,33 @@ def initialize(project:) end def apply_filter(filter_name) - within "#menu-sidebar" do + within '#menu-sidebar' do check filter_name - click_on "Apply" + click_on 'Apply' end end def remove_filter(filter_name) - within "#menu-sidebar" do + within '#menu-sidebar' do uncheck filter_name - click_on "Apply" + click_on 'Apply' end end def expect_filter_set(filter_name) - within "#menu-sidebar" do + within '#menu-sidebar' do expect(page).to have_checked_field(filter_name) end end def expect_filter_not_set(filter_name) - within "#menu-sidebar" do + within '#menu-sidebar' do expect(page).to have_no_checked_field(filter_name) end end def expect_versions_listed(*versions) - within "#roadmap" do + within '#roadmap' do versions.each do |version| expect(page).to have_content version.name end @@ -76,7 +76,7 @@ def expect_versions_listed(*versions) end def expect_versions_not_listed(*versions) - within "#roadmap" do + within '#roadmap' do versions.each do |version| expect(page).to have_no_content version.name end diff --git a/spec/support/pages/work_packages/abstract_work_package.rb b/spec/support/pages/work_packages/abstract_work_package.rb index 5e5df98cb476..9af4ea4aaf8d 100644 --- a/spec/support/pages/work_packages/abstract_work_package.rb +++ b/spec/support/pages/work_packages/abstract_work_package.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class AbstractWorkPackage < Page @@ -46,15 +46,15 @@ def visit_tab!(tab) end def switch_to_tab(tab:) - find(".op-tab-row--link", text: tab.upcase).click + find('.op-tab-row--link', text: tab.upcase).click end def expect_tab(tab) - expect(page).to have_css(".op-tab-row--link_selected", text: tab.to_s.upcase) + expect(page).to have_css('.op-tab-row--link_selected', text: tab.to_s.upcase) end def within_active_tab(&) - within(".work-packages-full-view--split-right .work-packages--panel-inner", &) + within('.work-packages-full-view--split-right .work-packages--panel-inner', &) end def edit_field(attribute) @@ -64,7 +64,7 @@ def edit_field(attribute) def custom_edit_field(custom_field) edit_field(custom_field.attribute_name(:camel_case)).tap do |field| if custom_field.list? - field.field_type = "create-autocompleter" + field.field_type = 'create-autocompleter' end end end @@ -96,12 +96,12 @@ def expect_subject end def open_in_split_view - find_by_id("work-packages-details-view-button").click + find_by_id('work-packages-details-view-button').click end def ensure_page_loaded expect_angular_frontend_initialized - expect(page).to have_css(".op-user-activity--user-name", + expect(page).to have_css('.op-user-activity--user-name', text: work_package.journals.last.user.name, minimum: 1, wait: 10) @@ -114,20 +114,20 @@ def disable_ajax_requests end def expect_group(name, &) - expect(page).to have_css(".attributes-group--header-text", text: name.upcase) + expect(page).to have_css('.attributes-group--header-text', text: name.upcase) if block_given? page.within(".attributes-group[data-group-name='#{name}']", &) end end def expect_no_group(name) - expect(page).to have_no_css(".attributes-group--header-text", text: name.upcase) + expect(page).to have_no_css('.attributes-group--header-text', text: name.upcase) end def expect_attributes(attribute_expectations) attribute_expectations.each do |label_name, value| label = label_name.to_s - if label == "status" + if label == 'status' expect(page).to have_css("[data-test-selector='op-wp-status-button'] .button", text: value) else expect(page).to have_css(".inline-edit--container.#{label.camelize(:lower)}", text: value) @@ -141,52 +141,52 @@ def expect_no_attribute(label) alias :expect_attribute_hidden :expect_no_attribute def expect_activity(user, number: nil) - container = "#work-package-activites-container" + container = '#work-package-activites-container' container += " #activity-#{number}" if number expect(page).to have_css("#{container} .op-user-activity--user-line", text: user.name) end def expect_activity_message(message) - expect(page).to have_css(".work-package-details-activities-messages .message", + expect(page).to have_css('.work-package-details-activities-messages .message', text: message) end def expect_no_parent - visit_tab!("relations") + visit_tab!('relations') expect(page).to have_no_css('[data-test-selector="op-wp-breadcrumb-parent"]') end def expect_zen_mode - expect(page).to have_css(".zen-mode") - expect(page).to have_css("#main-menu", visible: :hidden) - expect(page).to have_css(".op-app-header", visible: :hidden) + expect(page).to have_css('.zen-mode') + expect(page).to have_css('#main-menu', visible: :hidden) + expect(page).to have_css('.op-app-header', visible: :hidden) end def expect_no_zen_mode - expect(page).to have_no_css(".zen-mode") - expect(page).to have_css("#main-menu") - expect(page).to have_css(".op-app-header") + expect(page).to have_no_css('.zen-mode') + expect(page).to have_css('#main-menu') + expect(page).to have_css('.op-app-header') end def expect_custom_action(name) expect(page) - .to have_css(".custom-action", text: name) + .to have_css('.custom-action', text: name) end def expect_custom_action_disabled(name) expect(page) - .to have_css(".custom-action [disabled]", text: name) + .to have_css('.custom-action [disabled]', text: name) end def expect_no_custom_action(name) expect(page) - .to have_no_css(".custom-action", text: name) + .to have_no_css('.custom-action', text: name) end def expect_custom_action_order(*names) - within(".custom-actions") do + within('.custom-actions') do names.each_cons(2) do |earlier, later| body.index(earlier) < body.index(later) end @@ -231,7 +231,7 @@ def work_package_field(key) def work_package_custom_field(key, id) cf = CustomField.find id - if cf.field_format == "text" + if cf.field_format == 'text' TextEditorField.new container, key else EditField.new container, key @@ -239,10 +239,10 @@ def work_package_custom_field(key, id) end def add_child - visit_tab!("relations") + visit_tab!('relations') - page.find(".wp-inline-create--add-link", - text: I18n.t("js.relation_buttons.add_new_child")).click + page.find('.wp-inline-create--add-link', + text: I18n.t('js.relation_buttons.add_new_child')).click create_page(parent_work_package: work_package) end @@ -255,59 +255,59 @@ def visit_copy! end def click_custom_action(name, expect_success: true) - page.within(".custom-actions") do + page.within('.custom-actions') do click_button(name) end if expect_success - expect_and_dismiss_toaster message: "Successful update" + expect_and_dismiss_toaster message: 'Successful update' wait_for_network_idle end end def trigger_edit_mode - page.click_button(I18n.t("js.button_edit")) + page.click_button(I18n.t('js.button_edit')) end def trigger_edit_comment - add_comment_container.find(".work-package-comment").click + add_comment_container.find('.work-package-comment').click end def update_comment(comment) - editor = ::Components::WysiwygEditor.new ".work-packages--activity--add-comment" + editor = ::Components::WysiwygEditor.new '.work-packages--activity--add-comment' editor.click_and_type_slowly comment end def save_comment - label = "Comment: Save" + label = 'Comment: Save' add_comment_container.find(:xpath, "//button[@title='#{label}']").click end def save! - page.click_button(I18n.t("js.button_save")) + page.click_button(I18n.t('js.button_save')) end def add_comment_container - find(".work-packages--activity--add-comment") + find('.work-packages--activity--add-comment') end def click_add_wp_button - find(".add-work-package:not([disabled])", text: "Work package").click + find('.add-work-package:not([disabled])', text: 'Work package').click end def click_create_wp_button(type) - find(".add-work-package:not([disabled])", text: "Create").click + find('.add-work-package:not([disabled])', text: 'Create').click - find("#types-context-menu .menu-item", text: type.name.upcase, wait: 10).click + find('#types-context-menu .menu-item', text: type.name.upcase, wait: 10).click end def subject_field - expect(page).to have_css(".inline-edit--container.subject input", wait: 10) - find(".inline-edit--container.subject input") + expect(page).to have_css('.inline-edit--container.subject input', wait: 10) + find('.inline-edit--container.subject input') end def go_back - find(".work-packages-back-button").click + find('.work-packages-back-button').click end def mark_notifications_as_read @@ -321,9 +321,9 @@ def create_page(_args) end def ensure_no_conflicting_modifications - expect_toast(message: "Successful update") + expect_toast(message: 'Successful update') dismiss_toaster! - expect_no_toaster(message: "Successful update") + expect_no_toaster(message: 'Successful update') end end end diff --git a/spec/support/pages/work_packages/abstract_work_package_create.rb b/spec/support/pages/work_packages/abstract_work_package_create.rb index ef638e783445..d96bbf225951 100644 --- a/spec/support/pages/work_packages/abstract_work_package_create.rb +++ b/spec/support/pages/work_packages/abstract_work_package_create.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/abstract_work_package" +require 'support/pages/page' +require 'support/pages/work_packages/abstract_work_package' module Pages class AbstractWorkPackageCreate < AbstractWorkPackage @@ -59,15 +59,15 @@ def select_attribute(property, value) def expect_fully_loaded expect_angular_frontend_initialized - expect(page).to have_css "#wp-new-inline-edit--field-subject", wait: 20 + expect(page).to have_css '#wp-new-inline-edit--field-subject', wait: 20 end def save! - scroll_to_and_click find(".button", text: I18n.t("js.button_save")) + scroll_to_and_click find('.button', text: I18n.t('js.button_save')) end def cancel! - scroll_to_and_click find(".button", text: I18n.t("js.button_cancel")) + scroll_to_and_click find('.button', text: I18n.t('js.button_cancel')) end end end diff --git a/spec/support/pages/work_packages/concerns/work_package_by_button_creator.rb b/spec/support/pages/work_packages/concerns/work_package_by_button_creator.rb index 68643d7f05e8..b615acf41dba 100644 --- a/spec/support/pages/work_packages/concerns/work_package_by_button_creator.rb +++ b/spec/support/pages/work_packages/concerns/work_package_by_button_creator.rb @@ -33,37 +33,37 @@ module WorkPackageByButtonCreator def create_wp_by_button(type) click_wp_create_button - find("#types-context-menu .menu-item", text: type.name.upcase, wait: 10).click + find('#types-context-menu .menu-item', text: type.name.upcase, wait: 10).click create_page_class_instance(type) end def click_wp_create_button - find(".add-work-package:not([disabled])", text: "Create").click + find('.add-work-package:not([disabled])', text: 'Create').click end def expect_wp_create_button expect(page) - .to have_css(".add-work-package:not([disabled])", text: "Create") + .to have_css('.add-work-package:not([disabled])', text: 'Create') end def expect_wp_create_button_disabled expect(page) - .to have_css(".add-work-package[disabled]", text: "Create") + .to have_css('.add-work-package[disabled]', text: 'Create') end def expect_type_available_for_create(type) click_wp_create_button expect(page) - .to have_css("#types-context-menu .menu-item", text: type.name.upcase) + .to have_css('#types-context-menu .menu-item', text: type.name.upcase) end def expect_type_not_available_for_create(type) click_wp_create_button expect(page) - .to have_no_css("#types-context-menu .menu-item", text: type.name.upcase) + .to have_no_css('#types-context-menu .menu-item', text: type.name.upcase) end private diff --git a/spec/support/pages/work_packages/embedded_work_packages_table.rb b/spec/support/pages/work_packages/embedded_work_packages_table.rb index a50d88ebddfd..a28c4d7ec4df 100644 --- a/spec/support/pages/work_packages/embedded_work_packages_table.rb +++ b/spec/support/pages/work_packages/embedded_work_packages_table.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/work_packages_table" -require "support/components/autocompleter/ng_select_autocomplete_helpers" +require 'support/pages/page' +require 'support/pages/work_packages/work_packages_table' +require 'support/components/autocompleter/ng_select_autocomplete_helpers' module Pages class EmbeddedWorkPackagesTable < WorkPackagesTable @@ -42,7 +42,7 @@ def initialize(container, project = nil) end def table_container - container.find(".work-package-table") + container.find('.work-package-table') end def click_reference_inline_create @@ -58,7 +58,7 @@ def reference_work_package(work_package, query: work_package.subject) autocomplete_container = container.find('[data-test-selector="wp-relations-autocomplete"]') select_autocomplete autocomplete_container, query:, - results_selector: ".ng-dropdown-panel-items", + results_selector: '.ng-dropdown-panel-items', wait_for_fetched_options: false expect_work_package_listed work_package diff --git a/spec/support/pages/work_packages/full_work_package.rb b/spec/support/pages/work_packages/full_work_package.rb index a235fc0bead0..8ec2fe034c3b 100644 --- a/spec/support/pages/work_packages/full_work_package.rb +++ b/spec/support/pages/work_packages/full_work_package.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/work_packages/abstract_work_package" +require 'support/pages/work_packages/abstract_work_package' module Pages class FullWorkPackage < Pages::AbstractWorkPackage def ensure_loaded - find(".work-packages--details--subject", match: :first) + find('.work-packages--details--subject', match: :first) end def toolbar - find_by_id("toolbar-items") + find_by_id('toolbar-items') end def click_share_button @@ -46,23 +46,23 @@ def click_share_button # include waiting for other network requests unrelated to # sharing), waiting for the button to be present makes # the spec a tad faster. - click_button("Share", wait: 10) + click_button('Share', wait: 10) end end def expect_share_button_count(count) - page.within_test_selector("op-wp-share-button") do - expect(page).to have_css(".badge", text: count, wait: 10) + page.within_test_selector('op-wp-share-button') do + expect(page).to have_css('.badge', text: count, wait: 10) end end private def container - find(".work-packages--show-view") + find('.work-packages--show-view') end - def path(tab = "activity") + def path(tab = 'activity') if project project_work_package_path(project, work_package.id, tab) else diff --git a/spec/support/pages/work_packages/full_work_package_create.rb b/spec/support/pages/work_packages/full_work_package_create.rb index 15f953370da2..71407d3532e1 100644 --- a/spec/support/pages/work_packages/full_work_package_create.rb +++ b/spec/support/pages/work_packages/full_work_package_create.rb @@ -26,20 +26,20 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/abstract_work_package_create" +require 'support/pages/page' +require 'support/pages/work_packages/abstract_work_package_create' module Pages class FullWorkPackageCreate < AbstractWorkPackageCreate private def container - find(".work-packages--show-view") + find('.work-packages--show-view') end def path if original_work_package - project_work_package_path(original_work_package.project, original_work_package.id) + "/copy" + project_work_package_path(original_work_package.project, original_work_package.id) + '/copy' elsif parent_work_package new_project_work_packages_path(parent_work_package.project.identifier, parent_id: parent_work_package.id) diff --git a/spec/support/pages/work_packages/split_work_package.rb b/spec/support/pages/work_packages/split_work_package.rb index bbd5e28836c7..b26b4e8d8a94 100644 --- a/spec/support/pages/work_packages/split_work_package.rb +++ b/spec/support/pages/work_packages/split_work_package.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/work_packages/abstract_work_package" -require "support/pages/work_packages/split_work_package_create" +require 'support/pages/work_packages/abstract_work_package' +require 'support/pages/work_packages/split_work_package_create' module Pages class SplitWorkPackage < Pages::AbstractWorkPackage @@ -35,11 +35,11 @@ class SplitWorkPackage < Pages::AbstractWorkPackage def initialize(work_package, project = nil) super(work_package, project) - @selector = ".work-packages--details" + @selector = '.work-packages--details' end def switch_to_fullscreen - find(".work-packages--details-fullscreen-icon").click + find('.work-packages--details-fullscreen-icon').click FullWorkPackage.new(work_package, project) end @@ -54,7 +54,7 @@ def expect_open end def close - find(".work-packages--details-close-icon").click + find('.work-packages--details-close-icon').click end def container @@ -63,7 +63,7 @@ def container protected - def path(tab = "overview") + def path(tab = 'overview') state = "#{work_package.id}/#{tab}" if project diff --git a/spec/support/pages/work_packages/split_work_package_create.rb b/spec/support/pages/work_packages/split_work_package_create.rb index 8212a1a9162c..4483687a3afd 100644 --- a/spec/support/pages/work_packages/split_work_package_create.rb +++ b/spec/support/pages/work_packages/split_work_package_create.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/abstract_work_package_create" +require 'support/pages/page' +require 'support/pages/work_packages/abstract_work_package_create' module Pages class SplitWorkPackageCreate < AbstractWorkPackageCreate @@ -38,7 +38,7 @@ def initialize(project:, original_work_package: nil, parent_work_package: nil) end def container - find(".work-packages--new") + find('.work-packages--new') end private @@ -47,7 +47,7 @@ def path if original_work_package project_work_packages_path(project) + "/details/#{original_work_package.id}/copy" else - path = project_work_packages_path(project) + "/create_new" + path = project_work_packages_path(project) + '/create_new' path += "?parent_id=#{parent_work_package.id}" if parent_work_package path diff --git a/spec/support/pages/work_packages/work_package_card.rb b/spec/support/pages/work_packages/work_package_card.rb index 6c94aa32d4c1..326ca58fff85 100644 --- a/spec/support/pages/work_packages/work_package_card.rb +++ b/spec/support/pages/work_packages/work_package_card.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class WorkPackageCard < Page diff --git a/spec/support/pages/work_packages/work_package_cards.rb b/spec/support/pages/work_packages/work_package_cards.rb index 7aea30466d75..6099688f78c5 100644 --- a/spec/support/pages/work_packages/work_package_cards.rb +++ b/spec/support/pages/work_packages/work_package_cards.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" +require 'support/pages/page' module Pages class WorkPackageCards < Page @@ -37,7 +37,7 @@ def initialize(project = nil) end def expect_work_package_count(count) - expect(page).to have_css("wp-single-card", count:, wait: 20) + expect(page).to have_css('wp-single-card', count:, wait: 20) end def expect_work_package_listed(*work_packages) @@ -54,9 +54,9 @@ def expect_work_package_not_listed(*work_packages) def expect_work_package_order(*ids) retry_block do - rows = page.all "wp-single-card" + rows = page.all 'wp-single-card' expected = ids.map { |el| el.is_a?(WorkPackage) ? el.id.to_s : el.to_s } - found = rows.map { |el| el["data-work-package-id"] } + found = rows.map { |el| el['data-work-package-id'] } raise "Order is incorrect: #{found.inspect} != #{expected.inspect}" unless found == expected end @@ -68,7 +68,7 @@ def open_full_screen_by_doubleclick(work_package) page.driver.browser.action.double_click(card(work_package).native).perform # Ensure we show the subject field - page.find(".work-packages--subject-type-row") + page.find('.work-packages--subject-type-row') end Pages::FullWorkPackage.new(work_package, project) @@ -85,7 +85,7 @@ def open_split_view_by_info_icon(work_package) end def drag_and_drop_work_package(from:, to:) - drag_and_drop_list(from:, to:, elements: "wp-single-card", handler: ".op-wp-single-card--content") + drag_and_drop_list(from:, to:, elements: 'wp-single-card', handler: '.op-wp-single-card--content') end def select_work_package(work_package) @@ -100,7 +100,7 @@ def click_info_icon(work_package) def click_id_link(work_package) card_element = card(work_package) - card_element.find(".__ui-state-link").click + card_element.find('.__ui-state-link').click end def deselect_work_package(work_package) @@ -122,13 +122,13 @@ def select_work_package_with_shift(work_package) end def select_all_work_packages - find("body").send_keys [:control, "a"] - expect(page).to have_no_css "#work-package-context-menu" + find('body').send_keys [:control, 'a'] + expect(page).to have_no_css '#work-package-context-menu' end def deselect_all_work_packages - find("body").send_keys [:control, "d"] - expect(page).to have_no_css "#work-package-context-menu" + find('body').send_keys [:control, 'd'] + expect(page).to have_no_css '#work-package-context-menu' end def card(work_package) diff --git a/spec/support/pages/work_packages/work_packages_table.rb b/spec/support/pages/work_packages/work_packages_table.rb index 120169e29cb5..d1f82e2b263c 100644 --- a/spec/support/pages/work_packages/work_packages_table.rb +++ b/spec/support/pages/work_packages/work_packages_table.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require_relative "concerns/work_package_by_button_creator" +require 'support/pages/page' +require_relative 'concerns/work_package_by_button_creator' module Pages class WorkPackagesTable < Page @@ -154,9 +154,9 @@ def ensure_work_package_not_listed!(*work_packages) # objects. def expect_work_package_order(*ids) retry_block do - rows = page.all ".work-package-table .wp--row" + rows = page.all '.work-package-table .wp--row' expected = ids.map { |el| el.is_a?(WorkPackage) ? el.id.to_s : el.to_s } - found = rows.map { |el| el["data-work-package-id"] } + found = rows.map { |el| el['data-work-package-id'] } raise "Order is incorrect: #{found.inspect} != #{expected.inspect}" unless found == expected end @@ -165,7 +165,7 @@ def expect_work_package_order(*ids) # Expects no work packages to be listed in the table. def expect_no_work_package_listed within(table_container) do - expect(page).to have_css("#empty-row-notification") + expect(page).to have_css('#empty-row-notification') end end @@ -176,10 +176,10 @@ def expect_no_work_package_listed # editable. def expect_title(name, editable: true) if editable - expect(page).to have_field("editable-toolbar-title", with: name, wait: 10) + expect(page).to have_field('editable-toolbar-title', with: name, wait: 10) else expect(page) - .to have_css(".toolbar-container", text: name, wait: 10) + .to have_css('.toolbar-container', text: name, wait: 10) end end @@ -187,10 +187,10 @@ def expect_title(name, editable: true) # # @param name [String] The name of the query. def expect_query_in_select_dropdown(name) - page.find(".title-container").click + page.find('.title-container').click - page.within("#viewSelect") do - expect(page).to have_css(".op-sidemenu--item-action", text: name) + page.within('#viewSelect') do + expect(page).to have_css('.op-sidemenu--item-action', text: name) end end @@ -202,7 +202,7 @@ def click_inline_create sleep 3 container.find('[data-test-selector="op-wp-inline-create"]').click - expect(container).to have_css(".wp-inline-create-row", wait: 10) + expect(container).to have_css('.wp-inline-create-row', wait: 10) end # Opens the split view for the specified work package. @@ -216,7 +216,7 @@ def open_split_view(work_package) row_element = row(work_package) row_element.hover - scroll_to_and_click(row_element.find(".wp-table--details-link")) + scroll_to_and_click(row_element.find('.wp-table--details-link')) split_page end @@ -237,7 +237,7 @@ def click_on_row(work_package) def open_full_screen_by_doubleclick(work_package) loading_indicator_saveguard # The 'id' column should have enough space to be clicked - click_target = row(work_package).find(".inline-edit--display-field.id") + click_target = row(work_package).find('.inline-edit--display-field.id') page.driver.browser.action.double_click(click_target.native).perform FullWorkPackage.new(work_package, project) @@ -259,7 +259,7 @@ def open_full_screen_by_link(work_package) # @param from [WorkPackage] The source work package object. # @param to [WorkPackage] The target work package object. def drag_and_drop_work_package(from:, to:) - drag_and_drop_list(from:, to:, elements: ".wp-table--row", handler: ".wp-table--drag-and-drop-handle") + drag_and_drop_list(from:, to:, elements: '.wp-table--row', handler: '.wp-table--drag-and-drop-handle') end # Returns the row element for the specified work package. @@ -287,7 +287,7 @@ def row_selector(elem) def edit_field(work_package, attribute) context = if work_package.nil? - table_container.find(".wp-inline-create-row") + table_container.find('.wp-inline-create-row') else row(work_package) end @@ -324,16 +324,16 @@ def click_setting_item(label) # If `false` it will save through the context menu.. def save_as(name, by_title: false) if by_title - title_input = find(".editable-toolbar-title--input") + title_input = find('.editable-toolbar-title--input') title_input.set(name) title_input.send_keys(:enter) else - click_setting_item "Save as" - fill_in "save-query-name", with: name - click_button "Save" + click_setting_item 'Save as' + fill_in 'save-query-name', with: name + click_button 'Save' end - expect_toast message: "Successful creation." + expect_toast message: 'Successful creation.' expect_title name end @@ -343,7 +343,7 @@ def save end def table_container - find("#content .work-packages-split-view--tabletimeline-side") + find('#content .work-packages-split-view--tabletimeline-side') end def work_package_container(work_package) @@ -377,12 +377,12 @@ def path def get_filter_name(label) retry_block do - label_field = page.find(".advanced-filters--filter-name", text: label) - filter_container = label_field.find(:xpath, "..") + label_field = page.find('.advanced-filters--filter-name', text: label) + filter_container = label_field.find(:xpath, '..') - raise "Missing ID on Filter (Angular not ready?)" if filter_container["id"].nil? + raise 'Missing ID on Filter (Angular not ready?)' if filter_container['id'].nil? - filter_container["id"].gsub("filter_", "") + filter_container['id'].gsub('filter_', '') end end diff --git a/spec/support/pages/work_packages/work_packages_timeline.rb b/spec/support/pages/work_packages/work_packages_timeline.rb index b76802b9230b..0bbdc7acc3e8 100644 --- a/spec/support/pages/work_packages/work_packages_timeline.rb +++ b/spec/support/pages/work_packages/work_packages_timeline.rb @@ -26,8 +26,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "support/pages/page" -require "support/pages/work_packages/work_packages_table" +require 'support/pages/page' +require 'support/pages/work_packages/work_packages_table' module Pages class WorkPackagesTimeline < WorkPackagesTable @@ -40,12 +40,12 @@ def timeline_row_selector(wp_id) end def timeline_container - ".work-packages-tabletimeline--timeline-side" + '.work-packages-tabletimeline--timeline-side' end def expect_row_count(num) within(timeline_container) do - expect(page).to have_css(".wp-timeline-cell", count: num) + expect(page).to have_css('.wp-timeline-cell', count: num) end end @@ -69,9 +69,9 @@ def expect_work_package_not_listed(*work_packages) def expect_work_package_order(*ids) retry_block do - rows = page.all(".wp-table-timeline--body .wp--row") + rows = page.all('.wp-table-timeline--body .wp--row') expected = ids.map { |el| el.is_a?(WorkPackage) ? el.id.to_s : el.to_s } - found = rows.map { |el| el["data-work-package-id"] } + found = rows.map { |el| el['data-work-package-id'] } raise "Order is incorrect: #{found.inspect} != #{expected.inspect}" unless found == expected end @@ -79,9 +79,9 @@ def expect_work_package_order(*ids) def expect_timeline!(open: true) if open - expect(page).to have_css(".wp-table-timeline--container .wp-timeline-cell") + expect(page).to have_css('.wp-table-timeline--container .wp-timeline-cell') else - expect(page).to have_no_css(".wp-table-timeline--container .wp-timeline-cell", visible: true) + expect(page).to have_no_css('.wp-table-timeline--container .wp-timeline-cell', visible: true) end end @@ -90,7 +90,7 @@ def timeline_row(wp_id) end def zoom_in_button - page.find_by_id("work-packages-timeline-zoom-in-button") + page.find_by_id('work-packages-timeline-zoom-in-button') end def zoom_in @@ -102,11 +102,11 @@ def zoom_out end def zoom_out_button - page.find_by_id("work-packages-timeline-zoom-out-button") + page.find_by_id('work-packages-timeline-zoom-out-button') end def autozoom - page.find_by_id("work-packages-timeline-zoom-auto-button").click + page.find_by_id('work-packages-timeline-zoom-auto-button').click end def expect_zoom_at(value) diff --git a/spec/support/parallel_helper.rb b/spec/support/parallel_helper.rb index 1c39c1b10f2e..72070d680767 100644 --- a/spec/support/parallel_helper.rb +++ b/spec/support/parallel_helper.rb @@ -2,10 +2,10 @@ module ParallelHelper module_function def port_for_ldap - ENV.fetch("TEST_ENV_NUMBER", "1").to_i + 12389 + ENV.fetch('TEST_ENV_NUMBER', '1').to_i + 12389 end def port_for_app - ENV.fetch("TEST_ENV_NUMBER", "1").to_i + 3000 + ENV.fetch('TEST_ENV_NUMBER', '1').to_i + 3000 end end diff --git a/spec/support/permission_specs.rb b/spec/support/permission_specs.rb index 389e356dbe9a..92c28624486c 100644 --- a/spec/support/permission_specs.rb +++ b/spec/support/permission_specs.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require File.expand_path("shared/become_member", __dir__) +require File.expand_path('shared/become_member', __dir__) module PermissionSpecs def self.included(base) @@ -49,7 +49,7 @@ def self.controller_actions end def self.check_permission_required_for(controller_action, permission) - controller_name, action_name = controller_action.split("#") + controller_name, action_name = controller_action.split('#') it "allows calling #{controller_action} when having the permission #{permission}" do become_member_with_permissions(project, current_user, permission) diff --git a/spec/support/pry.rb b/spec/support/pry.rb index da0b9993c8df..e47ee69c65e5 100644 --- a/spec/support/pry.rb +++ b/spec/support/pry.rb @@ -45,7 +45,7 @@ config.after(pry: true) do |example| if example.exception exception_message = example.exception.message - backtrace_locations = example.exception.backtrace_locations.filter { _1.to_s.include? "/spec/" } + backtrace_locations = example.exception.backtrace_locations.filter { _1.to_s.include? '/spec/' } puts puts exception_message @@ -53,7 +53,7 @@ puts # rubocop:disable Lint/Debugger - require "pry" + require 'pry' binding.pry # rubocop:enable Lint/Debugger end diff --git a/spec/support/puffing_billy_proxy.rb b/spec/support/puffing_billy_proxy.rb index b8e4c09ed4f4..ccee3840aea9 100644 --- a/spec/support/puffing_billy_proxy.rb +++ b/spec/support/puffing_billy_proxy.rb @@ -35,9 +35,9 @@ # In order to use the proxied server, you need to use `driver: firefox_billy` in your examples # # See https://github.com/oesmith/puffing-billy for more information -require "billy/capybara/rspec" +require 'billy/capybara/rspec' -require "table_print" # Add this dependency to your gemfile +require 'table_print' # Add this dependency to your gemfile ## # Patch `puffing-billy`'s proxy so that it doesn't try to stop diff --git a/spec/support/queries/filters/shared_filter_examples.rb b/spec/support/queries/filters/shared_filter_examples.rb index de923493c9c7..660bd9754751 100644 --- a/spec/support/queries/filters/shared_filter_examples.rb +++ b/spec/support/queries/filters/shared_filter_examples.rb @@ -26,64 +26,64 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "filter tests" do +RSpec.shared_context 'filter tests' do let(:context) { nil } - let(:values) { ["bogus"] } - let(:operator) { "=" } + let(:values) { ['bogus'] } + let(:operator) { '=' } let(:instance_key) { described_class.key } let(:instance) do described_class.create!(name: instance_key, context:, operator:, values:) end - let(:name) { model.human_attribute_name((instance_key || expected_class_key).to_s.gsub("_id", "")) } + let(:name) { model.human_attribute_name((instance_key || expected_class_key).to_s.gsub('_id', '')) } let(:model) { WorkPackage } end -RSpec.shared_examples_for "basic query filter" do - include_context "filter tests" +RSpec.shared_examples_for 'basic query filter' do + include_context 'filter tests' let(:context) { build_stubbed(:query, project:) } let(:project) { build_stubbed(:project) } - let(:expected_class_key) { defined?(:class_key) ? class_key : raise("needs to be defined") } - let(:type) { raise "needs to be defined" } + let(:expected_class_key) { defined?(:class_key) ? class_key : raise('needs to be defined') } + let(:type) { raise 'needs to be defined' } let(:human_name) { nil } - describe ".key" do - it "is the defined key" do + describe '.key' do + it 'is the defined key' do expect(described_class.key).to eql(expected_class_key) end end - describe "#name" do - it "is the defined key" do + describe '#name' do + it 'is the defined key' do expect(instance.name).to eql(instance_key || expected_class_key) end end - describe "#type" do - it "is the defined filter type" do + describe '#type' do + it 'is the defined filter type' do expect(instance.type).to eql(type) end end - describe "#human_name" do - it "is the l10 name for the filter" do + describe '#human_name' do + it 'is the l10 name for the filter' do expect(instance.human_name).to eql(human_name.presence || name) end end end -RSpec.shared_examples_for "list query filter" do |scope: true| - include_context "filter tests" +RSpec.shared_examples_for 'list query filter' do |scope: true| + include_context 'filter tests' let(:attribute) { raise "needs to be defined" } let(:type) { :list } if scope - describe "#scope" do + describe '#scope' do context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } let(:values) { valid_values } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where(["#{model.table_name}.#{attribute} IN (?)", values]) expect(instance.scope.to_sql).to eql expected.to_sql @@ -91,10 +91,10 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } let(:values) { valid_values } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "(#{model.table_name}.#{attribute} IS NULL OR #{model.table_name}.#{attribute} NOT IN (?))".squish expected = model.where([sql, values]) @@ -105,34 +105,34 @@ end end - describe "#valid?" do - let(:operator) { "=" } + describe '#valid?' do + let(:operator) { '=' } let(:values) { valid_values } - it "is valid" do + it 'is valid' do expect(instance).to be_valid end - context "for an invalid operator" do - let(:operator) { "*" } + context 'for an invalid operator' do + let(:operator) { '*' } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end - context "for an invalid value" do - let(:values) { ["inexistent"] } + context 'for an invalid value' do + let(:values) { ['inexistent'] } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end end end -RSpec.shared_examples_for "list_optional query filter" do - include_context "filter tests" +RSpec.shared_examples_for 'list_optional query filter' do + include_context 'filter tests' let(:attribute) { raise "needs to be defined" } let(:type) { :list_optional } let(:joins) { nil } @@ -147,14 +147,14 @@ joins || model.table_name end - describe "#scope" do + describe '#scope' do let(:values) { valid_values } let(:db_values) { defined?(transformed_values) ? transformed_values : valid_values } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.#{attribute} IN (?)", db_values]) @@ -163,9 +163,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "(#{expected_table_name}.#{attribute} IS NULL OR #{expected_table_name}.#{attribute} NOT IN (?))".squish expected = expected_base_scope.where([sql, db_values]) @@ -175,9 +175,9 @@ end context 'for "*"' do - let(:operator) { "*" } + let(:operator) { '*' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "#{expected_table_name}.#{attribute} IS NOT NULL" expected = expected_base_scope.where([sql]) @@ -186,9 +186,9 @@ end context 'for "!*"' do - let(:operator) { "!*" } + let(:operator) { '!*' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "#{expected_table_name}.#{attribute} IS NULL" expected = expected_base_scope.where([sql]) expect(instance.scope.to_sql).to eql expected.to_sql @@ -196,102 +196,102 @@ end end - describe "#valid?" do - let(:operator) { "=" } + describe '#valid?' do + let(:operator) { '=' } let(:values) { valid_values } - it "is valid" do + it 'is valid' do expect(instance).to be_valid end - context "for an invalid operator" do - let(:operator) { "~" } + context 'for an invalid operator' do + let(:operator) { '~' } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end - context "for an invalid value" do - let(:values) { ["inexistent"] } + context 'for an invalid value' do + let(:values) { ['inexistent'] } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end end end -RSpec.shared_examples_for "list_optional group query filter" do - include_context "filter tests" - describe "#scope" do +RSpec.shared_examples_for 'list_optional group query filter' do + include_context 'filter tests' + describe '#scope' do let(:values) { valid_values } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where(["users.id IN (#{User.in_group(values).select(:id).to_sql})"]) expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where(["users.id NOT IN (#{User.in_group(values).select(:id).to_sql})"]) expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "*"' do - let(:operator) { "*" } + let(:operator) { '*' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where(["users.id IN (#{User.within_group([]).select(:id).to_sql})"]) expect(instance.scope.to_sql).to eql expected.to_sql end end context 'for "!*"' do - let(:operator) { "!*" } + let(:operator) { '!*' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = model.where(["users.id NOT IN (#{User.within_group([]).select(:id).to_sql})"]) expect(instance.scope.to_sql).to eql expected.to_sql end end end - describe "#valid?" do - let(:operator) { "=" } + describe '#valid?' do + let(:operator) { '=' } let(:values) { valid_values } - it "is valid" do + it 'is valid' do expect(instance).to be_valid end - context "for an invalid operator" do - let(:operator) { "~" } + context 'for an invalid operator' do + let(:operator) { '~' } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end - context "for an invalid value" do - let(:values) { ["inexistent"] } + context 'for an invalid value' do + let(:values) { ['inexistent'] } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end end end -RSpec.shared_examples_for "list_all query filter" do - include_context "filter tests" +RSpec.shared_examples_for 'list_all query filter' do + include_context 'filter tests' let(:attribute) { raise "needs to be defined" } let(:type) { :list_all } let(:joins) { nil } @@ -306,13 +306,13 @@ joins || model.table_name end - describe "#scope" do + describe '#scope' do let(:values) { valid_values } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.#{attribute} IN (?)", values]) @@ -321,9 +321,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "(#{expected_table_name}.#{attribute} IS NULL OR #{expected_table_name}.#{attribute} NOT IN (?))".squish expected = expected_base_scope.where([sql, values]) @@ -333,9 +333,9 @@ end context 'for "*"' do - let(:operator) { "*" } + let(:operator) { '*' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "#{expected_table_name}.#{attribute} IS NOT NULL" expected = expected_base_scope.where([sql]) @@ -344,34 +344,34 @@ end end - describe "#valid?" do - let(:operator) { "=" } + describe '#valid?' do + let(:operator) { '=' } let(:values) { valid_values } - it "is valid" do + it 'is valid' do expect(instance).to be_valid end - context "for an invalid operator" do - let(:operator) { "~" } + context 'for an invalid operator' do + let(:operator) { '~' } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end - context "for an invalid value" do - let(:values) { ["inexistent"] } + context 'for an invalid value' do + let(:values) { ['inexistent'] } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end end end -RSpec.shared_examples_for "boolean query filter" do |scope: true| - include_context "filter tests" +RSpec.shared_examples_for 'boolean query filter' do |scope: true| + include_context 'filter tests' let(:attribute) { raise "needs to be defined" } let(:type) { :list } let(:joins) { nil } @@ -388,8 +388,8 @@ let(:valid_values) { [OpenProject::Database::DB_VALUE_TRUE] } - describe "#allowed_values" do - it "is list for a bool" do + describe '#allowed_values' do + it 'is list for a bool' do expect(instance.allowed_values) .to contain_exactly([I18n.t(:general_text_yes), OpenProject::Database::DB_VALUE_TRUE], [I18n.t(:general_text_no), OpenProject::Database::DB_VALUE_FALSE]) @@ -397,13 +397,13 @@ end if scope - describe "#scope" do + describe '#scope' do let(:values) { valid_values } context 'for "="' do - let(:operator) { "=" } + let(:operator) { '=' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do expected = expected_base_scope .where(["#{expected_table_name}.#{attribute} IN (?)", values]) @@ -412,9 +412,9 @@ end context 'for "!"' do - let(:operator) { "!" } + let(:operator) { '!' } - it "is the same as handwriting the query" do + it 'is the same as handwriting the query' do sql = "#{expected_table_name}.#{attribute} IS NULL OR #{expected_table_name}.#{attribute} IN (?)".squish expected = expected_base_scope.where([sql, [OpenProject::Database::DB_VALUE_FALSE]]) @@ -425,66 +425,66 @@ end end - describe "#valid?" do - let(:operator) { "=" } + describe '#valid?' do + let(:operator) { '=' } let(:values) { valid_values } - it "is valid" do + it 'is valid' do expect(instance).to be_valid end - context "for an invalid operator" do - let(:operator) { "~" } + context 'for an invalid operator' do + let(:operator) { '~' } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end - context "for an invalid value" do - let(:values) { ["inexistent"] } + context 'for an invalid value' do + let(:values) { ['inexistent'] } - it "is invalid" do + it 'is invalid' do expect(instance).to be_invalid end end end end -RSpec.shared_examples_for "non ar filter" do - describe "#ar_object_filter?" do - it "is false" do +RSpec.shared_examples_for 'non ar filter' do + describe '#ar_object_filter?' do + it 'is false' do expect(instance) .not_to be_ar_object_filter end end - describe "#value_objects" do - it "is empty" do + describe '#value_objects' do + it 'is empty' do expect(instance.value_objects) .to be_empty end end end -RSpec.shared_examples_for "filter by work package id" do - include_context "filter tests" +RSpec.shared_examples_for 'filter by work package id' do + include_context 'filter tests' let(:project) { build_stubbed(:project) } let(:query) do build_stubbed(:query, project:) end - it_behaves_like "basic query filter" do + it_behaves_like 'basic query filter' do let(:type) { :list } before do instance.context = query end - describe "#available?" do - context "within a project" do - it "is true if any work package exists and is visible" do + describe '#available?' do + context 'within a project' do + it 'is true if any work package exists and is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :exists?) .with(no_args) @@ -495,7 +495,7 @@ expect(instance).to be_available end - it "is false if no work package exists/ is visible" do + it 'is false if no work package exists/ is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :exists?) .with(no_args) @@ -507,10 +507,10 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "is true if any work package exists and is visible" do + it 'is true if any work package exists and is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :exists?) .with(no_args) @@ -519,7 +519,7 @@ expect(instance).to be_available end - it "is false if no work package exists/ is visible" do + it 'is false if no work package exists/ is visible' do allow(WorkPackage) .to receive_message_chain(:visible, :exists?) .with(no_args) @@ -530,22 +530,22 @@ end end - describe "#ar_object_filter?" do - it "is true" do + describe '#ar_object_filter?' do + it 'is true' do expect(instance).to be_ar_object_filter end end - describe "#allowed_values" do - it "raises an error" do + describe '#allowed_values' do + it 'raises an error' do expect { instance.allowed_values }.to raise_error NotImplementedError end end - describe "#value_object" do + describe '#value_object' do let(:visible_wp) { build_stubbed(:work_package) } - it "returns the work package for the values" do + it 'returns the work package for the values' do allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :find) .with(no_args) @@ -558,19 +558,19 @@ end end - describe "#allowed_objects" do - it "raises an error" do + describe '#allowed_objects' do + it 'raises an error' do expect { instance.allowed_objects }.to raise_error NotImplementedError end end - describe "#valid_values!" do + describe '#valid_values!' do let(:visible_wp) { build_stubbed(:work_package) } let(:invisible_wp) { build_stubbed(:work_package) } - context "within a project" do - it "removes all non existing/non visible ids" do - instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, "999999"] + context 'within a project' do + it 'removes all non existing/non visible ids' do + instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999'] allow(WorkPackage) .to receive_message_chain(:visible, :for_projects, :where, :pluck) @@ -587,11 +587,11 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "removes all non existing/non visible ids" do - instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, "999999"] + it 'removes all non existing/non visible ids' do + instance.values = [visible_wp.id.to_s, invisible_wp.id.to_s, '999999'] allow(WorkPackage) .to receive_message_chain(:visible, :where, :pluck) @@ -608,12 +608,12 @@ end end - describe "#validate" do + describe '#validate' do let(:visible_wp) { build_stubbed(:work_package) } let(:invisible_wp) { build_stubbed(:work_package) } - context "within a project" do - it "is valid if only visible wps are values" do + context 'within a project' do + it 'is valid if only visible wps are values' do instance.values = [visible_wp.id.to_s] allow(WorkPackage) @@ -627,7 +627,7 @@ expect(instance).to be_valid end - it "is invalid if invisible wps are values" do + it 'is invalid if invisible wps are values' do instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s] allow(WorkPackage) @@ -642,10 +642,10 @@ end end - context "outside of a project" do + context 'outside of a project' do let(:project) { nil } - it "is valid if only visible wps are values" do + it 'is valid if only visible wps are values' do instance.values = [visible_wp.id.to_s] allow(WorkPackage) @@ -658,7 +658,7 @@ expect(instance).to be_valid end - it "is invalid if invisible wps are values" do + it 'is invalid if invisible wps are values' do instance.values = [invisible_wp.id.to_s, visible_wp.id.to_s] allow(WorkPackage) @@ -675,13 +675,13 @@ end end -RSpec.shared_examples_for "operators for relation filters" do +RSpec.shared_examples_for 'operators for relation filters' do context "on '=' operator" do before do - instance.operator = "=" + instance.operator = '=' end - it "returns the related work packages" do + it 'returns the related work packages' do expect(WorkPackage.where(instance.where)) .to contain_exactly(related_wp) end @@ -689,20 +689,20 @@ context "on '!' operator" do before do - instance.operator = "!" + instance.operator = '!' end - it "returns the unrelated work packages" do + it 'returns the unrelated work packages' do expect(WorkPackage.where(instance.where)) .to contain_exactly(filter_value_wp, unrelated_wp) end end end -RSpec.shared_examples_for "filter for relation" do - describe "#where" do +RSpec.shared_examples_for 'filter for relation' do + describe '#where' do let!(:filter_value_wp) { create(:work_package) } - let(:wp_relation_type) { defined?(:relation_type) ? relation_type : raise("needs to be defined") } + let(:wp_relation_type) { defined?(:relation_type) ? relation_type : raise('needs to be defined') } let!(:related_wp) do create(:work_package).tap do |wp| if Relation.canonical_type(wp_relation_type) == wp_relation_type @@ -725,6 +725,6 @@ instance.values = [filter_value_wp.id.to_s] end - it_behaves_like "operators for relation filters" + it_behaves_like 'operators for relation filters' end end diff --git a/spec/support/queries/shared_get_individual_query_examples.rb b/spec/support/queries/shared_get_individual_query_examples.rb index ad7ee08b3720..1880f9c3b1c3 100644 --- a/spec/support/queries/shared_get_individual_query_examples.rb +++ b/spec/support/queries/shared_get_individual_query_examples.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "GET individual query" do +RSpec.shared_examples_for 'GET individual query' do let(:work_package) { create(:work_package, :created_in_past, project:, created_at: 1.minute.ago) } let(:filter) { [] } let(:path) do @@ -43,26 +43,26 @@ get path end - it "succeeds" do + it 'succeeds' do expect(last_response.status).to eq(200) end - it "has the right endpoint set for the self reference" do + it 'has the right endpoint set for the self reference' do expect(last_response.body) .to be_json_eql(path.to_json) - .at_path("_links/self/href") + .at_path('_links/self/href') end - it "embedds the query results" do + it 'embedds the query results' do expect(last_response.body) - .to be_json_eql("WorkPackageCollection".to_json) - .at_path("_embedded/results/_type") + .to be_json_eql('WorkPackageCollection'.to_json) + .at_path('_embedded/results/_type') expect(last_response.body) .to be_json_eql(api_v3_paths.work_package(work_package.id).to_json) - .at_path("_embedded/results/_embedded/elements/0/_links/self/href") + .at_path('_embedded/results/_embedded/elements/0/_links/self/href') end - context "when providing a valid filters" do + context 'when providing a valid filters' do let(:filter) do [ { @@ -74,14 +74,14 @@ ] end - it "uses the provided filter" do + it 'uses the provided filter' do expect(last_response.body) .to be_json_eql(0.to_json) - .at_path("_embedded/results/total") + .at_path('_embedded/results/total') end end - context "when providing an invalid filter" do + context 'when providing an invalid filter' do let(:filter) do [ { @@ -90,68 +90,68 @@ ] end - it "returns an error" do + it 'returns an error' do expect(last_response.body) .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .at_path('errorIdentifier') end end - describe "timestamps" do + describe 'timestamps' do let(:path) do params = CGI.escape(timestamps.join(",")) "#{base_path}?timestamps=#{params}" end - context "when providing valid timestamps" do - context "with a range without a work package" do + context 'when providing valid timestamps' do + context 'with a range without a work package' do let(:timestamps) { [2.hours.ago.iso8601, 1.hour.ago.iso8601] } - it "uses the provided timestamp" do + it 'uses the provided timestamp' do expect(last_response.body) .to be_json_eql(0.to_json) - .at_path("_embedded/results/total") + .at_path('_embedded/results/total') end end - context "with a range containing a work package" do - let(:timestamps) { [2.hours.ago.iso8601, "P0D"] } + context 'with a range containing a work package' do + let(:timestamps) { [2.hours.ago.iso8601, 'P0D'] } - it "uses the provided timestamp" do + it 'uses the provided timestamp' do expect(last_response.body) .to be_json_eql(1.to_json) - .at_path("_embedded/results/total") + .at_path('_embedded/results/total') end end end - context "when providing an invalid timestamp" do - let(:timestamps) { ["invalid"] } + context 'when providing an invalid timestamp' do + let(:timestamps) { ['invalid'] } - it "returns an error" do + it 'returns an error' do expect(last_response.body) .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .at_path('errorIdentifier') end end - context "with timestamps older than 1 day" do - let(:timestamps) { [2.days.ago.iso8601, "PT0S"] } + context 'with timestamps older than 1 day' do + let(:timestamps) { [2.days.ago.iso8601, 'PT0S'] } - context "with EE", with_ee: %i[baseline_comparison] do - it "succeeds" do + context 'with EE', with_ee: %i[baseline_comparison] do + it 'succeeds' do expect(last_response.status).to eq(200) end end - context "without EE", with_ee: false do - it "returns an error" do + context 'without EE', with_ee: false do + it 'returns an error' do expect(last_response.body) .to be_json_eql("urn:openproject-org:api:v3:errors:InvalidQuery".to_json) - .at_path("errorIdentifier") + .at_path('errorIdentifier') expect(last_response.body) .to be_json_eql("Timestamps contain forbidden values: #{timestamps[0]}".to_json) - .at_path("message") + .at_path('message') end end end diff --git a/spec/support/repository_helpers.rb b/spec/support/repository_helpers.rb index 4796f639705e..de2c6f12f9bc 100644 --- a/spec/support/repository_helpers.rb +++ b/spec/support/repository_helpers.rb @@ -38,24 +38,24 @@ def with_filesystem_repository(vendor, command = nil) fixture = Rails.root.join("spec/fixtures/repositories/#{vendor}_repository.tar.gz") before do - skip_if_commands_unavailable("tar", command) + skip_if_commands_unavailable('tar', command) end after(:all) do FileUtils.remove_dir repo_dir end - skip_if_command_unavailable("tar") + skip_if_command_unavailable('tar') system "tar -xzf #{fixture} -C #{repo_dir}" yield(repo_dir) end def with_subversion_repository(&) - with_filesystem_repository("subversion", "svn", &) + with_filesystem_repository('subversion', 'svn', &) end def with_git_repository(&) - with_filesystem_repository("git", "git", &) + with_filesystem_repository('git', 'git', &) end ## @@ -68,7 +68,7 @@ def with_virtual_subversion_repository let(:repository) { create(:repository_subversion) } before do - allow(Setting).to receive(:enabled_scm).and_return(["subversion"]) + allow(Setting).to receive(:enabled_scm).and_return(['subversion']) end yield diff --git a/spec/support/request_with_header.rb b/spec/support/request_with_header.rb index 2cc0d19203e2..017781151e44 100644 --- a/spec/support/request_with_header.rb +++ b/spec/support/request_with_header.rb @@ -3,11 +3,11 @@ # Session-based API authentication requires the X-requested-with header to be present. c.before(:each, type: :request) do |ex| unless ex.metadata[:skip_xhr_header] - header("X-Requested-With", "XMLHttpRequest") + header('X-Requested-With', 'XMLHttpRequest') end end c.before(:each, content_type: :json, type: :request) do |_ex| - header("Content-Type", "application/json") + header('Content-Type', 'application/json') end end diff --git a/spec/support/roles.rb b/spec/support/roles.rb index 56aff723a39a..d475a31bd881 100644 --- a/spec/support/roles.rb +++ b/spec/support/roles.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "with non-member permissions from non_member_permissions" do +RSpec.shared_context 'with non-member permissions from non_member_permissions' do around do |example| non_member = ProjectRole.non_member previous_permissions = non_member.permissions diff --git a/spec/support/rspec_cleanup.rb b/spec/support/rspec_cleanup.rb index cacce348fe6e..034e5ebc4dfe 100644 --- a/spec/support/rspec_cleanup.rb +++ b/spec/support/rspec_cleanup.rb @@ -15,7 +15,7 @@ end # We don't want this to be reported on CI as it breaks the build - unless ENV["CI"] + unless ENV['CI'] config.append_after(:suite) do [User.not_builtin, Project, WorkPackage].each do |cls| next if cls.count == 0 diff --git a/spec/support/rspec_disabled_specs.rb b/spec/support/rspec_disabled_specs.rb index 879be58d6811..06d8cc993e5d 100644 --- a/spec/support/rspec_disabled_specs.rb +++ b/spec/support/rspec_disabled_specs.rb @@ -6,8 +6,8 @@ # (and other plugins' specs) keep working with this plugin in an OpenProject configuration # even if it changes things which would otherwise break existing specs. Rails.application.config.plugins_to_test_paths.each do |dir| - ["disabled_specs.rb", "disable_specs.rb", "config_spec_helper.rb"].each do |file_name| - file = File.join(dir, "spec", file_name) + ['disabled_specs.rb', 'disable_specs.rb', 'config_spec_helper.rb'].each do |file_name| + file = File.join(dir, 'spec', file_name) if File.exist?(file) puts "Loading #{file}" diff --git a/spec/support/rspec_mocks_ruby_3_2_fix_argument_forwarding.rb b/spec/support/rspec_mocks_ruby_3_2_fix_argument_forwarding.rb index 7a33ead0d88e..5ece23c45189 100644 --- a/spec/support/rspec_mocks_ruby_3_2_fix_argument_forwarding.rb +++ b/spec/support/rspec_mocks_ruby_3_2_fix_argument_forwarding.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rspec/mocks" +require 'rspec/mocks' module RSpec module Mocks diff --git a/spec/support/rspec_retry.rb b/spec/support/rspec_retry.rb index 80c3a0e75912..f1c6841302dc 100644 --- a/spec/support/rspec_retry.rb +++ b/spec/support/rspec_retry.rb @@ -1,5 +1,5 @@ -require "rspec/retry" -require "retriable" +require 'rspec/retry' +require 'retriable' ## # Enable specs to mark metadata retry: to retry that given example @@ -19,7 +19,7 @@ ## # Retry JS feature specs, but not during single runs - if ENV["CI"] + if ENV['CI'] config.around :each, :js do |ex| ex.run_with_retry retry: 2 end diff --git a/spec/support/schedule_helpers.rb b/spec/support/schedule_helpers.rb index e7293f9b89fc..3e042a15bac8 100644 --- a/spec/support/schedule_helpers.rb +++ b/spec/support/schedule_helpers.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -Dir[Rails.root.join("spec/support/schedule_helpers/*.rb")].each { |f| require f } +Dir[Rails.root.join('spec/support/schedule_helpers/*.rb')].each { |f| require f } RSpec.configure do |config| config.extend ScheduleHelpers::LetSchedule diff --git a/spec/support/schedule_helpers/chart.rb b/spec/support/schedule_helpers/chart.rb index 42124c5ce4cf..783c7a80030e 100644 --- a/spec/support/schedule_helpers/chart.rb +++ b/spec/support/schedule_helpers/chart.rb @@ -57,8 +57,8 @@ module ScheduleHelpers # * +_+: ignored but useful as a placeholder to highlight particular days, for # instance to highlight the previous dates of a work package. class Chart - FIRST_CELL_TEXT = "days".freeze - WEEK_DAYS_TEXT = "MTWTFSS".freeze + FIRST_CELL_TEXT = 'days'.freeze + WEEK_DAYS_TEXT = 'MTWTFSS'.freeze attr_reader :id_column_size, :first_day, :last_day, :monday @@ -226,15 +226,15 @@ def spaced_at(date, text) def span(attributes) case attributes in { start_date: nil, due_date: nil } - "" + '' in { start_date:, due_date: nil } - spaced_at(start_date, "[") + spaced_at(start_date, '[') in { start_date: nil, due_date: } - spaced_at(due_date, "]") + spaced_at(due_date, ']') in { start_date:, due_date: } days = days_for(attributes) span = (start_date..due_date).map do |date| - days.working?(date) ? "X" : "." + days.working?(date) ? 'X' : '.' end.join spaced_at(start_date, span) end diff --git a/spec/support/schedule_helpers/chart_builder.rb b/spec/support/schedule_helpers/chart_builder.rb index 3d71625d9391..0680950394b5 100644 --- a/spec/support/schedule_helpers/chart_builder.rb +++ b/spec/support/schedule_helpers/chart_builder.rb @@ -67,7 +67,7 @@ def use_work_packages(work_packages) private def parse_header(header) - _, week_days = header.split(" | ", 2) + _, week_days = header.split(' | ', 2) unless week_days.include?(Chart::WEEK_DAYS_TEXT) raise ArgumentError, "First header line of schedule chart must contain #{Chart::WEEK_DAYS_TEXT} to indicate day names and have an origin" @@ -78,7 +78,7 @@ def parse_header(header) def parse_line(line) case line - when "" + when '' # noop when / \| / parse_work_package_line(line) @@ -88,13 +88,13 @@ def parse_line(line) end def parse_work_package_line(line) - name, timespan, properties = line.split(" | ", 3) + name, timespan, properties = line.split(' | ', 3) name.strip! attributes = { subject: name } attributes.update(parse_timespan(timespan)) chart.add_work_package(attributes) - properties.to_s.split(",").map(&:strip).each do |property| + properties.to_s.split(',').map(&:strip).each do |property| parse_properties(name, property) end end @@ -129,15 +129,15 @@ def parse_properties(name, property) "working days include weekends" ] ) - suggestions = spell_checker.correct(property).map(&:inspect).join(" ") + suggestions = spell_checker.correct(property).map(&:inspect).join(' ') did_you_mean = " Did you mean #{suggestions} instead?" if suggestions.present? raise "unable to parse property #{property.inspect} for line #{name.inspect}.#{did_you_mean}" end end def parse_timespan(timespan) - start_pos = timespan.index("[") || timespan.index("X") - due_pos = timespan.rindex("]") || timespan.rindex("X") + start_pos = timespan.index('[') || timespan.index('X') + due_pos = timespan.rindex(']') || timespan.rindex('X') { start_date: start_pos && (chart.monday - @nb_days_from_origin_monday + start_pos), due_date: due_pos && (chart.monday - @nb_days_from_origin_monday + due_pos) diff --git a/spec/support/schedule_helpers/schedule.rb b/spec/support/schedule_helpers/schedule.rb index e9755c591baf..eb8e79aeaf3b 100644 --- a/spec/support/schedule_helpers/schedule.rb +++ b/spec/support/schedule_helpers/schedule.rb @@ -59,7 +59,7 @@ def normalize_name(name) return symbolic_name if @work_packages.has_key?(symbolic_name) spell_checker = DidYouMean::SpellChecker.new(dictionary: @work_packages.keys.map(&:to_s)) - suggestions = spell_checker.correct(name).map(&:inspect).join(" ") + suggestions = spell_checker.correct(name).map(&:inspect).join(' ') did_you_mean = " Did you mean #{suggestions} instead?" if suggestions.present? raise "No work package with name #{name.inspect} in schedule.#{did_you_mean}" end diff --git a/spec/support/schedule_reminder_mails.rb b/spec/support/schedule_reminder_mails.rb index 93dfea101bc1..75587ddee847 100644 --- a/spec/support/schedule_reminder_mails.rb +++ b/spec/support/schedule_reminder_mails.rb @@ -29,5 +29,5 @@ ## # Calculates a slot in the user's local time that hits for scheduling reminder mail jobs def hitting_reminder_slot_for(time_zone, current_utc_time = Time.current.getutc) - current_utc_time.in_time_zone(ActiveSupport::TimeZone[time_zone]).strftime("%H:00:00+00:00") + current_utc_time.in_time_zone(ActiveSupport::TimeZone[time_zone]).strftime('%H:00:00+00:00') end diff --git a/spec/support/scm/countable_repository.rb b/spec/support/scm/countable_repository.rb index f880c7944cac..e7e42d2f6adb 100644 --- a/spec/support/scm/countable_repository.rb +++ b/spec/support/scm/countable_repository.rb @@ -1,5 +1,5 @@ -require "open3" -RSpec.shared_examples_for "is a countable repository" do +require 'open3' +RSpec.shared_examples_for 'is a countable repository' do let(:cache_time) { 720 } before do @@ -7,23 +7,23 @@ allow(Setting).to receive(:repository_storage_cache_minutes).and_return(cache_time) end - it "is countable" do + it 'is countable' do expect(repository.scm).to be_storage_available end - context "with patched counter" do + context 'with patched counter' do let(:count) { 1234 } before do allow(repository.scm).to receive(:count_repository!).and_return(count) end - it "has has not been counted initially" do + it 'has has not been counted initially' do expect(repository.required_storage_bytes).to eq 0 expect(repository.storage_updated_at).to be_nil end - it "counts the repository storage automatically" do + it 'counts the repository storage automatically' do expect(repository.required_storage_bytes).to eq 0 expect(repository.update_required_storage).to be true @@ -34,12 +34,12 @@ expect(repository.storage_updated_at).to be >= 1.minute.ago end - context "when latest count is outdated" do + context 'when latest count is outdated' do before do allow(repository).to receive(:storage_updated_at).and_return(24.hours.ago) end - it "sucessfuly updates the count to what the adapter returns" do + it 'sucessfuly updates the count to what the adapter returns' do expect(repository.required_storage_bytes).to eq 0 expect(repository.update_required_storage).to be true @@ -50,8 +50,8 @@ end end - context "with real counter" do - it "counts the repository storage automatically" do + context 'with real counter' do + it 'counts the repository storage automatically' do expect(repository.required_storage_bytes).to eq 0 expect(repository.update_required_storage).to be true @@ -62,26 +62,26 @@ end end - describe "count methods" do - it "uses du when available" do - expect(Open3).to receive(:capture3).with("du", any_args) - .and_return(["1234\t.", "", 0]) + describe 'count methods' do + it 'uses du when available' do + expect(Open3).to receive(:capture3).with('du', any_args) + .and_return(["1234\t.", '', 0]) expect(repository.scm).not_to receive(:count_storage_fallback) expect(repository.scm.count_repository!).to eq(1234) end - it "falls back to using ruby when du is unavailable" do - expect(Open3).to receive(:capture3).with("du", any_args) - .and_raise(SystemCallError.new("foo")) + it 'falls back to using ruby when du is unavailable' do + expect(Open3).to receive(:capture3).with('du', any_args) + .and_raise(SystemCallError.new('foo')) expect(repository.scm).to receive(:count_storage_fallback).and_return(12345) expect(repository.scm.count_repository!).to eq(12345) end - it "falls back to using ruby when du is incompatible" do - expect(Open3).to receive(:capture3).with("du", any_args) - .and_return(["no output", nil, 1]) + it 'falls back to using ruby when du is incompatible' do + expect(Open3).to receive(:capture3).with('du', any_args) + .and_return(['no output', nil, 1]) expect(repository.scm).to receive(:count_storage_fallback).and_return(12345) expect(repository.scm.count_repository!).to eq(12345) @@ -89,12 +89,12 @@ end end -RSpec.shared_examples_for "is not a countable repository" do - it "is not countable" do +RSpec.shared_examples_for 'is not a countable repository' do + it 'is not countable' do expect(repository.scm).not_to be_storage_available end - it "does not return or update the count" do + it 'does not return or update the count' do expect(SCM::StorageUpdaterJob).not_to receive(:perform_later) expect(repository.update_required_storage).to be false end diff --git a/spec/support/scm/relocate_repository.rb b/spec/support/scm/relocate_repository.rb index 76f5f61cf51c..998047269b1b 100644 --- a/spec/support/scm/relocate_repository.rb +++ b/spec/support/scm/relocate_repository.rb @@ -1,4 +1,4 @@ -RSpec.shared_examples_for "repository can be relocated" do |vendor| +RSpec.shared_examples_for 'repository can be relocated' do |vendor| let(:job_call) do SCM::RelocateRepositoryJob.perform_now repository end @@ -19,19 +19,19 @@ allow(Repository).to receive(:find).and_return(repository) end - needed_command = "svnadmin" if vendor == :subversion + needed_command = 'svnadmin' if vendor == :subversion - context "with managed local config", skip_if_command_unavailable: needed_command do - include_context "with tmpdir" - let(:config) { { manages: File.join(tmpdir, "myrepos") } } + context 'with managed local config', skip_if_command_unavailable: needed_command do + include_context 'with tmpdir' + let(:config) { { manages: File.join(tmpdir, 'myrepos') } } - it "relocates when project identifier is updated" do + it 'relocates when project identifier is updated' do current_path = repository.root_url expect(repository.root_url).to eq(repository.managed_repository_path) expect(Dir.exist?(repository.managed_repository_path)).to be true # Rename the project - project.update!(identifier: "somenewidentifier") + project.update!(identifier: 'somenewidentifier') repository.reload job_call @@ -45,14 +45,14 @@ end end - context "with managed remote config", :webmock do - let(:url) { "http://myreposerver.example.com/api/" } + context 'with managed remote config', :webmock do + let(:url) { 'http://myreposerver.example.com/api/' } let(:config) { { manages: url } } let(:repository) do stub_request(:post, url) .to_return(status: 200, - body: { success: true, url: "file:///foo/bar", path: "/tmp/foo/bar" }.to_json) + body: { success: true, url: 'file:///foo/bar', path: '/tmp/foo/bar' }.to_json) create(:"repository_#{vendor}", project:, scm_type: :managed) @@ -61,21 +61,21 @@ before do stub_request(:post, url) .to_return(status: 200, - body: { success: true, url: "file:///new/bar", path: "/tmp/new/bar" }.to_json) + body: { success: true, url: 'file:///new/bar', path: '/tmp/new/bar' }.to_json) end - it "sends a relocation request when project identifier is updated" do - old_identifier = "bar" + it 'sends a relocation request when project identifier is updated' do + old_identifier = 'bar' # Rename the project - project.identifier = "somenewidentifier" + project.identifier = 'somenewidentifier' job_call expect(WebMock) .to have_requested(:post, url) .with(body: hash_including(old_identifier:, - action: "relocate")) + action: 'relocate')) end end end diff --git a/spec/support/seeders.rb b/spec/support/seeders.rb index c54e0d4719a7..ecc4894a0d40 100644 --- a/spec/support/seeders.rb +++ b/spec/support/seeders.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "with basic seed data" do |edition: "standard"| +RSpec.shared_context 'with basic seed data' do |edition: 'standard'| def add_needed_seeders_for(seeder_class, needed_acc) seeder_class.needs.each do |needed_seeder_class| next if needed_acc.include?(needed_seeder_class) diff --git a/spec/support/selector_helpers.rb b/spec/support/selector_helpers.rb index 44534f7cedbf..cef813aa3127 100644 --- a/spec/support/selector_helpers.rb +++ b/spec/support/selector_helpers.rb @@ -30,7 +30,7 @@ module SelectorHelpers module_function def get_pseudo_class_property(page, node, pseudo_class, property) - page.evaluate_script("window.getComputedStyle(" + element_by_node(node) + ', "' + + page.evaluate_script('window.getComputedStyle(' + element_by_node(node) + ', "' + pseudo_class + '").getPropertyValue("' + property + '")') end diff --git a/spec/support/shared/acts_as_attachable.rb b/spec/support/shared/acts_as_attachable.rb index b5d75761ddbd..aa6ad3f1e21d 100644 --- a/spec/support/shared/acts_as_attachable.rb +++ b/spec/support/shared/acts_as_attachable.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "acts_as_attachable included" do +RSpec.shared_examples_for 'acts_as_attachable included' do let(:attachment1) { create(:attachment, container: nil, author: current_user) } let(:attachment2) { create(:attachment, container: nil, author: current_user) } let(:instance_project) { respond_to?(:project) ? project : model_instance.project } @@ -44,21 +44,21 @@ let(:other_user) { create(:user) } let(:current_user) { user_with_permission } - describe "#validations on attachments_claimed" do + describe '#validations on attachments_claimed' do before do login_as(current_user) end - context "with no attachments_claimed" do - it "is valid" do + context 'with no attachments_claimed' do + it 'is valid' do expect(model_instance) .to be_valid end end - context "for attachments that are unattached, created by the current_user, " + - "added to attachments_claimed and the user having the permission" do - it "is valid" do + context 'for attachments that are unattached, created by the current_user, ' + + 'added to attachments_claimed and the user having the permission' do + it 'is valid' do model_instance.attachments_claimed = [attachment1, attachment2] expect(model_instance) @@ -66,12 +66,12 @@ end end - context "for attachments that are unattached, created by the current_user, " + - "added to attachments_claimed and the user not having the permission" do + context 'for attachments that are unattached, created by the current_user, ' + + 'added to attachments_claimed and the user not having the permission' do let(:current_user) { user_without_permission } - it "is invalid" do - skip "Skipping because permission checks are skipped" if model_instance.class.attachable_options[:skip_permission_checks] + it 'is invalid' do + skip 'Skipping because permission checks are skipped' if model_instance.class.attachable_options[:skip_permission_checks] model_instance.attachments_claimed = [attachment1, attachment2] expect(model_instance) @@ -82,12 +82,12 @@ end end - context "for attachments that are unattached, created by the current_user, " + - "added to attachments_claimed and the user not having the permission, but skipping permission checks" do + context 'for attachments that are unattached, created by the current_user, ' + + 'added to attachments_claimed and the user not having the permission, but skipping permission checks' do let(:current_user) { user_without_permission } - it "is valid" do - skip "Skipping because permission checks are not skipped" unless model_instance.class.attachable_options[:skip_permission_checks] + it 'is valid' do + skip 'Skipping because permission checks are not skipped' unless model_instance.class.attachable_options[:skip_permission_checks] model_instance.attachments_claimed = [attachment1, attachment2] expect(model_instance).to be_valid @@ -95,12 +95,12 @@ end end - context "for attachments that are attached, created by the current_user, " + - "added to attachments_claimed and the user having the permission" do + context 'for attachments that are attached, created by the current_user, ' + + 'added to attachments_claimed and the user having the permission' do let(:attachment1) { create(:attachment, author: current_user) } let(:attachment2) { create(:attachment, author: current_user) } - it "is invalid" do + it 'is invalid' do model_instance.attachments_claimed = [attachment1, attachment2] expect(model_instance) @@ -111,12 +111,12 @@ end end - context "for attachments that are unattached, not created by the current_user, " + - "added to attachments_claimed and the user having the permission" do + context 'for attachments that are unattached, not created by the current_user, ' + + 'added to attachments_claimed and the user having the permission' do let(:attachment1) { create(:attachment, container: nil, author: other_user) } let(:attachment2) { create(:attachment, container: nil, author: other_user) } - it "is invalid" do + it 'is invalid' do model_instance.attachments_claimed = [attachment1, attachment2] expect(model_instance) @@ -128,13 +128,13 @@ end end - describe "#attachments_claimed" do + describe '#attachments_claimed' do before do login_as(user_with_permission) model_instance.attachments_claimed = [attachment1, attachment2] end - it "updates all attachments to be linked to the model before saving" do + it 'updates all attachments to be linked to the model before saving' do model_instance.save expect(model_instance.attachments.reload).to contain_exactly(attachment1, attachment2) @@ -148,10 +148,10 @@ end end - describe "#attachments_visible" do + describe '#attachments_visible' do let!(:attachment1) { create(:attachment, container: model_instance, author: current_user) } - it "allows access to a logged user when viewable_by_all_users is set" do + it 'allows access to a logged user when viewable_by_all_users is set' do if model_instance.class.attachable_options[:viewable_by_all_users] || model_instance.class.attachable_options[:skip_permission_checks] expect(model_instance.attachments_visible?(other_user)).to be true expect(attachment1.visible?(user_without_permission)).to be true diff --git a/spec/support/shared/acts_as_customizable.rb b/spec/support/shared/acts_as_customizable.rb index 58155b4577b3..c51636c8cc42 100644 --- a/spec/support/shared/acts_as_customizable.rb +++ b/spec/support/shared/acts_as_customizable.rb @@ -26,73 +26,73 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "acts_as_customizable included" do - describe "#custom_field_changes" do - context "when no custom field value exists" do +RSpec.shared_examples_for 'acts_as_customizable included' do + describe '#custom_field_changes' do + context 'when no custom field value exists' do before do model_instance.custom_values.destroy_all end - it "returns no changes" do + it 'returns no changes' do expect(model_instance.custom_field_changes).to be_empty end - context "when a field value is set" do + context 'when a field value is set' do before do model_instance.custom_values.destroy_all end - it "returns the field changes" do - model_instance.custom_field_values = { custom_field.id => "test" } + it 'returns the field changes' do + model_instance.custom_field_values = { custom_field.id => 'test' } expect(model_instance.custom_field_changes) - .to eq({ custom_field.attribute_name.to_sym => [nil, "test"] }) + .to eq({ custom_field.attribute_name.to_sym => [nil, 'test'] }) end end end - context "when a field value is changed from nil" do - it "returns the field changes" do - model_instance.custom_field_values = { custom_field.id => "test" } + context 'when a field value is changed from nil' do + it 'returns the field changes' do + model_instance.custom_field_values = { custom_field.id => 'test' } expect(model_instance.custom_field_changes) - .to eq({ custom_field.attribute_name.to_sym => [nil, "test"] }) + .to eq({ custom_field.attribute_name.to_sym => [nil, 'test'] }) end end - context "when a field value is changed from a string" do + context 'when a field value is changed from a string' do before do - model_instance.custom_field_values = { custom_field.id => "test" } + model_instance.custom_field_values = { custom_field.id => 'test' } model_instance.save end - it "returns the field changes" do - model_instance.custom_field_values = { custom_field.id => "test2" } + it 'returns the field changes' do + model_instance.custom_field_values = { custom_field.id => 'test2' } expect(model_instance.custom_field_changes) - .to eq({ custom_field.attribute_name.to_sym => ["test", "test2"] }) + .to eq({ custom_field.attribute_name.to_sym => ['test', 'test2'] }) end end - context "when a field is set to the same value (unchanged)" do + context 'when a field is set to the same value (unchanged)' do before do - model_instance.custom_field_values = { custom_field.id => "test" } + model_instance.custom_field_values = { custom_field.id => 'test' } model_instance.save end - it "returns no changes" do - model_instance.custom_field_values = { custom_field.id => "test" } + it 'returns no changes' do + model_instance.custom_field_values = { custom_field.id => 'test' } expect(model_instance.custom_field_changes).to be_empty end end - context "when a field value is changed to nil" do + context 'when a field value is changed to nil' do before do - model_instance.custom_field_values = { custom_field.id => "test" } + model_instance.custom_field_values = { custom_field.id => 'test' } model_instance.save end - it "returns the field changes" do + it 'returns the field changes' do model_instance.custom_field_values = { custom_field.id => nil } expect(model_instance.custom_field_changes) - .to eq({ custom_field.attribute_name.to_sym => ["test", nil] }) + .to eq({ custom_field.attribute_name.to_sym => ['test', nil] }) end end end diff --git a/spec/support/shared/acts_as_watchable.rb b/spec/support/shared/acts_as_watchable.rb index 25c4aba132d3..0962a4267149 100644 --- a/spec/support/shared/acts_as_watchable.rb +++ b/spec/support/shared/acts_as_watchable.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "acts_as_watchable included" do +RSpec.shared_examples_for 'acts_as_watchable included' do before do unless defined?(model_instance) && defined?(watch_permission) && @@ -81,19 +81,19 @@ OpenProject::AccessControl.public_permissions.map(&:name).include?(watch_permission) end - shared_context "non member role has the permission to watch" do + shared_context 'non member role has the permission to watch' do before do non_member_role.add_permission! watch_permission unless is_public_permission end end - shared_context "anonymous role has the permission to watch" do + shared_context 'anonymous role has the permission to watch' do before do anonymous_role.add_permission! watch_permission unless is_public_permission end end - describe "#possible_watcher_users" do + describe '#possible_watcher_users' do subject { model_instance.possible_watcher_users } before do @@ -111,16 +111,16 @@ locked_user_with_permission.save! end - include_context "non member role has the permission to watch" - include_context "anonymous role has the permission to watch" + include_context 'non member role has the permission to watch' + include_context 'anonymous role has the permission to watch' - context "when it is a public project" do + context 'when it is a public project' do before do project.update public: true model_instance.reload end - it "contains all allowed to view" do + it 'contains all allowed to view' do expected_users = [user_with_permission, non_member_user, admin] @@ -132,20 +132,20 @@ end end - context "when it is a private project" do + context 'when it is a private project' do before do project.update public: false model_instance.reload end - it "contains members allowed to view" do + it 'contains members allowed to view' do expect(model_instance.possible_watcher_users) .to contain_exactly(user_with_permission) end end end - describe "#watched_by?" do + describe '#watched_by?' do before do watching_user model_instance.reload @@ -153,16 +153,16 @@ subject { model_instance.watched_by?(watching_user) } - it "is truthy" do + it 'is truthy' do expect(subject).to be_truthy end - context "when the permission to view work packages has been removed" do + context 'when the permission to view work packages has been removed' do # an existing watcher shouldn't be removed before do if is_public_permission skip "Not applicable for #{model_instance.class} as #{watch_permission} " + - "is a public permission" + 'is a public permission' end watcher_role.remove_permission! watch_permission @@ -174,7 +174,7 @@ end end - describe "#addable_watcher_users" do + describe '#addable_watcher_users' do subject { model_instance.addable_watcher_users } before do @@ -193,16 +193,16 @@ user_wo_permission.save! end - include_context "non member role has the permission to watch" - include_context "anonymous role has the permission to watch" + include_context 'non member role has the permission to watch' + include_context 'anonymous role has the permission to watch' - context "when it is a public project" do + context 'when it is a public project' do before do project.update public: true model_instance.reload end - it "contains all allowed to view" do + it 'contains all allowed to view' do expected_users = [user_with_permission, non_member_user, admin] @@ -213,13 +213,13 @@ .to match_array(expected_users) end - context "when the user is already watching" do + context 'when the user is already watching' do before do Watcher.create(watchable: model_instance, user: user_with_permission) Watcher.create(watchable: model_instance, user: non_member_user) end - it "is no longer contained" do + it 'is no longer contained' do expected_users = [admin] expected_users << user_wo_permission if is_public_permission @@ -230,23 +230,23 @@ end end - context "when it is a private project" do + context 'when it is a private project' do before do project.update public: false model_instance.reload end - it "contains members allowed to view" do + it 'contains members allowed to view' do expect(subject) .to contain_exactly(user_with_permission) end - context "when the user is already watching" do + context 'when the user is already watching' do before do Watcher.create(watchable: model_instance, user: user_with_permission) end - it "is no longer contained" do + it 'is no longer contained' do expect(subject) .to be_empty end diff --git a/spec/support/shared/audits.rb b/spec/support/shared/audits.rb index bcec5a50148d..28ce52131ec7 100644 --- a/spec/support/shared/audits.rb +++ b/spec/support/shared/audits.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "creates an audit trail on destroy" do +RSpec.shared_examples_for 'creates an audit trail on destroy' do with_versioning do let(:whodunnit) { build_stubbed(:user) } - it "adds an audit trail on destroy" do + it 'adds an audit trail on destroy' do User.execute_as(whodunnit) do subject.destroy! end @@ -38,9 +38,9 @@ expect { subject.reload }.to raise_error(ActiveRecord::RecordNotFound) expect(subject.paper_trail_audits.count).to eq 1 - expect(subject.paper_trail_audits.first.event).to eq "destroy" + expect(subject.paper_trail_audits.first.event).to eq 'destroy' expect(subject.paper_trail_audits.first.whodunnit).to eq whodunnit.id.to_s - expect(subject.paper_trail_audits.first.stack).to include "app/models" + expect(subject.paper_trail_audits.first.stack).to include 'app/models' end end end diff --git a/spec/support/shared/expect_page_reload.rb b/spec/support/shared/expect_page_reload.rb index e8ca10acd7a3..e4f2c68ff0cb 100644 --- a/spec/support/shared/expect_page_reload.rb +++ b/spec/support/shared/expect_page_reload.rb @@ -30,11 +30,11 @@ # due to a page reload def expect_page_reload - current_render = Time.parse page.find("body")["data-rendered-at"] + current_render = Time.parse page.find('body')['data-rendered-at'] yield - expect(page).to have_css("body") { |body| - Time.parse(body["data-rendered-at"]) > current_render + expect(page).to have_css('body') { |body| + Time.parse(body['data-rendered-at']) > current_render } end diff --git a/spec/support/shared/ferrum_patches.rb b/spec/support/shared/ferrum_patches.rb index e3d14a231167..33b27f1eb053 100644 --- a/spec/support/shared/ferrum_patches.rb +++ b/spec/support/shared/ferrum_patches.rb @@ -35,7 +35,7 @@ # # Use this as a temporary patch -require "ferrum/errors" +require 'ferrum/errors' def ignore_ferrum_javascript_error yield @@ -50,7 +50,7 @@ module Ferrum class Network class Request def loader_id - @params["loaderId"] + @params['loaderId'] end end diff --git a/spec/support/shared/forms_html.rb b/spec/support/shared/forms_html.rb index 23d429425148..99c199f7a4e7 100644 --- a/spec/support/shared/forms_html.rb +++ b/spec/support/shared/forms_html.rb @@ -26,59 +26,59 @@ # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_examples_for "labelled" do - it "has a label with title" do - expect(subject).to have_css "label.form--label[title]" +RSpec.shared_examples_for 'labelled' do + it 'has a label with title' do + expect(subject).to have_css 'label.form--label[title]' end end -RSpec.shared_examples_for "not labelled" do - it "does not have a label with title" do - expect(subject).to have_no_css "label.form--label[title]" +RSpec.shared_examples_for 'not labelled' do + it 'does not have a label with title' do + expect(subject).to have_no_css 'label.form--label[title]' end end -RSpec.shared_examples_for "labelled by default" do - context "by default" do - it_behaves_like "labelled" +RSpec.shared_examples_for 'labelled by default' do + context 'by default' do + it_behaves_like 'labelled' end - context "with no_label option" do + context 'with no_label option' do let(:options) { { no_label: true, label: false } } - it_behaves_like "not labelled" + it_behaves_like 'not labelled' end end -RSpec.shared_examples_for "wrapped in container" do |container = "field-container"| +RSpec.shared_examples_for 'wrapped in container' do |container = 'field-container'| it { is_expected.to have_css "span.form--#{container}", count: 1 } - context "with additional class provided" do - let(:css_class) { "my-additional-class" } + context 'with additional class provided' do + let(:css_class) { 'my-additional-class' } let(:expected_container_count) { defined?(container_count) ? container_count : 1 } before do options[:container_class] = css_class end - it "has the class" do + it 'has the class' do expect(subject).to have_css "span.#{css_class}", count: expected_container_count end end end -RSpec.shared_examples_for "not wrapped in container" do |container = "field-container"| +RSpec.shared_examples_for 'not wrapped in container' do |container = 'field-container'| it { is_expected.to have_no_css "span.form--#{container}" } end -RSpec.shared_examples_for "wrapped in field-container by default" do - context "by default" do - it_behaves_like "wrapped in container" +RSpec.shared_examples_for 'wrapped in field-container by default' do + context 'by default' do + it_behaves_like 'wrapped in container' end - context "with no_label option" do + context 'with no_label option' do let(:options) { { no_label: true, label: false } } - it_behaves_like "not wrapped in container" + it_behaves_like 'not wrapped in container' end end diff --git a/spec/support/shared/loading_indicator_saveguard.rb b/spec/support/shared/loading_indicator_saveguard.rb index 558ed9f10a10..835436805003 100644 --- a/spec/support/shared/loading_indicator_saveguard.rb +++ b/spec/support/shared/loading_indicator_saveguard.rb @@ -34,5 +34,5 @@ # def loading_indicator_saveguard - expect(page).to have_no_css(".op-loading-indicator") + expect(page).to have_no_css('.op-loading-indicator') end diff --git a/spec/support/shared/permissions.rb b/spec/support/shared/permissions.rb index 42f1365534b3..bae5e9b4d82e 100644 --- a/spec/support/shared/permissions.rb +++ b/spec/support/shared/permissions.rb @@ -28,10 +28,10 @@ module PermissionSpecHelpers def spec_permissions(test_denied = true) - describe "w/ valid auth" do + describe 'w/ valid auth' do before { allow(User).to receive(:current).and_return valid_user } - it "grants access" do + it 'grants access' do fetch if respond_to? :expect_redirect_to @@ -54,10 +54,10 @@ def spec_permissions(test_denied = true) end if test_denied - describe "w/o valid auth" do + describe 'w/o valid auth' do before { allow(User).to receive(:current).and_return invalid_user } - it "denies access" do + it 'denies access' do fetch if invalid_user.logged? @@ -74,14 +74,14 @@ def spec_permissions(test_denied = true) end end -RSpec.shared_context "a controller action with unrestricted access" do +RSpec.shared_context 'a controller action with unrestricted access' do let(:valid_user) { create(:anonymous) } extend PermissionSpecHelpers spec_permissions(false) end -RSpec.shared_context "a controller action with require_login" do +RSpec.shared_context 'a controller action with require_login' do let(:valid_user) { create(:user) } let(:invalid_user) { create(:anonymous) } @@ -89,7 +89,7 @@ def spec_permissions(test_denied = true) spec_permissions end -RSpec.shared_context "a controller action with require_admin" do +RSpec.shared_context 'a controller action with require_admin' do let(:valid_user) { User.where(admin: true).first || create(:admin) } let(:invalid_user) { create(:user) } @@ -97,7 +97,7 @@ def spec_permissions(test_denied = true) spec_permissions end -RSpec.shared_context "a controller action which needs project permissions" do +RSpec.shared_context 'a controller action which needs project permissions' do # Expecting the following environment # # let(:project) { create(:project) } diff --git a/spec/support/shared/rake.rb b/spec/support/shared/rake.rb index 3b49e8948b5d..08af9dcb612e 100644 --- a/spec/support/shared/rake.rb +++ b/spec/support/shared/rake.rb @@ -29,9 +29,9 @@ # Origins from http://robots.thoughtbot.com/test-rake-tasks-like-a-boss # Author: Josh Clayton -require "rake" +require 'rake' -RSpec.shared_context "rake" do +RSpec.shared_context 'rake' do let(:rake) { Rake::Application.new } let(:task_name) { self.class.description } let(:task_path) { "lib/tasks/#{task_name.split(':').first}" } diff --git a/spec/support/shared/require_admin.rb b/spec/support/shared/require_admin.rb index 7312c89981a2..1954fe5d40d6 100644 --- a/spec/support/shared/require_admin.rb +++ b/spec/support/shared/require_admin.rb @@ -27,20 +27,20 @@ #++ def require_admin_and_render_template(path) - describe "GET #show" do - subject { get "show" } + describe 'GET #show' do + subject { get 'show' } - describe "permissions" do + describe 'permissions' do let(:fetch) { subject } - it_behaves_like "a controller action with require_admin" + it_behaves_like 'a controller action with require_admin' end - it "renders the API settings template" do + it 'renders the API settings template' do subject expect(response).to be_successful - expect(response).to render_template "admin/settings/#{path}/show", "layouts/admin" + expect(response).to render_template "admin/settings/#{path}/show", 'layouts/admin' end end end diff --git a/spec/support/shared/with_blank_access_control_state.rb b/spec/support/shared/with_blank_access_control_state.rb index 9e8d1bf5e2ca..f77bb0060261 100644 --- a/spec/support/shared/with_blank_access_control_state.rb +++ b/spec/support/shared/with_blank_access_control_state.rb @@ -29,7 +29,7 @@ # Makes OpenProject::AccessControl clean before each example, like if no # permission initialization code was run at all, and restore it after each # example. -RSpec.shared_context "with blank access control state" do +RSpec.shared_context 'with blank access control state' do around do |example| stash = stash_instance_variables(OpenProject::AccessControl, :@mapped_permissions, :@modules, :@project_modules_without_permissions) diff --git a/spec/support/shared/with_direct_uploads.rb b/spec/support/shared/with_direct_uploads.rb index 72e1cc181e4b..ba2da109028d 100644 --- a/spec/support/shared/with_direct_uploads.rb +++ b/spec/support/shared/with_direct_uploads.rb @@ -96,10 +96,10 @@ def mock_attachment end def stub_frontend(redirect: false) - proxy.stub("https://" + OpenProject::Configuration.remote_storage_upload_host + ":443/", method: "options").and_return( + proxy.stub("https://" + OpenProject::Configuration.remote_storage_upload_host + ":443/", method: 'options').and_return( headers: { - "Access-Control-Allow-Methods" => "POST", - "Access-Control-Allow-Origin" => "*" + 'Access-Control-Allow-Methods' => 'POST', + 'Access-Control-Allow-Origin' => '*' }, code: 200 ) @@ -113,18 +113,18 @@ def stub_frontend(redirect: false) def stub_with_redirect proxy - .stub("https://" + OpenProject::Configuration.remote_storage_upload_host + ":443/", method: "post") + .stub("https://" + OpenProject::Configuration.remote_storage_upload_host + ":443/", method: 'post') .and_return(Proc.new do |_params, _headers, body, _url, _method| key = body.scan(/key"\s*([^\s]+)\s/m).flatten.first redirect_url = body.scan(/success_action_redirect"\s*(http[^\s]+)\s/m).flatten.first - ok = body.include?("X-Amz-Signature") # check that the expected post to AWS was made with the form fields + ok = body.include?('X-Amz-Signature') # check that the expected post to AWS was made with the form fields { code: ok ? 302 : 403, headers: { - "Location" => ok ? redirect_url + "?key=" + CGI.escape(key) : nil, - "Access-Control-Allow-Methods" => "POST", - "Access-Control-Allow-Origin" => "*" + 'Location' => ok ? redirect_url + '?key=' + CGI.escape(key) : nil, + 'Access-Control-Allow-Methods' => 'POST', + 'Access-Control-Allow-Origin' => '*' } } end) @@ -132,13 +132,13 @@ def stub_with_redirect def stub_with_status proxy - .stub("https://" + OpenProject::Configuration.remote_storage_upload_host + ":443/", method: "post") + .stub("https://" + OpenProject::Configuration.remote_storage_upload_host + ":443/", method: 'post') .and_return(Proc.new do |_params, _headers, body, _url, _method| { - code: body.include?("X-Amz-Signature") ? 201 : 403, # check that the expected post to AWS was made with the form fields + code: body.include?('X-Amz-Signature') ? 201 : 403, # check that the expected post to AWS was made with the form fields headers: { - "Access-Control-Allow-Methods" => "POST", - "Access-Control-Allow-Origin" => "*" + 'Access-Control-Allow-Methods' => 'POST', + 'Access-Control-Allow-Origin' => '*' } } end) diff --git a/spec/support/shared/with_ee.rb b/spec/support/shared/with_ee.rb index 11e4759ffdc2..d4c597f8ac72 100644 --- a/spec/support/shared/with_ee.rb +++ b/spec/support/shared/with_ee.rb @@ -31,7 +31,7 @@ def assert_valid_ee_action(action, example) return if valid_ee_actions.include?(action) spell_checker = DidYouMean::SpellChecker.new(dictionary: valid_ee_actions) - suggestions = spell_checker.correct(action).map(&:inspect).join(" ") + suggestions = spell_checker.correct(action).map(&:inspect).join(' ') did_you_mean = " Did you mean #{suggestions} instead?" if suggestions.present? raise "Invalid Enterprise action #{action.inspect} at #{example.location}.#{did_you_mean}" diff --git a/spec/support/shared/with_good_job.rb b/spec/support/shared/with_good_job.rb deleted file mode 100644 index 1cdf84367ae7..000000000000 --- a/spec/support/shared/with_good_job.rb +++ /dev/null @@ -1,53 +0,0 @@ -#-- copyright -# OpenProject is an open source project management software. -# Copyright (C) 2012-2024 the OpenProject GmbH -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version 3. -# -# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: -# Copyright (C) 2006-2013 Jean-Philippe Lang -# Copyright (C) 2010-2013 the ChiliProject Team -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -# -# See COPYRIGHT and LICENSE files for more details. -#++ - -# Disable the test adapter for the given classes -# allowing GoodJob to handle execution and scheduling, -# which in turn allows us to check concurrency controls etc. -RSpec.configure do |config| - config.around(:example, :with_good_job) do |example| - original_adapter = ActiveJob::Base.queue_adapter - good_job_adapter = GoodJob::Adapter.new(execution_mode: :inline) - - begin - classes = Array(example.metadata[:with_good_job]) - unless classes.all? { |cls| cls <= ApplicationJob } - raise ArgumentError.new("Pass the ApplicationJob subclasses you want to disable the test adapter on.") - end - - classes.each(&:disable_test_adapter) - ActiveJob::Base.queue_adapter = good_job_adapter - example.run - - ensure - ActiveJob::Base.queue_adapter = original_adapter - classes.each { |cls| cls.enable_test_adapter(original_adapter) } - good_job_adapter&.shutdown - end - end -end diff --git a/spec/support/shared/with_mobile_screen.rb b/spec/support/shared/with_mobile_screen.rb index cb4f851bb941..5ebaceeb14e7 100644 --- a/spec/support/shared/with_mobile_screen.rb +++ b/spec/support/shared/with_mobile_screen.rb @@ -24,7 +24,7 @@ # # See COPYRIGHT and LICENSE files for more details. -RSpec.shared_context "with mobile screen size" do |width, height| +RSpec.shared_context 'with mobile screen size' do |width, height| let!(:height_before) do if using_cuprite? page.current_window.size.second diff --git a/spec/support/shared/with_settings.rb b/spec/support/shared/with_settings.rb index 0794c6de5d66..19d8fb01f1c9 100644 --- a/spec/support/shared/with_settings.rb +++ b/spec/support/shared/with_settings.rb @@ -38,7 +38,7 @@ def aggregate_mocked_settings(example, settings) settings end -RSpec.shared_context "with settings reset" do +RSpec.shared_context 'with settings reset' do shared_let(:definitions_before) { Settings::Definition.all.dup } def reset(setting) @@ -51,14 +51,14 @@ def stub_configuration_yml allow(Rails.env).to receive(:test?).and_return(false) allow(File) .to receive(:file?) - .with(Rails.root.join("config/configuration.yml")) + .with(Rails.root.join('config/configuration.yml')) .and_return(true) # It is added to avoid warning about other File.read calls. allow(File).to receive(:read).and_call_original allow(File) .to receive(:read) - .with(Rails.root.join("config/configuration.yml")) + .with(Rails.root.join('config/configuration.yml')) .and_return(configuration_yml) end @@ -79,7 +79,7 @@ def with_settings(settings) allow(Setting).to receive(:[]).and_call_original settings.each do |k, v| - name = k.to_s.sub(/\?\Z/, "") # remove trailing question mark if present to get setting name + name = k.to_s.sub(/\?\Z/, '') # remove trailing question mark if present to get setting name raise "#{k} is not a valid setting" unless Setting.respond_to?(name) @@ -112,7 +112,7 @@ def with_settings(settings) end end -RSpec.shared_context "with settings" do +RSpec.shared_context 'with settings' do before do with_settings(settings) end diff --git a/spec/support/skip_if_command_unavailable.rb b/spec/support/skip_if_command_unavailable.rb index f0b6de62fa09..dc0abc07e6ee 100644 --- a/spec/support/skip_if_command_unavailable.rb +++ b/spec/support/skip_if_command_unavailable.rb @@ -34,11 +34,11 @@ module SkipIfCommandUnavailableMixin # # The test is not skipped if in continuous integration environment. def skip_if_commands_unavailable(*commands) - return if ENV["CI"] + return if ENV['CI'] commands.flatten.compact.each do |cmd| # Avoid `which`, as it's not POSIX - Open3.capture2e(cmd, "--version") + Open3.capture2e(cmd, '--version') rescue Errno::ENOENT skip "Skipped because '#{cmd}' command not found in PATH" end diff --git a/spec/support/support_links.rb b/spec/support/support_links.rb index 3b0865e3a0e9..6243fa098594 100644 --- a/spec/support/support_links.rb +++ b/spec/support/support_links.rb @@ -29,8 +29,8 @@ # ++ # rubocop:disable RSpec/ContextWording -RSpec.shared_context "support links" do - let(:support_link_as_community) { "https://www.openproject.org/pricing/#support" } - let(:support_link_as_enterprise) { "https://www.openproject.org/docs/enterprise-guide/support/" } +RSpec.shared_context 'support links' do + let(:support_link_as_community) { 'https://www.openproject.org/pricing/#support' } + let(:support_link_as_enterprise) { 'https://www.openproject.org/docs/enterprise-guide/support/' } end # rubocop:enable RSpec/ContextWording diff --git a/spec/support/table_helpers.rb b/spec/support/table_helpers.rb index e4597d06e140..044bbcee7e80 100644 --- a/spec/support/table_helpers.rb +++ b/spec/support/table_helpers.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -Dir[Rails.root.join("spec/support/table_helpers/*.rb")].each { |f| require f } +Dir[Rails.root.join('spec/support/table_helpers/*.rb')].each { |f| require f } RSpec.configure do |config| config.extend TableHelpers::LetWorkPackages diff --git a/spec/support/table_helpers/column.rb b/spec/support/table_helpers/column.rb index d4753d0f4474..48d1184f351e 100644 --- a/spec/support/table_helpers/column.rb +++ b/spec/support/table_helpers/column.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require_relative "identifier" +require_relative 'identifier' module TableHelpers module Column @@ -131,7 +131,7 @@ def text_align def format(value) if value.nil? - "" + '' elsif value == value.truncate "%sh" % value.to_i else diff --git a/spec/support/table_helpers/identifier.rb b/spec/support/table_helpers/identifier.rb index 5289dbe7d73e..155cabfb61c3 100644 --- a/spec/support/table_helpers/identifier.rb +++ b/spec/support/table_helpers/identifier.rb @@ -35,8 +35,8 @@ module Identifier def to_identifier(name) name = name.downcase name.strip! - name.tr!(' \-', "_") - name.gsub!(/_+(?=\d)/, "") + name.tr!(' \-', '_') + name.gsub!(/_+(?=\d)/, '') name.to_sym end end diff --git a/spec/support/table_helpers/table.rb b/spec/support/table_helpers/table.rb index 7f45a558fe3c..6ac342651c75 100644 --- a/spec/support/table_helpers/table.rb +++ b/spec/support/table_helpers/table.rb @@ -44,7 +44,7 @@ def normalize_name(name) return symbolic_name if @work_packages_by_identifier.has_key?(symbolic_name) spell_checker = DidYouMean::SpellChecker.new(dictionary: @work_packages_by_identifier.keys.map(&:to_s)) - suggestions = spell_checker.correct(name).map(&:inspect).join(" ") + suggestions = spell_checker.correct(name).map(&:inspect).join(' ') did_you_mean = " Did you mean #{suggestions} instead?" if suggestions.present? raise "No work package with name #{name.inspect} in _table.#{did_you_mean}" end diff --git a/spec/support/table_helpers/table_parser.rb b/spec/support/table_helpers/table_parser.rb index b77c02a87830..39f8518bd026 100644 --- a/spec/support/table_helpers/table_parser.rb +++ b/spec/support/table_helpers/table_parser.rb @@ -32,7 +32,7 @@ module TableHelpers class TableParser def parse(representation) headers, *rows = representation.split("\n") - headers = headers.split("|") + headers = headers.split('|') rows = rows.filter_map { |row| parse_row(row, headers) } work_packages_data = rows.map.with_index do |row, index| { @@ -52,10 +52,10 @@ def parse(representation) def parse_row(row, headers) case row - when "", /^\s*#/ + when '', /^\s*#/ # noop else - values = row.split("|") + values = row.split('|') headers.zip(values).to_h.compact_blank end end diff --git a/spec/support/tempdir.rb b/spec/support/tempdir.rb index 417f8aabe6b8..179e38fe17cd 100644 --- a/spec/support/tempdir.rb +++ b/spec/support/tempdir.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -RSpec.shared_context "with tmpdir" do +RSpec.shared_context 'with tmpdir' do around do |example| Dir.mktmpdir do |dir| @tmpdir = dir diff --git a/spec/support/toasts/expectations.rb b/spec/support/toasts/expectations.rb index acd09fc346cf..a50fdfc83b02 100644 --- a/spec/support/toasts/expectations.rb +++ b/spec/support/toasts/expectations.rb @@ -20,7 +20,7 @@ def expect_and_dismiss_toaster(message: nil, type: :success) def dismiss_toaster! sleep 0.1 - page.find(".op-toast--close").click + page.find('.op-toast--close').click end def expect_no_toaster(type: :success, message: nil, wait: 10) diff --git a/spec/support/vcr.rb b/spec/support/vcr.rb index b4e22e39c596..86360880e0c0 100644 --- a/spec/support/vcr.rb +++ b/spec/support/vcr.rb @@ -28,37 +28,37 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "vcr" +require 'vcr' VCR.configure do |config| - config.cassette_library_dir = "spec/support/fixtures/vcr_cassettes" + config.cassette_library_dir = 'spec/support/fixtures/vcr_cassettes' config.hook_into :webmock config.configure_rspec_metadata! config.before_record do |i| - i.response.body.force_encoding("UTF-8") + i.response.body.force_encoding('UTF-8') end - config.filter_sensitive_data "" do |interaction| - header = interaction.request.headers["Authorization"]&.first&.split + config.filter_sensitive_data '' do |interaction| + header = interaction.request.headers['Authorization']&.first&.split - header.last if header&.first == "Basic" + header.last if header&.first == 'Basic' end - config.filter_sensitive_data "" do |interaction| - header = interaction.request.headers["Authorization"]&.first&.split + config.filter_sensitive_data '' do |interaction| + header = interaction.request.headers['Authorization']&.first&.split - header.last if header&.first == "Bearer" + header.last if header&.first == 'Bearer' end - config.filter_sensitive_data "" do |interaction| - header_value = interaction.response.headers["Content-Type"]&.first + config.filter_sensitive_data '' do |interaction| + header_value = interaction.response.headers['Content-Type']&.first - if header_value&.include?("application/json") - MultiJson.load(interaction.response.body)["access_token"] + if header_value&.include?('application/json') + MultiJson.load(interaction.response.body)['access_token'] end end - config.default_cassette_options = { record: ENV.fetch("VCR_RECORD_MODE", :once).to_sym, drop_unused_requests: true } + config.default_cassette_options = { record: ENV.fetch('VCR_RECORD_MODE', :once).to_sym, drop_unused_requests: true } end VCR.turn_off! diff --git a/spec/support/view_components.rb b/spec/support/view_components.rb index fa5397fd931b..ccf0845157d2 100644 --- a/spec/support/view_components.rb +++ b/spec/support/view_components.rb @@ -28,8 +28,8 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "view_component/test_helpers" -require "capybara/rspec" +require 'view_component/test_helpers' +require 'capybara/rspec' RSpec.configure do |config| config.include ViewComponent::TestHelpers, type: :component diff --git a/spec/support/wait_for.rb b/spec/support/wait_for.rb index 6a2a93f3f8a8..c745093be9a7 100644 --- a/spec/support/wait_for.rb +++ b/spec/support/wait_for.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true -require_relative "wait/handler" -require_relative "wait/target" +require_relative 'wait/handler' +require_relative 'wait/target' # borrowed from rspec-wait, avoiding usage of Timeout module RSpec diff --git a/spec/support/webmock.rb b/spec/support/webmock.rb index 2a24ea29f80b..3037051504bf 100644 --- a/spec/support/webmock.rb +++ b/spec/support/webmock.rb @@ -27,7 +27,7 @@ #++ require "httpx/adapters/webmock" -require "webmock/rspec" +require 'webmock/rspec' RSpec.configure do |config| config.before(:suite) do @@ -45,8 +45,8 @@ # * chromedriver, since it might need to be downloaded WebMock.disable_net_connect!(allow_localhost: true, allow: ["selenium-hub", Capybara.server_host, - "chromedriver.storage.googleapis.com", - "openproject-ci-public-logs.s3.eu-west-1.amazonaws.com"]) + 'chromedriver.storage.googleapis.com', + 'openproject-ci-public-logs.s3.eu-west-1.amazonaws.com']) WebMock.enable! example.run ensure diff --git a/spec/support/work_packages/pdf_export.rb b/spec/support/work_packages/pdf_export.rb index e5b8de16b4b9..2d7c266098b1 100644 --- a/spec/support/work_packages/pdf_export.rb +++ b/spec/support/work_packages/pdf_export.rb @@ -1,5 +1,5 @@ -require "spec_helper" -require "pdf/inspector" +require 'spec_helper' +require 'pdf/inspector' module PDFExportSpecUtils def column_title(column_name) diff --git a/spec/support/work_packages/work_package_cards.rb b/spec/support/work_packages/work_package_cards.rb index 971dd45997d5..5f1fe725f325 100644 --- a/spec/support/work_packages/work_package_cards.rb +++ b/spec/support/work_packages/work_package_cards.rb @@ -25,7 +25,7 @@ # # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' class WorkPackageCards include Capybara::DSL diff --git a/spec/support_spec/mocked_permission_helper_spec.rb b/spec/support_spec/mocked_permission_helper_spec.rb index 09f43166ca80..a8aaec5e89bb 100644 --- a/spec/support_spec/mocked_permission_helper_spec.rb +++ b/spec/support_spec/mocked_permission_helper_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe MockedPermissionHelper do let(:user) { build(:user) } @@ -36,8 +36,8 @@ let(:other_work_package_in_project) { build(:work_package, project:) } let(:other_work_package) { build(:work_package) } - context "when trying to mock a permission that does not exist" do - it "raises UnknownPermissionError exception" do + context 'when trying to mock a permission that does not exist' do + it 'raises UnknownPermissionError exception' do expect do mock_permissions_for(user) do |mock| mock.allow_globally :this_permission_does_not_exist @@ -46,8 +46,8 @@ end end - context "when trying to mock a permission in the wrong context" do - it "raises IllegalPermissionContext exception" do + context 'when trying to mock a permission in the wrong context' do + it 'raises IllegalPermissionContext exception' do expect do mock_permissions_for(user) do |mock| mock.allow_globally :view_work_packages # this is a project/work_package permission @@ -56,8 +56,8 @@ end end - context "when trying to mock a permission on nil as the project" do - it "raises an ArgumentError exception" do + context 'when trying to mock a permission on nil as the project' do + it 'raises an ArgumentError exception' do expect do mock_permissions_for(user) do |mock| mock.allow_in_project :view_work_packages, project: nil @@ -66,8 +66,8 @@ end end - context "when trying to mock a permission on nil as the work package" do - it "raises an ArgumentError exception" do + context 'when trying to mock a permission on nil as the work package' do + it 'raises an ArgumentError exception' do expect do mock_permissions_for(user) do |mock| mock.allow_in_work_package :view_work_packages, work_package: nil @@ -76,15 +76,15 @@ end end - context "when not providing a block" do - it "does not allow anything" do + context 'when not providing a block' do + it 'does not allow anything' do expect do mock_permissions_for(user) end.to raise_error(ArgumentError) end end - context "when explicitly forbidding everything" do + context 'when explicitly forbidding everything' do before do mock_permissions_for(user) do |mock| mock.allow_everything @@ -96,7 +96,7 @@ end end - it "does not allow anything" do + it 'does not allow anything' do expect(user).not_to be_allowed_globally(:add_project) expect(user).not_to be_allowed_in_project(:add_work_packages, project) expect(user).not_to be_allowed_in_any_project(:add_work_packages) @@ -105,12 +105,12 @@ end end - context "when mocking all permissions" do + context 'when mocking all permissions' do before do mock_permissions_for(user, &:allow_everything) end - it "allows everything" do + it 'allows everything' do expect(user).to be_allowed_globally(:add_project) expect(user).to be_allowed_in_project(:add_work_packages, project) expect(user).to be_allowed_in_any_project(:add_work_packages) @@ -124,7 +124,7 @@ end end - context "when running the mock service multiple times" do + context 'when running the mock service multiple times' do before do mock_permissions_for(user) do |mock| mock.allow_globally :add_project @@ -136,41 +136,41 @@ end end - it "only allows the permissions from the last run" do + it 'only allows the permissions from the last run' do expect(user).not_to be_allowed_globally(:add_project) expect(user).to be_allowed_globally(:manage_user) end end - context "when mocking a global permission" do + context 'when mocking a global permission' do before do mock_permissions_for(user) do |mock| mock.allow_globally :add_project end end - it "allows the global permission" do + it 'allows the global permission' do expect(user).to be_allowed_globally(:add_project) end - it "allows the global permission when querying with controller and action hash" do - expect(user).to be_allowed_globally({ controller: "projects", action: "new" }) + it 'allows the global permission when querying with controller and action hash' do + expect(user).to be_allowed_globally({ controller: 'projects', action: 'new' }) end - it "allows the global permission using the deprecated interface" do + it 'allows the global permission using the deprecated interface' do expect(user).to be_allowed_to_globally(:add_project) expect(user).to be_allowed_to(:add_project, nil, global: true) end end - context "when mocking a permission in the project" do + context 'when mocking a permission in the project' do before do mock_permissions_for(user) do |mock| mock.allow_in_project :view_work_packages, :add_work_packages, project: end end - it "allows the permissions when asking for the project" do + it 'allows the permissions when asking for the project' do expect(user).to be_allowed_in_project(:view_work_packages, project) expect(user).not_to be_allowed_in_project(:view_work_packages, other_project) @@ -178,23 +178,23 @@ expect(user).not_to be_allowed_in_project(:add_work_packages, other_project) end - it "allows the project permission when querying with controller and action hash" do - expect(user).to be_allowed_in_project({ controller: "work_packages", action: "index", project_id: project.id }) - expect(user).to be_allowed_in_any_project({ controller: "work_packages", action: "index" }) + it 'allows the project permission when querying with controller and action hash' do + expect(user).to be_allowed_in_project({ controller: 'work_packages', action: 'index', project_id: project.id }) + expect(user).to be_allowed_in_any_project({ controller: 'work_packages', action: 'index' }) end - it "allows the permission when using the deprecated interface" do + it 'allows the permission when using the deprecated interface' do expect(user).to be_allowed_to_in_project(:view_work_packages, project) expect(user).to be_allowed_to(:view_work_packages, project) expect(user).to be_allowed_to_globally(:view_work_packages) end - it "allows the permissions when asking for any project" do + it 'allows the permissions when asking for any project' do expect(user).to be_allowed_in_any_project(:view_work_packages) expect(user).to be_allowed_in_any_project(:add_work_packages) end - it "allows the permissions when asking for any work package within the project" do + it 'allows the permissions when asking for any work package within the project' do expect(user).to be_allowed_in_any_work_package(:view_work_packages, in_project: project) expect(user).not_to be_allowed_in_any_work_package(:view_work_packages, in_project: other_project) @@ -202,20 +202,20 @@ expect(user).not_to be_allowed_in_any_work_package(:add_work_packages, in_project: other_project) end - it "allows the permissions when asking for any work package" do + it 'allows the permissions when asking for any work package' do expect(user).to be_allowed_in_any_work_package(:view_work_packages) expect(user).to be_allowed_in_any_work_package(:add_work_packages) expect(user).not_to be_allowed_in_any_work_package(:copy_work_packages) end - it "allows the permission when asking for a specific work package within the project" do + it 'allows the permission when asking for a specific work package within the project' do expect(user).to be_allowed_in_work_package(:view_work_packages, work_package_in_project) expect(user).not_to be_allowed_in_work_package(:view_work_packages, other_work_package) end end - context "when mocking a permission in the work package" do + context 'when mocking a permission in the work package' do before do mock_permissions_for(user) do |mock| mock.allow_in_work_package :view_work_packages, work_package: work_package_in_project @@ -223,16 +223,16 @@ end end - it "does not allow the permissions when asking for the project" do + it 'does not allow the permissions when asking for the project' do expect(user).not_to be_allowed_in_project(:view_work_packages, project) end - it "does not allow the permissions when asking for any project" do + it 'does not allow the permissions when asking for any project' do expect(user).not_to be_allowed_in_any_project(:view_work_packages) expect(user).not_to be_allowed_in_any_project(:edit_work_packages) end - it "allows the permissions when asking for any work package within the project" do + it 'allows the permissions when asking for any work package within the project' do expect(user).to be_allowed_in_any_work_package(:view_work_packages, in_project: project) expect(user).not_to be_allowed_in_any_work_package(:view_work_packages, in_project: other_project) @@ -242,22 +242,22 @@ expect(user).not_to be_allowed_in_any_work_package(:copy_work_packages, in_project: project) end - it "allows the work package permission when querying with controller and action hash" do - expect(user).to be_allowed_in_work_package({ controller: "work_packages", action: "index", project_id: project.id }, + it 'allows the work package permission when querying with controller and action hash' do + expect(user).to be_allowed_in_work_package({ controller: 'work_packages', action: 'index', project_id: project.id }, work_package_in_project) - expect(user).to be_allowed_in_any_work_package({ controller: "work_packages", action: "index", project_id: project.id }) - expect(user).to be_allowed_in_any_work_package({ controller: "work_packages", action: "index", project_id: project.id }, + expect(user).to be_allowed_in_any_work_package({ controller: 'work_packages', action: 'index', project_id: project.id }) + expect(user).to be_allowed_in_any_work_package({ controller: 'work_packages', action: 'index', project_id: project.id }, in_project: project) end - it "allows the permissions when asking for any work package" do + it 'allows the permissions when asking for any work package' do expect(user).to be_allowed_in_any_work_package(:view_work_packages) expect(user).to be_allowed_in_any_work_package(:edit_work_packages) expect(user).not_to be_allowed_in_any_work_package(:copy_work_packages) end - it "allows the permission when asking for a specific work package within the project" do + it 'allows the permission when asking for a specific work package within the project' do expect(user).to be_allowed_in_work_package(:view_work_packages, work_package_in_project) expect(user).to be_allowed_in_work_package(:view_work_packages, other_work_package_in_project) expect(user).not_to be_allowed_in_work_package(:view_work_packages, other_work_package) diff --git a/spec/support_spec/schedule_helpers/chart_builder_spec.rb b/spec/support_spec/schedule_helpers/chart_builder_spec.rb index 096dd94a5d2d..de717b407aaa 100644 --- a/spec/support_spec/schedule_helpers/chart_builder_spec.rb +++ b/spec/support_spec/schedule_helpers/chart_builder_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ScheduleHelpers::ChartBuilder do include ActiveSupport::Testing::TimeHelpers @@ -42,14 +42,14 @@ subject(:builder) { described_class.new } - describe "happy path" do + describe 'happy path' do let(:next_tuesday) { tuesday + 7.days } before do travel_to(fake_today) end - it "reads a chart and convert it into objects with attributes" do + it 'reads a chart and convert it into objects with attributes' do chart = builder.parse(<<~CHART) days | MTWTFSS | main | XX | @@ -61,12 +61,12 @@ CHART expect(chart.work_packages_attributes).to eq( [ - { name: :main, subject: "main", start_date: monday, due_date: tuesday }, - { name: :other, subject: "other", start_date: thursday, due_date: next_tuesday }, - { name: :follower, subject: "follower", start_date: wednesday, due_date: friday }, - { name: :start_only, subject: "start_only", start_date: tuesday, due_date: nil }, - { name: :due_only, subject: "due_only", start_date: nil, due_date: friday }, - { name: :no_dates, subject: "no_dates", start_date: nil, due_date: nil } + { name: :main, subject: 'main', start_date: monday, due_date: tuesday }, + { name: :other, subject: 'other', start_date: thursday, due_date: next_tuesday }, + { name: :follower, subject: 'follower', start_date: wednesday, due_date: friday }, + { name: :start_only, subject: 'start_only', start_date: tuesday, due_date: nil }, + { name: :due_only, subject: 'due_only', start_date: nil, due_date: friday }, + { name: :no_dates, subject: 'no_dates', start_date: nil, due_date: nil } ] ) expect(chart.predecessors_by_follower(:main)).to eq([]) @@ -75,12 +75,12 @@ end end - describe "origin day" do + describe 'origin day' do before do travel_to(fake_today) end - it "is identified by the M in MTWTFSS and corresponds to next monday" do + it 'is identified by the M in MTWTFSS and corresponds to next monday' do chart = builder.parse(<<~CHART) days | MTWTFSS | CHART @@ -88,7 +88,7 @@ expect(chart.monday).to eq(chart.first_day) end - it "is not identified by mtwtfss which can be used as documentation instead" do + it 'is not identified by mtwtfss which can be used as documentation instead' do chart = builder.parse(<<~CHART) days | mtwtfssMTWTFSSmtwtfss | wp | X | @@ -98,9 +98,9 @@ end end - describe "properties" do - describe "follows " do - it "adds a follows relation to the named" do + describe 'properties' do + describe 'follows ' do + it 'adds a follows relation to the named' do chart = builder.parse(<<~CHART) days | MTWTFSS | main | | @@ -110,7 +110,7 @@ expect(chart.delay_between(predecessor: :main, follower: :follower)).to eq(0) end - it "can be declared in any order" do + it 'can be declared in any order' do chart = builder.parse(<<~CHART) days | MTWTFSS | follower | | follows main @@ -121,8 +121,8 @@ end end - describe "follows with delay " do - it "adds a follows relation to the named with a delay" do + describe 'follows with delay ' do + it 'adds a follows relation to the named with a delay' do chart = builder.parse(<<~CHART) days | MTWTFSS | main | | @@ -133,8 +133,8 @@ end end - describe "child of " do - it "sets the parent to the named one" do + describe 'child of ' do + it 'sets the parent to the named one' do chart = builder.parse(<<~CHART) days | MTWTFSS | parent | | child of grandparent @@ -147,8 +147,8 @@ end end - describe "duration " do - it "sets the duration of the work package" do + describe 'duration ' do + it 'sets the duration of the work package' do chart = builder.parse(<<~CHART) days | MTWTFSS | main | | duration 3 @@ -157,8 +157,8 @@ end end - describe "working days work week" do - it "sets ignore_non_working_days to false for the work package" do + describe 'working days work week' do + it 'sets ignore_non_working_days to false for the work package' do chart = builder.parse(<<~CHART) days | MTWTFSS | main | | working days work week @@ -167,8 +167,8 @@ end end - describe "working days include weekends" do - it "sets ignore_non_working_days to true for the work package" do + describe 'working days include weekends' do + it 'sets ignore_non_working_days to true for the work package' do chart = builder.parse(<<~CHART) days | MTWTFSS | main | | working days include weekends @@ -178,8 +178,8 @@ end end - describe "error handling" do - it "raises an error if the relation references a non-existing work package predecessor" do + describe 'error handling' do + it 'raises an error if the relation references a non-existing work package predecessor' do expect do builder.parse(<<~CHART) | MTWTFSS | diff --git a/spec/support_spec/schedule_helpers/chart_representer_spec.rb b/spec/support_spec/schedule_helpers/chart_representer_spec.rb index 3bb65202c954..c09d495cd296 100644 --- a/spec/support_spec/schedule_helpers/chart_representer_spec.rb +++ b/spec/support_spec/schedule_helpers/chart_representer_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ScheduleHelpers::ChartRepresenter do - describe "#normalized_to_s" do + describe '#normalized_to_s' do shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } - context "when both charts have different work packages items and/or order" do + context 'when both charts have different work packages items and/or order' do def to_first_columns(charts) - charts.map { _1.split("\n").map(&:split).map(&:first).join(" ") } + charts.map { _1.split("\n").map(&:split).map(&:first).join(' ') } end - it "returns charts ascii with work packages in same order as the first given chart" do + it 'returns charts ascii with work packages in same order as the first given chart' do initial_expected_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -59,7 +59,7 @@ def to_first_columns(charts) expect(actual_column).to eq(expected_column) end - it "pushes extra elements of the second chart at the end" do + it 'pushes extra elements of the second chart at the end' do initial_expected_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -79,11 +79,11 @@ def to_first_columns(charts) .normalized_to_s(initial_expected_chart, initial_actual_chart) .then(&method(:to_first_columns)) - expect(expected_column).to eq("days main other") - expect(actual_column).to eq("days main other extra") + expect(expected_column).to eq('days main other') + expect(actual_column).to eq('days main other extra') end - it "keeps extra elements of the first chart at the same place" do + it 'keeps extra elements of the first chart at the same place' do initial_expected_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -103,17 +103,17 @@ def to_first_columns(charts) .normalized_to_s(initial_expected_chart, initial_actual_chart) .then(&method(:to_first_columns)) - expect(expected_column).to eq("days main extra other") - expect(actual_column).to eq("days main other") + expect(expected_column).to eq('days main extra other') + expect(actual_column).to eq('days main other') end end - context "when both charts have different first column width" do + context 'when both charts have different first column width' do def to_first_cells(charts) charts.map { _1.split("\n").first.split(" | ").first } end - it "returns charts ascii with identical first column width" do + it 'returns charts ascii with identical first column width' do tiny_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -131,7 +131,7 @@ def to_first_cells(charts) .normalized_to_s(tiny_chart, longer_chart) .then(&method(:to_first_cells)) - expect(first_cell).to eq("days ") + expect(first_cell).to eq('days ') expect(first_cell).to eq(second_cell) # tiny_chart as reference chart @@ -140,17 +140,17 @@ def to_first_cells(charts) .normalized_to_s(longer_chart, tiny_chart) .then(&method(:to_first_cells)) - expect(first_cell).to eq("days ") + expect(first_cell).to eq('days ') expect(first_cell).to eq(second_cell) end end - context "when both charts cover different time periods" do + context 'when both charts cover different time periods' do def to_headers(charts) charts.map { _1.split("\n").first } end - it "returns charts ascii with identical time periods" do + it 'returns charts ascii with identical time periods' do larger_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -180,12 +180,12 @@ def to_headers(charts) end end - context "when expected chart does not have working days information" do + context 'when expected chart does not have working days information' do def to_headers(charts) charts.map { _1.split("\n").first } end - it "gets it from actual chart information" do + it 'gets it from actual chart information' do # in real tests, actual will probably be created from WorkPackage instances actual_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) @@ -207,7 +207,7 @@ def to_headers(charts) expect(normalized_actual).to eq(normalized_expected) end - it "ignores working days information for extra work packages not defined in actual" do + it 'ignores working days information for extra work packages not defined in actual' do initial_actual_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -225,12 +225,12 @@ def to_headers(charts) end end - context "when expected chart has different working days information from actual" do + context 'when expected chart has different working days information from actual' do def to_headers(charts) charts.map { _1.split("\n").first } end - it "use each information from each side" do + it 'use each information from each side' do # in real tests, actual will probably be created from WorkPackage instances actual_chart = ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) diff --git a/spec/support_spec/schedule_helpers/chart_spec.rb b/spec/support_spec/schedule_helpers/chart_spec.rb index 3873d26f6719..36a3c4649f9c 100644 --- a/spec/support_spec/schedule_helpers/chart_spec.rb +++ b/spec/support_spec/schedule_helpers/chart_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ScheduleHelpers::Chart do include ActiveSupport::Testing::TimeHelpers @@ -46,12 +46,12 @@ travel_to(fake_today) end - describe "#first_day" do - it "returns the first day represented on the graph, which is next Monday" do + describe '#first_day' do + it 'returns the first day represented on the graph, which is next Monday' do expect(chart.first_day).to eq(monday) end - it "can be set to an earlier date by setting the origin monday to an earlier date" do + it 'can be set to an earlier date by setting the origin monday to an earlier date' do expect(chart.first_day).to eq(monday) # no change when origin is moved forward @@ -63,31 +63,31 @@ .to change(chart, :first_day).to(monday - 14.days) end - context "with work packages" do - it "returns the minimum between work packages dates and origin Monday" do + context 'with work packages' do + it 'returns the minimum between work packages dates and origin Monday' do expect(chart.first_day).to eq(monday) - chart.add_work_package(subject: "wp1", start_date: tuesday) + chart.add_work_package(subject: 'wp1', start_date: tuesday) expect(chart.first_day).to eq(monday) - chart.add_work_package(subject: "wp2", start_date: monday - 3.days) + chart.add_work_package(subject: 'wp2', start_date: monday - 3.days) expect(chart.first_day).to eq(monday - 3.days) - chart.add_work_package(subject: "wp3", start_date: sunday) + chart.add_work_package(subject: 'wp3', start_date: sunday) expect(chart.first_day).to eq(monday - 3.days) - chart.add_work_package(subject: "wp4", due_date: monday - 6.days) + chart.add_work_package(subject: 'wp4', due_date: monday - 6.days) expect(chart.first_day).to eq(monday - 6.days) end end end - describe "#last_day" do - it "returns the last day represented on the graph, which is the Sunday following origin Monday" do + describe '#last_day' do + it 'returns the last day represented on the graph, which is the Sunday following origin Monday' do expect(chart.last_day).to eq(sunday) end - it "can be set to an later date by setting the origin Monday to a later date" do + it 'can be set to an later date by setting the origin Monday to a later date' do expect(chart.last_day).to eq(sunday) # no change when origin is moved backward @@ -99,28 +99,28 @@ .to change(chart, :last_day).to(sunday + 14.days) end - context "with work packages" do - it "returns the maximum between work packages dates and the Sunday following origin Monday" do + context 'with work packages' do + it 'returns the maximum between work packages dates and the Sunday following origin Monday' do expect(chart.last_day).to eq(sunday) - chart.add_work_package(subject: "wp1", due_date: tuesday + 7.days) + chart.add_work_package(subject: 'wp1', due_date: tuesday + 7.days) expect(chart.last_day).to eq(tuesday + 7.days) - chart.add_work_package(subject: "wp2", start_date: monday - 3.days) + chart.add_work_package(subject: 'wp2', start_date: monday - 3.days) expect(chart.last_day).to eq(tuesday + 7.days) - chart.add_work_package(subject: "wp3", start_date: monday + 20.days) + chart.add_work_package(subject: 'wp3', start_date: monday + 20.days) expect(chart.last_day).to eq(monday + 20.days) end end end - describe "#compact_dates" do - it "makes the chart dates fit with the work packages dates" do - chart.add_work_package(subject: "wp1", start_date: friday - 21.days, due_date: tuesday - 14.days) - chart.add_work_package(subject: "wp2", start_date: wednesday - 14.days) - chart.add_work_package(subject: "wp3", due_date: thursday - 14.days) - chart.add_work_package(subject: "wp4", due_date: thursday - 14.days) + describe '#compact_dates' do + it 'makes the chart dates fit with the work packages dates' do + chart.add_work_package(subject: 'wp1', start_date: friday - 21.days, due_date: tuesday - 14.days) + chart.add_work_package(subject: 'wp2', start_date: wednesday - 14.days) + chart.add_work_package(subject: 'wp3', due_date: thursday - 14.days) + chart.add_work_package(subject: 'wp4', due_date: thursday - 14.days) expect { chart.compact_dates } .to change { [chart.monday, chart.first_day, chart.last_day] } @@ -128,62 +128,62 @@ .to([monday - 14.days, friday - 21.days, sunday - 14.days]) end - it "does nothing if there are no work packages" do + it 'does nothing if there are no work packages' do expect { chart.compact_dates } .not_to change { [chart.monday, chart.first_day, chart.last_day] } end - it "does nothing if none of the work packages have any dates" do - chart.add_work_package(subject: "wp1") - chart.add_work_package(subject: "wp2") - chart.add_work_package(subject: "wp3") + it 'does nothing if none of the work packages have any dates' do + chart.add_work_package(subject: 'wp1') + chart.add_work_package(subject: 'wp2') + chart.add_work_package(subject: 'wp3') expect { chart.compact_dates } .not_to change { [chart.monday, chart.first_day, chart.last_day] } end end - describe "#set_duration" do - it "sets the duration for a work package" do - chart.add_work_package(subject: "wp") - chart.set_duration("wp", 3) - expect(chart.work_package_attributes("wp")).to include(duration: 3) + describe '#set_duration' do + it 'sets the duration for a work package' do + chart.add_work_package(subject: 'wp') + chart.set_duration('wp', 3) + expect(chart.work_package_attributes('wp')).to include(duration: 3) end - it "must set the duration to a positive integer" do - chart.add_work_package(subject: "wp") - expect { chart.set_duration("wp", 0) } - .to raise_error(ArgumentError, "unable to set duration for wp: duration must be a positive integer (got 0)") + it 'must set the duration to a positive integer' do + chart.add_work_package(subject: 'wp') + expect { chart.set_duration('wp', 0) } + .to raise_error(ArgumentError, 'unable to set duration for wp: duration must be a positive integer (got 0)') - expect { chart.set_duration("wp", -5) } - .to raise_error(ArgumentError, "unable to set duration for wp: duration must be a positive integer (got -5)") + expect { chart.set_duration('wp', -5) } + .to raise_error(ArgumentError, 'unable to set duration for wp: duration must be a positive integer (got -5)') - expect { chart.set_duration("wp", "hello") } + expect { chart.set_duration('wp', 'hello') } .to raise_error(ArgumentError, 'unable to set duration for wp: duration must be a positive integer (got "hello")') - expect { chart.set_duration("wp", "42") } + expect { chart.set_duration('wp', '42') } .to raise_error(ArgumentError, 'unable to set duration for wp: duration must be a positive integer (got "42")') end - it "cannot set the duration if the work package has dates" do - chart.add_work_package(subject: "wp_start", start_date: monday) - expect { chart.set_duration("wp_start", 3) } - .to raise_error(ArgumentError, "unable to set duration for wp_start: start_date is set") + it 'cannot set the duration if the work package has dates' do + chart.add_work_package(subject: 'wp_start', start_date: monday) + expect { chart.set_duration('wp_start', 3) } + .to raise_error(ArgumentError, 'unable to set duration for wp_start: start_date is set') - chart.add_work_package(subject: "wp_due", due_date: monday) - expect { chart.set_duration("wp_due", 3) } - .to raise_error(ArgumentError, "unable to set duration for wp_due: due_date is set") + chart.add_work_package(subject: 'wp_due', due_date: monday) + expect { chart.set_duration('wp_due', 3) } + .to raise_error(ArgumentError, 'unable to set duration for wp_due: due_date is set') - chart.add_work_package(subject: "wp_both", start_date: monday, due_date: monday) - expect { chart.set_duration("wp_both", 3) } - .to raise_error(ArgumentError, "unable to set duration for wp_both: start_date and due_date is set") + chart.add_work_package(subject: 'wp_both', start_date: monday, due_date: monday) + expect { chart.set_duration('wp_both', 3) } + .to raise_error(ArgumentError, 'unable to set duration for wp_both: start_date and due_date is set') end end - describe "#to_s" do + describe '#to_s' do shared_let(:week_days) { week_with_saturday_and_sunday_as_weekend } - context "with a chart built from ascii representation" do + context 'with a chart built from ascii representation' do let(:chart) do ScheduleHelpers::ChartBuilder.new.parse(<<~CHART) days | MTWTFSS | @@ -196,7 +196,7 @@ CHART end - it "returns the same ascii representation without properties information" do + it 'returns the same ascii representation without properties information' do expect(chart.to_s).to eq(<<~CHART.chomp) days | MTWTFSS | main | X..X | @@ -209,19 +209,19 @@ end end - context "with a chart built from real work packages" do - let(:work_package1) { build_stubbed(:work_package, subject: "main", start_date: monday, due_date: tuesday) } + context 'with a chart built from real work packages' do + let(:work_package1) { build_stubbed(:work_package, subject: 'main', start_date: monday, due_date: tuesday) } let(:work_package2) do - build_stubbed(:work_package, subject: "working_days", ignore_non_working_days: false, + build_stubbed(:work_package, subject: 'working_days', ignore_non_working_days: false, start_date: tuesday, due_date: monday + 7.days) end let(:work_package2bis) do - build_stubbed(:work_package, subject: "all_days", ignore_non_working_days: true, + build_stubbed(:work_package, subject: 'all_days', ignore_non_working_days: true, start_date: tuesday, due_date: monday + 7.days) end - let(:work_package3) { build_stubbed(:work_package, subject: "start_only", start_date: monday - 3.days) } - let(:work_package4) { build_stubbed(:work_package, subject: "due_only", due_date: wednesday) } - let(:work_package5) { build_stubbed(:work_package, subject: "no_dates") } + let(:work_package3) { build_stubbed(:work_package, subject: 'start_only', start_date: monday - 3.days) } + let(:work_package4) { build_stubbed(:work_package, subject: 'due_only', due_date: wednesday) } + let(:work_package5) { build_stubbed(:work_package, subject: 'no_dates') } let(:chart) do ScheduleHelpers::ChartBuilder.new.use_work_packages( [ @@ -235,7 +235,7 @@ ) end - it "returns the same ascii representation without properties information" do + it 'returns the same ascii representation without properties information' do expect(chart.to_s).to eq(<<~CHART.chomp) days | MTWTFSS | main | XX | diff --git a/spec/support_spec/schedule_helpers/example_methods_spec.rb b/spec/support_spec/schedule_helpers/example_methods_spec.rb index 2f29d72f65a0..fa33ee5ae087 100644 --- a/spec/support_spec/schedule_helpers/example_methods_spec.rb +++ b/spec/support_spec/schedule_helpers/example_methods_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ScheduleHelpers::ExampleMethods do create_shared_association_defaults_for_work_package_factory - describe "create_schedule" do + describe 'create_schedule' do let(:monday) { Date.current.next_occurring(:monday) } let(:tuesday) { monday + 1.day } # rubocop:disable RSpec/ExampleLength - it "creates work packages from the given chart" do + it 'creates work packages from the given chart' do schedule = create_schedule(<<~CHART) days | MTWTFSS | main | XX | @@ -73,7 +73,7 @@ end # rubocop:enable RSpec/ExampleLength - it "creates parent/child relations from the given chart" do + it 'creates parent/child relations from the given chart' do schedule = create_schedule(<<~CHART) days | MTWTFSS | main | | @@ -87,7 +87,7 @@ ) end - it "creates follows relations from the given chart" do + it 'creates follows relations from the given chart' do schedule = create_schedule(<<~CHART) days | MTWTFSS | predecessor | XX | @@ -104,7 +104,7 @@ end end - describe "change_schedule" do + describe 'change_schedule' do include ActiveSupport::Testing::TimeHelpers let(:fake_today) { Date.new(2022, 6, 16) } # Thursday 16 June 2022 @@ -117,9 +117,9 @@ travel_to(fake_today) end - it "applies dates changes to a group of work packages from a visual chart representation" do - main = build_stubbed(:work_package, subject: "main") - second = build_stubbed(:work_package, subject: "second") + it 'applies dates changes to a group of work packages from a visual chart representation' do + main = build_stubbed(:work_package, subject: 'main') + second = build_stubbed(:work_package, subject: 'second') change_schedule([main, second], <<~CHART) days | MTWTFSS | main | XX | @@ -131,8 +131,8 @@ expect(second.due_date).to eq(friday) end - it "does not save changes" do - main = create(:work_package, subject: "main") + it 'does not save changes' do + main = create(:work_package, subject: 'main') expect(main.persisted?).to be(true) expect(main.has_changes_to_save?).to be(false) change_schedule([main], <<~CHART) @@ -140,18 +140,18 @@ main | XX | CHART expect(main.has_changes_to_save?).to be(true) - expect(main.changes).to eq("start_date" => [nil, monday], "due_date" => [nil, tuesday]) + expect(main.changes).to eq('start_date' => [nil, monday], 'due_date' => [nil, tuesday]) end end - describe "expect_schedule" do + describe 'expect_schedule' do let_schedule(<<~CHART) | MTWTFSS | main | XX | other | XXX | CHART - it "checks the work packages properties according to the given work packages and chart representation" do + it 'checks the work packages properties according to the given work packages and chart representation' do expect do expect_schedule([main, other], <<~CHART) | MTWTFSS | @@ -161,7 +161,7 @@ end.not_to raise_error end - it "raises an error if start_date is wrong" do + it 'raises an error if start_date is wrong' do expect do expect_schedule([main], <<~CHART) | MTWTFSS | @@ -170,7 +170,7 @@ end.to raise_error(RSpec::Expectations::ExpectationNotMetError) end - it "raises an error if due_date is wrong" do + it 'raises an error if due_date is wrong' do expect do expect_schedule([main], <<~CHART) | MTWTFSS | @@ -179,7 +179,7 @@ end.to raise_error(RSpec::Expectations::ExpectationNotMetError) end - it "raises an error if a work package name in the chart cannot be found in the given work packages" do + it 'raises an error if a work package name in the chart cannot be found in the given work packages' do expect do expect_schedule([main], <<~CHART) | MTWTFSS | diff --git a/spec/support_spec/schedule_helpers/let_schedule_spec.rb b/spec/support_spec/schedule_helpers/let_schedule_spec.rb index 030b18d6d80f..d561fa63028b 100644 --- a/spec/support_spec/schedule_helpers/let_schedule_spec.rb +++ b/spec/support_spec/schedule_helpers/let_schedule_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ScheduleHelpers::LetSchedule do create_shared_association_defaults_for_work_package_factory - describe "let_schedule" do + describe 'let_schedule' do let_schedule(<<~CHART) days | MTWTFSS | main | XX | @@ -39,32 +39,32 @@ child | | child of main CHART - it "creates let calls for each work package" do + it 'creates let calls for each work package' do expect([main, follower, child]).to all(be_an_instance_of(WorkPackage)) expect([main, follower, child]).to all(be_persisted) expect(main).to have_attributes( - subject: "main", + subject: 'main', start_date: schedule.monday, due_date: schedule.tuesday ) expect(follower).to have_attributes( - subject: "follower", + subject: 'follower', start_date: schedule.wednesday, due_date: schedule.friday ) expect(child).to have_attributes( - subject: "child", + subject: 'child', start_date: nil, due_date: nil ) end - it "creates follows relations between work packages" do + it 'creates follows relations between work packages' do expect(follower.follows_relations.count).to eq(1) expect(follower.follows_relations.first.to).to eq(main) end - it "creates parent / child relations" do + it 'creates parent / child relations' do expect(child.parent).to eq(main) end end diff --git a/spec/support_spec/table_helpers/column_spec.rb b/spec/support_spec/table_helpers/column_spec.rb index d2a0987527f8..2470f0a28e2d 100644 --- a/spec/support_spec/table_helpers/column_spec.rb +++ b/spec/support_spec/table_helpers/column_spec.rb @@ -28,59 +28,59 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' module TableHelpers::Column RSpec.describe Generic do - subject(:column) { described_class.new(header: "Some header") } + subject(:column) { described_class.new(header: 'Some header') } - describe "#format" do - it "renders the value as string" do - expect(column.format("hello")).to eq "hello" - expect(column.format(42)).to eq "42" - expect(column.format(3.5)).to eq "3.5" - expect(column.format(nil)).to eq "" - expect(column.format(true)).to eq "true" + describe '#format' do + it 'renders the value as string' do + expect(column.format('hello')).to eq 'hello' + expect(column.format(42)).to eq '42' + expect(column.format(3.5)).to eq '3.5' + expect(column.format(nil)).to eq '' + expect(column.format(true)).to eq 'true' end end - describe "#cell_format" do - it "renders the value on the left side of the cell" do - expect(column.cell_format("hello", 0)).to eq "hello" - expect(column.cell_format("hello", 10)).to eq "hello " - expect(column.cell_format("hello", 20)).to eq "hello " + describe '#cell_format' do + it 'renders the value on the left side of the cell' do + expect(column.cell_format('hello', 0)).to eq 'hello' + expect(column.cell_format('hello', 10)).to eq 'hello ' + expect(column.cell_format('hello', 20)).to eq 'hello ' end end end RSpec.describe Duration do - subject(:column) { described_class.new(header: "Duration in hours") } + subject(:column) { described_class.new(header: 'Duration in hours') } - describe "#parse" do - it "parses empty string as nil" do - expect(column.parse("")).to be_nil + describe '#parse' do + it 'parses empty string as nil' do + expect(column.parse('')).to be_nil end end - describe "#format" do + describe '#format' do it 'renders the duration with a "h" suffix' do - expect(column.format(3.5)).to eq "3.5h" + expect(column.format(3.5)).to eq '3.5h' end - it "renders the duration without the decimal part if the decimal part is 0" do - expect(column.format(3.0)).to eq "3h" + it 'renders the duration without the decimal part if the decimal part is 0' do + expect(column.format(3.0)).to eq '3h' end - it "renders nothing if nil" do - expect(column.format(nil)).to eq "" + it 'renders nothing if nil' do + expect(column.format(nil)).to eq '' end end - describe "#cell_format" do - it "renders the duration on the right side of the cell" do - expect(column.cell_format(3.5, 0)).to eq "3.5h" - expect(column.cell_format(3.5, 10)).to eq " 3.5h" - expect(column.cell_format(3.5, 20)).to eq " 3.5h" + describe '#cell_format' do + it 'renders the duration on the right side of the cell' do + expect(column.cell_format(3.5, 0)).to eq '3.5h' + expect(column.cell_format(3.5, 10)).to eq ' 3.5h' + expect(column.cell_format(3.5, 20)).to eq ' 3.5h' end end end diff --git a/spec/support_spec/table_helpers/identifier_spec.rb b/spec/support_spec/table_helpers/identifier_spec.rb index c15d4727e49f..59c2a9cccfa3 100644 --- a/spec/support_spec/table_helpers/identifier_spec.rb +++ b/spec/support_spec/table_helpers/identifier_spec.rb @@ -28,19 +28,19 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' module TableHelpers RSpec.describe Identifier do - shared_examples "an identifier" do |name:, expected_identifier:| + shared_examples 'an identifier' do |name:, expected_identifier:| it "converts #{name.inspect} to identifier #{expected_identifier.inspect}" do expect(described_class.to_identifier(name)).to eq(expected_identifier) end end - include_examples "an identifier", name: "Subject", expected_identifier: :subject - include_examples "an identifier", name: "Work package", expected_identifier: :work_package - include_examples "an identifier", name: "grand-child", expected_identifier: :grand_child - include_examples "an identifier", name: "Child 1", expected_identifier: :child1 + include_examples 'an identifier', name: 'Subject', expected_identifier: :subject + include_examples 'an identifier', name: 'Work package', expected_identifier: :work_package + include_examples 'an identifier', name: 'grand-child', expected_identifier: :grand_child + include_examples 'an identifier', name: 'Child 1', expected_identifier: :child1 end end diff --git a/spec/support_spec/table_helpers/table_data_spec.rb b/spec/support_spec/table_helpers/table_data_spec.rb index 11672ece4631..06808c812d40 100644 --- a/spec/support_spec/table_helpers/table_data_spec.rb +++ b/spec/support_spec/table_helpers/table_data_spec.rb @@ -28,12 +28,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' module TableHelpers RSpec.describe TableData do - describe ".for" do - it "reads a table representation and stores its data" do + describe '.for' do + it 'reads a table representation and stores its data' do table = <<~TABLE | subject | remaining work | | work package | 3h | @@ -43,13 +43,13 @@ module TableHelpers table_data = described_class.for(table) expect(table_data.work_packages_data.size).to eq(2) expect(table_data.columns.size).to eq(2) - expect(table_data.headers).to eq([" subject ", " remaining work "]) + expect(table_data.headers).to eq([' subject ', ' remaining work ']) expect(table_data.work_package_identifiers).to eq(%i[work_package another_one]) end end - describe ".from_work_packages" do - it "reads data from work packages according to the given columns" do + describe '.from_work_packages' do + it 'reads data from work packages according to the given columns' do table = <<~TABLE | subject | remaining work | | work package | 3h | @@ -57,19 +57,19 @@ module TableHelpers TABLE columns = described_class.for(table).columns - work_package = build(:work_package, subject: "work package", remaining_hours: 3) - another_one = build(:work_package, subject: "another one") + work_package = build(:work_package, subject: 'work package', remaining_hours: 3) + another_one = build(:work_package, subject: 'another one') table_data = described_class.from_work_packages([work_package, another_one], columns) expect(table_data.work_packages_data.size).to eq(2) expect(table_data.columns.size).to eq(2) - expect(table_data.headers).to eq(["subject", "remaining work"]) + expect(table_data.headers).to eq(['subject', 'remaining work']) expect(table_data.work_package_identifiers).to eq(%i[work_package another_one]) end end - describe "#values_for_attribute" do - it "returns all the values of the work packages for the given attribute" do + describe '#values_for_attribute' do + it 'returns all the values of the work packages for the given attribute' do table = <<~TABLE | subject | remaining work | | work package | 3h | @@ -78,7 +78,7 @@ module TableHelpers table_data = described_class.for(table) expect(table_data.values_for_attribute(:remaining_hours)).to eq([3.0, nil]) - expect(table_data.values_for_attribute(:subject)).to eq(["work package", "another one"]) + expect(table_data.values_for_attribute(:subject)).to eq(['work package', 'another one']) end end end diff --git a/spec/support_spec/table_helpers/table_parser_spec.rb b/spec/support_spec/table_helpers/table_parser_spec.rb index 3a14ebd645e5..5fd259dd2520 100644 --- a/spec/support_spec/table_helpers/table_parser_spec.rb +++ b/spec/support_spec/table_helpers/table_parser_spec.rb @@ -28,12 +28,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe TableHelpers::TableParser do let(:parsed_data) { described_class.new.parse(table) } - it "ignores empty decorative columns" do + it 'ignores empty decorative columns' do table = <<~TABLE | subject | description | | foo | bar | @@ -42,7 +42,7 @@ expect(parsed_data.dig(0, :attributes).keys).to eq(%i[subject description]) end - it "normalizes column names to identifiers" do + it 'normalizes column names to identifiers' do table = <<~TABLE | DeScRiPtIoN | | value | @@ -51,7 +51,7 @@ expect(parsed_data.dig(0, :attributes).keys).to eq(%i[description]) end - it "ignores comments and empty lines" do + it 'ignores comments and empty lines' do table = <<~TABLE | subject | # this comment and the following empty line are ignored @@ -62,7 +62,7 @@ expect(parsed_data.length).to eq(1) end - it "raises a error if the header name is deprecated " \ + it 'raises a error if the header name is deprecated ' \ '(for example "remaining hours" instead of "remaining work")' do table = <<~TABLE subject | remaining hours @@ -72,7 +72,7 @@ .to raise_error(ArgumentError, 'Please use "remaining work" instead of "remaining hours"') end - describe "subject column" do + describe 'subject column' do let(:table) do <<~TABLE | subject | @@ -80,18 +80,18 @@ TABLE end - it "sets the subject attribute" do + it 'sets the subject attribute' do data = parsed_data.first - expect(data.dig(:attributes, :subject)).to eq("Work Package") + expect(data.dig(:attributes, :subject)).to eq('Work Package') end - it "sets the identifier as the subject snake-cased" do + it 'sets the identifier as the subject snake-cased' do data = parsed_data.first expect(data[:identifier]).to eq(:work_package) end end - describe "hierarchy column" do + describe 'hierarchy column' do let(:table) do <<~TABLE hierarchy @@ -105,24 +105,24 @@ TABLE end - it "sets the parent attribute by its identifier" do + it 'sets the parent attribute by its identifier' do attributes = parsed_data.flat_map { _1[:attributes] } expect(attributes.pluck(:parent)).to eq([nil, :parent, :child, :parent, :parent, :child3, nil]) end - it "sets the subject attribute" do + it 'sets the subject attribute' do attributes = parsed_data.flat_map { _1[:attributes] } expect(attributes.pluck(:subject)) - .to eq(["Parent", "Child", "Grand-Child", "Child 2", "Child 3", "Another child", "Root sibling"]) + .to eq(['Parent', 'Child', 'Grand-Child', 'Child 2', 'Child 3', 'Another child', 'Root sibling']) end - it "sets the identifier metadata as the subject snake-cased" do + it 'sets the identifier metadata as the subject snake-cased' do expect(parsed_data.pluck(:identifier)) .to eq(%i[parent child grand_child child2 child3 another_child root_sibling]) end end - describe "remaining work column" do + describe 'remaining work column' do let(:table) do <<~TABLE subject | remaining work @@ -130,12 +130,12 @@ TABLE end - it "sets the derived remaining work attribute" do + it 'sets the derived remaining work attribute' do expect(parsed_data.first[:attributes]).to include(remaining_hours: 9) end end - describe "derived remaining work column" do + describe 'derived remaining work column' do let(:table) do <<~TABLE subject | derived remaining work @@ -143,7 +143,7 @@ TABLE end - it "sets the derived remaining work attribute" do + it 'sets the derived remaining work attribute' do expect(parsed_data.first[:attributes]).to include(derived_remaining_hours: 9) end end diff --git a/spec/support_spec/table_helpers/table_representer_spec.rb b/spec/support_spec/table_helpers/table_representer_spec.rb index 40f241cb30e8..f684ca48f42c 100644 --- a/spec/support_spec/table_helpers/table_representer_spec.rb +++ b/spec/support_spec/table_helpers/table_representer_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' module TableHelpers RSpec.describe TableRepresenter do @@ -43,7 +43,7 @@ module TableHelpers subject(:representer) { described_class.new(tables_data:, columns:) } - context "when using a second table for the size" do + context 'when using a second table for the size' do let(:twin_table) do <<~TABLE | subject | @@ -53,10 +53,10 @@ module TableHelpers let(:twin_table_data) { TableData.for(twin_table) } let(:tables_data) { [table_data, twin_table_data] } - let(:columns) { [Column.for("subject")] } + let(:columns) { [Column.for('subject')] } - it "adapts the column sizes to fit the largest value of both tables " \ - "so that they can be compared and diffed" do + it 'adapts the column sizes to fit the largest value of both tables ' \ + 'so that they can be compared and diffed' do expect(representer.render(table_data)).to eq <<~TABLE | subject | | Work Package | @@ -68,10 +68,10 @@ module TableHelpers end end - describe "subject column" do - let(:columns) { [Column.for("subject")] } + describe 'subject column' do + let(:columns) { [Column.for('subject')] } - it "is rendered as text" do + it 'is rendered as text' do expect(representer.render(table_data)).to eq <<~TABLE | subject | | Work Package | @@ -79,10 +79,10 @@ module TableHelpers end end - describe "remaining work column" do - let(:columns) { [Column.for("remaining work")] } + describe 'remaining work column' do + let(:columns) { [Column.for('remaining work')] } - it "is rendered as a duration" do + it 'is rendered as a duration' do expect(representer.render(table_data)).to eq <<~TABLE | remaining work | | 1.5h | @@ -90,10 +90,10 @@ module TableHelpers end end - describe "derived remaining work column" do - let(:columns) { [Column.for("derived remaining work")] } + describe 'derived remaining work column' do + let(:columns) { [Column.for('derived remaining work')] } - it "sets the derived remaining work attribute" do + it 'sets the derived remaining work attribute' do expect(representer.render(table_data)).to eq <<~TABLE | derived remaining work | | 9h | diff --git a/spec/tasks/backup_spec.rb b/spec/tasks/backup_spec.rb index c1ad631d70de..c39a27b59a1f 100644 --- a/spec/tasks/backup_spec.rb +++ b/spec/tasks/backup_spec.rb @@ -26,18 +26,18 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Rake::Task, "backup:database" do +RSpec.describe Rake::Task, 'backup:database' do let(:database_config) do - { "adapter" => "postgresql", - "database" => "openproject-database", - "username" => "test_user", - "password" => "test_password" } + { 'adapter' => 'postgresql', + 'database' => 'openproject-database', + 'username' => 'test_user', + 'password' => 'test_password' } end let(:hash_config) do - ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "primary", database_config) + ActiveRecord::DatabaseConfigurations::HashConfig.new('test', 'primary', database_config) end before do @@ -46,73 +46,73 @@ allow(Kernel).to receive(:system) end - describe "backup:database:create" do - include_context "rake" + describe 'backup:database:create' do + include_context 'rake' - it "calls the pg_dump binary" do + it 'calls the pg_dump binary' do subject.invoke expect(Kernel).to have_received(:system) do |*args| - expect(args[1]).to eql("pg_dump") + expect(args[1]).to eql('pg_dump') end end - it "passes environment variables to the binary" do + it 'passes environment variables to the binary' do subject.invoke expect(Kernel).to have_received(:system) do |*args| - expect(args[0]).to include("PGUSER" => "test_user", "PGPASSWORD" => "test_password") + expect(args[0]).to include('PGUSER' => 'test_user', 'PGPASSWORD' => 'test_password') end end - it "uses the first task parameter as the target filename" do - custom_file_path = "./foo/bar/test_file.sql" + it 'uses the first task parameter as the target filename' do + custom_file_path = './foo/bar/test_file.sql' subject.invoke custom_file_path expect(Kernel).to have_received(:system) do |*args| - result_file = args.find { |s| s.to_s.starts_with? "--file=" } + result_file = args.find { |s| s.to_s.starts_with? '--file=' } expect(result_file).to include(custom_file_path) end end end - describe "backup:database:restore" do - include_context "rake" + describe 'backup:database:restore' do + include_context 'rake' let(:backup_file) do - Tempfile.new("test_backup") + Tempfile.new('test_backup') end after do backup_file.unlink end - it "calls the pg_restore binary" do + it 'calls the pg_restore binary' do subject.invoke backup_file.path expect(Kernel).to have_received(:system) do |*args| - expect(args[1]).to start_with("pg_restore") + expect(args[1]).to start_with('pg_restore') end end - it "passes environment variables to the binary" do + it 'passes environment variables to the binary' do subject.invoke backup_file.path expect(Kernel).to have_received(:system) do |*args| - expect(args[0]).to include("PGUSER" => "test_user", "PGPASSWORD" => "test_password") + expect(args[0]).to include('PGUSER' => 'test_user', 'PGPASSWORD' => 'test_password') end end - it "uses the first task parameter as the target filename" do + it 'uses the first task parameter as the target filename' do subject.invoke backup_file.path expect(Kernel).to have_received(:system) do |*args| expect(args.last).to eql(backup_file.path) end end - it "specifies database name" do + it 'specifies database name' do subject.invoke backup_file.path expect(Kernel).to have_received(:system) do |*args| - expect(args).to include "--dbname=openproject-database" + expect(args).to include '--dbname=openproject-database' end end - it "throws an error when called without a parameter" do + it 'throws an error when called without a parameter' do expect { subject.invoke }.to raise_error(RuntimeError, "You must provide the path to the database dump") end end diff --git a/spec/tasks/seed_spec.rb b/spec/tasks/seed_spec.rb index 7c8cf828a5b8..1f553f825bd2 100644 --- a/spec/tasks/seed_spec.rb +++ b/spec/tasks/seed_spec.rb @@ -26,39 +26,39 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "db:seed" do # rubocop:disable RSpec/DescribeClass - include_context "rake" - let(:task_path) { "lib/tasks/seed" } +RSpec.describe 'db:seed' do # rubocop:disable RSpec/DescribeClass + include_context 'rake' + let(:task_path) { 'lib/tasks/seed' } - describe "db:seed:only" do + describe 'db:seed:only' do before do allow($stdout).to receive(:puts) end - it "fails if seeder is not specified" do + it 'fails if seeder is not specified' do expect { subject.invoke } .to raise_error "Specify a seeder class name 'rake db:seed:only[Some::ClassName]'" end - it "runs the specified seeder" do - subject.invoke("BasicData::WorkPackageRoleSeeder") + it 'runs the specified seeder' do + subject.invoke('BasicData::WorkPackageRoleSeeder') expect(WorkPackageRole.count).to eq 3 end - it "displays an error if the given seeder class name does not exist" do - expect { subject.invoke("BasicData::BadSeeder") } - .to raise_error ArgumentError, "No seeder with class name BasicData::BadSeeder" + it 'displays an error if the given seeder class name does not exist' do + expect { subject.invoke('BasicData::BadSeeder') } + .to raise_error ArgumentError, 'No seeder with class name BasicData::BadSeeder' end - it "displays an error if the given class name is not a seeder" do - expect { subject.invoke("Queries::Queries::QueryQuery") } - .to raise_error ArgumentError, "Queries::Queries::QueryQuery is not a seeder" + it 'displays an error if the given class name is not a seeder' do + expect { subject.invoke('Queries::Queries::QueryQuery') } + .to raise_error ArgumentError, 'Queries::Queries::QueryQuery is not a seeder' end - it "does not work for all seeders because of missing references" do - expect { subject.invoke("DevelopmentData::ProjectsSeeder") } + it 'does not work for all seeders because of missing references' do + expect { subject.invoke('DevelopmentData::ProjectsSeeder') } .to raise_error ActiveRecord::RecordNotFound expect(Project.count).to eq 0 end diff --git a/spec/tasks/setting_spec.rb b/spec/tasks/setting_spec.rb index 80501870a1b7..68cc84ecaa2e 100644 --- a/spec/tasks/setting_spec.rb +++ b/spec/tasks/setting_spec.rb @@ -26,10 +26,10 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Rake::Task, :settings_reset do - describe "setting:set" do + describe 'setting:set' do let(:configuration_yml) do <<~YAML --- @@ -38,66 +38,66 @@ YAML end - include_context "rake" do - let(:task_name) { "setting:set" } + include_context 'rake' do + let(:task_name) { 'setting:set' } end - it "saves the setting in database" do - subject.invoke("email_delivery_method=something") + it 'saves the setting in database' do + subject.invoke('email_delivery_method=something') Setting.clear_cache - expect(Setting.find_by(name: "email_delivery_method")&.value).to eq(:something) + expect(Setting.find_by(name: 'email_delivery_method')&.value).to eq(:something) expect(Setting.email_delivery_method).to eq(:something) end - context "if setting is overridden from config/configuration.yml file" do + context 'if setting is overridden from config/configuration.yml file' do before do stub_configuration_yml reset(:email_delivery_method) end - it "saves the setting in database" do - expect { subject.invoke("email_delivery_method=something") } - .to change { Setting.find_by(name: "email_delivery_method")&.value } + it 'saves the setting in database' do + expect { subject.invoke('email_delivery_method=something') } + .to change { Setting.find_by(name: 'email_delivery_method')&.value } .from(nil) .to(:something) end - it "keeps using the value from the file" do + it 'keeps using the value from the file' do expect(Setting.email_delivery_method).to eq(:initial_file_value) - expect { subject.invoke("email_delivery_method=something") } + expect { subject.invoke('email_delivery_method=something') } .not_to change(Setting, :email_delivery_method) .from(:initial_file_value) end end - context "if setting is already set in database" do + context 'if setting is already set in database' do before do - Setting.create!(name: "email_delivery_method", value: "initial_db_value") + Setting.create!(name: 'email_delivery_method', value: 'initial_db_value') end - it "updates the setting" do - expect { subject.invoke("email_delivery_method=something") } - .to change { Setting.find_by(name: "email_delivery_method")&.value } + it 'updates the setting' do + expect { subject.invoke('email_delivery_method=something') } + .to change { Setting.find_by(name: 'email_delivery_method')&.value } .from(:initial_db_value) .to(:something) end - context "if setting is overridden from config/configuration.yml file" do + context 'if setting is overridden from config/configuration.yml file' do before do stub_configuration_yml reset(:email_delivery_method) end - it "updates the setting in database" do - expect { subject.invoke("email_delivery_method=something") } - .to change { Setting.find_by(name: "email_delivery_method")&.value } + it 'updates the setting in database' do + expect { subject.invoke('email_delivery_method=something') } + .to change { Setting.find_by(name: 'email_delivery_method')&.value } .from(:initial_db_value) .to(:something) end - it "keeps using the value from the file" do + it 'keeps using the value from the file' do expect(Setting.email_delivery_method).to eq(:initial_file_value) - expect { subject.invoke("email_delivery_method=something") } + expect { subject.invoke('email_delivery_method=something') } .not_to change(Setting, :email_delivery_method) .from(:initial_file_value) end @@ -105,10 +105,10 @@ end end - describe "setting:available_envs" do - include_context "rake" + describe 'setting:available_envs' do + include_context 'rake' - it "displays all environment variables which can override settings values" do + it 'displays all environment variables which can override settings values' do # just want to ensure the code does not raise any errors expect { subject.invoke } .to output(/OPENPROJECT_SMTP__ENABLE__STARTTLS__AUTO/).to_stdout diff --git a/spec/validator/secure_context_uri_validator_spec.rb b/spec/validator/secure_context_uri_validator_spec.rb index ca74390bee7b..9a0678c9660a 100644 --- a/spec/validator/secure_context_uri_validator_spec.rb +++ b/spec/validator/secure_context_uri_validator_spec.rb @@ -28,7 +28,7 @@ # require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper') -require "spec_helper" +require 'spec_helper' RSpec.describe SecureContextUriValidator do let(:host) { nil } @@ -48,8 +48,8 @@ def self.model_name before { model_instance.validate } - context "with empty URI" do - ["", " ", nil].each do |uri| + context 'with empty URI' do + ['', ' ', nil].each do |uri| describe "when URI is '#{uri}'" do let(:host) { uri } @@ -61,7 +61,7 @@ def self.model_name end end - context "with invalid URI" do + context 'with invalid URI' do %w(some_string http://<>ample.com).each do |uri| describe "when URI is '#{uri}'" do let(:host) { uri } @@ -74,9 +74,9 @@ def self.model_name end end - context "with valid URI" do - context "when host is missing" do - let(:host) { "https://" } + context 'with valid URI' do + context 'when host is missing' do + let(:host) { 'https://' } it "adds an :invalid_url error" do expect(model_instance.errors).to include(:host) @@ -84,7 +84,7 @@ def self.model_name end end - context "when not providing a Secure Context" do + context 'when not providing a Secure Context' do %w{http://128.0.0.1 http://foo.com http://[::2]}.each do |uri| describe "when URI is '#{uri}'" do let(:host) { uri } @@ -97,8 +97,8 @@ def self.model_name end end - context "when providing a Secure Context" do - context "with a loopback IP" do + context 'when providing a Secure Context' do + context 'with a loopback IP' do %w{http://127.0.0.1 http://127.1.1.1}.each do |uri| describe "when URI is '#{uri}'" do let(:host) { uri } @@ -110,7 +110,7 @@ def self.model_name end end - context "with a domain name" do + context 'with a domain name' do %w(https://example.com http://localhost http://.localhost http://foo.localhost. http://foo.localhost).each do |uri| describe "when URI is '#{uri}'" do let(:host) { uri } @@ -122,8 +122,8 @@ def self.model_name end end - context "with IPV6 loopback URI" do - let(:host) { "http://[::1]" } + context 'with IPV6 loopback URI' do + let(:host) { 'http://[::1]' } it "does not add an error" do expect(model_instance.errors).not_to include(:host) diff --git a/spec/views/account/login.html.erb_spec.rb b/spec/views/account/login.html.erb_spec.rb index bb44131b2092..df749f96dfd8 100644 --- a/spec/views/account/login.html.erb_spec.rb +++ b/spec/views/account/login.html.erb_spec.rb @@ -26,27 +26,27 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "account/login" do - context "with password login enabled" do +RSpec.describe 'account/login' do + context 'with password login enabled' do before do render end - it "shows a login field" do - expect(rendered).to include "Password" + it 'shows a login field' do + expect(rendered).to include 'Password' end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) render end - it "does not show a login field" do - expect(rendered).not_to include "Password" + it 'does not show a login field' do + expect(rendered).not_to include 'Password' end end end diff --git a/spec/views/account/register.html.erb_spec.rb b/spec/views/account/register.html.erb_spec.rb index 9952f1a9573b..2609ab847769 100644 --- a/spec/views/account/register.html.erb_spec.rb +++ b/spec/views/account/register.html.erb_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "account/register" do +RSpec.describe 'account/register' do let(:user) { build(:user, ldap_auth_source: nil) } - context "with the email_login setting disabled (default value)" do + context 'with the email_login setting disabled (default value)' do before do allow(Setting).to receive(:email_login?).and_return(false) @@ -39,23 +39,23 @@ render end - context "with auth source" do + context 'with auth source' do let(:ldap_auth_source) { create(:ldap_auth_source) } let(:user) { build(:user, ldap_auth_source:) } - it "does not show a login field" do - expect(rendered).not_to include("user[login]") + it 'does not show a login field' do + expect(rendered).not_to include('user[login]') end end - context "without auth source" do - it "shows a login field" do - expect(rendered).to include("user[login]") + context 'without auth source' do + it 'shows a login field' do + expect(rendered).to include('user[login]') end end end - context "with the email_login setting enabled" do + context 'with the email_login setting enabled' do before do allow(Setting).to receive(:email_login?).and_return(true) @@ -63,31 +63,31 @@ render end - context "with auth source" do + context 'with auth source' do let(:ldap_auth_source) { create(:ldap_auth_source) } let(:user) { build(:user, ldap_auth_source:) } - it "does not show a login field" do - expect(rendered).not_to include("user[login]") + it 'does not show a login field' do + expect(rendered).not_to include('user[login]') end - it "shows an email field" do - expect(rendered).to include("user[mail]") + it 'shows an email field' do + expect(rendered).to include('user[mail]') end end - context "without auth source" do - it "does not show a login field" do - expect(rendered).not_to include("user[login]") + context 'without auth source' do + it 'does not show a login field' do + expect(rendered).not_to include('user[login]') end - it "shows an email field" do - expect(rendered).to include("user[mail]") + it 'shows an email field' do + expect(rendered).to include('user[mail]') end end end - context "with the registration_footer setting enabled" do + context 'with the registration_footer setting enabled' do let(:footer) { "Some email footer" } before do @@ -96,7 +96,7 @@ assign(:user, user) end - it "renders the registration footer from the settings" do + it 'renders the registration footer from the settings' do render expect(rendered).to include(footer) @@ -106,8 +106,8 @@ context "with consent required", with_settings: { consent_required: true, consent_info: { - "en" => "You must consent!", - "de" => "Du musst zustimmen!" + 'en' => "You must consent!", + 'de' => "Du musst zustimmen!" } } do let(:locale) { raise "you have to define the locale" } diff --git a/spec/views/admin/enterprises/_current.html.erb_spec.rb b/spec/views/admin/enterprises/_current.html.erb_spec.rb index 57e9467cf142..be2c84dda836 100644 --- a/spec/views/admin/enterprises/_current.html.erb_spec.rb +++ b/spec/views/admin/enterprises/_current.html.erb_spec.rb @@ -26,9 +26,9 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "admin/enterprises/_current" do +RSpec.describe 'admin/enterprises/_current' do let(:current_user) { create(:admin) } let(:ee_token) { "v1_expired_with_7_days_reprieve_at_2021_09_01.token" } let(:current_time) { DateTime.now } diff --git a/spec/views/admin/settings/authentication/show.html.erb_spec.rb b/spec/views/admin/settings/authentication/show.html.erb_spec.rb index 96a32365b010..5df4b871fd10 100644 --- a/spec/views/admin/settings/authentication/show.html.erb_spec.rb +++ b/spec/views/admin/settings/authentication/show.html.erb_spec.rb @@ -26,36 +26,36 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "admin/settings/authentication_settings/show" do - context "with password login enabled" do +RSpec.describe 'admin/settings/authentication_settings/show' do + context 'with password login enabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(false) render end - it "shows password settings" do - expect(rendered).to have_text I18n.t("label_password_lost") + it 'shows password settings' do + expect(rendered).to have_text I18n.t('label_password_lost') end - it "shows automated user blocking options" do - expect(rendered).to have_text I18n.t("settings.brute_force_prevention") + it 'shows automated user blocking options' do + expect(rendered).to have_text I18n.t('settings.brute_force_prevention') end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) render end - it "does not show password settings" do - expect(rendered).to have_no_text I18n.t("label_password_lost") + it 'does not show password settings' do + expect(rendered).to have_no_text I18n.t('label_password_lost') end - it "does not show automated user blocking options" do - expect(rendered).to have_no_text I18n.t("settings.brute_force_prevention") + it 'does not show automated user blocking options' do + expect(rendered).to have_no_text I18n.t('settings.brute_force_prevention') end end end diff --git a/spec/views/common/validation_error.html.erb_spec.rb b/spec/views/common/validation_error.html.erb_spec.rb index 1dc2ea544900..11139a4e66a7 100644 --- a/spec/views/common/validation_error.html.erb_spec.rb +++ b/spec/views/common/validation_error.html.erb_spec.rb @@ -26,29 +26,29 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "common/_validation_error" do - let(:base_error_messages) { ["Something went completely wrong!"] } - let(:fields_error_messages) { ["This field is incorrect.", "This cannot be blank."] } +RSpec.describe 'common/_validation_error' do + let(:base_error_messages) { ['Something went completely wrong!'] } + let(:fields_error_messages) { ['This field is incorrect.', 'This cannot be blank.'] } before do - view.content_for(:error_details, "Clear this!") + view.content_for(:error_details, 'Clear this!') - render partial: "common/validation_error", + render partial: 'common/validation_error', locals: { base_error_messages:, fields_error_messages:, - object_name: "Test" } + object_name: 'Test' } end - it "flushes the buffer before rendering" do + it 'flushes the buffer before rendering' do # that means the same partial can be called multiple times without side effects - expect(rendered).not_to include("Clear this!") + expect(rendered).not_to include('Clear this!') end - it "includes all given error messages" do - expect(rendered).to include("Something went completely wrong!") - expect(rendered).to include("This field is incorrect.") - expect(rendered).to include("This cannot be blank.") + it 'includes all given error messages' do + expect(rendered).to include('Something went completely wrong!') + expect(rendered).to include('This field is incorrect.') + expect(rendered).to include('This cannot be blank.') end end diff --git a/spec/views/custom_styles/show.html.erb_spec.rb b/spec/views/custom_styles/show.html.erb_spec.rb index 47b679df9e4d..72411ebb521d 100644 --- a/spec/views/custom_styles/show.html.erb_spec.rb +++ b/spec/views/custom_styles/show.html.erb_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "custom_styles/show" do +RSpec.describe 'custom_styles/show' do let(:user) { build(:admin) } before do @@ -38,12 +38,12 @@ context "no custom logo yet" do before do assign(:custom_style, CustomStyle.new) - assign(:current_theme, "") - allow(view).to receive(:options_for_select).and_return("") + assign(:current_theme, '') + allow(view).to receive(:options_for_select).and_return('') render end - it "shows an upload button" do + it 'shows an upload button' do expect(rendered).to include "Upload" end end @@ -51,12 +51,12 @@ context "with existing custom logo" do before do assign(:custom_style, build(:custom_style_with_logo)) - assign(:current_theme, "") - allow(view).to receive(:options_for_select).and_return("") + assign(:current_theme, '') + allow(view).to receive(:options_for_select).and_return('') render end - it "shows a replace button" do + it 'shows a replace button' do expect(rendered).to include "Replace" end end diff --git a/spec/views/layouts/admin.html.erb_spec.rb b/spec/views/layouts/admin.html.erb_spec.rb index 098ecefe392b..3253d581f8e7 100644 --- a/spec/views/layouts/admin.html.erb_spec.rb +++ b/spec/views/layouts/admin.html.erb_spec.rb @@ -26,16 +26,16 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "layouts/admin" do +RSpec.describe 'layouts/admin' do shared_let(:admin) { create(:admin) } include Redmine::MenuManager::MenuHelper helper Redmine::MenuManager::MenuHelper before do - allow(view).to receive(:current_menu_item).and_return("overview") + allow(view).to receive(:current_menu_item).and_return('overview') allow(view).to receive(:default_breadcrumb) allow(controller).to receive(:default_search_scope) @@ -51,26 +51,26 @@ # All password-based authentication is to be hidden and disabled if # `disable_password_login` is true. This includes LDAP. - describe "LDAP authentication menu entry" do - context "with password login enabled" do + describe 'LDAP authentication menu entry' do + context 'with password login enabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(false) render end - it "is shown" do - expect(rendered).to have_css("a", text: I18n.t(:label_ldap_auth_source_plural)) + it 'is shown' do + expect(rendered).to have_css('a', text: I18n.t(:label_ldap_auth_source_plural)) end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) render end - it "is hidden" do - expect(rendered).to have_no_css("a", text: I18n.t(:label_ldap_auth_source_plural)) + it 'is hidden' do + expect(rendered).to have_no_css('a', text: I18n.t(:label_ldap_auth_source_plural)) end end end diff --git a/spec/views/layouts/base.html.erb_spec.rb b/spec/views/layouts/base.html.erb_spec.rb index db5a8df9ef2c..1ea78c6de8ed 100644 --- a/spec/views/layouts/base.html.erb_spec.rb +++ b/spec/views/layouts/base.html.erb_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "layouts/base" do +RSpec.describe 'layouts/base' do # This is to make `visit` available. It might be already included by the time # we reach this spec, but for running this spec alone we need it here. Best # of both worlds. @@ -41,7 +41,7 @@ let(:anonymous) { build_stubbed(:anonymous) } before do - allow(view).to receive(:current_menu_item).and_return("overview") + allow(view).to receive(:current_menu_item).and_return('overview') allow(view).to receive(:default_breadcrumb) allow(controller).to receive(:default_search_scope) allow(view) @@ -51,71 +51,71 @@ allow(view).to receive(:current_user).and_return current_user end - describe "Sign in button" do + describe 'Sign in button' do let(:current_user) { anonymous } before do render end - context "with omni_auth_direct_login disabled" do - it "shows the login drop down menu" do - expect(rendered).to have_css("div#nav-login-content", visible: false) + context 'with omni_auth_direct_login disabled' do + it 'shows the login drop down menu' do + expect(rendered).to have_css('div#nav-login-content', visible: false) end end - context "with omni_auth_direct_login enabled", - with_config: { omniauth_direct_login_provider: "some_provider" } do - it "shows just a sign-in link, no menu" do + context 'with omni_auth_direct_login enabled', + with_config: { omniauth_direct_login_provider: 'some_provider' } do + it 'shows just a sign-in link, no menu' do expect(rendered).to have_css "a[href='/login']" - expect(rendered).to have_no_css "div#nav-login-content" + expect(rendered).to have_no_css 'div#nav-login-content' end end end - describe "login form" do + describe 'login form' do let(:current_user) { anonymous } - context "with password login enabled" do + context 'with password login enabled' do before do render end - it "shows a login form" do - expect(rendered).to include "Username" - expect(rendered).to include "Password" + it 'shows a login form' do + expect(rendered).to include 'Username' + expect(rendered).to include 'Password' end end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) render end - it "shows no password login form" do - expect(rendered).not_to include "Username" - expect(rendered).not_to include "Password" + it 'shows no password login form' do + expect(rendered).not_to include 'Username' + expect(rendered).not_to include 'Password' end end end - describe "icons" do + describe 'icons' do let(:current_user) { anonymous } - context "not in development environment" do + context 'not in development environment' do before do render end - it "renders main favicon" do + it 'renders main favicon' do expect(rendered).to have_css( "link[type='image/x-icon'][href*='/assets/favicon.ico']", visible: false ) end - it "renders apple icons" do + it 'renders apple icons' do expect(rendered).to have_css( "link[type='image/png'][href*='/assets/apple-touch-icon-120x120.png']", visible: false @@ -129,41 +129,41 @@ # We do this here as opposed to a request spec to 1. keep icon specs contained # in one place, and 2. the view itself makes this request, so this is an appropriate # location for it. - it "icons actually exist" do - visit "assets/favicon.ico" + it 'icons actually exist' do + visit 'assets/favicon.ico' expect(page.status_code).to eq(200) - visit "assets/apple-touch-icon-120x120.png" + visit 'assets/apple-touch-icon-120x120.png' expect(page.status_code).to eq(200) end end - context "in development environment" do + context 'in development environment' do before do allow(OpenProject::Configuration).to receive(:development_highlight_enabled?).and_return(true) render end - it "renders main favicon" do + it 'renders main favicon' do expect(rendered).to have_css( "link[type='image/x-icon'][href*='/assets/development/favicon.ico']", visible: false ) end - it "renders apple icons" do + it 'renders apple icons' do expect(rendered).to have_css( "link[type='image/png'][href*='/assets/development/apple-touch-icon-120x120.png']", visible: false ) end - it "icons actually exist" do - visit "assets/development/favicon.ico" + it 'icons actually exist' do + visit 'assets/development/favicon.ico' expect(page.status_code).to eq(200) - visit "assets/development/apple-touch-icon-120x120.png" + visit 'assets/development/apple-touch-icon-120x120.png' expect(page.status_code).to eq(200) end end @@ -190,7 +190,7 @@ context "EE is active and styles are present" do let(:custom_style) { create(:custom_style) } - let(:primary_color) { create(:"design_color_primary-button-color") } + let(:primary_color) { create(:'design_color_primary-color') } before do allow(EnterpriseToken).to receive(:allows_to?).with(:define_custom_style).and_return(true) @@ -199,14 +199,14 @@ it "contains inline CSS block with those styles." do render - expect(rendered).to render_template partial: "custom_styles/_inline_css" + expect(rendered).to render_template partial: 'custom_styles/_inline_css' end it "renders CSS4 variables" do primary_color render - expect(rendered).to render_template partial: "custom_styles/_inline_css" - expect(rendered).to match /--primary-button-color:\s*#{primary_color.hexcode}/ + expect(rendered).to render_template partial: 'custom_styles/_inline_css' + expect(rendered).to match /--primary-color:\s*#{primary_color.hexcode}/ end end @@ -221,7 +221,7 @@ end it "does not contain an inline CSS block for styles." do - expect(rendered).not_to render_template partial: "custom_styles/_inline_css" + expect(rendered).not_to render_template partial: 'custom_styles/_inline_css' end end @@ -235,7 +235,7 @@ end it "does not contain an inline CSS block for styles." do - expect(rendered).not_to render_template partial: "custom_styles/_inline_css" + expect(rendered).not_to render_template partial: 'custom_styles/_inline_css' end end @@ -247,42 +247,42 @@ end it "does not contain an inline CSS block for styles." do - expect(rendered).not_to render_template partial: "custom_styles/_inline_css" + expect(rendered).not_to render_template partial: 'custom_styles/_inline_css' end end end - describe "current user meta tag" do + describe 'current user meta tag' do before do render end - context "with the user being logged in" do + context 'with the user being logged in' do let(:current_user) { user } - it "has a current_user metatag" do + it 'has a current_user metatag' do expect(rendered).to have_css("meta[name=current_user]", visible: false) end end - context "with the user being anonymous" do + context 'with the user being anonymous' do let(:current_user) { anonymous } - it "has a current_user metatag" do - expect(rendered).to have_css("meta[name=current_user]", visible: false) + it 'has a current_user metatag' do + expect(rendered).to have_css('meta[name=current_user]', visible: false) end end end - describe "openproject_initializer meta tag" do + describe 'openproject_initializer meta tag' do let(:current_user) { anonymous } - let(:base) { "meta[name=openproject_initializer]" } + let(:base) { 'meta[name=openproject_initializer]' } before do render end - it "has the meta tag" do + it 'has the meta tag' do expect(rendered).to have_selector(base, visible: false) end end diff --git a/spec/views/projects/settings/general/show.html.erb_spec.rb b/spec/views/projects/settings/general/show.html.erb_spec.rb index b74966bf2538..0d87d8d033b1 100644 --- a/spec/views/projects/settings/general/show.html.erb_spec.rb +++ b/spec/views/projects/settings/general/show.html.erb_spec.rb @@ -26,71 +26,71 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "projects/settings/general/show" do +RSpec.describe 'projects/settings/general/show' do let(:project) { build_stubbed(:project) } - describe "project copy permission" do + describe 'project copy permission' do before do assign(:project, project) - allow(view).to receive(:labelled_tabular_form_for).and_return("") + allow(view).to receive(:labelled_tabular_form_for).and_return('') end - context "when project copy is allowed" do + context 'when project copy is allowed' do before do allow(project).to receive(:copy_allowed?).and_return(true) render end - it "the copy link should be visible" do - expect(rendered).to have_css "a.copy" + it 'the copy link should be visible' do + expect(rendered).to have_css 'a.copy' end end - context "when project copy is not allowed" do + context 'when project copy is not allowed' do before do allow(project).to receive(:copy_allowed?).and_return(false) render end - it "the copy link should not be visible" do - expect(rendered).to have_no_css "a.copy" + it 'the copy link should not be visible' do + expect(rendered).to have_no_css 'a.copy' end end end - context "User.current is admin" do + context 'User.current is admin' do let(:admin) { build_stubbed(:admin) } before do assign(:project, project) allow(project).to receive(:copy_allowed?).and_return(true) allow(User).to receive(:current).and_return(admin) - allow(view).to receive(:labelled_tabular_form_for).and_return("") + allow(view).to receive(:labelled_tabular_form_for).and_return('') render end - it "show delete and archive buttons" do - expect(rendered).to have_css("li.toolbar-item span.button--text", text: "Archive") - expect(rendered).to have_css("li.toolbar-item span.button--text", text: "Delete") + it 'show delete and archive buttons' do + expect(rendered).to have_css('li.toolbar-item span.button--text', text: 'Archive') + expect(rendered).to have_css('li.toolbar-item span.button--text', text: 'Delete') end end - context "User.current is non-admin" do + context 'User.current is non-admin' do let(:non_admin) { build_stubbed(:user) } before do assign(:project, project) allow(project).to receive(:copy_allowed?).and_return(true) allow(User).to receive(:current).and_return(non_admin) - allow(view).to receive(:labelled_tabular_form_for).and_return("") + allow(view).to receive(:labelled_tabular_form_for).and_return('') render end - it "hide delete and archive buttons" do - expect(rendered).to have_no_css("li.toolbar-item span.button--text", text: "Archive project") - expect(rendered).to have_no_css("li.toolbar-item span.button--text", text: "Delete project") + it 'hide delete and archive buttons' do + expect(rendered).to have_no_css('li.toolbar-item span.button--text', text: 'Archive project') + expect(rendered).to have_no_css('li.toolbar-item span.button--text', text: 'Delete project') end end end diff --git a/spec/views/repositories/stats.html.erb_spec.rb b/spec/views/repositories/stats.html.erb_spec.rb index 32dfb20179d1..ed7acf0713c3 100644 --- a/spec/views/repositories/stats.html.erb_spec.rb +++ b/spec/views/repositories/stats.html.erb_spec.rb @@ -26,34 +26,34 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "repositories/stats" do +RSpec.describe 'repositories/stats' do let(:project) { create(:project) } before do assign(:project, project) end - describe "requested by a user with view_commit_author_statistics permission" do + describe 'requested by a user with view_commit_author_statistics permission' do before do assign(:show_commits_per_author, true) render end - it "embeds the commits per author graph" do - expect(rendered).to include("commits_per_author") + it 'embeds the commits per author graph' do + expect(rendered).to include('commits_per_author') end end - describe "requested by a user without view_commit_author_statistics permission" do + describe 'requested by a user without view_commit_author_statistics permission' do before do assign(:show_commits_per_author, false) render end - it "does not embed the commits per author graph" do - expect(rendered).not_to include("commits_per_author") + it 'does not embed the commits per author graph' do + expect(rendered).not_to include('commits_per_author') end end end diff --git a/spec/views/users/edit.html.erb_spec.rb b/spec/views/users/edit.html.erb_spec.rb index 054259a0c394..9f24b17fd55b 100644 --- a/spec/views/users/edit.html.erb_spec.rb +++ b/spec/views/users/edit.html.erb_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "users/edit" do +RSpec.describe 'users/edit' do let(:admin) { build(:admin) } before do @@ -38,10 +38,10 @@ view.extend(Gon::ControllerHelpers) end - context "authentication provider" do + context 'authentication provider' do let(:user) do build(:user, id: 1, # id is required to create route to edit - identity_url: "test_provider:veryuniqueid") + identity_url: 'test_provider:veryuniqueid') end before do @@ -51,21 +51,21 @@ allow(view).to receive(:current_user).and_return(admin) end - it "shows the authentication provider" do + it 'shows the authentication provider' do render - expect(rendered).to include("Test Provider") + expect(rendered).to include('Test Provider') end - it "does not show a no-login warning when password login is disabled" do + it 'does not show a no-login warning when password login is disabled' do allow(OpenProject::Configuration).to receive(:disable_password_login).and_return(true) render - expect(rendered).not_to include I18n.t("user.no_login") + expect(rendered).not_to include I18n.t('user.no_login') end end - context "with an invited user" do + context 'with an invited user' do let(:user) { build_stubbed(:invited_user) } before do @@ -73,18 +73,18 @@ assign(:auth_sources, []) end - context "for an admin" do + context 'for an admin' do before do allow(view).to receive(:current_user).and_return(admin) render end - it "renders the resend invitation button" do + it 'renders the resend invitation button' do expect(rendered).to include I18n.t(:label_send_invitation) end end - context "for a non-admin with manage_user global permission" do + context 'for a non-admin with manage_user global permission' do let(:non_admin) { create(:user, global_permissions: [:manage_user]) } before do @@ -92,13 +92,13 @@ render end - it "does not render the resend invitation button" do + it 'does not render the resend invitation button' do expect(rendered).not_to include I18n.t(:label_send_invitation) end end end - context "with a normal (not invited) user" do + context 'with a normal (not invited) user' do let(:user) { create(:user) } before do @@ -109,12 +109,12 @@ render end - it "also renders the resend invitation button" do + it 'also renders the resend invitation button' do expect(rendered).to include I18n.t(:label_send_invitation) end end - context "with password-based login" do + context 'with password-based login' do let(:user) { build(:user, id: 42) } before do @@ -124,75 +124,75 @@ allow(view).to receive(:current_user).and_return(admin) end - context "with password login disabled" do + context 'with password login disabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(true) end - it "warns that the user cannot login" do + it 'warns that the user cannot login' do render - expect(rendered).to include I18n.t("user.no_login") + expect(rendered).to include I18n.t('user.no_login') end - context "with auth sources" do + context 'with auth sources' do let(:auth_sources) { create_list(:ldap_auth_source, 1) } before do assign :auth_sources, auth_sources end - it "does not show the auth source selection" do + it 'does not show the auth source selection' do render - expect(rendered).to have_no_css("#user_auth_source_id") + expect(rendered).to have_no_css('#user_auth_source_id') end end end - context "with password login enabled" do + context 'with password login enabled' do before do allow(OpenProject::Configuration).to receive(:disable_password_login?).and_return(false) end - it "shows password options" do + it 'shows password options' do render - expect(rendered).to have_text I18n.t("user.assign_random_password") + expect(rendered).to have_text I18n.t('user.assign_random_password') end - context "with auth sources" do + context 'with auth sources' do let(:auth_sources) { create_list(:ldap_auth_source, 1) } before do assign :auth_sources, auth_sources end - it "shows the auth source selection" do + it 'shows the auth source selection' do render - expect(rendered).to have_css("#user_ldap_auth_source_id") + expect(rendered).to have_css('#user_ldap_auth_source_id') end end - context "with password choice enabled" do + context 'with password choice enabled' do before do expect(OpenProject::Configuration) .to receive(:disable_password_choice?) .and_return(false) end - it "shows the password and password confirmation fields" do + it 'shows the password and password confirmation fields' do render - within "#password_fields" do - expect(rendered).to have_text("Password") - expect(rendered).to have_text("Confirmation") + within '#password_fields' do + expect(rendered).to have_text('Password') + expect(rendered).to have_text('Confirmation') end end end - context "with password choice disabled" do + context 'with password choice disabled' do before do expect(OpenProject::Configuration).to receive(:disable_password_choice?).and_return(true) end @@ -200,9 +200,9 @@ it "doesn't show the password and password confirmation fields" do render - within "#password_fields" do - expect(rendered).to have_no_text("Password") - expect(rendered).to have_no_text("Password confirmation") + within '#password_fields' do + expect(rendered).to have_no_text('Password') + expect(rendered).to have_no_text('Password confirmation') end end end diff --git a/spec/views/users/index.html.erb_spec.rb b/spec/views/users/index.html.erb_spec.rb index 1107f0134fdb..44216c124191 100644 --- a/spec/views/users/index.html.erb_spec.rb +++ b/spec/views/users/index.html.erb_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "users/index" do +RSpec.describe 'users/index' do shared_let(:admin) { create(:admin) } let!(:user) { create(:user, firstname: "Scarlet", lastname: "Scallywag") } @@ -46,7 +46,7 @@ subject { rendered.squish } - it "renders the user table" do + it 'renders the user table' do render expect(subject).to have_text("#{admin.firstname} #{admin.lastname}") diff --git a/spec/views/users/show.html.erb_spec.rb b/spec/views/users/show.html.erb_spec.rb index 3e76eb42d581..b61a124c7c98 100644 --- a/spec/views/users/show.html.erb_spec.rb +++ b/spec/views/users/show.html.erb_spec.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "users/show" do +RSpec.describe 'users/show' do let(:project) { create(:valid_project) } let(:user) { create(:admin, member_with_permissions: { project => %i[view_work_packages edit_work_packages] }) } let(:custom_field) { create(:user_custom_field, :text) } @@ -36,7 +36,7 @@ create(:principal_custom_value, customized: user, custom_field:, - value: "TextUserCustomFieldValue") + value: 'TextUserCustomFieldValue') end before do @@ -48,9 +48,9 @@ assign(:events, []) end - it "renders the visible custom values" do + it 'renders the visible custom values' do render - expect(rendered).to have_css("li", text: "TextUserCustomField") + expect(rendered).to have_css('li', text: 'TextUserCustomField') end end diff --git a/spec/views/wiki/new.html.erb_spec.rb b/spec/views/wiki/new.html.erb_spec.rb index 76d21366642f..9fd6a49cd49d 100644 --- a/spec/views/wiki/new.html.erb_spec.rb +++ b/spec/views/wiki/new.html.erb_spec.rb @@ -26,12 +26,12 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "wiki/new" do +RSpec.describe 'wiki/new' do let(:project) { build_stubbed(:project) } let(:wiki) { build_stubbed(:wiki, project:) } - let(:page) { build_stubbed(:wiki_page, wiki:, title: "foo") } + let(:page) { build_stubbed(:wiki_page, wiki:, title: 'foo') } # TODO: remove let(:content) { page } let(:user) { build_stubbed(:user) } @@ -46,25 +46,25 @@ .and_return(user) end - it "renders a form which POSTs to create_project_wiki_index_path" do - project.identifier = "my_project" + it 'renders a form which POSTs to create_project_wiki_index_path' do + project.identifier = 'my_project' render - assert_select "form", + assert_select 'form', action: create_project_wiki_index_path(project_id: project), - method: "post" + method: 'post' end - it "contains an input element for title" do - page.title = "Boogie" + it 'contains an input element for title' do + page.title = 'Boogie' render - assert_select "input", name: "page[title]", value: "Boogie" + assert_select 'input', name: 'page[title]', value: 'Boogie' end - it "contains an input element for parent page" do + it 'contains an input element for parent page' do page.parent_id = 123 render - assert_select "input", name: "page[parent_id]", value: "123", type: "hidden" + assert_select 'input', name: 'page[parent_id]', value: '123', type: 'hidden' end end diff --git a/spec/views/work_package/auto_complete/index_spec.rb b/spec/views/work_package/auto_complete/index_spec.rb index 38cf613e2511..aac2862f87e9 100644 --- a/spec/views/work_package/auto_complete/index_spec.rb +++ b/spec/views/work_package/auto_complete/index_spec.rb @@ -26,22 +26,22 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe "work_packages/auto_completes/index.html.erb" do +RSpec.describe 'work_packages/auto_completes/index.html.erb' do let(:work_package) do build(:work_package, subject: '') end - it "escapes work package subject in auto-completion" do + it 'escapes work package subject in auto-completion' do assign :work_packages, [work_package] render # there are items - expect(rendered).to have_css "li" + expect(rendered).to have_css 'li' # but there is not script tag - expect(rendered).to have_no_css "script" + expect(rendered).to have_no_css 'script' # normal text should be included - expect(rendered).to include "do not alert this" + expect(rendered).to include 'do not alert this' end end diff --git a/spec/workers/application_job_spec.rb b/spec/workers/application_job_spec.rb index 8bf628aeb05f..e300990d3efa 100644 --- a/spec/workers/application_job_spec.rb +++ b/spec/workers/application_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe ApplicationJob do class JobMock < ApplicationJob @@ -39,24 +39,24 @@ def perform end end - describe "resets request store" do - it "resets request store on each perform" do + describe 'resets request store' do + it 'resets request store on each perform' do job = JobMock.new(-> do expect(RequestStore[:test_value]).to be_nil RequestStore[:test_value] = 42 end) - RequestStore[:test_value] = "my value" + RequestStore[:test_value] = 'my value' expect { job.perform_now }.not_to change { RequestStore[:test_value] } - RequestStore[:test_value] = "my value2" + RequestStore[:test_value] = 'my value2' expect { job.perform_now }.not_to change { RequestStore[:test_value] } - expect(RequestStore[:test_value]).to eq "my value2" + expect(RequestStore[:test_value]).to eq 'my value2' end end - describe "email configuration" do + describe 'email configuration' do let(:ports) { [] } before do diff --git a/spec/workers/attachments/cleanup_uncontainered_job_integration_spec.rb b/spec/workers/attachments/cleanup_uncontainered_job_integration_spec.rb index 6135e85b071c..4b38aa370e1a 100644 --- a/spec/workers/attachments/cleanup_uncontainered_job_integration_spec.rb +++ b/spec/workers/attachments/cleanup_uncontainered_job_integration_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Attachments::CleanupUncontaineredJob, type: :job do let(:grace_period) { 120 } @@ -57,7 +57,7 @@ .and_return(grace_period) end - it "removes all uncontainered attachments and pending uploads that are older than the grace period" do + it 'removes all uncontainered attachments and pending uploads that are older than the grace period' do job.perform expect(Attachment.all) diff --git a/spec/workers/attachments/finish_direct_upload_job_integration_spec.rb b/spec/workers/attachments/finish_direct_upload_job_integration_spec.rb index 6a2c926090c6..d647aeb3e0a3 100644 --- a/spec/workers/attachments/finish_direct_upload_job_integration_spec.rb +++ b/spec/workers/attachments/finish_direct_upload_job_integration_spec.rb @@ -26,33 +26,33 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.describe Attachments::FinishDirectUploadJob, "integration", type: :job do +RSpec.describe Attachments::FinishDirectUploadJob, 'integration', type: :job do shared_let(:user) { create(:admin) } let!(:pending_attachment) do create(:attachment, author: user, status: :prepared, - digest: "", + digest: '', container:) end let(:job) { described_class.new } - shared_examples_for "turning pending attachment into a standard attachment" do + shared_examples_for 'turning pending attachment into a standard attachment' do it do job.perform(pending_attachment.id) attachment = Attachment.find(pending_attachment.id) - expect(attachment.status).to eq "uploaded" + expect(attachment.status).to eq 'uploaded' expect(attachment.downloads) .to be(0) # expect to replace the content type with the actual value expect(attachment.content_type) - .to eql("text/plain") + .to eql('text/plain') expect(attachment.digest) .to eql("9473fdd0d880a43c21b7778d34872157") end @@ -72,11 +72,11 @@ end end - context "for a journalized container" do + context 'for a journalized container' do let!(:container) { create(:work_package) } let!(:container_timestamp) { container.updated_at } - it_behaves_like "turning pending attachment into a standard attachment" + it_behaves_like 'turning pending attachment into a standard attachment' it_behaves_like "adding a journal to the attachment in the name of the attachment's author" it "adds a journal to the container in the name of the attachment's author" do @@ -99,7 +99,7 @@ .to be 0 end - describe "attachment created event" do + describe 'attachment created event' do let(:attachment_ids) { [] } let!(:subscription) do @@ -120,21 +120,21 @@ end end - context "for a non journalized container" do + context 'for a non journalized container' do let!(:container) { create(:wiki_page) } - it_behaves_like "turning pending attachment into a standard attachment" + it_behaves_like 'turning pending attachment into a standard attachment' it_behaves_like "adding a journal to the attachment in the name of the attachment's author" end - context "for a nil container" do + context 'for a nil container' do let!(:container) { nil } - it_behaves_like "turning pending attachment into a standard attachment" + it_behaves_like 'turning pending attachment into a standard attachment' it_behaves_like "adding a journal to the attachment in the name of the attachment's author" end - context "with an incompatible attachment whitelist", + context 'with an incompatible attachment whitelist', with_settings: { attachment_whitelist: %w[image/png] } do let!(:container) { create(:work_package) } let!(:container_timestamp) { container.updated_at } @@ -154,7 +154,7 @@ expect { pending_attachment.reload }.to raise_error(ActiveRecord::RecordNotFound) end - context "when the job is getting a whitelist override" do + context 'when the job is getting a whitelist override' do it "Does save the attachment" do job.perform(pending_attachment.id, whitelist: false) @@ -168,7 +168,7 @@ end end - context "with the user not being allowed", + context 'with the user not being allowed', with_settings: { attachment_whitelist: %w[image/png] } do shared_let(:user) { create(:user) } let!(:container) { create(:work_package) } diff --git a/spec/workers/copy_project_job_spec.rb b/spec/workers/copy_project_job_spec.rb index 16673761b35d..35b5841f7bcd 100644 --- a/spec/workers/copy_project_job_spec.rb +++ b/spec/workers/copy_project_job_spec.rb @@ -26,17 +26,17 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe CopyProjectJob, type: :model do - let(:params) { { name: "Copy", identifier: "copy" } } - let(:maildouble) { double("Mail::Message", deliver: true) } + let(:params) { { name: 'Copy', identifier: 'copy' } } + let(:maildouble) { double('Mail::Message', deliver: true) } before do allow(maildouble).to receive(:deliver_later) end - describe "copy localizes error message" do + describe 'copy localizes error message' do let(:user_de) { create(:admin, language: :de) } let(:source_project) { create(:project) } let(:target_project) { create(:project) } @@ -45,7 +45,7 @@ described_class.new end - it "sets locale correctly" do + it 'sets locale correctly' do expect(copy_job) .to receive(:create_project_copy) .and_wrap_original do |m, *args, &block| @@ -60,15 +60,15 @@ end end - describe "copy project succeeds with errors" do + describe 'copy project succeeds with errors' do let(:admin) { create(:admin) } let(:source_project) { create(:project, types: [type]) } let!(:work_package) { create(:work_package, project: source_project, type:) } let(:type) { create(:type_bug) } let(:custom_field) do create(:work_package_custom_field, - name: "required_field", - field_format: "text", + name: 'required_field', + field_format: 'text', is_required: true, is_for_all: true) end @@ -84,7 +84,7 @@ described_class.new(**job_args).tap(&:perform_now) end - let(:params) { { name: "Copy", identifier: "copy", type_ids: [type.id], work_package_custom_field_ids: [custom_field.id] } } + let(:params) { { name: 'Copy', identifier: 'copy', type_ids: [type.id], work_package_custom_field_ids: [custom_field.id] } } let(:expected_error_message) do "#{WorkPackage.model_name.human} '#{work_package.type.name} ##{work_package.id}: #{work_package.subject}': #{custom_field.name} #{I18n.t('errors.messages.blank')}." end @@ -100,22 +100,22 @@ @errors = copy_job.errors end - it "copies the project", :aggregate_failures do + it 'copies the project', :aggregate_failures do expect(Project.find_by(identifier: params[:identifier])).to eq(@copied_project) expect(@errors.first).to eq(expected_error_message) # expect to create a status expect(copy_job.job_status).to be_present - expect(copy_job.job_status[:status]).to eq "success" - expect(copy_job.job_status[:payload]["redirect"]).to include "/projects/copy" + expect(copy_job.job_status[:status]).to eq 'success' + expect(copy_job.job_status[:payload]['redirect']).to include '/projects/copy' - expected_link = { "href" => "/api/v3/projects/#{@copied_project.id}", "title" => @copied_project.name } - expect(copy_job.job_status[:payload]["_links"]["project"]).to eq(expected_link) + expected_link = { 'href' => "/api/v3/projects/#{@copied_project.id}", 'title' => @copied_project.name } + expect(copy_job.job_status[:payload]['_links']['project']).to eq(expected_link) end end # rubocop:enable RSpec/InstanceVariable - describe "project has an invalid repository" do + describe 'project has an invalid repository' do let(:admin) { create(:admin) } let(:source_project) do project = create(:project) @@ -140,7 +140,7 @@ allow(User).to receive(:current).and_return(admin) end - it "saves without the repository" do + it 'saves without the repository' do expect(source_project).not_to be_valid copied_project = copy_job.target_project @@ -149,11 +149,11 @@ expect(errors).to be_empty expect(copied_project).to be_valid expect(copied_project.repository).to be_nil - expect(copied_project.enabled_module_names).not_to include "repository" + expect(copied_project.enabled_module_names).not_to include 'repository' end end - describe "copy project fails with internal error" do + describe 'copy project fails with internal error' do let(:admin) { create(:admin) } let(:source_project) { create(:project) } let(:copy_job) do @@ -165,31 +165,31 @@ end end - let(:params) { { name: "Copy", identifier: "copy" } } + let(:params) { { name: 'Copy', identifier: 'copy' } } before do allow(User).to receive(:current).and_return(admin) - allow(ProjectMailer).to receive(:copy_project_succeeded).and_raise "error message not meant for user" + allow(ProjectMailer).to receive(:copy_project_succeeded).and_raise 'error message not meant for user' end - it "renders a error when unexpected errors occur" do + it 'renders a error when unexpected errors occur' do expect(ProjectMailer) .to receive(:copy_project_failed) - .with(admin, source_project, "Copy", [I18n.t("copy_project.failed_internal")]) + .with(admin, source_project, 'Copy', [I18n.t('copy_project.failed_internal')]) .and_return maildouble expect { copy_job }.not_to raise_error # expect to create a status expect(copy_job.job_status).to be_present - expect(copy_job.job_status[:status]).to eq "failure" + expect(copy_job.job_status[:status]).to eq 'failure' expect(copy_job.job_status[:message]).to include "Cannot copy project #{source_project.name}" - expect(copy_job.job_status[:payload]).to eq("title" => "Copy project") + expect(copy_job.job_status[:payload]).to eq('title' => 'Copy project') end end - context "when project has work package hierarchies with derived values" do - shared_let(:source_project) { create(:project, name: "Source project") } + context 'when project has work package hierarchies with derived values' do + shared_let(:source_project) { create(:project, name: 'Source project') } before_all do set_factory_default(:project, source_project) @@ -197,7 +197,7 @@ end let(:admin) { create(:admin) } - let(:params) { { name: "Copy", identifier: "copy" } } + let(:params) { { name: 'Copy', identifier: 'copy' } } let_work_packages(<<~TABLE) hierarchy | work | start date | end date @@ -211,7 +211,7 @@ .call(%i[estimated_hours remaining_hours ignore_non_working_days]) end - it "copies the project without any errord (Bug #52384)" do + it 'copies the project without any errord (Bug #52384)' do allow(OpenProject.logger).to receive(:error) copy_job = described_class.new @@ -220,18 +220,18 @@ target_project_params: params, associations_to_copy: [:work_packages] - expect(copy_job.job_status.status).to eq "success" + expect(copy_job.job_status.status).to eq 'success' expect(copy_job.errors).to be_empty expect(OpenProject.logger).not_to have_received(:error) end end - describe "perform" do + describe 'perform' do let(:project) { create(:project, public: false) } let(:user) { create(:user) } let(:role) { create(:project_role, permissions: [:copy_projects]) } - shared_context "copy project" do + shared_context 'copy project' do before do described_class.new.tap do |job| job.perform user_id: user.id, @@ -247,8 +247,8 @@ expect(User).to receive(:current=).with(user).at_least(:once) end - describe "subproject" do - let(:params) { { name: "Copy", identifier: "copy" } } + describe 'subproject' do + let(:params) { { name: 'Copy', identifier: 'copy' } } let(:subproject) do create(:project, parent: project).tap do |p| create(:member, @@ -258,14 +258,14 @@ end end - subject { Project.find_by(identifier: "copy") } + subject { Project.find_by(identifier: 'copy') } - describe "user without add_subprojects permission in parent" do - include_context "copy project" do + describe 'user without add_subprojects permission in parent' do + include_context 'copy project' do let(:project_to_copy) { subproject } end - it "copies the project without the parent being set" do + it 'copies the project without the parent being set' do expect(subject).not_to be_nil expect(subject.parent).to be_nil @@ -284,14 +284,14 @@ end end - describe "user without add_subprojects permission in parent and when explicitly setting that parent" do - let(:params) { { name: "Copy", identifier: "copy", parent_id: project.id } } + describe 'user without add_subprojects permission in parent and when explicitly setting that parent' do + let(:params) { { name: 'Copy', identifier: 'copy', parent_id: project.id } } - include_context "copy project" do + include_context 'copy project' do let(:project_to_copy) { subproject } end - it "does not copy the project" do + it 'does not copy the project' do expect(subject).to be_nil end @@ -300,12 +300,12 @@ mail = ActionMailer::Base.deliveries.first expect(mail).to be_present - expect(mail.subject).to eq I18n.t("copy_project.failed", source_project_name: subproject.name) + expect(mail.subject).to eq I18n.t('copy_project.failed', source_project_name: subproject.name) expect(mail.to).to eq [user.mail] end end - describe "user with add_subprojects permission in parent" do + describe 'user with add_subprojects permission in parent' do let(:role_add_subproject) { create(:project_role, permissions: [:add_subprojects]) } let(:member_add_subproject) do create(:member, @@ -318,11 +318,11 @@ member_add_subproject end - include_context "copy project" do + include_context 'copy project' do let(:project_to_copy) { subproject } end - it "copies the project" do + it 'copies the project' do expect(subject).not_to be_nil expect(subject.parent).to eql(project) diff --git a/spec/workers/extract_fulltext_job_spec.rb b/spec/workers/extract_fulltext_job_spec.rb index c923fecd8e48..31cd5edf4244 100644 --- a/spec/workers/extract_fulltext_job_spec.rb +++ b/spec/workers/extract_fulltext_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Attachments::ExtractFulltextJob, type: :job do subject(:extracted_attributes) do @@ -46,7 +46,7 @@ SQL end - let(:text) { "lorem ipsum" } + let(:text) { 'lorem ipsum' } let(:attachment) do create(:attachment).tap do |attachment| expect(Attachments::ExtractFulltextJob) @@ -65,48 +65,48 @@ allow_any_instance_of(Plaintext::Resolver).to receive(:text).and_return(text) end - context "attachment is readable" do + context 'attachment is readable' do before do allow(attachment).to receive(:readable?).and_return(true) end - it "updates the attachment's DB record with fulltext, fulltext_tsv, and file_tsv" do - expect(extracted_attributes["fulltext"]).to eq text - expect(extracted_attributes["fulltext_tsv"].size).to be > 0 - expect(extracted_attributes["file_tsv"].size).to be > 0 + it 'updates the attachment\'s DB record with fulltext, fulltext_tsv, and file_tsv' do + expect(extracted_attributes['fulltext']).to eq text + expect(extracted_attributes['fulltext_tsv'].size).to be > 0 + expect(extracted_attributes['file_tsv'].size).to be > 0 end - context "without text extracted" do + context 'without text extracted' do let(:text) { nil } # include_examples 'no fulltext but file name saved as TSV' - it "updates the attachment's DB record with file_tsv" do - expect(extracted_attributes["fulltext"]).to be_blank - expect(extracted_attributes["fulltext_tsv"]).to be_blank - expect(extracted_attributes["file_tsv"].size).to be > 0 + it 'updates the attachment\'s DB record with file_tsv' do + expect(extracted_attributes['fulltext']).to be_blank + expect(extracted_attributes['fulltext_tsv']).to be_blank + expect(extracted_attributes['file_tsv'].size).to be > 0 end end end end - shared_examples "only file name indexed" do - it "updates the attachment's DB record with file_tsv" do - expect(extracted_attributes["fulltext"]).to be_blank - expect(extracted_attributes["fulltext_tsv"]).to be_blank - expect(extracted_attributes["file_tsv"].size).to be > 0 + shared_examples 'only file name indexed' do + it 'updates the attachment\'s DB record with file_tsv' do + expect(extracted_attributes['fulltext']).to be_blank + expect(extracted_attributes['fulltext_tsv']).to be_blank + expect(extracted_attributes['file_tsv'].size).to be > 0 end end - context "with the file not readable" do + context 'with the file not readable' do before do allow(attachment).to receive(:readable?).and_return(false) end - include_examples "only file name indexed" + include_examples 'only file name indexed' end - context "with exception in extraction" do - let(:exception_message) { "boom-internal-error" } + context 'with exception in extraction' do + let(:exception_message) { 'boom-internal-error' } let(:logger) { Rails.logger } before do @@ -117,11 +117,11 @@ allow(attachment).to receive(:readable?).and_return(true) end - it "logs the error" do + it 'logs the error' do extracted_attributes expect(logger).to have_received(:error).with(/boom-internal-error/) end - include_examples "only file name indexed" + include_examples 'only file name indexed' end end diff --git a/spec/workers/journals/completed_job_spec.rb b/spec/workers/journals/completed_job_spec.rb index cadbd024606c..b859c861515c 100644 --- a/spec/workers/journals/completed_job_spec.rb +++ b/spec/workers/journals/completed_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Journals::CompletedJob, type: :model do let(:send_mail) { true } @@ -35,17 +35,17 @@ build_stubbed(:journal, journable:) end - describe ".schedule" do + describe '.schedule' do subject { described_class.schedule(journal, send_mail) } - shared_examples_for "enqueues a JournalCompletedJob" do + shared_examples_for 'enqueues a JournalCompletedJob' do before do allow(Time) .to receive(:current) .and_return(Time.current) end - it "enqueues a JournalCompletedJob" do + it 'enqueues a JournalCompletedJob' do expect { subject } .to have_enqueued_job(described_class) .at(Setting.journal_aggregation_time_minutes.to_i.minutes.from_now) @@ -55,33 +55,33 @@ end end - shared_examples_for "enqueues no job" do - it "enqueues no JournalCompletedJob" do + shared_examples_for 'enqueues no job' do + it 'enqueues no JournalCompletedJob' do expect { subject } .not_to have_enqueued_job(described_class) end end - context "with a work_package" do + context 'with a work_package' do let(:journable) { build_stubbed(:work_package) } - it_behaves_like "enqueues a JournalCompletedJob" + it_behaves_like 'enqueues a JournalCompletedJob' end - context "with a wiki page" do + context 'with a wiki page' do let(:journable) { build_stubbed(:wiki_page) } - it_behaves_like "enqueues a JournalCompletedJob" + it_behaves_like 'enqueues a JournalCompletedJob' end - context "with a news" do + context 'with a news' do let(:journable) { build_stubbed(:news) } - it_behaves_like "enqueues a JournalCompletedJob" + it_behaves_like 'enqueues a JournalCompletedJob' end end - describe "#perform" do + describe '#perform' do subject { described_class.new.perform(journal.id, journal.updated_at, send_mail) } let(:find_by_journal) { journal } @@ -93,8 +93,8 @@ .and_return(find_by_journal) end - shared_examples_for "sends a notification" do |event| - it "sends a notification" do + shared_examples_for 'sends a notification' do |event| + it 'sends a notification' do allow(OpenProject::Notifications) .to receive(:send) @@ -108,32 +108,32 @@ end end - context "with a work packages" do + context 'with a work packages' do let(:journable) { build_stubbed(:work_package) } - it_behaves_like "sends a notification", + it_behaves_like 'sends a notification', OpenProject::Events::AGGREGATED_WORK_PACKAGE_JOURNAL_READY end - context "with wiki page content" do + context 'with wiki page content' do let(:journable) { build_stubbed(:wiki_page) } - it_behaves_like "sends a notification", + it_behaves_like 'sends a notification', OpenProject::Events::AGGREGATED_WIKI_JOURNAL_READY end - context "with a news" do + context 'with a news' do let(:journable) { build_stubbed(:news) } - it_behaves_like "sends a notification", + it_behaves_like 'sends a notification', OpenProject::Events::AGGREGATED_NEWS_JOURNAL_READY end - context "with a non non-existent journal (either because the journable was deleted or the journal updated)" do + context 'with a non non-existent journal (either because the journable was deleted or the journal updated)' do let(:journable) { build_stubbed(:work_package) } let(:find_by_journal) { nil } - it "sends no notification" do + it 'sends no notification' do allow(OpenProject::Notifications) .to receive(:send) diff --git a/spec/workers/ldap/synchronization_job_spec.rb b/spec/workers/ldap/synchronization_job_spec.rb index b4cdda093109..e98ea7a4ec3d 100644 --- a/spec/workers/ldap/synchronization_job_spec.rb +++ b/spec/workers/ldap/synchronization_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Ldap::SynchronizationJob, type: :model do let!(:auth_source) { create(:ldap_auth_source) } @@ -48,7 +48,7 @@ end context "with user synchronization disabled", with_config: { - "ldap_users_disable_sync_job" => true + 'ldap_users_disable_sync_job' => true } do it "does not run the sync" do expect(service).not_to have_received(:call) diff --git a/spec/workers/mails/member_created_job_spec.rb b/spec/workers/mails/member_created_job_spec.rb index f230d5d3e086..6d31aa3d7e5f 100644 --- a/spec/workers/mails/member_created_job_spec.rb +++ b/spec/workers/mails/member_created_job_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared/member_job" +require 'spec_helper' +require_relative 'shared/member_job' RSpec.describe Mails::MemberCreatedJob, type: :model do - include_examples "member job" do + include_examples 'member job' do let(:user_project_mail_method) { :added_project } - context "with a group membership" do + context 'with a group membership' do let(:member) do build_stubbed(:member, project:, @@ -45,14 +45,14 @@ group_user_member end - context "with the user not having had a membership before the group`s membership was added" do + context 'with the user not having had a membership before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: group_member_roles.first.id)] end - it "sends mail" do + it 'sends mail' do run_job expect(MemberMailer) @@ -61,14 +61,14 @@ end end - context "with the user having had a membership with the same roles before the group`s membership was added" do + context 'with the user having had a membership with the same roles before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: nil)] end - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end context 'with the user having had a membership with the same roles @@ -79,11 +79,11 @@ inherited_from: group_member_roles.first.id + 5)] end - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end - context "with the user having had a membership before the group`s membership " + - "was added but now has additional roles" do + context 'with the user having had a membership before the group`s membership ' + + 'was added but now has additional roles' do let(:other_role) { build_stubbed(:project_role) } let(:group_user_member_roles) do [build_stubbed(:member_role, @@ -94,7 +94,7 @@ inherited_from: nil)] end - it "sends mail" do + it 'sends mail' do run_job expect(MemberMailer) @@ -106,7 +106,7 @@ end end - context "with a group global membership" do + context 'with a group global membership' do let(:project) { nil } let(:member) do build_stubbed(:member, @@ -119,14 +119,14 @@ group_user_member end - context "with the user not having had a membership before the group`s membership was added" do + context 'with the user not having had a membership before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: group_member_roles.first.id)] end - it "sends mail" do + it 'sends mail' do run_job expect(MemberMailer) @@ -135,14 +135,14 @@ end end - context "with the user having had a membership with the same roles before the group`s membership was added" do + context 'with the user having had a membership with the same roles before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: nil)] end - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end context 'with the user having had a membership with the same roles @@ -153,10 +153,10 @@ inherited_from: group_member_roles.first.id + 5)] end - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end - context "with the user having had a membership before the group`s membership was added but now has additional roles" do + context 'with the user having had a membership before the group`s membership was added but now has additional roles' do let(:other_role) { build_stubbed(:project_role) } let(:group_user_member_roles) do [build_stubbed(:member_role, @@ -167,7 +167,7 @@ inherited_from: nil)] end - it "sends mail" do + it 'sends mail' do run_job expect(MemberMailer) diff --git a/spec/workers/mails/member_updated_job_spec.rb b/spec/workers/mails/member_updated_job_spec.rb index 510e85047ec0..df09dc4d1e05 100644 --- a/spec/workers/mails/member_updated_job_spec.rb +++ b/spec/workers/mails/member_updated_job_spec.rb @@ -26,14 +26,14 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared/member_job" +require 'spec_helper' +require_relative 'shared/member_job' RSpec.describe Mails::MemberUpdatedJob, type: :model do - include_examples "member job" do + include_examples 'member job' do let(:user_project_mail_method) { :updated_project } - context "with a group membership" do + context 'with a group membership' do let(:member) do build_stubbed(:member, project:, @@ -41,8 +41,8 @@ member_roles: group_member_roles) end - shared_examples "updated mail" do - it "sends mail" do + shared_examples 'updated mail' do + it 'sends mail' do run_job expect(MemberMailer) @@ -55,24 +55,24 @@ group_user_member end - context "with the user not having had a membership before the group`s membership was added" do + context 'with the user not having had a membership before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: group_member_roles.first.id)] end - it_behaves_like "updated mail" + it_behaves_like 'updated mail' end - context "with the user having had a membership with the same roles before the group`s membership was added" do + context 'with the user having had a membership with the same roles before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: nil)] end - it_behaves_like "updated mail" + it_behaves_like 'updated mail' end context 'with the user having had a membership with the same roles @@ -83,10 +83,10 @@ inherited_from: group_member_roles.first.id + 5)] end - it_behaves_like "updated mail" + it_behaves_like 'updated mail' end - context "with the user having had a membership before the group`s membership was added but now has additional roles" do + context 'with the user having had a membership before the group`s membership was added but now has additional roles' do let(:other_role) { build_stubbed(:project_role) } let(:group_user_member_roles) do [build_stubbed(:member_role, @@ -97,11 +97,11 @@ inherited_from: nil)] end - it_behaves_like "updated mail" + it_behaves_like 'updated mail' end end - context "with a group global membership" do + context 'with a group global membership' do let(:project) { nil } let(:member) do build_stubbed(:member, @@ -110,8 +110,8 @@ member_roles: group_member_roles) end - shared_examples "updated mail" do - it "sends mail" do + shared_examples 'updated mail' do + it 'sends mail' do run_job expect(MemberMailer) @@ -124,24 +124,24 @@ group_user_member end - context "with the user not having had a membership before the group`s membership was added" do + context 'with the user not having had a membership before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: group_member_roles.first.id)] end - it_behaves_like "updated mail" + it_behaves_like 'updated mail' end - context "with the user having had a membership with the same roles before the group`s membership was added" do + context 'with the user having had a membership with the same roles before the group`s membership was added' do let(:group_user_member_roles) do [build_stubbed(:member_role, role:, inherited_from: nil)] end - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end context 'with the user having had a membership with the same roles @@ -152,10 +152,10 @@ inherited_from: group_member_roles.first.id + 5)] end - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end - context "with the user having had a membership before the group`s membership was added but now has additional roles" do + context 'with the user having had a membership before the group`s membership was added but now has additional roles' do let(:other_role) { build_stubbed(:project_role) } let(:group_user_member_roles) do [build_stubbed(:member_role, @@ -166,7 +166,7 @@ inherited_from: nil)] end - it_behaves_like "updated mail" + it_behaves_like 'updated mail' end end end diff --git a/spec/workers/mails/reminder_job_spec.rb b/spec/workers/mails/reminder_job_spec.rb index 63f042afb645..ef5801bf0a81 100644 --- a/spec/workers/mails/reminder_job_spec.rb +++ b/spec/workers/mails/reminder_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Mails::ReminderJob, type: :model do subject(:job) { described_class.perform_now(recipient) } @@ -78,16 +78,16 @@ .and_return(mail) end - describe "#perform" do - context "with successful mail sending" do - it "sends a mail" do + describe '#perform' do + context 'with successful mail sending' do + it 'sends a mail' do job expect(DigestMailer) .to have_received(:work_packages) .with(recipient.id, notification_ids) end - it "marks the notifications as read" do + it 'marks the notifications as read' do job expect(notifications) @@ -95,7 +95,7 @@ .with(mail_reminder_sent: true, updated_at: Time.current) end - it "impersonates the recipient" do + it 'impersonates the recipient' do allow(DigestMailer).to receive(:work_packages) do expect(User.current) .eql receiver @@ -105,46 +105,46 @@ end end - context "without a recipient" do + context 'without a recipient' do let(:recipient) { nil } - it "sends no mail" do + it 'sends no mail' do job expect(DigestMailer) .not_to have_received(:work_packages) end end - context "with an error on mail rendering" do + context 'with an error on mail rendering' do before do allow(DigestMailer) .to receive(:work_packages) - .and_raise("error") + .and_raise('error') end - it "swallows the error" do + it 'swallows the error' do expect { job } .not_to raise_error end end - context "with an error on mail sending" do + context 'with an error on mail sending' do before do allow(mail) .to receive(:deliver_now) .and_raise(SocketError) end - it "raises the error" do + it 'raises the error' do expect { job } .to raise_error(SocketError) end end - context "with an empty list of notification ids" do + context 'with an empty list of notification ids' do let(:notification_ids) { [] } - it "sends no mail" do + it 'sends no mail' do job expect(DigestMailer) .not_to have_received(:work_packages) diff --git a/spec/workers/mails/shared/member_job.rb b/spec/workers/mails/shared/member_job.rb index 0fa3865a00f9..fabc031015a4 100644 --- a/spec/workers/mails/shared/member_job.rb +++ b/spec/workers/mails/shared/member_job.rb @@ -26,9 +26,9 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' -RSpec.shared_examples "member job" do +RSpec.shared_examples 'member job' do subject(:run_job) do described_class.perform_now(current_user:, member:, @@ -97,12 +97,12 @@ %i[added_project updated_global updated_project].each do |mails| allow(MemberMailer) .to receive(mails) - .and_return(double("mail", deliver_now: nil)) # rubocop:disable RSpec/VerifiedDoubles + .and_return(double('mail', deliver_now: nil)) # rubocop:disable RSpec/VerifiedDoubles end end - shared_examples_for "sends no mail" do - it "sends no mail" do + shared_examples_for 'sends no mail' do + it 'sends no mail' do run_job %i[added_project updated_global updated_project].each do |mails| @@ -112,11 +112,11 @@ end end - context "with a global membership" do + context 'with a global membership' do let(:project) { nil } - context "with sending enabled" do - it "sends mail" do + context 'with sending enabled' do + it 'sends mail' do run_job expect(MemberMailer) @@ -125,7 +125,7 @@ end end - context "with sending disabled" do + context 'with sending disabled' do let(:principal) do create(:user, notification_settings: [ @@ -135,7 +135,7 @@ ]) end - it "still sends mail due to the message present" do + it 'still sends mail due to the message present' do run_job expect(MemberMailer) @@ -143,23 +143,23 @@ .with(current_user, member, message) end - context "when the message is nil" do - let(:message) { "" } + context 'when the message is nil' do + let(:message) { '' } - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end end - context "with the current user being the membership user" do + context 'with the current user being the membership user' do let(:user) { current_user } - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end end - context "with a user membership" do - context "with sending enabled" do - it "sends mail" do + context 'with a user membership' do + context 'with sending enabled' do + it 'sends mail' do run_job expect(MemberMailer) @@ -168,10 +168,10 @@ end end - context "with the current user being the member user" do + context 'with the current user being the member user' do let(:user) { current_user } - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end end end diff --git a/spec/workers/mails/shared/watcher_job.rb b/spec/workers/mails/shared/watcher_job.rb index 1420cd6e5d5e..baf877bfd878 100644 --- a/spec/workers/mails/shared/watcher_job.rb +++ b/spec/workers/mails/shared/watcher_job.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.shared_examples "watcher job" do |action| subject { described_class.perform_now(watcher_parameter, watcher_changer) } @@ -63,11 +63,11 @@ # make sure no actual calls make it into the UserMailer allow(WorkPackageMailer) .to receive(:watcher_changed) - .and_return(double("mail", deliver_now: nil)) + .and_return(double('mail', deliver_now: nil)) end - shared_examples_for "sends a mail" do - it "sends a mail" do + shared_examples_for 'sends a mail' do + it 'sends a mail' do subject expect(WorkPackageMailer) .to have_received(:watcher_changed) @@ -78,77 +78,77 @@ end end - shared_examples_for "sends no mail" do - it "sends no mail" do + shared_examples_for 'sends no mail' do + it 'sends no mail' do subject expect(WorkPackageMailer) .not_to have_received(:watcher_changed) end end - describe "exceptions" do - describe "exceptions should be raised" do + describe 'exceptions' do + describe 'exceptions should be raised' do before do - mail = double("mail") + mail = double('mail') allow(mail).to receive(:deliver_now).and_raise(SocketError) allow(WorkPackageMailer).to receive(:watcher_changed).and_return(mail) end - it "raises the error" do + it 'raises the error' do expect { subject }.to raise_error(SocketError) end end end - shared_examples_for "notifies the watcher" do - context "when added by a different user" do - it_behaves_like "sends a mail" + shared_examples_for 'notifies the watcher' do + context 'when added by a different user' do + it_behaves_like 'sends a mail' end - context "when watcher is added by theirself" do + context 'when watcher is added by theirself' do let(:watcher_changer) { watching_user } - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end end - shared_examples_for "does not notify the watcher" do - context "when added by a different user" do - it_behaves_like "sends no mail" + shared_examples_for 'does not notify the watcher' do + context 'when added by a different user' do + it_behaves_like 'sends no mail' end - context "when watcher is added by theirself" do + context 'when watcher is added by theirself' do let(:watcher_changer) { watching_user } - it_behaves_like "sends no mail" + it_behaves_like 'sends no mail' end end - it_behaves_like "notifies the watcher" do + it_behaves_like 'notifies the watcher' do let(:notification_settings) do [build_stubbed(:notification_setting, mentioned: false, assignee: false, responsible: false, watched: true)] end end - it_behaves_like "notifies the watcher" do + it_behaves_like 'notifies the watcher' do let(:notification_settings) do [build_stubbed(:notification_setting, mentioned: false, assignee: false, responsible: false, watched: true)] end end - it_behaves_like "does not notify the watcher" do + it_behaves_like 'does not notify the watcher' do let(:notification_settings) do [build_stubbed(:notification_setting, mentioned: false, assignee: true, responsible: true, watched: false)] end end - it_behaves_like "does not notify the watcher" do + it_behaves_like 'does not notify the watcher' do let(:notification_settings) do [build_stubbed(:notification_setting, mentioned: true, assignee: false, responsible: false, watched: false)] end end - it_behaves_like "does not notify the watcher" do + it_behaves_like 'does not notify the watcher' do # Regression test for notification settings being empty let(:notification_settings) do [] diff --git a/spec/workers/mails/watcher_added_job_spec.rb b/spec/workers/mails/watcher_added_job_spec.rb index de12d99ca94e..03190078d8bd 100644 --- a/spec/workers/mails/watcher_added_job_spec.rb +++ b/spec/workers/mails/watcher_added_job_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared/watcher_job" +require 'spec_helper' +require_relative 'shared/watcher_job' RSpec.describe Mails::WatcherAddedJob, type: :model do - include_examples "watcher job", "added" do + include_examples "watcher job", 'added' do let(:watcher_parameter) { watcher } end end diff --git a/spec/workers/mails/watcher_removed_job_spec.rb b/spec/workers/mails/watcher_removed_job_spec.rb index ac4c4b2469b8..c9752aa24756 100644 --- a/spec/workers/mails/watcher_removed_job_spec.rb +++ b/spec/workers/mails/watcher_removed_job_spec.rb @@ -26,11 +26,11 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" -require_relative "shared/watcher_job" +require 'spec_helper' +require_relative 'shared/watcher_job' RSpec.describe Mails::WatcherRemovedJob, type: :model do - include_examples "watcher job", "removed" do + include_examples "watcher job", 'removed' do let(:watcher_parameter) { watcher.attributes } before do diff --git a/spec/workers/mails/work_package_shared_job_spec.rb b/spec/workers/mails/work_package_shared_job_spec.rb index 75c26ea8e503..4c855a77b030 100644 --- a/spec/workers/mails/work_package_shared_job_spec.rb +++ b/spec/workers/mails/work_package_shared_job_spec.rb @@ -28,7 +28,7 @@ # See COPYRIGHT and LICENSE files for more details. # ++ -require "spec_helper" +require 'spec_helper' RSpec.describe Mails::WorkPackageSharedJob, type: :model do subject(:run_job) do @@ -50,7 +50,7 @@ def stub_sharing_mailer before { stub_sharing_mailer } - context "with a user membership" do + context 'with a user membership' do let(:shared_with_user) { build_stubbed(:user) } let(:work_package_member) do build_stubbed(:work_package_member, @@ -59,7 +59,7 @@ def stub_sharing_mailer roles: [role]) end - it "sends mail" do + it 'sends mail' do run_job expect(SharingMailer) @@ -68,7 +68,7 @@ def stub_sharing_mailer end end - context "with a group membership" do + context 'with a group membership' do let(:group) do build_stubbed(:group) do |g| allow(g) @@ -136,7 +136,7 @@ def stub_sharing_mailer let(:group_user_members) { [group_user_member, other_group_user_member] } let(:group_user_members_due_an_email) { group_user_members } - it "sends mail to every user in the group" do + it 'sends mail to every user in the group' do run_job group_user_members.each do |group_user_member| @@ -176,7 +176,7 @@ def stub_sharing_mailer let(:group_user_members) { [group_user_member, other_group_user_member] } let(:group_user_members_due_an_email) { [other_group_user_member] } - it "only sends mail to group user that had no active shares in the work package" do + it 'only sends mail to group user that had no active shares in the work package' do run_job expect(SharingMailer) diff --git a/app/workers/job_concurrency.rb b/spec/workers/non_existing_job_class_spec.rb similarity index 51% rename from app/workers/job_concurrency.rb rename to spec/workers/non_existing_job_class_spec.rb index c98816841ade..d63caa8cbee6 100644 --- a/app/workers/job_concurrency.rb +++ b/spec/workers/non_existing_job_class_spec.rb @@ -26,17 +26,40 @@ # See COPYRIGHT and LICENSE files for more details. #++ -module JobConcurrency - extend ActiveSupport::Concern +require 'spec_helper' - included do - include GoodJob::ActiveJobExtensions::Concurrency +RSpec.describe "NonExistingJobClass" do + let!(:job_with_non_existing_class) do + handler = <<~JOB.strip + --- !ruby/object:ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper + job_data: + job_class: WhichShallNotBeNamedJob + job_id: 8f72c3c9-a1e0-4e46-b0f2-b517288bb76c + provider_job_id: + queue_name: default + priority: 5 + arguments: + - 42 + executions: 0 + exception_executions: {} + locale: en + timezone: UTC + enqueued_at: '2022-12-05T09:41:39Z' + JOB + Delayed::Job.create(handler:) end - ## - # Run the concurrency check of good_job without actually trying to enqueue it - # Will call the provided block in case the job would be cancelled - def check_concurrency(&block) - good_job_enqueue_concurrency_check(self, on_abort: block, on_enqueue: nil) + before do + # allow to inspect the job is marked as failed after failure in the test + allow(Delayed::Worker).to receive(:destroy_failed_jobs).and_return(false) + end + + it 'does not crash the worker when processed' do + expect { Delayed::Worker.new(exit_on_complete: true).start } + .not_to raise_error + + job_with_non_existing_class.reload + expect(job_with_non_existing_class.last_error).to include("uninitialized constant WhichShallNotBeNamedJob") + expect(job_with_non_existing_class.failed_at).to be_within(1).of(Time.current) end end diff --git a/spec/workers/notifications/create_date_alerts_notifications_job/alertable_work_packages_spec.rb b/spec/workers/notifications/create_date_alerts_notifications_job/alertable_work_packages_spec.rb index 15826af42741..0ff47dd9f430 100644 --- a/spec/workers/notifications/create_date_alerts_notifications_job/alertable_work_packages_spec.rb +++ b/spec/workers/notifications/create_date_alerts_notifications_job/alertable_work_packages_spec.rb @@ -26,13 +26,13 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "rails_helper" +require 'rails_helper' def relative_days(nb_days) case nb_days - when 1 then "tomorrow" - when 0 then "today" - when -1 then "yesterday" + when 1 then 'tomorrow' + when 0 then 'today' + when -1 then 'yesterday' else nb_days > 0 ? "in #{nb_days} days" : "#{-nb_days} days ago" end end @@ -45,10 +45,10 @@ def relative_days(nb_days) shared_let(:in_1_day) { today + 1.day } shared_let(:role) { create(:existing_project_role, permissions: [:view_work_packages]) } - shared_let(:user) { create(:user, firstname: "main") } - shared_let(:other_user) { create(:user, firstname: "other") } - shared_let(:project) { create(:project, name: "main", members: { user => role }) } - shared_let(:other_project) { create(:project, name: "other", members: { user => role }) } + shared_let(:user) { create(:user, firstname: 'main') } + shared_let(:other_user) { create(:user, firstname: 'other') } + shared_let(:project) { create(:project, name: 'main', members: { user => role }) } + shared_let(:other_project) { create(:project, name: 'other', members: { user => role }) } shared_let(:status_open) { create(:status, name: "open", is_closed: false) } shared_let(:status_closed) { create(:status, name: "closed", is_closed: true) } @@ -72,58 +72,58 @@ def make_alertable_work_package(attributes = {}) ### open / closed work package - it "returns open work packages" do + it 'returns open work packages' do open_work_package = make_alertable_work_package(status: status_open) expect(subject.alertable_for_start).to include(open_work_package) end - it "does not return closed work packages" do + it 'does not return closed work packages' do make_alertable_work_package(status: status_closed) expect(subject.alertable_for_start).to be_empty end ### user involved - it "returns work packages the user is assigned to" do + it 'returns work packages the user is assigned to' do assigned_work_package = make_alertable_work_package(assigned_to: user) expect(subject.alertable_for_start).to include(assigned_work_package) end - it "returns work packages the user is responsible / accountable for" do + it 'returns work packages the user is responsible / accountable for' do accountable_work_package = make_alertable_work_package(responsible: user) expect(subject.alertable_for_start).to include(accountable_work_package) end - it "returns work packages the user is watching" do + it 'returns work packages the user is watching' do watched_work_package = make_alertable_work_package(assigned_to: nil) create(:watcher, watchable: watched_work_package, user:) expect(subject.alertable_for_start).to include(watched_work_package) end - it "does not return work packages the user is author of" do + it 'does not return work packages the user is author of' do make_alertable_work_package(author: user, assigned_to: nil) expect(subject.alertable_for_start).to be_empty end - it "does not return work packages other users are involved into" do + it 'does not return work packages other users are involved into' do make_alertable_work_package(assigned_to: other_user) expect(subject.alertable_for_start).to be_empty end ### default notification settings - context "with default global notification settings" do - it "returns work packages starting in 1 day for a user" do + context 'with default global notification settings' do + it 'returns work packages starting in 1 day for a user' do wp_start_in_1_day = make_alertable_work_package(start_date: in_1_day, due_date: nil) expect(subject.alertable_for_start).to include(wp_start_in_1_day) end - it "returns work packages due in 1 day for a user" do + it 'returns work packages due in 1 day for a user' do wp_due_in_1_day = make_alertable_work_package(start_date: nil, due_date: in_1_day) expect(subject.alertable_for_due).to include(wp_due_in_1_day) end - it "does not return overdue work packages for a user" do + it 'does not return overdue work packages for a user' do make_alertable_work_package(start_date: nil, due_date: yesterday) expect(subject.alertable_for_due).to be_empty end @@ -131,7 +131,7 @@ def make_alertable_work_package(attributes = {}) ### start_date specs - shared_examples "alertable if start date" do |days_from_now:| + shared_examples 'alertable if start date' do |days_from_now:| date = Date.current + days_from_now.days it "returns work packages with start date being #{relative_days(days_from_now)}" do @@ -140,7 +140,7 @@ def make_alertable_work_package(attributes = {}) end end - shared_examples "not alertable if start date" do |days_from_now:| + shared_examples 'not alertable if start date' do |days_from_now:| date = Date.current + days_from_now.days it "does not return work packages with start date being #{relative_days(days_from_now)}" do @@ -149,64 +149,64 @@ def make_alertable_work_package(attributes = {}) end end - context "with notification settings start_date not set" do + context 'with notification settings start_date not set' do before do global_notification_settings.update(start_date: nil, due_date: nil, overdue: nil) end - include_examples "not alertable if start date", days_from_now: 0 - include_examples "not alertable if start date", days_from_now: 1 - include_examples "not alertable if start date", days_from_now: 3 - include_examples "not alertable if start date", days_from_now: 42 + include_examples 'not alertable if start date', days_from_now: 0 + include_examples 'not alertable if start date', days_from_now: 1 + include_examples 'not alertable if start date', days_from_now: 3 + include_examples 'not alertable if start date', days_from_now: 42 end - context "with notification settings start_date set to same day" do + context 'with notification settings start_date set to same day' do before do global_notification_settings.update(start_date: 0, due_date: nil, overdue: nil) end - include_examples "alertable if start date", days_from_now: 0 - include_examples "not alertable if start date", days_from_now: 1 - include_examples "not alertable if start date", days_from_now: 3 - include_examples "not alertable if start date", days_from_now: 7 + include_examples 'alertable if start date', days_from_now: 0 + include_examples 'not alertable if start date', days_from_now: 1 + include_examples 'not alertable if start date', days_from_now: 3 + include_examples 'not alertable if start date', days_from_now: 7 end - context "with notification settings start_date set to 1 day" do + context 'with notification settings start_date set to 1 day' do before do global_notification_settings.update(start_date: 1, due_date: nil, overdue: nil) end - include_examples "not alertable if start date", days_from_now: 0 - include_examples "alertable if start date", days_from_now: 1 - include_examples "not alertable if start date", days_from_now: 3 - include_examples "not alertable if start date", days_from_now: 7 + include_examples 'not alertable if start date', days_from_now: 0 + include_examples 'alertable if start date', days_from_now: 1 + include_examples 'not alertable if start date', days_from_now: 3 + include_examples 'not alertable if start date', days_from_now: 7 end - context "with notification settings start_date set to 3 days" do + context 'with notification settings start_date set to 3 days' do before do global_notification_settings.update(start_date: 3, due_date: nil, overdue: nil) end - include_examples "not alertable if start date", days_from_now: 0 - include_examples "not alertable if start date", days_from_now: 1 - include_examples "alertable if start date", days_from_now: 3 - include_examples "not alertable if start date", days_from_now: 7 + include_examples 'not alertable if start date', days_from_now: 0 + include_examples 'not alertable if start date', days_from_now: 1 + include_examples 'alertable if start date', days_from_now: 3 + include_examples 'not alertable if start date', days_from_now: 7 end - context "with notification settings start_date set to 7 days" do + context 'with notification settings start_date set to 7 days' do before do global_notification_settings.update(start_date: 7, due_date: nil, overdue: nil) end - include_examples "not alertable if start date", days_from_now: 0 - include_examples "not alertable if start date", days_from_now: 1 - include_examples "not alertable if start date", days_from_now: 3 - include_examples "alertable if start date", days_from_now: 7 + include_examples 'not alertable if start date', days_from_now: 0 + include_examples 'not alertable if start date', days_from_now: 1 + include_examples 'not alertable if start date', days_from_now: 3 + include_examples 'alertable if start date', days_from_now: 7 end ### due_date specs - shared_examples "alertable if due date" do |days_from_now:| + shared_examples 'alertable if due date' do |days_from_now:| date = Date.current + days_from_now.days it "returns work packages with due date being #{relative_days(days_from_now)}" do @@ -215,7 +215,7 @@ def make_alertable_work_package(attributes = {}) end end - shared_examples "not alertable if due date" do |days_from_now:| + shared_examples 'not alertable if due date' do |days_from_now:| date = Date.current + days_from_now.days it "does not return work packages with due date being #{relative_days(days_from_now)}" do @@ -224,64 +224,64 @@ def make_alertable_work_package(attributes = {}) end end - context "with notification settings due_date not set" do + context 'with notification settings due_date not set' do before do global_notification_settings.update(start_date: nil, due_date: nil, overdue: nil) end - include_examples "not alertable if due date", days_from_now: 0 - include_examples "not alertable if due date", days_from_now: 1 - include_examples "not alertable if due date", days_from_now: 3 - include_examples "not alertable if due date", days_from_now: 42 + include_examples 'not alertable if due date', days_from_now: 0 + include_examples 'not alertable if due date', days_from_now: 1 + include_examples 'not alertable if due date', days_from_now: 3 + include_examples 'not alertable if due date', days_from_now: 42 end - context "with notification settings due_date set to same day" do + context 'with notification settings due_date set to same day' do before do global_notification_settings.update(start_date: nil, due_date: 0, overdue: nil) end - include_examples "alertable if due date", days_from_now: 0 - include_examples "not alertable if due date", days_from_now: 1 - include_examples "not alertable if due date", days_from_now: 3 - include_examples "not alertable if due date", days_from_now: 7 + include_examples 'alertable if due date', days_from_now: 0 + include_examples 'not alertable if due date', days_from_now: 1 + include_examples 'not alertable if due date', days_from_now: 3 + include_examples 'not alertable if due date', days_from_now: 7 end - context "with notification settings due_date set to 1 day" do + context 'with notification settings due_date set to 1 day' do before do global_notification_settings.update(start_date: nil, due_date: 1, overdue: nil) end - include_examples "not alertable if due date", days_from_now: 0 - include_examples "alertable if due date", days_from_now: 1 - include_examples "not alertable if due date", days_from_now: 3 - include_examples "not alertable if due date", days_from_now: 7 + include_examples 'not alertable if due date', days_from_now: 0 + include_examples 'alertable if due date', days_from_now: 1 + include_examples 'not alertable if due date', days_from_now: 3 + include_examples 'not alertable if due date', days_from_now: 7 end - context "with notification settings due_date set to 3 days" do + context 'with notification settings due_date set to 3 days' do before do global_notification_settings.update(start_date: nil, due_date: 3, overdue: nil) end - include_examples "not alertable if due date", days_from_now: 0 - include_examples "not alertable if due date", days_from_now: 1 - include_examples "alertable if due date", days_from_now: 3 - include_examples "not alertable if due date", days_from_now: 7 + include_examples 'not alertable if due date', days_from_now: 0 + include_examples 'not alertable if due date', days_from_now: 1 + include_examples 'alertable if due date', days_from_now: 3 + include_examples 'not alertable if due date', days_from_now: 7 end - context "with notification settings due_date set to 7 days" do + context 'with notification settings due_date set to 7 days' do before do global_notification_settings.update(start_date: nil, due_date: 7, overdue: nil) end - include_examples "not alertable if due date", days_from_now: 0 - include_examples "not alertable if due date", days_from_now: 1 - include_examples "not alertable if due date", days_from_now: 3 - include_examples "alertable if due date", days_from_now: 7 + include_examples 'not alertable if due date', days_from_now: 0 + include_examples 'not alertable if due date', days_from_now: 1 + include_examples 'not alertable if due date', days_from_now: 3 + include_examples 'alertable if due date', days_from_now: 7 end ### overdue specs - shared_examples "alertable if due" do |days_ago:| + shared_examples 'alertable if due' do |days_ago:| date = Date.current - days_ago.days it "returns work packages due #{relative_days(-days_ago)}" do @@ -290,7 +290,7 @@ def make_alertable_work_package(attributes = {}) end end - shared_examples "not alertable if due" do |days_ago:| + shared_examples 'not alertable if due' do |days_ago:| date = Date.current - days_ago.days it "does not return work packages due #{relative_days(-days_ago)}" do @@ -299,66 +299,66 @@ def make_alertable_work_package(attributes = {}) end end - context "with notification settings overdue not set" do + context 'with notification settings overdue not set' do before do global_notification_settings.update(start_date: nil, due_date: nil, overdue: nil) end - include_examples "not alertable if due", days_ago: 0 - include_examples "not alertable if due", days_ago: 1 - include_examples "not alertable if due", days_ago: 2 - include_examples "not alertable if due", days_ago: 3 - include_examples "not alertable if due", days_ago: 42 + include_examples 'not alertable if due', days_ago: 0 + include_examples 'not alertable if due', days_ago: 1 + include_examples 'not alertable if due', days_ago: 2 + include_examples 'not alertable if due', days_ago: 3 + include_examples 'not alertable if due', days_ago: 42 end - context "with notification settings overdue set to every day" do + context 'with notification settings overdue set to every day' do before do global_notification_settings.update(start_date: nil, due_date: nil, overdue: 1) end - include_examples "not alertable if due", days_ago: 0 - include_examples "alertable if due", days_ago: 1 - include_examples "alertable if due", days_ago: 2 - include_examples "alertable if due", days_ago: 10 + include_examples 'not alertable if due', days_ago: 0 + include_examples 'alertable if due', days_ago: 1 + include_examples 'alertable if due', days_ago: 2 + include_examples 'alertable if due', days_ago: 10 end - context "with notification settings overdue set to every 3 days" do + context 'with notification settings overdue set to every 3 days' do before do global_notification_settings.update(start_date: nil, due_date: nil, overdue: 3) end - include_examples "not alertable if due", days_ago: 0 - include_examples "alertable if due", days_ago: 1 - include_examples "not alertable if due", days_ago: 2 - include_examples "not alertable if due", days_ago: 3 - include_examples "alertable if due", days_ago: 4 - include_examples "not alertable if due", days_ago: 5 - include_examples "not alertable if due", days_ago: 6 - include_examples "alertable if due", days_ago: 7 + include_examples 'not alertable if due', days_ago: 0 + include_examples 'alertable if due', days_ago: 1 + include_examples 'not alertable if due', days_ago: 2 + include_examples 'not alertable if due', days_ago: 3 + include_examples 'alertable if due', days_ago: 4 + include_examples 'not alertable if due', days_ago: 5 + include_examples 'not alertable if due', days_ago: 6 + include_examples 'alertable if due', days_ago: 7 end - context "with notification settings overdue set to every 7 days" do + context 'with notification settings overdue set to every 7 days' do before do global_notification_settings.update(start_date: nil, due_date: nil, overdue: 7) end - include_examples "not alertable if due", days_ago: 0 - include_examples "alertable if due", days_ago: 1 - include_examples "not alertable if due", days_ago: 2 - include_examples "not alertable if due", days_ago: 3 - include_examples "not alertable if due", days_ago: 4 - include_examples "not alertable if due", days_ago: 7 - include_examples "alertable if due", days_ago: 8 - include_examples "not alertable if due", days_ago: 12 - include_examples "alertable if due", days_ago: 15 + include_examples 'not alertable if due', days_ago: 0 + include_examples 'alertable if due', days_ago: 1 + include_examples 'not alertable if due', days_ago: 2 + include_examples 'not alertable if due', days_ago: 3 + include_examples 'not alertable if due', days_ago: 4 + include_examples 'not alertable if due', days_ago: 7 + include_examples 'alertable if due', days_ago: 8 + include_examples 'not alertable if due', days_ago: 12 + include_examples 'alertable if due', days_ago: 15 end ### project-specific notification settings specs - context "with project notification settings overriding global notification settings" do + context 'with project notification settings overriding global notification settings' do shared_let(:project_notification_settings) { user.notification_settings.create(project:) } - it "uses the project settings" do + it 'uses the project settings' do global_notification_settings.update(start_date: nil, due_date: nil, overdue: nil) project_notification_settings.update(start_date: 1, due_date: 1, overdue: 1) @@ -376,7 +376,7 @@ def make_alertable_work_package(attributes = {}) expect(subject.alertable_for_due).not_to include(wp_start_and_due_in_1_day_other_project) end - it "does not use global settings if project settings are nil" do + it 'does not use global settings if project settings are nil' do global_notification_settings.update(start_date: 1, due_date: 1) project_notification_settings.update(start_date: nil, due_date: nil) diff --git a/spec/workers/notifications/create_date_alerts_notifications_job_spec.rb b/spec/workers/notifications/create_date_alerts_notifications_job_spec.rb index f43a0bb635b6..6b0f4290414b 100644 --- a/spec/workers/notifications/create_date_alerts_notifications_job_spec.rb +++ b/spec/workers/notifications/create_date_alerts_notifications_job_spec.rb @@ -26,21 +26,21 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::CreateDateAlertsNotificationsJob, type: :job, with_ee: %i[date_alerts] do include ActiveSupport::Testing::TimeHelpers - shared_let(:project) { create(:project, name: "main") } + shared_let(:project) { create(:project, name: 'main') } shared_let(:status_open) { create(:status, name: "open", is_closed: false) } shared_let(:status_closed) { create(:status, name: "closed", is_closed: true) } # Paris and Berlin are both UTC+01:00 (CET) or UTC+02:00 (CEST) - shared_let(:timezone_paris) { ActiveSupport::TimeZone["Europe/Paris"] } - shared_let(:timezone_berlin) { ActiveSupport::TimeZone["Europe/Berlin"] } + shared_let(:timezone_paris) { ActiveSupport::TimeZone['Europe/Paris'] } + shared_let(:timezone_berlin) { ActiveSupport::TimeZone['Europe/Berlin'] } # Kathmandu is UTC+05:45 (no DST) - shared_let(:timezone_kathmandu) { ActiveSupport::TimeZone["Asia/Kathmandu"] } + shared_let(:timezone_kathmandu) { ActiveSupport::TimeZone['Asia/Kathmandu'] } # use Paris time zone for most tests shared_let(:today) { timezone_paris.today } @@ -51,7 +51,7 @@ shared_let(:user) do create( :user, - firstname: "Paris", + firstname: 'Paris', preferences: { time_zone: timezone_paris.name } ) end @@ -91,7 +91,7 @@ def inspect_keys(object) formatted_pairs = object .slice(*keys) .map { |k, v| "#{k}: #{v.is_a?(Date) ? v.to_s : v.inspect}" } - .join(", ") + .join(', ') "#<#{formatted_pairs}>" end end @@ -125,7 +125,7 @@ def inspect_keys(object) formatted_pairs = object .slice(*keys) .map { |k, v| "#{k}: #{v.is_a?(Date) ? v.to_s : v.inspect}" } - .join(", ") + .join(', ') "#<#{formatted_pairs}>" end end @@ -143,14 +143,14 @@ def alertable_work_package(attributes = {}) # Converts "hh:mm" into { hour: h, min: m } def time_hash(time) - %i[hour min].zip(time.split(":", 2).map(&:to_i)).to_h + %i[hour min].zip(time.split(':', 2).map(&:to_i)).to_h end def timezone_time(time, timezone) timezone.now.change(time_hash(time)) end - def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) + def run_job(scheduled_at: '1:00', local_time: '1:04', timezone: timezone_paris) travel_to(timezone_time(local_time, timezone)) do job.perform_now(user) @@ -158,8 +158,8 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - describe "#perform" do - it "creates date alert notifications only for open work packages" do + describe '#perform' do + it 'creates date alert notifications only for open work packages' do open_work_package = alertable_work_package(status: status_open) closed_work_package = alertable_work_package(status: status_closed) @@ -169,7 +169,7 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - it "creates date alert notifications if user is assigned to the work package" do + it 'creates date alert notifications if user is assigned to the work package' do work_package_assigned = alertable_work_package(assigned_to: user) run_job do @@ -177,7 +177,7 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - it "creates date alert notifications if user is accountable of the work package" do + it 'creates date alert notifications if user is accountable of the work package' do work_package_accountable = alertable_work_package(responsible: user) run_job do @@ -185,7 +185,7 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - it "creates date alert notifications if user is watcher of the work package" do + it 'creates date alert notifications if user is watcher of the work package' do work_package_watched = alertable_work_package(responsible: nil) build(:watcher, watchable: work_package_watched, user:).save(validate: false) @@ -194,7 +194,7 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - it "creates start date alert notifications based on user notification settings" do + it 'creates start date alert notifications based on user notification settings' do user.notification_settings.first.update( start_date: 1, due_date: nil @@ -209,7 +209,7 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - it "creates due date alert notifications based on user notification settings" do + it 'creates due date alert notifications based on user notification settings' do user.notification_settings.first.update( start_date: nil, due_date: 3 @@ -224,8 +224,8 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - context "without enterprise token", with_ee: false do - it "does not create any date alerts" do + context 'without enterprise token', with_ee: false do + it 'does not create any date alerts' do work_package = alertable_work_package run_job do @@ -234,8 +234,8 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - context "when project notification settings are defined for a user" do - it "creates date alert notifications using these settings for work packages of the project" do + context 'when project notification settings are defined for a user' do + it 'creates date alert notifications using these settings for work packages of the project' do # global notification settings user.notification_settings.first.update( start_date: 1, @@ -265,8 +265,8 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end end - context "with existing date alerts" do - it "marks them as read when new ones are created" do + context 'with existing date alerts' do + it 'marks them as read when new ones are created' do work_package = alertable_work_package(assigned_to: user, start_date: in_1_day, due_date: in_1_day) @@ -291,7 +291,7 @@ def run_job(scheduled_at: "1:00", local_time: "1:04", timezone: timezone_paris) end # rubocop:disable RSpec/ExampleLength - it "does not mark them as read when if no new notifications are created" do + it 'does not mark them as read when if no new notifications are created' do work_package_start = alertable_work_package(assigned_to: user, start_date: in_1_day, due_date: nil) diff --git a/spec/workers/notifications/group_member_altered_job_spec.rb b/spec/workers/notifications/group_member_altered_job_spec.rb index 4174c366dc95..356eed7ce900 100644 --- a/spec/workers/notifications/group_member_altered_job_spec.rb +++ b/spec/workers/notifications/group_member_altered_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::GroupMemberAlteredJob, type: :model do subject(:service_call) do @@ -56,7 +56,7 @@ .and_return(members) end - it "sends a created notification for the membership with the matching timestamps" do + it 'sends a created notification for the membership with the matching timestamps' do service_call expect(OpenProject::Notifications) @@ -64,7 +64,7 @@ .with(OpenProject::Events::MEMBER_CREATED, member: member1, message:, send_notifications: send_notification) end - it "sends an updated notification for the membership with the mismatching timestamps" do + it 'sends an updated notification for the membership with the mismatching timestamps' do service_call expect(OpenProject::Notifications) @@ -72,7 +72,7 @@ .with(OpenProject::Events::MEMBER_UPDATED, member: member2, message:, send_notifications: send_notification) end - it "propagates the given current user when sending notifications" do + it 'propagates the given current user when sending notifications' do captured_current_user = nil allow(OpenProject::Notifications) .to receive(:send) do |_args| diff --git a/spec/workers/notifications/schedule_date_alerts_notifications_job_spec.rb b/spec/workers/notifications/schedule_date_alerts_notifications_job_spec.rb index 5e9fcc86917d..fe29cb487635 100644 --- a/spec/workers/notifications/schedule_date_alerts_notifications_job_spec.rb +++ b/spec/workers/notifications/schedule_date_alerts_notifications_job_spec.rb @@ -26,157 +26,176 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::ScheduleDateAlertsNotificationsJob, type: :job, with_ee: %i[date_alerts] do include ActiveSupport::Testing::TimeHelpers - shared_let(:project) { create(:project, name: "main") } + shared_let(:project) { create(:project, name: 'main') } + # Paris and Berlin are both UTC+01:00 (CET) or UTC+02:00 (CEST) - shared_let(:timezone_paris) { ActiveSupport::TimeZone["Europe/Paris"] } + shared_let(:timezone_paris) { ActiveSupport::TimeZone['Europe/Paris'] } # Kathmandu is UTC+05:45 (no DST) - shared_let(:timezone_kathmandu) { ActiveSupport::TimeZone["Asia/Kathmandu"] } + shared_let(:timezone_kathmandu) { ActiveSupport::TimeZone['Asia/Kathmandu'] } + shared_let(:user_paris) do - create(:user, - firstname: "Paris", - preferences: { time_zone: timezone_paris.name }) + create( + :user, + firstname: 'Paris', + preferences: { time_zone: timezone_paris.name } + ) end shared_let(:user_kathmandu) do - create(:user, - firstname: "Kathmandu", - preferences: { time_zone: timezone_kathmandu.name }) + create( + :user, + firstname: 'Kathmandu', + preferences: { time_zone: timezone_kathmandu.name } + ) end - let(:scheduled_job) { described_class.perform_later } + let(:schedule_job) do + described_class.ensure_scheduled! + described_class.delayed_job + end before do - ActiveJob::Base.disable_test_adapter - scheduled_job + # We need to access the job as stored in the database to get at the run_at time persisted there + allow(ActiveJob::Base) + .to receive(:queue_adapter) + .and_return(ActiveJob::QueueAdapters::DelayedJobAdapter.new) + schedule_job end - def set_scheduled_time(scheduled_at) - GoodJob::Job.where(id: scheduled_job.job_id).update_all(scheduled_at:) + def set_scheduled_time(run_at) + schedule_job.update_column(:run_at, run_at) end # Converts "hh:mm" into { hour: h, min: m } def time_hash(time) - %i[hour min].zip(time.split(":", 2).map(&:to_i)).to_h + %i[hour min].zip(time.split(':', 2).map(&:to_i)).to_h end def timezone_time(time, timezone) timezone.now.change(time_hash(time)) end - def run_job(scheduled_at:, local_time:, timezone:) + def run_job(scheduled_at: '1:00', local_time: '1:04', timezone: timezone_paris) set_scheduled_time(timezone_time(scheduled_at, timezone)) travel_to(timezone_time(local_time, timezone)) do - GoodJob.perform_inline - # scheduled_job.reload.invoke_job + schedule_job.reload.invoke_job yield if block_given? end end - def deserialize_job(job) - deserializer_class = Class.new { include(ActiveJob::Arguments) } - deserializer_class.new - .deserialize(job.serialized_params) - .to_h + def deserialized_of_job(job) + deserializer_class = Class.new do + include(ActiveJob::Arguments) + end + + deserializer = deserializer_class.new + + deserializer.deserialize(job.payload_object.job_data).to_h end - def expect_job(job, *arguments) - job_data = deserialize_job(job) - expect(job_data["job_class"]).to eql(job.job_class) - expect(job_data["arguments"]).to match_array arguments - expect(job_data["executions"]).to eq 0 + def expect_job(job, klass, *arguments) + job_data = deserialized_of_job(job) + expect(job_data['job_class']) + .to eql klass + expect(job_data['arguments']) + .to match_array arguments end - shared_examples_for "job execution creates date alerts creation job" do - let(:job_class) { Notifications::CreateDateAlertsNotificationsJob.name } + shared_examples_for 'job execution creates date alerts creation job' do + let(:timezone) { timezone_paris } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:04' } + let(:user) { user_paris } - it "creates the job for the user" do + it 'creates the job for the user' do expect do run_job(timezone:, scheduled_at:, local_time:) do - j = GoodJob::Job.where(job_class:) - .order(created_at: :desc) - .last - expect_job(j, user) + expect_job(Delayed::Job.last, "Notifications::CreateDateAlertsNotificationsJob", user) end - end.to change { GoodJob::Job.where(job_class:).count }.by 1 + end.to change(Delayed::Job, :count).by 1 end end - shared_examples_for "job execution creates no date alerts creation job" do - it "creates no job" do + shared_examples_for 'job execution creates no date alerts creation job' do + let(:timezone) { timezone_paris } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:04' } + + it 'creates no job' do expect do run_job(timezone:, scheduled_at:, local_time:) - end.not_to change(GoodJob::Job, :count) + end.not_to change(Delayed::Job, :count) end end - describe "#perform" do - context "for users whose local time is 1:00 am (UTC+1) when the job is executed" do - it_behaves_like "job execution creates date alerts creation job" do + describe '#perform' do + context 'for users whose local time is 1:00 am (UTC+1) when the job is executed' do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:04" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:04' } let(:user) { user_paris } end end - context "for users whose local time is 1:00 am (UTC+05:45) when the job is executed" do - it_behaves_like "job execution creates date alerts creation job" do + context 'for users whose local time is 1:00 am (UTC+05:45) when the job is executed' do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_kathmandu } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:04" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:04' } let(:user) { user_kathmandu } end end - context "without enterprise token", with_ee: false do - it_behaves_like "job execution creates no date alerts creation job" do + context 'without enterprise token', with_ee: false do + it_behaves_like 'job execution creates no date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:04" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:04' } end end - context "when scheduled and executed at 01:00 am local time" do - it_behaves_like "job execution creates date alerts creation job" do + context 'when scheduled and executed at 01:00 am local time' do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } let(:user) { user_paris } end end - context "when scheduled and executed at 01:14 am local time" do - it_behaves_like "job execution creates date alerts creation job" do + context 'when scheduled and executed at 01:14 am local time' do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:14" } - let(:local_time) { "1:14" } + let(:scheduled_at) { '1:14' } + let(:local_time) { '1:14' } let(:user) { user_paris } end end - context "when scheduled and executed at 01:15 am local time" do - it_behaves_like "job execution creates no date alerts creation job" do + context 'when scheduled and executed at 01:15 am local time' do + it_behaves_like 'job execution creates no date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:15" } - let(:local_time) { "1:15" } + let(:scheduled_at) { '1:15' } + let(:local_time) { '1:15' } end end - context "when scheduled at 01:00 am local time and executed at 01:37 am local time" do - it_behaves_like "job execution creates date alerts creation job" do + context 'when scheduled at 01:00 am local time and executed at 01:37 am local time' do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:37" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:37' } let(:user) { user_paris } end end - context "with a user having only due_date active in notification settings" do + context 'with a user having only due_date active in notification settings' do before do NotificationSetting .where(user: user_paris) @@ -185,15 +204,15 @@ def expect_job(job, *arguments) overdue: nil) end - it_behaves_like "job execution creates date alerts creation job" do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } let(:user) { user_paris } end end - context "with a user having only start_date active in notification settings" do + context 'with a user having only start_date active in notification settings' do before do NotificationSetting .where(user: user_paris) @@ -202,15 +221,15 @@ def expect_job(job, *arguments) overdue: nil) end - it_behaves_like "job execution creates date alerts creation job" do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } let(:user) { user_paris } end end - context "with a user having only overdue active in notification settings" do + context 'with a user having only overdue active in notification settings' do before do NotificationSetting .where(user: user_paris) @@ -219,15 +238,15 @@ def expect_job(job, *arguments) overdue: 1) end - it_behaves_like "job execution creates date alerts creation job" do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } let(:user) { user_paris } end end - context "without a user having notification settings" do + context 'without a user having notification settings' do before do NotificationSetting .where(user: user_paris) @@ -236,14 +255,14 @@ def expect_job(job, *arguments) overdue: nil) end - it_behaves_like "job execution creates no date alerts creation job" do + it_behaves_like 'job execution creates no date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } end end - context "with a user having only a project active notification settings" do + context 'with a user having only a project active notification settings' do before do NotificationSetting .where(user: user_paris) @@ -259,23 +278,23 @@ def expect_job(job, *arguments) overdue: nil) end - it_behaves_like "job execution creates date alerts creation job" do + it_behaves_like 'job execution creates date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } let(:user) { user_paris } end end - context "with a locked user" do + context 'with a locked user' do before do user_paris.locked! end - it_behaves_like "job execution creates no date alerts creation job" do + it_behaves_like 'job execution creates no date alerts creation job' do let(:timezone) { timezone_paris } - let(:scheduled_at) { "1:00" } - let(:local_time) { "1:00" } + let(:scheduled_at) { '1:00' } + let(:local_time) { '1:00' } end end end diff --git a/spec/workers/notifications/schedule_reminder_mails_job_spec.rb b/spec/workers/notifications/schedule_reminder_mails_job_spec.rb index a8c3a2fcfa48..99538d4f7b81 100644 --- a/spec/workers/notifications/schedule_reminder_mails_job_spec.rb +++ b/spec/workers/notifications/schedule_reminder_mails_job_spec.rb @@ -26,51 +26,74 @@ # See docs/COPYRIGHT.rdoc for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::ScheduleReminderMailsJob, type: :job do - let(:scheduled_job) { described_class.perform_later } + subject(:job) { scheduled_job.invoke_job } + + let(:scheduled_job) do + described_class.ensure_scheduled! + + Delayed::Job.first + end + let(:ids) { [23, 42] } + let(:run_at) { scheduled_job.run_at } before do - # We need to access the job as stored in the database to get at the scheduled_at time persisted there - ActiveJob::Base.disable_test_adapter - scheduled_job + # We need to access the job as stored in the database to get at the run_at time persisted there + allow(ActiveJob::Base) + .to receive(:queue_adapter) + .and_return(ActiveJob::QueueAdapters::DelayedJobAdapter.new) + + scheduled_job.update_column(:run_at, run_at) scope = instance_double(ActiveRecord::Relation) - allow(User).to receive(:having_reminder_mail_to_send).and_return(scope) - allow(scope).to receive(:pluck).with(:id).and_return(ids) + allow(User) + .to receive(:having_reminder_mail_to_send) + .and_return(scope) + + allow(scope) + .to receive(:pluck) + .with(:id) + .and_return(ids) end - describe "#perform" do - shared_examples_for "schedules reminder mails" do - it "schedules reminder jobs for every user with a reminder mails to be sent" do - expect { GoodJob.perform_inline }.to change(GoodJob::Job, :count).by(2) + describe '#perform' do + shared_examples_for 'schedules reminder mails' do + it 'schedules reminder jobs for every user with a reminder mails to be sent' do + expect { subject } + .to change(Delayed::Job, :count) + .by(2) + + jobs = Delayed::Job.all.map do |job| + YAML.safe_load(job.handler, permitted_classes: [ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper]) + end + + reminder_jobs = jobs.select { |job| job.job_data['job_class'] == "Mails::ReminderJob" } - arguments_from_both_jobs = - GoodJob::Job.where(job_class: "Mails::ReminderJob") - .flat_map {|i| i.serialized_params["arguments"]} - .sort - expect(arguments_from_both_jobs).to eq(ids) + expect(reminder_jobs[0].job_data['arguments']) + .to contain_exactly(23) + + expect(reminder_jobs[1].job_data['arguments']) + .to contain_exactly(42) end - it "queries with the intended job execution time (which might have been missed due to high load)" do - GoodJob.perform_inline + it 'queries with the intended job execution time (which might have been missed due to high load)' do + subject - expect(User).to have_received(:having_reminder_mail_to_send).with(scheduled_job.job_scheduled_at) + expect(User) + .to have_received(:having_reminder_mail_to_send) + .with(run_at) end end - it_behaves_like "schedules reminder mails" + it_behaves_like 'schedules reminder mails' - context "with a job that missed some runs" do - before do - GoodJob::Job - .where(id: scheduled_job.job_id) - .update_all(scheduled_at: scheduled_job.job_scheduled_at - 3.hours) - end + context 'with a job that missed some runs' do + let(:run_at) { scheduled_job.run_at - 3.hours } - it_behaves_like "schedules reminder mails" + it_behaves_like 'schedules reminder mails' end end end diff --git a/spec/workers/notifications/workflow_job_spec.rb b/spec/workers/notifications/workflow_job_spec.rb index 4c8e7a5d26ad..7f78a2eb5d5e 100644 --- a/spec/workers/notifications/workflow_job_spec.rb +++ b/spec/workers/notifications/workflow_job_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Notifications::WorkflowJob, type: :model do subject(:perform_job) do @@ -45,8 +45,8 @@ build_stubbed(:notification, reason: :mentioned) end - describe "#perform" do - context "with the :create_notifications state" do + describe '#perform' do + context 'with the :create_notifications state' do let(:state) { :create_notifications } let(:arguments) { [resource, send_notification] } let(:resource) { build_stubbed(:comment) } @@ -84,7 +84,7 @@ service_instance end - it "calls the service to create notifications" do + it 'calls the service to create notifications' do perform_job expect(create_service) @@ -92,14 +92,14 @@ .with(send_notification) end - it "sends mails for all notifications that are marked to send mails and that have a mention reason" do + it 'sends mails for all notifications that are marked to send mails and that have a mention reason' do perform_job expect(mail_service) .to have_received(:call) end - it "schedules a delayed WorkflowJob for those notifications not to be sent directly" do + it 'schedules a delayed WorkflowJob for those notifications not to be sent directly' do allow(Time) .to receive(:current) .and_return(Time.current) @@ -114,7 +114,7 @@ end end - context "with the :send_mails state" do + context 'with the :send_mails state' do let(:state) { :send_mails } let(:arguments) { notifications.map(&:id) } @@ -139,7 +139,7 @@ .and_return(scope) end - it "sends mails for all notifications that are marked to send mails" do + it 'sends mails for all notifications that are marked to send mails' do perform_job expect(mail_service) diff --git a/spec/workers/principals/delete_job_integration_spec.rb b/spec/workers/principals/delete_job_integration_spec.rb index 2837477f3253..9b73379a4a01 100644 --- a/spec/workers/principals/delete_job_integration_spec.rb +++ b/spec/workers/principals/delete_job_integration_spec.rb @@ -26,7 +26,7 @@ # See COPYRIGHT and LICENSE files for more details. #++ -require "spec_helper" +require 'spec_helper' RSpec.describe Principals::DeleteJob, type: :model do subject(:job) { described_class.perform_now(principal) } @@ -50,11 +50,11 @@ create(:project_role, permissions: %i[view_work_packages]) end - describe "#perform" do + describe '#perform' do # These are the only tests that include testing # the ReplaceReferencesService. Most of the tests for this # Service are handled within the matching spec file. - shared_examples_for "work_package handling" do + shared_examples_for 'work_package handling' do let(:work_package) do create(:work_package, assigned_to: principal, @@ -66,28 +66,28 @@ job end - it "resets assigned to to the deleted user" do + it 'resets assigned to to the deleted user' do expect(work_package.reload.assigned_to) .to eql(deleted_user) end - it "resets assigned to in all journals to the deleted user" do + it 'resets assigned to in all journals to the deleted user' do expect(Journal::WorkPackageJournal.pluck(:assigned_to_id)) .to eql([deleted_user.id]) end - it "resets responsible to to the deleted user" do + it 'resets responsible to to the deleted user' do expect(work_package.reload.responsible) .to eql(deleted_user) end - it "resets responsible to in all journals to the deleted user" do + it 'resets responsible to in all journals to the deleted user' do expect(Journal::WorkPackageJournal.pluck(:responsible_id)) .to eql([deleted_user.id]) end end - shared_examples_for "labor_budget_item handling" do + shared_examples_for 'labor_budget_item handling' do let(:item) { build(:labor_budget_item, user: principal) } before do @@ -100,7 +100,7 @@ it { expect(item.user_id).to eq(principal.id) } end - shared_examples_for "cost_entry handling" do + shared_examples_for 'cost_entry handling' do let(:work_package) { create(:work_package) } let(:entry) do create(:cost_entry, @@ -109,7 +109,7 @@ units: 100.0, spent_on: Time.zone.today, work_package:, - comments: "") + comments: '') end before do @@ -127,27 +127,27 @@ it { expect(entry.user_id).to eq(deleted_user.id) } end - shared_examples_for "member handling" do + shared_examples_for 'member handling' do before do member job end - it "removes that member" do + it 'removes that member' do expect(Member.find_by(id: member.id)).to be_nil end - it "leaves the role" do + it 'leaves the role' do expect(Role.find_by(id: role.id)).to eq(role) end - it "leaves the project" do + it 'leaves the project' do expect(Project.find_by(id: project.id)).to eq(project) end end - shared_examples_for "work package member handling" do + shared_examples_for 'work package member handling' do let(:work_package) { create(:work_package, project:) } let(:work_package_member) do @@ -164,24 +164,24 @@ job end - it "removes that work package member" do + it 'removes that work package member' do expect(Member.find_by(id: work_package_member.id)).to be_nil end - it "leaves the role" do + it 'leaves the role' do expect(Role.find_by(id: role.id)).to eq(role) end - it "leaves the work_package" do + it 'leaves the work_package' do expect(WorkPackage.find_by(id: work_package.id)).to eq(work_package) end - it "leaves the project" do + it 'leaves the project' do expect(Project.find_by(id: project.id)).to eq(project) end end - shared_examples_for "hourly_rate handling" do + shared_examples_for 'hourly_rate handling' do let(:hourly_rate) do build(:hourly_rate, user: principal, @@ -197,7 +197,7 @@ it { expect(hourly_rate.reload.user_id).to eq(principal.id) } end - shared_examples_for "watcher handling" do + shared_examples_for 'watcher handling' do let(:watched) { create(:news, project:) } let(:watch) do Watcher.create(user: principal, @@ -214,9 +214,9 @@ it { expect(Watcher.find_by(id: watch.id)).to be_nil } end - shared_examples_for "rss token handling" do + shared_examples_for 'rss token handling' do let(:token) do - Token::RSS.new(user: principal, value: "loremipsum") + Token::RSS.new(user: principal, value: 'loremipsum') end before do @@ -228,7 +228,7 @@ it { expect(Token::RSS.find_by(id: token.id)).to be_nil } end - shared_examples_for "notification handling" do + shared_examples_for 'notification handling' do let(:notification) do create(:notification, recipient: principal) end @@ -242,7 +242,7 @@ it { expect(Notification.find_by(id: notification.id)).to be_nil } end - shared_examples_for "private query handling" do + shared_examples_for 'private query handling' do let!(:query) do create(:private_query, user: principal, views: create_list(:view_work_packages_table, 1)) end @@ -254,7 +254,7 @@ it { expect(Query.find_by(id: query.id)).to be_nil } end - shared_examples_for "backup token handling" do + shared_examples_for 'backup token handling' do let!(:backup_token) do create(:backup_token, user: principal) end @@ -270,7 +270,7 @@ it { expect(Token::Base.where(user_id: principal.id)).to be_empty } end - shared_examples_for "issue category handling" do + shared_examples_for 'issue category handling' do let(:category) do create(:category, assigned_to: principal, @@ -283,17 +283,17 @@ job end - it "does not remove the category" do + it 'does not remove the category' do expect(Category.find_by(id: category.id)).to eq(category) end - it "removes the assigned_to association to the principal" do + it 'removes the assigned_to association to the principal' do expect(category.reload.assigned_to).to be_nil end end - shared_examples_for "removes the principal" do - it "deletes the principal" do + shared_examples_for 'removes the principal' do + it 'deletes the principal' do job expect(Principal.find_by(id: principal.id)) @@ -301,27 +301,27 @@ end end - shared_examples_for "private cost_query handling" do + shared_examples_for 'private cost_query handling' do let!(:query) { create(:private_cost_query, user: principal) } - it "removes the query" do + it 'removes the query' do job expect(CostQuery.find_by(id: query.id)).to be_nil end end - shared_examples_for "project query handling" do + shared_examples_for 'project query handling' do let!(:query) { create(:project_query, user: principal) } - it "removes the query" do + it 'removes the query' do job expect(Queries::Projects::ProjectQuery.find_by(id: query.id)).to be_nil end end - shared_examples_for "public cost_query handling" do + shared_examples_for 'public cost_query handling' do let!(:query) { create(:public_cost_query, user: principal) } before do @@ -330,16 +330,16 @@ job end - it "leaves the query" do + it 'leaves the query' do expect(CostQuery.find_by(id: query.id)).to eq(query) end - it "rewrites the user reference" do + it 'rewrites the user reference' do expect(query.reload.user).to eq(deleted_user) end end - shared_examples_for "cost_query handling" do + shared_examples_for 'cost_query handling' do let(:query) { create(:cost_query) } let(:other_user) { create(:user) } @@ -354,7 +354,7 @@ job end - it "removes the filter" do + it 'removes the filter' do expect(CostQuery.find_by(id: query.id).deserialize.filters) .not_to(be_any { |f| f.is_a?(filter) }) end @@ -368,12 +368,12 @@ job end - it "keeps the filter" do + it 'keeps the filter' do expect(CostQuery.find_by(id: query.id).deserialize.filters) .to(be_any { |f| f.is_a?(filter) }) end - it "does not alter the filter values" do + it 'does not alter the filter values' do expect(CostQuery.find_by(id: query.id).deserialize.filters.detect do |f| f.is_a?(filter) end.values).to eq([other_user.id.to_s]) @@ -388,12 +388,12 @@ job end - it "keeps the filter" do + it 'keeps the filter' do expect(CostQuery.find_by(id: query.id).deserialize.filters) .to(be_any { |f| f.is_a?(filter) }) end - it "removes only the deleted user" do + it 'removes only the deleted user' do expect(CostQuery.find_by(id: query.id).deserialize.filters.detect do |f| f.is_a?(filter) end.values).to eq([other_user.id.to_s]) @@ -426,7 +426,7 @@ end end - shared_examples_for "mention rewriting" do + shared_examples_for 'mention rewriting' do let(:text) do <<~TEXT