Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4118233
Update.js
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
Update.js
View Options
'use strict'
;
const
{
action
,
assert
,
REST
,
utils
}
=
require
(
'api-testing'
);
let
pathPrefix
=
'rest.php/content/v1'
;
describe
(
'PUT /page/{title}'
,
()
=>
{
let
client
,
mindy
,
mindyToken
;
before
(
async
()
=>
{
mindy
=
await
action
.
mindy
();
client
=
new
REST
(
pathPrefix
,
mindy
);
mindyToken
=
await
mindy
.
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
title
=
utils
.
title
(
'Edit Test '
);
const
normalizedTitle
=
utils
.
dbkey
(
title
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
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
);
}
);
it
(
'should create a page with specific content model'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
const
normalizedTitle
=
utils
.
dbkey
(
title
);
// TODO: test a content model different from the default.
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
content_model
:
'wikitext'
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
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
);
}
);
it
(
'should update an existing page'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
const
normalizedTitle
=
utils
.
dbkey
(
title
);
// create
await
mindy
.
edit
(
normalizedTitle
,
{}
);
const
{
body
:
newPage
}
=
await
client
.
get
(
`/page/
${
normalizedTitle
}
/bare`
);
const
firstRev
=
newPage
.
latest
;
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
latest
:
firstRev
// provide the base revision
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
200
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
checkEditResponse
(
title
,
reqBody
,
editBody
);
assert
.
isAbove
(
editBody
.
latest
.
id
,
firstRev
.
id
);
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 handle null-edits (unchanged content) gracefully'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
// create
const
firstRev
=
await
mindy
.
edit
(
title
,
{}
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
firstRev
.
param_text
,
comment
:
'nothing at all changed'
,
latest
:
{
id
:
firstRev
.
newrevid
}
};
const
resp
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
resp
;
assert
.
equal
(
editStatus
,
200
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
checkEditResponse
(
title
,
reqBody
,
editBody
);
// No revision was created, new ID is the same as the old ID
assert
.
equal
(
editBody
.
latest
.
id
,
firstRev
.
newrevid
);
}
);
it
(
'should automatically solve merge conflicts'
,
async
()
=>
{
// XXX: this test may fail if the diff3 utility is not found on the web host
const
title
=
utils
.
title
(
'Edit Test '
);
// create
const
firstRev
=
await
mindy
.
edit
(
title
,
{
text
:
'first line\nlorem ipsum\nsecond line'
}
);
await
mindy
.
edit
(
title
,
{
text
:
'FIRST LINE\nlorem ipsum\nsecond line'
}
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
'first line\nlorem ipsum\nSECOND LINE'
,
comment
:
'tästing'
,
content_model
:
'wikitext'
,
latest
:
{
id
:
firstRev
.
newrevid
}
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
200
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
const
expectedText
=
'FIRST LINE\nlorem ipsum\nSECOND LINE'
;
assert
.
nestedPropertyVal
(
editBody
,
'source'
,
expectedText
);
}
);
}
);
describe
(
'request validation'
,
()
=>
{
const
requiredProps
=
[
'source'
,
'comment'
];
requiredProps
.
forEach
(
(
missingPropName
)
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
content_model
:
'wikitext'
};
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
.
put
(
`/page/
${
title
}
`
,
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'
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
403
);
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'
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
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
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
content_model
:
'THIS DOES NOT EXIST!'
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
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
=
{
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
content_model
:
'wikitext'
,
token
:
mindyToken
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
400
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
assert
.
nestedProperty
(
editBody
,
'messageTranslations'
);
}
);
it
(
'should fail if no title is given'
,
async
()
=>
{
const
reqBody
=
{
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
content_model
:
'wikitext'
,
token
:
mindyToken
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
'/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 when the target page does not exist but revision ID was given'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
latest
:
{
id
:
1234
}
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
404
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
assert
.
nestedProperty
(
editBody
,
'messageTranslations'
);
}
);
it
(
'should detect a conflict if page exist but no revision ID was given'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
// create
await
mindy
.
edit
(
title
,
{}
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
// not 'latest' key, so page should be created
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
409
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
assert
.
nestedProperty
(
editBody
,
'messageTranslations'
);
}
);
it
(
'should detect a conflict when an old base revision ID is given and conflict resolution fails'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
// create
const
firstRev
=
await
mindy
.
edit
(
title
,
{
text
:
'initial text'
}
);
await
mindy
.
edit
(
title
,
{
text
:
'updated text'
}
);
const
reqBody
=
{
token
:
mindyToken
,
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
latest
:
{
id
:
firstRev
.
newrevid
}
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
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 edit a protected page without appropriate permissions'
,
async
()
=>
{
const
title
=
utils
.
title
(
'Edit Test '
);
// create a protected page
const
firstRev
=
await
mindy
.
edit
(
title
,
{}
);
await
mindy
.
action
(
'protect'
,
{
title
,
token
:
await
mindy
.
token
(),
protections
:
'edit=sysop'
},
'POST'
);
const
anon
=
action
.
getAnon
();
const
reqBody
=
{
token
:
await
anon
.
token
(),
source
:
'Lörem Ipsüm'
,
comment
:
'tästing'
,
latest
:
{
id
:
firstRev
.
newrevid
}
};
const
{
status
:
editStatus
,
body
:
editBody
,
header
:
editHeader
}
=
await
client
.
put
(
`/page/
${
title
}
`
,
reqBody
);
assert
.
equal
(
editStatus
,
403
);
assert
.
match
(
editHeader
[
'content-type'
],
/^application\/json/
);
assert
.
nestedProperty
(
editBody
,
'messageTranslations'
);
}
);
}
);
}
);
// eslint-disable-next-line mocha/no-exports
exports
.
init
=
function
(
pp
)
{
// Allow testing both legacy and module paths using the same tests
pathPrefix
=
pp
;
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Aug 19, 02:40 (2 w, 2 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
38/99/764b8fa01146bb351dda9be25033
Default Alt Text
Update.js (12 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment