diff --git a/.circleci/config.yml b/.circleci/config.yml index 15c40dc77..459faf1c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,84 +1,87 @@ -# Ruby CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-ruby/ for more details -# -version: 2 +version: 2.1 +orbs: + node: circleci/node@6.1.0 + defaults: &defaults working_directory: ~/build - docker: - # specify the version you desire here - - image: cimg/ruby:3.3.3-browsers - - # Specify service dependencies here if necessary - # CircleCI maintains a library of pre-built images - # documented at https://circleci.com/docs/2.0/circleci-images/ - - image: cimg/postgres:15.3 - - image: cimg/redis:6.2.6 - environment: - - RAILS_LOG_TO_STDOUT: false - - COVERAGE: true - - LOG_LEVEL: warn - parallelism: 4 + machine: + image: ubuntu-2204:2024.05.1 resource_class: large + environment: + RAILS_LOG_TO_STDOUT: false + COVERAGE: true + LOG_LEVEL: warn + parallelism: 4 jobs: build: <<: *defaults steps: - checkout + - node/install: + node-version: '20.12' + - node/install-pnpm + - node/install-packages: + pkg-manager: pnpm + override-ci-command: pnpm i + - run: node --version + - run: pnpm --version - run: - name: Configure Bundler + name: Install System Dependencies command: | - echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV - source $BASH_ENV + sudo apt-get update + DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \ + libpq-dev \ + redis-server \ + postgresql \ + build-essential \ + git \ + curl \ + libssl-dev \ + zlib1g-dev \ + libreadline-dev \ + libyaml-dev \ + openjdk-11-jdk \ + jq \ + software-properties-common \ + ca-certificates \ + imagemagick \ + libxml2-dev \ + libxslt1-dev \ + file \ + g++ \ + gcc \ + autoconf \ + gnupg2 \ + patch \ + ruby-dev \ + liblzma-dev \ + libgmp-dev \ + libncurses5-dev \ + libffi-dev \ + libgdbm6 \ + libgdbm-dev \ + libvips + + - run: + name: Install RVM and Ruby 3.3.3 + command: | + sudo apt-get install -y gpg + gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB + \curl -sSL https://get.rvm.io | bash -s stable + echo 'source ~/.rvm/scripts/rvm' >> $BASH_ENV + source ~/.rvm/scripts/rvm + rvm install "3.3.3" + rvm use 3.3.3 --default gem install bundler - run: - name: Which bundler? - command: bundle -v - - - run: - name: Swap node versions + name: Install Application Dependencies command: | - set +e - wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash - export NVM_DIR="$HOME/.nvm" - [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" - nvm install v20 - echo 'export NVM_DIR="$HOME/.nvm"' >> $BASH_ENV - echo '[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV - - # Run bundler - # Load installed gems from cache if possible, bundle install then save cache - # Multiple caches are used to increase the chance of a cache hit - - - restore_cache: - keys: - - chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-v20220524-{{ checksum "Gemfile.lock" }} - - - run: bundle install --frozen --path ~/.bundle - - save_cache: - paths: - - ~/.bundle - key: chatwoot-bundle-{{ .Environment.CACHE_VERSION }}-v20220524-{{ checksum "Gemfile.lock" }} - - # Only necessary if app uses webpacker or yarn in some other way - - restore_cache: - keys: - - chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - - chatwoot-yarn- - - - run: - name: yarn - command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn - - # Store yarn / webpacker cache - - save_cache: - key: chatwoot-yarn-{{ .Environment.CACHE_VERSION }}-{{ checksum "yarn.lock" }} - paths: - - ~/.cache/yarn + source ~/.rvm/scripts/rvm + bundle install + # pnpm install - run: name: Download cc-test-reporter @@ -86,12 +89,8 @@ jobs: mkdir -p ~/tmp curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter chmod +x ~/tmp/cc-test-reporter - - persist_to_workspace: - root: ~/tmp - paths: - - cc-test-reporter - # verify swagger specification + # Swagger verification - run: name: Verify swagger API specification command: | @@ -104,45 +103,62 @@ jobs: curl -L https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.3.0/openapi-generator-cli-6.3.0.jar > ~/tmp/openapi-generator-cli-6.3.0.jar java -jar ~/tmp/openapi-generator-cli-6.3.0.jar validate -i swagger/swagger.json - # Database setup - - run: bundle exec rake db:create - - run: bundle exec rake db:schema:load + # we remove the FRONTED_URL from the .env before running the tests + - run: + name: Database Setup and Configure Environment Variables + command: | + pg_pass=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 15 ; echo '') + sed -i "s/REPLACE_WITH_PASSWORD/${pg_pass}/g" ${PWD}/.circleci/setup_chatwoot.sql + chmod 644 ${PWD}/.circleci/setup_chatwoot.sql + mv ${PWD}/.circleci/setup_chatwoot.sql /tmp/ + sudo -i -u postgres psql -f /tmp/setup_chatwoot.sql + cp .env.example .env + sed -i '/^FRONTEND_URL/d' .env + sed -i -e '/REDIS_URL/ s/=.*/=redis:\/\/localhost:6379/' .env + sed -i -e '/POSTGRES_HOST/ s/=.*/=localhost/' .env + sed -i -e '/POSTGRES_USERNAME/ s/=.*/=chatwoot/' .env + sed -i -e "/POSTGRES_PASSWORD/ s/=.*/=$pg_pass/" .env + echo -en "\nINSTALLATION_ENV=circleci" >> ".env" + # Database setup + - run: + name: Run DB migrations + command: bundle exec rails db:chatwoot_prepare + + # Bundle audit - run: name: Bundle audit command: bundle exec bundle audit update && bundle exec bundle audit check -v + # Rubocop linting - run: name: Rubocop command: bundle exec rubocop - # - run: - # name: Brakeman - # command: bundle exec brakeman - + # ESLint linting - run: name: eslint - command: yarn run eslint + command: pnpm run eslint - # Run frontend tests - run: name: Run frontend tests command: | - mkdir -p ~/tmp/test-results/frontend_specs + mkdir -p ~/build/coverage/frontend ~/tmp/cc-test-reporter before-build - yarn test:coverage - - run: - name: Code Climate Test Coverage - command: | - ~/tmp/cc-test-reporter format-coverage -t lcov -o "coverage/codeclimate.frontend_$CIRCLE_NODE_INDEX.json" + pnpm run test:coverage - # Run rails tests + - run: + name: Code Climate Test Coverage (Frontend) + command: | + ~/tmp/cc-test-reporter format-coverage -t lcov -o "~/build/coverage/frontend/codeclimate.frontend_$CIRCLE_NODE_INDEX.json" + + # Run backend tests - run: name: Run backend tests command: | mkdir -p ~/tmp/test-results/rspec mkdir -p ~/tmp/test-artifacts - mkdir -p coverage + mkdir -p ~/build/coverage/backend ~/tmp/cc-test-reporter before-build TESTFILES=$(circleci tests glob "spec/**/*_spec.rb" | circleci tests split --split-by=timings) bundle exec rspec --format progress \ @@ -150,54 +166,18 @@ jobs: --out ~/tmp/test-results/rspec.xml \ -- ${TESTFILES} no_output_timeout: 30m + - run: - name: Code Climate Test Coverage + name: Code Climate Test Coverage (Backend) command: | - ~/tmp/cc-test-reporter format-coverage -t simplecov -o "coverage/codeclimate.$CIRCLE_NODE_INDEX.json" + ~/tmp/cc-test-reporter format-coverage -t simplecov -o "~/build/coverage/backend/codeclimate.$CIRCLE_NODE_INDEX.json" + + - run: + name: List coverage directory contents + command: | + ls -R ~/build/coverage - persist_to_workspace: - root: coverage + root: ~/build paths: - - codeclimate.*.json - # collect reports - - store_test_results: - path: ~/tmp/test-results - - store_artifacts: - path: ~/tmp/test-artifacts - - store_artifacts: - path: log - - upload-coverage: - working_directory: ~/build - docker: - # specify the version you desire here - - image: circleci/ruby:3.0.2-node-browsers - environment: - - CC_TEST_REPORTER_ID: caf26a895e937974a90860cfadfded20891cfd1373a5aaafb3f67406ab9d433f - steps: - - attach_workspace: - at: ~/build - - run: - name: Download cc-test-reporter - command: | - mkdir -p ~/tmp - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ~/tmp/cc-test-reporter - chmod +x ~/tmp/cc-test-reporter - - persist_to_workspace: - root: ~/tmp - paths: - - cc-test-reporter - - run: - name: Upload coverage results to Code Climate - command: | - ~/tmp/cc-test-reporter sum-coverage --output - codeclimate.*.json | ~/tmp/cc-test-reporter upload-coverage --debug --input - - -workflows: - version: 2 - - commit: - jobs: - - build - - upload-coverage: - requires: - - build + - coverage diff --git a/.circleci/setup_chatwoot.sql b/.circleci/setup_chatwoot.sql new file mode 100644 index 000000000..4e5430f1d --- /dev/null +++ b/.circleci/setup_chatwoot.sql @@ -0,0 +1,11 @@ +CREATE USER chatwoot CREATEDB; +ALTER USER chatwoot PASSWORD 'REPLACE_WITH_PASSWORD'; +ALTER ROLE chatwoot SUPERUSER; + +UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1'; +DROP DATABASE template1; +CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UNICODE'; +UPDATE pg_database SET datistemplate = TRUE WHERE datname = 'template1'; + +\c template1; +VACUUM FREEZE; diff --git a/.codeclimate.yml b/.codeclimate.yml index d8b8d985b..5e16262da 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -27,7 +27,8 @@ checks: threshold: 50 exclude_patterns: - 'spec/' - - '**/specs/' + - '**/specs/**/**' + - '**/spec/**/**' - 'db/*' - 'bin/**/*' - 'db/**/*' diff --git a/.eslintrc.js b/.eslintrc.js index cf4d1e7e1..a229133a2 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,6 +1,23 @@ module.exports = { - extends: ['airbnb-base/legacy', 'prettier', 'plugin:vue/vue3-recommended'], + extends: [ + 'airbnb-base/legacy', + 'prettier', + 'plugin:vue/vue3-recommended', + 'plugin:vitest-globals/recommended', + ], + overrides: [ + { + files: ['**/*.spec.{j,t}s?(x)'], + env: { + 'vitest-globals/env': true, + }, + }, + ], plugins: ['html', 'prettier'], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, rules: { 'prettier/prettier': ['error'], camelcase: 'off', @@ -206,5 +223,11 @@ module.exports = { globals: { bus: true, vi: true, + // beforeEach: true, + // afterEach: true, + // test: true, + // describe: true, + // it: true, + // expect: true, }, }; diff --git a/.github/workflows/frontend-fe.yml b/.github/workflows/frontend-fe.yml new file mode 100644 index 000000000..15bb6f5e9 --- /dev/null +++ b/.github/workflows/frontend-fe.yml @@ -0,0 +1,43 @@ +name: Frontend Lint & Test + +on: + push: + branches: + - develop + pull_request: + branches: + - develop + +jobs: + test: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + + - uses: pnpm/action-setup@v4 + with: + version: 9.3.0 + + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: Install pnpm dependencies + run: pnpm install --frozen-lockfile + + - name: Run eslint + run: pnpm run eslint + + - name: Run frontend tests with coverage + run: | + mkdir -p coverage + pnpm run test:coverage diff --git a/.github/workflows/run_foss_spec.yml b/.github/workflows/run_foss_spec.yml index 9382ccbf6..6a018b314 100644 --- a/.github/workflows/run_foss_spec.yml +++ b/.github/workflows/run_foss_spec.yml @@ -21,7 +21,7 @@ jobs: image: postgres:15.3 env: POSTGRES_USER: postgres - POSTGRES_PASSWORD: "" + POSTGRES_PASSWORD: '' POSTGRES_DB: postgres POSTGRES_HOST_AUTH_METHOD: trust ports: @@ -41,46 +41,49 @@ jobs: options: --entrypoint redis-server steps: - - uses: actions/checkout@v4 - - uses: pnpm/action-setup@v4 - with: - version: 9 - ref: ${{ github.event.pull_request.head.ref }} - repository: ${{ github.event.pull_request.head.repo.full_name }} + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 9 + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} - - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true # runs 'bundle install' and caches installed gems automatically + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true # runs 'bundle install' and caches installed gems automatically - - uses: actions/setup-node@v4 - with: - node-version: 20 - cache: 'pnpm' + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' - - name: Install pnpm dependencies - run: pnpm i + - name: Install pnpm dependencies + run: pnpm i - - name: Strip enterprise code - run: | - rm -rf enterprise - rm -rf spec/enterprise + - name: Strip enterprise code + run: | + rm -rf enterprise + rm -rf spec/enterprise - - name: Create database - run: bundle exec rake db:create + - name: Create database + run: bundle exec rake db:create - - name: Seed database - run: bundle exec rake db:schema:load + - name: Seed database + run: bundle exec rake db:schema:load - # Run rails tests - - name: Run backend tests - run: | - bundle exec rspec --profile=10 --format documentation - env: - NODE_OPTIONS: --openssl-legacy-provider + - name: Run frontend tests + run: pnpm run test:coverage - - name: Upload rails log folder - uses: actions/upload-artifact@v4 - if: always() - with: - name: rails-log-folder - path: log + # Run rails tests + - name: Run backend tests + run: | + bundle exec rspec --profile=10 --format documentation + env: + NODE_OPTIONS: --openssl-legacy-provider + + - name: Upload rails log folder + uses: actions/upload-artifact@v4 + if: always() + with: + name: rails-log-folder + path: log diff --git a/app/javascript/dashboard/components/ModalHeader.vue b/app/javascript/dashboard/components/ModalHeader.vue index 63d361278..9e2330aa4 100644 --- a/app/javascript/dashboard/components/ModalHeader.vue +++ b/app/javascript/dashboard/components/ModalHeader.vue @@ -27,14 +27,14 @@ export default {
No image

