From bd4be00ae42d3888a498443ae0933378d671dac4 Mon Sep 17 00:00:00 2001
From: polesye <s2pak.anton@gmail.com>
Date: Mon, 17 Mar 2014 14:20:43 +0200
Subject: [PATCH] BLD-534: Add acceptance test.

---
 lms/djangoapps/courseware/features/video.feature |  59 +++++++++++++++++++++++++++++++++++++++++++----------------
 lms/djangoapps/courseware/features/video.py      | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------
 2 files changed, 168 insertions(+), 79 deletions(-)

diff --git a/lms/djangoapps/courseware/features/video.feature b/lms/djangoapps/courseware/features/video.feature
index 1051143..8556bed 100644
--- a/lms/djangoapps/courseware/features/video.feature
+++ b/lms/djangoapps/courseware/features/video.feature
@@ -4,8 +4,8 @@ Feature: LMS Video component
 
   # 1
   Scenario: Video component stores position correctly when page is reloaded
-    Given the course has a Video component in Youtube mode
-    Then when I view the video it has rendered in Youtube mode
+    Given the course has a Video component in "Youtube" mode
+    When the video has rendered in "Youtube" mode
     And I click video button "play"
     Then I seek video to "10" seconds
     And I click video button "pause"
@@ -15,13 +15,13 @@ Feature: LMS Video component
 
   # 2
   Scenario: Video component is fully rendered in the LMS in HTML5 mode
-    Given the course has a Video component in HTML5 mode
-    Then when I view the video it has rendered in HTML5 mode
+    Given the course has a Video component in "HTML5" mode
+    When the video has rendered in "HTML5" mode
     And all sources are correct
 
   # 3
   # Firefox doesn't have HTML5 (only mp4 - fix here)
-  # Disabled because does_not_autoplay fails with the 
+  # Disabled because does_not_autoplay fails with the
   # selenium upgrade from 2.34.0 to 2.39.0. See TE-368
 #  @skip_firefox
 #  Scenario: Autoplay is disabled in LMS for a Video component
@@ -32,30 +32,30 @@ Feature: LMS Video component
   # Youtube testing
   Scenario: Video component is fully rendered in the LMS in Youtube mode with HTML5 sources
     Given youtube server is up and response time is 0.4 seconds
-    And the course has a Video component in Youtube_HTML5 mode
-    Then when I view the video it has rendered in Youtube mode
+    And the course has a Video component in "Youtube_HTML5" mode
+    When the video has rendered in "Youtube" mode
 
   # 5
   Scenario: Video component is not rendered in the LMS in Youtube mode with HTML5 sources
     Given youtube server is up and response time is 2 seconds
-    And the course has a Video component in Youtube_HTML5 mode
-    Then when I view the video it has rendered in HTML5 mode
+    And the course has a Video component in "Youtube_HTML5" mode
+    When the video has rendered in "HTML5" mode
 
   # 6
   Scenario: Video component is rendered in the LMS in Youtube mode without HTML5 sources
     Given youtube server is up and response time is 2 seconds
-    And the course has a Video component in Youtube mode
-    Then when I view the video it has rendered in Youtube mode
+    And the course has a Video component in "Youtube" mode
+    When the video has rendered in "Youtube" mode
 
   # 7
   Scenario: Video component is rendered in the LMS in Youtube mode with HTML5 sources that doesn't supported by browser
     Given youtube server is up and response time is 2 seconds
-    And the course has a Video component in Youtube_HTML5_Unsupported_Video mode
-    Then when I view the video it has rendered in Youtube mode
+    And the course has a Video component in "Youtube_HTML5_Unsupported_Video" mode
+    When the video has rendered in "Youtube" mode
 
   # 8
   Scenario: Video component is rendered in the LMS in HTML5 mode with HTML5 sources that doesn't supported by browser
-    Given the course has a Video component in HTML5_Unsupported_Video mode
+    Given the course has a Video component in "HTML5_Unsupported_Video" mode
     Then error message is shown
     And error message has correct text
 
