wiki.techinc.nl/tests/api-testing/REST/Creation.js
Kosta Harlan 405cb9cad9
api-testing/REST/Creation.js: Reset REST client before each test run
Why:

- We need a clear state for each test run, because anonymous editing
  with temp accounts results in a temporary acocunt being generated, and
  the anonymous token is no longer valid.

What:

- Set a new REST client so that we have a clear cookie state before
  running a test

Bug: T365647
Change-Id: I79666ff92de090e69d32f1152ba330cf913e64e2
2024-07-10 10:24:27 +02:00

259 lines
8.4 KiB
JavaScript

'use strict';
const { action, assert, REST, utils } = require( 'api-testing' );
const supertest = require( 'supertest' );
describe( 'POST /page', () => {
// NOTE: the /page/{title} endpoint (PageSourceHandler) has to go to v1 first!
let client, mindy, anon, anonToken;
beforeEach( async () => {
// Reset the client and token before each test
// In a temp account context, making an anonymous edit generates an account
// so we want to reset state after each edit
mindy = await action.mindy();
client = new REST();
anon = await action.getAnon();
anonToken = await anon.token();
} );
const checkEditResponse = function ( title, reqBody, body ) {
assert.containsAllKeys( body, [ 'title', 'key', 'source', 'latest', 'id',
'license', 'content_model' ] );
assert.containsAllKeys( body.latest, [ 'id', 'timestamp' ] );
assert.nestedPropertyVal( body, 'source', reqBody.source );
assert.nestedPropertyVal( body, 'title', title );
assert.nestedPropertyVal( body, 'key', utils.dbkey( title ) );
assert.isAbove( body.latest.id, 0 );
if ( reqBody.content_model ) {
assert.nestedPropertyVal( body, 'content_model', reqBody.content_model );
}
};
const checkSourceResponse = function ( title, reqBody, body ) {
if ( reqBody.content_model ) {
assert.nestedPropertyVal( body, 'content_model', reqBody.content_model );
}
assert.nestedPropertyVal( body, 'title', title );
assert.nestedPropertyVal( body, 'key', utils.dbkey( title ) );
assert.nestedPropertyVal( body, 'source', reqBody.source );
};
describe( 'successful operation', () => {
it( 'should create a page if it does not exist', async () => {
const titleSuffix = utils.title();
const title = 'A B+C:D@E-' + titleSuffix;
const normalizedTitle = utils.dbkey( title );
// In "title style" encoding, spaces turn to underscores,
// colons are preserved, and slashes and pluses get encoded.
// FIXME: correct handling of encoded slashes depends on
// the server setup and can't be tested reliably.
const encodedTitle = 'A_B%2BC:D@E-' + titleSuffix;
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
const { status: editStatus, body: editBody, header } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 201 );
assert.match( header[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( header, 'location' );
const location = header.location;
assert.match( location, new RegExp( `^https?://.*/v1/page/${ encodedTitle }$` ) );
checkEditResponse( title, reqBody, editBody );
// follow redirect
const { status: redirStatus, body: redirBody, header: redirHeader } =
await supertest.agent( location ).get( '' );
assert.equal( redirStatus, 200 );
assert.match( redirHeader[ 'content-type' ], /^application\/json/ );
checkSourceResponse( title, reqBody, redirBody );
// construct request to fetch content
const { status: sourceStatus, body: sourceBody, header: sourceHeader } =
await client.get( `/page/${ normalizedTitle }` );
assert.equal( sourceStatus, 200 );
assert.match( sourceHeader[ 'content-type' ], /^application\/json/ );
checkSourceResponse( title, reqBody, sourceBody );
} );
it( 'should create a page with specified model', async () => {
const title = utils.title( 'Edit Test ' );
const normalizedTitle = utils.dbkey( title );
// TODO: Test with a model different from the default. This however requires
// the changecontentmodel permission, which anons don't have.
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
content_model: 'wikitext',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 201 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
checkEditResponse( title, reqBody, editBody );
const { status: sourceStatus, body: sourceBody, header: sourceHeader } =
await client.get( `/page/${ normalizedTitle }` );
assert.equal( sourceStatus, 200 );
assert.match( sourceHeader[ 'content-type' ], /^application\/json/ );
checkSourceResponse( title, reqBody, sourceBody );
} );
} );
describe( 'request validation', () => {
const requiredProps = [ 'source', 'comment', 'title' ];
requiredProps.forEach( ( missingPropName ) => {
const title = utils.title( 'Edit Test ' );
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
it( `should fail when ${ missingPropName } is missing from the request body`, async () => {
const incompleteBody = { ...reqBody };
delete incompleteBody[ missingPropName ];
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', incompleteBody );
assert.equal( editStatus, 400 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
} );
it( 'should fail if no token is given', async () => {
const title = utils.title( 'Edit Test ' );
const reqBody = {
// no token
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 400 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
it( 'should fail if a bad token is given', async () => {
const title = utils.title( 'Edit Test ' );
const reqBody = {
token: 'BAD',
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 403 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
it( 'should fail if a bad content model is given', async () => {
const title = utils.title( 'Edit Test ' );
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
content_model: 'THIS DOES NOT EXIST!',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 400 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
it( 'should fail if a bad title is given', async () => {
const title = '_|_'; // not a valid page title
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 400 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
} );
describe( 'failures due to system state', () => {
it( 'should detect a conflict if page exist', async () => {
const title = utils.title( 'Edit Test ' );
// create
await mindy.edit( title, {} );
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 409 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
} );
describe( 'permission checks', () => {
it( 'should fail when trying to create a protected title without appropriate permissions', async () => {
const title = utils.title( 'Edit Test ' );
// protected a non-existing title against creation
await mindy.action( 'protect', {
title,
token: await mindy.token(),
protections: 'create=sysop'
}, 'POST' );
const reqBody = {
token: anonToken,
source: 'Lörem Ipsüm',
comment: 'tästing',
title
};
const { status: editStatus, body: editBody, header: editHeader } =
await client.post( '/page', reqBody );
assert.equal( editStatus, 403 );
assert.match( editHeader[ 'content-type' ], /^application\/json/ );
assert.nestedProperty( editBody, 'messageTranslations' );
} );
} );
} );