Compare commits
2 Commits
payload/2.
...
feat/trans
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26a2f8d0d7 | ||
|
|
c7a02803a0 |
@@ -6,6 +6,12 @@ module.exports = {
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['package.json', 'tsconfig.json'],
|
||||
rules: {
|
||||
|
||||
@@ -29,9 +29,12 @@
|
||||
"prompts": "2.4.2",
|
||||
"uuid": "9.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"@payloadcms/eslint-config": "workspace:*",
|
||||
"@types/mongoose-aggregate-paginate-v2": "1.0.9",
|
||||
"mongodb": "^6.1.0",
|
||||
"mongodb-memory-server": "8.13.0",
|
||||
"payload": "workspace:*"
|
||||
},
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { TransactionOptions } from 'mongodb'
|
||||
import type { ClientSession, ConnectOptions, Connection } from 'mongoose'
|
||||
import type { Payload } from 'payload'
|
||||
import type { BaseDatabaseAdapter } from 'payload/database'
|
||||
@@ -6,8 +7,6 @@ import mongoose from 'mongoose'
|
||||
import path from 'path'
|
||||
import { createDatabaseAdapter } from 'payload/database'
|
||||
|
||||
export type { MigrateDownArgs, MigrateUpArgs } from './types'
|
||||
|
||||
import type { CollectionModel, GlobalModel } from './types'
|
||||
|
||||
import { connect } from './connect'
|
||||
@@ -38,6 +37,8 @@ import { updateGlobalVersion } from './updateGlobalVersion'
|
||||
import { updateOne } from './updateOne'
|
||||
import { updateVersion } from './updateVersion'
|
||||
|
||||
export type { MigrateDownArgs, MigrateUpArgs } from './types'
|
||||
|
||||
export interface Args {
|
||||
/** Set to false to disable auto-pluralization of collection names, Defaults to true */
|
||||
autoPluralization?: boolean
|
||||
@@ -47,6 +48,10 @@ export interface Args {
|
||||
useFacet?: boolean
|
||||
}
|
||||
migrationDir?: string
|
||||
/**
|
||||
* set to false to disable using transactions
|
||||
*/
|
||||
transactions?: TransactionOptions | false
|
||||
/** The URL to connect to MongoDB or false to start payload and prevent connecting */
|
||||
url: false | string
|
||||
}
|
||||
@@ -60,6 +65,7 @@ export type MongooseAdapter = BaseDatabaseAdapter &
|
||||
globals: GlobalModel
|
||||
mongoMemoryServer: any
|
||||
sessions: Record<number | string, ClientSession>
|
||||
transactionOptions: TransactionOptions | false
|
||||
versions: {
|
||||
[slug: string]: CollectionModel
|
||||
}
|
||||
@@ -70,7 +76,7 @@ type MongooseAdapterResult = (args: { payload: Payload }) => MongooseAdapter
|
||||
declare module 'payload' {
|
||||
export interface DatabaseAdapter
|
||||
extends Omit<BaseDatabaseAdapter, 'sessions'>,
|
||||
Omit<Args, 'migrationDir'> {
|
||||
Omit<Args, 'migrationDir' | 'transactions'> {
|
||||
collections: {
|
||||
[slug: string]: CollectionModel
|
||||
}
|
||||
@@ -88,6 +94,7 @@ export function mongooseAdapter({
|
||||
autoPluralization = true,
|
||||
connectOptions,
|
||||
migrationDir: migrationDirArg,
|
||||
transactions,
|
||||
url,
|
||||
}: Args): MongooseAdapterResult {
|
||||
function adapter({ payload }: { payload: Payload }) {
|
||||
@@ -108,6 +115,12 @@ export function mongooseAdapter({
|
||||
globals: undefined,
|
||||
mongoMemoryServer: undefined,
|
||||
sessions: {},
|
||||
transactionOptions: transactions ?? {
|
||||
readConcern: { level: 'local' },
|
||||
// TODO: this needs to be dynamic based on the operation
|
||||
readPreference: 'nearest',
|
||||
// readPreference: 'primary', // primary for write
|
||||
},
|
||||
url,
|
||||
versions: {},
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// @ts-expect-error // TODO: Fix this import
|
||||
import type { TransactionOptions } from 'mongodb'
|
||||
import type { BeginTransaction } from 'payload/database'
|
||||
|
||||
@@ -7,8 +6,11 @@ import { v4 as uuid } from 'uuid'
|
||||
|
||||
let transactionsNotAvailable: boolean
|
||||
export const beginTransaction: BeginTransaction = async function beginTransaction(
|
||||
options: TransactionOptions = {},
|
||||
options?: TransactionOptions,
|
||||
) {
|
||||
if (this.transactionOptions === false) {
|
||||
return null
|
||||
}
|
||||
let id = null
|
||||
if (!this.connection) {
|
||||
throw new APIError('beginTransaction called while no connection to the database exists')
|
||||
@@ -27,7 +29,7 @@ export const beginTransaction: BeginTransaction = async function beginTransactio
|
||||
if (this.sessions[id].inTransaction()) {
|
||||
this.payload.logger.warn('beginTransaction called while transaction already exists')
|
||||
} else {
|
||||
await this.sessions[id].startTransaction(options)
|
||||
await this.sessions[id].startTransaction(options || this.transactionOptions)
|
||||
}
|
||||
}
|
||||
return id
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { EditorProps } from '@monaco-editor/react'
|
||||
import type { TFunction } from 'i18next'
|
||||
import type { CSSProperties } from 'react'
|
||||
|
||||
import monacoeditor from 'monaco-editor' // IMPORTANT - DO NOT REMOVE: This is required for pnpm's default isolated mode to work - even though the import is not used. This is due to a typescript bug: https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189. (tsbugisolatedmode)
|
||||
import type { ConditionalDateProps } from '../../admin/components/elements/DatePicker/types'
|
||||
import type { Description } from '../../admin/components/forms/FieldDescription/types'
|
||||
import type { RowLabel } from '../../admin/components/forms/RowLabel/types'
|
||||
|
||||
@@ -12,14 +12,13 @@ export interface Relation {
|
||||
|
||||
const openAccess = {
|
||||
create: () => true,
|
||||
delete: () => true,
|
||||
read: () => true,
|
||||
update: () => true,
|
||||
delete: () => true,
|
||||
}
|
||||
|
||||
const collectionWithName = (collectionSlug: string): CollectionConfig => {
|
||||
return {
|
||||
slug: collectionSlug,
|
||||
access: openAccess,
|
||||
fields: [
|
||||
{
|
||||
@@ -27,55 +26,36 @@ const collectionWithName = (collectionSlug: string): CollectionConfig => {
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
slug: collectionSlug,
|
||||
}
|
||||
}
|
||||
|
||||
export const slug = 'posts'
|
||||
export const relationSlug = 'relation'
|
||||
|
||||
export const transactionSlug = 'transactions'
|
||||
|
||||
export const pointSlug = 'point'
|
||||
|
||||
export default buildConfigWithDefaults({
|
||||
graphQL: {
|
||||
schemaOutputFile: path.resolve(__dirname, 'schema.graphql'),
|
||||
queries: (GraphQL) => {
|
||||
return {
|
||||
QueryWithInternalError: {
|
||||
type: new GraphQL.GraphQLObjectType({
|
||||
name: 'QueryWithInternalError',
|
||||
fields: {
|
||||
text: {
|
||||
type: GraphQL.GraphQLString,
|
||||
},
|
||||
},
|
||||
}),
|
||||
resolve: () => {
|
||||
// Throwing an internal error with potentially sensitive data
|
||||
throw new Error('Lost connection to the Pentagon. Secret data: ******')
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
{
|
||||
slug: 'users',
|
||||
auth: true,
|
||||
access: openAccess,
|
||||
auth: true,
|
||||
fields: [],
|
||||
slug: 'users',
|
||||
},
|
||||
{
|
||||
slug: pointSlug,
|
||||
access: openAccess,
|
||||
fields: [
|
||||
{
|
||||
type: 'point',
|
||||
name: 'point',
|
||||
type: 'point',
|
||||
},
|
||||
],
|
||||
slug: pointSlug,
|
||||
},
|
||||
{
|
||||
slug,
|
||||
access: openAccess,
|
||||
fields: [
|
||||
{
|
||||
@@ -92,173 +72,173 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
{
|
||||
name: 'min',
|
||||
type: 'number',
|
||||
min: 10,
|
||||
type: 'number',
|
||||
},
|
||||
// Relationship
|
||||
{
|
||||
name: 'relationField',
|
||||
type: 'relationship',
|
||||
relationTo: relationSlug,
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'relationToCustomID',
|
||||
type: 'relationship',
|
||||
relationTo: 'custom-ids',
|
||||
type: 'relationship',
|
||||
},
|
||||
// Relation hasMany
|
||||
{
|
||||
name: 'relationHasManyField',
|
||||
type: 'relationship',
|
||||
relationTo: relationSlug,
|
||||
hasMany: true,
|
||||
relationTo: relationSlug,
|
||||
type: 'relationship',
|
||||
},
|
||||
// Relation multiple relationTo
|
||||
{
|
||||
name: 'relationMultiRelationTo',
|
||||
type: 'relationship',
|
||||
relationTo: [relationSlug, 'dummy'],
|
||||
type: 'relationship',
|
||||
},
|
||||
// Relation multiple relationTo hasMany
|
||||
{
|
||||
name: 'relationMultiRelationToHasMany',
|
||||
type: 'relationship',
|
||||
relationTo: [relationSlug, 'dummy'],
|
||||
hasMany: true,
|
||||
relationTo: [relationSlug, 'dummy'],
|
||||
type: 'relationship',
|
||||
},
|
||||
{
|
||||
name: 'A1',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'A2',
|
||||
defaultValue: 'textInRowInGroup',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
{
|
||||
name: 'B1',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'B2',
|
||||
defaultValue: 'textInRowInGroup',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
label: 'Collapsible',
|
||||
type: 'collapsible',
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
{
|
||||
name: 'C1',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'C2Text',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible2',
|
||||
fields: [
|
||||
{
|
||||
name: 'C2',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible2',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'C3',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
label: 'Collapsible2',
|
||||
type: 'collapsible',
|
||||
},
|
||||
],
|
||||
type: 'row',
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
],
|
||||
label: 'Collapsible2',
|
||||
type: 'collapsible',
|
||||
},
|
||||
],
|
||||
type: 'row',
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Tab1',
|
||||
name: 'D1',
|
||||
fields: [
|
||||
{
|
||||
name: 'D2',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible2',
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
label: 'Tab1',
|
||||
fields: [
|
||||
{
|
||||
name: 'D3',
|
||||
type: 'group',
|
||||
fields: [
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible2',
|
||||
fields: [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'D4',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
label: 'Collapsible2',
|
||||
type: 'collapsible',
|
||||
},
|
||||
],
|
||||
type: 'row',
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
],
|
||||
label: 'Tab1',
|
||||
},
|
||||
],
|
||||
type: 'tabs',
|
||||
},
|
||||
],
|
||||
label: 'Collapsible2',
|
||||
type: 'collapsible',
|
||||
},
|
||||
],
|
||||
type: 'row',
|
||||
},
|
||||
],
|
||||
type: 'group',
|
||||
},
|
||||
],
|
||||
label: 'Tab1',
|
||||
},
|
||||
],
|
||||
type: 'tabs',
|
||||
},
|
||||
],
|
||||
slug,
|
||||
},
|
||||
{
|
||||
slug: 'custom-ids',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
@@ -272,45 +252,87 @@ export default buildConfigWithDefaults({
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
slug: 'custom-ids',
|
||||
},
|
||||
collectionWithName(relationSlug),
|
||||
collectionWithName('dummy'),
|
||||
{
|
||||
slug: 'payload-api-test-ones',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'payloadAPI',
|
||||
type: 'text',
|
||||
hooks: {
|
||||
afterRead: [({ req }) => req.payloadAPI],
|
||||
},
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
slug: 'payload-api-test-ones',
|
||||
},
|
||||
{
|
||||
slug: 'payload-api-test-twos',
|
||||
access: {
|
||||
read: () => true,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'payloadAPI',
|
||||
type: 'text',
|
||||
hooks: {
|
||||
afterRead: [({ req }) => req.payloadAPI],
|
||||
},
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'relation',
|
||||
type: 'relationship',
|
||||
relationTo: 'payload-api-test-ones',
|
||||
type: 'relationship',
|
||||
},
|
||||
],
|
||||
slug: 'payload-api-test-twos',
|
||||
},
|
||||
{
|
||||
access: openAccess,
|
||||
fields: [
|
||||
{
|
||||
name: 'transactionID',
|
||||
hooks: {
|
||||
beforeChange: [({ req }) => req.transactionID],
|
||||
},
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'sessions',
|
||||
hooks: {
|
||||
beforeChange: [({ req }) => Object.keys(req.payload.db.sessions)],
|
||||
},
|
||||
type: 'json',
|
||||
},
|
||||
],
|
||||
slug: transactionSlug,
|
||||
},
|
||||
],
|
||||
graphQL: {
|
||||
queries: (GraphQL) => {
|
||||
return {
|
||||
QueryWithInternalError: {
|
||||
resolve: () => {
|
||||
// Throwing an internal error with potentially sensitive data
|
||||
throw new Error('Lost connection to the Pentagon. Secret data: ******')
|
||||
},
|
||||
type: new GraphQL.GraphQLObjectType({
|
||||
name: 'QueryWithInternalError',
|
||||
fields: {
|
||||
text: {
|
||||
type: GraphQL.GraphQLString,
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
}
|
||||
},
|
||||
schemaOutputFile: path.resolve(__dirname, 'schema.graphql'),
|
||||
},
|
||||
onInit: async (payload) => {
|
||||
const user = await payload.create({
|
||||
collection: 'users',
|
||||
@@ -331,8 +353,8 @@ export default buildConfigWithDefaults({
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'has custom ID relation',
|
||||
relationToCustomID: 1,
|
||||
title: 'has custom ID relation',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -353,23 +375,23 @@ export default buildConfigWithDefaults({
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'with-description',
|
||||
description: 'description',
|
||||
title: 'with-description',
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'numPost1',
|
||||
number: 1,
|
||||
title: 'numPost1',
|
||||
},
|
||||
})
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'numPost2',
|
||||
number: 2,
|
||||
title: 'numPost2',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -390,15 +412,15 @@ export default buildConfigWithDefaults({
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'rel to hasMany',
|
||||
relationHasManyField: rel1.id,
|
||||
title: 'rel to hasMany',
|
||||
},
|
||||
})
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'rel to hasMany 2',
|
||||
relationHasManyField: rel2.id,
|
||||
title: 'rel to hasMany 2',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -406,11 +428,11 @@ export default buildConfigWithDefaults({
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'rel to multi',
|
||||
relationMultiRelationTo: {
|
||||
relationTo: relationSlug,
|
||||
value: rel2.id,
|
||||
},
|
||||
title: 'rel to multi',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -418,7 +440,6 @@ export default buildConfigWithDefaults({
|
||||
await payload.create({
|
||||
collection: slug,
|
||||
data: {
|
||||
title: 'rel to multi hasMany',
|
||||
relationMultiRelationToHasMany: [
|
||||
{
|
||||
relationTo: relationSlug,
|
||||
@@ -429,6 +450,7 @@ export default buildConfigWithDefaults({
|
||||
value: rel2.id,
|
||||
},
|
||||
],
|
||||
title: 'rel to multi hasMany',
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { Post } from './payload-types'
|
||||
|
||||
import payload from '../../packages/payload/src'
|
||||
import { mapAsync } from '../../packages/payload/src/utilities/mapAsync'
|
||||
import { devUser } from '../credentials'
|
||||
import { initPayloadTest } from '../helpers/configHelpers'
|
||||
import configPromise, { pointSlug, slug } from './config'
|
||||
|
||||
@@ -685,11 +686,11 @@ describe('collections-graphql', () => {
|
||||
|
||||
// language=graphQL
|
||||
const query = `query {
|
||||
Posts(where: { title: { exists: true }}) {
|
||||
docs {
|
||||
badFieldName
|
||||
Posts(where: { title: { exists: true }}) {
|
||||
docs {
|
||||
badFieldName
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
await client.request(query).catch((err) => {
|
||||
error = err
|
||||
@@ -702,12 +703,12 @@ describe('collections-graphql', () => {
|
||||
let error
|
||||
// language=graphQL
|
||||
const query = `mutation {
|
||||
createPost(data: {min: 1}) {
|
||||
id
|
||||
min
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
createPost(data: {min: 1}) {
|
||||
id
|
||||
min
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}`
|
||||
|
||||
await client.request(query).catch((err) => {
|
||||
@@ -722,21 +723,21 @@ describe('collections-graphql', () => {
|
||||
let error
|
||||
// language=graphQL
|
||||
const query = `mutation createTest {
|
||||
test1:createUser(data: { email: "test@test.com", password: "test" }) {
|
||||
email
|
||||
}
|
||||
test1:createUser(data: { email: "test@test.com", password: "test" }) {
|
||||
email
|
||||
}
|
||||
|
||||
test2:createUser(data: { email: "test2@test.com", password: "" }) {
|
||||
email
|
||||
}
|
||||
test2:createUser(data: { email: "test2@test.com", password: "" }) {
|
||||
email
|
||||
}
|
||||
|
||||
test3:createUser(data: { email: "test@test.com", password: "test" }) {
|
||||
email
|
||||
}
|
||||
test3:createUser(data: { email: "test@test.com", password: "test" }) {
|
||||
email
|
||||
}
|
||||
|
||||
test4:createUser(data: { email: "", password: "test" }) {
|
||||
email
|
||||
}
|
||||
test4:createUser(data: { email: "", password: "test" }) {
|
||||
email
|
||||
}
|
||||
}`
|
||||
|
||||
await client.request(query).catch((err) => {
|
||||
@@ -775,9 +776,9 @@ describe('collections-graphql', () => {
|
||||
let error
|
||||
// language=graphQL
|
||||
const query = `query {
|
||||
QueryWithInternalError {
|
||||
text
|
||||
}
|
||||
QueryWithInternalError {
|
||||
text
|
||||
}
|
||||
}`
|
||||
|
||||
await client.request(query).catch((err) => {
|
||||
@@ -792,6 +793,46 @@ describe('collections-graphql', () => {
|
||||
expect(error.response.errors[0].extensions.name).toEqual('Error')
|
||||
})
|
||||
})
|
||||
|
||||
if (['postgres'].includes(process.env.PAYLOAD_DATABASE)) {
|
||||
describe('Transactions', () => {
|
||||
let token
|
||||
let user
|
||||
|
||||
beforeAll(async () => {
|
||||
// language=graphQL
|
||||
const query = `mutation {
|
||||
loginUser(email: "${devUser.email}", password: "${devUser.password}") {
|
||||
token
|
||||
user {
|
||||
id
|
||||
email
|
||||
}
|
||||
}
|
||||
}`
|
||||
const response = await client.request(query)
|
||||
user = response.loginUser.user
|
||||
token = response.loginUser.token
|
||||
client.setHeaders({ Authorization: `JWT ${token}` })
|
||||
})
|
||||
|
||||
it('should use transaction', async () => {
|
||||
const query = `mutation {
|
||||
createTransaction(data: {}) {
|
||||
id
|
||||
transactionID
|
||||
sessions
|
||||
}
|
||||
}`
|
||||
const response = await client.request(query)
|
||||
const doc = response.createTransaction
|
||||
|
||||
expect(doc.transactionID).toBeDefined()
|
||||
expect(doc.sessions).toBeDefined()
|
||||
expect(doc.sessions).toContain(doc.transactionID)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
async function createPost(overrides?: Partial<Post>) {
|
||||
|
||||
Reference in New Issue
Block a user