diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ac050ff..01b910c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,10 @@ name: CI script -on: push +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] jobs: lint: @@ -37,4 +41,24 @@ jobs: run: vercel pull --yes --token=${{ secrets.VERCEL_AUTH_TOKEN }} - name: 📦 Build staging app artifacts - run: vercel build --token=${{ secrets.VERCEL_AUTH_TOKEN }} \ No newline at end of file + run: vercel build --token=${{ secrets.VERCEL_AUTH_TOKEN }} + + test-coverage: + name: SonarCloud + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: 🏗 Install dependencies + run: yarn + + - name: 📦 Test and coverage + run: yarn coverage + + - name: 📦 SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} \ No newline at end of file diff --git a/README.md b/README.md index 0783c96..ee195f9 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,13 @@


+
+ +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=liftlearning_P2Pix-Front-End&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=liftlearning_P2Pix-Front-End) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=liftlearning_P2Pix-Front-End&metric=coverage)](https://sonarcloud.io/summary/new_code?id=liftlearning_P2Pix-Front-End) + +
+ This application aims to create a democratic and secure solution for the purchase and sale of ERC20 tokens, through the PIX, integrating the functionalities of smart contracts (smart contracts) of the blockchain with a receipt by digital signature. Allowing the integration of national financial system transactions to public blockchains, dispensing with custody through intermediaries. # Table of Contents diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..42555d7 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,18 @@ +module.exports = { + presets: [ + [ + "@babel/preset-env", + { + modules: false, + }, + ], + ], + env: { + test: { + presets: [ + ["@babel/preset-env", { targets: { node: "current" } }], + "@babel/preset-typescript", + ], + }, + }, +}; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e69de29..0000000 diff --git a/package.json b/package.json index c3e1f11..0d122f3 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,13 @@ { "name": "p2pix-front-end", - "version": "0.0.0", + "version": "0.1.0", "scripts": { "start": "vite --host=0.0.0.0 --port 3000", "build": "run-p type-check build-only", "preview": "vite preview", + "test": "vitest", "serve": "vue-cli-service serve", + "coverage": "vitest run --coverage", "build-only": "vite build", "type-check": "vue-tsc --noEmit", "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --ignore-path .gitignore", @@ -25,27 +27,35 @@ "vue-router": "^4.1.5" }, "devDependencies": { + "@babel/preset-env": "^7.20.2", + "@babel/preset-typescript": "^7.18.6", + "@pinia/testing": "^0.0.14", "@rushstack/eslint-patch": "^1.1.4", "@types/crc": "^3.8.0", + "@types/jest": "^27.0.0", "@types/marked": "^4.0.8", "@types/node": "^16.11.68", "@types/qrcode": "^1.5.0", "@types/vue-markdown": "^2.2.1", "@vitejs/plugin-vue": "^3.1.2", "@vitejs/plugin-vue-jsx": "^2.0.1", + "@vitest/coverage-c8": "^0.28.2", "@vue/eslint-config-prettier": "^7.0.0", "@vue/eslint-config-typescript": "^11.0.0", + "@vue/test-utils": "^2.2.7", "@vue/tsconfig": "^0.1.3", "autoprefixer": "^10.4.12", "eslint": "^8.22.0", "eslint-plugin-vue": "^9.3.0", "ethers": "^5.7.2", + "jsdom": "^21.1.0", "npm-run-all": "^4.1.5", "postcss": "^8.4.18", "prettier": "^2.7.1", "tailwindcss": "^3.2.1", "typescript": "~4.7.4", "vite": "^3.1.8", + "vitest": "^0.28.1", "vue-tsc": "^1.0.8" } } diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..8166776 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,8 @@ +sonar.organization=liftlearning +sonar.projectKey=liftlearning_P2Pix-Front-End +sonar.sources=src/ + +sonar.javascript.lcov.reportPaths=coverage/lcov.info + +sonar.exclusions=dist/** +sonar.coverage.exclusions=**/*.spec.* \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 2dad8e1..cbdd5c7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,5 @@ - - diff --git a/src/assets/base.css b/src/assets/base.css index 43f68aa..f38d3a0 100644 --- a/src/assets/base.css +++ b/src/assets/base.css @@ -19,10 +19,7 @@ --vt-c-text-light-2: rgba(60, 60, 60, 0.66); --vt-c-text-dark-1: var(--vt-c-white); --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); -} -/* semantic color variables for this project */ -:root { --color-background: var(--vt-c-white); --color-background-soft: var(--vt-c-white-soft); --color-background-mute: var(--vt-c-white-mute); diff --git a/src/blockchain/__tests__/addresses.spec.ts b/src/blockchain/__tests__/addresses.spec.ts new file mode 100644 index 0000000..8bb306c --- /dev/null +++ b/src/blockchain/__tests__/addresses.spec.ts @@ -0,0 +1,110 @@ +import { expectTypeOf, it, expect } from "vitest"; +import { + getTokenAddress, + getP2PixAddress, + getProviderUrl, + isPossibleNetwork, + possibleChains, + network2Chain, +} from "../addresses"; + +import { setActivePinia, createPinia } from "pinia"; +import { NetworkEnum } from "@/model/NetworkEnum"; +import { useEtherStore } from "@/store/ether"; + +describe("addresses.ts types", () => { + it("My addresses.ts types work properly", () => { + expectTypeOf(getTokenAddress).toBeFunction(); + expectTypeOf(getP2PixAddress).toBeFunction(); + expectTypeOf(getProviderUrl).toBeFunction(); + expectTypeOf(isPossibleNetwork).toBeFunction(); + + expectTypeOf(possibleChains).toBeObject(); + expectTypeOf(network2Chain).toBeObject(); + }); +}); + +describe("addresses.ts functions", () => { + beforeEach(() => { + setActivePinia(createPinia()); + }); + + it("getTokenAddress Ethereum", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.ethereum); + expect(getTokenAddress()).toBe( + "0x294003F602c321627152c6b7DED3EAb5bEa853Ee" + ); + }); + + it("getTokenAddress Polygon", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.polygon); + expect(getTokenAddress()).toBe( + "0x294003F602c321627152c6b7DED3EAb5bEa853Ee" + ); + }); + + it("getTokenAddress Default", () => { + expect(getTokenAddress()).toBe( + "0x294003F602c321627152c6b7DED3EAb5bEa853Ee" + ); + }); + + it("getP2PixAddress Ethereum", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.ethereum); + expect(getP2PixAddress()).toBe( + "0x5f3EFA9A90532914545CEf527C530658af87e196" + ); + }); + + it("getP2PixAddress Polygon", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.polygon); + expect(getP2PixAddress()).toBe( + "0x5f3EFA9A90532914545CEf527C530658af87e196" + ); + }); + + it("getP2PixAddress Default", () => { + expect(getP2PixAddress()).toBe( + "0x5f3EFA9A90532914545CEf527C530658af87e196" + ); + }); + + it("getProviderUrl Ethereum", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.ethereum); + expect(getProviderUrl()).toBe(import.meta.env.VITE_GOERLI_API_URL); + }); + + it("getProviderUrl Polygon", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.polygon); + expect(getProviderUrl()).toBe(import.meta.env.VITE_MUMBAI_API_URL); + }); + + it("getProviderUrl Default", () => { + expect(getProviderUrl()).toBe(import.meta.env.VITE_GOERLI_API_URL); + }); + + it("isPossibleNetwork Returns", () => { + const etherStore = useEtherStore(); + etherStore.setNetworkName(NetworkEnum.ethereum); + expect(isPossibleNetwork("0x5")).toBe(true); + expect(isPossibleNetwork("5")).toBe(true); + expect(isPossibleNetwork("0x13881")).toBe(true); + expect(isPossibleNetwork("80001")).toBe(true); + + expect(isPossibleNetwork("")).toBe(false); + expect(isPossibleNetwork(" ")).toBe(false); + expect(isPossibleNetwork("0x55")).toBe(false); + }); +}); + +describe("addresses.ts Unset Store", () => { + it("getProviderUrl Unset", () => { + expect(getProviderUrl()).toBe(undefined); + }); +}); diff --git a/src/blockchain/events.ts b/src/blockchain/events.ts index f0242d0..0e5558e 100644 --- a/src/blockchain/events.ts +++ b/src/blockchain/events.ts @@ -55,7 +55,7 @@ const getValidDeposits = async ( const filterDeposits = p2pContract.filters.DepositAdded(null); const eventsDeposits = await p2pContract.queryFilter(filterDeposits); - p2pContract = getContract(); // get metamask provider contract + if (!contract) p2pContract = getContract(); // get metamask provider contract const depositList = await Promise.all( eventsDeposits.map(async (deposit) => { diff --git a/src/blockchain/wallet.ts b/src/blockchain/wallet.ts index f7175aa..4f8bf29 100644 --- a/src/blockchain/wallet.ts +++ b/src/blockchain/wallet.ts @@ -75,7 +75,7 @@ const listAllTransactionByWalletAddress = async ( const listReleaseTransactionByWalletAddress = async ( walletAddress: string ): Promise => { - const p2pContract = getContract(); + const p2pContract = getContract(true); const filterReleasedLocks = p2pContract.filters.LockReleased([walletAddress]); const eventsReleasedLocks = await p2pContract.queryFilter( diff --git a/src/components/BuyConfirmedComponent.vue b/src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue similarity index 94% rename from src/components/BuyConfirmedComponent.vue rename to src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue index e2ea805..90e284b 100644 --- a/src/components/BuyConfirmedComponent.vue +++ b/src/components/BuyConfirmedComponent/BuyConfirmedComponent.vue @@ -1,6 +1,6 @@