@@ -136,7 +136,7 @@ Feature: LMS Video component
 
   # 15
   Scenario: CC button is hidden if no translations
-    Given the course has a Video component in Youtube mode
+    Given the course has a Video component in "Youtube" mode
     Then button "CC" is hidden
 
   # 16
@@ -152,7 +152,7 @@ Feature: LMS Video component
 
   # 17
   Scenario: Video is aligned correctly if transcript is hidden in fullscreen mode
-    Given the course has a Video component in Youtube mode
+    Given the course has a Video component in "Youtube" mode
     And I click video button "fullscreen"
     Then I see video aligned correctly without enabled transcript
 
@@ -251,3 +251,30 @@ Feature: LMS Video component
       | {"zh": "chinese_transcripts.srt"} | true           |
     And I see "好 各位同学" text in the captions
     Then I can download transcript in "srt" format that has text "好 各位同学"
+
+  # 25
+  Scenario: Verify that each video in each sub-section includes a transcript for non-Youtube countries.
+    Given youtube server is up and response time is 2 seconds
+    And I am registered for the course "test_course"
+    And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
+    And I have a "subs_b7xgknqkQk8.srt.sjson" transcript file in assets
+    And I have a "chinese_transcripts.srt" transcript file in assets
+    And it has videos "A, B" in "Youtube_HTML5" mode in position "1" of sequential:
+      | sub         |
+      | OEoXaMPEzfM |
+      | b7xgknqkQk8 |
+    And a video "C" in "Youtube_HTML5" mode in position "2" of sequential:
+      | transcripts                       |
+      | {"zh": "chinese_transcripts.srt"} |
+    And a video "D" in "Youtube_HTML5" mode in position "3" of sequential
+    And I open the section with videos
+    Then videos have rendered in "HTML5" mode
+    And I see "Hi, welcome to Edx." text in the captions
+    And I see "Equal transcripts" text in the captions
+    When I open video "C"
+    Then the video has rendered in "HTML5" mode
+    And I make sure captions are opened
+    And I see "好 各位同学" text in the captions
+    When I open video "D"
+    Then the video has rendered in "HTML5" mode
+    And the video does not show the captions
diff --git a/lms/djangoapps/courseware/features/video.py b/lms/djangoapps/courseware/features/video.py
index 414371c..0fd58a5 100644
--- a/lms/djangoapps/courseware/features/video.py
+++ b/lms/djangoapps/courseware/features/video.py
@@ -1,12 +1,12 @@
 # -*- coding: utf-8 -*-
 # pylint: disable=C0111
 
-from lettuce import world, step
-import os
+from lettuce import world, step, before
 import json
+import os
 import time
 import requests
-from common import i_am_registered_for_the_course, section_location, visit_scenario_item
+from common import i_am_registered_for_the_course, visit_scenario_item
 from django.utils.translation import ugettext as _
 from django.conf import settings
 from cache_toolbox.core import del_cached_content
@@ -45,7 +45,10 @@ VIDEO_MENUS = {
 }
 
 coursenum = 'test_course'
-sequence = {}
+
+@before.each_scenario
+def setUp(scenario):
+    world.video_sequences = {}
 
 
 class ReuqestHandlerWithSessionId(object):
@@ -86,28 +89,26 @@ class ReuqestHandlerWithSessionId(object):
             return True
         return False
 
-def add_video_to_course(course, player_mode, hashes, display_name='Video'):
-    category = 'video'
-
+def get_metadata(parent_location, player_mode, data, display_name='Video'):
     kwargs = {
-        'parent_location': section_location(course),
-        'category': category,
+        'parent_location': parent_location,
+        'category': 'video',
         'display_name': display_name,
         'metadata': {},
     }
 
-    if hashes:
-        kwargs['metadata'].update(hashes[0])
+    if data:
+        conversions = {
+            'transcripts': json.loads,
+            'download_track': json.loads,
+            'download_video': json.loads,
+        }
 
-    conversions = {
-        'transcripts': json.loads,
-        'download_track': json.loads,
-        'download_video': json.loads,
-    }
+        for key in data:
+            if key in conversions:
+                data[key] = conversions[key](data[key])
 
