* [PATCH 1/4] toaster: layerdetails api Fix saving of git revision of a layer
2016-07-06 17:22 [PATCH 0/4] add link to delete imported layer Elliot Smith
@ 2016-07-06 17:22 ` Elliot Smith
2016-07-06 17:22 ` [PATCH 2/4] toaster: api Add util function for returning the error response Elliot Smith
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Elliot Smith @ 2016-07-06 17:22 UTC (permalink / raw)
To: bitbake-devel
From: Michael Wood <michael.g.wood@intel.com>
Update, clean up and move the api for updating a layerversion from the
views to api. Also update the layerdetails page to include the
layerversion id in the url getter.
[YOCTO #8952]
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
---
lib/toaster/toastergui/api.py | 99 +++++++++++++++++++++-
lib/toaster/toastergui/templates/layerdetails.html | 2 +-
lib/toaster/toastergui/urls.py | 5 +-
lib/toaster/toastergui/views.py | 43 ----------
4 files changed, 103 insertions(+), 46 deletions(-)
diff --git a/lib/toaster/toastergui/api.py b/lib/toaster/toastergui/api.py
index 961b594..a024748 100644
--- a/lib/toaster/toastergui/api.py
+++ b/lib/toaster/toastergui/api.py
@@ -20,11 +20,14 @@
# Temporary home for the UI's misc API
import re
-from orm.models import Project, ProjectTarget, Build
+from orm.models import Project, ProjectTarget, Build, Layer_Version
+from orm.models import LayerVersionDependency, LayerSource, ProjectLayer
from bldcontrol.models import BuildRequest
from bldcontrol import bbcontroller
from django.http import HttpResponse, JsonResponse
from django.views.generic import View
+from django.core.urlresolvers import reverse
+
class XhrBuildRequest(View):
@@ -109,3 +112,97 @@ class XhrBuildRequest(View):
response = HttpResponse()
response.status_code = 500
return response
+
+
+class XhrLayer(View):
+ """ Get and Update Layer information """
+
+ def post(self, request, *args, **kwargs):
+ """
+ Update a layer
+
+ Entry point: /xhr_layer/<layerversion_id>
+ Method: POST
+
+ Args:
+ vcs_url, dirpath, commit, up_branch, summary, description
+
+ add_dep = append a layerversion_id as a dependency
+ rm_dep = remove a layerversion_id as a depedency
+ Returns:
+ {"error": "ok"}
+ or
+ {"error": <error message>}
+ """
+
+ def error_response(error):
+ return JsonResponse({"error": error})
+
+ try:
+ # We currently only allow Imported layers to be edited
+ layer_version = Layer_Version.objects.get(
+ id=kwargs['layerversion_id'],
+ project=kwargs['pid'],
+ layer_source__sourcetype=LayerSource.TYPE_IMPORTED)
+
+ except Layer_Version.DoesNotExist:
+ return error_response("Cannot find imported layer to update")
+
+ if "vcs_url" in request.POST:
+ layer_version.layer.vcs_url = request.POST["vcs_url"]
+ if "dirpath" in request.POST:
+ layer_version.dirpath = request.POST["dirpath"]
+ if "commit" in request.POST:
+ layer_version.commit = request.POST["commit"]
+ layer_version.branch = request.POST["commit"]
+ if "up_branch" in request.POST:
+ layer_version.up_branch_id = int(request.POST["up_branch"])
+ if "summary" in request.POST:
+ layer_version.layer.summary = request.POST["summary"]
+ if "description" in request.POST:
+ layer_version.layer.description = request.POST["description"]
+
+ if "add_dep" in request.POST:
+ lvd = LayerVersionDependency(
+ layer_version=layer_version,
+ depends_on_id=request.POST["add_dep"])
+ lvd.save()
+
+ if "rm_dep" in request.POST:
+ rm_dep = LayerVersionDependency.objects.get(
+ layer_version=layer_version,
+ depends_on_id=request.POST["rm_dep"])
+ rm_dep.delete()
+
+ try:
+ layer_version.layer.save()
+ layer_version.save()
+ except Exception as e:
+ return error_response("Could not update layer version entry: %s"
+ % e)
+
+ return JsonResponse({"error": "ok"})
+
+ def delete(self, request, *args, **kwargs):
+ try:
+ # We currently only allow Imported layers to be deleted
+ layer_version = Layer_Version.objects.get(
+ id=kwargs['layerversion_id'],
+ project=kwargs['pid'],
+ layer_source__sourcetype=LayerSource.TYPE_IMPORTED)
+ except Layer_Version.DoesNotExist:
+ return error_response("Cannot find imported layer to delete")
+
+ try:
+ ProjectLayer.objects.get(project=kwargs['pid'],
+ layercommit=layer_version).delete()
+ except ProjectLayer.DoesNotExist:
+ pass
+
+ layer_version.layer.delete()
+ layer_version.delete()
+
+ return JsonResponse({
+ "error": "ok",
+ "redirect": reverse('project', args=(kwargs['pid'],))
+ })
diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 0f0b2b4..143ec25 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -44,7 +44,7 @@
$(document).ready(function(){
var ctx = {
- xhrUpdateLayerUrl : "{% url 'xhr_updatelayer' %}",
+ xhrUpdateLayerUrl : "{% url 'xhr_layer' layerversion.pk %}",
layerVersion : {
name : "{{layerversion.layer.name}}",
id : {{layerversion.id}},
diff --git a/lib/toaster/toastergui/urls.py b/lib/toaster/toastergui/urls.py
index 9510a38..15b1063 100644
--- a/lib/toaster/toastergui/urls.py
+++ b/lib/toaster/toastergui/urls.py
@@ -190,7 +190,10 @@ urlpatterns = patterns('toastergui.views',
name='xhr_configvaredit'),
url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'),
- url(r'^xhr_updatelayer/$', 'xhr_updatelayer', name='xhr_updatelayer'),
+
+ url(r'^xhr_layer/(?P<layerversion_id>\d+)$',
+ api.XhrLayer.as_view(),
+ name='xhr_layer'),
# JS Unit tests
url(r'^js-unit-tests/$', 'jsunittests', name='js-unit-tests'),
diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 2db68bd..ad85faf 100755
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -1739,49 +1739,6 @@ if True:
return HttpResponse(jsonfilter(json_response), content_type = "application/json")
- def xhr_updatelayer(request):
-
- def error_response(error):
- return HttpResponse(jsonfilter({"error": error}), content_type = "application/json")
-
- if "layer_version_id" not in request.POST:
- return error_response("Please specify a layer version id")
- try:
- layer_version_id = request.POST["layer_version_id"]
- layer_version = Layer_Version.objects.get(id=layer_version_id)
- except Layer_Version.DoesNotExist:
- return error_response("Cannot find layer to update")
-
-
- if "vcs_url" in request.POST:
- layer_version.layer.vcs_url = request.POST["vcs_url"]
- if "dirpath" in request.POST:
- layer_version.dirpath = request.POST["dirpath"]
- if "commit" in request.POST:
- layer_version.commit = request.POST["commit"]
- if "up_branch" in request.POST:
- layer_version.up_branch_id = int(request.POST["up_branch"])
-
- if "add_dep" in request.POST:
- lvd = LayerVersionDependency(layer_version=layer_version, depends_on_id=request.POST["add_dep"])
- lvd.save()
-
- if "rm_dep" in request.POST:
- rm_dep = LayerVersionDependency.objects.get(layer_version=layer_version, depends_on_id=request.POST["rm_dep"])
- rm_dep.delete()
-
- if "summary" in request.POST:
- layer_version.layer.summary = request.POST["summary"]
- if "description" in request.POST:
- layer_version.layer.description = request.POST["description"]
-
- try:
- layer_version.layer.save()
- layer_version.save()
- except Exception as e:
- return error_response("Could not update layer version entry: %s" % e)
-
- return HttpResponse(jsonfilter({"error": "ok",}), content_type = "application/json")
@xhr_response
def xhr_customrecipe(request):
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/4] toaster: api Add util function for returning the error response
2016-07-06 17:22 [PATCH 0/4] add link to delete imported layer Elliot Smith
2016-07-06 17:22 ` [PATCH 1/4] toaster: layerdetails api Fix saving of git revision of a layer Elliot Smith
@ 2016-07-06 17:22 ` Elliot Smith
2016-07-06 17:22 ` [PATCH 3/4] toaster: add Layer delete front end feature to layerdetails Elliot Smith
2016-07-06 17:22 ` [PATCH 4/4] toaster: tests Add selenium test for layerdetails page Elliot Smith
3 siblings, 0 replies; 5+ messages in thread
From: Elliot Smith @ 2016-07-06 17:22 UTC (permalink / raw)
To: bitbake-devel
From: Michael Wood <michael.g.wood@intel.com>
Also clean up flake8 warnings in XhrBuildRequest
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
---
lib/toaster/toastergui/api.py | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/lib/toaster/toastergui/api.py b/lib/toaster/toastergui/api.py
index a024748..112ce58 100644
--- a/lib/toaster/toastergui/api.py
+++ b/lib/toaster/toastergui/api.py
@@ -29,6 +29,9 @@ from django.views.generic import View
from django.core.urlresolvers import reverse
+def error_response(error):
+ return JsonResponse({"error": error})
+
class XhrBuildRequest(View):
@@ -81,20 +84,24 @@ class XhrBuildRequest(View):
br.save()
except BuildRequest.DoesNotExist:
- return JsonResponse({'error':'No such build id %s' % i})
+ return error_response('No such build id %s' % i)
- return JsonResponse({'error': 'ok'})
+ return error_response('ok')
if 'buildDelete' in request.POST:
for i in request.POST['buildDelete'].strip().split(" "):
try:
- BuildRequest.objects.select_for_update().get(project = project, pk = i, state__lte = BuildRequest.REQ_DELETED).delete()
+ BuildRequest.objects.select_for_update().get(
+ project=project,
+ pk=i,
+ state__lte=BuildRequest.REQ_DELETED).delete()
+
except BuildRequest.DoesNotExist:
pass
- return JsonResponse({'error': 'ok' })
+ return error_response("ok")
if 'targets' in request.POST:
- ProjectTarget.objects.filter(project = project).delete()
+ ProjectTarget.objects.filter(project=project).delete()
s = str(request.POST['targets'])
for t in re.sub(r'[;%|"]', '', s).split(" "):
if ":" in t:
@@ -102,12 +109,12 @@ class XhrBuildRequest(View):
else:
target = t
task = ""
- ProjectTarget.objects.create(project = project,
- target = target,
- task = task)
+ ProjectTarget.objects.create(project=project,
+ target=target,
+ task=task)
project.schedule_build()
- return JsonResponse({'error': 'ok' })
+ return error_response('ok')
response = HttpResponse()
response.status_code = 500
@@ -135,9 +142,6 @@ class XhrLayer(View):
{"error": <error message>}
"""
- def error_response(error):
- return JsonResponse({"error": error})
-
try:
# We currently only allow Imported layers to be edited
layer_version = Layer_Version.objects.get(
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 3/4] toaster: add Layer delete front end feature to layerdetails
2016-07-06 17:22 [PATCH 0/4] add link to delete imported layer Elliot Smith
2016-07-06 17:22 ` [PATCH 1/4] toaster: layerdetails api Fix saving of git revision of a layer Elliot Smith
2016-07-06 17:22 ` [PATCH 2/4] toaster: api Add util function for returning the error response Elliot Smith
@ 2016-07-06 17:22 ` Elliot Smith
2016-07-06 17:22 ` [PATCH 4/4] toaster: tests Add selenium test for layerdetails page Elliot Smith
3 siblings, 0 replies; 5+ messages in thread
From: Elliot Smith @ 2016-07-06 17:22 UTC (permalink / raw)
To: bitbake-devel
From: Michael Wood <michael.g.wood@intel.com>
Add the front end feature to delete a layer from the layer details page.
[YOCO #9184]
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
---
lib/toaster/toastergui/static/js/layerdetails.js | 20 ++++++++++++++++++++
lib/toaster/toastergui/static/js/projectpage.js | 18 ++++++++++++++++++
lib/toaster/toastergui/templates/layerdetails.html | 20 +++++++++++++++++++-
lib/toaster/toastergui/urls.py | 2 +-
4 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/lib/toaster/toastergui/static/js/layerdetails.js b/lib/toaster/toastergui/static/js/layerdetails.js
index a56087b..683486e 100644
--- a/lib/toaster/toastergui/static/js/layerdetails.js
+++ b/lib/toaster/toastergui/static/js/layerdetails.js
@@ -397,6 +397,26 @@ function layerDetailsPageInit (ctx) {
$(this).parents("form").submit();
});
+ $("#layer-delete-confirmed").click(function(){
+ $.cookie("layer-deleted", ctx.layerVersion.name, { path: '/'});
+
+ $.ajax({
+ type: "DELETE",
+ url: ctx.xhrUpdateLayerUrl,
+ headers: { 'X-CSRFToken' : $.cookie('csrftoken')},
+ success: function(data) {
+ if (data.error != "ok") {
+ console.warn(data.error);
+ } else {
+ window.location = data.redirect + "?notify=layer-deleted";
+ }
+ },
+ error: function(data) {
+ console.warn("Call failed");
+ console.warn(data);
+ }
+ });
+ });
layerDepsList.find(".glyphicon-trash").click(layerDepRemoveClick);
layerDepsList.find("a").tooltip();
diff --git a/lib/toaster/toastergui/static/js/projectpage.js b/lib/toaster/toastergui/static/js/projectpage.js
index 6d92490..df79849 100644
--- a/lib/toaster/toastergui/static/js/projectpage.js
+++ b/lib/toaster/toastergui/static/js/projectpage.js
@@ -58,12 +58,30 @@ function projectPageInit(ctx) {
case 'layer-imported':
layerImportedNotification();
break;
+ case 'layer-deleted':
+ layerDeletedNotification();
default:
break;
}
}
})();
+ /* Layer deleted notification */
+ function layerDeletedNotification(){
+ var layer = $.cookie("layer-deleted");
+
+ if (!layer)
+ return;
+
+ var message = "You have deleted <strong>1</strong> layer from your ";
+ message += "project: <strong>" + layer + "</strong>";
+
+ libtoaster.showChangeNotification(message);
+
+ $.removeCookie("layer-deleted", { path: "/"});
+ }
+
+
/* Layer imported notification */
function layerImportedNotification(){
var imported = $.cookie("layer-imported-alert");
diff --git a/lib/toaster/toastergui/templates/layerdetails.html b/lib/toaster/toastergui/templates/layerdetails.html
index 143ec25..4b51d1a 100644
--- a/lib/toaster/toastergui/templates/layerdetails.html
+++ b/lib/toaster/toastergui/templates/layerdetails.html
@@ -6,6 +6,20 @@
{% block title %} {{layerversion.layer.name}} - {{project.name}} - Toaster {% endblock %}
{% block pagecontent %}
+<div id="delete-layer-modal" class="modal fade" tabindex="-1" role="dialog">
+ <div class="modal-dialog" role="document">
+ <div class="modal-content">
+ <div class="modal-body">
+ Are you sure you want to delete the <strong>{{layerversion.layer.name}}</strong> layer?
+ </div>
+ <div class="modal-footer">
+ <button type="button" id="layer-delete-confirmed" class="btn btn-primary">Delete</button>
+ <button type="button" class="btn btn-default btn-link" data-dismiss="modal">Cancel</button>
+ </div>
+ </div>
+ </div>
+</div>
+
<div class="row">
<div class="col-md-12">
<ul class="breadcrumb">
@@ -44,7 +58,7 @@
$(document).ready(function(){
var ctx = {
- xhrUpdateLayerUrl : "{% url 'xhr_layer' layerversion.pk %}",
+ xhrUpdateLayerUrl : "{% url 'xhr_layer' project.id layerversion.pk %}",
layerVersion : {
name : "{{layerversion.layer.name}}",
id : {{layerversion.id}},
@@ -271,6 +285,10 @@
</dd>
{% endif %}
</dl>
+ {% if layerversion.layer_source_id and layerversion.layer_source.sourcetype == layerversion.layer_source.TYPE_IMPORTED %}
+ <i class="icon-trash text-danger"></i>
+ <a href="#delete-layer-modal" role="button" class="text-danger" data-toggle="modal" data-target="#delete-layer-modal">Delete {{layerversion.layer.name}}</a>
+ {% endif %}
</div>
</div>
</div>
diff --git a/lib/toaster/toastergui/urls.py b/lib/toaster/toastergui/urls.py
index 15b1063..1c0ccbb 100644
--- a/lib/toaster/toastergui/urls.py
+++ b/lib/toaster/toastergui/urls.py
@@ -191,7 +191,7 @@ urlpatterns = patterns('toastergui.views',
url(r'^xhr_importlayer/$', 'xhr_importlayer', name='xhr_importlayer'),
- url(r'^xhr_layer/(?P<layerversion_id>\d+)$',
+ url(r'^xhr_layer/(?P<pid>\d+)/(?P<layerversion_id>\d+)$',
api.XhrLayer.as_view(),
name='xhr_layer'),
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 4/4] toaster: tests Add selenium test for layerdetails page
2016-07-06 17:22 [PATCH 0/4] add link to delete imported layer Elliot Smith
` (2 preceding siblings ...)
2016-07-06 17:22 ` [PATCH 3/4] toaster: add Layer delete front end feature to layerdetails Elliot Smith
@ 2016-07-06 17:22 ` Elliot Smith
3 siblings, 0 replies; 5+ messages in thread
From: Elliot Smith @ 2016-07-06 17:22 UTC (permalink / raw)
To: bitbake-devel
From: Michael Wood <michael.g.wood@intel.com>
This tests:
- Adding remove layer from project
- Deleting layer
- Editing layer fields
Signed-off-by: Michael Wood <michael.g.wood@intel.com>
Signed-off-by: Elliot Smith <elliot.smith@intel.com>
---
.../tests/browser/test_layerdetails_page.py | 190 +++++++++++++++++++++
1 file changed, 190 insertions(+)
create mode 100644 bitbake/lib/toaster/tests/browser/test_layerdetails_page.py
diff --git a/lib/toaster/tests/browser/test_layerdetails_page.py b/lib/toaster/tests/browser/test_layerdetails_page.py
new file mode 100644
index 0000000..fb1007f
--- /dev/null
+++ b/lib/toaster/tests/browser/test_layerdetails_page.py
@@ -0,0 +1,190 @@
+#! /usr/bin/env python
+# ex:ts=4:sw=4:sts=4:et
+# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
+#
+# BitBake Toaster Implementation
+#
+# Copyright (C) 2013-2016 Intel Corporation
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+from django.core.urlresolvers import reverse
+from tests.browser.selenium_helpers import SeleniumTestCase
+
+from orm.models import Layer, Layer_Version, Project, LayerSource, Release
+from orm.models import BitbakeVersion
+
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.common.by import By
+
+
+class TestLayerDetailsPage(SeleniumTestCase):
+ """ Test layerdetails page works correctly """
+
+ def __init__(self, *args, **kwargs):
+ super(TestLayerDetailsPage, self).__init__(*args, **kwargs)
+
+ self.initial_values = None
+ self.url = None
+ self.imported_layer_version = None
+
+ def setUp(self):
+ release = Release.objects.create(
+ name='baz',
+ bitbake_version=BitbakeVersion.objects.create(name='v1')
+ )
+
+ # project to add new custom images to
+ self.project = Project.objects.create(name='foo', release=release)
+
+ layer_source = LayerSource.objects.create(
+ sourcetype=LayerSource.TYPE_IMPORTED)
+
+ name = "meta-imported"
+ vcs_url = "git://example.com/meta-imported"
+ subdir = "/layer"
+ gitrev = "d33d"
+ summary = "A imported layer"
+ description = "This was imported"
+
+ imported_layer = Layer.objects.create(name=name,
+ vcs_url=vcs_url,
+ summary=summary,
+ description=description)
+
+ self.imported_layer_version = Layer_Version.objects.create(
+ layer=imported_layer,
+ layer_source=layer_source,
+ branch=gitrev,
+ commit=gitrev,
+ dirpath=subdir,
+ project=self.project)
+
+ self.initial_values = [name, vcs_url, subdir, gitrev, summary,
+ description]
+ self.url = reverse('layerdetails',
+ args=(self.project.pk,
+ self.imported_layer_version.pk))
+
+ def test_edit_layerdetails(self):
+ """ Edit all the editable fields for the layer refresh the page and
+ check that the new values exist"""
+
+ self.get(self.url)
+
+ self.click("#add-remove-layer-btn")
+
+ # Open every edit box
+ for btn in self.find_all("dd .glyphicon-edit"):
+ btn.click()
+
+ self.wait_until_visible("dd input")
+
+ # Edit each value
+ for inputs in self.find_all("dd input[type=text]") + \
+ self.find_all("dd textarea"):
+ # ignore the tt inputs (twitter typeahead input)
+ if "tt-" in inputs.get_attribute("class"):
+ continue
+
+ value = inputs.get_attribute("value")
+
+ self.assertTrue(value in self.initial_values,
+ "Expecting any of \"%s\"but got \"%s\"" %
+ (self.initial_values, value))
+
+ inputs.send_keys("-edited")
+
+ for save_btn in self.find_all(".change-btn"):
+ save_btn.click()
+
+ # Refresh the page to see if the new values are returned
+ self.get(self.url)
+
+ new_values = ["%s-edited" % old_val
+ for old_val in self.initial_values]
+
+ for inputs in self.find_all("dd input[type=text]") + \
+ self.find_all("dd textarea"):
+ # ignore the tt inputs (twitter typeahead input)
+ if "tt-" in inputs.get_attribute("class"):
+ continue
+
+ value = inputs.get_attribute("value")
+
+ self.assertTrue(value in new_values,
+ "Expecting any of \"%s\"but got \"%s\"" %
+ (self.initial_values, value))
+
+ def test_delete_layer(self):
+ """ Delete the layer """
+
+ self.get(self.url)
+
+ # Wait for the tables to load to avoid a race condition where the
+ # toaster tables have made an async request. If the layer is deleted
+ # before the request finishes it will cause an exception and fail this
+ # test.
+ wait = WebDriverWait(self.driver, 30)
+
+ wait.until(EC.text_to_be_present_in_element(
+ (By.CLASS_NAME,
+ "table-count-recipestable"), "0"))
+
+ wait.until(EC.text_to_be_present_in_element(
+ (By.CLASS_NAME,
+ "table-count-machinestable"), "0"))
+
+ self.click('a[data-target="#delete-layer-modal"]')
+ self.wait_until_visible("#delete-layer-modal")
+ self.click("#layer-delete-confirmed")
+
+ notification = self.wait_until_visible("#change-notification-msg")
+ expected_text = "You have deleted 1 layer from your project: %s" % \
+ self.imported_layer_version.layer.name
+
+ self.assertTrue(expected_text in notification.text,
+ "Expected notification text \"%s\" not found instead"
+ "it was \"%s\"" %
+ (expected_text, notification.text))
+
+ def test_addrm_to_project(self):
+ self.get(self.url)
+
+ # Add the layer
+ self.click("#add-remove-layer-btn")
+
+ notification = self.wait_until_visible("#change-notification-msg")
+
+ expected_text = "You have added 1 layer to your project: %s" % \
+ self.imported_layer_version.layer.name
+
+ self.assertTrue(expected_text in notification.text,
+ "Expected notification text %s not found was "
+ " \"%s\" instead" %
+ (expected_text, notification.text))
+
+ # Remove the layer
+ self.click("#add-remove-layer-btn")
+
+ notification = self.wait_until_visible("#change-notification-msg")
+
+ expected_text = "You have removed 1 layer from your project: %s" % \
+ self.imported_layer_version.layer.name
+
+ self.assertTrue(expected_text in notification.text,
+ "Expected notification text %s not found was "
+ " \"%s\" instead" %
+ (expected_text, notification.text))
--
2.7.4
^ permalink raw reply related [flat|nested] 5+ messages in thread