Compare commits

..

77 Commits

Author SHA1 Message Date
Jun Pataleta f21e1443dc Moodle release 3.11.12 2023-01-14 14:16:53 +08:00
Jun Pataleta dc93055e28 weekly release 3.11.11+ 2023-01-13 10:52:25 +08:00
Jake Dallimore d57db03d20 MDL-76862 user: Unit test for setting user home page preferences 2023-01-12 11:30:59 +08:00
Paul Holden bd5bcec3f1 MDL-76862 user: ensure user can only update own preferred start page. 2023-01-12 11:17:12 +08:00
Tim Hunt 261fe42c05 MDL-76810 redirect handling: ensure return URLs are properly sanitised 2023-01-11 11:44:12 +08:00
Paul Holden 6f622e2393 Merge branch 'MDL-76811-311' of https://github.com/andrewnicols/moodle into MOODLE_311_STABLE 2023-01-10 16:40:08 +00:00
Paul Holden 00b9fe36c1 Merge branch 'MDL-76653-311' of https://github.com/lameze/moodle into MOODLE_311_STABLE 2023-01-10 15:29:17 +00:00
Paul Holden e4b27dd81b Merge branch 'MDL-76833-311' of https://github.com/andrewnicols/moodle into MOODLE_311_STABLE 2023-01-10 12:29:19 +00:00
Andrew Nicols 5c9704b210 MDL-76833 core: Bump phpunit/php-code-coverage version
This includes a bug fix for a display issue with code coverage reporting
in phpunit's HTML output report.
2023-01-10 12:09:01 +08:00
Andrew Nicols f6f2dd5022 MDL-76811 mod_data: Remove duplicate tests 2023-01-10 11:39:40 +08:00
Andrew Nicols 9fc5f273e0 MDL-76811 mod_data: strpos check should be strict 2023-01-10 11:39:40 +08:00
Andrew Nicols dd63b85ed4 MDL-76811 mod_data: Generator test cleanup 2023-01-10 11:39:39 +08:00
Simey Lameze f164d03df5 MDL-76653 behat: add coverage for SCORM availability 2023-01-10 10:20:58 +08:00
Paul Holden 00ccb3a314 weekly release 3.11.11+ 2023-01-05 10:53:16 +00:00
Sara Arjona 88d4939f25 Merge branch 'MDL-76375-311' of https://github.com/lucaboesch/moodle into MOODLE_311_STABLE 2023-01-04 16:22:00 +01:00
Luca Bösch e3be2fcfb6 MDL-76375 quiz generator: Allow more than one attempt by Behat tests. 2023-01-04 15:15:51 +01:00
Sara Arjona 3585ab5afa Merge branch 'MDL-76760-311' of https://github.com/paulholden/moodle into MOODLE_311_STABLE 2023-01-02 12:27:54 +01:00
Sara Arjona b7bfc77b52 weekly release 3.11.11+ 2022-12-29 12:57:57 +01:00
Sara Arjona 72d98b0dd5 Merge branch 'MDL-76399-patch-311' of https://github.com/ilyatregubov/moodle into MOODLE_311_STABLE 2022-12-29 09:13:49 +01:00
Ilya Tregubov 15916a6f3b MDL-76399 behat: switch to appropriate Behat step for selects. 2022-12-29 14:39:37 +07:00
Ilya Tregubov 48256e0242 Merge branch 'MDL-76399-311' of https://github.com/paulholden/moodle into MOODLE_311_STABLE 2022-12-29 09:44:30 +07:00
Paul Holden 18013b2153 MDL-76760 tool_behat: defer library loading until service execution.
Ensures that API documentation can be generated without requiring
the presence of the `vendor/` directory.
2022-12-28 10:48:02 +00:00
Ilya Tregubov 9da4095949 Merge branch 'MDL-76731_311' of https://github.com/PhilippImhof/moodle into MOODLE_311_STABLE 2022-12-28 15:15:09 +07:00
Paul Holden dc399cd841 MDL-76679 admin: correct password config field template.
The template changes were missed as part of 0795b579, update them
to match so that they continue to work with the unmask JS module.
2022-12-27 16:55:57 +01:00
Philipp Imhof e4a8272d9c MDL-76731 behat: add steps to check for version
Co-authored-by: Andrew Nicols <andrew@nicols.co.uk>
2022-12-22 17:11:44 +01:00
Ilya Tregubov 6832ac123d weekly release 3.11.11+ 2022-12-22 19:16:40 +07:00
Ilya Tregubov e892c66058 Merge branch 'install_311_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_311_STABLE 2022-12-22 19:16:38 +07:00
Andrew Nicols 48637c438d MDL-75105 tool_behat: Coding style fixes 2022-12-22 12:32:01 +07:00
Andrew Nicols 0e64a10ecf Merge branch 'MDL-75105_311_STABLE' of https://github.com/marxjohnson/moodle into MOODLE_311_STABLE 2022-12-22 12:32:01 +07:00
AMOS bot 0dd5b86d3f Automatically generated installer lang files 2022-12-22 00:07:36 +00:00
Mark Johnson b0f89e5b92 MDL-75105 tool_behat: List available data generators
This will find all data generators that can be used in behat via the
'the following "something" exist:' step, and display them in a select
list on the step definitions page.

When a generator is selected, it will fetch the required fields for that
generator and display them on the page.
2022-12-21 08:38:38 +00:00
Ilya Tregubov c4c67cd975 Merge branch 'MDL-76727-311' of https://github.com/andrewnicols/moodle into MOODLE_311_STABLE 2022-12-21 09:51:19 +07:00
Andrew Nicols 9ae06b8dc7 MDL-76727 core: Allow phpcs configuration to be overridden locally
This change reduces the priority of the shipped phpcs configuration to
allow for local overrides.

This is beneficial in several situations:
- when users wish to apply stricter or additional standards
- when the integration team wishes to trial new rules
2022-12-21 09:07:52 +08:00
Paul Holden e59e39c78f MDL-76399 question: switch to appropriate Behat step for selects. 2022-12-16 13:13:55 +00:00
Paul Holden 99e20baa54 MDL-76399 behat: improvements to "should exist in" thrown exception. 2022-12-16 12:29:13 +00:00
Andrew Nicols 7c04ccfdf9 weekly release 3.11.11+ 2022-12-16 09:06:03 +08:00
Andrew Nicols 2f8a56eaf0 Merge branch 'install_311_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_311_STABLE 2022-12-16 09:06:01 +08:00
Sara Arjona 0a774cefb8 Merge branch 'MDL-76674_311' of https://github.com/stronk7/moodle into MOODLE_311_STABLE 2022-12-14 18:35:08 +01:00
Eloy Lafuente (stronk7) 6257ac4de7 MDL-76674 core_lang: Add string for new America/Ciudad_Juarez 2022-12-14 15:52:03 +01:00
Paul Holden 5f34ca7b01 Merge branch 'MDL-76666_311' of https://github.com/stronk7/moodle into MOODLE_311_STABLE 2022-12-14 13:22:09 +00:00
Eloy Lafuente (stronk7) 624d027753 MDL-76666 local_langimport: Better handling of long locales
Under some linux versions, and depending of the configured
locale categories, it's possible to get a current locally
which length > 255 when calling to setlocale(LC_ALL, 0).

Later, if that long locale is tried to be restored, there
is a "setlocale(): Specified locale name is too long" warning
error.

When that happens we need to split the long locale into
individual chunks and set all the (six) locale categories
supported one by one.

Covered with tests, note that, in practice, this only
happens with linux because it supports 12 locale categories
@ OS level. Both BSD (6) and Windows (5) hardly can reach the limit.

No matter of that, the tests have been designed to ensure that
they pass on all OSs, just the new code only will be executed
on linux.
2022-12-14 12:26:27 +01:00
AMOS bot b492fa8255 Automatically generated installer lang files 2022-12-14 00:07:36 +00:00
Andrew Nicols 2d1c45a40e Merge branch 'MDL-76398-311' of https://github.com/paulholden/moodle into MOODLE_311_STABLE 2022-12-11 20:21:17 +08:00
Sara Arjona 13000ae319 weekly release 3.11.11+ 2022-12-09 08:57:13 +01:00
Sara Arjona 81dee5182b Merge branch 'install_311_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_311_STABLE 2022-12-09 08:57:09 +01:00
AMOS bot 44ec3591c0 Automatically generated installer lang files 2022-12-08 00:07:35 +00:00
Jun Pataleta 3ad36ca4f9 Merge branch 'MDL-73017-M311_add-environment-check-for-versions-not-supporting-php-8-1' of https://github.com/ziegenberg/moodle into MOODLE_311_STABLE 2022-12-07 13:47:27 +08:00
Ilya Tregubov ffc0155eab Merge branch 'MDL-76490-311' of https://github.com/paulholden/moodle into MOODLE_311_STABLE 2022-12-06 13:10:47 +03:00
Andrew Nicols 42e3f4d696 Merge branch 'MDL-75446-311' of https://github.com/andelacruz/moodle into MOODLE_311_STABLE 2022-12-06 15:21:01 +08:00
Paul Holden ff446d05f6 MDL-76490 behat: use defined step for interaction with autocomplete. 2022-12-05 14:22:34 +00:00
Marina Glancy a213654a08 MDL-76490 behat: correct step for opening autocomplete in container. 2022-12-05 14:22:05 +00:00
Ilya Tregubov b7947e03ff Merge branch 'MDL-75788-311' of https://github.com/lameze/moodle into MOODLE_311_STABLE 2022-12-05 14:32:56 +03:00
Daniel Ziegenberg 2c18225da4 MDL-73017 env: Moodle 3.9.x, 3.11.x and 4.0.x do not support PHP 8.1
This commit adds an additional environment check for the unsupported
PHP 8.1 version to Moodle 3.9.x, 3.11.x and 4.0.x.

It also updates the lang string for unsupported PHP version.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2022-12-05 11:43:37 +01:00
Angelia Dela Cruz 67edcbd16f MDL-75446 behat: Workshop behat generators use UI
Replace steps that manually add Workshop instances via the UI and use
Behat generators. This improves the speed of the Behat test runs.
2022-12-05 16:49:04 +08:00
AMOS bot a6154a1cab Automatically generated installer lang files 2022-12-04 00:08:25 +00:00
Dani Palou eb7a2e3070 MDL-75788 behat: Use profile field generators in existing tests 2022-12-02 15:04:36 +08:00
Dani Palou 29a6589b8d MDL-75788 testing: Handle new lines in menu profile field generator 2022-12-02 15:04:33 +08:00
Sara Arjona 219206d83e weekly release 3.11.11+ 2022-12-01 16:08:09 +01:00
Jun Pataleta 7391010aac Merge branch 'MDL-76429_311' of https://github.com/stronk7/moodle into MOODLE_311_STABLE 2022-11-30 10:52:28 +08:00
Andrew Nicols 713048a0c9 Merge branch 'MDL-75960-311' of https://github.com/andelacruz/moodle into MOODLE_311_STABLE 2022-11-29 17:05:39 +08:00
Andrew Nicols 9f018ab557 Merge branch 'MDL-65939-311' of https://github.com/ewallah/moodle into MOODLE_311_STABLE 2022-11-29 15:42:38 +08:00
Andrew Nicols 8e6aeda4ba Merge branch 'MDL-76058-311' of https://github.com/lameze/moodle into MOODLE_311_STABLE 2022-11-29 15:37:45 +08:00
Angelia Dela Cruz 8af4bb6a40 MDL-75960 behat: Survey behat generators use UI
Replace steps that manually add Survey instances via the UI and use
Behat generators. This improves the speed of the Behat test runs.
2022-11-28 10:21:24 +08:00
Eloy Lafuente (stronk7) 804ae9ad72 MDL-76429 composer: Bump to phpwebdriver 1.2.1 for php81 compat
This fix is really only required for Moodle 4.1 and up, that will
be the one supporting php81, but we always apply composer changes
to all branches (supported and security), so we keep them running
the same stuff.

