Compare commits
1 Commits
loot-core-
...
revert-329
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d6b1508d6 |
@@ -14,7 +14,6 @@ packages/desktop-client/**/node_modules/*
|
|||||||
packages/desktop-client/node_modules/
|
packages/desktop-client/node_modules/
|
||||||
packages/desktop-client/src/icons/**/*
|
packages/desktop-client/src/icons/**/*
|
||||||
packages/desktop-client/test-results/
|
packages/desktop-client/test-results/
|
||||||
packages/desktop-client/playwright-report/
|
|
||||||
|
|
||||||
packages/desktop-electron/client-build/
|
packages/desktop-electron/client-build/
|
||||||
packages/desktop-electron/dist/
|
packages/desktop-electron/dist/
|
||||||
|
|||||||
11
.eslintrc.js
@@ -161,12 +161,7 @@ module.exports = {
|
|||||||
],
|
],
|
||||||
'no-with': 'warn',
|
'no-with': 'warn',
|
||||||
'no-whitespace-before-property': 'warn',
|
'no-whitespace-before-property': 'warn',
|
||||||
'react-hooks/exhaustive-deps': [
|
'react-hooks/exhaustive-deps': 'warn',
|
||||||
'warn',
|
|
||||||
{
|
|
||||||
additionalHooks: '(useQuery)',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'require-yield': 'warn',
|
'require-yield': 'warn',
|
||||||
'rest-spread-spacing': ['warn', 'never'],
|
'rest-spread-spacing': ['warn', 'never'],
|
||||||
strict: ['warn', 'never'],
|
strict: ['warn', 'never'],
|
||||||
@@ -531,8 +526,8 @@ module.exports = {
|
|||||||
'./packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx',
|
'./packages/desktop-client/src/components/budget/DynamicBudgetTable.tsx',
|
||||||
'./packages/desktop-client/src/components/budget/index.tsx',
|
'./packages/desktop-client/src/components/budget/index.tsx',
|
||||||
'./packages/desktop-client/src/components/budget/MobileBudget.tsx',
|
'./packages/desktop-client/src/components/budget/MobileBudget.tsx',
|
||||||
'./packages/desktop-client/src/components/budget/envelope/HoldMenu.tsx',
|
'./packages/desktop-client/src/components/budget/rollover/HoldMenu.tsx',
|
||||||
'./packages/desktop-client/src/components/budget/envelope/TransferMenu.tsx',
|
'./packages/desktop-client/src/components/budget/rollover/TransferMenu.tsx',
|
||||||
'./packages/desktop-client/src/components/common/Menu.tsx',
|
'./packages/desktop-client/src/components/common/Menu.tsx',
|
||||||
'./packages/desktop-client/src/components/FinancesApp.tsx',
|
'./packages/desktop-client/src/components/FinancesApp.tsx',
|
||||||
'./packages/desktop-client/src/components/GlobalKeys.ts',
|
'./packages/desktop-client/src/components/GlobalKeys.ts',
|
||||||
|
|||||||
11
.github/workflows/electron-master.yml
vendored
@@ -40,7 +40,6 @@ jobs:
|
|||||||
python3 -m pip install setuptools
|
python3 -m pip install setuptools
|
||||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install flatpak -y
|
sudo apt-get install flatpak -y
|
||||||
sudo apt-get install flatpak-builder -y
|
sudo apt-get install flatpak-builder -y
|
||||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
@@ -49,17 +48,13 @@ jobs:
|
|||||||
sudo flatpak install org.electronjs.Electron2.BaseApp/x86_64/23.08 -y
|
sudo flatpak install org.electronjs.Electron2.BaseApp/x86_64/23.08 -y
|
||||||
- name: Set up environment
|
- name: Set up environment
|
||||||
uses: ./.github/actions/setup
|
uses: ./.github/actions/setup
|
||||||
- name: Build Electron for Mac
|
- name: Build Electron
|
||||||
if: ${{ startsWith(matrix.os, 'macos') }}
|
|
||||||
run: ./bin/package-electron
|
run: ./bin/package-electron
|
||||||
env:
|
env:
|
||||||
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
# CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
|
||||||
CSC_LINK: ${{ secrets.CSC_LINK }}
|
# CSC_LINK: ${{ secrets.CSC_LINK }}
|
||||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||||
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
|
||||||
- name: Build Electron
|
|
||||||
if: ${{ ! startsWith(matrix.os, 'macos') }}
|
|
||||||
run: ./bin/package-electron
|
|
||||||
- name: Upload Build
|
- name: Upload Build
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
1
.github/workflows/electron-pr.yml
vendored
@@ -35,7 +35,6 @@ jobs:
|
|||||||
python3 -m pip install setuptools
|
python3 -m pip install setuptools
|
||||||
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
- if: ${{ startsWith(matrix.os, 'ubuntu') }}
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install flatpak -y
|
sudo apt-get install flatpak -y
|
||||||
sudo apt-get install flatpak-builder -y
|
sudo apt-get install flatpak-builder -y
|
||||||
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||||
|
|||||||
13
.github/workflows/size-compare.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Wait for ${{github.base_ref}} build to succeed
|
- name: Wait for ${{github.base_ref}} build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@v1.2.0
|
uses: fountainhead/action-wait-for-check@v1.1.0
|
||||||
id: master-build
|
id: master-build
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
ref: ${{github.base_ref}}
|
ref: ${{github.base_ref}}
|
||||||
|
|
||||||
- name: Wait for PR build to succeed
|
- name: Wait for PR build to succeed
|
||||||
uses: fountainhead/action-wait-for-check@v1.2.0
|
uses: fountainhead/action-wait-for-check@v1.1.0
|
||||||
id: wait-for-build
|
id: wait-for-build
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -46,7 +46,7 @@ jobs:
|
|||||||
echo "Build failed on PR branch or ${{github.base_ref}}"
|
echo "Build failed on PR branch or ${{github.base_ref}}"
|
||||||
exit 1
|
exit 1
|
||||||
- name: Download build artifact from ${{github.base_ref}}
|
- name: Download build artifact from ${{github.base_ref}}
|
||||||
uses: dawidd6/action-download-artifact@v6
|
uses: dawidd6/action-download-artifact@v3
|
||||||
id: pr-build
|
id: pr-build
|
||||||
with:
|
with:
|
||||||
branch: ${{github.base_ref}}
|
branch: ${{github.base_ref}}
|
||||||
@@ -55,13 +55,12 @@ jobs:
|
|||||||
path: base
|
path: base
|
||||||
|
|
||||||
- name: Download build artifact from PR
|
- name: Download build artifact from PR
|
||||||
uses: dawidd6/action-download-artifact@v6
|
uses: dawidd6/action-download-artifact@v3
|
||||||
with:
|
with:
|
||||||
pr: ${{github.event.pull_request.number}}
|
pr: ${{github.event.pull_request.number}}
|
||||||
workflow: build.yml
|
workflow: build.yml
|
||||||
name: build-stats
|
name: build-stats
|
||||||
path: head
|
path: head
|
||||||
allow_forks: true
|
|
||||||
|
|
||||||
- name: Strip content hashes from stats files
|
- name: Strip content hashes from stats files
|
||||||
run: |
|
run: |
|
||||||
@@ -71,14 +70,14 @@ jobs:
|
|||||||
sed -i -E 's/index\.[0-9a-zA-Z_-]{8,}\./index./g' ./base/web-stats.json
|
sed -i -E 's/index\.[0-9a-zA-Z_-]{8,}\./index./g' ./base/web-stats.json
|
||||||
sed -i -E 's/\.[0-9a-zA-Z_-]{8,}\.chunk\././g' ./base/web-stats.json
|
sed -i -E 's/\.[0-9a-zA-Z_-]{8,}\.chunk\././g' ./base/web-stats.json
|
||||||
sed -i -E 's/\.[0-9a-f]{8,}\././g' ./base/*.json
|
sed -i -E 's/\.[0-9a-f]{8,}\././g' ./base/*.json
|
||||||
- uses: twk3/rollup-size-compare-action@v1.1.1
|
- uses: twk3/rollup-size-compare-action@v1.0.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
current-stats-json-path: ./head/web-stats.json
|
current-stats-json-path: ./head/web-stats.json
|
||||||
base-stats-json-path: ./base/web-stats.json
|
base-stats-json-path: ./base/web-stats.json
|
||||||
title: desktop-client
|
title: desktop-client
|
||||||
|
|
||||||
- uses: github/webpack-bundlesize-compare-action@v2.1.0
|
- uses: github/webpack-bundlesize-compare-action@v1.8.2
|
||||||
with:
|
with:
|
||||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
current-stats-json-path: ./head/loot-core-stats.json
|
current-stats-json-path: ./head/loot-core-stats.json
|
||||||
|
|||||||
113
.github/workflows/update-vrt.yml
vendored
@@ -1,113 +0,0 @@
|
|||||||
name: /update-vrt
|
|
||||||
on:
|
|
||||||
issue_comment:
|
|
||||||
types: [ created ]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
pull-requests: read
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.event.issue.number }}-${{ contains(github.event.comment.body, '/update-vrt') }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
update-vrt:
|
|
||||||
name: Update VRT
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: |
|
|
||||||
github.event.issue.pull_request &&
|
|
||||||
contains(github.event.comment.body, '/update-vrt')
|
|
||||||
container:
|
|
||||||
image: mcr.microsoft.com/playwright:v1.41.1-jammy
|
|
||||||
steps:
|
|
||||||
- name: Get PR branch
|
|
||||||
# Until https://github.com/xt0rted/pull-request-comment-branch/issues/322 is resolved we use the forked version
|
|
||||||
uses: gotson/pull-request-comment-branch@head-repo-owner-dist
|
|
||||||
id: comment-branch
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ steps.comment-branch.outputs.head_owner }}/${{ steps.comment-branch.outputs.head_repo }}
|
|
||||||
ref: ${{ steps.comment-branch.outputs.head_ref }}
|
|
||||||
- name: Set up environment
|
|
||||||
uses: ./.github/actions/setup
|
|
||||||
- name: Wait for Netlify build to finish
|
|
||||||
id: netlify
|
|
||||||
env:
|
|
||||||
COMMIT_SHA: ${{ steps.comment-branch.outputs.head_sha }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
run: ./.github/actions/netlify-wait-for-build
|
|
||||||
- name: Run VRT Tests on Netlify URL
|
|
||||||
run: yarn vrt --update-snapshots
|
|
||||||
env:
|
|
||||||
E2E_START_URL: ${{ steps.netlify.outputs.url }}
|
|
||||||
- name: Create patch
|
|
||||||
run: |
|
|
||||||
git config --system --add safe.directory "*"
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git reset
|
|
||||||
git add "**/*.png"
|
|
||||||
if git diff --staged --quiet; then
|
|
||||||
echo "No changes to commit"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
git commit -m "Update VRT"
|
|
||||||
git format-patch -1 HEAD --stdout > Update-VRT.patch
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: patch
|
|
||||||
path: Update-VRT.patch
|
|
||||||
|
|
||||||
push-patch:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: update-vrt
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- name: Get PR branch
|
|
||||||
# Until https://github.com/xt0rted/pull-request-comment-branch/issues/322 is resolved we use the forked version
|
|
||||||
uses: gotson/pull-request-comment-branch@head-repo-owner-dist
|
|
||||||
id: comment-branch
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
repository: ${{ steps.comment-branch.outputs.head_owner }}/${{ steps.comment-branch.outputs.head_repo }}
|
|
||||||
ref: ${{ steps.comment-branch.outputs.head_ref }}
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
continue-on-error: true
|
|
||||||
with:
|
|
||||||
name: patch
|
|
||||||
- name: Apply patch and push
|
|
||||||
run: |
|
|
||||||
git config --global user.name "github-actions[bot]"
|
|
||||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
||||||
git apply Update-VRT.patch
|
|
||||||
git add "**/*.png"
|
|
||||||
if git diff --staged --quiet; then
|
|
||||||
echo "No changes to commit"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
git commit -m "Update VRT"
|
|
||||||
git push origin HEAD:${{ steps.comment-branch.outputs.head_ref }}
|
|
||||||
- name: Add finished reaction
|
|
||||||
uses: dkershner6/reaction-action@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
commentId: ${{ github.event.comment.id }}
|
|
||||||
reaction: "rocket"
|
|
||||||
|
|
||||||
add-starting-reaction:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: |
|
|
||||||
github.event.issue.pull_request &&
|
|
||||||
contains(github.event.comment.body, '/update-vrt')
|
|
||||||
permissions:
|
|
||||||
pull-requests: write
|
|
||||||
steps:
|
|
||||||
- name: React to comment
|
|
||||||
uses: dkershner6/reaction-action@v2
|
|
||||||
with:
|
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
commentId: ${{ github.event.comment.id }}
|
|
||||||
reaction: "+1"
|
|
||||||
3
.gitignore
vendored
@@ -50,6 +50,3 @@ bundle.mobile.js.map
|
|||||||
|
|
||||||
# Local Netlify folder
|
# Local Netlify folder
|
||||||
.netlify
|
.netlify
|
||||||
|
|
||||||
# build output
|
|
||||||
package.tgz
|
|
||||||
|
|||||||
@@ -74,6 +74,6 @@ Make Actual Budget accessible to more people by helping with the [Internationali
|
|||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
Thanks to our wonderful sponsors who make Actual Budget possible!
|
Thanks to our wonderful sponsors who make Actual budget possible!
|
||||||
|
|
||||||
<a href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-accent.svg" alt="Deploys by Netlify" /> </a>
|
<a href="https://www.netlify.com"> <img src="https://www.netlify.com/v3/img/components/netlify-color-accent.svg" alt="Deploys by Netlify" /> </a>
|
||||||
|
|||||||
1
TODO.txt
@@ -1 +0,0 @@
|
|||||||
Figure out why loot-core-server is not detecting loot-core-shared files.
|
|
||||||
@@ -4,8 +4,7 @@ ROOT=`dirname $0`
|
|||||||
|
|
||||||
cd "$ROOT/.."
|
cd "$ROOT/.."
|
||||||
|
|
||||||
yarn workspace loot-core-server build:browser
|
yarn workspace loot-core build:browser
|
||||||
# yarn workspace loot-core build:browser
|
|
||||||
yarn workspace @actual-app/web build:browser
|
yarn workspace @actual-app/web build:browser
|
||||||
|
|
||||||
echo "packages/desktop-client/build"
|
echo "packages/desktop-client/build"
|
||||||
|
|||||||
@@ -34,10 +34,9 @@ if [ "$OSTYPE" == "msys" ]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
yarn workspace loot-core-server build:node
|
yarn workspace loot-core build:node
|
||||||
# yarn workspace loot-core build:node
|
|
||||||
|
|
||||||
yarn workspace @actual-app/web build --mode=desktop # electron specific build
|
yarn workspace @actual-app/web build --mode=desktop
|
||||||
|
|
||||||
yarn workspace desktop-electron update-client
|
yarn workspace desktop-electron update-client
|
||||||
|
|
||||||
|
|||||||
@@ -28,5 +28,5 @@ echo "Running VRT tests with the following parameters:"
|
|||||||
echo "E2E_START_URL: $E2E_START_URL"
|
echo "E2E_START_URL: $E2E_START_URL"
|
||||||
echo "VRT_ARGS: $VRT_ARGS"
|
echo "VRT_ARGS: $VRT_ARGS"
|
||||||
|
|
||||||
MSYS_NO_PATHCONV=1 docker run --rm --network host -v "$(pwd)":/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.41.1-jammy /bin/bash \
|
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"
|
-c "E2E_START_URL=$E2E_START_URL yarn vrt $VRT_ARGS"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@actual-app/api",
|
"name": "@actual-app/api",
|
||||||
"version": "24.11.0",
|
"version": "6.9.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"description": "An API for Actual",
|
"description": "An API for Actual",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
2
packages/desktop-client/.gitignore
vendored
@@ -6,11 +6,9 @@ node_modules
|
|||||||
# testing
|
# testing
|
||||||
coverage
|
coverage
|
||||||
test-results
|
test-results
|
||||||
playwright-report
|
|
||||||
|
|
||||||
# production
|
# production
|
||||||
build
|
build
|
||||||
build-electron
|
|
||||||
build-stats
|
build-stats
|
||||||
stats.json
|
stats.json
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test';
|
|
||||||
|
|
||||||
import { ConfigurationPage } from './page-models/configuration-page';
|
|
||||||
import { MobileNavigation } from './page-models/mobile-navigation';
|
|
||||||
|
|
||||||
test.describe('Mobile Accounts', () => {
|
|
||||||
let page;
|
|
||||||
let navigation;
|
|
||||||
let configurationPage;
|
|
||||||
|
|
||||||
test.beforeEach(async ({ browser }) => {
|
|
||||||
page = await browser.newPage();
|
|
||||||
navigation = new MobileNavigation(page);
|
|
||||||
configurationPage = new ConfigurationPage(page);
|
|
||||||
|
|
||||||
await page.setViewportSize({
|
|
||||||
width: 350,
|
|
||||||
height: 600,
|
|
||||||
});
|
|
||||||
await page.goto('/');
|
|
||||||
await configurationPage.createTestFile();
|
|
||||||
});
|
|
||||||
|
|
||||||
test.afterEach(async () => {
|
|
||||||
await page.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('opens the accounts page and asserts on balances', async () => {
|
|
||||||
const accountsPage = await navigation.goToAccountsPage();
|
|
||||||
await accountsPage.waitFor();
|
|
||||||
|
|
||||||
const account = await accountsPage.getNthAccount(1);
|
|
||||||
|
|
||||||
await expect(account.name).toHaveText('Ally Savings');
|
|
||||||
await expect(account.balance).toHaveText('7,653.00');
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('opens individual account page and checks that filtering is working', async () => {
|
|
||||||
const accountsPage = await navigation.goToAccountsPage();
|
|
||||||
await accountsPage.waitFor();
|
|
||||||
|
|
||||||
const accountPage = await accountsPage.openNthAccount(0);
|
|
||||||
await accountPage.waitFor();
|
|
||||||
|
|
||||||
await expect(accountPage.heading).toHaveText('Bank of America');
|
|
||||||
await expect(accountPage.transactionList).toBeVisible();
|
|
||||||
await expect(await accountPage.getBalance()).toBeGreaterThan(0);
|
|
||||||
await expect(accountPage.noTransactionsMessage).not.toBeVisible();
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
|
|
||||||
await accountPage.searchByText('nothing should be found');
|
|
||||||
await expect(accountPage.noTransactionsMessage).toBeVisible();
|
|
||||||
await expect(accountPage.transactions).toHaveCount(0);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
|
|
||||||
await accountPage.clearSearch();
|
|
||||||
await expect(accountPage.transactions).not.toHaveCount(0);
|
|
||||||
|
|
||||||
await accountPage.searchByText('Kroger');
|
|
||||||
await expect(accountPage.transactions).not.toHaveCount(0);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,5 +1,3 @@
|
|||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
import { test, expect } from '@playwright/test';
|
import { test, expect } from '@playwright/test';
|
||||||
|
|
||||||
import { ConfigurationPage } from './page-models/configuration-page';
|
import { ConfigurationPage } from './page-models/configuration-page';
|
||||||
@@ -11,7 +9,7 @@ test.describe('Accounts', () => {
|
|||||||
let configurationPage;
|
let configurationPage;
|
||||||
let accountPage;
|
let accountPage;
|
||||||
|
|
||||||
test.beforeEach(async ({ browser }) => {
|
test.beforeAll(async ({ browser }) => {
|
||||||
page = await browser.newPage();
|
page = await browser.newPage();
|
||||||
navigation = new Navigation(page);
|
navigation = new Navigation(page);
|
||||||
configurationPage = new ConfigurationPage(page);
|
configurationPage = new ConfigurationPage(page);
|
||||||
@@ -20,7 +18,7 @@ test.describe('Accounts', () => {
|
|||||||
await configurationPage.createTestFile();
|
await configurationPage.createTestFile();
|
||||||
});
|
});
|
||||||
|
|
||||||
test.afterEach(async () => {
|
test.afterAll(async () => {
|
||||||
await page.close();
|
await page.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,8 +60,6 @@ test.describe('Accounts', () => {
|
|||||||
|
|
||||||
test('creates a transfer from two existing transactions', async () => {
|
test('creates a transfer from two existing transactions', async () => {
|
||||||
accountPage = await navigation.goToAccountPage('For budget');
|
accountPage = await navigation.goToAccountPage('For budget');
|
||||||
await accountPage.waitFor();
|
|
||||||
|
|
||||||
await expect(accountPage.accountName).toHaveText('Budgeted Accounts');
|
await expect(accountPage.accountName).toHaveText('Budgeted Accounts');
|
||||||
|
|
||||||
await accountPage.filterByNote('Test Acc Transfer');
|
await accountPage.filterByNote('Test Acc Transfer');
|
||||||
@@ -103,61 +99,4 @@ test.describe('Accounts', () => {
|
|||||||
await expect(transaction.account).toHaveText('Ally Savings');
|
await expect(transaction.account).toHaveText('Ally Savings');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe('Import Transactions', () => {
|
|
||||||
test.beforeEach(async () => {
|
|
||||||
accountPage = await navigation.createAccount({
|
|
||||||
name: 'CSV import',
|
|
||||||
offBudget: false,
|
|
||||||
balance: 0,
|
|
||||||
});
|
|
||||||
await accountPage.waitFor();
|
|
||||||
});
|
|
||||||
|
|
||||||
async function importCsv(screenshot = false) {
|
|
||||||
const fileChooserPromise = page.waitForEvent('filechooser');
|
|
||||||
await accountPage.page.getByRole('button', { name: 'Import' }).click();
|
|
||||||
|
|
||||||
const fileChooser = await fileChooserPromise;
|
|
||||||
await fileChooser.setFiles(join(__dirname, 'data/test.csv'));
|
|
||||||
|
|
||||||
if (screenshot) await expect(page).toMatchThemeScreenshots();
|
|
||||||
|
|
||||||
const importButton = accountPage.page.getByRole('button', {
|
|
||||||
name: /Import \d+ transactions/,
|
|
||||||
});
|
|
||||||
await importButton.click();
|
|
||||||
|
|
||||||
await expect(importButton).not.toBeVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
test('imports transactions from a CSV file', async () => {
|
|
||||||
await importCsv(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('import csv file twice', async () => {
|
|
||||||
await importCsv(false);
|
|
||||||
|
|
||||||
const fileChooserPromise = page.waitForEvent('filechooser');
|
|
||||||
await accountPage.page.getByRole('button', { name: 'Import' }).click();
|
|
||||||
|
|
||||||
const fileChooser = await fileChooserPromise;
|
|
||||||
await fileChooser.setFiles(join(__dirname, 'data/test.csv'));
|
|
||||||
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
|
|
||||||
const importButton = accountPage.page.getByRole('button', {
|
|
||||||
name: /Import \d+ transactions/,
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(importButton).toBeDisabled();
|
|
||||||
await expect(await importButton.innerText()).toMatch(
|
|
||||||
/Import 0 transactions/,
|
|
||||||
);
|
|
||||||
|
|
||||||
await accountPage.page.getByRole('button', { name: 'Close' }).click();
|
|
||||||
|
|
||||||
await expect(importButton).not.toBeVisible();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 171 KiB |
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 153 KiB |
|
Before Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 190 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 54 KiB |
@@ -1,280 +0,0 @@
|
|||||||
import { test, expect } from '@playwright/test';
|
|
||||||
import * as monthUtils from 'loot-core-shared/months';
|
|
||||||
|
|
||||||
import { ConfigurationPage } from './page-models/configuration-page';
|
|
||||||
import { MobileNavigation } from './page-models/mobile-navigation';
|
|
||||||
|
|
||||||
const budgetTypes = ['Envelope', 'Tracking'];
|
|
||||||
|
|
||||||
budgetTypes.forEach(budgetType => {
|
|
||||||
test.describe(`Mobile Budget [${budgetType}]`, () => {
|
|
||||||
let page;
|
|
||||||
let navigation;
|
|
||||||
let configurationPage;
|
|
||||||
let previousGlobalIsTesting;
|
|
||||||
|
|
||||||
test.beforeAll(() => {
|
|
||||||
// TODO: Hack, properly mock the currentMonth function
|
|
||||||
previousGlobalIsTesting = global.IS_TESTING;
|
|
||||||
global.IS_TESTING = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.afterAll(() => {
|
|
||||||
// TODO: Hack, properly mock the currentMonth function
|
|
||||||
global.IS_TESTING = previousGlobalIsTesting;
|
|
||||||
});
|
|
||||||
|
|
||||||
test.beforeEach(async ({ browser }) => {
|
|
||||||
page = await browser.newPage();
|
|
||||||
navigation = new MobileNavigation(page);
|
|
||||||
configurationPage = new ConfigurationPage(page);
|
|
||||||
|
|
||||||
await page.setViewportSize({
|
|
||||||
width: 350,
|
|
||||||
height: 600,
|
|
||||||
});
|
|
||||||
await page.goto('/');
|
|
||||||
await configurationPage.createTestFile();
|
|
||||||
|
|
||||||
if (budgetType === 'Tracking') {
|
|
||||||
// Set budget type to tracking
|
|
||||||
const settingsPage = await navigation.goToSettingsPage();
|
|
||||||
await settingsPage.useBudgetType('tracking');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test.afterEach(async () => {
|
|
||||||
await page.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('loads the budget page with budgeted amounts', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
await expect(budgetPage.categoryNames).toHaveText([
|
|
||||||
'Food',
|
|
||||||
'Restaurants',
|
|
||||||
'Entertainment',
|
|
||||||
'Clothing',
|
|
||||||
'General',
|
|
||||||
'Gift',
|
|
||||||
'Medical',
|
|
||||||
'Savings',
|
|
||||||
'Cell',
|
|
||||||
'Internet',
|
|
||||||
'Mortgage',
|
|
||||||
'Water',
|
|
||||||
'Power',
|
|
||||||
'Starting Balances',
|
|
||||||
'Misc',
|
|
||||||
'Income',
|
|
||||||
]);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Page Header Tests
|
|
||||||
|
|
||||||
test('checks that clicking the Actual logo in the page header opens the budget page menu', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
await budgetPage.openBudgetPageMenu();
|
|
||||||
|
|
||||||
const budgetPageMenuModal = page.getByRole('dialog');
|
|
||||||
|
|
||||||
await expect(budgetPageMenuModal).toBeVisible();
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("checks that clicking the left arrow in the page header shows the previous month's budget", async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const selectedMonth = await budgetPage.getSelectedMonth();
|
|
||||||
const displayMonth = monthUtils.format(
|
|
||||||
selectedMonth,
|
|
||||||
budgetPage.MONTH_HEADER_DATE_FORMAT,
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(budgetPage.heading).toHaveText(displayMonth);
|
|
||||||
|
|
||||||
const previousMonth = await budgetPage.goToPreviousMonth();
|
|
||||||
const previousDisplayMonth = monthUtils.format(
|
|
||||||
previousMonth,
|
|
||||||
budgetPage.MONTH_HEADER_DATE_FORMAT,
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(budgetPage.heading).toHaveText(previousDisplayMonth);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('checks that clicking the month in the page header opens the month menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const selectedMonth = await budgetPage.getSelectedMonth();
|
|
||||||
|
|
||||||
await budgetPage.openMonthMenu();
|
|
||||||
|
|
||||||
const monthMenuModal = page.getByRole('dialog');
|
|
||||||
const monthMenuModalHeading = monthMenuModal.getByRole('heading');
|
|
||||||
|
|
||||||
const displayMonth = monthUtils.format(
|
|
||||||
selectedMonth,
|
|
||||||
budgetPage.MONTH_HEADER_DATE_FORMAT,
|
|
||||||
);
|
|
||||||
await expect(monthMenuModalHeading).toHaveText(displayMonth);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("checks that clicking the right arrow in the page header shows the next month's budget", async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const selectedMonth = await budgetPage.getSelectedMonth();
|
|
||||||
const displayMonth = monthUtils.format(
|
|
||||||
selectedMonth,
|
|
||||||
budgetPage.MONTH_HEADER_DATE_FORMAT,
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(budgetPage.heading).toHaveText(displayMonth);
|
|
||||||
|
|
||||||
const nextMonth = await budgetPage.goToNextMonth();
|
|
||||||
const nextDisplayMonth = monthUtils.format(
|
|
||||||
nextMonth,
|
|
||||||
budgetPage.MONTH_HEADER_DATE_FORMAT,
|
|
||||||
);
|
|
||||||
|
|
||||||
await expect(budgetPage.heading).toHaveText(nextDisplayMonth);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Category / Category Group Menu Tests
|
|
||||||
|
|
||||||
test('checks that clicking the category group name opens the category group menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const categoryGroupName = await budgetPage.getCategoryGroupNameForRow(0);
|
|
||||||
await budgetPage.openCategoryGroupMenu(categoryGroupName);
|
|
||||||
|
|
||||||
const categoryMenuModalHeading = page
|
|
||||||
.getByRole('dialog')
|
|
||||||
.getByRole('heading');
|
|
||||||
|
|
||||||
await expect(categoryMenuModalHeading).toHaveText(categoryGroupName);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('checks that clicking the category name opens the category menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const categoryName = await budgetPage.getCategoryNameForRow(0);
|
|
||||||
await budgetPage.openCategoryMenu(categoryName);
|
|
||||||
|
|
||||||
const categoryMenuModalHeading = page
|
|
||||||
.getByRole('dialog')
|
|
||||||
.getByRole('heading');
|
|
||||||
|
|
||||||
await expect(categoryMenuModalHeading).toHaveText(categoryName);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Budgeted Cell Tests
|
|
||||||
|
|
||||||
test('checks that clicking the budgeted cell opens the budget menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const categoryName = await budgetPage.getCategoryNameForRow(0);
|
|
||||||
await budgetPage.openBudgetMenu(categoryName);
|
|
||||||
|
|
||||||
const budgetMenuModalHeading = page
|
|
||||||
.getByRole('dialog')
|
|
||||||
.getByRole('heading');
|
|
||||||
|
|
||||||
await expect(budgetMenuModalHeading).toHaveText(categoryName);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
test('updates the budgeted amount', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const categoryName = await budgetPage.getCategoryNameForRow(0);
|
|
||||||
|
|
||||||
// Set to 100.00
|
|
||||||
await budgetPage.setBudget(categoryName, 10000);
|
|
||||||
|
|
||||||
const budgetedButton =
|
|
||||||
await budgetPage.getButtonForBudgeted(categoryName);
|
|
||||||
|
|
||||||
await expect(budgetedButton).toHaveText('100.00');
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Spent Cell Tests
|
|
||||||
|
|
||||||
test('checks that clicking spent cell redirects to the category transactions page', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const categoryName = await budgetPage.getCategoryNameForRow(0);
|
|
||||||
const accountPage = await budgetPage.openSpentPage(categoryName);
|
|
||||||
|
|
||||||
await expect(accountPage.heading).toContainText(categoryName);
|
|
||||||
await expect(accountPage.transactionList).toBeVisible();
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Balance Cell Tests
|
|
||||||
|
|
||||||
test('checks that clicking the balance cell opens the balance menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
const categoryName = await budgetPage.getCategoryNameForRow(0);
|
|
||||||
await budgetPage.openBalanceMenu(categoryName);
|
|
||||||
|
|
||||||
const balanceMenuModalHeading = page
|
|
||||||
.getByRole('dialog')
|
|
||||||
.getByRole('heading');
|
|
||||||
|
|
||||||
await expect(balanceMenuModalHeading).toHaveText(categoryName);
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (budgetType === 'Envelope') {
|
|
||||||
test('checks that clicking the To Budget/Overbudgeted amount opens the budget summary menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
await budgetPage.openEnvelopeBudgetSummaryMenu();
|
|
||||||
|
|
||||||
const summaryModalHeading = page
|
|
||||||
.getByRole('dialog')
|
|
||||||
.getByRole('heading');
|
|
||||||
|
|
||||||
await expect(summaryModalHeading).toHaveText('Budget Summary');
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (budgetType === 'Tracking') {
|
|
||||||
test('checks that clicking the Saved/Projected Savings/Overspent amount opens the budget summary menu modal', async () => {
|
|
||||||
const budgetPage = await navigation.goToBudgetPage();
|
|
||||||
await budgetPage.waitForBudgetTable();
|
|
||||||
|
|
||||||
await budgetPage.openTrackingBudgetSummaryMenu();
|
|
||||||
|
|
||||||
const summaryModalHeading = page
|
|
||||||
.getByRole('dialog')
|
|
||||||
.getByRole('heading');
|
|
||||||
|
|
||||||
await expect(summaryModalHeading).toHaveText('Budget Summary');
|
|
||||||
await expect(page).toMatchThemeScreenshots();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 29 KiB |