Compare commits

..

21 Commits

Author SHA1 Message Date
Joel Jeremy Marquez
1877286702 yarn install 2024-01-24 13:01:36 -08:00
Joel Jeremy Marquez
ab2857521f Fix lint errors 2024-01-24 13:00:34 -08:00
Joel Jeremy Marquez
ae43ed86ea Cleanup 2024-01-24 13:00:34 -08:00
Joel Jeremy Marquez
2aa94b5d89 Sortable mobile accounts 2024-01-24 13:00:34 -08:00
Joel Jeremy Marquez
140f564e2e Delay uncollapsed when sorting groups 2024-01-24 13:00:34 -08:00
Joel Jeremy Marquez
59168a284e Fix lint 2024-01-24 13:00:34 -08:00
Joel Jeremy Marquez
61a65895cb Remove Group: text when sorting groups + use onDragOver 2024-01-24 13:00:34 -08:00
Joel Jeremy Marquez
779f2a5c13 Restrict drag to parent element 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
def0aed7c6 Fix accounts sorting 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
8d8cd631b5 Check for null over 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
ed53972817 Revert ROW_HEIGHT 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
04e761e08a Fix lint error 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
811f9e4300 Release notes 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
fae68c19f5 Fix sort bug 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
96a9966d6b Fix types 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
ca88608218 Remove react-dnd 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
30a7701bdb Fix typecheck error 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
c438a60fd7 Budget drag and drop 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
72d491963f Use dnd-kit touch and mouse sensors 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
f46d87fd2d Add touch-action 2024-01-24 12:59:54 -08:00
Joel Jeremy Marquez
675918edea dnd-kit POC 2024-01-24 12:59:54 -08:00
773 changed files with 23222 additions and 33133 deletions

View File

@@ -38,7 +38,6 @@ module.exports = {
extends: [
'react-app',
'plugin:react/recommended',
'plugin:react/jsx-runtime',
'plugin:prettier/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/typescript',
@@ -58,7 +57,7 @@ module.exports = {
'@typescript-eslint/no-unused-vars': [
'warn',
{
varsIgnorePattern: '^(_|React)',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
@@ -91,7 +90,15 @@ module.exports = {
'react/prop-types': 'off',
// TODO: re-enable these rules
'react-hooks/exhaustive-deps': 'off',
'react/display-name': 'off',
'react/react-in-jsx-scope': 'off',
// 'react-hooks/exhaustive-deps': [
// 'warn',
// {
// additionalHooks: 'useLiveQuery',
// },
// ],
'no-var': 'warn',
'react/jsx-curly-brace-presence': 'warn',
@@ -146,9 +153,10 @@ module.exports = {
'Using default React import is discouraged, please use named exports directly instead.',
},
{
// forbid <a> in favor of <Link>
// forbid <a> in favor of <LinkButton> or <ExternalLink>
selector: 'JSXOpeningElement[name.name="a"]',
message: 'Using <a> is discouraged, please use <Link> instead.',
message:
'Using <a> is discouraged, please use <LinkButton> or <ExternalLink> instead.',
},
],
'no-restricted-imports': [
@@ -269,69 +277,6 @@ module.exports = {
'import/no-default-export': 'off',
},
},
{
// TODO: fix the issues in these files
files: [
'./packages/desktop-client/src/components/accounts/Account.jsx',
'./packages/desktop-client/src/components/accounts/MobileAccount.jsx',
'./packages/desktop-client/src/components/accounts/MobileAccounts.jsx',
'./packages/desktop-client/src/components/App.tsx',
'./packages/desktop-client/src/components/budget/BudgetCategories.jsx',
'./packages/desktop-client/src/components/budget/BudgetSummaries.tsx',
'./packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx',
'./packages/desktop-client/src/components/budget/index.tsx',
'./packages/desktop-client/src/components/budget/MobileBudget.tsx',
'./packages/desktop-client/src/components/budget/rollover/HoldMenu.tsx',
'./packages/desktop-client/src/components/budget/rollover/TransferMenu.tsx',
'./packages/desktop-client/src/components/common/Menu.tsx',
'./packages/desktop-client/src/components/FinancesApp.tsx',
'./packages/desktop-client/src/components/GlobalKeys.ts',
'./packages/desktop-client/src/components/LoggedInUser.tsx',
'./packages/desktop-client/src/components/manager/ManagementApp.jsx',
'./packages/desktop-client/src/components/manager/subscribe/common.tsx',
'./packages/desktop-client/src/components/ManageRules.tsx',
'./packages/desktop-client/src/components/mobile/MobileAmountInput.jsx',
'./packages/desktop-client/src/components/mobile/MobileNavTabs.tsx',
'./packages/desktop-client/src/components/Modals.tsx',
'./packages/desktop-client/src/components/modals/EditRule.jsx',
'./packages/desktop-client/src/components/modals/ImportTransactions.jsx',
'./packages/desktop-client/src/components/modals/MergeUnusedPayees.jsx',
'./packages/desktop-client/src/components/Notifications.tsx',
'./packages/desktop-client/src/components/payees/ManagePayees.jsx',
'./packages/desktop-client/src/components/payees/ManagePayeesWithData.jsx',
'./packages/desktop-client/src/components/payees/PayeeTable.tsx',
'./packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTable.tsx',
'./packages/desktop-client/src/components/reports/graphs/tableGraph/ReportTableTotals.tsx',
'./packages/desktop-client/src/components/reports/reports/CashFlowCard.jsx',
'./packages/desktop-client/src/components/reports/reports/CustomReport.jsx',
'./packages/desktop-client/src/components/reports/reports/NetWorthCard.jsx',
'./packages/desktop-client/src/components/reports/SaveReportName.tsx',
'./packages/desktop-client/src/components/reports/useReport.ts',
'./packages/desktop-client/src/components/schedules/ScheduleDetails.jsx',
'./packages/desktop-client/src/components/schedules/SchedulesTable.tsx',
'./packages/desktop-client/src/components/select/DateSelect.tsx',
'./packages/desktop-client/src/components/sidebar/Tools.tsx',
'./packages/desktop-client/src/components/sort.tsx',
'./packages/desktop-client/src/components/spreadsheet/useSheetValue.ts',
'./packages/desktop-client/src/components/table.tsx',
'./packages/desktop-client/src/components/Titlebar.tsx',
'./packages/desktop-client/src/components/transactions/MobileTransaction.jsx',
'./packages/desktop-client/src/components/transactions/SelectedTransactions.jsx',
'./packages/desktop-client/src/components/transactions/SimpleTransactionsTable.jsx',
'./packages/desktop-client/src/components/transactions/TransactionList.jsx',
'./packages/desktop-client/src/components/transactions/TransactionsTable.jsx',
'./packages/desktop-client/src/components/transactions/TransactionsTable.test.jsx',
'./packages/desktop-client/src/hooks/useAccounts.ts',
'./packages/desktop-client/src/hooks/useCategories.ts',
'./packages/desktop-client/src/hooks/usePayees.ts',
'./packages/desktop-client/src/hooks/useProperFocus.tsx',
'./packages/desktop-client/src/hooks/useSelected.tsx',
'./packages/loot-core/src/client/query-hooks.tsx',
],
rules: {
'react-hooks/exhaustive-deps': 'off',
},
},
],
settings: {
'import/resolver': {

View File

@@ -8,13 +8,6 @@ body:
attributes:
value: |
Thanks for taking the time to fill out this bug report! Please ensure you provide as much information as possible to better assist in confirming and identifying a fix for the bug.
- type: markdown
id: intro-md
attributes:
value: |
**IMPORTANT:** we use Github Issues only for BUG REPORTS and FEATURE REQUESTS. If you are looking for help/support - please reach out to the [community on Discord](https://discord.gg/pRYNYr4W5A). All non-bug and non-feature-request issues will be closed.
**Bank-sync problems (SimpleFin / GoCardless)?** Reach out via the [community Discord](https://discord.gg/pRYNYr4W5A) first and open an issue only if the community deems the issue to be a legitimate bug in Actual.
- type: checkboxes
id: existing-issue
attributes:
@@ -23,10 +16,20 @@ body:
options:
- label: 'I have searched and found no existing issue'
required: true
- label: 'I will be providing steps how to reproduce the bug (in most cases this will also mean uploading a demo budget file)'
required: true
validations:
required: true
- type: checkboxes
id: bank-sync-issue
attributes:
label: 'Is this related to GoCardless, Simplefin or another bank-sync provider?'
description: 'Most issues with bank-sync providers are due to a lack of a custom bank-mapper (i.e. payee or other fields not coming through). In such cases you can create a custom bank mapper in [actual-server](https://github.com/actualbudget/actual-server/blob/master/src/app-gocardless/README.md) repository. Other likely issue is misconfigured server - in which case please reach out via the [community Discord](https://discord.gg/pRYNYr4W5A) to get support.'
options:
- label: 'I have checked my server logs and could not see any errors there'
- label: 'I will be attaching my server logs to this issue'
- label: 'I will be attaching my client-side (browser) logs to this issue'
- label: 'I understand that this issue will be automatically closed if insufficient information is provided'
validations:
required: false
- type: textarea
id: what-happened
attributes:
@@ -36,6 +39,13 @@ body:
value: 'A bug happened!'
validations:
required: true
- type: textarea
id: errors-received
attributes:
label: 'What error did you receive?'
description: 'If you received an error or a message on the screen, please provide that here.'
validations:
required: false
- type: markdown
id: env-info
attributes:
@@ -49,7 +59,6 @@ body:
- Locally via Yarn
- Docker
- Fly.io
- Pikapods
- NAS
- Desktop App (Electron)
- Other

View File

@@ -1,8 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Bank-sync issues
url: https://discord.gg/pRYNYr4W5A
about: Is bank-sync not working? Returning too much or too few information? Reach out to the community on Discord.
- name: Support
url: https://discord.gg/pRYNYr4W5A
about: Need help with something? Having troubles setting up? Or perhaps issues using the API? Reach out to the community on Discord.
about: Need help with something? Perhaps having issues setting up bank-sync with GoCardless or SimpleFin? Reach out to the community on Discord.

View File

@@ -4,11 +4,11 @@ runs:
using: composite
steps:
- name: Install node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18.16.0
- name: Cache
uses: actions/cache@v4
uses: actions/cache@v3
id: cache
with:
path: '**/node_modules'

View File

@@ -21,7 +21,7 @@ jobs:
api:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Build API
@@ -29,7 +29,7 @@ jobs:
- name: Create package tgz
run: cd packages/api && yarn pack && mv package.tgz actual-api.tgz
- name: Upload Build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: actual-api
path: packages/api/actual-api.tgz
@@ -37,7 +37,7 @@ jobs:
crdt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Build CRDT
@@ -45,7 +45,7 @@ jobs:
- name: Create package tgz
run: cd packages/crdt && yarn pack && mv package.tgz actual-crdt.tgz
- name: Upload Build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: actual-crdt
path: packages/crdt/actual-crdt.tgz
@@ -53,18 +53,18 @@ jobs:
web:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Build Web
run: ./bin/package-browser
- name: Upload Build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: actual-web
path: packages/desktop-client/build
- name: Upload Build Stats
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: build-stats
path: packages/desktop-client/build-stats

View File

@@ -14,7 +14,7 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Lint
@@ -22,7 +22,7 @@ jobs:
typecheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Typecheck
@@ -30,7 +30,7 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Test
@@ -40,8 +40,8 @@ jobs:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '19'
- name: Check migrations

View File

@@ -22,14 +22,14 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v2
with:
languages: javascript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v2
with:
category: '/language:javascript'

View File

@@ -16,7 +16,7 @@ jobs:
outputs:
netlify_url: ${{ steps.netlify.outputs.url }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Wait for Netlify build to finish
@@ -33,20 +33,19 @@ jobs:
container:
image: mcr.microsoft.com/playwright:v1.41.1-jammy
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Run E2E Tests on Netlify URL
run: yarn e2e
env:
E2E_START_URL: ${{ needs.netlify.outputs.netlify_url }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
if: always()
with:
name: desktop-client-test-results
path: packages/desktop-client/test-results/
retention-days: 30
overwrite: true
vrt:
name: Visual regression
needs: netlify
@@ -54,17 +53,16 @@ jobs:
container:
image: mcr.microsoft.com/playwright:v1.41.1-jammy
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Set up environment
uses: ./.github/actions/setup
- name: Run VRT Tests on Netlify URL
run: yarn vrt
env:
E2E_START_URL: ${{ needs.netlify.outputs.netlify_url }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v3
if: always()
with:
name: desktop-client-test-results
path: packages/desktop-client/test-results/
retention-days: 30
overwrite: true

View File

@@ -1,4 +1,4 @@
name: Electron Master
name: Electron
defaults:
run:
@@ -9,8 +9,8 @@ env:
on:
push:
tags:
- v**
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
@@ -18,9 +18,6 @@ concurrency:
jobs:
build:
# this is so the assets can be added to the release
permissions:
contents: write
strategy:
matrix:
os:
@@ -29,46 +26,25 @@ jobs:
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- if: ${{ startsWith(matrix.os, 'windows') }}
run: pip.exe install setuptools
- if: ${{ ! startsWith(matrix.os, 'windows') }}
run: |
mkdir .venv
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install setuptools
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: |
sudo apt-get install flatpak -y
sudo apt-get install flatpak-builder -y
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install org.freedesktop.Sdk/x86_64/23.08 -y
sudo flatpak install org.freedesktop.Platform/x86_64/23.08 -y
sudo flatpak install org.electronjs.Electron2.BaseApp/x86_64/23.08 -y
run: python3 -m pip install setuptools
- name: Set up environment
uses: ./.github/actions/setup
- name: Build Electron
run: ./bin/package-electron
env:
# CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
# CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.CSC_LINK }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
- name: Upload Build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: actual-electron-${{ matrix.os }}
path: |
packages/desktop-electron/dist/*.dmg
packages/desktop-electron/dist/*.exe
packages/desktop-electron/dist/*.AppImage
packages/desktop-electron/dist/*.flatpak
- name: Add to Release
uses: softprops/action-gh-release@v2
with:
files: |
packages/desktop-electron/dist/*.dmg
packages/desktop-electron/dist/*.exe
packages/desktop-electron/dist/*.AppImage
packages/desktop-electron/dist/*.flatpak

View File

@@ -24,33 +24,20 @@ jobs:
- macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- if: ${{ startsWith(matrix.os, 'windows') }}
run: pip.exe install setuptools
- if: ${{ ! startsWith(matrix.os, 'windows') }}
run: |
mkdir .venv
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install setuptools
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
run: |
sudo apt-get install flatpak -y
sudo apt-get install flatpak-builder -y
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
sudo flatpak install org.freedesktop.Sdk/x86_64/23.08 -y
sudo flatpak install org.freedesktop.Platform/x86_64/23.08 -y
sudo flatpak install org.electronjs.Electron2.BaseApp/x86_64/23.08 -y
run: python3 -m pip install setuptools
- name: Set up environment
uses: ./.github/actions/setup
- name: Build Electron
run: ./bin/package-electron
- name: Upload Build
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3
with:
name: actual-electron-${{ matrix.os }}
path: |
packages/desktop-electron/dist/*.dmg
packages/desktop-electron/dist/*.exe
packages/desktop-electron/dist/*.AppImage
packages/desktop-electron/dist/*.flatpak

View File

@@ -24,8 +24,8 @@ jobs:
runs-on: ubuntu-latest
steps:
# This is not a security concern because we have approved & merged the PR
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '19'
- name: Handle feature requests

View File

@@ -1,43 +0,0 @@
name: Deploy Netlify Release
defaults:
run:
shell: bash
env:
CI: true
on:
push:
tags:
- v**
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- name: Repository Checkout
uses: actions/checkout@v4
- name: Set up environment
uses: ./.github/actions/setup
- name: Install Netlify
run: npm install netlify-cli@17.10.1 -g
- name: Build Actual
run: ./bin/package-browser
- name: Deploy to Netlify
id: netlify_deploy
run: |
netlify deploy \
--dir packages/desktop-client/build \
--site ${{ secrets.NETLIFY_SITE_ID }} \
--auth ${{ secrets.NETLIFY_API_TOKEN }} \
--filter @actual-app/web \
--prod

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Check release notes
if: startsWith(github.head_ref, 'release/') == false
uses: actualbudget/actions/release-notes/check@main

View File

@@ -46,7 +46,7 @@ jobs:
echo "Build failed on PR branch or ${{github.base_ref}}"
exit 1
- name: Download build artifact from ${{github.base_ref}}
uses: dawidd6/action-download-artifact@v3
uses: dawidd6/action-download-artifact@v2
id: pr-build
with:
branch: ${{github.base_ref}}
@@ -55,7 +55,7 @@ jobs:
path: base
- name: Download build artifact from PR
uses: dawidd6/action-download-artifact@v3
uses: dawidd6/action-download-artifact@v2
with:
pr: ${{github.event.pull_request.number}}
workflow: build.yml

View File

@@ -1,39 +0,0 @@
##########################################################################################
# WARNING! This workflow uses the 'pull_request_target' event. That mans that it will #
# always run in the context of the main actualbudget/actual repo, even if the PR is from #
# a fork. This is necessary to get access to a GitHub token that can modify the PR. #
# Be VERY CAREFUL about adding things to this workflow, since forks can inject #
# arbitrary code into their branch, and can pollute the artifacts we download. Arbitrary #
# code execution in this workflow could lead to a compromise of the main repo. #
##########################################################################################
# See: https://securitylab.github.com/research/github-actions-preventing-pwn-requests #
##########################################################################################
name: Trafico Reviews
on:
pull_request_target:
types:
- opened
- closed
- reopened
- synchronize
- edited
- review_requested
- review_request_removed
pull_request_review:
types: [submitted, edited, dismissed]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
manage-review:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actualbudget/trafico@main
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,27 +0,0 @@
name: Add WIP
on:
pull_request_target:
types:
- opened
jobs:
add_wip_prefix:
if: |
join(github.event.pull_request.requested_reviewers) == ''
&& !contains(github.event.pull_request.title, 'WIP')
&& !contains(github.event.pull_request.labels.*.name, 'WIP')
&& github.event.pull_request.draft != true
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Add WIP
env:
TITLE: ${{ github.event.pull_request.title }}
shell: bash
run: |
echo ${{ secrets.GITHUB_TOKEN }} | gh auth login --with-token
gh pr edit ${{ github.event.pull_request.number }} -t "[WIP] ${TITLE}"

37
.gitignore vendored
View File

@@ -1,22 +1,6 @@
# Sample Data
/data/*
!data/.gitkeep
/data2
Actual-*
**/xcuserdata/*
export-2020-01-10.csv
# Secrets
.secret-tokens
# MacOS
.DS_Store
# Logs
**/*.log
# JavaScript
node_modules
packages/api/dist
packages/api/@types
packages/crdt/dist
@@ -24,10 +8,22 @@ packages/desktop-electron/client-build
packages/desktop-electron/.electron-symbols
packages/desktop-electron/dist
packages/desktop-electron/loot-core
node_modules
.DS_Store
lerna-debug.log
Actual-*
.#*
**/xcuserdata/*
.secret-tokens
bundle.desktop.js
bundle.desktop.js.map
bundle.mobile.js
bundle.mobile.js.map
export-2020-01-10.csv
.idea
.vscode
**/*.log
# Yarn
.pnp.*
@@ -40,12 +36,3 @@ bundle.mobile.js.map
# VSCode
.vscode
# IntelliJ IDEA
.idea
# Misc
.#*
# Local Netlify folder
.netlify

File diff suppressed because one or more lines are too long

View File

@@ -4,4 +4,4 @@ enableGlobalCache: false
nodeLinker: node-modules
yarnPath: .yarn/releases/yarn-4.0.2.cjs
yarnPath: .yarn/releases/yarn-4.0.1.cjs

View File

@@ -10,4 +10,4 @@ if [ ! -d "node_modules" ] || [ "$(ls -A node_modules)" = "" ]; then
yarn
fi
BROWSER=0 yarn start:browser
yarn start:browser

View File

@@ -38,7 +38,7 @@ yarn rebuild-electron
yarn workspace loot-core build:node
yarn workspace @actual-app/web build --mode=desktop
yarn workspace @actual-app/web build
yarn workspace desktop-electron update-client

View File

@@ -1,32 +0,0 @@
#!/bin/sh
# See here for more information: https://github.com/actualbudget/actual/tree/master/packages/desktop-client#visual-regression
if [ ! -d "node_modules" ] || [ "$(ls -A node_modules)" = "" ]; then
yarn
fi
E2E_START_URL="${E2E_START_URL:-https://localhost:3001}"
VRT_ARGS=""
# Loop through all arguments
while [ $# -gt 0 ]; do
key="$1"
case $key in
--e2e-start-url)
E2E_START_URL="$2"
shift
;;
*)
VRT_ARGS="$VRT_ARGS $1"
;;
esac
shift
done
echo "Running VRT tests with the following parameters:"
echo "E2E_START_URL: $E2E_START_URL"
echo "VRT_ARGS: $VRT_ARGS"
docker run --rm --network host -v "$(pwd)":/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.41.1-jammy /bin/bash \
-c "E2E_START_URL=$E2E_START_URL yarn vrt $VRT_ARGS"

View File

@@ -8,8 +8,6 @@ services:
actual-development:
build: .
image: actual-development
environment:
- HTTPS
ports:
- '3001:3001'
volumes:

View File

@@ -34,7 +34,6 @@
"test:debug": "yarn workspaces foreach --all --verbose run test",
"e2e": "yarn workspaces foreach --all --parallel --verbose run e2e",
"vrt": "yarn workspaces foreach --all --parallel --verbose run vrt",
"vrt:docker": "./bin/run-vrt",
"rebuild-electron": "./node_modules/.bin/electron-rebuild -f -m ./packages/loot-core",
"rebuild-node": "yarn workspace loot-core rebuild",
"lint": "eslint . --max-warnings 0 --ext .js,.jsx,.ts,.tsx",
@@ -53,19 +52,17 @@
"eslint-plugin-react": "7.32.2",
"eslint-plugin-rulesdir": "^0.2.2",
"node-jq": "^4.0.1",
"npm-run-all": "^4.1.5",
"npm-run-all": "^4.1.3",
"prettier": "3.2.4",
"react-refresh": "^0.14.0",
"source-map-support": "^0.5.21",
"typescript": "^5.0.2",
"typescript-strict-plugin": "^2.2.2-beta.2"
},
"resolutions": {
"rollup": "4.9.4"
},
"engines": {
"node": ">=18.0.0"
},
"packageManager": "yarn@4.0.2",
"packageManager": "yarn@4.0.1",
"browserslist": [
"electron 24.0",
"defaults"

View File

@@ -58,42 +58,11 @@ describe('API CRUD operations', () => {
await api.loadBudget(budgetName);
});
// apis: getCategoryGroups, createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
// apis: createCategoryGroup, updateCategoryGroup, deleteCategoryGroup
test('CategoryGroups: successfully update category groups', async () => {
const month = '2023-10';
global.currentMonth = month;
// get existing category groups
const groups = await api.getCategoryGroups();
expect(groups).toEqual(
expect.arrayContaining([
expect.objectContaining({
hidden: 0,
id: 'fc3825fd-b982-4b72-b768-5b30844cf832',
is_income: 0,
name: 'Usual Expenses',
sort_order: 16384,
tombstone: 0,
}),
expect.objectContaining({
hidden: 0,
id: 'a137772f-cf2f-4089-9432-822d2ddc1466',
is_income: 0,
name: 'Investments and Savings',
sort_order: 32768,
tombstone: 0,
}),
expect.objectContaining({
hidden: 0,
id: '2E1F5BDB-209B-43F9-AF2C-3CE28E380C00',
is_income: 1,
name: 'Income',
sort_order: 32768,
tombstone: 0,
}),
]),
);
// create our test category group
const mainGroupId = await api.createCategoryGroup({
name: 'test-group',
@@ -346,221 +315,13 @@ describe('API CRUD operations', () => {
);
});
// apis: getRules, getPayeeRules, createRule, updateRule, deleteRule
test('Rules: successfully update rules', async () => {
await api.createPayee({ name: 'test-payee' });
await api.createPayee({ name: 'test-payee2' });
// create our test rules
const rule = await api.createRule({
stage: 'pre',
conditionsOp: 'and',
conditions: [
{
field: 'payee',
op: 'is',
value: 'test-payee',
},
],
actions: [
{
op: 'set',
field: 'category',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
},
],
});
const rule2 = await api.createRule({
stage: 'pre',
conditionsOp: 'and',
conditions: [
{
field: 'payee',
op: 'is',
value: 'test-payee2',
},
],
actions: [
{
op: 'set',
field: 'category',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
},
],
});
// get existing rules
const rules = await api.getRules();
expect(rules).toEqual(
expect.arrayContaining([
expect.objectContaining({
actions: expect.arrayContaining([
expect.objectContaining({
field: 'category',
op: 'set',
type: 'id',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
}),
]),
conditions: expect.arrayContaining([
expect.objectContaining({
field: 'payee',
op: 'is',
type: 'id',
value: 'test-payee2',
}),
]),
conditionsOp: 'and',
id: rule2.id,
stage: 'pre',
}),
expect.objectContaining({
actions: expect.arrayContaining([
expect.objectContaining({
field: 'category',
op: 'set',
type: 'id',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
}),
]),
conditions: expect.arrayContaining([
expect.objectContaining({
field: 'payee',
op: 'is',
type: 'id',
value: 'test-payee',
}),
]),
conditionsOp: 'and',
id: rule.id,
stage: 'pre',
}),
]),
);
// get by payee
expect(await api.getPayeeRules('test-payee')).toEqual(
expect.arrayContaining([
expect.objectContaining({
actions: expect.arrayContaining([
expect.objectContaining({
field: 'category',
op: 'set',
type: 'id',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
}),
]),
conditions: expect.arrayContaining([
expect.objectContaining({
field: 'payee',
op: 'is',
type: 'id',
value: 'test-payee',
}),
]),
conditionsOp: 'and',
id: rule.id,
stage: 'pre',
}),
]),
);
expect(await api.getPayeeRules('test-payee2')).toEqual(
expect.arrayContaining([
expect.objectContaining({
actions: expect.arrayContaining([
expect.objectContaining({
field: 'category',
op: 'set',
type: 'id',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
}),
]),
conditions: expect.arrayContaining([
expect.objectContaining({
field: 'payee',
op: 'is',
type: 'id',
value: 'test-payee2',
}),
]),
conditionsOp: 'and',
id: rule2.id,
stage: 'pre',
}),
]),
);
// update one rule
const updatedRule = {
...rule,
stage: 'post',
conditionsOp: 'or',
};
expect(await api.updateRule(updatedRule)).toEqual(updatedRule);
expect(await api.getRules()).toEqual(
expect.arrayContaining([
expect.objectContaining({
actions: expect.arrayContaining([
expect.objectContaining({
field: 'category',
op: 'set',
type: 'id',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
}),
]),
conditions: expect.arrayContaining([
expect.objectContaining({
field: 'payee',
op: 'is',
type: 'id',
value: 'test-payee',
}),
]),
conditionsOp: 'or',
id: rule.id,
stage: 'post',
}),
expect.objectContaining({
actions: expect.arrayContaining([
expect.objectContaining({
field: 'category',
op: 'set',
type: 'id',
value: 'fc3825fd-b982-4b72-b768-5b30844cf832',
}),
]),
conditions: expect.arrayContaining([
expect.objectContaining({
field: 'payee',
op: 'is',
type: 'id',
value: 'test-payee2',
}),
]),
conditionsOp: 'and',
id: rule2.id,
stage: 'pre',
}),
]),
);
// delete rules
await api.deleteRule(rules[1]);
expect(await api.getRules()).toHaveLength(1);
await api.deleteRule(rules[0]);
expect(await api.getRules()).toHaveLength(0);
});
// apis: addTransactions, getTransactions, importTransactions, updateTransaction, deleteTransaction
test('Transactions: successfully update transactions', async () => {
const accountId = await api.createAccount({ name: 'test-account' }, 0);
let newTransaction = [
{ date: '2023-11-03', imported_id: '11', amount: 100, notes: 'notes' },
{ date: '2023-11-03', imported_id: '12', amount: 100, notes: '' },
{ date: '2023-11-03', imported_id: '11', amount: 100 },
{ date: '2023-11-03', imported_id: '11', amount: 100 },
];
const addResult = await api.addTransactions(accountId, newTransaction, {
@@ -583,9 +344,8 @@ describe('API CRUD operations', () => {
expect(transactions).toHaveLength(2);
newTransaction = [
{ date: '2023-12-03', imported_id: '11', amount: 100, notes: 'notes' },
{ date: '2023-12-03', imported_id: '12', amount: 100, notes: 'notes' },
{ date: '2023-12-03', imported_id: '22', amount: 200, notes: '' },
{ date: '2023-12-03', imported_id: '11', amount: 100 },
{ date: '2023-12-03', imported_id: '22', amount: 200 },
];
const reconciled = await api.importTransactions(accountId, newTransaction);
@@ -601,22 +361,9 @@ describe('API CRUD operations', () => {
'2023-12-31',
);
expect(transactions).toEqual(
expect.arrayContaining([
expect.objectContaining({ imported_id: '22', amount: 200 }),
]),
);
expect(transactions).toHaveLength(1);
// confirm imported transactions update perfomed
transactions = await api.getTransactions(
accountId,
'2023-11-01',
'2023-11-30',
);
expect(transactions).toEqual(
expect.arrayContaining([
expect.objectContaining({ notes: 'notes', amount: 100 }),
]),
expect.arrayContaining(
newTransaction.map(trans => expect.objectContaining(trans)),
),
);
expect(transactions).toHaveLength(2);

View File

@@ -35,10 +35,6 @@ export async function sync() {
return send('api/sync');
}
export async function runBankSync(args?: { accountId: string }) {
return send('api/bank-sync', args);
}
export async function batchBudgetUpdates(func) {
await send('api/batch-budget-start');
try {
@@ -125,10 +121,6 @@ export function deleteAccount(id) {
return send('api/account-delete', { id });
}
export function getCategoryGroups() {
return send('api/category-groups-get');
}
export function createCategoryGroup(group) {
return send('api/category-group-create', { group });
}
@@ -172,23 +164,3 @@ export function updatePayee(id, fields) {
export function deletePayee(id) {
return send('api/payee-delete', { id });
}
export function getRules() {
return send('api/rules-get');
}
export function getPayeeRules(id) {
return send('api/payee-rules-get', { id });
}
export function createRule(rule) {
return send('api/rule-create', { rule });
}
export function updateRule(rule) {
return send('api/rule-update', { rule });
}
export function deleteRule(id) {
return send('api/rule-delete', { id });
}

View File

@@ -1,6 +1,6 @@
{
"name": "@actual-app/api",
"version": "6.8.1",
"version": "6.4.0",
"license": "MIT",
"description": "An API for Actual",
"engines": {
@@ -9,8 +9,7 @@
"main": "dist/index.js",
"types": "@types/index.d.ts",
"files": [
"dist",
"@types"
"dist"
],
"scripts": {
"build:app": "yarn workspace loot-core build:api",
@@ -22,18 +21,17 @@
"clean": "rm -rf dist @types"
},
"dependencies": {
"@actual-app/crdt": "workspace:^",
"better-sqlite3": "^9.6.0",
"better-sqlite3": "^9.2.2",
"compare-versions": "^6.1.0",
"node-fetch": "^3.3.2",
"uuid": "^9.0.1"
"uuid": "^9.0.0"
},
"devDependencies": {
"@swc/core": "^1.5.3",
"@swc/jest": "^0.2.36",
"@types/jest": "^27.5.2",
"@swc/core": "^1.3.105",
"@swc/jest": "^0.2.31",
"@types/jest": "^27.5.0",
"@types/uuid": "^9.0.2",
"jest": "^27.5.1",
"jest": "^27.0.0",
"tsc-alias": "^1.8.8",
"typescript": "^5.0.2"
}

View File

@@ -10,7 +10,6 @@
"outDir": "dist",
"declarationDir": "@types",
"paths": {
"loot-core/src/*": ["./loot-core/*"],
"loot-core/*": ["./@types/loot-core/*"],
}
},

View File

@@ -17,14 +17,14 @@
"dependencies": {
"google-protobuf": "^3.12.0-rc.1",
"murmurhash": "^2.0.1",
"uuid": "^9.0.1"
"uuid": "^9.0.0"
},
"devDependencies": {
"@swc/core": "^1.5.3",
"@swc/jest": "^0.2.36",
"@types/jest": "^27.5.2",
"@swc/core": "^1.3.105",
"@swc/jest": "^0.2.31",
"@types/jest": "^27.5.0",
"@types/uuid": "^9.0.2",
"jest": "^27.5.1",
"jest": "^27.0.0",
"ts-protoc-gen": "^0.15.0",
"typescript": "^5.0.2"
}

View File

@@ -32,35 +32,13 @@ Prerequisites:
#### Running against the local server
First start a dev instance:
First start the dev server:
```sh
HTTPS=true yarn start
```
or using the dev container:
```
HTTPS=true docker compose up --build
```
Note the network IP address and port the dev instance is listening on.
Next, navigate to the root of your project folder, run the standardized docker container, and launch the visual regression tests from within it.
Run via yarn:
```sh
# By default, this connects to https://localhost:3001
yarn vrt:docker
# To use a different ip and port:
yarn vrt:docker --e2e-start-url https://ip:port
# To update snapshots, use the following command:
yarn vrt:docker --e2e-start-url https://ip:port --update-snapshots
```
Run manually:
Next, navigate to the root of your project folder, run the standartised docker container, and launch the visual regression tests from within it.
```sh
# Run docker container
@@ -69,27 +47,17 @@ docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/
# If you receive an error such as "docker: invalid reference format", please instead use the following command:
docker run --rm --network host -v ${pwd}:/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.41.1-jammy /bin/bash
# Once inside the docker container, run the VRT tests: important - they MUST be ran against a HTTPS server.
# Use the ip and port noted earlier
E2E_START_URL=https://ip:port yarn vrt
# Run the VRT tests: important - they MUST be ran against a HTTPS server
E2E_START_URL=https://192.168.0.178:3001 yarn vrt
# To update snapshots, use the following command:
E2E_START_URL=https://ip:port yarn vrt --update-snapshots
E2E_START_URL=https://192.168.0.178:3001 yarn vrt --update-snapshots
```
#### Running against a remote server
You can also run the tests against a remote server by passing the URL:
Run in standardized docker container:
```sh
E2E_START_URL=https://my-remote-server.com yarn vrt:docker
# Or pass in server URL as argument
yarn vrt:docker --e2e-start-url https://my-remote-server.com
```
Run locally:
```sh
E2E_START_URL=https://my-remote-server.com yarn vrt
```

View File

@@ -7,7 +7,6 @@ test.describe('Accounts', () => {
let page;
let navigation;
let configurationPage;
let accountPage;
test.beforeAll(async ({ browser }) => {
page = await browser.newPage();
@@ -23,7 +22,7 @@ test.describe('Accounts', () => {
});
test('creates a new account and views the initial balance transaction', async () => {
accountPage = await navigation.createAccount({
const accountPage = await navigation.createAccount({
name: 'New Account',
offBudget: false,
balance: 100,
@@ -39,7 +38,7 @@ test.describe('Accounts', () => {
});
test('closes an account', async () => {
accountPage = await navigation.goToAccountPage('Roth IRA');
const accountPage = await navigation.goToAccountPage('Roth IRA');
await expect(accountPage.accountName).toHaveText('Roth IRA');
@@ -51,52 +50,4 @@ test.describe('Accounts', () => {
await expect(accountPage.accountName).toHaveText('Closed: Roth IRA');
await expect(page).toMatchThemeScreenshots();
});
test.describe('Budgeted Accounts', () => {
// Reset filters
test.afterEach(async () => {
await accountPage.removeFilter(0);
});
test('creates a transfer from two existing transactions', async () => {
accountPage = await navigation.goToAccountPage('For budget');
await expect(accountPage.accountName).toHaveText('Budgeted Accounts');
await accountPage.filterByNote('Test Acc Transfer');
await accountPage.createSingleTransaction({
account: 'Ally Savings',
payee: '',
notes: 'Test Acc Transfer',
category: 'Food',
debit: '34.56',
});
await accountPage.createSingleTransaction({
account: 'HSBC',
payee: '',
notes: 'Test Acc Transfer',
category: 'Food',
credit: '34.56',
});
await page.waitForTimeout(100); // Give time for the previous transaction to be rendered
await accountPage.selectNthTransaction(0);
await accountPage.selectNthTransaction(1);
await accountPage.clickSelectAction('Make transfer');
let transaction = accountPage.getNthTransaction(0);
await expect(transaction.payee).toHaveText('Ally Savings');
await expect(transaction.category).toHaveText('Transfer');
await expect(transaction.credit).toHaveText('34.56');
await expect(transaction.account).toHaveText('HSBC');
transaction = accountPage.getNthTransaction(1);
await expect(transaction.payee).toHaveText('HSBC');
await expect(transaction.category).toHaveText('Transfer');
await expect(transaction.debit).toHaveText('34.56');
await expect(transaction.account).toHaveText('Ally Savings');
});
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 127 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -59,9 +59,12 @@ test.describe('Budget', () => {
});
test('clicking on spent amounts opens a transaction page', async () => {
const categoryName = await budgetPage.getCategoryNameForRow(1);
const accountPage = await budgetPage.clickOnSpentAmountForRow(1);
expect(page.url()).toContain('/accounts');
expect(await accountPage.accountName.textContent()).toMatch('All Accounts');
expect(await accountPage.accountName.textContent()).toMatch(
new RegExp(String.raw`${categoryName} \(\w+ \d+\)`),
);
await page.getByRole('button', { name: 'Back' }).click();
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -102,22 +102,10 @@
"name": "Store",
"transfer_account_id": null,
"deleted": false
},
{
"id": "620e85b1-2ae7-45b1-bb3e-b875ea5c553a",
"name": "Work",
"transfer_account_id": null,
"deleted": false
}
],
"payee_locations": [],
"category_groups": [
{
"id": "a5c355c2-3b77-4a7f-b8b3-c832b10cfec8",
"name": "Income",
"hidden": false,
"deleted": false
},
{
"id": "d5c355c2-3b77-4a7f-b8b3-c832b10cfec9",
"name": "Internal Master Category",
@@ -623,30 +611,6 @@
"goal_overall_funded": null,
"goal_overall_left": null,
"deleted": false
},
{
"id": "1429f287-50aa-49d8-a89c-752cbd167d6c",
"category_group_id": "a5c355c2-3b77-4a7f-b8b3-c832b10cfec8",
"name": "Income",
"hidden": false,
"original_category_group_id": null,
"note": null,
"budgeted": 0,
"activity": 0,
"balance": 0,
"goal_type": "NEED",
"goal_day": null,
"goal_cadence": 1,
"goal_cadence_frequency": 1,
"goal_creation_month": null,
"goal_target": 0,
"goal_target_month": null,
"goal_percentage_complete": null,
"goal_months_to_budget": null,
"goal_under_funded": null,
"goal_overall_funded": null,
"goal_overall_left": null,
"deleted": false
}
],
"months": [
@@ -1633,7 +1597,7 @@
"date": "2023-08-04",
"amount": 0,
"memo": "getting paid",
"cleared": "reconciled",
"cleared": "cleared",
"approved": true,
"flag_color": null,
"account_id": "bc1d862f-bab0-41c3-bd1e-6cee8c688e32",
@@ -1693,7 +1657,7 @@
"date": "2023-08-04",
"amount": 1000000,
"memo": "",
"cleared": "reconciled",
"cleared": "cleared",
"approved": true,
"flag_color": null,
"account_id": "bc1d862f-bab0-41c3-bd1e-6cee8c688e32",
@@ -1740,28 +1704,8 @@
"payee_id": "",
"category_id": null,
"transfer_account_id": "bc1d862f-bab0-41c3-bd1e-6cee8c688e32",
"transfer_transaction_id": null,
"matched_transaction_id": null,
"import_id": null,
"import_payee_name": null,
"import_payee_name_original": null,
"debt_transaction_type": null,
"deleted": false
},
{
"id": "9a22f287-f1e0-4667-9fc0-91e4a4262193",
"date": "2024-02-02",
"amount": 2000000,
"memo": "Paycheck",
"cleared": "cleared",
"approved": true,
"flag_color": null,
"account_id": "bc1d862f-bab0-41c3-bd1e-6cee8c688e32",
"payee_id": "620e85b1-2ae7-45b1-bb3e-b875ea5c553a",
"category_id": "1429f287-50aa-49d8-a89c-752cbd167d6c",
"transfer_account_id": null,
"transfer_transaction_id": null,
"matched_transaction_id": null,
"transfer_transaction_id": "213526fc-ba49-4790-8a96-cc2a50182728",
"matched_transaction_id": "",
"import_id": null,
"import_payee_name": null,
"import_payee_name_original": null,
@@ -1785,7 +1729,7 @@
"transaction_id": "213526fc-ba49-4790-8a96-cc2a50182728",
"amount": -50000,
"memo": "split part b",
"payee_id": "8d3017e0-2aa6-4fe2-b011-c53c9f147eb6",
"payee_id": "2a20470a-634f-4efa-a7f6-f1c0b0bdda41",
"category_id": null,
"transfer_account_id": "125f339b-2a63-481e-84c0-f04d898905d2",
"deleted": false

View File

@@ -42,9 +42,6 @@ test.describe('Mobile', () => {
'Mortgage',
'Water',
'Power',
'Starting Balances',
'Misc',
'Income',
]);
await expect(page).toMatchThemeScreenshots();
});
@@ -52,7 +49,7 @@ test.describe('Mobile', () => {
test('opens the accounts page and asserts on balances', async () => {
const accountsPage = await navigation.goToAccountsPage();
const account = await accountsPage.getNthAccount(1);
const account = await accountsPage.getNthAccount(0);
await expect(account.name).toHaveText('Ally Savings');
await expect(account.balance).toHaveText('7,653.00');
@@ -61,7 +58,7 @@ test.describe('Mobile', () => {
test('opens individual account page and checks that filtering is working', async () => {
const accountsPage = await navigation.goToAccountsPage();
const accountPage = await accountsPage.openNthAccount(0);
const accountPage = await accountsPage.openNthAccount(1);
await expect(accountPage.heading).toHaveText('Bank of America');
expect(await accountPage.getBalance()).toBeGreaterThan(0);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -59,7 +59,7 @@ test.describe('Onboarding', () => {
await expect(budgetPage.budgetTable).toBeVisible({ timeout: 30000 });
const accountPage = await navigation.goToAccountPage('Checking');
await expect(accountPage.accountBalance).toHaveText('2,600.00');
await expect(accountPage.accountBalance).toHaveText('600.00');
await navigation.goToAccountPage('Saving');
await expect(accountPage.accountBalance).toHaveText('250.00');

Binary file not shown.

Before

Width:  |  Height:  |  Size: 560 KiB

After

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 567 KiB

After

Width:  |  Height:  |  Size: 649 KiB

View File

@@ -25,9 +25,6 @@ export class AccountPage {
this.filterButton = this.page.getByRole('button', { name: 'Filter' });
this.filterSelectTooltip = this.page.getByTestId('filters-select-tooltip');
this.selectButton = this.page.getByTestId('transactions-select-button');
this.selectTooltip = this.page.getByTestId('transactions-select-tooltip');
}
/**
@@ -71,21 +68,14 @@ export class AccountPage {
await this.cancelTransactionButton.click();
}
async selectNthTransaction(index) {
const row = this.transactionTableRow.nth(index);
await row.getByTestId('select').click();
}
/**
* Retrieve the data for the nth-transaction.
* 0-based index
*/
getNthTransaction(index) {
const row = this.transactionTableRow.nth(index);
const account = row.getByTestId('account');
return {
...(account ? { account } : {}),
payee: row.getByTestId('payee'),
notes: row.getByTestId('notes'),
category: row.getByTestId('category'),
@@ -94,11 +84,6 @@ export class AccountPage {
};
}
async clickSelectAction(action) {
await this.selectButton.click();
await this.selectTooltip.getByRole('button', { name: action }).click();
}
/**
* Open the modal for closing the account.
*/
@@ -121,15 +106,6 @@ export class AccountPage {
return new FilterTooltip(this.page.getByTestId('filters-menu-tooltip'));
}
/**
* Filter to a specific note
*/
async filterByNote(note) {
const filterTooltip = await this.filterBy('Note');
await this.page.keyboard.type(note);
await filterTooltip.applyButton.click();
}
/**
* Remove the nth filter
*/
@@ -141,24 +117,6 @@ export class AccountPage {
}
async _fillTransactionFields(transactionRow, transaction) {
if (transaction.debit) {
await transactionRow.getByTestId('debit').click();
await this.page.keyboard.type(transaction.debit);
await this.page.keyboard.press('Tab');
}
if (transaction.credit) {
await transactionRow.getByTestId('credit').click();
await this.page.keyboard.type(transaction.credit);
await this.page.keyboard.press('Tab');
}
if (transaction.account) {
await transactionRow.getByTestId('account').click();
await this.page.keyboard.type(transaction.account);
await this.page.keyboard.press('Tab');
}
if (transaction.payee) {
await transactionRow.getByTestId('payee').click();
await this.page.keyboard.type(transaction.payee);
@@ -181,6 +139,18 @@ export class AccountPage {
await this.page.keyboard.press('Tab');
}
}
if (transaction.debit) {
await transactionRow.getByTestId('debit').click();
await this.page.keyboard.type(transaction.debit);
await this.page.keyboard.press('Tab');
}
if (transaction.credit) {
await transactionRow.getByTestId('credit').click();
await this.page.keyboard.type(transaction.credit);
await this.page.keyboard.press('Tab');
}
}
}

View File

@@ -5,7 +5,7 @@ export class MobileAccountPage {
this.page = page;
this.heading = page.getByRole('heading');
this.balance = page.getByTestId('transactions-balance');
this.balance = page.getByTestId('account-balance');
this.noTransactionsFoundError = page.getByText('No transactions');
this.searchBox = page.getByPlaceholder(/^Search/);
this.transactionList = page.getByLabel('transaction list');

View File

@@ -61,27 +61,6 @@ export class RulesPage {
this.page.getByTestId('action-list'),
);
}
if (data.splits) {
if (data.splits.beforeSplitActions) {
await this._fillEditorFields(
data.splits.beforeSplitActions,
this.page.getByTestId('action-list'),
);
}
if (data.splits.splitActions) {
let idx = data.splits?.beforeSplitActions.length ?? 0;
for (const splitActions of data.splits.splitActions) {
await this.page.getByTestId('add-split-transactions').click();
await this._fillEditorFields(
splitActions,
this.page.getByTestId('action-list').nth(idx),
);
idx++;
}
}
}
}
async _fillEditorFields(data, rootElement) {

View File

@@ -6,10 +6,4 @@ export class SettingsPage {
async exportData() {
await this.page.getByRole('button', { name: 'Export data' }).click();
}
async enableExperimentalFeature(featureName) {
await this.page.getByTestId('advanced-settings').click();
await this.page.getByTestId('experimental-settings').click();
await this.page.getByLabel(featureName).check();
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Some files were not shown because too many files have changed in this diff Show More