@@ -0,0 +1,220 @@
1+import { test, expect, Page } from '@playwright/test';
2+
3+async function logIn(page: Page) {
4+ await page.locator('input[type="url"]').tap();
5+ await page.locator('input[type="url"]').press('Control+a');
6+ await page.locator('input[type="url"]').fill('http://localhost:8000');
7+ await page.locator('input[type="email"]').tap();
8+ await page.locator('input[type="email"]').fill('test@example.com');
9+ await page.locator('input[type="password"]').tap();
10+ await page.locator('input[type="password"]').fill('Password123');
11+ await page.getByRole('button', { name: 'Log in' }).tap();
12+ await page.locator('.p-icon--spinner.u-animation--spin.spinner').waitFor({ state: "visible" })
13+ await page.locator('.p-icon--spinner.u-animation--spin.spinner').waitFor({ state: "hidden" })
14+}
15+
16+async function fillInLoginCipher(page: Page) {
17+ await page.locator('p:has-text("Entry name") input[type="text"]').tap();
18+ await page.locator('p:has-text("Entry name") input[type="text"]').fill('Test login entry');
19+ await page.locator('p:has-text("Username") input[type="text"]').tap();
20+ await page.locator('p:has-text("Username") input[type="text"]').fill('login_entry_username');
21+ await page.locator('input[type="text"]').nth(2).tap();
22+ await page.locator('input[type="text"]').nth(2).fill('Password123');
23+ await page.locator('input[type="url"]').tap();
24+ await page.locator('input[type="url"]').fill('https://example.com');
25+}
26+
27+async function fillInCardCipher(page: Page) {
28+ await page.locator('p:has-text("Entry name") input[type="text"]').tap();
29+ await page.locator('p:has-text("Entry name") input[type="text"]').fill('Test card');
30+ await page.locator('p:has-text("Card number") input[type="text"]').tap();
31+ await page.locator('p:has-text("Card number") input[type="text"]').fill('1234567890123456');
32+ await page.locator('p:has-text("Expiration date /") input[type="text"]').first().tap();
33+ await page.locator('p:has-text("Expiration date /") input[type="text"]').first().fill('01');
34+ await page.locator('p:has-text("Expiration date /") input[type="text"]').nth(1).tap();
35+ await page.locator('p:has-text("Expiration date /") input[type="text"]').nth(1).fill('01');
36+ await page.locator('p:has-text("CVV") input[type="text"]').tap();
37+ await page.locator('p:has-text("CVV") input[type="text"]').fill('123');
38+ await page.locator('p:has-text("Cardholder name") input[type="text"]').tap();
39+ await page.locator('p:has-text("Cardholder name") input[type="text"]').fill('Sampel Palnet');
40+}
41+
42+async function fillInNoteCipher(page: Page) {
43+ await page.locator('input[type="text"]').tap();
44+ await page.locator('input[type="text"]').fill('Secret note');
45+ await page.locator('textarea').tap();
46+ await page.locator('textarea').fill('This is a very secret note');
47+}
48+
49+async function fillInContractCipher(page: Page) {
50+ await page.locator('p:has-text("Entry name") input[type="text"]').tap();
51+ await page.locator('p:has-text("Entry name") input[type="text"]').fill('John Appleseed');
52+ await page.locator('p:has-text("First name") input[type="text"]').tap();
53+ await page.locator('p:has-text("First name") input[type="text"]').fill('John');
54+ await page.locator('p:has-text("Middle name") input[type="text"]').tap();
55+ await page.locator('p:has-text("Middle name") input[type="text"]').fill('Mathews');
56+ await page.locator('p:has-text("Last name") input[type="text"]').tap();
57+ await page.locator('p:has-text("Last name") input[type="text"]').fill('Appleseed');
58+ await page.locator('p:has-text("Username") input[type="text"]').tap();
59+ await page.locator('p:has-text("Username") input[type="text"]').fill('jappleseed');
60+ await page.locator('p:has-text("Company") input[type="text"]').tap();
61+ await page.locator('p:has-text("Company") input[type="text"]').fill('Very good building company');
62+ await page.locator('p:has-text("Social security number") input[type="number"]').tap();
63+ await page.locator('p:has-text("Social security number") input[type="number"]').fill('123456789');
64+ await page.locator('p:has-text("Passport number") input[type="number"]').tap();
65+ await page.locator('p:has-text("Passport number") input[type="number"]').fill('123456798');
66+ await page.locator('p:has-text("License Number") input[type="number"]').tap();
67+ await page.locator('p:has-text("License Number") input[type="number"]').fill('12345');
68+ await page.locator('input[type="email"]').tap();
69+ await page.locator('input[type="email"]').fill('john@example.com');
70+ await page.locator('input[type="tel"]').tap();
71+ await page.locator('input[type="tel"]').fill('123456789');
72+ await page.locator('p:has-text("Address line 1") input[type="text"]').tap();
73+ await page.locator('p:has-text("Address line 1") input[type="text"]').fill('Abc def');
74+ await page.locator('p:has-text("Address line 2") input[type="text"]').tap();
75+ await page.locator('p:has-text("Address line 2") input[type="text"]').fill('Ghijk Lmn');
76+}
77+
78+async function screenshot(page: Page) {
79+ await page.waitForLoadState("networkidle")
80+
81+ if (await page.locator('div.floating-notifications').isVisible()) {
82+ await page.locator("button.p-notification__close").tap()
83+ await screenshot(page)
84+ } else if (await page.locator('.p-icon--spinner.u-animation--spin.spinner').isVisible()) {
85+ await page.locator('.p-icon--spinner.u-animation--spin.spinner').waitFor({ state: "hidden" })
86+ await screenshot(page)
87+ } else {
88+ await expect.soft(page).toHaveScreenshot({ mask: [page.locator(".hide-in-test")], animations: "disabled", fullPage: true })
89+ }
90+}
91+
92+async function waitForNotification(page: Page) {
93+ await page.locator('div.floating-notifications').waitFor({ state: "visible" })
94+}
95+
96+
97+/**
98+ * Screenshots the very first (last edited) entry.
99+ */
100+function cipherPage(name: string) {
101+ test(name + " cipher page", async ({ page }) => {
102+ await logIn(page)
103+
104+ await page.locator('.cipher-row').first().tap()
105+
106+ await screenshot(page)
107+ })
108+}
109+
110+test.beforeEach(async ({ page }) => {
111+ await page.goto(`file://${__dirname}/../../build/all/app/install/index.html`);
112+})
113+
114+if (process.env.RECORD_TEST === "true") {
115+
116+ test('record', async ({ page }) => {
117+ await logIn(page)
118+ await page.pause()
119+ })
120+
121+} else {
122+ test('Login page', async ({ page }) => {
123+ await screenshot(page)
124+ });
125+
126+ test('Empty ciphers page', async ({ page }) => {
127+ await logIn(page)
128+
129+ await screenshot(page)
130+ })
131+
132+ test('Login entry page', async ({ page }) => {
133+ await logIn(page)
134+
135+ await page.getByRole('button').nth(2).tap();
136+ await page.getByRole('button', { name: 'Login' }).tap();
137+
138+ await screenshot(page)
139+
140+ await fillInLoginCipher(page)
141+
142+ await screenshot(page)
143+
144+ await page.getByRole('heading').locator('span').getByRole('button').tap();
145+
146+ await waitForNotification(page)
147+ });
148+
149+ cipherPage("Login")
150+
151+ test('Create Card entry page', async ({ page }) => {
152+ await logIn(page)
153+
154+ await page.getByRole('button').nth(2).tap();
155+ await page.getByRole('button', { name: 'Card' }).tap();
156+
157+ await screenshot(page)
158+
159+ await fillInCardCipher(page)
160+
161+ await screenshot(page)
162+
163+ await page.getByRole('heading').locator('span').getByRole('button').tap();
164+
165+ await waitForNotification(page)
166+ })
167+
168+ cipherPage("Card")
169+
170+ test('Create Note entry page', async ({ page }) => {
171+ await logIn(page)
172+
173+ await page.getByRole('button').nth(2).tap();
174+ await page.getByRole('button', { name: 'Note' }).tap();
175+
176+ await screenshot(page)
177+
178+ await fillInNoteCipher(page)
179+
180+ await screenshot(page)
181+
182+ await page.getByRole('heading').locator('span').getByRole('button').tap();
183+
184+ await waitForNotification(page)
185+ })
186+
187+ cipherPage("Note")
188+
189+ test('Create Contact entry page', async ({ page }) => {
190+ await logIn(page)
191+
192+ await page.getByRole('button').nth(2).tap();
193+ await page.getByRole('button', { name: 'Contact' }).tap();
194+
195+ await screenshot(page)
196+
197+ await fillInContractCipher(page)
198+
199+ await screenshot(page)
200+
201+ await page.getByRole('heading').locator('span').getByRole('button').tap();
202+
203+ await waitForNotification(page)
204+ })
205+
206+ cipherPage("Contact")
207+
208+ test('Filled ciphers page', async ({ page }) => {
209+ await logIn(page)
210+ await screenshot(page)
211+ })
212+
213+ test('Side bar', async ({ page }) => {
214+ await logIn(page)
215+
216+ await page.getByRole('button').nth(1).tap();
217+
218+ await screenshot(page)
219+ })
220+}