Note this comes with a bunch of other small updates, all them
pretty minor and should not be problematic. Better we get them
than keeping them apart.
2022-11-25 16:27:31 +01:00
Ilya Tregubov 75a49ff1b2 weekly release 3.11.11+ 2022-11-25 15:38:33 +03:00
Jun Pataleta 3931e6fe5c Merge branch 'MDL-76340-311' of https://github.com/stevandoMoodle/moodle into MOODLE_311_STABLE 2022-11-25 08:21:40 +08:00
Stevani Andolo 8e195adb84 MDL-76340 VideoJS: Fixed the menu item not being displayed as expected 2022-11-24 22:55:52 +08:00
Paul Holden 44ab3ba8f1 MDL-76398 behat: broader action menu partial matching by element.
For action menu elements whose trigger element isn't plain text
(e.g. a pix icon), we should be able to match via the title of
that element.
2022-11-21 16:59:24 +00:00
Paul Holden 91de19a803 weekly release 3.11.11+ 2022-11-18 11:43:16 +00:00
Paul Holden fcbd95d16d Merge branch 'install_311_STABLE' of https://git.in.moodle.com/amosbot/moodle-install into MOODLE_311_STABLE 2022-11-18 11:43:13 +00:00
AMOS bot ccb7bb2767 Automatically generated installer lang files 2022-11-18 00:07:36 +00:00
info@eWallah.net 09be924480 MDL-65939 phpunit: Maildigest tests can query a wrong adhoc task 2022-11-17 15:52:11 +01:00
Jun Pataleta 9d9a626038 Merge branch 'MDL-76292-311' of https://github.com/lameze/moodle into MOODLE_311_STABLE 2022-11-17 14:53:10 +08:00
Jun Pataleta 9a3cf47a77 Merge branch 'MDL-76310-311' of https://github.com/paulholden/moodle into MOODLE_311_STABLE 2022-11-17 14:39:26 +08:00
Paul Holden 1fb8bedf50 MDL-76310 enrol_lti: fix consumer key upgrade steps for Oracle.
Avoids CLOB comparison exceptions, related to ORA-00932.
2022-11-16 09:28:46 +00:00
Simey Lameze 92b909033e MDL-76292 completion: split criteria duration test into two tests 2022-11-14 16:13:22 +08:00
Simey Lameze 2a36ff8dfb MDL-76058 behat: send message using data generator 2022-11-09 09:52:16 +08:00
81 changed files with 1341 additions and 569 deletions
+1 -1
View File
@@ -51,5 +51,5 @@ moodle-plugin-ci.phar
.eslintignore
.stylelintignore
/jsdoc
.phpcs.xml
phpcs.xml
jsconfig.json
+2 -2
View File
@@ -39,7 +39,7 @@ module.exports = grunt => {
{
rule: {
_attrs: {
ref: './.phpcs.xml.dist',
ref: './phpcs.xml.dist',
},
},
},
@@ -52,7 +52,7 @@ module.exports = grunt => {
});
});
grunt.file.write('.phpcs.xml', toXML(config, {
grunt.file.write('phpcs.xml', toXML(config, {
header: true,
indent: ' ',
}) + "\n");
+2
View File
@@ -3371,6 +3371,7 @@
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.3.0" level="required">
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -3557,6 +3558,7 @@
<VENDOR name="oracle" version="11.2" />
</DATABASE>
<PHP version="7.3.0" level="required">
<RESTRICT function="restrict_php_version_81" message="unsupportedphpversion81" />
</PHP>
<PCREUNICODE level="optional">
<FEEDBACK>
@@ -51,12 +51,12 @@
<div class="form-password">
<span data-passwordunmask="wrapper" data-passwordunmaskid="{{ id }}">
<span data-passwordunmask="editor">
<input type="hidden"
<input type="password"
name="{{ name }}"
id="{{ id }}"
value="{{ value }}"
data-size="{{ size }}"
class="form-control d-inline-block"
class="form-control d-none"
>
</span>
<a href="#" data-passwordunmask="edit" title="{{ edithint }}">
+12
View File
@@ -0,0 +1,12 @@
define("tool_behat/steps",["exports","core/ajax","core/templates","core/pending"],(function(_exports,_ajax,_templates,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function asyncGeneratorStep(gen,resolve,reject,_next,_throw,key,arg){try{var info=gen[key](arg),value=info.value}catch(error){return void reject(error)}info.done?resolve(value):Promise.resolve(value).then(_next,_throw)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_ajax=_interopRequireDefault(_ajax),_templates=_interopRequireDefault(_templates),_pending=_interopRequireDefault(_pending);
/**
* Enhancements for the step definitions page.
*
* @module tool_behat/steps
* @copyright 2022 Catalyst IT EU
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
var getRequiredFieldsContent=function(entityData){var _entityData$required;return null!==(_entityData$required=entityData.required)&&void 0!==_entityData$required&&_entityData$required.length?_templates.default.renderForPromise("tool_behat/steprequiredfields",{fields:entityData.required}):Promise.resolve({html:"",js:""})};_exports.init=function(){var fn,_ref;document.addEventListener("change",(fn=regeneratorRuntime.mark((function _callee(e){var entityElement,stepElement,pendingPromise,entityData,_yield$getRequiredFie,html,js,stepRequiredFields;return regeneratorRuntime.wrap((function(_context){for(;;)switch(_context.prev=_context.next){case 0:if(entityElement=e.target.closest(".entities"),stepElement=e.target.closest(".stepcontent"),entityElement&&stepElement){_context.next=4;break}return _context.abrupt("return");case 4:return pendingPromise=new _pending.default("tool_behat/steps:change"),_context.next=7,entityType=e.target.value,_ajax.default.call([{methodname:"tool_behat_get_entity_generator",args:{entitytype:entityType}}])[0];case 7:return entityData=_context.sent,_context.next=10,getRequiredFieldsContent(entityData);case 10:if(_yield$getRequiredFie=_context.sent,html=_yield$getRequiredFie.html,js=_yield$getRequiredFie.js,!(stepRequiredFields=stepElement.querySelector(".steprequiredfields"))){_context.next=19;break}return _context.next=17,_templates.default.replaceNode(stepRequiredFields,html,js);case 17:_context.next=21;break;case 19:return _context.next=21,_templates.default.appendNodeContents(stepElement,html,js);case 21:pendingPromise.resolve();case 22:case"end":return _context.stop()}var entityType}),_callee)})),_ref=function(){var self=this,args=arguments;return new Promise((function(resolve,reject){var gen=fn.apply(self,args);function _next(value){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"next",value)}function _throw(err){asyncGeneratorStep(gen,resolve,reject,_next,_throw,"throw",err)}_next(void 0)}))},function(_x){return _ref.apply(this,arguments)}))}}));
//# sourceMappingURL=steps.min.js.map
@@ -0,0 +1 @@
{"version":3,"file":"steps.min.js","sources":["../src/steps.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\nimport Ajax from 'core/ajax';\nimport Templates from 'core/templates';\nimport PendingJS from 'core/pending';\n\n/**\n * Enhancements for the step definitions page.\n *\n * @module tool_behat/steps\n * @copyright 2022 Catalyst IT EU\n * @author Mark Johnson <mark.johnson@catalyst-eu.net>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Call the get_entity_generator web service function\n *\n * Takes the name of an entity generator and returns an object containing a list of the required fields.\n *\n * @param {String} entityType\n * @returns {Promise}\n */\nconst getGeneratorEntities = (entityType) => Ajax.call([{\n methodname: 'tool_behat_get_entity_generator',\n args: {entitytype: entityType}\n}])[0];\n\n/**\n * Render HTML for required fields\n *\n * Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.\n *\n * @param {String} entityData\n * @return {Promise}\n */\nconst getRequiredFieldsContent = (entityData) => {\n if (!entityData.required?.length) {\n return Promise.resolve({\n html: '',\n js: ''\n });\n }\n return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});\n};\n\nexport const init = () => {\n // When an entity is selected in the \"the following exist\" step, fetch and display the required fields.\n document.addEventListener('change', async(e) => {\n const entityElement = e.target.closest('.entities');\n const stepElement = e.target.closest('.stepcontent');\n if (!entityElement || !stepElement) {\n return;\n }\n\n const pendingPromise = new PendingJS('tool_behat/steps:change');\n\n const entityData = await getGeneratorEntities(e.target.value);\n const {html, js} = await getRequiredFieldsContent(entityData);\n\n const stepRequiredFields = stepElement.querySelector('.steprequiredfields');\n if (stepRequiredFields) {\n await Templates.replaceNode(stepRequiredFields, html, js);\n } else {\n await Templates.appendNodeContents(stepElement, html, js);\n }\n pendingPromise.resolve();\n });\n};\n"],"names":["getRequiredFieldsContent","entityData","required","_entityData$required","length","Templates","renderForPromise","fields","Promise","resolve","html","js","document","addEventListener","e","entityElement","target","closest","stepElement","pendingPromise","PendingJS","entityType","value","Ajax","call","methodname","args","entitytype","stepRequiredFields","querySelector","replaceNode","appendNodeContents"],"mappings":";;;;;;;;;IAiDMA,yBAA2B,SAACC,yEACzBA,WAAWC,0CAAXC,qBAAqBC,OAMnBC,mBAAUC,iBAAiB,gCAAiC,CAACC,OAAQN,WAAWC,WAL5EM,QAAQC,QAAQ,CACnBC,KAAM,GACNC,GAAI,oBAMI,uBAEhBC,SAASC,iBAAiB,sCAAU,iBAAMC,oNAChCC,cAAgBD,EAAEE,OAAOC,QAAQ,aACjCC,YAAcJ,EAAEE,OAAOC,QAAQ,gBAChCF,eAAkBG,kFAIjBC,eAAiB,IAAIC,iBAAU,2CAhCfC,WAkCwBP,EAAEE,OAAOM,MAlClBC,cAAKC,KAAK,CAAC,CACpDC,WAAY,kCACZC,KAAM,CAACC,WAAYN,eACnB,iBA+BUpB,0CACmBD,yBAAyBC,2DAA3CS,2BAAAA,KAAMC,yBAAAA,KAEPiB,mBAAqBV,YAAYW,cAAc,wEAE3CxB,mBAAUyB,YAAYF,mBAAoBlB,KAAMC,mEAEhDN,mBAAU0B,mBAAmBb,YAAaR,KAAMC,YAE1DQ,eAAeV,mDA3CM,IAACY"}
+82
View File
@@ -0,0 +1,82 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
import Ajax from 'core/ajax';
import Templates from 'core/templates';
import PendingJS from 'core/pending';
/**
* Enhancements for the step definitions page.
*
* @module tool_behat/steps
* @copyright 2022 Catalyst IT EU
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Call the get_entity_generator web service function
*
* Takes the name of an entity generator and returns an object containing a list of the required fields.
*
* @param {String} entityType
* @returns {Promise}
*/
const getGeneratorEntities = (entityType) => Ajax.call([{
methodname: 'tool_behat_get_entity_generator',
args: {entitytype: entityType}
}])[0];
/**
* Render HTML for required fields
*
* Takes the entity data returned from getGeneratorEntities and renders the HTML to display the required fields.
*
* @param {String} entityData
* @return {Promise}
*/
const getRequiredFieldsContent = (entityData) => {
if (!entityData.required?.length) {
return Promise.resolve({
html: '',
js: ''
});
}
return Templates.renderForPromise('tool_behat/steprequiredfields', {fields: entityData.required});
};
export const init = () => {
// When an entity is selected in the "the following exist" step, fetch and display the required fields.
document.addEventListener('change', async(e) => {
const entityElement = e.target.closest('.entities');
const stepElement = e.target.closest('.stepcontent');
if (!entityElement || !stepElement) {
return;
}
const pendingPromise = new PendingJS('tool_behat/steps:change');
const entityData = await getGeneratorEntities(e.target.value);
const {html, js} = await getRequiredFieldsContent(entityData);
const stepRequiredFields = stepElement.querySelector('.steprequiredfields');
if (stepRequiredFields) {
await Templates.replaceNode(stepRequiredFields, html, js);
} else {
await Templates.appendNodeContents(stepElement, html, js);
}
pendingPromise.resolve();
});
};
@@ -0,0 +1,92 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Return data about an entity generator.
*
* @package tool_behat
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_behat\external;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/externallib.php');
/**
* External function for getting properties of entity generators.
*/
class get_entity_generator extends \external_api {
/**
* Define parameters for external function.
*
* The parameter is either in the format 'entity' or 'component_name > entity'. There is no appropriate param type for a
* string like this containing angle brackets, so we will do PARAM_RAW. The value will be parsed by
* behat_data_generators::parse_entity_type, which validates the format of the parameter and throws an exception if it is not
* correct.
*
* @return \external_function_parameters
*/
public static function execute_parameters(): \external_function_parameters {
return new \external_function_parameters([
'entitytype' => new \external_value(PARAM_RAW, 'Entity type that can be created by a generator.'),
]);
}
/**
* Return a list of the required fields for a given entity type.
*
* @param string $entitytype
* @return array
*/
public static function execute(string $entitytype): array {
global $CFG;
// Ensure we can load Behat and Facebook namespaces in behat libraries.
require_once("{$CFG->dirroot}/vendor/autoload.php");
require_once("{$CFG->libdir}/tests/behat/behat_data_generators.php");
$params = self::validate_parameters(self::execute_parameters(), ['entitytype' => $entitytype]);
$context = \context_system::instance();
self::validate_context($context);
require_capability('moodle/site:config', $context);
$generators = new \behat_data_generators();
$entity = $generators->get_entity($params['entitytype']);
return ['required' => $entity['required']];
}
/**
* Define return values.
*
* Return required fields
*
* @return \external_single_structure
*/
public static function execute_returns(): \external_single_structure {
return new \external_single_structure([
'required' => new \external_multiple_structure(
new \external_value(PARAM_TEXT, 'Required field'),
'Required fields',
VALUE_OPTIONAL
),
]);
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Define web service functions for tool_behat
*
* @package tool_behat
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$functions = [
'tool_behat_get_entity_generator' => [
'classname' => 'tool_behat\\external\\get_entity_generator',
'methodname' => 'execute',
'description' => 'Get the generator details for an entity',
'type' => 'read',
'ajax' => true,
'capabilities' => 'moodle/site:config'
]
];
+1
View File
@@ -56,6 +56,7 @@ if ($components) {
$form = new steps_definitions_form(null, array('components' => $componentswithsteps));
// Output contents.
$PAGE->requires->js_call_amd('tool_behat/steps', 'init');
$renderer = $PAGE->get_renderer('tool_behat');
echo $renderer->render_stepsdefinitions($steps, $form);
+28
View File
@@ -24,6 +24,8 @@
defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
/**
* Renderer for behat tool web features
*
@@ -106,6 +108,32 @@ class tool_behat_renderer extends plugin_renderer_base {
},
$stepsdefinitions
);
$elementstrings = [];
$count = 1;
$stepsdefinitions = preg_replace_callback('/(the following ")ELEMENT\d?_STRING(" exist:)/',
function($matches) use (&$elementstrings, &$count) {
// Replace element type arguments with a user-friendly select.
if (empty($elementstrings)) {
$behatgenerators = new behat_data_generators();
$componententities = $behatgenerators->get_all_entities();
ksort($componententities);
$elementstrings = [];
foreach ($componententities as $component => $entities) {
asort($entities);
foreach ($entities as $entity) {
$string = ($component === 'core') ? $entity : $component . ' > ' . $entity;
$elementstrings[$string] = $string;
}
}
}
$select = html_writer::select($elementstrings, 'entities' . $count, '', ['' => 'choosedots'],
['class' => 'entities']);
$count++;
return $matches[1] . $select . $matches[2];
},
$stepsdefinitions
);
}
// Steps definitions.
+6
View File
@@ -29,3 +29,9 @@
#page-admin-tool-behat-index .steps-definitions .stepregex {
color: #060;
}
#page-admin-tool-behat-index .steprequiredfields {
font-weight: bold;
font-size: 1em;
margin-top: 1em;
}
@@ -0,0 +1,33 @@
{{!
This file is part of Moodle - https://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template tool_behat/steprequiredfields
Display a Gherkin-style table row showing required columns for a step.
Example context (json):
{
"fields": [
"user",
"role",
"context"
]
}
}}
<pre class="steprequiredfields">
|{{#fields}} {{{.}}} |{{/fields}}
</pre>
@@ -13,6 +13,10 @@ Feature: List the system steps definitions
Scenario: Accessing the list
Then I should see "Step definitions"
And I should not see "There aren't steps definitions matching this filter"
And I should not see "the following \"ELEMENT_STRING\" exist:"
And "entities1" "select" should exist
And the "entities1" select box should contain "users"
And the "entities1" select box should contain "mod_assign > submissions"
@javascript
Scenario: Filtering by type
@@ -34,3 +38,11 @@ Feature: List the system steps definitions
Then I should not see "There aren't steps definitions matching this filter"
And I should see "Checks the provided element and selector type exists in the current page."
And I should see "Checks that an element and selector type exists in another element and selector type on the current page."
@javascript
Scenario: Get required fields
Given I set the field "entities1" to "users"
And I should see "| username |"
When I set the field "entities1" to "mod_quiz > user overrides"
Then I should not see "| username |"
And I should see "| quiz | user |"
@@ -0,0 +1,104 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Unit tests for get_entity_generator web service
*
* @package tool_behat
* @copyright 2022 onwards Catalyst IT EU {@link https://catalyst-eu.net}
* @author Mark Johnson <mark.johnson@catalyst-eu.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_behat\external;
/**
* Tests for get_entity_generator web service
*
* @covers \tool_behat\external\get_entity_generator
*/
class get_entity_generator_test extends \advanced_testcase {
/**
* Log in as admin
*
* @return void
*/
public function setUp(): void {
$this->resetAfterTest();
$this->setAdminUser();
}
/**
* Get the generator for a core entity.
*
* @return void
*/
public function test_execute_core_entity(): void {
$generator = get_entity_generator::execute('users');
$this->assertEquals(['required' => ['username']], $generator);
}
/**
* Get the generator for the plugin entity.
*
* @return void
*/
public function test_execute_plugin_entity(): void {
$generator = get_entity_generator::execute('mod_book > chapters');
$this->assertEquals(['required' => ['book', 'title', 'content']], $generator);
}
/**
* Get the generator for an entity with no required fields.
*
* @return void
*/
public function test_execute_no_requried(): void {
$generator = get_entity_generator::execute('mod_forum > posts');
$this->assertEquals(['required' => []], $generator);
}
/**
* Attempt to get the generator for a core entity that does not exist.
*
* @return void
*/
public function test_execute_invalid_entity(): void {
$this->expectException('coding_exception');
get_entity_generator::execute('foo');
}
/**
* Attempt to get a generator form a plugin that does not exist.
*
* @return void
*/
public function test_execute_invalid_plugin(): void {
$this->expectException('coding_exception');
get_entity_generator::execute('foo > bar');
}
/**
* Attempt to get a generator for an entity that does not exist, from a plugin that does.
*
* @return void
*/
public function test_execute_invalid_plugin_entity(): void {
$this->expectException('coding_exception');
get_entity_generator::execute('mod_book > bar');
}
}
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2021051700; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2021051701; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2021051100; // Requires this Moodle version.
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
+14 -1
View File
@@ -79,6 +79,19 @@ class locale {
* @return string|false Returns the new current locale, or FALSE on error.
*/
protected function set_locale(int $category = LC_ALL, string $locale = '0') {
return setlocale($category, $locale);
if (strlen($locale) <= 255 || PHP_OS_FAMILY === 'BSD' || PHP_OS_FAMILY === 'Darwin') {
// We can set the whole locale all together.
return setlocale($category, $locale);
}
// Too long locale with linux or windows, let's split it into known and supported categories.
$split = explode(';', $locale);
foreach ($split as $element) {
[$category, $value] = explode('=', $element);
if (defined($category)) { // Only if the category exists, there are OS differences.
setlocale(constant($category), $value);
}
}
return setlocale(LC_ALL, 0); // Finally, return the complete configured locale.
}
}
+101 -11
View File
@@ -14,14 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Tests for \tool_langimport\locale class.
*
* @package tool_langimport
* @copyright 2018 Université Rennes 2 {@link https://www.univ-rennes2.fr}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_langimport;
/**
@@ -29,6 +21,7 @@ namespace tool_langimport;
*
* @package tool_langimport
* @category test
* @coversDefaultClass \tool_langimport\locale
* @copyright 2018 Université Rennes 2 {@link https://www.univ-rennes2.fr}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
@@ -36,6 +29,7 @@ class locale_test extends \advanced_testcase {
/**
* Test that \tool_langimport\locale::check_locale_availability() works as expected.
*
* @covers ::check_locale_availability
* @return void
*/
public function test_check_locale_availability() {
@@ -43,7 +37,7 @@ class locale_test extends \advanced_testcase {
// - first setlocale() call which backup current locale
// - second setlocale() call which try to set new 'es' locale
// - third setlocale() call which restore locale.
$mock = $this->getMockBuilder(\tool_langimport\locale::class)
$mock = $this->getMockBuilder(locale::class)
->onlyMethods(['set_locale'])
->getMock();
$mock->method('set_locale')->will($this->onConsecutiveCalls('en', 'es', 'en'));
@@ -56,7 +50,7 @@ class locale_test extends \advanced_testcase {
// - first setlocale() call which backup current locale
// - second setlocale() call which fail to set new locale
// - third setlocale() call which restore locale.
$mock = $this->getMockBuilder(\tool_langimport\locale::class)
$mock = $this->getMockBuilder(locale::class)
->onlyMethods(['set_locale'])
->getMock();
$mock->method('set_locale')->will($this->onConsecutiveCalls('en', false, 'en'));
@@ -66,8 +60,104 @@ class locale_test extends \advanced_testcase {
$this->assertFalse($result);
// Test an invalid parameter.
$locale = new \tool_langimport\locale();
$locale = new locale();
$this->expectException(\coding_exception::class);
$locale->check_locale_availability('');
}
/**
* Test \tool_langimport\locale::set_locale() own logic.
*
* We have to explicitly test set_locale() own logic and results,
* that effectively sets the current locale, so we need to restore
* the original locale after every test (ugly, from a purist unit test
* point of view, but needed).
*
* @dataProvider set_locale_provider
* @covers ::set_locale
*
* @param string $set locale string to be set.
* @param string $ret expected results returned after setting the locale.
*/
public function test_set_locale(string $set, string $ret) {
// Make set_locale() public.
$loc = new locale();
$rc = new \ReflectionClass(locale::class);
$rm = $rc->getMethod('set_locale');
$rm->setAccessible(true);
// Capture current locale for later restore (funnily, using the set_locale() method itself.
$originallocale = $rm->invokeArgs($loc, [LC_ALL, 0]);
// Assert we get the locale defined as expected.
$this->assertEquals($ret, $rm->invokeArgs($loc, [LC_ALL, $set]));
// We have finished, restore the original locale, so this doesn't affect other tests at distance.
// (again, funnily, using the very same set_locale() method).
$rm->invokeArgs($loc, [LC_ALL, $originallocale]);
}
/**
* Data provider for test_set_locale().
*
* Provides a locale to be set (as 'set') and a expected return value (as 'ret'). Note that
* some of the locales are OS dependent, so only the ones matching the OS will be provided.
*
* We make extensive use of the en_AU.UTF-8/English_Australia.1252 locale that is mandatory to
* be installed in any system running PHPUnit tests.
*/
public function set_locale_provider(): array {
// Let's list the allowed categories by OS.
$bsdallowed = ['LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME'];
$winallowed = ['LC_COLLATE', 'LC_CTYPE', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME'];
$linuxallowed = [
'LC_COLLATE', 'LC_CTYPE', 'LC_MESSAGES', 'LC_MONETARY', 'LC_NUMERIC', 'LC_TIME',
'LC_PAPER', 'LC_NAME', 'LC_ADDRESS', 'LC_TELEPHONE', 'LC_MEASUREMENT', 'LC_IDENTIFICATION'
];
// The base locale name is also OS dependent.
$baselocale = get_string('locale', 'langconfig');
if (PHP_OS_FAMILY === 'Windows') {
$baselocale = get_string('localewin', 'langconfig');
}
// Here we'll go accumulating cases to be provided.
$cases = [];
// First, the simplest case, just pass a locale name, without categories.
$cases['rawlocale'] = [
'set' => $baselocale,
'ret' => $baselocale,
];
// Now, let's fill ALL LC categories, we should get back the locale name if all them are set with same value.
// Note that this case is the one that, under Linux only, covers the changes performed to the set_locale() method.
// Pick the correct categories depending on the OS.
$oscategories = $bsdallowed; // Default to BSD/Dawrwin ones because they are the standard 6 supported by PHP.
if (PHP_OS_FAMILY === 'Windows') {
$oscategories = $winallowed;
} else if (PHP_OS_FAMILY === 'Linux') {
$oscategories = $linuxallowed;
}
$localestr = '';
foreach ($oscategories as $category) {
// Format is different by OS too, so let build the string conditionally.
if (PHP_OS_FAMILY === 'BSD' || PHP_OS_FAMILY === 'Darwin') {
// BSD uses slashes (/) separated list of the 6 values in exact order.
$localestr .= '/' . $baselocale;
} else {
// Linux/Windows use semicolon (;) separated list of category=value pairs.
$localestr .= ';' . $category . '=' . $baselocale;
}
}
$cases['allcategories'] = [
'set' => trim($localestr, ';/'),
'ret' => $baselocale,
];
// Return all the built cases.
return $cases;
}
}
@@ -67,14 +67,10 @@ Feature: Upload users
@javascript
Scenario: Upload users with custom profile fields
# Create user profile field.
Given I log in as "admin"
And I navigate to "Users > Accounts > User profile fields" in site administration
And I click on "Create a new profile field" "link"
And I click on "Text area" "link"
And I set the following fields to these values:
| Short name | superfield |
| Name | Super field |
And I click on "Save changes" "button"
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | superfield | Super field |
And I log in as "admin"
# Upload users.
When I navigate to "Users > Accounts > Upload users" in site administration
And I upload "lib/tests/fixtures/upload_users_profile.csv" file to "File" filemanager
@@ -62,15 +62,10 @@ Feature: availability_profile
@javascript
Scenario: Test with custom user profile field
# Add custom field.
Given I log in as "admin"
And I navigate to "Users > Accounts > User profile fields" in site administration
And I click on "Create a new profile field" "link"
And I click on "Text input" "link"
And I set the following fields to these values:
| Short name | superfield |
| Name | Super field |
And I click on "Save changes" "button"
Given the following "custom profile fields" exist:
| datatype | shortname | name |
| text | superfield | Super field |
And I log in as "admin"
# Set field value for user.
And I navigate to "Users > Accounts > Browse list of users" in site administration
+1 -1
View File
@@ -48,7 +48,7 @@ class backup_files_edit_form extends moodleform {
$mform->setType('component', PARAM_COMPONENT);
$mform->addElement('hidden', 'returnurl', $this->_customdata['returnurl']);
$mform->setType('returnurl', PARAM_URL);
$mform->setType('returnurl', PARAM_LOCALURL);
$this->add_action_buttons(true, get_string('savechanges'));
$this->set_data($this->_customdata['data']);
+5 -12
View File
@@ -15,25 +15,18 @@ Feature: Block appearances
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | description | course | idnumber | section |
| survey | Test survey name | Test survey description | C1 | survey1 | 1 |
| book | Test book name | Test book description | C1 | book1 | 1 |
| activity | name | description | course | idnumber | section | template |
| survey | Test survey name | | C1 | survey1 | 1 | 4 |
| book | Test book name | Test book description | C1 | book1 | 1 | |
And I log in as "admin"
And I am on "Course 1" course homepage
And I follow "Test survey name"
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
| Survey type | ATTLS (20 item version) |
And I press "Save and return to course"
And I am on "Course 1" course homepage with editing mode on
And I follow "Test book name"
And I set the following fields to these values:
| Chapter title | Book title |
| Content | Book content test test |
And I press "Save changes"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
And I am on the "Course 1" course page logged in as teacher1
And I turn editing mode on
And I add the "Comments" block
And I configure the "Comments" block
And I set the following fields to these values:
+3 -4
View File
@@ -14,12 +14,11 @@ Feature: Block region moving
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | course | template |
| survey | Test survey name | C1 | 4 |
And I log in as "admin"
And I am on "Course 1" course homepage with editing mode on
And I add a "Survey" to section "1" and I fill the form with:
| Name | Test survey name |
| Survey type | ATTLS (20 item version) |
| Description | Test survey description |
And I add a "Book" to section "1" and I fill the form with:
| Name | Test book name |
| Description | Test book description |
+1 -1
View File
@@ -64,7 +64,7 @@ class blog_edit_external_form extends moodleform {
$mform->setDefault('id', 0);
$mform->addElement('hidden', 'returnurl');
$mform->setType('returnurl', PARAM_URL);
$mform->setType('returnurl', PARAM_LOCALURL);
$mform->setDefault('returnurl', 0);
}
+43 -17
View File
@@ -108,26 +108,16 @@ class completion_criteria_test extends \advanced_testcase {
}
/**
* Test that enrolment timestart/timecreated are used when duration criteria is marked as completed.
* Test that enrolment timestart are used when duration criteria is marked as completed.
*/
public function test_completion_criteria_duration(): void {
public function test_completion_criteria_duration_timestart(): void {
global $DB;
$timestarted = 1610000000;
$timecreated = 1620000000;
$durationperiod = DAYSECS;
// Create a course and users.
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
$user1 = $this->getDataGenerator()->create_user();
$user2 = $this->getDataGenerator()->create_user();
$studentrole = $DB->get_record('role', ['shortname' => 'student']);
// Enrol User 1 with time start = $timestarted.
$this->getDataGenerator()->enrol_user($user1->id, $course->id, $studentrole->id, 'manual', $timestarted);
// Enrol User 2 with an empty time start, but update the record like it was created at $timecreated.
$this->getDataGenerator()->enrol_user($user2->id, $course->id, $studentrole->id);
$DB->set_field('user_enrolments', 'timecreated', $timecreated, ['userid' => $user2->id]);
$user = $this->getDataGenerator()->create_and_enrol($course, 'student', null, 'manual', $timestarted);
// Set completion criteria.
$criteriadata = (object) [
@@ -147,13 +137,49 @@ class completion_criteria_test extends \advanced_testcase {
sleep(1);
$task->execute();
// The course for User 1 is supposed to be marked as completed at $timestarted + $durationperiod.
$ccompletion = new \completion_completion(['userid' => $user1->id, 'course' => $course->id]);
// The course for User is supposed to be marked as completed at $timestarted + $durationperiod.
$ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
$this->assertEquals($timestarted + $durationperiod, $ccompletion->timecompleted);
$this->assertTrue($ccompletion->is_complete());
}
// The course for User 2 is supposed to be marked as completed at $timecreated + $durationperiod.
$ccompletion = new \completion_completion(['userid' => $user2->id, 'course' => $course->id]);
/**
* Test that enrolment timecreated are used when duration criteria is marked as completed.
*/
public function test_completion_criteria_duration_timecreated(): void {
global $DB;
$timecreated = 1620000000;
$durationperiod = DAYSECS;
// Create a course and users.
$course = $this->getDataGenerator()->create_course(['enablecompletion' => 1]);
// Create and enrol user with an empty time start, but update the record like it was created at $timecreated.
$user = $this->getDataGenerator()->create_and_enrol($course);
$DB->set_field('user_enrolments', 'timecreated', $timecreated, ['userid' => $user->id]);
// Set completion criteria.
$criteriadata = (object) [
'id' => $course->id,
'criteria_duration' => 1,
'criteria_duration_days' => $durationperiod,
];
$criterion = new \completion_criteria_duration();
$criterion->update_config($criteriadata);
// Run completion scheduled task.
$task = new \core\task\completion_regular_task();
$this->expectOutputRegex("/Marking complete/");
$task->execute();
// Hopefully, some day MDL-33320 will be fixed and all these sleeps
// and double cron calls in behat and unit tests will be removed.
sleep(1);
$task->execute();
// The course for user is supposed to be marked as completed at $timecreated + $durationperiod.
$ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]);
$this->assertEquals($timecreated + $durationperiod, $ccompletion->timecompleted);
$this->assertTrue($ccompletion->is_complete());
}
+1 -1
View File
@@ -18,7 +18,7 @@
"behat/mink-goutte-driver": "^1.3",
"symfony/process": "^4.0 || ^5.0",
"behat/behat": "3.11.*",
"oleg-andreyev/mink-phpwebdriver": "^1.0.1"
"oleg-andreyev/mink-phpwebdriver": "^1.2.1"
},
"autoload-dev": {
"psr-0": {
Generated
+139 -134
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "16fbc0e74dc2b087c7088a17baa4625e",
"content-hash": "fa627bec8f3096efcce9cee5d645876a",
"packages": [],
"packages-dev": [
{
@@ -1005,16 +1005,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.15.1",
"version": "v4.15.2",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900"
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
"reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
"reference": "f59bbe44bf7d96f24f3e2b4ddc21cd52c1d2adbc",
"shasum": ""
},
"require": {
@@ -1055,22 +1055,22 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.15.2"
},
"time": "2022-09-04T07:30:47+00:00"
"time": "2022-11-12T15:38:23+00:00"
},
{
"name": "oleg-andreyev/mink-phpwebdriver",
"version": "v1.0.1",
"version": "v1.2.1",
"source": {
"type": "git",
"url": "https://github.com/oleg-andreyev/MinkPhpWebDriver.git",
"reference": "66207ad04b45ad4348dd68ab2a918da2875ae46f"
"reference": "e265917faf79b649f4e5d4419325e02c096caec2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/oleg-andreyev/MinkPhpWebDriver/zipball/66207ad04b45ad4348dd68ab2a918da2875ae46f",
"reference": "66207ad04b45ad4348dd68ab2a918da2875ae46f",
"url": "https://api.github.com/repos/oleg-andreyev/MinkPhpWebDriver/zipball/e265917faf79b649f4e5d4419325e02c096caec2",
"reference": "e265917faf79b649f4e5d4419325e02c096caec2",
"shasum": ""
},
"require": {
@@ -1079,11 +1079,12 @@
"php-webdriver/webdriver": "^1.8"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8",
"behat/mink-extension": "^2.3",
"ext-json": "*",
"mink/driver-testsuite": "dev-integration-branch",
"roave/security-advisories": "dev-master",
"symfony/phpunit-bridge": "^5.2"
"symfony/phpunit-bridge": "^4.4 || ^5.4 || ^6.0"
},
"type": "mink-driver",
"extra": {
@@ -1119,9 +1120,9 @@
],
"support": {
"issues": "https://github.com/oleg-andreyev/MinkPhpWebDriver/issues",
"source": "https://github.com/oleg-andreyev/MinkPhpWebDriver/tree/v1.0.1"
"source": "https://github.com/oleg-andreyev/MinkPhpWebDriver/tree/v1.2.1"
},
"time": "2021-01-30T23:07:29+00:00"
"time": "2022-11-21T15:35:27+00:00"
},
{
"name": "phar-io/manifest",
@@ -1236,16 +1237,16 @@
},
{
"name": "php-webdriver/webdriver",
"version": "1.12.1",
"version": "1.13.1",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "b27ddf458d273c7d4602106fcaf978aa0b7fe15a"
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/b27ddf458d273c7d4602106fcaf978aa0b7fe15a",
"reference": "b27ddf458d273c7d4602106fcaf978aa0b7fe15a",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/6dfe5f814b796c1b5748850aa19f781b9274c36c",
"reference": "6dfe5f814b796c1b5748850aa19f781b9274c36c",
"shasum": ""
},
"require": {
@@ -1295,22 +1296,22 @@
],
"support": {
"issues": "https://github.com/php-webdriver/php-webdriver/issues",
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.12.1"
"source": "https://github.com/php-webdriver/php-webdriver/tree/1.13.1"
},
"time": "2022-05-03T12:16:34+00:00"
"time": "2022-10-11T11:49:44+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.17",
"version": "9.2.23",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "aa94dc41e8661fe90c7316849907cba3007b10d8"
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8",
"reference": "aa94dc41e8661fe90c7316849907cba3007b10d8",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
"reference": "9f1f0f9a2fbb680b26d1cf9b61b6eac43a6e4e9c",
"shasum": ""
},
"require": {
@@ -1366,7 +1367,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.23"
},
"funding": [
{
@@ -1374,7 +1375,7 @@
"type": "github"
}
],
"time": "2022-08-30T12:24:04+00:00"
"time": "2022-12-28T12:41:10+00:00"
},
{
"name": "phpunit/php-file-iterator",
@@ -1619,16 +1620,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.5.24",
"version": "9.5.26",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5"
"reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
"reference": "d0aa6097bef9fd42458a9b3c49da32c6ce6129c5",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/851867efcbb6a1b992ec515c71cdcf20d895e9d2",
"reference": "851867efcbb6a1b992ec515c71cdcf20d895e9d2",
"shasum": ""
},
"require": {
@@ -1650,14 +1651,14 @@
"phpunit/php-timer": "^5.0.2",
"sebastian/cli-parser": "^1.0.1",
"sebastian/code-unit": "^1.0.6",
"sebastian/comparator": "^4.0.5",
"sebastian/comparator": "^4.0.8",
"sebastian/diff": "^4.0.3",
"sebastian/environment": "^5.1.3",
"sebastian/exporter": "^4.0.3",
"sebastian/exporter": "^4.0.5",
"sebastian/global-state": "^5.0.1",
"sebastian/object-enumerator": "^4.0.3",
"sebastian/resource-operations": "^3.0.3",
"sebastian/type": "^3.1",
"sebastian/type": "^3.2",
"sebastian/version": "^3.0.2"
},
"suggest": {
@@ -1701,7 +1702,7 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.24"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.26"
},
"funding": [
{
@@ -1711,9 +1712,13 @@
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
"type": "tidelift"
}
],
"time": "2022-08-30T07:42:16+00:00"
"time": "2022-10-28T06:00:21+00:00"
},
{
"name": "psr/container",
@@ -3027,16 +3032,16 @@
},
{
"name": "symfony/console",
"version": "v5.4.12",
"version": "v5.4.15",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1"
"reference": "ea59bb0edfaf9f28d18d8791410ee0355f317669"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/c072aa8f724c3af64e2c7a96b796a4863d24dba1",
"reference": "c072aa8f724c3af64e2c7a96b796a4863d24dba1",
"url": "https://api.github.com/repos/symfony/console/zipball/ea59bb0edfaf9f28d18d8791410ee0355f317669",
"reference": "ea59bb0edfaf9f28d18d8791410ee0355f317669",
"shasum": ""
},
"require": {
@@ -3106,7 +3111,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v5.4.12"
"source": "https://github.com/symfony/console/tree/v5.4.15"
},
"funding": [
{
@@ -3122,7 +3127,7 @@
"type": "tidelift"
}
],
"time": "2022-08-17T13:18:05+00:00"
"time": "2022-10-26T21:41:52+00:00"
},
{
"name": "symfony/css-selector",
@@ -3192,16 +3197,16 @@
},
{
"name": "symfony/dependency-injection",
"version": "v5.4.11",
"version": "v5.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "a8b9251016e9476db73e25fa836904bc0bf74c62"
"reference": "24cf522668845391c0542bc1de496366072a6d0e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/a8b9251016e9476db73e25fa836904bc0bf74c62",
"reference": "a8b9251016e9476db73e25fa836904bc0bf74c62",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/24cf522668845391c0542bc1de496366072a6d0e",
"reference": "24cf522668845391c0542bc1de496366072a6d0e",
"shasum": ""
},
"require": {
@@ -3261,7 +3266,7 @@
"description": "Allows you to standardize and centralize the way objects are constructed in your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.11"
"source": "https://github.com/symfony/dependency-injection/tree/v5.4.13"
},
"funding": [
{
@@ -3277,7 +3282,7 @@
"type": "tidelift"
}
],
"time": "2022-07-20T13:00:38+00:00"
"time": "2022-08-30T19:10:13+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -3586,16 +3591,16 @@
},
{
"name": "symfony/filesystem",
"version": "v5.4.12",
"version": "v5.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447"
"reference": "ac09569844a9109a5966b9438fc29113ce77cf51"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/2d67c1f9a1937406a9be3171b4b22250c0a11447",
"reference": "2d67c1f9a1937406a9be3171b4b22250c0a11447",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/ac09569844a9109a5966b9438fc29113ce77cf51",
"reference": "ac09569844a9109a5966b9438fc29113ce77cf51",
"shasum": ""
},
"require": {
@@ -3630,7 +3635,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/filesystem/tree/v5.4.12"
"source": "https://github.com/symfony/filesystem/tree/v5.4.13"
},
"funding": [
{
@@ -3646,20 +3651,20 @@
"type": "tidelift"
}
],
"time": "2022-08-02T13:48:16+00:00"
"time": "2022-09-21T19:53:16+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4"
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a",
"reference": "5bbc823adecdae860bb64756d639ecfec17b050a",
"shasum": ""
},
"require": {
@@ -3674,7 +3679,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3712,7 +3717,7 @@
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0"
},
"funding": [
{
@@ -3728,20 +3733,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-intl-grapheme",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
"reference": "433d05519ce6990bf3530fba6957499d327395c2"
"reference": "511a08c03c1960e08a883f4cffcacd219b758354"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/433d05519ce6990bf3530fba6957499d327395c2",
"reference": "433d05519ce6990bf3530fba6957499d327395c2",
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354",
"reference": "511a08c03c1960e08a883f4cffcacd219b758354",
"shasum": ""
},
"require": {
@@ -3753,7 +3758,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3793,7 +3798,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0"
},
"funding": [
{
@@ -3809,20 +3814,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8"
"reference": "639084e360537a19f9ee352433b84ce831f3d2da"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"reference": "59a8d271f00dd0e4c2e518104cc7963f655a1aa8",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/639084e360537a19f9ee352433b84ce831f3d2da",
"reference": "639084e360537a19f9ee352433b84ce831f3d2da",
"shasum": ""
},
"require": {
@@ -3836,7 +3841,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3880,7 +3885,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.27.0"
},
"funding": [
{
@@ -3896,20 +3901,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd"
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/219aa369ceff116e673852dce47c3a41794c14bd",
"reference": "219aa369ceff116e673852dce47c3a41794c14bd",
"url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6",
"shasum": ""
},
"require": {
@@ -3921,7 +3926,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -3964,7 +3969,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0"
},
"funding": [
{
@@ -3980,20 +3985,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534",
"shasum": ""
},
"require": {
@@ -4008,7 +4013,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4047,7 +4052,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0"
},
"funding": [
{
@@ -4063,20 +4068,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php72",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2"
"reference": "869329b1e9894268a8a61dabb69153029b7a8c97"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/bf44a9fd41feaac72b074de600314a93e2ae78e2",
"reference": "bf44a9fd41feaac72b074de600314a93e2ae78e2",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/869329b1e9894268a8a61dabb69153029b7a8c97",
"reference": "869329b1e9894268a8a61dabb69153029b7a8c97",
"shasum": ""
},
"require": {
@@ -4085,7 +4090,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4123,7 +4128,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php72/tree/v1.27.0"
},
"funding": [
{
@@ -4139,20 +4144,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php73",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php73.git",
"reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85"
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85",
"reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85",
"url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
"reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9",
"shasum": ""
},
"require": {
@@ -4161,7 +4166,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4202,7 +4207,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0"
},
"funding": [
{
@@ -4218,20 +4223,20 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php80",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace"
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"shasum": ""
},
"require": {
@@ -4240,7 +4245,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4285,7 +4290,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
},
"funding": [
{
@@ -4301,20 +4306,20 @@
"type": "tidelift"
}
],
"time": "2022-05-10T07:21:04+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/polyfill-php81",
"version": "v1.26.0",
"version": "v1.27.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1"
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/13f6d1271c663dc5ae9fb843a8f16521db7687a1",
"reference": "13f6d1271c663dc5ae9fb843a8f16521db7687a1",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a",
"reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a",
"shasum": ""
},
"require": {
@@ -4323,7 +4328,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.26-dev"
"dev-main": "1.27-dev"
},
"thanks": {
"name": "symfony/polyfill",
@@ -4364,7 +4369,7 @@
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.26.0"
"source": "https://github.com/symfony/polyfill-php81/tree/v1.27.0"
},
"funding": [
{
@@ -4380,7 +4385,7 @@
"type": "tidelift"
}
],
"time": "2022-05-24T11:49:31+00:00"
"time": "2022-11-03T14:55:06+00:00"
},
{
"name": "symfony/process",
@@ -4529,16 +4534,16 @@
},
{
"name": "symfony/string",
"version": "v5.4.12",
"version": "v5.4.15",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "2fc515e512d721bf31ea76bd02fe23ada4640058"
"reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/2fc515e512d721bf31ea76bd02fe23ada4640058",
"reference": "2fc515e512d721bf31ea76bd02fe23ada4640058",
"url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed",
"reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed",
"shasum": ""
},
"require": {
@@ -4595,7 +4600,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v5.4.12"
"source": "https://github.com/symfony/string/tree/v5.4.15"
},
"funding": [
{
@@ -4611,20 +4616,20 @@
"type": "tidelift"
}
],
"time": "2022-08-12T17:03:11+00:00"
"time": "2022-10-05T15:16:54+00:00"
},
{
"name": "symfony/translation",
"version": "v5.4.12",
"version": "v5.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "42ecc77eb4f229ce2df702a648ec93b8478d76ae"
"reference": "f0ed07675863aa6e3939df8b1bc879450b585cab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/42ecc77eb4f229ce2df702a648ec93b8478d76ae",
"reference": "42ecc77eb4f229ce2df702a648ec93b8478d76ae",
"url": "https://api.github.com/repos/symfony/translation/zipball/f0ed07675863aa6e3939df8b1bc879450b585cab",
"reference": "f0ed07675863aa6e3939df8b1bc879450b585cab",
"shasum": ""
},
"require": {
@@ -4692,7 +4697,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/translation/tree/v5.4.12"
"source": "https://github.com/symfony/translation/tree/v5.4.14"
},
"funding": [
{
@@ -4708,7 +4713,7 @@
"type": "tidelift"
}
],
"time": "2022-08-02T15:52:22+00:00"
"time": "2022-10-07T08:01:20+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -4790,16 +4795,16 @@
},
{
"name": "symfony/yaml",
"version": "v5.4.12",
"version": "v5.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "7a3aa21ac8ab1a96cc6de5bbcab4bc9fc943b18c"
"reference": "e83fe9a72011f07c662da46a05603d66deeeb487"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/7a3aa21ac8ab1a96cc6de5bbcab4bc9fc943b18c",
"reference": "7a3aa21ac8ab1a96cc6de5bbcab4bc9fc943b18c",
"url": "https://api.github.com/repos/symfony/yaml/zipball/e83fe9a72011f07c662da46a05603d66deeeb487",
"reference": "e83fe9a72011f07c662da46a05603d66deeeb487",
"shasum": ""
},
"require": {
@@ -4845,7 +4850,7 @@
"description": "Loads and dumps YAML files",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/yaml/tree/v5.4.12"
"source": "https://github.com/symfony/yaml/tree/v5.4.14"
},
"funding": [
{
@@ -4861,7 +4866,7 @@
"type": "tidelift"
}
],
"time": "2022-08-02T15:52:22+00:00"
"time": "2022-10-03T15:15:50+00:00"
},
{
"name": "theseer/tokenizer",
+2 -2
View File
@@ -34,7 +34,7 @@ require_once($CFG->dirroot.'/course/lib.php');
$id = required_param('id', PARAM_INT);
$switchrole = optional_param('switchrole', -1, PARAM_INT);
$returnurl = optional_param('returnurl', '', PARAM_RAW);
$returnurl = optional_param('returnurl', '', PARAM_LOCALURL);
if (strpos($returnurl, '?') === false) {
// Looks like somebody did not set proper page url, better go to course page.
@@ -43,7 +43,7 @@ if (strpos($returnurl, '?') === false) {
if (strpos($returnurl, $CFG->wwwroot) !== 0) {
$returnurl = $CFG->wwwroot.$returnurl;
}
$returnurl = clean_param($returnurl, PARAM_URL);
$returnurl = clean_param($returnurl, PARAM_LOCALURL);
}
$PAGE->set_url('/course/switchrole.php', array('id'=>$id, 'switchrole'=>$switchrole));
+1 -2
View File
@@ -35,9 +35,8 @@ Feature: Rename roles within a course
And I should see "Learner (Student)" in the ".form-autocomplete-suggestions" "css_element"
And I press the escape key
And I set the field "Type or select..." in the "Filter 1" "fieldset" to "Tutor (Non-editing teacher)"
And I click on "Student 1's role assignments" "link"
And I click on ".form-autocomplete-downarrow" "css_element" in the "Student 1" "table_row"
And I open the autocomplete suggestions list in the "Student 1" "table_row"
And "Tutor (Non-editing teacher)" "autocomplete_suggestions" should exist
And I click on "Cancel" "link"
And I press "Enrol users"
+3 -3
View File
@@ -76,9 +76,9 @@ function xmldb_enrol_lti_upgrade($oldversion) {
$sql = "SELECT lu.id, lc.secret
FROM {enrol_lti_users} lu
JOIN {enrol_lti_lti2_consumer} lc
ON (lu.consumerkey = lc.consumerkey256)
ON (" . $DB->sql_compare_text('lu.consumerkey', 255) . " = lc.consumerkey256)
WHERE lc.ltiversion = :ltiversion
AND lu.consumersecret != lc.secret
AND " . $DB->sql_compare_text('lu.consumersecret') . " != lc.secret
AND lu.lastaccess IS NOT NULL";
$affectedltiusersrs = $DB->get_recordset_sql($sql, ['ltiversion' => 'LTI-2p0']);
foreach ($affectedltiusersrs as $ltiuser) {
@@ -98,7 +98,7 @@ function xmldb_enrol_lti_upgrade($oldversion) {
$sql = "SELECT lu.id, lc.secret
FROM {enrol_lti_users} lu
JOIN {enrol_lti_lti2_consumer} lc
ON (lu.consumerkey = lc.consumerkey256)
ON (" . $DB->sql_compare_text('lu.consumerkey', 255) . " = lc.consumerkey256)
WHERE lu.consumersecret IS NULL
AND lu.lastaccess IS NOT NULL";
$affectedltiusersrs = $DB->get_recordset_sql($sql);
+1 -2
View File
@@ -28,9 +28,8 @@ Feature: Users can be added to multiple groups at once
And I am on "Course 1" course homepage
And I follow "Participants"
And I click on "Edit groups for \"Student 1\"" "link" in the "student1" "table_row"
And I click on ".form-autocomplete-downarrow" "css_element" in the "student1" "table_row"
And I open the autocomplete suggestions list in the "student1" "table_row"
And I click on "Group 1" item in the autocomplete list
And I click on ".form-autocomplete-downarrow" "css_element" in the "student1" "table_row"
And I click on "Group 2" item in the autocomplete list
And I press the escape key
And I click on "Save changes" "link" in the "student1" "table_row"
+8 -13
View File
@@ -26,8 +26,7 @@ Feature: We can set the grade to pass value
| name | Test Assignment 1 |
| intro | Submit your online text |
| assignsubmission_onlinetext_enabled | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I am on the "Course 1" course page logged in as teacher1
@javascript
Scenario: Validate that switching the type of grading used correctly disables grade to pass
@@ -115,11 +114,10 @@ Feature: We can set the grade to pass value
Scenario: Set a valid grade to pass for workshop activity
Given the following "activities" exist:
| activity | name | intro | course | section | idnumber |
| workshop | Test Workshop 1 | Test workshop | C1 | 1 | workshop1 |
| activity | name | course | idnumber |
| workshop | Test Workshop 1 | C1 | workshop1 |
And I am on "Course 1" course homepage with editing mode on
And I follow "Test Workshop 1"
And I navigate to "Edit settings" in current page administration
And I am on the "Test Workshop 1" "workshop activity editing" page
And I set the following fields to these values:
| grade | 80 |
| Submission grade to pass | 40 |
@@ -138,19 +136,16 @@ Feature: We can set the grade to pass value
And the field "Grade to pass" matches value "10"
And I set the field "Grade to pass" to "15"
And I press "Save changes"
And I am on "Course 1" course homepage
And I follow "Test Workshop 1"
And I follow "Edit settings"
And I am on the "Test Workshop 1" "workshop activity editing" page
And the field "Submission grade to pass" matches value "45"
And the field "Assessment grade to pass" matches value "15"
Scenario: Set an invalid grade to pass for workshop activity
Given the following "activities" exist:
| activity | name | intro | course | section | idnumber |
| workshop | Test Workshop 1 | Test workshop | C1 | 1 | workshop1 |
| activity | name | course | idnumber |
| workshop | Test Workshop 1 | C1 | workshop1 |
And I am on "Course 1" course homepage with editing mode on
And I follow "Test Workshop 1"
And I navigate to "Edit settings" in current page administration
And I am on the "Test Workshop 1" "workshop activity editing" page
And I set the following fields to these values:
| grade | 80 |
| Submission grade to pass | 90 |
+1 -1
View File
@@ -36,7 +36,7 @@ $string['cannotcreatelangdir'] = 'langディレクトリを作成できません
$string['cannotcreatetempdir'] = 'tempディレクトリを作成できません。';
$string['cannotdownloadcomponents'] = 'コンポーネントをダウンロードできません。';
$string['cannotdownloadzipfile'] = 'ZIPファイルをダウンロードできません。';
$string['cannotfindcomponent'] = 'コンポーネント見つけることができません。';
$string['cannotfindcomponent'] = 'コンポーネント見つかりません。';
$string['cannotsavemd5file'] = 'mp5ファイルを保存できません。';
$string['cannotsavezipfile'] = 'ZIPファイルを保存できません。';
$string['cannotunzipfile'] = 'ZIPファイルを展開できません。';
+32
View File
@@ -0,0 +1,32 @@
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
* Automatically generated strings for Moodle installer
*
* Do not edit this file manually! It contains just a subset of strings
* needed during the very first steps of installation. This file was
* generated automatically by export-installer.php (which is part of AMOS
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
* list of strings defined in /install/stringnames.txt.
*
* @package installer
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$string['thislanguage'] = 'Luganda';
+2 -2
View File
@@ -89,7 +89,7 @@ $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['welcomep20'] = 'Você está vendo esa página pois instalou com sucesso o pacote<strong>{$a->packname} {$a->packversion}</strong>. Parabéns!';
$string['welcomep30'] = 'Esta versão do <strong>{$a->installername}</strong> inclui as aplicações para a criação de um ambiente em que o <strong>Moodle</strong> possa operar:';
$string['welcomep40'] = 'O pacote inclui também o <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
$string['welcomep50'] = 'O uso das aplicações incluídas neste pacote é regulamentado pelas respectivas licenças. O instalador completo <strong>{$a->installername}</strong> é <a href="http://www.opensource.org/docs/definition_plain.html">open source</a> e é distribuído com uma licença <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'As seguinte páginas guiam passo a passo a configuração de <strong>Moodle</strong> no seu computador. Você pode usar a configuração padrão ou alterá-las de acordo com as suas necessidades.';
$string['welcomep50'] = 'O uso de todos os aplicativos deste pacote é regulamentado por suas respectivas licenças. O pacote completo <strong>{$a->installername}</strong> é <a href="https://www.opensource.org/docs/definition_plain.html">código aberto</a> e é distribuído sob a licença <a href="https://www.gnu.org/copyleft/gpl.html">GPL</a>.';
$string['welcomep60'] = 'As páginas a seguir conduzirão você por algumas etapas para configurar e instalar o <strong>Moodle</strong> facilmente em seu computador. Você pode aceitar as configurações padrão ou, opcionalmente, alterá-las para atender às suas próprias necessidades.';
$string['welcomep70'] = 'Clique no botão "Próximo" abaixo para continuar a configuração do <strong>Moodle</strong>.';
$string['wwwroot'] = 'Endereço web';
+4 -4
View File
@@ -33,12 +33,12 @@ $string['clianswerno'] = 'n';
$string['cliansweryes'] = 'd';
$string['cliincorrectvalueerror'] = 'Eroare, valoare incorectă "{$a->value}" pentru "{$a->option}"';
$string['cliincorrectvalueretry'] = 'Valoare incorectă, încercaţi din nou';
$string['clitypevalue'] = 'introduceţi valoarea';
$string['clitypevaluedefault'] = 'introduceţi valoarea, apăsaţi Enter pentru a folosi valoarea implicită ({$a})';
$string['clitypevalue'] = 'introdu valoarea';
$string['clitypevaluedefault'] = 'introdu valoarea, apasă Enter pentru a folosi valoarea implicită ({$a})';
$string['cliunknowoption'] = 'Opţiuni necunoscute:
{$a}
rugăm folosiţi --opţiunea Ajutor.';
$string['cliyesnoprompt'] = 'tastați d (pentru \'da\') sau \'n\' (pentru \'nu\')';
Te rugăm folosește--opţiunea Ajutor.';
$string['cliyesnoprompt'] = 'tastează d (pentru \'da\') sau \'n\' (pentru \'nu\')';
$string['environmentrequireinstall'] = 'trebuie instalat şi activat';
$string['environmentrequireversion'] = 'versiuna necesară este {$a->needed} în timp ce dumneavoastră rulaţi versiunea {$a->current}';
$string['upgradekeyset'] = 'Actualizează cheie (lăsați gol pentru a nu fi setat)';
+7 -6
View File
@@ -1399,12 +1399,13 @@ $string['unsupporteddbfilepertable'] = 'For full support of UTF-8 both MySQL and
$string['unsupporteddblargeprefix'] = 'For full support of UTF-8 both MySQL and MariaDB require you to change your MySQL setting \'innodb_large_prefix\' to \'ON\'. See the documentation for further details.';
$string['unsupporteddbstorageengine'] = 'The database storage engine being used is no longer supported.';
$string['unsupporteddbtablerowformat'] = 'Your database has tables using Antelope as the file format. You are recommended to convert the tables to the Barracuda file format. See the documentation <a href="https://docs.moodle.org/en/cli">Administration via command line</a> for details of a tool for converting InnoDB tables to Barracuda.';
$string['unsupportedphpversion7'] = 'PHP version 7 is not supported.';
$string['unsupportedphpversion71'] = 'PHP version 7.1 is not supported.';
$string['unsupportedphpversion72'] = 'PHP version 7.2 is not supported.';
$string['unsupportedphpversion73'] = 'PHP version 7.3 is not supported.';
$string['unsupportedphpversion74'] = 'PHP version 7.4 is not supported.';
$string['unsupportedphpversion80'] = 'PHP version 8.0 is not supported.';
$string['unsupportedphpversion7'] = 'PHP version 7 and higher are not supported.';
$string['unsupportedphpversion71'] = 'PHP version 7.1 and higher are not supported.';
$string['unsupportedphpversion72'] = 'PHP version 7.2 and higher are not supported.';
$string['unsupportedphpversion73'] = 'PHP version 7.3 and higher are not supported.';
$string['unsupportedphpversion74'] = 'PHP version 7.4 and higher are not supported.';
$string['unsupportedphpversion80'] = 'PHP version 8.0 and higher are not supported.';
$string['unsupportedphpversion81'] = 'PHP version 8.1 and higher are not supported.';
$string['unsuspenduser'] = 'Activate user account';
$string['updateaccounts'] = 'Update existing accounts';
$string['updatecomponent'] = 'Update component';
+1
View File
@@ -112,6 +112,7 @@ $string['america/cayenne'] = 'America/Cayenne';
$string['america/cayman'] = 'America/Cayman';
$string['america/chicago'] = 'America/Chicago';
$string['america/chihuahua'] = 'America/Chihuahua';
$string['america/ciudad_juarez'] = 'America/Ciudad_Juarez';
$string['america/costa_rica'] = 'America/Costa_Rica';
$string['america/creston'] = 'America/Creston';
$string['america/cuiaba'] = 'America/Cuiaba';
@@ -165,6 +165,15 @@ abstract class behat_generator_base {
*/
protected abstract function get_creatable_entities(): array;
/**
* Get the list of available generators for this class.
*
* @return array
*/
final public function get_available_generators(): array {
return $this->get_creatable_entities();
}
/**
* Do the work to generate an entity.
*
+1 -2
View File
@@ -440,13 +440,12 @@ trait behat_session_trait {
if ($containerselectortype === 'NodeElement' && is_a($containerelement, NodeElement::class)) {
// Support a NodeElement being passed in for use in step chaining.
$containernode = $containerelement;
$locatorexceptionmsg = $element;
} else {
// Gets the container, it will always be text based.
$containernode = $this->get_text_selector_node($containerselectortype, $containerelement);
$locatorexceptionmsg = $element . '" in the "' . $containerelement. '" "' . $containerselectortype. '"';
}
$locatorexceptionmsg = $element . '" in the "' . $this->get_selector_description($containerselectortype, $containerelement);
$exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $locatorexceptionmsg);
return $this->find($selectortype, $element, $exception, $containernode);
+1 -1
View File
@@ -145,7 +145,7 @@ XPATH
descendant::*[
contains(concat(' ', normalize-space(@class), ' '), ' dropdown-toggle ')
and
contains(normalize-space(.), %locator%)
(contains(normalize-space(.), %locator%) or descendant::*[%titleMatch%])
]
]
XPATH
+3 -2
View File
@@ -969,8 +969,9 @@ class core_user {
$preferences['user_home_page_preference'] = array('type' => PARAM_INT, 'null' => NULL_ALLOWED, 'default' => HOMEPAGE_MY,
'choices' => array(HOMEPAGE_SITE, HOMEPAGE_MY),
'permissioncallback' => function ($user, $preferencename) {
global $CFG;
return (!empty($CFG->defaulthomepage) && ($CFG->defaulthomepage == HOMEPAGE_USER));
global $CFG, $USER;
return $user->id == $USER->id &&
(!empty($CFG->defaulthomepage) && ($CFG->defaulthomepage == HOMEPAGE_USER));
}
);
+11
View File
@@ -1664,3 +1664,14 @@ function restrict_php_version_74(&$result) {
function restrict_php_version_80($result) {
return restrict_php_version($result, '8.0');
}
/**
* Check if the current PHP version is greater than or equal to
* PHP version 8.1
*
* @param object $result an environment_results instance
* @return bool result of version check
*/
function restrict_php_version_81($result) {
return restrict_php_version($result, '8.1');
}
+5
View File
@@ -1315,6 +1315,11 @@ EOD;
[$data['categoryid']]) + 1;
}
if ($data['datatype'] === 'menu' && isset($data['param1'])) {
// Convert new lines to the proper character.
$data['param1'] = str_replace('\n', "\n", $data['param1']);
}
// Defaults for other values.
$defaults = [
'description' => '',
@@ -575,5 +575,12 @@ class testing_generator_test extends \advanced_testcase {
$field7 = $generator->create_custom_profile_field(
['datatype' => 'checkbox', 'shortname' => 'areyousure', 'name' => 'Are you sure?']);
$this->assertEquals(0, $field7->defaultdata);
// Check setting options for menu using \n work as expected.
$field8 = $generator->create_custom_profile_field([
'datatype' => 'menu', 'shortname' => 'cuisine', 'name' => 'Cuisine', 'param1' => 'French\nChinese\nLebanese',
'defaultdata' => 'Chinese'
]);
$this->assertEquals("French\nChinese\nLebanese", $field8->param1);
}
}
+47
View File
@@ -170,4 +170,51 @@ class behat_data_generators extends behat_base {
$instance = new $componentclass($component);
return $instance;
}
/**
* Get all entities that can be created in all components using the_following_entities_exist()
*
* @return array
* @throws coding_exception
*/
public function get_all_entities(): array {
global $CFG;
// Ensure the generator class is loaded.
require_once($CFG->libdir . '/behat/classes/behat_generator_base.php');
$componenttypes = core_component::get_component_list();
$coregenerator = $this->get_instance_for_component('core');
$pluginswithentities = ['core' => array_keys($coregenerator->get_available_generators())];
foreach ($componenttypes as $components) {
foreach ($components as $component => $componentdir) {
try {
$plugingenerator = $this->get_instance_for_component($component);
$entities = array_keys($plugingenerator->get_available_generators());
if (!empty($entities)) {
$pluginswithentities[$component] = $entities;
}
} catch (Exception $e) {
// The component has no generator, skip it.
continue;
}
}
}
return $pluginswithentities;
}
/**
* Get the required fields for a specific creatable entity.
*
* @param string $entitytype
* @return mixed
* @throws coding_exception
*/
public function get_entity(string $entitytype): array {
[$component, $entity] = $this->parse_entity_type($entitytype);
$generator = $this->get_instance_for_component($component);
$entities = $generator->get_available_generators();
if (!array_key_exists($entity, $entities)) {
throw new coding_exception('No generator for ' . $entity . ' in component ' . $component);
}
return $entities[$entity];
}
}
+1 -1
View File
@@ -718,7 +718,7 @@ class behat_forms extends behat_base {
public function i_open_the_autocomplete_suggestions_list($container = null, $containertype = null) {
$csstarget = ".form-autocomplete-downarrow";
if ($container && $containertype) {
$this->execute('behat_general::i_click_on', [$csstarget, 'css_element', $container, $containertype]);
$this->execute('behat_general::i_click_on_in_the', [$csstarget, 'css_element', $container, $containertype]);
} else {
$this->execute('behat_general::i_click_on', [$csstarget, 'css_element']);
}
+46 -14
View File
@@ -28,6 +28,7 @@
require_once(__DIR__ . '/../../behat/behat_base.php');
use Behat\Gherkin\Node\TableNode;
use Behat\Mink\Element\NodeElement;
use Behat\Mink\Exception\DriverException;
use Behat\Mink\Exception\ElementNotFoundException;
use Behat\Mink\Exception\ExpectationException;
@@ -1162,20 +1163,12 @@ EOF;
* @throws ElementNotFoundException Thrown by behat_base::find
* @param string $element The locator of the specified selector
* @param string $selectortype The selector type
* @param string $containerelement The container selector type
* @param string $containerselectortype The container locator
* @param NodeElement|string $containerelement The locator of the container selector
* @param string $containerselectortype The container selector type
*/
public function should_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) {
// Get the container node.
$containernode = $this->find($containerselectortype, $containerelement);
// Specific exception giving info about where can't we find the element.
$containerdescription = $this->get_selector_description($containerselectortype, $containerelement);
$locatorexceptionmsg = "{$element} not found in the {$containerdescription}}";
$exception = new ElementNotFoundException($this->getSession(), $selectortype, null, $locatorexceptionmsg);
// Looks for the requested node inside the container node.
$this->find($selectortype, $element, $exception, $containernode);
// Will throw an ElementNotFoundException if it does not exist.
$this->get_node_in_container($selectortype, $element, $containerselectortype, $containerelement);
}
/**
@@ -1187,8 +1180,8 @@ EOF;
* @throws ExpectationException
* @param string $element The locator of the specified selector
* @param string $selectortype The selector type
* @param string $containerelement The container selector type
* @param string $containerselectortype The container locator
* @param NodeElement|string $containerelement The locator of the container selector
* @param string $containerselectortype The container selector type
*/
public function should_not_exist_in_the($element, $selectortype, $containerelement, $containerselectortype) {
// Get the container node.
@@ -2157,4 +2150,43 @@ EOF;
// Set the list new list of editors.
set_config('texteditors', implode(',', $list));
}
/**
* Allow to check for minimal Moodle version.
*
* @Given the site is running Moodle version :minversion or higher
* @param string $minversion The minimum version of Moodle required (inclusive).
*/
public function the_site_is_running_moodle_version_or_higher(string $minversion): void {
global $CFG;
require_once($CFG->libdir . '/environmentlib.php');
$currentversion = normalize_version(get_config('', 'release'));
if (version_compare($currentversion, $minversion, '<')) {
throw new Moodle\BehatExtension\Exception\SkippedException(
'Site must be running Moodle version ' . $minversion . ' or higher'
);
}
}
/**
* Allow to check for maximum Moodle version.
*
* @Given the site is running Moodle version :maxversion or lower
* @param string $maxversion The maximum version of Moodle required (inclusive).
*/
public function the_site_is_running_moodle_version_or_lower(string $maxversion): void {
global $CFG;
require_once($CFG->libdir . '/environmentlib.php');
$currentversion = normalize_version(get_config('', 'release'));
if (version_compare($currentversion, $maxversion, '>')) {
throw new Moodle\BehatExtension\Exception\SkippedException(
'Site must be running Moodle version ' . $maxversion . ' or lower'
);
}
}
}
+27
View File
@@ -0,0 +1,27 @@
@core
Feature: Check for minimum or maximimum version of Moodle
In order adapt acceptance tests for different versions of Moodle
As a developer
I should be able to skip tests according to the Moodle version present on a site
Scenario: Minimum version too low
Given the site is running Moodle version 99.0 or higher
# The following steps should not be executed. If they are, the test will fail.
When I log in as "admin"
Then I should not see "Home"
Scenario: Maximum version too high
Given the site is running Moodle version 3.0 or lower
# The following steps should not be executed. If they are, the test will fail.
When I log in as "admin"
Then I should not see "Home"
Scenario: Minimum version OK
Given the site is running Moodle version 3.0 or higher
When I log in as "admin"
Then I should see "Home"
Scenario: Maximum version OK
Given the site is running Moodle version 99.0 or lower
When I log in as "admin"
Then I should see "Home"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+31 -40
View File
@@ -18040,22 +18040,20 @@
var _proto = MenuItem.prototype;
_proto.createEl = function createEl(type, props, attrs) {
var el = _ClickableComponent.prototype.createEl.call(this, type, props, attrs);
var parentSpan = _ClickableComponent.prototype.createEl.call(this, 'li', assign({
// The control is textual, not just an icon
this.nonIconControl = true;
var el = _ClickableComponent.prototype.createEl.call(this, 'li', assign({
className: 'vjs-menu-item',
tabIndex: -1
}, props), attrs);
parentSpan.appendChild(_ClickableComponent.prototype.createEl.call(this, 'span', {
className: 'vjs-icon-placeholder'
}, {
'aria-hidden': true
}));
parentSpan.appendChild(_ClickableComponent.prototype.createEl.call(this, 'span', {
className: 'vjs-control-text',
textContent: this.localize(this.options_.label)
}));
var iconplaceholder = el.querySelector('.vjs-icon-placeholder');
if (typeof iconplaceholder === 'object' && iconplaceholder !== null) {
el.replaceChild(_ClickableComponent.prototype.createEl.call(this, 'span', {
className: 'vjs-menu-item-text',
textContent: this.localize(this.options_.label)
}), iconplaceholder);
}
return el;
}
/**
@@ -19120,23 +19118,19 @@
var _proto = SubsCapsMenuItem.prototype;
_proto.createEl = function createEl(type, props, attrs) {
var el = _TextTrackMenuItem.prototype.createEl.call(this, type, props, attrs);
var el = _TextTrackMenuItem.prototype.createEl.call(this, 'li', assign({
className: 'vjs-menu-item',
tabIndex: -1
}, props), attrs);
var parentSpan = el.querySelector('.vjs-menu-item-text');
if (this.options_.track.kind === 'captions') {
parentSpan.appendChild(createEl('span', {
className: 'vjs-icon-placeholder'
}, {
'aria-hidden': true
}));
parentSpan.appendChild(createEl('span', {
className: 'vjs-control-text',
// space added as the text will visually flow with the
// label
textContent: " " + this.localize('Captions')
}));
const menuitem = el.querySelector('.vjs-menu-item-text');
if (this.options_.track.kind === 'captions' && menuitem) {
const icon = document.createElement("span");
icon.className = 'vjs-icon-placeholder';
menuitem.appendChild(icon);
el.appendChild(menuitem);
}
return el;
};
return SubsCapsMenuItem;
@@ -19285,20 +19279,17 @@
var _proto = AudioTrackMenuItem.prototype;
_proto.createEl = function createEl(type, props, attrs) {
var el = _MenuItem.prototype.createEl.call(this, type, props, attrs);
var el = _MenuItem.prototype.createEl.call(this, 'li', assign({
className: 'vjs-menu-item',
tabIndex: -1
}, props), attrs);
var parentSpan = el.querySelector('.vjs-menu-item-text');
if (this.options_.track.kind === 'main-desc') {
parentSpan.appendChild(_MenuItem.prototype.createEl.call(this, 'span', {
className: 'vjs-icon-placeholder'
}, {
'aria-hidden': true
}));
parentSpan.appendChild(_MenuItem.prototype.createEl.call(this, 'span', {
className: 'vjs-control-text',
textContent: this.localize('Descriptions')
}));
const menuitem = el.querySelector('.vjs-menu-item-text');
if (this.options_.track.kind === 'main' && menuitem) {
const icon = document.createElement("span");
icon.className = 'vjs-icon-placeholder';
menuitem.appendChild(icon);
el.appendChild(menuitem);
}
return el;
+2 -1
View File
@@ -67,4 +67,5 @@ Changes:
In order to improve the validation, a couple of minor changes have been added to the video-lazy.js:
1. Partial upgrade from VideoJS 7.17.0 for 'Subtitles' label check in 18043 - 18059
2. Partial upgrade from VideoJS 7.17.0 for 'Captions' label check from 19123 - 19138
3. Partial upgrade from VideoJS 7.17.0 for 'Description' label check from 19288 - 19302
3. Partial upgrade from VideoJS 7.17.0 for 'Description' label check from 19288 - 19302
4. Fixed the menu item not being displayed as expected
+6 -4
View File
@@ -262,8 +262,10 @@ Feature: Delete messages from conversations
And I click on "//button[@data-action='confirm-delete-selected-messages']" "xpath_element"
And I go back in "view-conversation" message drawer
Then I should not see "Student 2" in the "//*[@data-region='message-drawer']//div[@data-region='view-overview-favourites']" "xpath_element"
And I send "Hi!" message to "Student 2" user
And I go back in "view-conversation" message drawer
And I go back in "view-search" message drawer
And the following "private messages" exist:
| user | contact | message |
| student1 | student2 | Hi! |
And I open messaging
And I open the "Starred" conversations list
And I should see "Student 2" in the "//*[@data-region='message-drawer']//div[@data-region='view-overview-favourites']" "xpath_element"
And I select "Student 2" conversation in the "favourites" conversations list
And I should see "Hi!" in the "Student 2" "core_message > Message conversation"
@@ -118,7 +118,8 @@ Feature: Message delete conversations
And I should not see "Hi!" in the "Student 2" "core_message > Message conversation"
And I go back in "view-conversation" message drawer
And I should not see "Student 2" in the "favourites" "core_message > Message list area"
And I send "Hi!" message to "Student 2" user
And I go back in "view-conversation" message drawer
And I go back in "view-search" message drawer
And the following "private messages" exist:
| user | contact | message |
| student1 | student2 | Hi! |
And I open messaging
And I should see "Student 2" in the "favourites" "core_message > Message list area"
+56 -38
View File
@@ -23,8 +23,12 @@ namespace mod_data;
* @category phpunit
* @copyright 2012 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @coversDefaultClass \mod_data_generator
*/
class generator_test extends \advanced_testcase {
/**
* @covers ::create_instance
*/
public function test_generator() {
global $DB;
@@ -39,9 +43,9 @@ class generator_test extends \advanced_testcase {
$this->assertInstanceOf('mod_data_generator', $generator);
$this->assertEquals('data', $generator->get_modulename());
$generator->create_instance(array('course' => $course->id));
$generator->create_instance(array('course' => $course->id));
$data = $generator->create_instance(array('course' => $course->id));
$generator->create_instance(['course' => $course->id]);
$generator->create_instance(['course' => $course->id]);
$data = $generator->create_instance(['course' => $course->id]);
$this->assertEquals(3, $DB->count_records('data'));
$cm = get_coursemodule_from_instance('data', $data->id);
@@ -52,16 +56,23 @@ class generator_test extends \advanced_testcase {
$context = \context_module::instance($cm->id);
$this->assertEquals($data->cmid, $context->instanceid);
// test gradebook integration using low level DB access - DO NOT USE IN PLUGIN CODE!
$data = $generator->create_instance(array('course' => $course->id, 'assessed' => 1, 'scale' => 100));
$gitem = $DB->get_record('grade_items', array('courseid' => $course->id, 'itemtype' => 'mod',
'itemmodule' => 'data', 'iteminstance' => $data->id));
// Test gradebook integration using low level DB access - DO NOT USE IN PLUGIN CODE!
$data = $generator->create_instance(['course' => $course->id, 'assessed' => 1, 'scale' => 100]);
$gitem = $DB->get_record('grade_items', [
'courseid' => $course->id,
'itemtype' => 'mod',
'itemmodule' => 'data',
'iteminstance' => $data->id,
]);
$this->assertNotEmpty($gitem);
$this->assertEquals(100, $gitem->grademax);
$this->assertEquals(0, $gitem->grademin);
$this->assertEquals(GRADE_TYPE_VALUE, $gitem->gradetype);
}
/**
* @covers ::create_field
*/
public function test_create_field() {
global $DB;
@@ -77,7 +88,7 @@ class generator_test extends \advanced_testcase {
$this->assertInstanceOf('mod_data_generator', $generator);
$this->assertEquals('data', $generator->get_modulename());
$data = $generator->create_instance(array('course' => $course->id));
$data = $generator->create_instance(['course' => $course->id]);
$this->assertEquals(1, $DB->count_records('data'));
$cm = get_coursemodule_from_instance('data', $data->id);
@@ -88,13 +99,12 @@ class generator_test extends \advanced_testcase {
$context = \context_module::instance($cm->id);
$this->assertEquals($data->cmid, $context->instanceid);
$fieldtypes = array('checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url');
$fieldtypes = ['checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url'];
$count = 1;
// Creating test Fields with default parameter values.
foreach ($fieldtypes as $fieldtype) {
// Creating variables dynamically.
$fieldname = 'field-' . $count;
$record = new \stdClass();
@@ -107,17 +117,22 @@ class generator_test extends \advanced_testcase {
$count++;
}
$this->assertEquals(count($fieldtypes), $DB->count_records('data_fields', array('dataid' => $data->id)));
$this->assertEquals(count($fieldtypes), $DB->count_records('data_fields', ['dataid' => $data->id]));
$addtemplate = $DB->get_record('data', array('id' => $data->id), 'addtemplate');
$addtemplate = $DB->get_record('data', ['id' => $data->id], 'addtemplate');
$addtemplate = $addtemplate->addtemplate;
for ($i = 1; $i < $count; $i++) {
$fieldname = 'field-' . $i;
$this->assertTrue(strpos($addtemplate, '[[' . $fieldname . ']]') >= 0);
$position = strpos($addtemplate, '[[' . $fieldname . ']]');
$this->assertIsNumeric($position);
$this->assertGreaterThanOrEqual(0, $position);
}
}
/**
* @covers ::create_entry
*/
public function test_create_entry() {
global $DB;
@@ -130,15 +145,15 @@ class generator_test extends \advanced_testcase {
$course = $this->getDataGenerator()->create_course();
$this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student');
$groupa = $this->getDataGenerator()->create_group(array('courseid' => $course->id, 'name' => 'groupA'));
$this->getDataGenerator()->create_group_member(array('userid' => $user1->id, 'groupid' => $groupa->id));
$groupa = $this->getDataGenerator()->create_group(['courseid' => $course->id, 'name' => 'groupA']);
$this->getDataGenerator()->create_group_member(['userid' => $user1->id, 'groupid' => $groupa->id]);
/** @var mod_data_generator $generator */
$generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$this->assertInstanceOf('mod_data_generator', $generator);
$this->assertEquals('data', $generator->get_modulename());
$data = $generator->create_instance(array('course' => $course->id));
$data = $generator->create_instance(['course' => $course->id]);
$this->assertEquals(1, $DB->count_records('data'));
$cm = get_coursemodule_from_instance('data', $data->id);
@@ -149,14 +164,14 @@ class generator_test extends \advanced_testcase {
$context = \context_module::instance($cm->id);
$this->assertEquals($data->cmid, $context->instanceid);
$fieldtypes = array('checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url',
'latlong', 'file', 'picture');
$fieldtypes = ['checkbox', 'date', 'menu', 'multimenu', 'number', 'radiobutton', 'text', 'textarea', 'url',
'latlong', 'file', 'picture',
];
$count = 1;
// Creating test Fields with default parameter values.
foreach ($fieldtypes as $fieldtype) {
// Creating variables dynamically.
$fieldname = 'field-' . $count;
$record = new \stdClass();
@@ -164,30 +179,27 @@ class generator_test extends \advanced_testcase {
$record->type = $fieldtype;
$record->required = 1;
${$fieldname} = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_field($record, $data);
$this->assertInstanceOf('data_field_' . $fieldtype, ${$fieldname});
$this->getDataGenerator()->get_plugin_generator('mod_data')->create_field($record, $data);
$count++;
}
$this->assertEquals(count($fieldtypes), $DB->count_records('data_fields', array('dataid' => $data->id)));
$fields = $DB->get_records('data_fields', ['dataid' => $data->id], 'id');
$fields = $DB->get_records('data_fields', array('dataid' => $data->id), 'id');
$contents = array();
$contents[] = array('opt1', 'opt2', 'opt3', 'opt4');
$contents = [];
$contents[] = ['opt1', 'opt2', 'opt3', 'opt4'];
$contents[] = '01-01-2037'; // It should be lower than 2038, to avoid failing on 32-bit windows.
$contents[] = 'menu1';
$contents[] = array('multimenu1', 'multimenu2', 'multimenu3', 'multimenu4');
$contents[] = ['multimenu1', 'multimenu2', 'multimenu3', 'multimenu4'];
$contents[] = '12345';
$contents[] = 'radioopt1';
$contents[] = 'text for testing';
$contents[] = '<p>text area testing<br /></p>';
$contents[] = array('example.url', 'sampleurl');
$contents[] = ['example.url', 'sampleurl'];
$contents[] = [-31.9489873, 115.8382036]; // Latlong.
$contents[] = 'Filename.pdf'; // File - filename.
$contents[] = array('Cat1234.jpg', 'Cat'); // Picture - filename with alt text.
$contents[] = ['Cat1234.jpg', 'Cat']; // Picture - filename with alt text.
$count = 0;
$fieldcontents = array();
$fieldcontents = [];
foreach ($fields as $fieldrecord) {
$fieldcontents[$fieldrecord->id] = $contents[$count++];
}
@@ -195,16 +207,20 @@ class generator_test extends \advanced_testcase {
$tags = ['Cats', 'mice'];
$this->setUser($user1);
$datarecordid = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry($data,
$fieldcontents, $groupa->id, $tags);
$datarecordid = $this->getDataGenerator()->get_plugin_generator('mod_data')->create_entry(
$data,
$fieldcontents,
$groupa->id,
$tags
);
$this->assertEquals(1, $DB->count_records('data_records', array('dataid' => $data->id)));
$this->assertEquals(count($contents), $DB->count_records('data_content', array('recordid' => $datarecordid)));
$this->assertEquals(1, $DB->count_records('data_records', ['dataid' => $data->id]));
$this->assertEquals(count($contents), $DB->count_records('data_content', ['recordid' => $datarecordid]));
$entry = $DB->get_record('data_records', array('id' => $datarecordid));
$entry = $DB->get_record('data_records', ['id' => $datarecordid]);
$this->assertEquals($entry->groupid, $groupa->id);
$contents = $DB->get_records('data_content', array('recordid' => $datarecordid), 'id');
$contents = $DB->get_records('data_content', ['recordid' => $datarecordid], 'id');
$contentstartid = 0;
$flag = 0;
@@ -226,7 +242,9 @@ class generator_test extends \advanced_testcase {
$this->assertEquals($contents[$contentstartid]->content1, '1');
$this->assertEquals($contents[++$contentstartid]->content, 'http://example.url');
$this->assertEquals($contents[$contentstartid]->content1, 'sampleurl');
$this->assertEquals(array('Cats', 'mice'),
array_values(\core_tag_tag::get_item_tags_array('mod_data', 'data_records', $datarecordid)));
$this->assertEquals(
['Cats', 'mice'],
array_values(\core_tag_tag::get_item_tags_array('mod_data', 'data_records', $datarecordid))
);
}
}
+4 -4
View File
@@ -653,7 +653,7 @@ class maildigest_test extends \advanced_testcase {
];
$this->queue_tasks_and_assert($expect);
$tasks = $DB->get_records('task_adhoc');
$tasks = $DB->get_records('task_adhoc', ['component' => 'mod_forum']);
$task = reset($tasks);
$this->assertGreaterThanOrEqual(time(), $task->nextruntime);
}
@@ -693,7 +693,7 @@ class maildigest_test extends \advanced_testcase {
];
$this->queue_tasks_and_assert($expect);
$tasks = $DB->get_records('task_adhoc');
$tasks = $DB->get_records('task_adhoc', ['component' => 'mod_forum']);
$task = reset($tasks);
$digesttime = usergetmidnight(time(), \core_date::get_server_timezone()) + ($CFG->digestmailtime * 3600);
$this->assertLessThanOrEqual($digesttime, $task->nextruntime);
@@ -746,7 +746,7 @@ class maildigest_test extends \advanced_testcase {
$this->queue_tasks_and_assert($expect);
// There should now be two tasks queued.
$tasks = $DB->get_records('task_adhoc');
$tasks = $DB->get_records('task_adhoc', ['component' => 'mod_forum']);
$this->assertCount(2, $tasks);
// Add yet another another discussions to forum 1.
@@ -762,7 +762,7 @@ class maildigest_test extends \advanced_testcase {
$this->queue_tasks_and_assert($expect);
// There should still be two tasks queued.
$tasks = $DB->get_records('task_adhoc');
$tasks = $DB->get_records('task_adhoc', ['component' => 'mod_forum']);
$this->assertCount(2, $tasks);
}
@@ -0,0 +1,55 @@
@mod @mod_quiz
Feature: Several attempts in a quiz
As a student
In order to demonstrate what I know
I need to be able to attempt quizzes and sometimes take multiple attempts
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | One | student1@example.com |
| student2 | Student | One | student2@example.com |
| teacher | Teacher | One | teacher@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student2 | C1 | student |
| teacher | C1 | teacher |
And the following "question categories" exist:
| contextlevel | reference | name |
| Course | C1 | Test questions |
And the following "questions" exist:
| questioncategory | qtype | name | questiontext |
| Test questions | truefalse | TF1 | First question |
| Test questions | truefalse | TF2 | Second question |
And the following "activities" exist:
| activity | name | intro | course | idnumber | preferredbehaviour | navmethod |
| quiz | Quiz 1 | Quiz 1 description | C1 | quiz1 | immediatefeedback | free |
And quiz "Quiz 1" contains the following questions:
| question | page | requireprevious |
| TF1 | 1 | 1 |
| TF2 | 2 | 1 |
# Add some attempts
And user "student1" has attempted "Quiz 1" with responses:
| slot | response |
| 1 | True |
| 2 | False |
And user "student2" has attempted "Quiz 1" with responses:
| slot | response |
| 1 | True |
| 2 | True |
# Add a second attempt by student1
And user "student1" has attempted "Quiz 1" with responses:
| slot | response |
| 1 | False |
| 2 | False |
@javascript
Scenario: The redo question buttons are visible after 2 attempts are preset for student1.
Given I am on the "Quiz 1" "mod_quiz > View" page logged in as "student1"
Then "Re-attempt quiz" "button" should exist
And "1" row "Marks / 2.00" column of "quizattemptsummary" table should contain "1.00"
And "2" row "Marks / 2.00" column of "quizattemptsummary" table should contain "0.00"
+10 -7
View File
@@ -103,9 +103,6 @@ class mod_quiz_generator extends testing_module_generator {
/**
* Create a quiz attempt for a particular user at a particular course.
*
* Currently this method can only create a first attempt for each
* user at each quiz. TODO remove this limitation.
*
* @param int $quizid the quiz id (from the mdl_quit table, not cmid).
* @param int $userid the user id.
* @param array $forcedrandomquestions slot => questionid. Optional,
@@ -120,12 +117,18 @@ class mod_quiz_generator extends testing_module_generator {
// Build quiz object and load questions.
$quizobj = quiz::create($quizid, $userid);
if (quiz_get_user_attempts($quizid, $userid, 'all', true)) {
throw new coding_exception('mod_quiz_generator is currently limited to only ' .
'be able to create one attempt for each user. (This should be fixed.)');
$attemptnumber = 1;
$attempt = null;
if ($attempts = quiz_get_user_attempts($quizid, $userid, 'all', true)) {
// There is/are already an attempt/some attempts.
// Take the last attempt.
$attempt = end($attempts);
// Take the attempt number of the last attempt and increase it.
$attemptnumber = $attempt->attempt + 1;
}
return quiz_prepare_and_start_new_attempt($quizobj, 1, null, false,
return quiz_prepare_and_start_new_attempt($quizobj, $attemptnumber, $attempt, false,
$forcedrandomquestions, $forcedvariants);
}
@@ -0,0 +1,44 @@
@mod @mod_scorm
Feature: Scorm availability
In order to control when a SCORM activity is available to students
As a teacher
I need be able to set availability dates for the SCORM
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| student1 | Student | 1 | student1@example.com |
And the following "courses" exist:
| fullname | shortname | category |
| Course 1 | C1 | 0 |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
And the following "activities" exist:
| activity | course | name | packagefilepath | timeopen | timeclose |
| scorm | C1 | Past SCORM | mod/scorm/tests/packages/singlesco_scorm12.zip | ##yesterday## | ##yesterday## |
| scorm | C1 | Current SCORM | mod/scorm/tests/packages/singlesco_scorm12.zip | ##yesterday## | ##tomorrow## |
| scorm | C1 | Future SCORM | mod/scorm/tests/packages/singlesco_scorm12.zip | ##tomorrow## | ##tomorrow## |
Scenario: Scorm activity with dates in the past should not be available.
When I am on the "Past SCORM" "scorm activity" page logged in as "student1"
Then the activity date in "Past SCORM" should contain "Opened:"
And the activity date in "Past SCORM" should contain "##yesterday noon##%A, %d %B %Y, %I:%M##"
And the activity date in "Past SCORM" should contain "Closed:"
And the activity date in "Past SCORM" should contain "##yesterday noon##%A, %d %B %Y, %I:%M##"
And "Enter" "button" should not exist
And I should not see "Preview"
And I am on the "Current SCORM" "scorm activity" page
And the activity date in "Current SCORM" should contain "Opened:"
And the activity date in "Current SCORM" should contain "##yesterday noon##%A, %d %B %Y, %I:%M##"
And the activity date in "Current SCORM" should contain "Closes:"
And the activity date in "Current SCORM" should contain "##tomorrow noon##%A, %d %B %Y, %I:%M##"
And "Enter" "button" should exist
And I should see "Preview"
And I am on the "Future SCORM" "scorm activity" page
And the activity date in "Future SCORM" should contain "Opens:"
And the activity date in "Future SCORM" should contain "##tomorrow noon##%A, %d %B %Y, %I:%M##"
And the activity date in "Future SCORM" should contain "Closes:"
And the activity date in "Future SCORM" should contain "##tomorrow noon##%A, %d %B %Y, %I:%M##"
And I should not see "Enter"
And I should not see "Preview"
@@ -20,24 +20,13 @@ Feature: A teacher can use activity completion to track a student progress
Scenario: Require survey view
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| survey | Test survey name | Test survey description | C1 | survey1 |
And I am on "Course 1" course homepage
And I follow "Test survey name"
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
| Survey type | Critical incidents |
| Completion tracking | Show activity as complete when conditions are met |
| completionview | 1 |
| completionsubmit | 0 |
And I press "Save and return to course"
And I follow "Test survey name"
| activity | name | course | idnumber | template | completion | completionview | completionsubmit |
| survey | Test survey name | C1 | survey1 | 5 | 2 | 1 | 0 |
And I am on the "Test survey name" "survey activity" page
# Teacher view.
And "Test survey name" should have the "View" completion condition
And I log out
# Student view.
When I log in as "student1"
And I am on "Course 1" course homepage
When I am on the "Course 1" course page logged in as student1
And the "View" completion condition of "Test survey name" is displayed as "todo"
And I follow "Test survey name"
And I am on "Course 1" course homepage
@@ -45,24 +34,13 @@ Feature: A teacher can use activity completion to track a student progress
Scenario: Require survey submission
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| survey | Test survey name | Test survey description | C1 | survey1 |
And I am on "Course 1" course homepage
And I follow "Test survey name"
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
| Survey type | Critical incidents |
| Completion tracking | Show activity as complete when conditions are met |
| completionview | 1 |
| completionsubmit | 1 |
And I press "Save and return to course"
And I follow "Test survey name"
| activity | name | course | idnumber | template | completion | completionview | completionsubmit |
| survey | Test survey name | C1 | survey1 | 5 | 2 | 1 | 1 |
And I am on the "Test survey name" "survey activity" page
# Teacher view.
And "Test survey name" should have the "Submit answers" completion condition
And I log out
# Student view.
When I log in as "student1"
And I am on "Course 1" course homepage
When I am on the "Course 1" course page logged in as student1
And the "Submit answers" completion condition of "Test survey name" is displayed as "todo"
And I follow "Test survey name"
And the "Submit answers" completion condition of "Test survey name" is displayed as "todo"
@@ -75,16 +53,13 @@ Feature: A teacher can use activity completion to track a student progress
@javascript
Scenario: Use manual completion
Given the following "activities" exist:
| activity | name | intro | course | idnumber | completion |
| survey | Test survey name | Test survey description | C1 | survey1 | 1 |
| activity | name | course | idnumber | completion |
| survey | Test survey name | C1 | survey1 | 1 |
And I am on "Course 1" course homepage
# Teacher view.
And the manual completion button for "Test survey name" should be disabled
And I log out
# Student view.
When I log in as "student1"
And I am on "Course 1" course homepage
And I follow "Test survey name"
When I am on the "Test survey name" "survey activity" page logged in as student1
Then the manual completion button of "Test survey name" is displayed as "Mark as done"
And I toggle the manual completion state of "Test survey name"
And the manual completion button of "Test survey name" is displayed as "Done"
@@ -18,17 +18,11 @@ Feature: A teacher navigates to response reports of students
| student1 | C1 | student |
| student2 | C1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| survey | Test survey name | Test survey description | C1 | survey1 | 1 |
| activity | name | course | idnumber | template |
| survey | Test survey name | C1 | survey1 | 5 |
Scenario: Only questions and participants page should be available under response reports as teacher
Given I am on the "Test survey name" "survey activity" page logged in as teacher1
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
| Survey type | Critical incidents |
And I press "Save and return to course"
And I log out
And I am on the "Test survey name" "survey activity" page logged in as student1
Given I am on the "Test survey name" "survey activity" page logged in as student1
And I set the field "At what moment in class were you most engaged as a learner?" to "most engaged as student1"
And I set the field "At what moment in class were you most distanced as a learner?" to "most distanced as student1"
And I set the field "What action from anyone in the forums did you find most affirming or helpful?" to "most helpful student1"
@@ -36,7 +30,6 @@ Feature: A teacher navigates to response reports of students
And I set the field "What event surprised you most?" to "most surprised student1"
And I press "Click here to continue"
And I press "Continue"
And I log out
And I am on the "Test survey name" "survey activity" page logged in as student2
And I set the field "At what moment in class were you most engaged as a learner?" to "most engaged as student2"
And I set the field "At what moment in class were you most distanced as a learner?" to "most distanced as student2"
@@ -45,7 +38,6 @@ Feature: A teacher navigates to response reports of students
And I set the field "What event surprised you most?" to "most surprised student1"
And I press "Click here to continue"
And I press "Continue"
And I log out
When I am on the "Test survey name" "survey activity" page logged in as teacher1
And "Summary" "link" should not exist in current page administration
And "Scales" "link" should not exist in current page administration
+20 -9
View File
@@ -4,7 +4,7 @@ Feature: A teacher can set three types of survey activity
As a teacher
I need to set survey activities and select which survey type suits my needs
Scenario: Switching between the three survey types
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.com |
@@ -14,17 +14,16 @@ Feature: A teacher can set three types of survey activity
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| survey | Test survey name | Test survey description | C1 | survey1 | 1 |
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I follow "Test survey name"
And I navigate to "Edit settings" in current page administration
Scenario: Switching between the three survey types
Given the following "activities" exist:
| activity | name | course | idnumber |
| survey | Test survey name | C1 | survey1 |
And I am on the "Test survey name" "survey activity editing" page
And I set the following fields to these values:
| Survey type | ATTLS (20 item version) |
And I press "Save and return to course"
And I follow "Test survey name"
And I press "Save and display"
Then I should see "Attitudes Towards Thinking and Learning"
And I navigate to "Edit settings" in current page administration
And I set the following fields to these values:
@@ -37,3 +36,15 @@ Feature: A teacher can set three types of survey activity
And I press "Save and display"
And I should see "In this online unit..."
And I should see "my learning focuses on issues that interest me."
@javascript
Scenario: Survey activity is create via UI
Given I am on the "Course 1" course page
And I turn editing mode on
And I add a "Survey" to section "1"
And I set the following fields to these values:
| Name | Test survey name |
| Description | Test survey description |
| Survey type | ATTLS (20 item version) |
When I press "Save and return to course"
Then I should see "Test survey name"
+1 -1
View File
@@ -36,7 +36,7 @@ class mod_wiki_filesedit_form extends moodleform {
$mform->addElement('filemanager', 'files_filemanager', get_string('files'), null, $options);
$mform->addElement('hidden', 'returnurl', $data->returnurl);
$mform->setType('returnurl', PARAM_URL);
$mform->setType('returnurl', PARAM_LOCALURL);
$mform->addElement('hidden', 'subwiki', $data->subwikiid);
$mform->setType('subwiki', PARAM_INT);
@@ -21,45 +21,33 @@ Feature: Workshop submission removal
| student3 | c1 | student |
| teacher1 | c1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypefile |
| workshop | TestWorkshop | Test workshop description | c1 | workshop1 | 1 |
| activity | name | course | idnumber | submissiontypefile |
| workshop | TestWorkshop | c1 | workshop1 | 1 |
# Teacher sets up assessment form and changes the phase to submission.
And I log in as "teacher1"
And I am on "Course1" course homepage
And I am on the "Course1" course page logged in as teacher1
And I edit assessment form in workshop "TestWorkshop" as:"
| id_description__idx_0_editor | Aspect1 |
| id_description__idx_1_editor | Aspect2 |
| id_description__idx_2_editor | |
And I change phase in workshop "TestWorkshop" to "Submission phase"
And I log out
# Student1 submits.
And I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
And I am on the "TestWorkshop" "workshop activity" page logged in as student1
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission1 |
| Submission content | Some content |
And I log out
# Student2 submits.
And I log in as "student2"
And I am on "Course1" course homepage
And I am on the "Course1" course page logged in as student2
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission2 |
| Submission content | Some content |
And I log out
# Teacher allocates student3 to be reviewer of student2's submission.
And I log in as "teacher1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
And I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
And I allocate submissions in workshop "TestWorkshop" as:"
| Participant | Reviewer |
| Sam2 Student2 | Sam3 Student3 |
And I log out
Scenario: Students can delete their submissions as long as the submissions are editable and not allocated for assessments
Given I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
Given I am on the "TestWorkshop" "workshop activity" page logged in as student1
When I follow "Submission1"
Then I should see "Submission1"
And "Delete submission" "button" should exist
@@ -70,30 +58,21 @@ Feature: Workshop submission removal
And I should see "You have not submitted your work yet"
Scenario: Students cannot delete their submissions if the submissions are not editable
Given I log in as "teacher1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
Given I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
And I change phase in workshop "TestWorkshop" to "Closed"
And I log out
And I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
And I am on the "TestWorkshop" "workshop activity" page logged in as student1
When I follow "Submission1"
Then I should see "Submission1"
And "Delete submission" "button" should not exist
Scenario: Students cannot delete their submissions if the submissions are allocated for assessments
Given I log in as "student2"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
Given I am on the "TestWorkshop" "workshop activity" page logged in as student2
When I follow "Submission2"
Then I should see "Submission2"
And "Delete submission" "button" should not exist
Scenario: Teachers can delete submissions even if the submissions are allocated for assessments.
Given I log in as "teacher1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
Given I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
And "Submission1" "link" should exist
And "Submission2" "link" should exist
When I follow "Submission2"
@@ -16,16 +16,23 @@ Feature: Teachers can embed images into instructions and conclusion fields
And the following "course enrolments" exist:
| user | course | role |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | course | name |
| workshop | C1 | Workshop with embedded images |
And I am on the "Workshop with embedded images" "workshop activity editing" page logged in as admin
And I set the following fields to these values:
| instructauthorseditor[format] | 1 |
| instructreviewerseditor[format] | 1 |
| conclusioneditor[format] | 1 |
And I press "Save and display"
And I log out
And I log in as "teacher1"
# Upload an image into the private files.
And I follow "Manage private files"
And I upload "mod/workshop/tests/fixtures/moodlelogo.png" file to "Files" filemanager
And I click on "Save changes" "button"
And I am on "Course 1" course homepage with editing mode on
# Create and edit the workshop.
When I add a "Workshop" to section "1" and I fill the form with:
| Workshop name | Workshop with embedded images |
And I am on the "Workshop with embedded images" "workshop activity editing" page
# Edit the workshop.
When I am on the "Workshop with embedded images" "workshop activity editing" page
And I expand all fieldsets
And I set the field "Instructions for submission" to "<p>Image test</p>"
And I select the text in the "Instructions for submission" Atto editor
@@ -17,11 +17,10 @@ Feature: Provide example submission
| user | course | role |
| teacher1 | c1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | useexamples |
| workshop | TestWorkshop | Test workshop description | c1 | workshop1 | 1 |
| activity | name | course | idnumber | useexamples |
| workshop | TestWorkshop | c1 | workshop1 | 1 |
# As a teacher, define the assessment form to be used in the workshop.
When I log in as "teacher1"
And I am on "Course1" course homepage
When I am on the "Course1" course page logged in as teacher1
And I edit assessment form in workshop "TestWorkshop" as:"
| id_description__idx_0_editor | Aspect1 |
| id_description__idx_1_editor | Aspect2 |
@@ -19,8 +19,8 @@ Feature: Exporting workshop submissions and assessments to a portfolio
| student2 | c1 | student |
| teacher1 | c1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypefile |
| workshop | TestWorkshop | Test workshop description | c1 | workshop1 | 1 |
| activity | name | course | idnumber | submissiontypefile |
| workshop | TestWorkshop | c1 | workshop1 | 1 |
# Admin needs to enable portfolio API and set a portfolio instance first.
And I log in as "admin"
And the following config values are set as admin:
@@ -28,34 +28,24 @@ Feature: Exporting workshop submissions and assessments to a portfolio
And I navigate to "Plugins > Portfolios > Manage portfolios" in site administration
And I set portfolio instance "File download" to "Enabled and visible"
And I click on "Save" "button"
And I log out
# Teacher sets up assessment form and changes the phase to submission.
And I log in as "teacher1"
And I am on "Course1" course homepage
And I am on the "Course1" course page logged in as teacher1
And I edit assessment form in workshop "TestWorkshop" as:"
| id_description__idx_0_editor | Aspect1 |
| id_description__idx_1_editor | Aspect2 |
And I change phase in workshop "TestWorkshop" to "Submission phase"
And I log out
# Student1 submits.
And I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
And I am on the "TestWorkshop" "workshop activity" page logged in as student1
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission1 |
| Submission content | Some content |
And I log out
# Student2 submits.
And I log in as "student2"
And I am on "Course1" course homepage
And I am on the "Course1" course page logged in as student2
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission2 |
| Submission content | Some content |
And I log out
# Teacher allocates reviewers and changes the phase to assessment.
And I log in as "teacher1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
And I am on the "TestWorkshop" "workshop activity" page logged in as teacher1
And I should see "to allocate: 2"
And I should see "Workshop submissions report"
And I should see "Submitted (2) / not submitted (0)"
@@ -68,12 +58,9 @@ Feature: Exporting workshop submissions and assessments to a portfolio
And I follow "TestWorkshop"
And I should see "to allocate: 0"
And I change phase in workshop "TestWorkshop" to "Assessment phase"
And I log out
Scenario: Students can export their own submission to a portfolio.
Given I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
Given I am on the "TestWorkshop" "workshop activity" page logged in as student1
When I follow "Submission1"
Then I should see "Submission1"
And "Export this page" "button" should exist
@@ -83,12 +70,9 @@ Feature: Exporting workshop submissions and assessments to a portfolio
And I should see "Summary of your export"
And I click on "Continue" "button"
And I should see "Return to where you were"
And I log out
Scenario: Students can export submission they have peer-assessed.
Given I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
Given I am on the "TestWorkshop" "workshop activity" page logged in as student1
And I should see "Submission2"
And I follow "Submission2"
And "Export this page" "button" should exist
@@ -98,14 +82,11 @@ Feature: Exporting workshop submissions and assessments to a portfolio
And I should see "Summary of your export"
And I click on "Continue" "button"
And I should see "Return to where you were"
And I log out
Scenario: If the portfolio API is disabled, the portfolio export button is not displayed.
Given the following config values are set as admin:
| enableportfolios | 0 |
When I log in as "student1"
And I am on "Course1" course homepage
And I follow "TestWorkshop"
When I am on the "TestWorkshop" "workshop activity" page logged in as student1
And I follow "Submission1"
Then I should see "Submission1"
And "Export this page" "button" should not exist
@@ -19,19 +19,17 @@ Feature: File types of the submission and feedback attachments can be limitted
| student1 | c1 | student |
| student2 | c1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | TestWorkshop | Test workshop description | c1 | workshop1 | 2 | 1 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | TestWorkshop | c1 | workshop1 | 2 | 1 |
@_file_upload @javascript
Scenario: Student submission attachments obey the list of allowed file types
# Define workshop to accept only images as submission attachments.
Given I am on the TestWorkshop "workshop activity" page logged in as teacher1
And I navigate to "Edit settings" in current page administration
Given I am on the "TestWorkshop" "workshop activity editing" page logged in as teacher1
And I expand all fieldsets
And I set the field "Submission attachment allowed file types" to "image"
And I press "Save and display"
And I change phase in workshop "TestWorkshop" to "Submission phase"
And I log out
# As a student, attempt to attach a non-image file.
And I am on the TestWorkshop "workshop activity" page logged in as student1
And I press "Add submission"
@@ -58,8 +56,7 @@ Feature: File types of the submission and feedback attachments can be limitted
@_file_upload @javascript
Scenario: Overall feedback attachments obey the list of allowed file types
# Define workshop to accept only .php files as overall feedback attachments.
Given I log in as "teacher1"
And I am on "Course1" course homepage
Given I am on the "Course1" course page logged in as teacher1
And I edit assessment form in workshop "TestWorkshop" as:"
| id_description__idx_0_editor | Aspect1 |
| id_description__idx_1_editor | Aspect2 |
@@ -70,20 +67,17 @@ Feature: File types of the submission and feedback attachments can be limitted
And I set the field "Feedback attachment allowed file types" to "PHP"
And I press "Save and display"
And I change phase in workshop "TestWorkshop" to "Submission phase"
And I log out
# As a student, attempt to attach an invalid file.
And I am on the TestWorkshop "workshop activity" page logged in as student1
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission1 |
| Submission content | Some content |
And I log out
# As a teacher, allocate that submission to be assessed by another student.
And I am on the TestWorkshop "workshop activity" page logged in as teacher1
And I allocate submissions in workshop "TestWorkshop" as:"
| Participant | Reviewer |
| Sam1 Student1 | Sam2 Student2 |
And I change phase in workshop "TestWorkshop" to "Assessment phase"
And I log out
# As the other student, assess the assigned submission.
And I am on the TestWorkshop "workshop activity" page logged in as student2
And I follow "Submission1"
+14 -18
View File
@@ -17,8 +17,8 @@ Feature: Setting grades to pass via workshop editing form
Scenario: Adding a new workshop with grade to pass field set
Given the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| workshop | Awesome workshop | Grades to pass are set here | c1 | workshop1 | 1 |
| activity | name | course | idnumber |
| workshop | Awesome workshop | c1 | workshop1 |
When I am on the "Awesome workshop" "workshop activity editing" page logged in as teacher1
And I set the field "Submission grade to pass" to "45"
And I set the field "Assessment grade to pass" to "10.5"
@@ -29,14 +29,10 @@ Feature: Setting grades to pass via workshop editing form
@javascript
Scenario: Grade to pass kept even with submission types without online text (MDL-64862)
Given I log in as "teacher1"
And I am on "Course1" course homepage with editing mode on
When I add a "Workshop" to section "1" and I fill the form with:
| Workshop name | Another workshop |
| Description | Grades to pass are set here |
| Submission grade to pass | 42 |
| Assessment grade to pass | 10.1 |
| submissiontypetextavailable | 0 |
Given the following "activities" exist:
| activity | course | name | submissiongradepass | gradinggradepass | submissiontypetextavailable |
| workshop | c1 | Another workshop | 42 | 10.1 | 0 |
When I am on the "Course1" course page logged in as teacher1
Then I should not see "Adding a new Workshop"
And I am on the "Another workshop" "workshop activity editing" page
And the field "Submission grade to pass" matches value "42.00"
@@ -44,16 +40,16 @@ Feature: Setting grades to pass via workshop editing form
Scenario: Adding a new workshop with grade to pass fields left empty
Given the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| workshop | Another awesome workshop | No grades to pass are set here | c1 | workshop1 | 1 |
| activity | name | course | idnumber |
| workshop | Another awesome workshop | c1 | workshop1 |
When I am on the "Another awesome workshop" "workshop activity editing" page logged in as teacher1
Then the field "Submission grade to pass" matches value "0.00"
And the field "Assessment grade to pass" matches value "0.00"
Scenario: Adding a new workshop with non-numeric value of a grade to pass
Given the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| workshop | Another awesome workshop | Invalid grade to pass is set here | c1 | workshop1 | 1 |
| activity | name | course | idnumber | section |
| workshop | Another awesome workshop | c1 | workshop1 | 1 |
When I am on the "Another awesome workshop" "workshop activity editing" page logged in as teacher1
And I set the field "Assessment grade to pass" to "You shall not pass!"
And I press "Save and return to course"
@@ -62,8 +58,8 @@ Feature: Setting grades to pass via workshop editing form
Scenario: Adding a new workshop with invalid value of a grade to pass
Given the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| workshop | Almost awesome workshop | Invalid grade to pass is set here | c1 | workshop1 | 1 |
| activity | name | course | idnumber | section |
| workshop | Almost awesome workshop | c1 | workshop1 | 1 |
When I am on the "Almost awesome workshop" "workshop activity editing" page logged in as teacher1
And I set the field "Assessment grade to pass" to "10000000"
And I press "Save and return to course"
@@ -72,8 +68,8 @@ Feature: Setting grades to pass via workshop editing form
Scenario: Emptying grades to pass fields sets them to zero
Given the following "activities" exist:
| activity | name | intro | course | idnumber | section |
| workshop | Super awesome workshop | Grade to pass are set and then unset here | c1 | workshop1 | 1 |
| activity | name | course | idnumber | section |
| workshop | Super awesome workshop | c1 | workshop1 | 1 |
When I am on the "Super awesome workshop" "workshop activity editing" page logged in as teacher1
And I set the field "Submission grade to pass" to "59.99"
And I set the field "Assessment grade to pass" to "0.000"
@@ -67,8 +67,8 @@ Feature: Submission types
@javascript @_file_upload
Scenario: All submission fields required
Given the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | All required | Test workshop description | TEST | workshop1 | 2 | 2 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | All required | TEST | workshop1 | 2 | 2 |
And I am on the "All required" "workshop activity" page
And I follow "Switch to the submission phase"
And I press "Continue"
@@ -88,8 +88,8 @@ Feature: Submission types
Scenario: Online text required, file attachment optional
Given the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Optional file | Test workshop description | TEST | workshop1 | 2 | 1 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Optional file | TEST | workshop1 | 2 | 1 |
And I am on the "Optional file" "workshop activity" page
And I follow "Switch to the submission phase"
And I press "Continue"
@@ -107,8 +107,8 @@ Feature: Submission types
@javascript @_file_upload
Scenario: Online text optional, file attachment required
Given the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Optional text | Test workshop description | TEST | workshop1 | 1 | 2 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Optional text | TEST | workshop1 | 1 | 2 |
And I am on the "Optional text" "workshop activity" page
And I follow "Switch to the submission phase"
And I press "Continue"
@@ -125,8 +125,8 @@ Feature: Submission types
Scenario: Online text only
Given the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Only text | Test workshop description | TEST | workshop1 | 2 | 0 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Only text | TEST | workshop1 | 2 | 0 |
And I am on the "Only text" "workshop activity" page
And I follow "Switch to the submission phase"
And I press "Continue"
@@ -145,8 +145,8 @@ Feature: Submission types
@javascript @_file_upload
Scenario: File attachment only
Given the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Only file | Test workshop description | TEST | workshop1 | 0 | 2 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | Only file | TEST | workshop1 | 0 | 2 |
And I am on the "Only file" "workshop activity" page
And I follow "Switch to the submission phase"
And I press "Continue"
@@ -166,8 +166,8 @@ Feature: Submission types
@javascript @_file_upload
Scenario: Neither submission type explicitly required
Given the following "activities" exist:
| activity | name | intro | course | idnumber |
| workshop | Neither required | Test workshop description | TEST | workshop1 |
| activity | name | course | idnumber |
| workshop | Neither required | TEST | workshop1 |
And I am on the "Neither required" "workshop activity" page
And I follow "Switch to the submission phase"
And I press "Continue"
@@ -19,8 +19,8 @@ Feature: View activity completion information in the Workshop activity
| student2 | C1 | student |
| teacher1 | C1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | submissiontypefile | completion | completionview |
| workshop | Music history | Test workshop description | C1 | 1 | 2 | 1 |
| activity | name | course | submissiontypefile | completion | completionview |
| workshop | Music history | C1 | 1 | 2 | 1 |
And I am on the "Music history" "workshop activity editing" page logged in as teacher1
And I set the following fields to these values:
| Require grade | Submission |
@@ -28,10 +28,9 @@ Feature: View activity completion information in the Workshop activity
And I edit assessment form in workshop "Music history" as:"
| id_description__idx_0_editor | Aspect1 |
And I change phase in workshop "Music history" to "Submission phase"
And I log out
Scenario: View automatic completion items as a teacher
Given I am on the "Music history" "workshop activity" page logged in as teacher1
Given I am on the "Music history" "workshop activity" page
Then "Music history" should have the "Receive a grade" completion condition
And "Music history" should have the "View" completion condition
@@ -44,28 +43,22 @@ Feature: View activity completion information in the Workshop activity
And I set the field "Title" to "Pinch harmonics"
And I set the field "Submission content" to "Satisfying to play"
And I press "Save changes"
And I log out
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I am on the "Course 1" course page logged in as teacher1
And I change phase in workshop "Music history" to "Assessment phase"
And I allocate submissions in workshop "Music history" as:"
| Participant | Reviewer |
| Vinnie Student1 | Rex Student2 |
And I log out
# Assess the submission.
And I am on the "Music history" "workshop activity" page logged in as student2
And I assess submission "Pinch harmonics" in workshop "Music history" as:"
| grade__idx_0 | 9 / 10 |
| peercomment__idx_0 | Well done |
And I log out
# Evaluate and close the workshop so a grade is recorded for the student.
And I log in as "teacher1"
And I am on "Course 1" course homepage
And I am on the "Course 1" course page logged in as teacher1
And I change phase in workshop "Music history" to "Grading evaluation phase"
And I follow "Music history"
And I click on "Re-calculate grades" "button"
And I change phase in workshop "Music history" to "Closed"
And I log out
# Confirm completion condition is updated.
When I am on the "Music history" "workshop activity" page logged in as student1
Then the "View" completion condition of "Music history" is displayed as "done"
@@ -73,14 +66,13 @@ Feature: View activity completion information in the Workshop activity
@javascript
Scenario: Use manual completion
Given I am on the "Music history" "workshop activity" page logged in as teacher1
Given I am on the "Music history" "workshop activity" page
And I am on the "Music history" "workshop activity editing" page
And I expand all fieldsets
And I set the field "Completion tracking" to "Students can manually mark the activity as completed"
And I press "Save and display"
# Teacher view
And the manual completion button for "Music history" should be disabled
And I log out
# Student view.
When I am on the "Music history" "workshop activity" page logged in as student1
Then the manual completion button of "Music history" is displayed as "Mark as done"
@@ -23,17 +23,15 @@ Feature: Workshop submission and assessment
| student4 | c1 | student |
| teacher1 | c1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | TestWorkshop | Test workshop description | c1 | workshop1 | 2 | 1 |
| activity | name | course | idnumber | submissiontypetext | submissiontypefile |
| workshop | TestWorkshop | c1 | workshop1 | 2 | 1 |
# teacher1 sets up assessment form and changes the phase to submission
When I log in as "teacher1"
And I am on "Course1" course homepage
When I am on the "Course1" course page logged in as teacher1
And I edit assessment form in workshop "TestWorkshop" as:"
| id_description__idx_0_editor | Aspect1 |
| id_description__idx_1_editor | Aspect2 |
| id_description__idx_2_editor | |
And I change phase in workshop "TestWorkshop" to "Submission phase"
And I log out
# student1 submits
And I am on the TestWorkshop "workshop activity" page logged in as student1
Then I should see "Submit your work"
@@ -41,21 +39,16 @@ Feature: Workshop submission and assessment
| Title | Submission1 |
| Submission content | Some content |
And "//div[@class='submission-full' and contains(.,'Submission1') and contains(.,'submitted on')]" "xpath_element" should exist
And I log out
# student2 submits
And I log in as "student2"
And I am on "Course1" course homepage
And I am on the "Course1" course page logged in as student2
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission2 |
| Submission content | Some content |
And I log out
# student3 submits
And I log in as "student3"
And I am on "Course1" course homepage
And I am on the "Course1" course page logged in as student3
And I add a submission in workshop "TestWorkshop" as:"
| Title | Submission3 |
| Submission content | Some content |
And I log out
# teacher1 allocates reviewers and changes the phase to assessment
And I am on the TestWorkshop "workshop activity" page logged in as teacher1
And I should see "to allocate: 3"
@@ -75,7 +68,6 @@ Feature: Workshop submission and assessment
And I am on the TestWorkshop "workshop activity" page
And I should see "to allocate: 0"
And I change phase in workshop "TestWorkshop" to "Assessment phase"
And I log out
# student1 assesses work of student2 and student3
And I am on the TestWorkshop "workshop activity" page logged in as student1
And "//ul[@class='tasks']/li[div[@class='title' and contains(.,'Assess peers')]]/div[@class='details' and contains(.,'pending: 2') and contains(.,'total: 2')]" "xpath_element" should exist
@@ -94,7 +86,6 @@ Feature: Workshop submission and assessment
| peercomment__idx_1 | Very good |
| Feedback for the author | No comments |
And "//ul[@class='tasks']/li[div[@class='title' and contains(.,'Assess peers')]]/div[@class='details' and contains(.,'pending: 0') and contains(.,'total: 2')]" "xpath_element" should exist
And I log out
# student2 assesses work of student1
And I am on the TestWorkshop "workshop activity" page logged in as student2
And "//ul[@class='tasks']/li[div[@class='title' and contains(.,'Assess peers')]]/div[@class='details' and contains(.,'pending: 1') and contains(.,'total: 1')]" "xpath_element" should exist
@@ -105,7 +96,6 @@ Feature: Workshop submission and assessment
| peercomment__idx_1 | |
| Feedback for the author | Keep it up |
And "//ul[@class='tasks']/li[div[@class='title' and contains(.,'Assess peers')]]/div[@class='details' and contains(.,'pending: 0') and contains(.,'total: 1')]" "xpath_element" should exist
And I log out
# teacher1 makes sure he can see all peer grades
And I am on the TestWorkshop "workshop activity" page logged in as teacher1
And I should see grade "52" for workshop participant "Sam1" set by peer "Sam2"
@@ -139,7 +129,6 @@ Feature: Workshop submission and assessment
And I should see "32" in the "//table/tbody/tr[td[contains(concat(' ', normalize-space(@class), ' '), ' participant ') and contains(.,'Sam1')]]/td[contains(concat(' ', normalize-space(@class), ' '), ' submissiongrade ')]" "xpath_element"
And I should see "16" in the "//table/tbody/tr[td[contains(concat(' ', normalize-space(@class), ' '), ' participant ') and contains(.,'Sam1')]]/td[contains(concat(' ', normalize-space(@class), ' '), ' gradinggrade ')]" "xpath_element"
And I change phase in workshop "TestWorkshop" to "Closed"
And I log out
# student1 looks at the activity
And I am on the TestWorkshop "workshop activity" page logged in as student1
@@ -19,8 +19,8 @@ Feature: Workshop 'Late submissions are allowed' task
| student2 | c1 | student |
| teacher1 | c1 | editingteacher |
And the following "activities" exist:
| activity | name | intro | course | idnumber | latesubmissions | submisstionstart | submissionend |
| workshop | TestWorkshop1 | TW3 with Submission deadline in future (1 Jan 2030)| c1 | workshop1 | 1 | 1514904308 | 1893369600 |
| activity | name | course | idnumber | latesubmissions | submisstionstart | submissionend |
| workshop | TestWorkshop1 | c1 | workshop1 | 1 | 1514904308 | 1893369600 |
# Teacher sets up assessment form and changes the phase to submission.
And I am on the "TestWorkshop1" "workshop activity" page logged in as teacher1
And I edit assessment form in workshop "TestWorkshop1" as:"
@@ -28,7 +28,6 @@ Feature: Workshop 'Late submissions are allowed' task
| id_description__idx_1_editor | Aspect2 |
| id_description__idx_2_editor | Aspect3 |
And I change phase in workshop "TestWorkshop1" to "Submission phase"
And I log out
@javascript
Scenario: Student1 add his submission to TestWorkshop1 before submission deadline, but student2 does not submitt
@@ -39,7 +38,6 @@ Feature: Workshop 'Late submissions are allowed' task
And I add a submission in workshop "TestWorkshop1" as:"
| Title | Submission from s1 |
| Submission content | Some content from student1 |
And I log out
# Teacher modifies submission deadline.
When I am on the "TestWorkshop1" "workshop activity" page logged in as teacher1
@@ -51,20 +49,17 @@ Feature: Workshop 'Late submissions are allowed' task
And I set the field "id_submissionend_year" to "2018"
And I click on "Save and display" "button"
And I follow "Switch to the assessment phase"
And I log out
# Student1 has already submitted and cannot see 'Late submissions are allowed'.
When I am on the "TestWorkshop1" "workshop activity" page logged in as student1
Then I should see "Submissions deadline:"
And I should not see "Late submissions are allowed"
And I log out
# Student2 has not submitted yet who can see 'Late submissions are allowed' text after the submission deadline.
When I am on the "TestWorkshop1" "workshop activity" page logged in as student2
Then I should see "Submissions deadline:"
And I should see "Monday, 1 January 2018"
And I should see "Late submissions are allowed"
And I log out
# Teacher can see 'Late submissions are allowed' text after submission deadline.
When I am on the "TestWorkshop1" "workshop activity" page logged in as teacher1
@@ -17,15 +17,14 @@ Feature: Workshop should remember collapsed/expanded sections in view page.
| teacher1 | c1 | editingteacher |
| student1 | c1 | student |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| workshop | Workshop 1 | Workshop 1 description | c1 | workshop1 |
| activity | name | course | idnumber |
| workshop | Workshop 1 | c1 | workshop1 |
@javascript
Scenario: Check section in view page can be remembered.
Given I am on the "Workshop 1" "workshop activity" page logged in as teacher1
When I change phase in workshop "Workshop 1" to "Submission phase"
And I wait until the page is ready
And I log out
And I am on the "Workshop 1" "workshop activity" page logged in as student1
Then I should see "You have not submitted your work yet"
View File
@@ -34,7 +34,7 @@ Feature: A teacher can put questions in categories in the question bank
And I press "submitbutton"
Then I should see "New Category 1 ID number newcatidnumber (0)"
And I should see "Created as a test" in the "New Category 1" "list_item"
And "New Category 1 [newcatidnumber]" "option" should exist in the "Parent category" "select"
And the "Parent category" select box should contain "New Category 1 [newcatidnumber]"
Scenario: A question category can be edited
When I am on the "Course 1" "core_question > course question categories" page logged in as "teacher1"
+1 -1
View File
@@ -61,7 +61,7 @@ if ($formaction == 'bulkchange.php') {
$userids = optional_param_array('userid', array(), PARAM_INT);
$default = new moodle_url('/user/index.php', ['id' => $course->id]);
$returnurl = new moodle_url(optional_param('returnto', $default, PARAM_URL));
$returnurl = new moodle_url(optional_param('returnto', $default, PARAM_LOCALURL));
if (empty($userids)) {
$userids = optional_param_array('bulkuser', array(), PARAM_INT);
@@ -241,3 +241,27 @@ Feature: Custom profile fields should be visible and editable by those with the
And I should not see "notvisible_field_information"
And I should not see "Edit profile"
@javascript
Scenario: Menu profile field's default data works as expected when editing user profile
Given the following "custom profile fields" exist:
| datatype | shortname | name | visible | param1 | defaultdata |
| menu | menufield | Menu field | 2 | OptA\nOptB\nOptC | OptB |
And I log in as "userwithinformation"
When I follow "Profile" in the user menu
And I click on "Edit profile" "link" in the "region-main" "region"
Then the following fields match these values:
| Menu field | OptB |
@javascript
Scenario: Menu profile field successfully updated when editing user profile
Given the following "custom profile fields" exist:
| datatype | shortname | name | visible | param1 |
| menu | menufield | Menu field | 2 | OptA\nOptB\nOptC |
And I log in as "userwithinformation"
When I follow "Profile" in the user menu
And I click on "Edit profile" "link" in the "region-main" "region"
And I set the following fields to these values:
| Menu field | OptC |
And I click on "Update profile" "button"
Then I should see "OptC"
+32
View File
@@ -1629,4 +1629,36 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertEquals('email', $user['extrafields'][0]['name']);
}
}
/**
* Test verifying that update_user_preferences prevents changes to the default homepage for other users.
*/
public function test_update_user_preferences_homepage_permission_callback() {
global $DB;
$this->resetAfterTest();
$user = self::getDataGenerator()->create_user();
$this->setUser($user);
$adminuser = get_admin();
// Allow user selection of the default homepage via preferences.
set_config('defaulthomepage', HOMEPAGE_USER);
// Try to save another user's home page preference which uses the permissioncallback.
$preferences = [
[
'name' => 'user_home_page_preference',
'value' => '3',
'userid' => $adminuser->id,
]
];
$result = core_user_external::set_user_preferences($preferences);
$result = \external_api::clean_returnvalue(core_user_external::set_user_preferences_returns(), $result);
$this->assertCount(1, $result['warnings']);
$this->assertCount(0, $result['saved']);
// Verify no change to the preference, checking from DB to avoid cache.
$this->assertEquals(null, $DB->get_field('user_preferences', 'value',
['userid' => $adminuser->id, 'name' => 'user_home_page_preference']));
}
}
+2 -2
View File
@@ -29,9 +29,9 @@
defined('MOODLE_INTERNAL') || die();
$version = 2021051711.00; // 20210517 = branching date YYYYMMDD - do not modify!
$version = 2021051712.00; // 20210517 = branching date YYYYMMDD - do not modify!
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '3.11.11 (Build: 20221114)';// Human-friendly version name
$release = '3.11.12 (Build: 20230116)';// Human-friendly version name
$branch = '311'; // This version's branch.
$maturity = MATURITY_STABLE; // This version's maturity level.