{{ headerTitle }}

{{ headerContent }} diff --git a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue index 4fce895b2..8bce09250 100644 --- a/app/javascript/dashboard/components/layout/AvailabilityStatus.vue +++ b/app/javascript/dashboard/components/layout/AvailabilityStatus.vue @@ -105,7 +105,7 @@ export default { size="small" :color-scheme="status.disabled ? '' : 'secondary'" :variant="status.disabled ? 'smooth' : 'clear'" - class-names="status-change--dropdown-button" + class="status-change--dropdown-button" @click="changeAvailabilityStatus(status.value)" > diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js b/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js index fb76e0ff4..1af49195f 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js +++ b/app/javascript/dashboard/components/layout/sidebarComponents/specs/AccountSelector.spec.js @@ -1,79 +1,62 @@ +import { mount } from '@vue/test-utils'; +import { createStore } from 'vuex'; import AccountSelector from '../AccountSelector.vue'; -import { createLocalVue, mount } from '@vue/test-utils'; -import Vuex from 'vuex'; -import VueI18n from 'vue-i18n'; - -import i18n from 'dashboard/i18n'; import WootModal from 'dashboard/components/Modal.vue'; import WootModalHeader from 'dashboard/components/ModalHeader.vue'; import FluentIcon from 'shared/components/FluentIcon/DashboardIcon.vue'; -const localVue = createLocalVue(); -localVue.component('woot-modal', WootModal); -localVue.component('woot-modal-header', WootModalHeader); -localVue.component('fluent-icon', FluentIcon); - -localVue.use(Vuex); -localVue.use(VueI18n); - -const i18nConfig = new VueI18n({ - locale: 'en', - messages: i18n, +const store = createStore({ + modules: { + auth: { + namespaced: false, + getters: { + getCurrentAccountId: () => 1, + getCurrentUser: () => ({ + accounts: [ + { id: 1, name: 'Chatwoot', role: 'administrator' }, + { id: 2, name: 'GitX', role: 'agent' }, + ], + }), + }, + }, + globalConfig: { + namespaced: true, + getters: { + get: () => ({ createNewAccountFromDashboard: false }), + }, + }, + }, }); -describe('accountSelctor', () => { +describe('AccountSelector', () => { let accountSelector = null; - const currentUser = { - accounts: [ - { - id: 1, - name: 'Chatwoot', - role: 'administrator', - }, - { - id: 2, - name: 'GitX', - role: 'agent', - }, - ], - }; - - let actions = null; - let modules = null; beforeEach(() => { - actions = {}; - modules = { - auth: { - getters: { - getCurrentAccountId: () => 1, - getCurrentUser: () => currentUser, - }, - }, - globalConfig: { - getters: { - 'globalConfig/get': () => ({ createNewAccountFromDashboard: false }), - }, - }, - }; - - let store = new Vuex.Store({ actions, modules }); accountSelector = mount(AccountSelector, { - store, - localVue, - i18n: i18nConfig, - propsData: { showAccountModal: true }, - stubs: { WootButton: { template: '' } }, + }, }); }); - it(' the agent status', () => { - expect(agentDetails.find('thumbnail-stub').vm.status).toBe('online'); + it('shows the correct agent status', () => { + expect(agentDetails.findComponent(Thumbnail).vm.status).toBe('online'); }); it('agent thumbnail exists', () => { diff --git a/app/javascript/dashboard/components/layout/sidebarComponents/specs/NotificationBell.spec.js b/app/javascript/dashboard/components/layout/sidebarComponents/specs/NotificationBell.spec.js index 85596bb3e..607604d48 100644 --- a/app/javascript/dashboard/components/layout/sidebarComponents/specs/NotificationBell.spec.js +++ b/app/javascript/dashboard/components/layout/sidebarComponents/specs/NotificationBell.spec.js @@ -1,20 +1,7 @@ -import NotificationBell from '../NotificationBell.vue'; -import { createLocalVue, shallowMount } from '@vue/test-utils'; -import Vuex from 'vuex'; -import VueI18n from 'vue-i18n'; +import { shallowMount } from '@vue/test-utils'; +import { createStore } from 'vuex'; import FluentIcon from 'shared/components/FluentIcon/DashboardIcon.vue'; - -import i18n from 'dashboard/i18n'; - -const localVue = createLocalVue(); -localVue.use(Vuex); -localVue.use(VueI18n); -localVue.component('fluent-icon', FluentIcon); - -const i18nConfig = new VueI18n({ - locale: 'en', - messages: i18n, -}); +import NotificationBell from '../NotificationBell.vue'; const $route = { name: 'notifications_index', @@ -33,43 +20,51 @@ describe('notificationBell', () => { }; modules = { auth: { + namespaced: false, getters: { getCurrentAccountId: () => accountId, }, }, notifications: { + namespaced: false, getters: { 'notifications/getMeta': () => notificationMetadata, }, }, }; - store = new Vuex.Store({ + store = createStore({ actions, modules, }); }); - it('it should return unread count 19 ', () => { + it('it should return unread count 19', () => { const wrapper = shallowMount(NotificationBell, { - localVue, - i18n: i18nConfig, - store, - mocks: { - $route, + global: { + plugins: [store], + mocks: { + $route, + }, + components: { + 'fluent-icon': FluentIcon, + }, }, }); expect(wrapper.vm.unreadCount).toBe('19'); }); - it('it should return unread count 99+ ', async () => { + it('it should return unread count 99+', async () => { notificationMetadata.unreadCount = 100; const wrapper = shallowMount(NotificationBell, { - localVue, - i18n: i18nConfig, - store, - mocks: { - $route, + global: { + plugins: [store], + mocks: { + $route, + }, + components: { + 'fluent-icon': FluentIcon, + }, }, }); expect(wrapper.vm.unreadCount).toBe('99+'); @@ -77,11 +72,14 @@ describe('notificationBell', () => { it('isNotificationPanelActive', async () => { const notificationBell = shallowMount(NotificationBell, { - store, - localVue, - i18n: i18nConfig, - mocks: { - $route, + global: { + plugins: [store], + mocks: { + $route, + }, + components: { + 'fluent-icon': FluentIcon, + }, }, }); diff --git a/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js b/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js index c70cffa13..2a9dbaba0 100644 --- a/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js +++ b/app/javascript/dashboard/components/layout/specs/AvailabilityStatus.spec.js @@ -1,9 +1,6 @@ +import { mount } from '@vue/test-utils'; +import { createStore } from 'vuex'; import AvailabilityStatus from '../AvailabilityStatus.vue'; -import { createLocalVue, mount } from '@vue/test-utils'; -import Vuex from 'vuex'; -import VueI18n from 'vue-i18n'; -import FloatingVue from 'floating-vue'; - import WootButton from 'dashboard/components/ui/WootButton.vue'; import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue'; import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue'; @@ -11,70 +8,64 @@ import WootDropdownHeader from 'shared/components/ui/dropdown/DropdownHeader.vue import WootDropdownDivider from 'shared/components/ui/dropdown/DropdownDivider.vue'; import FluentIcon from 'shared/components/FluentIcon/DashboardIcon.vue'; -import i18n from 'dashboard/i18n'; - -const localVue = createLocalVue(); -localVue.use(FloatingVue, { - html: false, -}); -localVue.use(Vuex); -localVue.use(VueI18n); -localVue.component('woot-button', WootButton); -localVue.component('woot-dropdown-header', WootDropdownHeader); -localVue.component('woot-dropdown-menu', WootDropdownMenu); -localVue.component('woot-dropdown-divider', WootDropdownDivider); -localVue.component('woot-dropdown-item', WootDropdownItem); -localVue.component('fluent-icon', FluentIcon); - -const i18nConfig = new VueI18n({ locale: 'en', messages: i18n }); - describe('AvailabilityStatus', () => { const currentAvailability = 'online'; const currentAccountId = '1'; const currentUserAutoOffline = false; let store = null; let actions = null; - let modules = null; - let availabilityStatus = null; beforeEach(() => { actions = { - updateAvailability: vi.fn(() => { - return Promise.resolve(); - }), + updateAvailability: vi.fn(() => Promise.resolve()), }; - modules = { - auth: { - getters: { - getCurrentUserAvailability: () => currentAvailability, - getCurrentAccountId: () => currentAccountId, - getCurrentUserAutoOffline: () => currentUserAutoOffline, + store = createStore({ + modules: { + auth: { + namespaced: false, + getters: { + getCurrentUserAvailability: () => currentAvailability, + getCurrentAccountId: () => currentAccountId, + getCurrentUserAutoOffline: () => currentUserAutoOffline, + }, }, }, - }; - - store = new Vuex.Store({ actions, modules }); - - availabilityStatus = mount(AvailabilityStatus, { - store, - localVue, - i18n: i18nConfig, - stubs: { WootSwitch: { template: ' `; diff --git a/app/javascript/dashboard/components/widgets/WootWriter/utils/mp3ConversionUtils.js b/app/javascript/dashboard/components/widgets/WootWriter/utils/mp3ConversionUtils.js index 373d9dfd2..3ae37911d 100644 --- a/app/javascript/dashboard/components/widgets/WootWriter/utils/mp3ConversionUtils.js +++ b/app/javascript/dashboard/components/widgets/WootWriter/utils/mp3ConversionUtils.js @@ -1,6 +1,7 @@ import lamejs from '@breezystack/lamejs'; const writeString = (view, offset, string) => { + // eslint-disable-next-line no-plusplus for (let i = 0; i < string.length; i++) { view.setUint8(offset + i, string.charCodeAt(i)); } @@ -28,7 +29,9 @@ const bufferToWav = async (buffer, numChannels, sampleRate) => { // WAV Data const offset = 44; + // eslint-disable-next-line no-plusplus for (let i = 0; i < buffer.length; i++) { + // eslint-disable-next-line no-plusplus for (let channel = 0; channel < numChannels; channel++) { const sample = Math.max( -1, diff --git a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue index f4eeedc32..0b19ea2bf 100644 --- a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue +++ b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue @@ -478,6 +478,7 @@ export default {