@webship.co/workspace-joomla 0.0.0-stage → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,30 @@
1
+ Feature: The Joomla plugin on the dashboard
2
+ Once the plugin is activated and installed, the sites folders offer the Joomla builder, each
3
+ AI folder lists the items of its kind the plugin ships, and the Plugins page lists the plugin
4
+ with its steps.
5
+
6
+ Scenario: The plugin is listed on the Plugins page
7
+ Given I am on "/settings/plugins"
8
+ Then I should see "Joomla"
9
+ And I should see "@webship.co/workspace-joomla"
10
+
11
+ Scenario: A sites folder offers the Joomla builder
12
+ Given I am on "/dev"
13
+ Then "option[value='cmd-joomla-project.sh']" should be attached
14
+
15
+ Scenario: The AI Agents folder lists the agents the plugin ships
16
+ Given I am on "/ai-agents"
17
+ Then I should see "joomla-site-builder"
18
+ And I should see "joomla-tester"
19
+
20
+ Scenario: The AI Skills folder lists the skill the plugin ships
21
+ Given I am on "/ai-skills"
22
+ Then I should see "joomla-scenarios"
23
+
24
+ Scenario: The AI Commands folder lists the command the plugin ships
25
+ Given I am on "/ai-commands"
26
+ Then I should see "joomla-test"
27
+
28
+ Scenario: The AI Prompts folder lists the prompt the plugin ships
29
+ Given I am on "/ai-prompts"
30
+ Then I should see "joomla-build-and-test"
package/package.json CHANGED
@@ -1,6 +1,97 @@
1
1
  {
2
2
  "name": "@webship.co/workspace-joomla",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.8",
4
+ "description": "Joomla for Webship Workspace: the builder (`cmd-joomla-project.sh`) and the Joomla CLI tool in every sites folder, the default accounts, the Joomla step pack wired into the testing setup, and its AI items in their folders: two agents, a skill, a command and a prompt.",
5
+ "main": "dist/src/index.js",
6
+ "types": "dist/src/index.d.ts",
7
+ "license": "ISC",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/webship/workspace-joomla.git"
11
+ },
12
+ "files": [
13
+ "dist/src",
14
+ "ai",
15
+ "commands",
16
+ "docs",
17
+ "features",
18
+ "scripts",
19
+ "testing",
20
+ "README.md"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc -p tsconfig.json",
24
+ "prepare": "npm run build",
25
+ "test": "npm run build && node --test dist/tests/*.test.js",
26
+ "lint": "tsc -p tsconfig.json --noEmit"
27
+ },
28
+ "workspacePlugin": {
29
+ "name": "joomla",
30
+ "label": "Joomla",
31
+ "needs": [
32
+ [
33
+ "dev",
34
+ "test",
35
+ "sandboxes",
36
+ "demos"
37
+ ],
38
+ "ai-agents",
39
+ "ai-skills",
40
+ "ai-commands",
41
+ "ai-prompts"
42
+ ],
43
+ "commands": {
44
+ "types": [
45
+ "sites"
46
+ ],
47
+ "workspaces": [
48
+ "dev",
49
+ "test",
50
+ "sandboxes",
51
+ "demos"
52
+ ],
53
+ "files": [
54
+ "commands/cmd-joomla-project.sh",
55
+ "commands/cmd-tools-joomla-cli.sh"
56
+ ]
57
+ },
58
+ "scripts": {
59
+ "functions": [
60
+ "scripts/functions/fun-joomla.sh"
61
+ ],
62
+ "args": [
63
+ "scripts/args/arg-joomla.sh",
64
+ "scripts/args/arg-joomla-cli.sh"
65
+ ],
66
+ "machine": [
67
+ "testing/site.feature"
68
+ ]
69
+ },
70
+ "ai": {
71
+ "agents": [
72
+ "ai/agents/joomla-site-builder.md",
73
+ "ai/agents/joomla-tester.md"
74
+ ],
75
+ "skills": [
76
+ "ai/skills/joomla-scenarios"
77
+ ],
78
+ "commands": [
79
+ "ai/commands/joomla-test.md"
80
+ ],
81
+ "prompts": [
82
+ "ai/prompts/joomla-build-and-test.md"
83
+ ]
84
+ },
85
+ "features": [
86
+ "features/joomla.feature"
87
+ ]
88
+ },
89
+ "devDependencies": {
90
+ "@types/node": "^24.0.0",
91
+ "@webship.co/workspace-plugin-api": "^1.0.7",
92
+ "typescript": "^5.9.0"
93
+ },
94
+ "publishConfig": {
95
+ "access": "public"
96
+ }
97
+ }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env bash
2
+
3
+ argparse "$@" <<ARGEOF || exit 1
4
+ parser.add_argument('PROJECT_NAME',
5
+ help='The Joomla project in this workspace.')
6
+ parser.add_argument('-r', '--run',
7
+ default="_none_",
8
+ help='A Joomla CLI command to run in the project, without the leading php cli/joomla.php. Example: --run "extension:list --type=plugin"')
9
+ parser.add_argument('-u', '--update',
10
+ action='store_true',
11
+ default=False,
12
+ help='Update Joomla itself to the latest release of its line, and clean the cache.')
13
+ parser.add_argument('-k', '--check',
14
+ action='store_true',
15
+ default=False,
16
+ help='Look for updates of Joomla and of its extensions, and change nothing.')
17
+ parser.add_argument('-a', '--add-users',
18
+ action='store_true',
19
+ default=False,
20
+ help='Add the default accounts, one per user group. An account that is already there is left as it is.')
21
+ parser.add_argument('-c', '--cancel-users',
22
+ action='store_true',
23
+ default=False,
24
+ help='Delete the default accounts.')
25
+ ARGEOF
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ argparse "$@" <<ARGEOF || exit 1
4
+ parser.add_argument('PROJECT_NAME',
5
+ help='The name of the project: its folder, its DDEV project and its host name.')
6
+ parser.add_argument('-v', '--version',
7
+ default="${site_version}",
8
+ help='The Joomla release to download: latest, or a version number. Example: --version 6.2.0 [default %(default)s]')
9
+ parser.add_argument('-i', '--install',
10
+ action='store_true',
11
+ default=False,
12
+ help='Install Joomla, with the workspace account as the Super User.')
13
+ parser.add_argument('-a', '--add-users',
14
+ action='store_true',
15
+ default=False,
16
+ help='With --install, add the default accounts: one per user group, the ones the test scenarios log in as.')
17
+ parser.add_argument('-s', '--sample-data',
18
+ action='store_true',
19
+ default=False,
20
+ help='With --install, add the blog sample data of Joomla: articles, a menu and modules.')
21
+ parser.add_argument('-l', '--launch',
22
+ action='store_true',
23
+ default=False,
24
+ help='Open the site in a browser when it is ready.')
25
+ parser.add_argument('--php-version',
26
+ default="8.3",
27
+ choices=['8.5', '8.4', '8.3'],
28
+ help='PHP version for the project container. Example: --php-version 8.4 [default %(default)s]')
29
+ ARGEOF
@@ -0,0 +1,387 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Joomla for the Webship Workspace: build a site, run the Joomla CLI on it, add its default
4
+ # accounts, and wire its step pack into the testing setup.
5
+ #
6
+ # Placed by `plugins.sh --install joomla` in core/scripts/plugins/joomla/functions/, where
7
+ # bootstrap sources it after the core's own functions. Everything runs in the project's container
8
+ # (DDEV by default: `ddev exec php <docroot>/cli/joomla.php …`), never on the host.
9
+ #
10
+ # The container tool has no project type for Joomla, so a Joomla project is a `php` project that
11
+ # carries the Joomla CLI in its docroot; that file is how the functions here recognise one. The
12
+ # installer is given the container's own database values (db / db / db) and nothing personal.
13
+ #
14
+ # Four names are the ones the core's tools look for:
15
+ # set_joomla_users the default accounts (cmd-tools-add-users.sh <project> joomla)
16
+ # add_joomla_users create them with the Joomla CLI (the same tool, and --add-users of the builder)
17
+ # cancel_joomla_users delete them (cmd-tools-cancel-users.sh <project> joomla)
18
+ # testing_configure_joomla the step pack in the testing stack (cmd-tools-testing.sh <project>)
19
+
20
+ # The step pack a Joomla project is tested with, and the release line it is required at.
21
+ readonly JOOMLA_STEPS_PACKAGE='@webship-js/joomla-steps';
22
+ readonly JOOMLA_STEPS_VERSION='^2.1.0';
23
+
24
+ # The release a build falls back on when the latest one cannot be read: the one this plugin was proven on.
25
+ readonly JOOMLA_PROVEN_VERSION='6.2.0';
26
+
27
+ # Joomla refuses a password shorter than this.
28
+ readonly JOOMLA_PASSWORD_LENGTH=12;
29
+
30
+ # The default accounts: one per user group a scenario logs in as. Accounts are configuration,
31
+ # created once on the site; a test suite never creates or deletes one. The role is the Joomla
32
+ # user group, by its title.
33
+ function set_joomla_users() {
34
+ users=(administrator manager editor member);
35
+ local groups=('Super Users' 'Manager' 'Editor' 'Registered') i user ;
36
+ for i in "${!users[@]}" ; do
37
+ user="${users[$i]}" ;
38
+ printf -v "user_${user}_name" '%s' "${user}" ;
39
+ printf -v "user_${user}_mail" '%s' "${user}@example.com" ;
40
+ printf -v "user_${user}_password" '%s' 'dD.123123ddd' ;
41
+ printf -v "user_${user}_role" '%s' "${groups[$i]}" ;
42
+ done
43
+ }
44
+
45
+ # The docroot of a project, from its own container configuration.
46
+ function joomla_docroot() {
47
+ local project_path="$1" docroot ;
48
+ docroot="$(grep -E '^docroot:' "${project_path}/.ddev/config.yaml" 2>/dev/null | head -1 | sed -E 's/^docroot:[[:space:]]*//; s/^"(.*)"$/\1/; s/[[:space:]]*$//')" ;
49
+ printf '%s' "${docroot}" ;
50
+ }
51
+
52
+ # Where the Joomla CLI is, from the project root: <docroot>/cli/joomla.php.
53
+ function joomla_cli_path() {
54
+ local docroot ; docroot="$(joomla_docroot "$1")" ;
55
+ printf '%s' "${docroot:+${docroot}/}cli/joomla.php" ;
56
+ }
57
+
58
+ # Is this folder a Joomla project? The Joomla CLI and the administrator in its docroot say so.
59
+ function joomla_is_project() {
60
+ local project_path="$1" docroot ;
61
+ [ -f "${project_path}/.ddev/config.yaml" ] || return 1 ;
62
+ docroot="$(joomla_docroot "${project_path}")" ;
63
+ [ -f "${project_path}/${docroot:+${docroot}/}cli/joomla.php" ] && [ -d "${project_path}/${docroot:+${docroot}/}administrator" ] ;
64
+ }
65
+
66
+ # Is the site installed? The installer writes configuration.php, and nothing else does.
67
+ function joomla_is_installed() {
68
+ local project_path="$1" docroot ;
69
+ docroot="$(joomla_docroot "${project_path}")" ;
70
+ [ -f "${project_path}/${docroot:+${docroot}/}configuration.php" ] ;
71
+ }
72
+
73
+ # Go to the project a tool was asked about, or say why not.
74
+ function joomla_enter_project() {
75
+ local project_path="${WORKSPACE_ROOT}/${doc_name}/${PROJECT_NAME}";
76
+ if [ ! -d "${project_path}" ] ; then
77
+ echo "No project ${PROJECT_NAME} in ${WORKSPACE_ROOT}/${doc_name}." ;
78
+ return 1 ;
79
+ fi
80
+ if ! joomla_is_project "${project_path}" ; then
81
+ echo "${doc_name}/${PROJECT_NAME} is not a Joomla project (its docroot has no cli/joomla.php)." ;
82
+ return 1 ;
83
+ fi
84
+ cd "${project_path}" || return 1 ;
85
+ }
86
+
87
+ # Run the Joomla CLI in the container of the project the shell is in. Every argument is quoted
88
+ # for the container's shell, so a name with a space ("Super Users") arrives as one argument.
89
+ function joomla_cli() {
90
+ local line arg ;
91
+ line="php $(joomla_cli_path "$(pwd)")" ;
92
+ for arg in "$@" ; do
93
+ line="${line} $(printf '%q' "${arg}")" ;
94
+ done
95
+ ddev exec "${line}" ;
96
+ }
97
+
98
+ # Is there an account of this username on the site?
99
+ function joomla_user_exists() {
100
+ # A row of the list: the number of the account, then its username.
101
+ joomla_cli user:list --no-interaction 2>/dev/null | grep -qE "^[[:space:]]*[0-9]+[[:space:]]+$1[[:space:]]" ;
102
+ }
103
+
104
+ # The number of the latest stable release, read in the container from where the releases are
105
+ # published; the proven release when it cannot be read.
106
+ function joomla_latest_version() {
107
+ local version ;
108
+ version="$(ddev exec "curl -fsSI https://github.com/joomla/joomla-cms/releases/latest" 2>/dev/null \
109
+ | tr -d '\r' | sed -nE 's#^[Ll]ocation:.*/tag/([0-9][0-9A-Za-z.-]*)$#\1#p' | head -1)" ;
110
+ printf '%s' "${version:-${JOOMLA_PROVEN_VERSION}}" ;
111
+ }
112
+
113
+ # Build a Joomla site from nothing: the container, the code, and with --install the site itself.
114
+ function joomla_build() {
115
+ trim_project_name ;
116
+ local base_url="https://${PROJECT_NAME}.ddev.site" ;
117
+ local version="${VERSION:-${site_version:-latest}}" ;
118
+ local php_version="${PHP_VERSION:-${site_php_version:-8.3}}" ;
119
+ local docroot="${distribution_webroot}" ;
120
+ local web="${docroot:+${docroot}/}" ;
121
+
122
+ if [ "${INSTALL}" == 'yes' ] && [ "${#account_pass}" -lt "${JOOMLA_PASSWORD_LENGTH}" ] ; then
123
+ echo "Joomla asks for a password of ${JOOMLA_PASSWORD_LENGTH} characters or more, and the workspace account's is shorter." ;
124
+ echo "Change account: pass in core/config/settings.yml, or build without --install." ;
125
+ exit 1 ;
126
+ fi
127
+
128
+ cd ${WORKSPACE_ROOT}/${doc_name} || exit 1 ;
129
+
130
+ drop_database ;
131
+ rm -rf "${PROJECT_NAME}" ;
132
+ mkdir -p "${PROJECT_NAME}/${docroot}" ;
133
+ cd ${WORKSPACE_ROOT}/${doc_name}/${PROJECT_NAME} || exit 1 ;
134
+
135
+ ddev config --project-type=php --docroot="${docroot}" --project-name=${PROJECT_NAME} \
136
+ --php-version=${php_version} --webserver-type=nginx-fpm --nodejs-version=$(ddev_nodejs_version) || exit 1 ;
137
+ ddev_up start -y || exit 1 ;
138
+
139
+ [ "${version}" == 'latest' ] && version="$(joomla_latest_version)" ;
140
+ local package="https://github.com/joomla/joomla-cms/releases/download/${version}/Joomla_${version}-Stable-Full_Package.zip" ;
141
+ echo "Downloading Joomla ${version}." ;
142
+ ddev exec "curl -fsSL -o /tmp/joomla.zip '${package}' && unzip -q -o /tmp/joomla.zip -d '/var/www/html/${docroot}' && rm -f /tmp/joomla.zip" \
143
+ || { echo "The Joomla ${version} package could not be downloaded or unpacked." ; exit 1 ; } ;
144
+
145
+ if [ "${INSTALL}" == 'yes' ] ; then
146
+ # The container's own database values, the same in every project: nothing personal is written.
147
+ ddev exec "php ${web}installation/joomla.php install --no-interaction \
148
+ --site-name=$(printf '%q' "${doc_name} ${PROJECT_NAME}") \
149
+ --admin-user=$(printf '%q' "${account_name}") --admin-username=$(printf '%q' "${account_name}") \
150
+ --admin-password=$(printf '%q' "${account_pass}") --admin-email=$(printf '%q' "${account_mail}") \
151
+ --db-type=mysqli --db-host=db --db-user=db --db-pass=db --db-name=db --db-prefix=jos_" \
152
+ || { echo "The Joomla installer failed." ; exit 1 ; } ;
153
+
154
+ # The administrator asks every new site to share anonymous statistics, with a notice on each
155
+ # page. A local site answers "never" once.
156
+ ddev mysql -e "UPDATE jos_extensions SET params='{\"mode\":3}' WHERE element='stats' AND folder='system'" ;
157
+
158
+ if [ "${SAMPLE_DATA}" == 'yes' ] ; then
159
+ joomla_sample_data ;
160
+ fi
161
+
162
+ if [ "${ADD_USERS}" == 'yes' ] ; then
163
+ set_joomla_users ;
164
+ add_joomla_users ;
165
+ cd ${WORKSPACE_ROOT}/${doc_name}/${PROJECT_NAME} || exit 1 ;
166
+ fi
167
+
168
+ echo "${doc_name} ${PROJECT_NAME} has been installed: Joomla ${version}.";
169
+ echo "Go to ${base_url}/administrator and log in as ${account_name}";
170
+ else
171
+ [ "${ADD_USERS}" == 'yes' ] && echo "--add-users needs --install: there is no site to add accounts to yet." ;
172
+ [ "${SAMPLE_DATA}" == 'yes' ] && echo "--sample-data needs --install: there is no site to add content to yet." ;
173
+ echo "${doc_name} ${PROJECT_NAME} is ready to install.";
174
+ echo "Go to ${base_url}";
175
+ fi
176
+
177
+ if [ "${LAUNCH}" == 'yes' ] ; then
178
+ ddev launch ;
179
+ fi
180
+
181
+ cd ${WORKSPACE_ROOT}/${doc_name};
182
+ }
183
+
184
+ # The "blog" sample data of Joomla: articles, a menu and the modules that show them. Joomla
185
+ # offers it through the administrator only, so the container logs in as the workspace account,
186
+ # the way a browser would, and asks for each of its four steps in order; then the Smart Search
187
+ # index is built, which the sample data leaves empty. The password travels in the container's
188
+ # environment for that one command and is written nowhere.
189
+ function joomla_sample_data() {
190
+ echo "Adding the blog sample data." ;
191
+ ddev exec "JOOMLA_USER=$(printf '%q' "${account_name}") JOOMLA_PASSWORD=$(printf '%q' "${account_pass}") bash -s" <<'SAMPLEEOF' || { echo " The sample data could not be added; the site itself is installed." ; return 1 ; } ;
192
+ set -e
193
+ site="${DDEV_PRIMARY_URL%/}"
194
+ jar="$(mktemp)"
195
+ trap 'rm -f "${jar}"' EXIT
196
+ admin="${site}/administrator/index.php"
197
+ login_token="$(curl -ksL -c "${jar}" "${admin}" | grep -oP '(?<=name=")[a-f0-9]{32}(?=" value="1")' | head -1)"
198
+ curl -ksL -o /dev/null -b "${jar}" -c "${jar}" "${admin}" \
199
+ --data-urlencode "username=${JOOMLA_USER}" --data-urlencode "passwd=${JOOMLA_PASSWORD}" \
200
+ --data-urlencode "option=com_login" --data-urlencode "task=login" \
201
+ --data-urlencode "return=aW5kZXgucGhw" --data-urlencode "${login_token}=1"
202
+ # A token of the session that is now open: the one of the login form is stale by now.
203
+ token="$(curl -ksL -b "${jar}" -c "${jar}" "${admin}" | grep -oP '(?<=csrf.token":")[a-f0-9]{32}' | head -1)"
204
+ [ -n "${token}" ] || { echo " The administrator did not open a session." ; exit 1 ; }
205
+ # In order: the second step makes the menu the third one attaches the modules to.
206
+ for step in 1 2 3 4 ; do
207
+ curl -ksL -b "${jar}" -c "${jar}" -o /dev/null \
208
+ "${admin}?option=com_ajax&group=sampledata&type=blog&plugin=SampledataApplyStep${step}&format=json&${token}=1"
209
+ done
210
+ SAMPLEEOF
211
+ joomla_cli finder:index --no-interaction ;
212
+ }
213
+
214
+ # Create the default accounts with the Joomla CLI. An account that is already there is left as it is.
215
+ # The list is loaded by the caller (set_joomla_users): the core's add_users, the builder, the CLI tool.
216
+ function add_joomla_users() {
217
+ joomla_enter_project || return 1 ;
218
+ local user user_name user_mail user_password user_role ;
219
+ for user in "${users[@]}" ; do
220
+ user_name="user_${user}_name"; user_mail="user_${user}_mail";
221
+ user_password="user_${user}_password"; user_role="user_${user}_role";
222
+
223
+ echo " ---------------------------------------------------------------- ";
224
+ echo " User name: ${!user_name}";
225
+ echo " User mail: ${!user_mail}";
226
+ echo " User password: ${!user_password}";
227
+ echo " User role: ${!user_role}";
228
+ echo " ================================================================= ";
229
+
230
+ if joomla_user_exists "${!user_name}" ; then
231
+ echo " ${!user_name} is already there." ;
232
+ else
233
+ joomla_cli user:add --no-interaction --username="${!user_name}" --name="${!user_name^}" \
234
+ --password="${!user_password}" --email="${!user_mail}" --usergroup="${!user_role}" ;
235
+ fi
236
+ done
237
+ cd ${WORKSPACE_ROOT}/${doc_name};
238
+ }
239
+
240
+ # Delete the default accounts.
241
+ function cancel_joomla_users() {
242
+ joomla_enter_project || return 1 ;
243
+ local user user_name ;
244
+ for user in "${users[@]}" ; do
245
+ user_name="user_${user}_name";
246
+ echo " ---------------------------------------------------------------- ";
247
+ echo " User name: ${!user_name}";
248
+ echo " ================================================================= ";
249
+ if joomla_user_exists "${!user_name}" ; then
250
+ joomla_cli user:delete --no-interaction --username="${!user_name}" ;
251
+ else
252
+ echo " ${!user_name} is not there." ;
253
+ fi
254
+ done
255
+ cd ${WORKSPACE_ROOT}/${doc_name};
256
+ }
257
+
258
+ # What cmd-tools-joomla-cli.sh does: the first of --run, --update, --check, --add-users,
259
+ # --cancel-users that was asked for; with none of them, what the site is.
260
+ function joomla_cli_tool() {
261
+ trim_project_name ;
262
+ joomla_enter_project || exit 1 ;
263
+
264
+ if ! ddev describe -j 2>/dev/null | grep -q '"status":"running"' ; then
265
+ ddev start -y || exit 1 ;
266
+ fi
267
+
268
+ if [ ! "${RUN}" == '_none_' ] ; then
269
+ # One string on purpose: --run "extension:list --type=plugin" is a command and its arguments.
270
+ ddev exec "php $(joomla_cli_path "$(pwd)") ${RUN}" ;
271
+ exit $? ;
272
+ fi
273
+
274
+ if [ "${UPDATE}" == 'yes' ] ; then
275
+ joomla_cli core:update --no-interaction && joomla_cli cache:clean --no-interaction ;
276
+ elif [ "${CHECK}" == 'yes' ] ; then
277
+ joomla_cli core:check-updates --no-interaction ;
278
+ joomla_cli update:extensions:check --no-interaction ;
279
+ elif [ "${ADD_USERS}" == 'yes' ] ; then
280
+ set_joomla_users ;
281
+ add_joomla_users ;
282
+ elif [ "${CANCEL_USERS}" == 'yes' ] ; then
283
+ set_joomla_users ;
284
+ cancel_joomla_users ;
285
+ else
286
+ echo "${doc_name}/${PROJECT_NAME}: $(joomla_cli --version 2>/dev/null | head -1) at https://${PROJECT_NAME}.ddev.site" ;
287
+ if joomla_is_installed "$(pwd)" ; then
288
+ echo "" ; echo "Accounts:" ; joomla_cli user:list --no-interaction ;
289
+ else
290
+ echo "The site is not installed yet: open its address, or build it again with --install." ;
291
+ fi
292
+ fi
293
+ cd ${WORKSPACE_ROOT}/${doc_name};
294
+ }
295
+
296
+ # The step pack in the testing stack of a Joomla project. The core's testing_configure calls
297
+ # this in the project folder once webship-js is scaffolded and before the dependencies are
298
+ # installed; for a project that is not Joomla it changes nothing.
299
+ #
300
+ # It adds the pack to package.json, lists its step definitions in cucumber.js after webship-js's
301
+ # own, gives cucumber.js the users registry of the default accounts (a handle a scenario reads,
302
+ # mapped to an account; never the workspace account), and writes a first feature when the project
303
+ # has none of its own. Every part is skipped when it is already there, so a second run adds what
304
+ # the first missed and never resets a suite.
305
+ function testing_configure_joomla() {
306
+ local project_path="$1";
307
+ joomla_is_project "${project_path}" || return 0 ;
308
+ if [ ! -f "${project_path}/cucumber.js" ] || [ ! -f "${project_path}/package.json" ] ; then
309
+ echo " Joomla: cucumber.js is not here yet — run the testing setup again once webship-js is scaffolded." ;
310
+ return 1 ;
311
+ fi
312
+
313
+ echo "Adding the Joomla step pack (${JOOMLA_STEPS_PACKAGE} ${JOOMLA_STEPS_VERSION}).";
314
+ set_joomla_users ;
315
+ local registry="" user user_name user_password handle ;
316
+ for user in "${users[@]}" ; do
317
+ user_name="user_${user}_name"; user_password="user_${user}_password";
318
+ # The pack's features call the Super User "admin".
319
+ handle="${user}" ; [ "${user}" == 'administrator' ] && handle="admin" ;
320
+ registry="${registry}${handle}|${!user_name}|${!user_password}"$'\n' ;
321
+ done
322
+
323
+ python3 - "${project_path}" "${JOOMLA_STEPS_PACKAGE}" "${JOOMLA_STEPS_VERSION}" 'JOOMLA' "${registry}" <<'PYEOF' || return 1
324
+ import json, re, sys
325
+
326
+ project, pack, version, prefix, registry = sys.argv[1:6]
327
+
328
+ # package.json: the pack as a dev dependency, at the release line this plugin was proven on.
329
+ pkg_file = project + '/package.json'
330
+ pkg = json.load(open(pkg_file))
331
+ if pack not in pkg.get('dependencies', {}) and pack not in pkg.get('devDependencies', {}):
332
+ pkg.setdefault('devDependencies', {})[pack] = version
333
+ open(pkg_file, 'w').write(json.dumps(pkg, indent=2) + '\n')
334
+ print(' package.json: %s %s' % (pack, version))
335
+
336
+ # cucumber.js: the pack's step definitions after webship-js's own, and the users registry.
337
+ cucumber_file = project + '/cucumber.js'
338
+ src = open(cucumber_file).read()
339
+ before = src
340
+
341
+ if ('node_modules/%s/' % pack) not in src:
342
+ line = "'node_modules/%s/tests/step-definitions/**/*.js'," % pack
343
+ core = re.search(r"^([ \t]*)'node_modules/webship-js/tests/step-definitions/[^']*',.*$", src, re.M)
344
+ opening = re.search(r"^([ \t]*)require:[ \t]*\[[ \t]*$", src, re.M)
345
+ if core:
346
+ src = src[:core.end()] + '\n' + core.group(1) + line + src[core.end():]
347
+ elif opening:
348
+ src = src[:opening.end()] + '\n' + opening.group(1) + ' ' + line + src[opening.end():]
349
+ else:
350
+ sys.exit(" cucumber.js has no require list this can add to. Add this line to it:\n " + line)
351
+ print(' cucumber.js: the step definitions of %s' % pack)
352
+
353
+ if not re.search(r"^[ \t]*users:[ \t]*\{", src, re.M):
354
+ world = re.search(r"^([ \t]*)worldParameters:[ \t]*\{[ \t]*$", src, re.M)
355
+ if not world:
356
+ sys.exit(" cucumber.js has no worldParameters block to add the users registry to.")
357
+ pad = world.group(1) + ' '
358
+ rows = [r.split('|') for r in registry.splitlines() if r.strip()]
359
+ block = [
360
+ pad + "// The users registry: a handle a scenario reads, mapped to an account of this site (the default",
361
+ pad + "// accounts: cmd-tools-add-users.sh). Override one with %s_<HANDLE>_USER and %s_<HANDLE>_PASSWORD." % (prefix, prefix),
362
+ pad + "users: {",
363
+ ]
364
+ for handle, name, password in rows:
365
+ env = '%s_%s' % (prefix, handle.upper())
366
+ block.append(pad + " %s: { username: process.env.%s_USER || '%s', password: process.env.%s_PASSWORD || '%s' }," % (handle, env, name, env, password))
367
+ block.append(pad + "},")
368
+ src = src[:world.end()] + '\n' + '\n'.join(block) + src[world.end():]
369
+ print(' cucumber.js: the users registry (%s)' % ', '.join(r[0] for r in rows))
370
+
371
+ if src != before:
372
+ open(cucumber_file, 'w').write(src)
373
+ PYEOF
374
+
375
+ # A first feature, when the project has none for the site yet: the front page, the login page,
376
+ # each default account in its group.
377
+ local feature="${WORKSPACE_SCRIPTS}/plugins/joomla/site.feature" ;
378
+ if [ -f "${feature}" ] && [ ! -f "${project_path}/tests/features/site.feature" ] ; then
379
+ mkdir -p "${project_path}/tests/features" && cp "${feature}" "${project_path}/tests/features/site.feature" \
380
+ && echo " tests/features/site.feature: a first feature for the site" ;
381
+ fi
382
+
383
+ # The scenarios log in as the default accounts: make sure an installed site has them.
384
+ if joomla_is_installed "${project_path}" ; then
385
+ ( add_joomla_users > /dev/null ) && echo " the default accounts are on the site (${users[*]})" ;
386
+ fi
387
+ }
@@ -0,0 +1,64 @@
1
+ Feature: The site answers and its accounts work
2
+ As the owner of the site
3
+ I want the front page, the login page and each default account to work
4
+ So that a build that came out broken is caught before anything else is tested
5
+
6
+ # Placed by the workspace's testing setup as a starting point: it is yours to change.
7
+ # The accounts are the default ones (cmd-tools-add-users.sh); a scenario logs in by a handle of
8
+ # the users registry in cucumber.js, so no password is written here.
9
+
10
+ @critical
11
+ Scenario: The front page is served
12
+ Given I am an anonymous user
13
+ And I am on the homepage
14
+ Then the response status code should be 200
15
+ And the page should have a title
16
+
17
+ @critical
18
+ Scenario: The login page is served with its form
19
+ Given I am on the login page
20
+ Then the response status code should be 200
21
+ And I should see the login form
22
+
23
+ Scenario Outline: Each default account is on the site, in the group of its role
24
+ Given I am a logged in user with the "admin" user
25
+ Then the user "<account>" should exist
26
+ And the user "<account>" should be enabled
27
+ And the user "<account>" should be in the "<group>" group
28
+
29
+ Examples:
30
+ | account | group |
31
+ | administrator | Super Users |
32
+ | manager | Manager |
33
+ | editor | Editor |
34
+ | member | Registered |
35
+
36
+ Scenario Outline: An account of the administrator logs in to it
37
+ Given I am a logged in user with the "<handle>" user
38
+ Then I should see the administrator dashboard
39
+ And I should see the administrator menu
40
+
41
+ Examples:
42
+ | handle |
43
+ | admin |
44
+ | manager |
45
+
46
+ Scenario Outline: An account of the site logs in to it
47
+ Given I am logged in to the site with the "<handle>" user
48
+ Then I should be logged in to the site as "<handle>"
49
+
50
+ Examples:
51
+ | handle |
52
+ | editor |
53
+ | member |
54
+
55
+ Scenario: An account is refused a page its group may not open
56
+ Given I am a logged in user with the "manager" user
57
+ When I go to the administrator "Users" page
58
+ Then the response status code should be 403
59
+
60
+ Scenario: An anonymous visitor has no session
61
+ Given I am not logged in
62
+ When I am on the profile page
63
+ Then I should see the login form
64
+ And I should not be logged in to the site