/*
 * Copyright 2018-19 IBM Corporation
 *
 * 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.
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import * as assert from 'assert';
import { Common, CLI, ReplExpect, SidecarExpect, Selectors, Keys, Util } from '@kui-shell/test';
import { waitForGreen, createNS, allocateNS, deleteNS, defaultModeForGet } from '@kui-shell/plugin-kubectl/tests/lib/k8s/utils';
import { dirname } from 'path';
const ROOT = dirname(require.resolve('@kui-shell/plugin-kubectl/tests/package.json'));
const commands = ['kubectl'];
commands.forEach(command => {
    describe(`${command} edit ${process.env.MOCHA_RUN_TARGET || ''}`, function () {
        before(Common.before(this));
        after(Common.after(this));
        const ns = createNS();
        const inNamespace = `-n ${ns}`;
        const create = (name, source = 'pod.yaml') => {
            it(`should create sample pod ${name} from URL via ${command}`, () => __awaiter(this, void 0, void 0, function* () {
                try {
                    const selector = yield CLI.command(`${command} create -f ${ROOT}/data/k8s/headless/${source} ${inNamespace}`, this.app).then(ReplExpect.okWithCustom({ selector: Selectors.BY_NAME(name) }));
                    // wait for the badge to become green
                    yield waitForGreen(this.app, selector);
                }
                catch (err) {
                    yield Common.oops(this, true)(err);
                }
            }));
        };
        const edit = (name, kind = 'Pod', nameAsShown = name, mode = 'raw') => {
            it(`should edit it via ${command} edit with name=${name || 'no-name'}`, () => __awaiter(this, void 0, void 0, function* () {
                try {
                    yield CLI.command(`${command} edit pod ${name || ''} ${inNamespace}`, this.app)
                        .then(ReplExpect.justOK)
                        .then(SidecarExpect.open)
                        .then(SidecarExpect.showing(nameAsShown, undefined, undefined, ns))
                        .then(SidecarExpect.mode(mode))
                        .then(SidecarExpect.yaml({
                        kind
                    }));
                }
                catch (err) {
                    yield Common.oops(this, true)(err);
                }
            }));
        };
        const modifyWithError = (title, where, expectedError, revert) => {
            it(`should modify the content, introducing a ${title}`, () => __awaiter(this, void 0, void 0, function* () {
                try {
                    const actualText = yield Util.getValueFromMonaco(this.app);
                    const specLineIdx = actualText.split(/\n/).indexOf('spec:');
                    // +1 here because nth-child is indexed from 1
                    const lineSelector = `.view-lines > .view-line:nth-child(${specLineIdx + 1}) .mtk22`;
                    yield this.app.client.click(lineSelector);
                    // we'll inject some garbage that we expect to fail validation
                    const garbage = 'zzzzzz';
                    yield new Promise(resolve => setTimeout(resolve, 2000));
                    yield this.app.client.keys(`${where}${garbage}`); // <-- injecting garbage
                    yield new Promise(resolve => setTimeout(resolve, 2000));
                    yield this.app.client.click(Selectors.SIDECAR_MODE_BUTTON('Save'));
                    // an error state and the garbage text had better appear in the toolbar text
                    yield SidecarExpect.toolbarAlert({ type: 'error', text: expectedError || garbage, exact: false })(this.app);
                    // expect line number to be highlighted, and for that line to be visible
                    yield this.app.client.waitForVisible(`${Selectors.SIDECAR_TAB_CONTENT} .kui--editor-line-highlight`);
                    if (revert) {
                        yield this.app.client.click(Selectors.SIDECAR_MODE_BUTTON('Revert'));
                        yield this.app.client.waitUntil(() => __awaiter(this, void 0, void 0, function* () {
                            const revertedText = yield Util.getValueFromMonaco(this.app);
                            return revertedText === actualText;
                        }), CLI.waitTimeout);
                    }
                }
                catch (err) {
                    yield Common.oops(this, true)(err);
                }
            }));
        };
        // go to spec: line, insert garbage at the beginning (Keys.Home),
        // expect to find garbage text in error message; the last
        // "undefined" means use garbage text as the expected error
        const validationError = modifyWithError.bind(undefined, 'validation error', Keys.Home, undefined);
        // go to spec: line, insert garbage at the end (Keys.End), expect
        // to find "could not find expected..." in error message
        const parseError = modifyWithError.bind(undefined, 'parse error', Keys.End, 'could not find expected');
        /** modify pod {name} so as to add a label of key=value */
        const modify = (name, key = 'foo', value = 'bar') => {
            it('should modify the content', () => __awaiter(this, void 0, void 0, function* () {
                try {
                    const actualText = yield Util.getValueFromMonaco(this.app);
                    const labelsLineIdx = actualText.split(/\n/).indexOf('  labels:');
                    // +2 here because nth-child is indexed from 1, and we want the line after that
                    const lineSelector = `.view-lines > .view-line:nth-child(${labelsLineIdx + 2}) .mtk5:last-child`;
                    yield this.app.client.click(lineSelector);
                    yield new Promise(resolve => setTimeout(resolve, 2000));
                    yield this.app.client.keys(`${Keys.End}${Keys.ENTER}${key}: ${value}${Keys.ENTER}`);
                    yield new Promise(resolve => setTimeout(resolve, 2000));
                    yield this.app.client.click(Selectors.SIDECAR_MODE_BUTTON('Save'));
                    yield SidecarExpect.toolbarAlert({ type: 'success', text: 'Successfully Applied', exact: false })(this.app);
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON('Save'), 10000, true);
                }
                catch (err) {
                    yield Common.oops(this, true)(err);
                }
            }));
            it('should show the modified content in the current yaml tab', () => {
                return SidecarExpect.yaml({ metadata: { labels: { [key]: value } } })(this.app).catch(Common.oops(this, true));
            });
        };
        /** kubectl get pod ${name} */
        const get = (name) => {
            it(`should get pod ${name}`, () => {
                return CLI.command(`${command} get pod ${name} ${inNamespace} -o yaml`, this.app)
                    .then(ReplExpect.justOK)
                    .then(SidecarExpect.open)
                    .then(SidecarExpect.showing(name, undefined, undefined, ns))
                    .catch(Common.oops(this, true));
            });
        };
        /** click Edit button */
        const clickToEdit = (name) => {
            it(`should click the edit button to edit ${name}`, () => __awaiter(this, void 0, void 0, function* () {
                try {
                    // start with the default mode showing
                    yield SidecarExpect.mode(defaultModeForGet);
                    // click the edit button
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON('edit-button'));
                    yield this.app.client.click(Selectors.SIDECAR_MODE_BUTTON('edit-button'));
                    console.error('1');
                    yield new Promise(resolve => setTimeout(resolve, 5000));
                    // edit button should not exist
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON('edit-button'), 5000, true);
                    // should still be showing pod {name}, but now with the yaml tab selected
                    console.error('2');
                    yield SidecarExpect.showing(name, undefined, undefined, ns);
                    console.error('3');
                    yield SidecarExpect.mode('raw');
                    // also: no back/forward buttons should be visible
                    console.error('4');
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_BACK_BUTTON, 5000, true);
                    console.error('5');
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_FORWARD_BUTTON, 5000, true);
                    console.error('6');
                }
                catch (err) {
                    yield Common.oops(this, true)(err);
                }
            }));
            modify(name, 'clickfoo1', 'clickbar1');
            modify(name, 'clickfoo2', 'clickbar2'); // after success, should re-modify the resource in the current tab successfully
            validationError(true); // do unsupported edits in the current tab, validate the error alert, and then undo the changes
            modify(name, 'clickfoo3', 'clickbar3'); // after error, should re-modify the resource in the current tab successfully
            it('should switch to summary tab, expect no alerts and not editable', () => __awaiter(this, void 0, void 0, function* () {
                try {
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON('summary'));
                    yield this.app.client.click(Selectors.SIDECAR_MODE_BUTTON('summary'));
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON_SELECTED('summary'));
                    // toolbar alert should not exist
                    yield this.app.client.waitForExist(Selectors.SIDECAR_ALERT('success'), CLI.waitTimeout, true);
                    // edit button should not exist
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON('edit-button'), 5000, true);
                    // try editing the summary mode
                    const actualText = yield Util.getValueFromMonaco(this.app);
                    const labelsLineIdx = actualText.split(/\n/).indexOf('Name:');
                    // +2 here because nth-child is indexed from 1, and we want the line after that
                    const lineSelector = `.view-lines > .view-line:nth-child(${labelsLineIdx + 2}) .mtk5:last-child`;
                    yield this.app.client.click(lineSelector);
                    yield new Promise(resolve => setTimeout(resolve, 2000));
                    yield this.app.client.keys('x'); // random key
                    yield new Promise(resolve => setTimeout(resolve, 2000));
                    // should have same text
                    const actualText2 = yield Util.getValueFromMonaco(this.app);
                    assert.ok(actualText === actualText2);
                    yield this.app.client.waitForVisible(Selectors.SIDECAR_MODE_BUTTON('Save'), 10000, true); // should not have apply button
                }
                catch (err) {
                    yield Common.oops(this, true)(err);
                }
            }));
        };
        //
        // here come the tests
        //
        allocateNS(this, ns);
        const nginx = 'nginx';
        create(nginx);
        const name2 = 'nginx2';
        create(name2, 'pod2.yaml');
        edit('', 'List', '2 items', 'edit');
        edit(nginx);
        modify(nginx);
        modify(nginx, 'foo1', 'bar1'); // successfully re-modify the resource in the current tab
        validationError(true); // do unsupported edits in the current tab, and then undo the changes
        modify(nginx, 'foo2', 'bar2'); // after error, successfully re-modify the resource in the current tab
        parseError(); // after sucess, do unsupported edits
        edit(nginx);
        validationError(true); // do unsupported edits in the current tab, then undo the changes
        parseError(); // after error, do another unsupported edits in the current tab
        it('should refresh', () => Common.refresh(this));
        get(nginx);
        clickToEdit(nginx);
        deleteNS(this, ns);
    });
});
//# sourceMappingURL=edit.js.map