Apply new web plugin code layout to delete-project
And add basic karma testing capabilities.
Change-Id: Ib9742c79da68cc9426afd3d2947b9f6ce8be9631
diff --git a/BUILD b/BUILD
index 47d5db0..0dc7769 100644
--- a/BUILD
+++ b/BUILD
@@ -1,14 +1,11 @@
load("@rules_java//java:defs.bzl", "java_library")
load("//tools/bzl:junit.bzl", "junit_tests")
-load("//tools/js:eslint.bzl", "eslint")
load(
"//tools/bzl:plugin.bzl",
"PLUGIN_DEPS",
"PLUGIN_TEST_DEPS",
"gerrit_plugin",
)
-load("//tools/bzl:js.bzl", "gerrit_js_bundle")
-load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
gerrit_plugin(
name = "delete-project",
@@ -19,39 +16,11 @@
"Gerrit-HttpModule: com.googlesource.gerrit.plugins.deleteproject.HttpModule",
"Gerrit-SshModule: com.googlesource.gerrit.plugins.deleteproject.SshModule",
],
- resource_jars = [":gr-delete-repo"],
+ resource_jars = ["//plugins/delete-project/web:gr-delete-repo"],
resources = glob(["src/main/resources/Documentation/*.md"]),
deps = ["@commons-io//jar"],
)
-ts_config(
- name = "tsconfig",
- src = "tsconfig.json",
- deps = [
- "//plugins:tsconfig-plugins-base.json",
- ],
-)
-
-ts_project(
- name = "gr-delete-repo-ts",
- srcs = glob([
- "gr-delete-repo/**/*.ts",
- ]),
- incremental = True,
- tsc = "//tools/node_tools:tsc-bin",
- tsconfig = ":tsconfig",
- deps = [
- "@plugins_npm//@gerritcodereview/typescript-api",
- "@plugins_npm//lit",
- ],
-)
-
-gerrit_js_bundle(
- name = "gr-delete-repo",
- srcs = [":gr-delete-repo-ts"],
- entry_point = "gr-delete-repo/plugin.js",
-)
-
junit_tests(
name = "delete-project_tests",
srcs = glob(["src/test/java/**/*.java"]),
@@ -71,28 +40,3 @@
"@mockito//jar",
],
)
-
-# The eslint macro creates 2 rules: lint_test and lint_bin. Typical usage:
-# bazel test $DIR:lint_test
-# bazel run $DIR:lint_bin -- --fix $PATH_TO_SRCS
-eslint(
- name = "lint",
- srcs = glob(["gr-delete-repo/**/*"]),
- config = ".eslintrc.js",
- data = [
- "tsconfig.json",
- "//plugins:.eslintrc.js",
- "//plugins:.prettierrc.js",
- "//plugins:tsconfig-plugins-base.json",
- ],
- extensions = [".ts"],
- ignore = "//plugins:.eslintignore",
- plugins = [
- "@npm//eslint-config-google",
- "@npm//eslint-plugin-html",
- "@npm//eslint-plugin-import",
- "@npm//eslint-plugin-jsdoc",
- "@npm//eslint-plugin-prettier",
- "@npm//gts",
- ],
-)
diff --git a/README.md b/README.md
index 1444d1a..5a87b38 100644
--- a/README.md
+++ b/README.md
@@ -5,3 +5,24 @@
[![Build Status](https://gerrit-ci.gerritforge.com/view/Plugins-master/job/plugin-delete-project-bazel-master/badge/icon
)](https://gerrit-ci.gerritforge.com/view/Plugins-master/job/plugin-delete-project-bazel-master/)
+
+## JavaScript Plugin Development
+
+For running unit tests execute:
+
+ bazel test --test_output=all //plugins/delete-project/web:karma_test
+
+For checking or fixing eslint formatter problems run:
+
+ bazel test //plugins/delete-project/web:lint_test
+ bazel run //plugins/delete-project/web:lint_bin -- --fix "$(pwd)/plugins/delete-project/web"
+
+For testing the plugin with
+[Gerrit FE Dev Helper](https://gerrit.googlesource.com/gerrit-fe-dev-helper/)
+build the JavaScript bundle and copy it to the `plugins/` folder:
+
+ bazel build //plugins/delete-project/web:gr-delete-repo
+ cp -f bazel-bin/plugins/delete-project/web/gr-delete-repo.js plugins/
+
+and let the Dev Helper redirect from `.+/plugins/delete-project/static/gr-delete-repo.js` to
+`http://localhost:8081/plugins_/gr-delete-repo.js`.
diff --git a/package.json b/package.json
deleted file mode 100644
index 5a46795..0000000
--- a/package.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "delete-project",
- "description": "Delete project plugin",
- "browser": true,
- "scripts": {
- "safe_bazelisk": "if which bazelisk >/dev/null; then bazel_bin=bazelisk; else bazel_bin=bazel; fi && $bazel_bin",
- "eslint": "npm run safe_bazelisk test :lint_test",
- "eslintfix": "npm run safe_bazelisk run :lint_bin -- -- --fix $(pwd)"
- },
- "devDependencies": {},
- "license": "Apache-2.0",
- "private": true
-}
diff --git a/tsconfig.json b/tsconfig.json
deleted file mode 100644
index 9be4292..0000000
--- a/tsconfig.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "extends": "../tsconfig-plugins-base.json",
- "include": [
- "gr-delete-repo/**/*",
- ]
-}
diff --git a/.eslintrc.js b/web/.eslintrc.js
similarity index 89%
rename from .eslintrc.js
rename to web/.eslintrc.js
index 30df322..ee166d3 100644
--- a/.eslintrc.js
+++ b/web/.eslintrc.js
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-__plugindir = 'delete-project';
+__plugindir = 'delete-project/web';
module.exports = {
- extends: '../.eslintrc.js',
+ extends: '../../.eslintrc.js',
};
diff --git a/web/BUILD b/web/BUILD
new file mode 100644
index 0000000..5490c23
--- /dev/null
+++ b/web/BUILD
@@ -0,0 +1,61 @@
+load("//tools/js:eslint.bzl", "plugin_eslint")
+load("//tools/bzl:js.bzl", "gerrit_js_bundle", "karma_test")
+load("@npm//@bazel/typescript:index.bzl", "ts_config", "ts_project")
+
+package_group(
+ name = "visibility",
+ packages = ["//plugins/delete-project/..."],
+)
+
+package(default_visibility = [":visibility"])
+
+ts_config(
+ name = "tsconfig",
+ src = "tsconfig.json",
+ deps = [
+ "//plugins:tsconfig-plugins-base.json",
+ ],
+)
+
+ts_project(
+ name = "delete-project-ts",
+ srcs = glob(
+ ["**/*.ts"],
+ exclude = ["**/*test*"],
+ ),
+ incremental = True,
+ out_dir = "_bazel_ts_out",
+ tsc = "//tools/node_tools:tsc-bin",
+ tsconfig = ":tsconfig",
+ deps = [
+ "@plugins_npm//@gerritcodereview/typescript-api",
+ "@plugins_npm//lit",
+ ],
+)
+
+ts_project(
+ name = "delete-project-ts-tests",
+ srcs = glob(["**/*.ts"]),
+ incremental = True,
+ out_dir = "_bazel_ts_out_tests",
+ tsc = "//tools/node_tools:tsc-bin",
+ tsconfig = ":tsconfig",
+ deps = [
+ "@plugins_npm//:node_modules",
+ "@ui_dev_npm//:node_modules",
+ ],
+)
+
+gerrit_js_bundle(
+ name = "gr-delete-repo",
+ srcs = [":delete-project-ts"],
+ entry_point = "_bazel_ts_out/plugin.js",
+)
+
+karma_test(
+ name = "karma_test",
+ srcs = ["karma_test.sh"],
+ data = [":delete-project-ts-tests"],
+)
+
+plugin_eslint()
diff --git a/gr-delete-repo/gr-delete-repo.ts b/web/gr-delete-repo.ts
similarity index 98%
rename from gr-delete-repo/gr-delete-repo.ts
rename to web/gr-delete-repo.ts
index e16cefb..dec8efe 100644
--- a/gr-delete-repo/gr-delete-repo.ts
+++ b/web/gr-delete-repo.ts
@@ -36,7 +36,7 @@
}
@customElement('gr-delete-repo')
-class GrDeleteRepo extends LitElement {
+export class GrDeleteRepo extends LitElement {
@query('#deleteRepoOverlay')
deleteRepoOverlay?: GrOverlay;
diff --git a/web/gr-delete-repo_test.ts b/web/gr-delete-repo_test.ts
new file mode 100644
index 0000000..2da6b2b
--- /dev/null
+++ b/web/gr-delete-repo_test.ts
@@ -0,0 +1,76 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import './test/test-setup';
+import './gr-delete-repo';
+import {queryAndAssert} from './test/test-util';
+import {PluginApi} from '@gerritcodereview/typescript-api/plugin';
+import {GrDeleteRepo} from './gr-delete-repo';
+import {
+ ConfigInfo,
+ HttpMethod,
+ RepoName,
+} from '@gerritcodereview/typescript-api/rest-api';
+
+suite('gr-delete-repo tests', () => {
+ let element: GrDeleteRepo;
+ let sendStub: sinon.SinonStub;
+
+ setup(async () => {
+ sendStub = sinon.stub();
+ sendStub.returns(Promise.resolve({}));
+
+ element = document.createElement('gr-delete-repo');
+ element.repoName = 'test-repo-name' as RepoName;
+ element.config = {
+ actions: {
+ 'delete-project~delete': {
+ label: 'test-action-label',
+ title: 'test-aciton-title',
+ enabled: true,
+ method: HttpMethod.DELETE,
+ },
+ },
+ } as unknown as ConfigInfo;
+ element.plugin = {
+ getPluginName: () => 'delete-project',
+ restApi: () => {
+ return {
+ send: sendStub,
+ invalidateReposCache: () => {},
+ };
+ },
+ } as unknown as PluginApi;
+ document.body.appendChild(element);
+ await element.updateComplete;
+ });
+
+ teardown(() => {
+ document.body.removeChild(element);
+ });
+
+ test('confirm and send', () => {
+ const dialog = queryAndAssert<HTMLElement>(element, '#deleteRepoDialog');
+ dialog.dispatchEvent(new CustomEvent('confirm'));
+ assert.isTrue(sendStub.called);
+ const method = sendStub.firstCall.args[0] as HttpMethod;
+ const endpoint = sendStub.firstCall.args[1] as string;
+ const json = sendStub.firstCall.args[2];
+ assert.equal(method, HttpMethod.DELETE);
+ assert.equal(endpoint, '/projects/test-repo-name/delete-project~delete');
+ assert.deepEqual(json, {force: false, preserve: false});
+ });
+});
diff --git a/web/karma_test.sh b/web/karma_test.sh
new file mode 100755
index 0000000..35430ad
--- /dev/null
+++ b/web/karma_test.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -euo pipefail
+./$1 start $2 --single-run \
+ --root 'plugins/delete-project/web/_bazel_ts_out_tests/' \
+ --test-files '*_test.js'
diff --git a/gr-delete-repo/plugin.ts b/web/plugin.ts
similarity index 100%
rename from gr-delete-repo/plugin.ts
rename to web/plugin.ts
diff --git a/web/test/test-setup.ts b/web/test/test-setup.ts
new file mode 100644
index 0000000..ddeaf89
--- /dev/null
+++ b/web/test/test-setup.ts
@@ -0,0 +1,43 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import 'chai/chai';
+import '@gerritcodereview/typescript-api/gerrit';
+import {css} from 'lit';
+
+declare global {
+ interface Window {
+ assert: typeof chai.assert;
+ expect: typeof chai.expect;
+ sinon: typeof sinon;
+ }
+ let assert: typeof chai.assert;
+ let expect: typeof chai.expect;
+ let sinon: typeof sinon;
+}
+window.assert = chai.assert;
+window.expect = chai.expect;
+window.sinon = sinon;
+
+window.Gerrit = {
+ install: () => {},
+ styles: {
+ form: css``,
+ menuPage: css``,
+ subPage: css``,
+ table: css``,
+ },
+};
diff --git a/web/test/test-util.ts b/web/test/test-util.ts
new file mode 100644
index 0000000..25a1c79
--- /dev/null
+++ b/web/test/test-util.ts
@@ -0,0 +1,42 @@
+/**
+ * @license
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export function queryAll<E extends Element = Element>(
+ el: Element,
+ selector: string
+): NodeListOf<E> {
+ if (!el) throw new Error('element not defined');
+ const root = el.shadowRoot ?? el;
+ return root.querySelectorAll<E>(selector);
+}
+
+export function query<E extends Element = Element>(
+ el: Element | undefined,
+ selector: string
+): E | undefined {
+ if (!el) return undefined;
+ const root = el.shadowRoot ?? el;
+ return root.querySelector<E>(selector) ?? undefined;
+}
+
+export function queryAndAssert<E extends Element = Element>(
+ el: Element | undefined,
+ selector: string
+): E {
+ const found = query<E>(el, selector);
+ if (!found) throw new Error(`selector '${selector}' did not match anything'`);
+ return found;
+}
diff --git a/web/tsconfig.json b/web/tsconfig.json
new file mode 100644
index 0000000..d12f85e
--- /dev/null
+++ b/web/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig-plugins-base.json",
+ "compilerOptions": {
+ "outDir": "../../../.ts-out/plugins/delete-project", /* overridden by bazel */
+ },
+ "include": [
+ "**/*.ts"
+ ]
+}