Commit 2a7690c5 authored by Andrew Fontaine's avatar Andrew Fontaine

Remove new environments table feature flag

Cleans up the feature tests for the environmetns page as well, making
sure they pass with the new table.

Changes are shockingly minimal, which is nice.

Changelog: changed
parent ccd20df3
......@@ -302,7 +302,11 @@ export default {
class="gl-pl-4"
/>
</div>
<div v-if="upcomingDeployment" :class="$options.deploymentClasses">
<div
v-if="upcomingDeployment"
:class="$options.deploymentClasses"
data-testid="upcoming-deployment-content"
>
<deployment
:deployment="upcomingDeployment"
:class="{ 'gl-ml-7': inFolder }"
......
......@@ -16,12 +16,14 @@ import EnvironmentItem from './new_environment_item.vue';
import ConfirmRollbackModal from './confirm_rollback_modal.vue';
import DeleteEnvironmentModal from './delete_environment_modal.vue';
import CanaryUpdateModal from './canary_update_modal.vue';
import EmptyState from './empty_state.vue';
export default {
components: {
DeleteEnvironmentModal,
CanaryUpdateModal,
ConfirmRollbackModal,
EmptyState,
EnvironmentFolder,
EnableReviewAppModal,
EnvironmentItem,
......@@ -66,7 +68,7 @@ export default {
query: environmentToChangeCanaryQuery,
},
},
inject: ['newEnvironmentPath', 'canCreateEnvironment'],
inject: ['newEnvironmentPath', 'canCreateEnvironment', 'helpPagePath'],
i18n: {
newEnvironmentButtonLabel: s__('Environments|New environment'),
reviewAppButtonLabel: s__('Environments|Enable review app'),
......@@ -103,6 +105,9 @@ export default {
environments() {
return this.environmentApp?.environments?.filter((e) => e.size === 1) ?? [];
},
hasEnvironments() {
return this.environments.length > 0 || this.folders.length > 0;
},
availableCount() {
return this.environmentApp?.availableCount;
},
......@@ -221,19 +226,23 @@ export default {
</template>
</gl-tab>
</gl-tabs>
<environment-folder
v-for="folder in folders"
:key="folder.name"
class="gl-mb-3"
:nested-environment="folder"
/>
<environment-item
v-for="environment in environments"
:key="environment.name"
class="gl-mb-3 gl-border-gray-100 gl-border-1 gl-border-b-solid"
:environment="environment.latest"
@change="resetPolling"
/>
<template v-if="hasEnvironments">
<environment-folder
v-for="folder in folders"
:key="folder.name"
class="gl-mb-3"
:scope="scope"
:nested-environment="folder"
/>
<environment-item
v-for="environment in environments"
:key="environment.name"
class="gl-mb-3 gl-border-gray-100 gl-border-1 gl-border-b-solid"
:environment="environment.latest"
@change="resetPolling"
/>
</template>
<empty-state v-else :help-path="helpPagePath" />
<gl-pagination
align="center"
:total-items="totalItems"
......
- page_title _("Environments")
- add_page_specific_style 'page_bundles/environments'
- if Feature.enabled?(:new_environments_table)
#environments-table{ data: { endpoint: project_environments_path(@project, format: :json),
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
"can-create-environment" => can?(current_user, :create_environment, @project).to_s,
"new-environment-path" => new_project_environment_path(@project),
"help-page-path" => help_page_path("ci/environments/index.md"),
"project-path" => @project.full_path,
"project-id" => @project.id,
"default-branch-name" => @project.default_branch_or_main } }
- else
#environments-list-view{ data: { environments_data: environments_list_data,
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
"can-create-environment" => can?(current_user, :create_environment, @project).to_s,
"new-environment-path" => new_project_environment_path(@project),
"help-page-path" => help_page_path("ci/environments/index.md"),
"project-path" => @project.full_path,
"project-id" => @project.id,
"default-branch-name" => @project.default_branch_or_main } }
#environments-table{ data: { endpoint: project_environments_path(@project, format: :json),
"can-read-environment" => can?(current_user, :read_environment, @project).to_s,
"can-create-environment" => can?(current_user, :create_environment, @project).to_s,
"new-environment-path" => new_project_environment_path(@project),
"help-page-path" => help_page_path("ci/environments/index.md"),
"project-path" => @project.full_path,
"project-id" => @project.id,
"default-branch-name" => @project.default_branch_or_main } }
---
name: new_environments_table
introduced_by_url:
rollout_issue_url:
milestone: '14.4'
type: development
group: group::release
default_enabled: false
......@@ -216,6 +216,8 @@ RSpec.describe 'Environments page', :js do
it 'shows the open alert for the environment row' do
visit project_environments_path(project)
page.click_button _('Expand')
within(find('div[data-testid="alert"]')) do
expect(page).to have_content('Critical')
expect(page).to have_content('HTTP Error Rate exceeded 1.0%')
......
......@@ -10,7 +10,6 @@ RSpec.describe 'Environments page', :js do
let(:role) { :developer }
before do
stub_feature_flags(new_environments_table: false)
project.add_role(user, role)
sign_in(user)
end
......@@ -35,24 +34,18 @@ RSpec.describe 'Environments page', :js do
it 'shows "Available" and "Stopped" tab with links' do
visit_environments(project)
expect(page).to have_selector('.js-environments-tab-available')
expect(page).to have_content('Available')
expect(page).to have_selector('.js-environments-tab-stopped')
expect(page).to have_content('Stopped')
expect(page).to have_link(_('Available'))
expect(page).to have_link(_('Stopped'))
end
describe 'with one available environment' do
before do
create(:environment, project: project, state: :available)
end
let!(:environment) { create(:environment, project: project, state: :available) }
describe 'in available tab page' do
it 'shows one environment' do
visit_environments(project, scope: 'available')
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
expect(page.all('[data-testid="stop-icon"]').length).to eq(1)
expect(page).to have_link(environment.name, href: project_environment_path(project, environment))
end
end
......@@ -77,7 +70,6 @@ RSpec.describe 'Environments page', :js do
it 'shows no environments' do
visit_environments(project, scope: 'stopped')
expect(page).to have_css('.environments-container')
expect(page).to have_content('You don\'t have any environments right now')
end
end
......@@ -95,22 +87,18 @@ RSpec.describe 'Environments page', :js do
it 'shows one environment without error' do
visit_environments(project, scope: 'available')
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
expect(page).to have_link(environment.name, href: project_environment_path(project, environment))
end
end
end
describe 'with one stopped environment' do
before do
create(:environment, project: project, state: :stopped)
end
let!(:environment) { create(:environment, project: project, state: :stopped) }
describe 'in available tab page' do
it 'shows no environments' do
visit_environments(project, scope: 'available')
expect(page).to have_css('.environments-container')
expect(page).to have_content('You don\'t have any environments right now')
end
end
......@@ -119,8 +107,7 @@ RSpec.describe 'Environments page', :js do
it 'shows one environment' do
visit_environments(project, scope: 'stopped')
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
expect(page).to have_link(environment.name, href: project_environment_path(project, environment))
expect(page.all('[data-testid="stop-icon"]').length).to eq(0)
end
end
......@@ -135,8 +122,8 @@ RSpec.describe 'Environments page', :js do
it 'does not show environments and counters are set to zero' do
expect(page).to have_content('You don\'t have any environments right now')
expect(page.find('.js-environments-tab-available .badge').text).to eq('0')
expect(page.find('.js-environments-tab-stopped .badge').text).to eq('0')
expect(page).to have_link("#{_('Available')} 0")
expect(page).to have_link("#{_('Stopped')} 0")
end
end
......@@ -150,21 +137,23 @@ RSpec.describe 'Environments page', :js do
context 'when there are no deployments' do
before do
visit_environments(project)
page.click_button _('Expand')
end
it 'shows environments names and counters' do
expect(page).to have_link(environment.name)
expect(page).to have_link(environment.name, href: project_environment_path(project, environment))
expect(page.find('.js-environments-tab-available .badge').text).to eq('1')
expect(page.find('.js-environments-tab-stopped .badge').text).to eq('0')
expect(page).to have_link("#{_('Available')} 1")
expect(page).to have_link("#{_('Stopped')} 0")
end
it 'does not show deployments' do
expect(page).to have_content('No deployments yet')
expect(page).to have_content(s_('Environments|There are no deployments for this environment yet. Learn more about setting up deployments.'))
end
it 'shows stop button when environment is not stoppable' do
expect(page).to have_selector(stop_button_selector)
expect(page).to have_button('Stop')
end
end
......@@ -179,8 +168,10 @@ RSpec.describe 'Environments page', :js do
it 'shows deployment SHA and internal ID' do
visit_environments(project)
page.click_button _('Expand')
expect(page).to have_link(deployment.short_sha)
expect(page).to have_text(deployment.short_sha)
expect(page).to have_link(deployment.commit.full_title)
expect(page).to have_content(deployment.iid)
end
......@@ -218,10 +209,6 @@ RSpec.describe 'Environments page', :js do
.not_to change { Ci::Pipeline.count }
end
it 'shows build name and id' do
expect(page).to have_link("#{build.name} ##{build.id}")
end
it 'shows a stop button' do
expect(page).to have_selector(stop_button_selector)
end
......@@ -373,7 +360,8 @@ RSpec.describe 'Environments page', :js do
it 'does not show deployments' do
visit_environments(project)
expect(page).to have_content('No deployments yet')
page.click_button _('Expand')
expect(page).to have_content(s_('Environments|There are no deployments for this environment yet. Learn more about setting up deployments.'))
end
end
......@@ -389,9 +377,10 @@ RSpec.describe 'Environments page', :js do
it "renders the upcoming deployment", :aggregate_failures do
visit_environments(project)
page.click_button _('Expand')
within(upcoming_deployment_content_selector) do
expect(page).to have_content("##{deployment.iid}")
expect(page).to have_selector("a[href=\"#{project_job_path(project, deployment.deployable)}\"]")
expect(page).to have_link(href: /#{deployment.user.username}/)
end
end
......@@ -413,15 +402,15 @@ RSpec.describe 'Environments page', :js do
let(:role) { :developer }
it 'developer creates a new environment with a valid name' do
within(".environments-section") { click_link 'New environment' }
click_link 'New environment'
fill_in('Name', with: 'production')
click_on 'Save'
expect(page).to have_content('production')
end
it 'developer creates a new environmetn with invalid name' do
within(".environments-section") { click_link 'New environment' }
it 'developer creates a new environment with invalid name' do
click_link 'New environment'
fill_in('Name', with: 'name,with,commas')
click_on 'Save'
......@@ -458,20 +447,11 @@ RSpec.describe 'Environments page', :js do
expect(page).not_to have_content 'review-2'
expect(page).to have_content 'staging 2'
within('.folder-row') do
find('.folder-name', text: 'staging').click
end
page.click_button _('Expand')
expect(page).to have_content 'review-1'
expect(page).to have_content 'review-2'
within('.ci-table') do
within('[data-qa-selector="environment_item"]', text: 'review-1') do # rubocop:disable QA/SelectorUsage
expect(find('.js-auto-stop').text).not_to be_empty
end
within('[data-qa-selector="environment_item"]', text: 'review-2') do # rubocop:disable QA/SelectorUsage
expect(find('.js-auto-stop').text).not_to be_empty
end
end
expect(page).to have_content 'Auto stop in'
end
end
......@@ -494,9 +474,7 @@ RSpec.describe 'Environments page', :js do
expect(page).not_to have_content 'review-2'
expect(page).to have_content 'staging 2'
within('.folder-row') do
find('.folder-name', text: 'staging').click
end
page.click_button _('Expand')
expect(page).to have_content 'review-1'
expect(page).to have_content 'review-2'
......
......@@ -16,8 +16,6 @@ describe('~/environments/components/new_environments_folder.vue', () => {
let wrapper;
let environmentFolderMock;
let nestedEnvironment;
let folderName;
let button;
const findLink = () => wrapper.findByRole('link', { name: s__('Environments|Show all') });
......@@ -42,62 +40,93 @@ describe('~/environments/components/new_environments_folder.vue', () => {
environmentFolderMock = jest.fn();
[nestedEnvironment] = resolvedEnvironmentsApp.environments;
environmentFolderMock.mockReturnValue(resolvedFolder);
wrapper = createWrapper({ nestedEnvironment }, createApolloProvider());
await nextTick();
await waitForPromises();
folderName = wrapper.findByText(nestedEnvironment.name);
button = wrapper.findByRole('button', { name: __('Expand') });
});
afterEach(() => {
wrapper?.destroy();
});
it('displays the name of the folder', () => {
expect(folderName.text()).toBe(nestedEnvironment.name);
});
describe('default', () => {
let folderName;
let button;
describe('collapse', () => {
let icons;
let collapse;
beforeEach(async () => {
wrapper = createWrapper({ nestedEnvironment }, createApolloProvider());
beforeEach(() => {
collapse = wrapper.findComponent(GlCollapse);
icons = wrapper.findAllComponents(GlIcon);
await nextTick();
await waitForPromises();
folderName = wrapper.findByText(nestedEnvironment.name);
button = wrapper.findByRole('button', { name: __('Expand') });
});
it('is collapsed by default', () => {
const link = findLink();
expect(collapse.attributes('visible')).toBeUndefined();
const iconNames = icons.wrappers.map((i) => i.props('name')).slice(0, 2);
expect(iconNames).toEqual(['angle-right', 'folder-o']);
expect(folderName.classes('gl-font-weight-bold')).toBe(false);
expect(link.exists()).toBe(false);
it('displays the name of the folder', () => {
expect(folderName.text()).toBe(nestedEnvironment.name);
});
it('opens on click', async () => {
await button.trigger('click');
const link = findLink();
expect(button.attributes('aria-label')).toBe(__('Collapse'));
expect(collapse.attributes('visible')).toBe('visible');
const iconNames = icons.wrappers.map((i) => i.props('name')).slice(0, 2);
expect(iconNames).toEqual(['angle-down', 'folder-open']);
expect(folderName.classes('gl-font-weight-bold')).toBe(true);
expect(link.attributes('href')).toBe(nestedEnvironment.latest.folderPath);
describe('collapse', () => {
let icons;
let collapse;
beforeEach(() => {
collapse = wrapper.findComponent(GlCollapse);
icons = wrapper.findAllComponents(GlIcon);
});
it('is collapsed by default', () => {
const link = findLink();
expect(collapse.attributes('visible')).toBeUndefined();
const iconNames = icons.wrappers.map((i) => i.props('name')).slice(0, 2);
expect(iconNames).toEqual(['angle-right', 'folder-o']);
expect(folderName.classes('gl-font-weight-bold')).toBe(false);
expect(link.exists()).toBe(false);
});
it('opens on click', async () => {
await button.trigger('click');
const link = findLink();
expect(button.attributes('aria-label')).toBe(__('Collapse'));
expect(collapse.attributes('visible')).toBe('visible');
const iconNames = icons.wrappers.map((i) => i.props('name')).slice(0, 2);
expect(iconNames).toEqual(['angle-down', 'folder-open']);
expect(folderName.classes('gl-font-weight-bold')).toBe(true);
expect(link.attributes('href')).toBe(nestedEnvironment.latest.folderPath);
});
it('displays all environments when opened', async () => {
await button.trigger('click');
const names = resolvedFolder.environments.map((e) =>
expect.stringMatching(e.nameWithoutType),
);
const environments = wrapper
.findAllComponents(EnvironmentItem)
.wrappers.map((w) => w.text());
expect(environments).toEqual(expect.arrayContaining(names));
});
});
});
it('displays all environments when opened', async () => {
await button.trigger('click');
const names = resolvedFolder.environments.map((e) =>
expect.stringMatching(e.nameWithoutType),
it.each(['available', 'stopped'])(
'with scope=%s, fetches environments with scope',
async (scope) => {
wrapper = createWrapper({ nestedEnvironment, scope }, createApolloProvider());
await nextTick();
await waitForPromises();
expect(environmentFolderMock).toHaveBeenCalledTimes(1);
expect(environmentFolderMock).toHaveBeenCalledWith(
{},
{
environment: nestedEnvironment.latest,
scope,
},
expect.anything(),
expect.anything(),
);
const environments = wrapper.findAllComponents(EnvironmentItem).wrappers.map((w) => w.text());
expect(environments).toEqual(expect.arrayContaining(names));
});
});
},
);
});
......@@ -9,6 +9,7 @@ import { sprintf, __, s__ } from '~/locale';
import EnvironmentsApp from '~/environments/components/new_environments_app.vue';
import EnvironmentsFolder from '~/environments/components/new_environment_folder.vue';
import EnvironmentsItem from '~/environments/components/new_environment_item.vue';
import EmptyState from '~/environments/components/empty_state.vue';
import StopEnvironmentModal from '~/environments/components/stop_environment_modal.vue';
import CanaryUpdateModal from '~/environments/components/canary_update_modal.vue';
import { resolvedEnvironmentsApp, resolvedFolder, resolvedEnvironment } from './graphql/mock_data';
......@@ -121,6 +122,14 @@ describe('~/environments/components/new_environments_app.vue', () => {
expect(text).toContainEqual(expect.stringMatching('production'));
});
it('should show an empty state with no environments', async () => {
await createWrapperWithMocked({
environmentsApp: { ...resolvedEnvironmentsApp, environments: [] },
});
expect(wrapper.findComponent(EmptyState).exists()).toBe(true);
});
it('should show a button to create a new environment', async () => {
await createWrapperWithMocked({
environmentsApp: resolvedEnvironmentsApp,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment