mirror of
https://github.com/frappe/books.git
synced 2024-11-08 14:50:56 +00:00
Merge pull request #674 from frappe/uitest
test: add some simple UI test, format files using prettier
This commit is contained in:
commit
a3590bbc5b
@ -50,6 +50,7 @@ module.exports = {
|
||||
],
|
||||
ignorePatterns: [
|
||||
'*.mjs',
|
||||
'uitest',
|
||||
'.eslintrc.js',
|
||||
'tailwind.config.js',
|
||||
'node_modules',
|
||||
|
@ -1,2 +1,5 @@
|
||||
# Rename 'frappe' to 'fyo' outside src
|
||||
32d282dc9c6f129807a1cf53eae47fc3602aa976
|
||||
32d282dc9c6f129807a1cf53eae47fc3602aa976
|
||||
|
||||
# Format files using prettier
|
||||
8c9d81d298dd08ae7acaf6de297aa30d95329778
|
5
.github/workflows/lint.yml
vendored
5
.github/workflows/lint.yml
vendored
@ -29,4 +29,7 @@ jobs:
|
||||
run: yarn
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
run: yarn lint
|
||||
|
||||
- name: Check Formatting
|
||||
run: yarn prettier --check .
|
||||
|
27
.github/workflows/test.yml
vendored
27
.github/workflows/test.yml
vendored
@ -28,5 +28,28 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Yarn Tests
|
||||
run: yarn test
|
||||
- name: Run Tests
|
||||
run: yarn test
|
||||
|
||||
setup_and_uitest:
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16.14.0'
|
||||
|
||||
- name: Set yarn version
|
||||
run: yarn set version 1.22.18
|
||||
|
||||
- name: Checkout Books
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install Dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build Source Files
|
||||
run: yarn build --nosign --nopackage
|
||||
|
||||
- name: Run UI Tests
|
||||
run: yarn uitest
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dbs
|
||||
/dist
|
||||
/notebook
|
||||
|
||||
|
@ -1 +1,3 @@
|
||||
**/types.ts
|
||||
**/types.ts
|
||||
**/dist_electron
|
||||
**/dummy/*.json
|
@ -97,7 +97,6 @@ couple of seconds to render this because of how dev mode works. Each file is
|
||||
individually served by the dev server. And there are many files that have to be
|
||||
sent.
|
||||
|
||||
|
||||
**Note: Debug Electron Main Process**
|
||||
|
||||
When in dev mode electron runs with the `--inspect` flag which allows an
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
assertDoesNotThrow,
|
||||
assertThrows,
|
||||
BaseMetaKey,
|
||||
getBuiltTestSchemaMap
|
||||
getBuiltTestSchemaMap,
|
||||
} from './helpers';
|
||||
|
||||
/**
|
||||
|
@ -16,11 +16,29 @@ const packageDirPath = path.join(root, 'dist_electron', 'bundled');
|
||||
const mainFileName = 'main.js';
|
||||
const commonConfig = getMainProcessCommonConfig(root);
|
||||
|
||||
const rawArgs = yargs(hideBin(process.argv))
|
||||
.option('nosign', {
|
||||
type: 'boolean',
|
||||
description: 'Run electron-builder without code signing',
|
||||
})
|
||||
.option('nopackage', {
|
||||
type: 'boolean',
|
||||
description: 'Only build the source files, electron-builder will not run',
|
||||
});
|
||||
|
||||
const argv = rawArgs.argv;
|
||||
if (argv.nosign) {
|
||||
process.env['CSC_IDENTITY_AUTO_DISCOVERY'] = false;
|
||||
}
|
||||
|
||||
updatePaths();
|
||||
await buildMainProcessSource();
|
||||
await buildRendererProcessSource();
|
||||
copyPackageJson();
|
||||
await packageApp();
|
||||
|
||||
if (!argv.nopackage) {
|
||||
await packageApp();
|
||||
}
|
||||
|
||||
function updatePaths() {
|
||||
fs.removeSync(buildDirPath);
|
||||
@ -117,8 +135,8 @@ function copyPackageJson() {
|
||||
* Packages the app using electron builder.
|
||||
*
|
||||
* Note: this also handles signing and notarization if the
|
||||
* appropriate flags are set.
|
||||
*
|
||||
* appropriate flags are set.
|
||||
*
|
||||
* Electron builder cli [commands](https://www.electron.build/cli)
|
||||
* are passed on as builderArgs.
|
||||
*/
|
||||
@ -127,11 +145,14 @@ async function packageApp() {
|
||||
'electron-builder/out/builder.js'
|
||||
);
|
||||
|
||||
const rawArgs = hideBin(process.argv);
|
||||
const builderArgs = yargs(rawArgs)
|
||||
const builderArgs = rawArgs
|
||||
.command(['build', '*'], 'Build', configureBuildCommand)
|
||||
.parse();
|
||||
|
||||
for (const opt of ['nosign', 'nopackage']) {
|
||||
delete builderArgs[opt];
|
||||
}
|
||||
|
||||
const buildOptions = {
|
||||
config: {
|
||||
directories: { output: packageDirPath, app: buildDirPath },
|
||||
|
@ -8,4 +8,4 @@ these are not to be edited.
|
||||
|
||||
The generated data has some randomness, there is a `baseCount` arg to the
|
||||
exported `setupDummyInstance` function, the number of transactions generated are
|
||||
always more than this.
|
||||
always more than this.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,3 @@
|
||||
|
||||
{
|
||||
"countryCode": "ae",
|
||||
"name": "U.A.E - Chart of Accounts",
|
||||
@ -464,4 +463,4 @@
|
||||
"rootType": "Equity"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -409,4 +409,4 @@
|
||||
"rootType": "Income"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -420,4 +420,4 @@
|
||||
"rootType": "Asset"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -832,4 +832,4 @@
|
||||
"rootType": "Income"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -684,4 +684,4 @@
|
||||
"rootType": "Income"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -173,4 +173,4 @@
|
||||
"rootType": "Liability"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -599,4 +599,4 @@
|
||||
"rootType": "Liability"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -491,4 +491,4 @@
|
||||
"rootType": "Liability"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -690,4 +690,4 @@
|
||||
"rootType": "Asset"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,4 +308,4 @@
|
||||
"rootType": "Liability"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,170 +1,170 @@
|
||||
{
|
||||
"Application of Funds (Assets)": {
|
||||
"Current Assets": {
|
||||
"Accounts Receivable": {
|
||||
"Debtors": {
|
||||
"accountType": "Receivable"
|
||||
}
|
||||
},
|
||||
"Bank Accounts": {
|
||||
"accountType": "Bank",
|
||||
"isGroup": true
|
||||
},
|
||||
"Cash In Hand": {
|
||||
"Cash": {
|
||||
"accountType": "Cash"
|
||||
},
|
||||
"accountType": "Cash"
|
||||
},
|
||||
"Loans and Advances (Assets)": {
|
||||
"isGroup": true
|
||||
},
|
||||
"Securities and Deposits": {
|
||||
"Earnest Money": {}
|
||||
},
|
||||
"Stock Assets": {
|
||||
"Stock In Hand": {
|
||||
"accountType": "Stock"
|
||||
},
|
||||
"accountType": "Stock"
|
||||
},
|
||||
"Tax Assets": {
|
||||
"isGroup": true
|
||||
}
|
||||
"Current Assets": {
|
||||
"Accounts Receivable": {
|
||||
"Debtors": {
|
||||
"accountType": "Receivable"
|
||||
}
|
||||
},
|
||||
"Fixed Assets": {
|
||||
"Capital Equipments": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Electronic Equipments": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Furnitures and Fixtures": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Office Equipments": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Plants and Machineries": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Buildings": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Softwares": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Accumulated Depreciation": {
|
||||
"accountType": "Accumulated Depreciation"
|
||||
}
|
||||
},
|
||||
"Investments": {
|
||||
"Bank Accounts": {
|
||||
"accountType": "Bank",
|
||||
"isGroup": true
|
||||
},
|
||||
"Temporary Accounts": {
|
||||
"Temporary Opening": {
|
||||
"accountType": "Temporary"
|
||||
}
|
||||
"Cash In Hand": {
|
||||
"Cash": {
|
||||
"accountType": "Cash"
|
||||
},
|
||||
"accountType": "Cash"
|
||||
},
|
||||
"rootType": "Asset"
|
||||
"Loans and Advances (Assets)": {
|
||||
"isGroup": true
|
||||
},
|
||||
"Securities and Deposits": {
|
||||
"Earnest Money": {}
|
||||
},
|
||||
"Stock Assets": {
|
||||
"Stock In Hand": {
|
||||
"accountType": "Stock"
|
||||
},
|
||||
"accountType": "Stock"
|
||||
},
|
||||
"Tax Assets": {
|
||||
"isGroup": true
|
||||
}
|
||||
},
|
||||
"Fixed Assets": {
|
||||
"Capital Equipments": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Electronic Equipments": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Furnitures and Fixtures": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Office Equipments": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Plants and Machineries": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Buildings": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Softwares": {
|
||||
"accountType": "Fixed Asset"
|
||||
},
|
||||
"Accumulated Depreciation": {
|
||||
"accountType": "Accumulated Depreciation"
|
||||
}
|
||||
},
|
||||
"Investments": {
|
||||
"isGroup": true
|
||||
},
|
||||
"Temporary Accounts": {
|
||||
"Temporary Opening": {
|
||||
"accountType": "Temporary"
|
||||
}
|
||||
},
|
||||
"rootType": "Asset"
|
||||
},
|
||||
"Expenses": {
|
||||
"Direct Expenses": {
|
||||
"Stock Expenses": {
|
||||
"Cost of Goods Sold": {
|
||||
"accountType": "Cost of Goods Sold"
|
||||
},
|
||||
"Expenses Included In Valuation": {
|
||||
"accountType": "Expenses Included In Valuation"
|
||||
},
|
||||
"Stock Adjustment": {
|
||||
"accountType": "Stock Adjustment"
|
||||
}
|
||||
}
|
||||
"Direct Expenses": {
|
||||
"Stock Expenses": {
|
||||
"Cost of Goods Sold": {
|
||||
"accountType": "Cost of Goods Sold"
|
||||
},
|
||||
"Expenses Included In Valuation": {
|
||||
"accountType": "Expenses Included In Valuation"
|
||||
},
|
||||
"Stock Adjustment": {
|
||||
"accountType": "Stock Adjustment"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Indirect Expenses": {
|
||||
"Administrative Expenses": {},
|
||||
"Commission on Sales": {},
|
||||
"Depreciation": {
|
||||
"accountType": "Depreciation"
|
||||
},
|
||||
"Indirect Expenses": {
|
||||
"Administrative Expenses": {},
|
||||
"Commission on Sales": {},
|
||||
"Depreciation": {
|
||||
"accountType": "Depreciation"
|
||||
},
|
||||
"Entertainment Expenses": {},
|
||||
"Freight and Forwarding Charges": {
|
||||
"accountType": "Chargeable"
|
||||
},
|
||||
"Legal Expenses": {},
|
||||
"Marketing Expenses": {
|
||||
"accountType": "Chargeable"
|
||||
},
|
||||
"Miscellaneous Expenses": {
|
||||
"accountType": "Chargeable"
|
||||
},
|
||||
"Office Maintenance Expenses": {},
|
||||
"Office Rent": {},
|
||||
"Postal Expenses": {},
|
||||
"Print and Stationery": {},
|
||||
"Round Off": {
|
||||
"accountType": "Round Off"
|
||||
},
|
||||
"Salary": {},
|
||||
"Sales Expenses": {},
|
||||
"Telephone Expenses": {},
|
||||
"Travel Expenses": {},
|
||||
"Utility Expenses": {},
|
||||
"Write Off": {},
|
||||
"Exchange Gain/Loss": {},
|
||||
"Gain/Loss on Asset Disposal": {}
|
||||
"Entertainment Expenses": {},
|
||||
"Freight and Forwarding Charges": {
|
||||
"accountType": "Chargeable"
|
||||
},
|
||||
"rootType": "Expense"
|
||||
"Legal Expenses": {},
|
||||
"Marketing Expenses": {
|
||||
"accountType": "Chargeable"
|
||||
},
|
||||
"Miscellaneous Expenses": {
|
||||
"accountType": "Chargeable"
|
||||
},
|
||||
"Office Maintenance Expenses": {},
|
||||
"Office Rent": {},
|
||||
"Postal Expenses": {},
|
||||
"Print and Stationery": {},
|
||||
"Round Off": {
|
||||
"accountType": "Round Off"
|
||||
},
|
||||
"Salary": {},
|
||||
"Sales Expenses": {},
|
||||
"Telephone Expenses": {},
|
||||
"Travel Expenses": {},
|
||||
"Utility Expenses": {},
|
||||
"Write Off": {},
|
||||
"Exchange Gain/Loss": {},
|
||||
"Gain/Loss on Asset Disposal": {}
|
||||
},
|
||||
"rootType": "Expense"
|
||||
},
|
||||
"Income": {
|
||||
"Direct Income": {
|
||||
"Sales": {},
|
||||
"Service": {}
|
||||
},
|
||||
"Indirect Income": {
|
||||
"isGroup": true
|
||||
},
|
||||
"rootType": "Income"
|
||||
"Direct Income": {
|
||||
"Sales": {},
|
||||
"Service": {}
|
||||
},
|
||||
"Indirect Income": {
|
||||
"isGroup": true
|
||||
},
|
||||
"rootType": "Income"
|
||||
},
|
||||
"Source of Funds (Liabilities)": {
|
||||
"Current Liabilities": {
|
||||
"Accounts Payable": {
|
||||
"Creditors": {
|
||||
"accountType": "Payable"
|
||||
},
|
||||
"Payroll Payable": {}
|
||||
},
|
||||
"Stock Liabilities": {
|
||||
"Stock Received But Not Billed": {
|
||||
"accountType": "Stock Received But Not Billed"
|
||||
}
|
||||
},
|
||||
"Duties and Taxes": {
|
||||
"accountType": "Tax",
|
||||
"isGroup": true
|
||||
},
|
||||
"Loans (Liabilities)": {
|
||||
"Secured Loans": {},
|
||||
"Unsecured Loans": {},
|
||||
"Bank Overdraft Account": {}
|
||||
}
|
||||
"Current Liabilities": {
|
||||
"Accounts Payable": {
|
||||
"Creditors": {
|
||||
"accountType": "Payable"
|
||||
},
|
||||
"Payroll Payable": {}
|
||||
},
|
||||
"rootType": "Liability"
|
||||
"Stock Liabilities": {
|
||||
"Stock Received But Not Billed": {
|
||||
"accountType": "Stock Received But Not Billed"
|
||||
}
|
||||
},
|
||||
"Duties and Taxes": {
|
||||
"accountType": "Tax",
|
||||
"isGroup": true
|
||||
},
|
||||
"Loans (Liabilities)": {
|
||||
"Secured Loans": {},
|
||||
"Unsecured Loans": {},
|
||||
"Bank Overdraft Account": {}
|
||||
}
|
||||
},
|
||||
"rootType": "Liability"
|
||||
},
|
||||
"Equity": {
|
||||
"Capital Stock": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"Dividends Paid": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"Opening Balance Equity": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"Retained Earnings": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"rootType": "Equity"
|
||||
"Capital Stock": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"Dividends Paid": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"Opening Balance Equity": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"Retained Earnings": {
|
||||
"accountType": "Equity"
|
||||
},
|
||||
"rootType": "Equity"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ located in `model/doc.ts`, all classes exported from `books/models` extend this.
|
||||
- **Model**: the controller class that extends the `Doc` class, or the `Doc`
|
||||
class itself (if a specific controller doesn't exist).
|
||||
- **doc** (not `Doc`): instance of a Model, i.e. what has the data.
|
||||
|
||||
|
||||
If you are confused, I understand.
|
||||
|
||||
## Initialization
|
||||
@ -102,6 +102,7 @@ strings globally since this will be evaluated before the map is loaded.
|
||||
|
||||
The doc and db handlers have observers (instances of `Observable`) as
|
||||
properties, these can be accessed using
|
||||
|
||||
- `fyo.db.observer`
|
||||
- `fyo.doc.observer`
|
||||
|
||||
@ -109,4 +110,4 @@ The purpose of the observer is to trigger registered callbacks when some `doc`
|
||||
operation or `db` operation takes place.
|
||||
|
||||
These are schema level observers i.e. they are registered like so:
|
||||
`method:schemaName`. The callbacks receive args passed to the functions.
|
||||
`method:schemaName`. The callbacks receive args passed to the functions.
|
||||
|
@ -15,7 +15,9 @@
|
||||
"script:translate": "scripts/runner.sh scripts/generateTranslations.ts",
|
||||
"script:profile": "scripts/profile.sh",
|
||||
"test": "scripts/test.sh",
|
||||
"lint": "eslint . --ext ts,vue"
|
||||
"uitest": "node uitest/index.mjs | tap-spec",
|
||||
"lint": "eslint . --ext ts,vue",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.4.2",
|
||||
@ -44,7 +46,6 @@
|
||||
"@types/electron-devtools-installer": "^2.2.0",
|
||||
"@types/lodash": "^4.14.179",
|
||||
"@types/luxon": "^2.3.1",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^17.0.23",
|
||||
"@types/node-fetch": "^2.6.1",
|
||||
"@types/tape": "^4.13.2",
|
||||
@ -65,6 +66,7 @@
|
||||
"eslint-plugin-vue": "^9.15.0",
|
||||
"execa": "^7.1.1",
|
||||
"fs-extra": "^11.1.1",
|
||||
"playwright": "^1.35.1",
|
||||
"postcss": "^8",
|
||||
"prettier": "^2.4.1",
|
||||
"tailwindcss": "npm:@tailwindcss/postcss7-compat",
|
||||
|
@ -1,3 +1,3 @@
|
||||
module.exports = {
|
||||
plugins: [require('tailwindcss'), require('autoprefixer')]
|
||||
plugins: [require('tailwindcss'), require('autoprefixer')],
|
||||
};
|
||||
|
@ -17,7 +17,7 @@ There are a few types of schemas:
|
||||
- **Subclass**: Schemas that have an `"extends"` field on them, the value of which
|
||||
points to an Abstract schema.
|
||||
- **Complete**: Schemas which are neither abstract nor stub.
|
||||
|
||||
|
||||
For more detail on the meta structure of the schema check `books/schemas/types.ts`.
|
||||
|
||||
## Final Schema
|
||||
@ -40,4 +40,4 @@ In all the schemas, the `"name"` field/column is the primary key. If it isn't
|
||||
explicitly added, the schema builder will add it in.
|
||||
|
||||
The following schema fields will be implicitly translated by the frontend:
|
||||
`"label"`, `"description"`, and `"placeholder"`, irrespective of nesting.
|
||||
`"label"`, `"description"`, and `"placeholder"`, irrespective of nesting.
|
||||
|
@ -21,4 +21,4 @@
|
||||
],
|
||||
"keywordFields": ["name"],
|
||||
"quickEditFields": ["details"]
|
||||
}
|
||||
}
|
||||
|
@ -21,4 +21,4 @@
|
||||
}
|
||||
],
|
||||
"tableFields": ["account", "rate"]
|
||||
}
|
||||
}
|
||||
|
@ -2,4 +2,4 @@
|
||||
"name": "Customer",
|
||||
"label": "Customer",
|
||||
"extends": "Party"
|
||||
}
|
||||
}
|
||||
|
@ -6,14 +6,14 @@ import {
|
||||
cleanSchemas,
|
||||
getAbstractCombinedSchemas,
|
||||
getRegionalCombinedSchemas,
|
||||
setSchemaNameOnFields
|
||||
setSchemaNameOnFields,
|
||||
} from '../index';
|
||||
import { metaSchemas } from '../schemas';
|
||||
import {
|
||||
everyFieldExists,
|
||||
getTestSchemaMap,
|
||||
someFieldExists,
|
||||
subtract
|
||||
subtract,
|
||||
} from './helpers';
|
||||
|
||||
const { appSchemaMap, regionalSchemaMap } = getTestSchemaMap();
|
||||
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<button
|
||||
class="rounded-md flex justify-center items-center text-sm"
|
||||
:disabled="disabled"
|
||||
:class="_class"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
|
@ -262,15 +262,15 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
if (label && this.suggestions.length === 0) {
|
||||
if (this.suggestions.length === 0) {
|
||||
this.triggerChange(label);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
label &&
|
||||
!this.suggestions.map(({ label }) => label).includes(label)
|
||||
) {
|
||||
const suggestion = this.suggestions.find((s) => s.label === label);
|
||||
if (suggestion) {
|
||||
this.setSuggestion(suggestion);
|
||||
} else {
|
||||
const suggestions = await this.getSuggestions(label);
|
||||
this.setSuggestion(suggestions[0]);
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
"
|
||||
>
|
||||
<h6
|
||||
data-testid="company-name"
|
||||
class="
|
||||
font-semibold
|
||||
whitespace-nowrap
|
||||
@ -115,6 +116,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
data-testid="change-db"
|
||||
class="
|
||||
flex
|
||||
text-sm text-gray-600
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
<!-- New File (Blue Icon) -->
|
||||
<div
|
||||
data-testid="create-new-file"
|
||||
class="px-4 h-row-largest flex flex-row items-center gap-4 p-2"
|
||||
:class="creatingDemo ? '' : 'hover:bg-gray-50 cursor-pointer'"
|
||||
@click="newDatabase"
|
||||
|
@ -60,6 +60,7 @@
|
||||
<Button
|
||||
type="primary"
|
||||
class="w-24"
|
||||
data-testid="submit-button"
|
||||
:disabled="!areAllValuesFilled || loading"
|
||||
@click="submit"
|
||||
>{{ t`Submit` }}</Button
|
||||
|
@ -141,7 +141,7 @@ export async function getSavePath(name: string, extention: string) {
|
||||
const canceled = response.canceled;
|
||||
let filePath = response.filePath;
|
||||
|
||||
if (filePath && !filePath.endsWith(extention)) {
|
||||
if (filePath && !filePath.endsWith(extention) && filePath !== ':memory:') {
|
||||
filePath = `${filePath}.${extention}`;
|
||||
}
|
||||
|
||||
|
@ -64,4 +64,4 @@ test('import SalesInvoices', async (t) => {
|
||||
);
|
||||
});
|
||||
|
||||
closeTestFyo(fyo, __filename);
|
||||
closeTestFyo(fyo, __filename);
|
||||
|
@ -6,7 +6,7 @@ import { getValueMapFromList } from 'utils';
|
||||
import {
|
||||
getTestDbPath,
|
||||
getTestFyo,
|
||||
getTestSetupWizardOptions
|
||||
getTestSetupWizardOptions,
|
||||
} from './helpers';
|
||||
|
||||
const dbPath = getTestDbPath();
|
||||
|
88
uitest/index.mjs
Normal file
88
uitest/index.mjs
Normal file
@ -0,0 +1,88 @@
|
||||
import path from 'path';
|
||||
import { _electron } from 'playwright';
|
||||
import { fileURLToPath } from 'url';
|
||||
import test from 'tape';
|
||||
|
||||
const dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.join(dirname, '..');
|
||||
const appSourcePath = path.join(root, 'dist_electron', 'build', 'main.js');
|
||||
|
||||
(async function run() {
|
||||
const electronApp = await _electron.launch({ args: [appSourcePath] });
|
||||
const window = await electronApp.firstWindow();
|
||||
window.setDefaultTimeout(60_000);
|
||||
|
||||
test('load app', async (t) => {
|
||||
t.equal(await window.title(), 'Frappe Books', 'title matches');
|
||||
|
||||
await new Promise((r) => window.once('load', () => r()));
|
||||
t.ok(true, 'window has loaded');
|
||||
});
|
||||
|
||||
test('navigate to database selector', async (t) => {
|
||||
/**
|
||||
* When running on local, Frappe Books will open
|
||||
* the last selected database.
|
||||
*/
|
||||
const changeDb = window.getByTestId('change-db');
|
||||
const createNew = window.getByTestId('create-new-file');
|
||||
|
||||
const changeDbPromise = changeDb
|
||||
.waitFor({ state: 'visible' })
|
||||
.then(() => 'change-db');
|
||||
const createNewPromise = createNew
|
||||
.waitFor({ state: 'visible' })
|
||||
.then(() => 'create-new-file');
|
||||
|
||||
const el = await Promise.race([changeDbPromise, createNewPromise]);
|
||||
if (el === 'change-db') {
|
||||
await changeDb.click();
|
||||
await createNewPromise;
|
||||
}
|
||||
|
||||
t.ok(await createNew.isVisible(), 'create new is visible');
|
||||
});
|
||||
|
||||
test('fill setup form', async (t) => {
|
||||
await electronApp.evaluate(({ dialog }, filePath) => {
|
||||
dialog.showSaveDialog = () =>
|
||||
Promise.resolve({ canceled: false, filePath });
|
||||
}, ':memory:');
|
||||
await window.getByTestId('create-new-file').click();
|
||||
await window.getByTestId('submit-button').waitFor();
|
||||
|
||||
t.equal(
|
||||
await window.getByTestId('submit-button').isDisabled(),
|
||||
true,
|
||||
'submit button is disabled before form fill'
|
||||
);
|
||||
|
||||
await window.getByPlaceholder('Company Name').fill('Test Company');
|
||||
await window.getByPlaceholder('John Doe').fill('Test Owner');
|
||||
await window.getByPlaceholder('john@doe.com').fill('test@example.com');
|
||||
await window.getByPlaceholder('Select Country').fill('India');
|
||||
await window.getByPlaceholder('Select Country').blur();
|
||||
await window.getByPlaceholder('Prime Bank').fill('Test Bank');
|
||||
await window.getByPlaceholder('Prime Bank').blur();
|
||||
|
||||
t.equal(
|
||||
await window.getByTestId('submit-button').isDisabled(),
|
||||
false,
|
||||
'submit button enabled after form fill'
|
||||
);
|
||||
});
|
||||
|
||||
test('create new instance', async (t) => {
|
||||
await window.getByTestId('submit-button').click();
|
||||
t.equal(
|
||||
await window.getByTestId('company-name').innerText(),
|
||||
'Test Company',
|
||||
'new instance created, company name found in sidebar'
|
||||
);
|
||||
});
|
||||
|
||||
test('close app', async (t) => {
|
||||
await electronApp.close();
|
||||
t.ok(true, 'app closed without errors');
|
||||
});
|
||||
})();
|
@ -2,12 +2,11 @@ import vue from '@vitejs/plugin-vue';
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
|
||||
/**
|
||||
* This vite config file is used only for dev mode, i.e.
|
||||
* to create a serve build modules of the source code
|
||||
* which will be rendered by electron.
|
||||
*
|
||||
*
|
||||
* For building the project, vite is used programmatically
|
||||
* see build/scripts/build.mjs for this.
|
||||
*/
|
||||
|
17
yarn.lock
17
yarn.lock
@ -651,11 +651,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.3.1.tgz#e34763178b46232e4c5f079f1706e18692415519"
|
||||
integrity sha512-nAPUltOT28fal2eDZz8yyzNhBjHw1NEymFBP7Q9iCShqpflWPybxHbD7pw/46jQmT+HXOy1QN5hNTms8MOTlOQ==
|
||||
|
||||
"@types/mocha@^9.1.0":
|
||||
version "9.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.0.tgz#baf17ab2cca3fcce2d322ebc30454bff487efad5"
|
||||
integrity sha512-QCWHkbMv4Y5U9oW10Uxbr45qMMSzl4OzijsozynUAgx3kEHUdXB00udx2dWDQ7f2TU2a2uuiFaRZjCe3unPpeg==
|
||||
|
||||
"@types/ms@*":
|
||||
version "0.7.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
||||
@ -4484,6 +4479,18 @@ pkg-up@^3.1.0:
|
||||
dependencies:
|
||||
find-up "^3.0.0"
|
||||
|
||||
playwright-core@1.35.1:
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.35.1.tgz#52c1e6ffaa6a8c29de1a5bdf8cce0ce290ffb81d"
|
||||
integrity sha512-pNXb6CQ7OqmGDRspEjlxE49w+4YtR6a3X6mT1hZXeJHWmsEz7SunmvZeiG/+y1yyMZdHnnn73WKYdtV1er0Xyg==
|
||||
|
||||
playwright@^1.35.1:
|
||||
version "1.35.1"
|
||||
resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.35.1.tgz#f991d0c76ae517d4a0023d9428b09d19d5e87128"
|
||||
integrity sha512-NbwBeGJLu5m7VGM0+xtlmLAH9VUfWwYOhUi/lSEDyGg46r1CA9RWlvoc5yywxR9AzQb0mOCm7bWtOXV7/w43ZA==
|
||||
dependencies:
|
||||
playwright-core "1.35.1"
|
||||
|
||||
plist@^3.0.4, plist@^3.0.5:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.6.tgz#7cfb68a856a7834bca6dbfe3218eb9c7740145d3"
|
||||
|
Loading…
Reference in New Issue
Block a user