Skip to content

Commit

Permalink
✅ (e2e) adding sample schedules to test budget
Browse files Browse the repository at this point in the history
  • Loading branch information
MatissJanis committed Sep 8, 2023
1 parent a8a0f77 commit 4410a71
Show file tree
Hide file tree
Showing 20 changed files with 186 additions and 71 deletions.
2 changes: 1 addition & 1 deletion packages/desktop-client/e2e/mobile.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ test.describe('Mobile', () => {

test('creates a transaction from `/accounts/:id` page', async () => {
const accountsPage = await navigation.goToAccountsPage();
const accountPage = await accountsPage.openNthAccount(1);
const accountPage = await accountsPage.openNthAccount(2);
const transactionEntryPage = await accountPage.clickCreateTransaction();

await expect(transactionEntryPage.header).toHaveText('New Transaction');
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 8 additions & 7 deletions packages/desktop-client/e2e/page-models/rules-page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export class RulesPage {
constructor(page) {
this.page = page;
this.searchBox = page.getByPlaceholder('Filter rules...');
}

/**
Expand All @@ -22,19 +23,19 @@ export class RulesPage {
* Retrieve the data for the nth-rule.
* 0-based index
*/
async getNthRule(index) {
getNthRule(index) {
const row = this.page.getByTestId('table').getByTestId('row').nth(index);

return {
conditions: await row
.getByTestId('conditions')
.evaluate(el => [...el.children].map(c => c.textContent)),
actions: await row
.getByTestId('actions')
.evaluate(el => [...el.children].map(c => c.textContent)),
conditions: row.getByTestId('conditions').locator(':scope > div'),
actions: row.getByTestId('actions').locator(':scope > div'),
};
}

async searchFor(text) {
await this.searchBox.fill(text);
}

async _fillRuleFields(data) {
if (data.conditionsOp) {
await this.page
Expand Down
12 changes: 6 additions & 6 deletions packages/desktop-client/e2e/page-models/schedules-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ export class SchedulesPage {
* Retrieve the data for the nth-schedule.
* 0-based index
*/
async getNthSchedule(index) {
getNthSchedule(index) {
const row = this.getNthScheduleRow(index);

return {
payee: await row.getByTestId('payee').textContent(),
account: await row.getByTestId('account').textContent(),
date: await row.getByTestId('date').textContent(),
status: await row.getByTestId('status').textContent(),
amount: await row.getByTestId('amount').textContent(),
payee: row.getByTestId('payee'),
account: row.getByTestId('account'),
date: row.getByTestId('date'),
status: row.getByTestId('status'),
amount: row.getByTestId('amount'),
};
}

Expand Down
9 changes: 4 additions & 5 deletions packages/desktop-client/e2e/rules.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,12 @@ test.describe('Rules', () => {
],
});

expect(await rulesPage.getNthRule(0)).toMatchObject({
conditions: ['payee is Fast Internet'],
actions: ['set category to General'],
});
const rule = rulesPage.getNthRule(0);
await expect(rule.conditions).toHaveText(['payee is Fast Internet']);
await expect(rule.actions).toHaveText(['set category to General']);
await expect(page).toHaveScreenshot(screenshotConfig(page));

const accountPage = await navigation.goToAccountPage('Bank of America');
const accountPage = await navigation.goToAccountPage('HSBC');

await accountPage.createSingleTransaction({
payee: 'Fast Internet',
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 21 additions & 26 deletions packages/desktop-client/e2e/schedules.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,15 @@ test.describe('Schedules', () => {
amount: 25,
});

expect(await schedulesPage.getNthSchedule(0)).toMatchObject({
payee: 'Home Depot',
account: 'HSBC',
amount: '~25.00',
status: 'Due',
});
const schedule = schedulesPage.getNthSchedule(2);
await expect(schedule.payee).toHaveText('Home Depot');
await expect(schedule.account).toHaveText('HSBC');
await expect(schedule.amount).toHaveText('~25.00');
await expect(schedule.status).toHaveText('Due');
await expect(page).toHaveScreenshot(screenshotConfig(page));

await schedulesPage.postNthSchedule(0);
expect(await schedulesPage.getNthSchedule(0)).toMatchObject({
status: 'Paid',
});
await schedulesPage.postNthSchedule(2);
await expect(schedulesPage.getNthSchedule(2).status).toHaveText('Paid');
await expect(page).toHaveScreenshot(screenshotConfig(page));

// Go to transactions page
Expand All @@ -62,26 +59,24 @@ test.describe('Schedules', () => {

// go to rules page
const rulesPage = await navigation.goToRulesPage();
expect(await rulesPage.getNthRule(0)).toMatchObject({
// actions: ['link schedule Home Depot (2023-02-28)'],
actions: [
expect.stringMatching(
/^link schedule Home Depot \(\d{4}-\d{2}-\d{2}\)$/,
),
],
conditions: [
'payee is Home Depot',
'and account is HSBC',
expect.stringMatching(/^and date is approx Every month on the/),
'and amount is approx -25.00',
],
});
await rulesPage.searchFor('Home Depot');
const rule = rulesPage.getNthRule(0);
await expect(rule.actions).toHaveText([
'link schedule Home Depot (2017-01-01)',
]);
await expect(rule.conditions).toHaveText([
'payee is Home Depot',
'and account is HSBC',
'and date is approx Every month on the 1st',
'and amount is approx -25.00',
]);

// Go back to schedules page
await navigation.goToSchedulesPage();
await schedulesPage.completeNthSchedule(0);
expect(await schedulesPage.getNthScheduleRow(0)).toHaveText(
await schedulesPage.completeNthSchedule(2);
await expect(schedulesPage.getNthScheduleRow(4)).toHaveText(
'Show completed schedules',
);
await expect(page).toHaveScreenshot(screenshotConfig(page));
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 1 addition & 9 deletions packages/desktop-client/src/components/ManageRules.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import React, {
useState,
useEffect,
useRef,
useCallback,
useMemo,
} from 'react';
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { pushModal } from 'loot-core/src/client/actions/modals';
Expand Down Expand Up @@ -116,7 +110,6 @@ function ManageRulesContent({ isModal, payeeId, setLoading }) {
);
let selectedInst = useSelected('manage-rules', allRules, []);
let [hoveredRule, setHoveredRule] = useState(null);
let tableRef = useRef(null);

async function loadRules() {
setLoading(true);
Expand Down Expand Up @@ -283,7 +276,6 @@ function ManageRulesContent({ isModal, payeeId, setLoading }) {
<View style={{ flex: 1 }}>
<RulesHeader />
<SimpleTable
ref={tableRef}
data={filteredRules}
loadMore={loadMore}
// Hide the last border of the item in the table
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { send } from 'loot-core/src/platform/client/fetch';
import * as monthUtils from 'loot-core/src/shared/months';
import { getScheduledAmount } from 'loot-core/src/shared/schedules';
import {
isPreviewId,
ungroupTransactions,
updateTransaction,
realizeTempTransactions,
Expand Down Expand Up @@ -70,10 +71,6 @@ const zIndices = { SECTION_HEADING: 10 };
let getPayeesById = memoizeOne(payees => groupById(payees));
let getAccountsById = memoizeOne(accounts => groupById(accounts));

function isPreviewId(id) {
return id.indexOf('preview/') !== -1;
}

function getDescriptionPretty(transaction, payee, transferAcct) {
let { amount } = transaction;

Expand Down Expand Up @@ -1043,7 +1040,9 @@ export class TransactionList extends Component {
}

sections.push({
id: transaction.date,
id: `${isPreviewId(transaction.id) ? 'preview/' : ''}${
transaction.date
}`,
date: transaction.date,
data: [],
});
Expand Down
32 changes: 24 additions & 8 deletions packages/desktop-client/src/util/versions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as Platform from 'loot-core/src/client/platform';

function parseSemanticVersion(versionString): [number, number, number] {
return versionString
.replace('v', '')
Expand All @@ -15,18 +17,32 @@ function cmpSemanticVersion(
return x[0] - y[0] || x[1] - y[1] || x[2] - y[2];
}

export async function getLatestVersion(): Promise<string> {
let response = await fetch(
'https://api.github.com/repos/actualbudget/actual/tags',
);
let json = await response.json();
let tags = json.map(t => t.name).concat([`v${window.Actual.ACTUAL_VERSION}`]);
tags.sort(cmpSemanticVersion);
export async function getLatestVersion(): Promise<string | 'unknown'> {
if (Platform.isPlaywright) {
return Promise.resolve('v99.9.9');
}

try {
let response = await fetch(
'https://api.github.com/repos/actualbudget/actual/tags',
);
let json = await response.json();
let tags = json
.map(t => t.name)
.concat([`v${window.Actual.ACTUAL_VERSION}`]);
tags.sort(cmpSemanticVersion);

return tags[tags.length - 1];
return tags[tags.length - 1];
} catch {
// Rate limit exceeded? Or perhaps Github is down?
return 'unknown';
}
}

export async function getIsOutdated(latestVersion: string): Promise<boolean> {
let clientVersion = window.Actual.ACTUAL_VERSION;
if (latestVersion === 'unknown') {
return Promise.resolve(false);
}
return cmpSemanticVersion(clientVersion, latestVersion) < 0;
}
110 changes: 110 additions & 0 deletions packages/loot-core/src/mocks/budget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,116 @@ export async function createTestBudget(handlers) {

await sheet.waitOnSpreadsheet();

// Create some schedules
await runMutator(() =>
batchMessages(async () => {
const account = accounts.find(acc => acc.name === 'Bank of America');

await runHandler(handlers['schedule/create'], {
schedule: {
name: 'Phone bills',
posts_transaction: false,
},
conditions: [
{
op: 'is',
field: 'payee',
value: payees.find(item => item.name === 'Dominion Power').id,
},
{
op: 'is',
field: 'account',
value: account.id,
},
{
op: 'is',
field: 'date',
value: {
start: monthUtils.currentDay(),
frequency: 'monthly',
patterns: [],
skipWeekend: false,
weekendSolveMode: 'after',
},
},
{ op: 'isapprox', field: 'amount', value: -12000 },
],
});

await runHandler(handlers['schedule/create'], {
schedule: {
name: 'Internet bill',
posts_transaction: false,
},
conditions: [
{
op: 'is',
field: 'payee',
value: payees.find(item => item.name === 'Fast Internet').id,
},
{
op: 'is',
field: 'account',
value: account.id,
},
{
op: 'is',
field: 'date',
value: monthUtils.subDays(monthUtils.currentDay(), 1),
},
{ op: 'isapprox', field: 'amount', value: -14000 },
],
});

await runHandler(handlers['schedule/create'], {
schedule: {
name: 'Wedding',
posts_transaction: false,
},
conditions: [
{
op: 'is',
field: 'date',
value: {
start: monthUtils.subDays(monthUtils.currentDay(), 3),
frequency: 'monthly',
patterns: [],
skipWeekend: false,
weekendSolveMode: 'after',
},
},
{ op: 'is', field: 'amount', value: -2700000 },
],
});

await runHandler(handlers['schedule/create'], {
schedule: {
name: 'Utilities',
posts_transaction: false,
},
conditions: [
{
op: 'is',
field: 'account',
value: account.id,
},
{
op: 'is',
field: 'date',
value: {
start: monthUtils.addDays(monthUtils.currentDay(), 1),
frequency: 'monthly',
patterns: [],
skipWeekend: false,
weekendSolveMode: 'after',
},
},
{ op: 'is', field: 'amount', value: -190000 },
],
});
}),
);

// Create a budget
await createBudget(accounts, payees, allGroups);
}
5 changes: 2 additions & 3 deletions packages/loot-core/src/server/schedules/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export async function createSchedule({
schedule = null,
conditions = [],
} = {}) {
let scheduleId = (schedule && schedule.id) || uuidv4();
let scheduleId = schedule?.id || uuidv4();

let { date: dateCond } = extractScheduleConds(conditions);
if (dateCond == null) {
Expand All @@ -235,8 +235,7 @@ export async function createSchedule({
}

// Create the rule here based on the info
let ruleId;
ruleId = await insertRule({
let ruleId = await insertRule({
stage: null,
conditionsOp: 'and',
conditions,
Expand Down
Loading

0 comments on commit 4410a71

Please sign in to comment.