-    for key in kwargs['metadata']:
-        if key in conversions:
-            kwargs['metadata'][key] = conversions[key](kwargs['metadata'][key])
+        kwargs['metadata'].update(data)
 
     if player_mode == 'html5':
         kwargs['metadata'].update({
@@ -134,19 +135,53 @@ def add_video_to_course(course, player_mode, hashes, display_name='Video'):
             'html5_sources': HTML5_SOURCES_INCORRECT
         })
 
+    return kwargs
+
+
+def add_videos_to_course(course, player_mode=None, display_names=None, hashes=None):
+    parent_location = add_vertical_to_course(course)
+    kwargs = {
+        'course': course,
+        'parent_location': parent_location,
+        'player_mode': player_mode,
+        'display_name': display_names[0],
+    }
+
+    if hashes:
+        for index, item_data in enumerate(hashes):
+            kwargs.update({
+                'display_name': display_names[index],
+                'data': item_data,
+            })
+            add_video_to_course(**kwargs)
+    else:
+        add_video_to_course(**kwargs)
+
+
+def add_video_to_course(course, parent_location=None, player_mode=None, data=None, display_name='Video'):
+    if not parent_location:
+        parent_location = add_vertical_to_course(course)
+    kwargs = get_metadata(parent_location, player_mode, data, display_name=display_name)
     world.scenario_dict['VIDEO'] = world.ItemFactory.create(**kwargs)
     world.wait_for_present('.is-initialized')
     world.wait_for_invisible('.video-wrapper .spinner')
 
 
-def _get_sjson_filename(videoId, lang):
-    if lang == 'en':
-        return 'subs_{0}.srt.sjson'.format(videoId)
-    else:
-        return '{0}_subs_{1}.srt.sjson'.format(lang, videoId)
+def add_vertical_to_course(course_num):
+    world.scenario_dict['LAST_VERTICAL'] = world.ItemFactory.create(
+        parent_location=world.scenario_dict['SECTION'].location,
+        category='vertical',
+        display_name='Test Vertical-{}'.format(len(set(world.video_sequences.values()))),
+    )
+
+    return last_vertical_location(course_num)
+
 
+def last_vertical_location(course_num):
+    return world.scenario_dict['LAST_VERTICAL'].location._replace(course=course_num)
 
-def _upload_file(filename, location):
+
+def upload_file(filename, location):
     path = os.path.join(TEST_ROOT, 'uploads/', filename)
     f = open(os.path.abspath(path))
     mime_type = "application/json"
@@ -159,27 +194,28 @@ def _upload_file(filename, location):
     del_cached_content(content.location)
 
 
-def _navigate_to_an_item_in_a_sequence(number):
+def navigate_to_an_item_in_a_sequence(number):
     sequence_css = '#sequence-list a[data-element="{0}"]'.format(number)
     world.css_click(sequence_css)
 
 
-def _change_video_speed(speed):
+def change_video_speed(speed):
     world.browser.execute_script("$('.speeds').addClass('open')")
     speed_css = 'li[data-speed="{0}"] a'.format(speed)
     world.css_click(speed_css)
 
-def _open_menu(menu):
+
+def open_menu(menu):
     world.browser.execute_script("$('{selector}').parent().addClass('open')".format(
         selector=VIDEO_MENUS[menu]
     ))
 
 
-def _get_all_dimensions():
-    video = _get_dimensions('.video-player iframe, .video-player video')
-    wrapper = _get_dimensions('.tc-wrapper')
-    controls = _get_dimensions('.video-controls')
-    progress_slider = _get_dimensions('.video-controls > .slider')
+def get_all_dimensions():
+    video = get_dimensions('.video-player iframe, .video-player video')
+    wrapper = get_dimensions('.tc-wrapper')
+    controls = get_dimensions('.video-controls')
+    progress_slider = get_dimensions('.video-controls > .slider')
 
     expected = dict(wrapper)
     expected['height'] -= controls['height'] + 0.5 * progress_slider['height']
