refactor: split
This commit is contained in:
@@ -0,0 +1,866 @@
|
||||
const {test, expect} = require('@playwright/test')
|
||||
|
||||
const {
|
||||
apiKeyHeaders,
|
||||
clearMirror,
|
||||
createAccount,
|
||||
createWallet,
|
||||
decodePayment,
|
||||
expectStatus,
|
||||
fetchManifest,
|
||||
getPayment,
|
||||
getPayments,
|
||||
getWallet,
|
||||
initServer,
|
||||
jsonRequest,
|
||||
latestRelease,
|
||||
loginAdmin,
|
||||
lnurlScan,
|
||||
mirrorUrl,
|
||||
pageStatus,
|
||||
pollPayment,
|
||||
pollWalletBalance,
|
||||
responseJson,
|
||||
textRequest,
|
||||
topUpWallet,
|
||||
uninstallExtension
|
||||
} = require('./helpers')
|
||||
|
||||
const state = {
|
||||
baseURL: null,
|
||||
adminContext: null,
|
||||
adminWallet: null,
|
||||
adminSession: null,
|
||||
extensionById: null,
|
||||
contextFactory: null
|
||||
}
|
||||
|
||||
const contexts = []
|
||||
const browserContexts = []
|
||||
|
||||
async function newContext() {
|
||||
const context = await state.contextFactory.newContext({
|
||||
baseURL: state.baseURL,
|
||||
extraHTTPHeaders: {
|
||||
Accept: 'application/json, text/plain, */*'
|
||||
}
|
||||
})
|
||||
contexts.push(context)
|
||||
return context
|
||||
}
|
||||
|
||||
async function newUser(name) {
|
||||
const context = await newContext()
|
||||
const account = await createAccount(context, `${name}-${Date.now()}`)
|
||||
return {context, ...account}
|
||||
}
|
||||
|
||||
async function newBrowserSession(browser, account) {
|
||||
const uiContext = await browser.newContext({baseURL: state.baseURL})
|
||||
browserContexts.push(uiContext)
|
||||
if (account?.userId) {
|
||||
await textRequest(uiContext.request, 'get', '/')
|
||||
await jsonRequest(uiContext.request, 'post', '/api/v1/auth/usr', {
|
||||
data: {usr: account.userId}
|
||||
})
|
||||
} else {
|
||||
await loginAdmin(uiContext.request)
|
||||
}
|
||||
const page = await uiContext.newPage()
|
||||
page.setDefaultTimeout(45_000)
|
||||
return {uiContext, page}
|
||||
}
|
||||
|
||||
async function newUserWithUi(browser, name) {
|
||||
const user = await newUser(name)
|
||||
return {...user, ...(await newBrowserSession(browser, user))}
|
||||
}
|
||||
|
||||
async function getAdminSession(browser) {
|
||||
if (!state.adminSession) {
|
||||
state.adminSession = {
|
||||
...state.adminWallet,
|
||||
...(await newBrowserSession(browser))
|
||||
}
|
||||
}
|
||||
return state.adminSession
|
||||
}
|
||||
|
||||
function extensionName(extensionId) {
|
||||
return state.extensionById?.get(extensionId)?.name || extensionId
|
||||
}
|
||||
|
||||
async function refreshExtensionCatalog(context = state.adminContext) {
|
||||
const extensions = await jsonRequest(context, 'get', '/api/v1/extension')
|
||||
for (const extension of extensions) {
|
||||
const id = extension.id || extension.code
|
||||
if (id) {
|
||||
state.extensionById.set(id, {
|
||||
id,
|
||||
name: extension.name || extension.title || id
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function responsePath(response) {
|
||||
return new URL(response.url()).pathname
|
||||
}
|
||||
|
||||
function responseMatches(response, method, path) {
|
||||
return (
|
||||
response.request().method() === method && responsePath(response) === path
|
||||
)
|
||||
}
|
||||
|
||||
async function clickAndCheckResponse(
|
||||
page,
|
||||
method,
|
||||
path,
|
||||
action,
|
||||
expected = 200,
|
||||
timeout = 45_000
|
||||
) {
|
||||
const responsePromise = page.waitForResponse(
|
||||
response => responseMatches(response, method, path),
|
||||
{timeout}
|
||||
)
|
||||
await action()
|
||||
const response = await responsePromise
|
||||
await expectStatus(response, expected, `${method} ${path}`)
|
||||
return response
|
||||
}
|
||||
|
||||
async function clickAndGetJsonResponse(
|
||||
page,
|
||||
method,
|
||||
path,
|
||||
action,
|
||||
expected = 200
|
||||
) {
|
||||
const response = await clickAndCheckResponse(
|
||||
page,
|
||||
method,
|
||||
path,
|
||||
action,
|
||||
expected
|
||||
)
|
||||
return responseJson(response)
|
||||
}
|
||||
|
||||
async function gotoPage(page, path, expected = 200) {
|
||||
const response = await page.goto(path)
|
||||
if (response) {
|
||||
await expectStatus(response, expected, `GET ${path}`)
|
||||
}
|
||||
await page.waitForFunction(() => window.LNbits && window.g)
|
||||
const credentialsButton = page.getByRole('button', {name: /i understand/i})
|
||||
if (await credentialsButton.isVisible({timeout: 1000}).catch(() => false)) {
|
||||
await credentialsButton.click()
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
async function gotoWallet(session, walletId = session.walletId) {
|
||||
await gotoPage(session.page, `/wallet/${walletId}`)
|
||||
await expect(
|
||||
session.page.getByRole('button', {name: /receive/i})
|
||||
).toBeVisible()
|
||||
}
|
||||
|
||||
async function fillQuasarField(scope, label, value) {
|
||||
const field = scope
|
||||
.locator('.q-field')
|
||||
.filter({hasText: label})
|
||||
.locator('input, textarea')
|
||||
.first()
|
||||
await field.fill(String(value))
|
||||
}
|
||||
|
||||
async function createInvoiceViaUi(session, amount, memo) {
|
||||
await gotoWallet(session)
|
||||
await session.page.getByRole('button', {name: /receive/i}).click()
|
||||
const dialog = session.page
|
||||
.locator('.q-dialog')
|
||||
.filter({hasText: 'Create Invoice'})
|
||||
.last()
|
||||
await fillQuasarField(dialog, 'Amount (sat)', amount)
|
||||
await fillQuasarField(dialog, 'Memo', memo)
|
||||
const invoice = await clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'POST',
|
||||
'/api/v1/payments',
|
||||
() => dialog.getByRole('button', {name: /create invoice/i}).click(),
|
||||
[200, 201]
|
||||
)
|
||||
expect(invoice.bolt11).toBeTruthy()
|
||||
return invoice
|
||||
}
|
||||
|
||||
async function payInvoiceViaUi(session, bolt11, expected = 201) {
|
||||
await gotoWallet(session)
|
||||
await session.page.getByRole('button', {name: /send/i}).click()
|
||||
const dialog = session.page.locator('.q-dialog').last()
|
||||
await fillQuasarField(dialog, 'Paste an invoice', bolt11)
|
||||
await dialog.getByRole('button', {name: /read/i}).click()
|
||||
await expect(dialog.getByRole('button', {name: /^pay$/i})).toBeVisible()
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'POST',
|
||||
'/api/v1/payments',
|
||||
() => dialog.getByRole('button', {name: /^pay$/i}).click(),
|
||||
expected
|
||||
)
|
||||
}
|
||||
|
||||
async function payLnurlViaUi(session, lnurl, amountMsat, comment) {
|
||||
await gotoWallet(session)
|
||||
await session.page.getByRole('button', {name: /send/i}).click()
|
||||
const dialog = session.page.locator('.q-dialog').last()
|
||||
await fillQuasarField(dialog, 'Paste an invoice', lnurl)
|
||||
await clickAndCheckResponse(session.page, 'POST', '/api/v1/lnurlscan', () =>
|
||||
dialog.getByRole('button', {name: /read/i}).click()
|
||||
)
|
||||
await fillQuasarField(dialog, 'Amount (sat)', amountMsat / 1000)
|
||||
if (comment) {
|
||||
await fillQuasarField(dialog, 'Comment (optional)', comment)
|
||||
}
|
||||
const payment = await clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'POST',
|
||||
'/api/v1/payments/lnurl',
|
||||
() => dialog.getByRole('button', {name: /^send$/i}).click()
|
||||
)
|
||||
expect(payment.payment_hash).toBeTruthy()
|
||||
return payment
|
||||
}
|
||||
|
||||
async function withdrawLnurlViaUi(
|
||||
session,
|
||||
lnurl,
|
||||
amount = 10,
|
||||
memo = 'withdraw 1',
|
||||
walletId = session.walletId
|
||||
) {
|
||||
await gotoWallet(session, walletId)
|
||||
await session.page.getByRole('button', {name: /send/i}).click()
|
||||
const scanDialog = session.page.locator('.q-dialog').last()
|
||||
await fillQuasarField(scanDialog, 'Paste an invoice', lnurl)
|
||||
await clickAndCheckResponse(session.page, 'POST', '/api/v1/lnurlscan', () =>
|
||||
scanDialog.getByRole('button', {name: /read/i}).click()
|
||||
)
|
||||
const withdrawDialog = session.page
|
||||
.locator('.q-dialog')
|
||||
.filter({hasText: 'Withdraw from'})
|
||||
.last()
|
||||
await fillQuasarField(withdrawDialog, 'Amount (sat)', amount)
|
||||
await fillQuasarField(withdrawDialog, 'Memo', memo)
|
||||
const payment = await clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'POST',
|
||||
'/api/v1/payments',
|
||||
() => withdrawDialog.getByRole('button', {name: /withdraw from/i}).click(),
|
||||
[200, 201]
|
||||
)
|
||||
expect(payment.payment_hash).toBeTruthy()
|
||||
return payment
|
||||
}
|
||||
|
||||
async function openExtensionsPage(session, tab = 'installed') {
|
||||
const extensionsLoaded = session.page
|
||||
.waitForResponse(response =>
|
||||
responseMatches(response, 'GET', '/api/v1/extension')
|
||||
)
|
||||
.catch(() => null)
|
||||
await gotoPage(session.page, '/extensions')
|
||||
await extensionsLoaded
|
||||
await session.page.waitForLoadState('networkidle').catch(() => null)
|
||||
await session.page.getByLabel(/search extensions/i).waitFor()
|
||||
const tabButton = session.page.getByRole('tab', {
|
||||
name: new RegExp(`^${tab}$`, 'i')
|
||||
})
|
||||
await tabButton.click()
|
||||
await expect(tabButton).toHaveAttribute('aria-selected', 'true')
|
||||
}
|
||||
|
||||
async function findExtensionCard(session, extensionId, tab = 'installed') {
|
||||
await openExtensionsPage(session, tab)
|
||||
const name = extensionName(extensionId)
|
||||
await session.page.getByLabel(/search extensions/i).fill(name)
|
||||
const card = session.page
|
||||
.locator('.q-card')
|
||||
.filter({
|
||||
has: session.page.locator('.text-h5').filter({
|
||||
hasText: new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`)
|
||||
})
|
||||
})
|
||||
.first()
|
||||
await expect(card).toBeVisible()
|
||||
return card
|
||||
}
|
||||
|
||||
async function openExtensionManager(session, extensionId, tab = 'installed') {
|
||||
const card = await findExtensionCard(session, extensionId, tab)
|
||||
await clickAndCheckResponse(
|
||||
session.page,
|
||||
'GET',
|
||||
`/api/v1/extension/${extensionId}/releases`,
|
||||
() => card.getByRole('button', {name: /manage/i}).click()
|
||||
)
|
||||
const dialog = session.page.locator('.q-dialog').filter({hasText: 'Releases'})
|
||||
await expect(dialog.last()).toBeVisible()
|
||||
return dialog.last()
|
||||
}
|
||||
|
||||
async function installExtensionVersionViaUi(session, extensionId, version) {
|
||||
let dialog
|
||||
try {
|
||||
dialog = await openExtensionManager(session, extensionId, 'installed')
|
||||
} catch {
|
||||
dialog = await openExtensionManager(session, extensionId, 'all')
|
||||
}
|
||||
const versionLabel = dialog.getByText(version, {exact: true}).first()
|
||||
if (!(await versionLabel.isVisible({timeout: 1000}).catch(() => false))) {
|
||||
await dialog
|
||||
.getByRole('button', {name: /expand/i})
|
||||
.first()
|
||||
.click()
|
||||
}
|
||||
await versionLabel.click()
|
||||
const installButton = dialog.getByRole('button', {name: /^install$/i}).first()
|
||||
if (!(await installButton.isVisible({timeout: 1000}).catch(() => false))) {
|
||||
await dialog.getByRole('button', {name: /close/i}).last().click()
|
||||
return null
|
||||
}
|
||||
const activatePromise = session.page
|
||||
.waitForResponse(response =>
|
||||
responseMatches(
|
||||
response,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/activate`
|
||||
)
|
||||
)
|
||||
.catch(() => null)
|
||||
let installResponsePromise = session.page.waitForResponse(response =>
|
||||
responseMatches(response, 'POST', '/api/v1/extension')
|
||||
)
|
||||
await installButton.click()
|
||||
const grantButton = session.page.getByRole('button', {
|
||||
name: /grant and install/i
|
||||
})
|
||||
if (await grantButton.isVisible({timeout: 1000}).catch(() => false)) {
|
||||
installResponsePromise.catch(() => null)
|
||||
installResponsePromise = session.page.waitForResponse(response =>
|
||||
responseMatches(response, 'POST', '/api/v1/extension')
|
||||
)
|
||||
await grantButton.click()
|
||||
}
|
||||
const installResponse = await installResponsePromise
|
||||
await expectStatus(installResponse, [200, 201], 'POST /api/v1/extension')
|
||||
const activateResponse = await activatePromise
|
||||
if (activateResponse) {
|
||||
await expectStatus(
|
||||
activateResponse,
|
||||
200,
|
||||
`PUT /api/v1/extension/${extensionId}/activate`
|
||||
)
|
||||
}
|
||||
return responseJson(installResponse)
|
||||
}
|
||||
|
||||
async function installLatestExtensionViaUi(session, extensionId) {
|
||||
const release = await latestRelease(session.uiContext.request, extensionId)
|
||||
return installExtensionVersionViaUi(session, extensionId, release.version)
|
||||
}
|
||||
|
||||
async function ensureExtensionsInstalledViaUi(session, extensionIds) {
|
||||
for (const extensionId of extensionIds) {
|
||||
const installed = await findExtensionCard(session, extensionId, 'installed')
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
if (!installed) {
|
||||
await installLatestExtensionViaUi(session, extensionId)
|
||||
}
|
||||
await setExtensionActiveViaUi(session, extensionId, true)
|
||||
}
|
||||
}
|
||||
|
||||
async function enableExtensionViaUi(session, extensionId) {
|
||||
const card = await findExtensionCard(session, extensionId)
|
||||
const alreadyEnabled =
|
||||
(await card.getByRole('button', {name: /open/i}).isVisible()) ||
|
||||
(await card.getByRole('button', {name: /^disable$/i}).isVisible())
|
||||
if (alreadyEnabled) {
|
||||
return null
|
||||
}
|
||||
const payToEnableButton = card.getByRole('button', {name: /pay to enable/i})
|
||||
if (await payToEnableButton.isVisible()) {
|
||||
await payToEnableButton.click()
|
||||
const dialog = session.page
|
||||
.locator('.q-dialog')
|
||||
.filter({hasText: 'Recheck'})
|
||||
await expect(dialog.last()).toBeVisible()
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/enable`,
|
||||
() => session.page.getByText(/recheck/i).click()
|
||||
)
|
||||
}
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/enable`,
|
||||
() => card.getByRole('button', {name: /^enable$/i}).click()
|
||||
)
|
||||
}
|
||||
|
||||
async function disableExtensionViaUi(session, extensionId) {
|
||||
const card = await findExtensionCard(session, extensionId)
|
||||
if (!(await card.getByRole('button', {name: /^disable$/i}).isVisible())) {
|
||||
return null
|
||||
}
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/disable`,
|
||||
() => card.getByRole('button', {name: /^disable$/i}).click()
|
||||
)
|
||||
}
|
||||
|
||||
async function setExtensionActiveViaUi(
|
||||
session,
|
||||
extensionId,
|
||||
active,
|
||||
expected = 200
|
||||
) {
|
||||
const card = await findExtensionCard(session, extensionId)
|
||||
const action = active ? 'activate' : 'deactivate'
|
||||
const toggle = card.locator('.q-toggle').first()
|
||||
const alreadySet = await toggle
|
||||
.innerText()
|
||||
.then(text =>
|
||||
text.toLowerCase().includes(active ? 'activated' : 'deactivated')
|
||||
)
|
||||
if (alreadySet && expected === 200) return null
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/${action}`,
|
||||
() => toggle.click(),
|
||||
expected
|
||||
)
|
||||
}
|
||||
|
||||
async function payToEnableExtensionViaUi(session, extensionId) {
|
||||
const card = await findExtensionCard(session, extensionId)
|
||||
await card.getByRole('button', {name: /pay to enable/i}).click()
|
||||
const dialog = session.page.locator('.q-dialog').filter({hasText: 'Recheck'})
|
||||
await expect(dialog.last()).toBeVisible()
|
||||
const invoice = await clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/invoice/enable`,
|
||||
() =>
|
||||
dialog
|
||||
.last()
|
||||
.getByRole('button', {name: /show qr/i})
|
||||
.click()
|
||||
)
|
||||
await dialog.last().getByRole('button', {name: /close/i}).click()
|
||||
await payInvoiceViaUi(session, invoice.payment_request || invoice.bolt11)
|
||||
const cardAfterPayment = await findExtensionCard(session, extensionId)
|
||||
if (
|
||||
await cardAfterPayment.getByRole('button', {name: /^enable$/i}).isVisible()
|
||||
) {
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/enable`,
|
||||
() => cardAfterPayment.getByRole('button', {name: /^enable$/i}).click()
|
||||
)
|
||||
}
|
||||
await cardAfterPayment.getByRole('button', {name: /pay to enable/i}).click()
|
||||
return clickAndGetJsonResponse(
|
||||
session.page,
|
||||
'PUT',
|
||||
`/api/v1/extension/${extensionId}/enable`,
|
||||
() => session.page.getByText(/recheck/i).click()
|
||||
)
|
||||
}
|
||||
|
||||
async function createPayLink(context, account, index, overrides = {}) {
|
||||
const data = compactObject({
|
||||
description: `receive payments ${index}`,
|
||||
min: 11,
|
||||
comment_chars: 128,
|
||||
webhook_url: mirrorUrl(),
|
||||
webhook_headers: '{"h1": "1"}',
|
||||
webhook_body: '{"b2": 2}',
|
||||
success_text: 'All goood!',
|
||||
success_url: 'https://lnbits.com',
|
||||
max: Number(`${index}1`),
|
||||
...overrides
|
||||
})
|
||||
const link = await jsonRequest(context, 'post', '/lnurlp/api/v1/links', {
|
||||
headers: apiKeyHeaders(account.adminkey),
|
||||
data,
|
||||
expected: 201
|
||||
})
|
||||
|
||||
expect(link.id).toBeTruthy()
|
||||
expect(link.wallet).toBe(account.walletId)
|
||||
return link
|
||||
}
|
||||
|
||||
async function createWithdrawLink(context, account, index, overrides = {}) {
|
||||
const link = await jsonRequest(context, 'post', '/withdraw/api/v1/links', {
|
||||
headers: apiKeyHeaders(account.adminkey),
|
||||
data: {
|
||||
is_unique: false,
|
||||
use_custom: false,
|
||||
title: `withdraw ${index}`,
|
||||
min_withdrawable: 10,
|
||||
max_withdrawable: index * 10,
|
||||
uses: 5,
|
||||
wait_time: 1,
|
||||
webhook_url: mirrorUrl(),
|
||||
webhook_headers: '{"h1": "1"}',
|
||||
webhook_body: '{"b2": 2}',
|
||||
custom_url: null,
|
||||
...overrides
|
||||
},
|
||||
expected: 201
|
||||
})
|
||||
|
||||
expect(link.id).toBeTruthy()
|
||||
expect(link.wallet).toBe(account.walletId)
|
||||
expect(link.title).toBe(`withdraw ${index}`)
|
||||
return link
|
||||
}
|
||||
|
||||
async function withdrawLnurl(
|
||||
context,
|
||||
receiveWallet,
|
||||
withdrawResponse,
|
||||
amount = 10,
|
||||
memo = 'withdraw 1'
|
||||
) {
|
||||
return jsonRequest(context, 'post', '/api/v1/payments', {
|
||||
headers: apiKeyHeaders(receiveWallet.inkey),
|
||||
data: {
|
||||
out: false,
|
||||
amount,
|
||||
memo,
|
||||
unit: 'sat',
|
||||
lnurl_withdraw: withdrawResponse
|
||||
},
|
||||
expected: 201
|
||||
})
|
||||
}
|
||||
|
||||
async function lndhubHeaders(accessToken) {
|
||||
return {Authorization: `Bearer ${accessToken}`}
|
||||
}
|
||||
|
||||
async function createNip5Domain(context, account, extra = {}) {
|
||||
const {cost_extra: extraCost = {}, ...extraFields} = extra
|
||||
return jsonRequest(context, 'post', '/nostrnip5/api/v1/domain', {
|
||||
headers: apiKeyHeaders(account.adminkey),
|
||||
data: {
|
||||
cost_extra: {
|
||||
max_years: '3',
|
||||
char_count_cost: [],
|
||||
rank_cost: [],
|
||||
...extraCost
|
||||
},
|
||||
wallet: account.walletId,
|
||||
currency: 'USD',
|
||||
domain: `nostr-${Date.now()}.com`,
|
||||
cost: '100',
|
||||
...extraFields
|
||||
},
|
||||
expected: 201
|
||||
})
|
||||
}
|
||||
|
||||
async function createUserNip5Address(context, account, domainId, localPart) {
|
||||
const address = await jsonRequest(
|
||||
context,
|
||||
'post',
|
||||
`/nostrnip5/api/v1/user/domain/${domainId}/address`,
|
||||
{
|
||||
headers: apiKeyHeaders(account.adminkey),
|
||||
data: {
|
||||
config: {relays: ['relay.nostr.com']},
|
||||
pubkey:
|
||||
'04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9',
|
||||
local_part: localPart,
|
||||
domain_id: domainId
|
||||
},
|
||||
expected: 201
|
||||
}
|
||||
)
|
||||
expect(address.id).toBeTruthy()
|
||||
return address
|
||||
}
|
||||
|
||||
async function createNip5Address(
|
||||
context,
|
||||
account,
|
||||
domainId,
|
||||
localPart,
|
||||
pubkey
|
||||
) {
|
||||
const address = await jsonRequest(
|
||||
context,
|
||||
'post',
|
||||
`/nostrnip5/api/v1/domain/${domainId}/address`,
|
||||
{
|
||||
headers: apiKeyHeaders(account.adminkey),
|
||||
data: {
|
||||
config: {relays: ['relay.nostr.com']},
|
||||
pubkey,
|
||||
local_part: localPart,
|
||||
domain_id: domainId
|
||||
},
|
||||
expected: 201
|
||||
}
|
||||
)
|
||||
expect(address.id).toBeTruthy()
|
||||
return address
|
||||
}
|
||||
|
||||
async function activateNip5Address(context, account, domainId, addressId) {
|
||||
return jsonRequest(
|
||||
context,
|
||||
'put',
|
||||
`/nostrnip5/api/v1/domain/${domainId}/address/${addressId}/activate`,
|
||||
{
|
||||
headers: apiKeyHeaders(account.adminkey)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function getNostrJson(context, domainId, name, expected = 200) {
|
||||
return jsonRequest(
|
||||
context,
|
||||
'get',
|
||||
`/nostrnip5/api/v1/domain/${domainId}/nostr.json`,
|
||||
{
|
||||
params: {name},
|
||||
expected
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function buyNip5Address(context, account, domainId, localPart, options) {
|
||||
return jsonRequest(
|
||||
context,
|
||||
'post',
|
||||
`/nostrnip5/api/v1/user/domain/${domainId}/address`,
|
||||
{
|
||||
headers: apiKeyHeaders(account.adminkey),
|
||||
data: {
|
||||
domain_id: domainId,
|
||||
local_part: localPart,
|
||||
pubkey: options.pubkey,
|
||||
years: options.years,
|
||||
promo_code: options.promo_code ?? null,
|
||||
referer: options.referer ?? null,
|
||||
create_invoice: options.create_invoice ?? false
|
||||
},
|
||||
expected: options.expected ?? 200
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
async function createAuctionRoom(context, owner, data) {
|
||||
const room = await jsonRequest(
|
||||
context,
|
||||
'post',
|
||||
'/auction_house/api/v1/auction_room',
|
||||
{
|
||||
headers: apiKeyHeaders(owner.adminkey),
|
||||
data,
|
||||
expected: 201
|
||||
}
|
||||
)
|
||||
expect(room.id).toBeTruthy()
|
||||
return room
|
||||
}
|
||||
|
||||
async function updateAuctionRoom(context, owner, data) {
|
||||
const room = await jsonRequest(
|
||||
context,
|
||||
'put',
|
||||
'/auction_house/api/v1/auction_room',
|
||||
{
|
||||
headers: apiKeyHeaders(owner.adminkey),
|
||||
data
|
||||
}
|
||||
)
|
||||
expect(room.id).toBe(data.id)
|
||||
return room
|
||||
}
|
||||
|
||||
async function createAuctionItem(context, seller, roomId, data) {
|
||||
const item = await jsonRequest(
|
||||
context,
|
||||
'post',
|
||||
`/auction_house/api/v1/items/${roomId}`,
|
||||
{
|
||||
headers: apiKeyHeaders(seller.adminkey),
|
||||
data,
|
||||
expected: 201
|
||||
}
|
||||
)
|
||||
expect(item.id).toBeTruthy()
|
||||
return item
|
||||
}
|
||||
|
||||
async function bidOnItem(context, bidder, itemId, amount, memo) {
|
||||
const bid = await jsonRequest(
|
||||
context,
|
||||
'put',
|
||||
`/auction_house/api/v1/bids/${itemId}`,
|
||||
{
|
||||
headers: apiKeyHeaders(bidder.adminkey),
|
||||
data: {amount, ln_address: '', memo},
|
||||
expected: 201
|
||||
}
|
||||
)
|
||||
expect(bid.payment_request).toBeTruthy()
|
||||
return bid
|
||||
}
|
||||
|
||||
function setupIntegration() {
|
||||
test.beforeAll(async ({playwright}, testInfo) => {
|
||||
state.baseURL = testInfo.project.use.baseURL
|
||||
state.contextFactory = playwright.request
|
||||
state.adminSession = null
|
||||
state.adminContext = await newContext()
|
||||
state.adminWallet = await initServer(state.adminContext)
|
||||
const manifest = await fetchManifest()
|
||||
state.extensionById = new Map(
|
||||
manifest.extensions.map(extension => [extension.id, extension])
|
||||
)
|
||||
})
|
||||
|
||||
test.afterAll(async () => {
|
||||
await Promise.all(contexts.map(context => context.dispose()))
|
||||
await Promise.all(browserContexts.map(context => context.close()))
|
||||
contexts.splice(0, contexts.length)
|
||||
browserContexts.splice(0, browserContexts.length)
|
||||
state.baseURL = null
|
||||
state.adminContext = null
|
||||
state.adminWallet = null
|
||||
state.adminSession = null
|
||||
state.extensionById = null
|
||||
state.contextFactory = null
|
||||
})
|
||||
}
|
||||
|
||||
function compactObject(value) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).filter(([, entry]) => entry !== undefined)
|
||||
)
|
||||
}
|
||||
|
||||
function auctionNip5Webhooks(domainId) {
|
||||
return {
|
||||
duration: {days: 7, hours: 0, minutes: 0},
|
||||
lock_webhook: {
|
||||
method: 'PUT',
|
||||
url: `${state.baseURL}/nostrnip5/api/v1/domain/${domainId}/address/lock`,
|
||||
headers: '',
|
||||
data: '{\n "transfer_code": "${transfer_code}"\n}'
|
||||
},
|
||||
unlock_webhook: {
|
||||
method: 'PUT',
|
||||
url: `${state.baseURL}/nostrnip5/api/v1/domain/${domainId}/address/unlock`,
|
||||
headers: '',
|
||||
data: '{\n "lock_code": "${lock_code}"\n}'
|
||||
},
|
||||
transfer_webhook: {
|
||||
method: 'PUT',
|
||||
url: `${state.baseURL}/nostrnip5/api/v1/domain/${domainId}/address/transfer`,
|
||||
headers: '',
|
||||
data: '{\n "lock_code": "${lock_code}",\n "new_owner_id": "${new_owner_id}"\n}'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
test,
|
||||
expect,
|
||||
setupIntegration,
|
||||
state,
|
||||
apiKeyHeaders,
|
||||
clearMirror,
|
||||
createAccount,
|
||||
createWallet,
|
||||
decodePayment,
|
||||
expectStatus,
|
||||
fetchManifest,
|
||||
getPayment,
|
||||
getPayments,
|
||||
getWallet,
|
||||
initServer,
|
||||
jsonRequest,
|
||||
latestRelease,
|
||||
loginAdmin,
|
||||
lnurlScan,
|
||||
mirrorUrl,
|
||||
pageStatus,
|
||||
pollPayment,
|
||||
pollWalletBalance,
|
||||
responseJson,
|
||||
textRequest,
|
||||
topUpWallet,
|
||||
uninstallExtension,
|
||||
newContext,
|
||||
newUser,
|
||||
newBrowserSession,
|
||||
newUserWithUi,
|
||||
getAdminSession,
|
||||
extensionName,
|
||||
refreshExtensionCatalog,
|
||||
responsePath,
|
||||
responseMatches,
|
||||
clickAndCheckResponse,
|
||||
clickAndGetJsonResponse,
|
||||
gotoPage,
|
||||
gotoWallet,
|
||||
fillQuasarField,
|
||||
createInvoiceViaUi,
|
||||
payInvoiceViaUi,
|
||||
payLnurlViaUi,
|
||||
withdrawLnurlViaUi,
|
||||
openExtensionsPage,
|
||||
findExtensionCard,
|
||||
openExtensionManager,
|
||||
installExtensionVersionViaUi,
|
||||
installLatestExtensionViaUi,
|
||||
ensureExtensionsInstalledViaUi,
|
||||
enableExtensionViaUi,
|
||||
disableExtensionViaUi,
|
||||
setExtensionActiveViaUi,
|
||||
payToEnableExtensionViaUi,
|
||||
createPayLink,
|
||||
createWithdrawLink,
|
||||
withdrawLnurl,
|
||||
lndhubHeaders,
|
||||
createNip5Domain,
|
||||
createUserNip5Address,
|
||||
createNip5Address,
|
||||
activateNip5Address,
|
||||
getNostrJson,
|
||||
buyNip5Address,
|
||||
createAuctionRoom,
|
||||
updateAuctionRoom,
|
||||
createAuctionItem,
|
||||
bidOnItem,
|
||||
compactObject,
|
||||
auctionNip5Webhooks
|
||||
}
|
||||
Reference in New Issue
Block a user