@@ -187,30 +223,30 @@ def _get_all_dimensions():
     return (video, expected)
 
 
-def _get_dimensions(selector):
+def get_dimensions(selector):
     element = world.css_find(selector).first
     return element._element.size
 
 
-def _get_window_dimensions():
+def get_window_dimensions():
     return world.browser.driver.get_window_size()
 
 
-def _set_window_dimensions(width, height):
+def set_window_dimensions(width, height):
     world.browser.driver.set_window_size(width, height)
     # Wait 200 ms when JS finish resizing
     world.wait(0.2)
 
 
-def _duration():
+def duration():
         """
         Total duration of the video, in seconds.
         """
-        elapsed_time, duration = _video_time()
+        elapsed_time, duration = video_time()
         return duration
 
 
-def _video_time():
+def video_time():
         """
         Return a tuple `(elapsed_time, duration)`, each in seconds.
         """
@@ -221,10 +257,10 @@ def _video_time():
         elapsed_str, duration_str = full_time.split(' / ')
 
         # Convert each string to seconds
-        return (_parse_time_str(elapsed_str), _parse_time_str(duration_str))
+        return (parse_time_str(elapsed_str), parse_time_str(duration_str))
 
 
-def _parse_time_str(time_str):
+def parse_time_str(time_str):
     """
     Parse a string of the form 1:23 into seconds (int).
     """
@@ -237,23 +273,26 @@ def does_not_autoplay(_step, video_type):
     assert(world.css_find('.%s' % video_type)[0]['data-autoplay'] == 'False')
 
 
-@step('the course has a Video component in (.*) mode(?:\:)?$')
+@step('the course has a Video component in "([^"]*)" mode(?:\:)?$')
 def view_video(_step, player_mode):
     i_am_registered_for_the_course(_step, coursenum)
-    add_video_to_course(coursenum, player_mode.lower(), _step.hashes)
+    data = _step.hashes[0] if _step.hashes else None
+    add_video_to_course(coursenum, player_mode=player_mode.lower(), data=data)
     visit_scenario_item('SECTION')
 
 
 @step('a video in "([^"]*)" mode(?:\:)?$')
 def add_video(_step, player_mode):
-    add_video_to_course(coursenum, player_mode.lower(), _step.hashes)
+    data = _step.hashes[0] if _step.hashes else None
+    add_video_to_course(coursenum, player_mode=player_mode.lower(), data=data)
     visit_scenario_item('SECTION')
 
 
-@step('a video "([^"]*)" in "([^"]*)" mode in position "([^"]*)" of sequential(?:\:)?$')
-def add_video_in_position(_step, player_id, player_mode, position):
-    sequence[player_id] = position
-    add_video_to_course(coursenum, player_mode.lower(), _step.hashes, display_name=player_id)
+@step('video(?:s)? "([^"]*)" in "([^"]*)" mode in position "([^"]*)" of sequential(?:\:)?$')
+def add_video_in_position(_step, video_ids, player_mode, position):
+    sequences = {video_id.strip(): position for video_id in video_ids.split(',')}
+    add_videos_to_course(coursenum, player_mode=player_mode.lower(), display_names=sequences.keys(), hashes=_step.hashes)
+    world.video_sequences.update(sequences)
 
 
 @step('I open the section with videos$')
@@ -262,19 +301,19 @@ def visit_video_section(_step):
 
 
 @step('I select the "([^"]*)" speed$')
-def change_video_speed(_step, speed):
-      _change_video_speed(speed)
+def i_select_video_speed(_step, speed):
+      change_video_speed(speed)
 
 
 @step('I select the "([^"]*)" speed on video "([^"]*)"$')
 def change_video_speed_on_video(_step, speed, player_id):
-      _navigate_to_an_item_in_a_sequence(sequence[player_id])
-      _change_video_speed(speed)
+      navigate_to_an_item_in_a_sequence(world.video_sequences[player_id])
+      change_video_speed(speed)
 
 
 @step('I open video "([^"]*)"$')
 def open_video(_step, player_id):
-    _navigate_to_an_item_in_a_sequence(sequence[player_id])
+    navigate_to_an_item_in_a_sequence(world.video_sequences[player_id])
 
 
 @step('video "([^"]*)" should start playing at speed "([^"]*)"$')
@@ -288,7 +327,7 @@ def set_youtube_response_timeout(_step, time):
     world.youtube.config['time_to_response'] = float(time)
 
 
-@step('when I view the video it has rendered in (.*) mode$')
+@step('the video has rendered in "([^"]*)" mode$')
 def video_is_rendered(_step, mode):
     modes = {
         'html5': 'video',
@@ -299,6 +338,20 @@ def video_is_rendered(_step, mode):
     assert world.is_css_present('.speed_link')
 
 
+@step('videos have rendered in "([^"]*)" mode$')
+def videos_are_rendered(_step, mode):
+    modes = {
+        'html5': 'video',
+        'youtube': 'iframe'
+    }
+    html_tag = modes[mode.lower()]
+
+    actual = len(world.css_find('.video {0}'.format(html_tag)))
+    expected = len(world.css_find('.xmodule_VideoModule'))
+    assert actual == expected
+    assert world.is_css_present('.speed_link')
+
+
 @step('all sources are correct$')
 def all_sources_are_correct(_step):
     elements = world.css_find('.video-player video source')
@@ -333,7 +386,7 @@ def set_captions_visibility_state(_step, captions_state):
 
 @step('I see video menu "([^"]*)" with correct items$')
 def i_see_menu(_step, menu):
-    _open_menu(menu)
+    open_menu(menu)
     menu_items = world.css_find(VIDEO_MENUS[menu] + ' li')
     video = world.scenario_dict['VIDEO']
     transcripts = dict(video.transcripts)
@@ -388,7 +441,7 @@ def start_playing_video_from_n_seconds(_step, position):
 @step('I see duration "([^"]*)"$')
 def i_see_duration(_step, position):
     world.wait_for(
-        func=lambda _: _duration() == _parse_time_str(position),
+        func=lambda _: duration() == parse_time_str(position),
         timeout=5
     )
 
@@ -402,7 +455,7 @@ def seek_video_to_n_seconds(_step, seconds):
 
 @step('I have a "([^"]*)" transcript file in assets$')
 def upload_to_assets(_step, filename):
-    _upload_file(filename, world.scenario_dict['COURSE'].location)
+    upload_file(filename, world.scenario_dict['COURSE'].location)
 
 
 @step('button "([^"]*)" is hidden$')
@@ -419,20 +472,20 @@ def is_hidden_menu(_step, menu):
 def video_alignment(_step, transcript_visibility):
     # Width of the video container in css equal 75% of window if transcript enabled
     wrapper_width = 75 if transcript_visibility == "with" else 100
-    initial = _get_window_dimensions()
+    initial = get_window_dimensions()
 
-    _set_window_dimensions(300, 600)
-    real, expected = _get_all_dimensions()
+    set_window_dimensions(300, 600)
+    real, expected = get_all_dimensions()
 
     width = round(100 * real['width']/expected['width']) == wrapper_width
 
-    _set_window_dimensions(600, 300)
-    real, expected = _get_all_dimensions()
+    set_window_dimensions(600, 300)
+    real, expected = get_all_dimensions()
 
     height = abs(expected['height'] - real['height']) <= 5
 
     # Restore initial window size
-    _set_window_dimensions(
+    set_window_dimensions(
         initial['width'], initial['height']
     )
 
@@ -473,3 +526,12 @@ def select_transcript_format(_step, format):
 
     assert world.css_find(menu_selector + ' .active a')[0]['data-value'] == format
     assert world.css_has_text(button_selector, '.' + format, strip=True)
+
+
+@step('video (.*) show the captions$')
+def shows_captions(_step, show_captions):
+    if 'not' in show_captions or 'n\'t' in show_captions:
+        assert world.is_css_present('div.video.closed')
+    else:
+        assert world.is_css_not_present('div.video.closed')
+
--
libgit2 0.26.0