Commit 65adb7b2 by polesye

BLD-896: Fix cc button in HTML5 videos.

parent 78fe797e
......@@ -75,32 +75,8 @@
expect(state.el).toBe('#video_id');
});
it('parse the videos if subtitles exist', function () {
var sub = 'Z5KLxerq05Y';
expect(state.videos).toEqual({
'0.75': sub,
'1.0': sub,
'1.25': sub,
'1.50': sub
});
});
it(
'parse the videos if subtitles do not exist',
function ()
{
var sub = '';
$('#example').find('.video').data('sub', '');
state = new window.Video('#example');
expect(state.videos).toEqual({
'0.75': sub,
'1.0': sub,
'1.25': sub,
'1.50': sub
});
it('doesn\'t have `videos` dictionary', function () {
expect(state.videos).toBeUndefined();
});
it('parse Html5 sources', function () {
......
......@@ -7,8 +7,6 @@
window.onTouchBasedDevice = jasmine.createSpy('onTouchBasedDevice')
.andReturn(null);
state = jasmine.initializePlayer();
videoControl = state.videoControl;
$.fn.scrollTo.reset();
});
......@@ -29,18 +27,20 @@
describe('always', function () {
beforeEach(function () {
spyOn($, 'ajaxWithPrefix').andCallThrough();
state = jasmine.initializePlayer();
});
it('create the caption element', function () {
state = jasmine.initializePlayer();
expect($('.video')).toContain('ol.subtitles');
});
it('add caption control to video player', function () {
state = jasmine.initializePlayer();
expect($('.video')).toContain('a.hide-subtitles');
});
it('add ARIA attributes to caption control', function () {
state = jasmine.initializePlayer();
var captionControl = $('a.hide-subtitles');
expect(captionControl).toHaveAttrs({
'role': 'button',
......@@ -49,7 +49,11 @@
});
});
it('fetch the caption', function () {
it('fetch the caption in HTML5 mode', function () {
runs(function () {
state = jasmine.initializePlayer();
});
waitsFor(function () {
if (state.videoCaption.loaded === true) {
return true;
......@@ -62,29 +66,62 @@
expect($.ajaxWithPrefix).toHaveBeenCalledWith({
url: '/transcript/translation',
notifyOnError: false,
data: {
videoId: 'Z5KLxerq05Y',
data: jasmine.any(Object),
success: jasmine.any(Function),
error: jasmine.any(Function)
});
expect($.ajaxWithPrefix.mostRecentCall.args[0].data)
.toEqual({
language: 'en'
},
});
});
});
it('fetch the caption in Youtube mode', function () {
runs(function () {
state = jasmine.initializePlayerYouTube();
});
waitsFor(function () {
if (state.videoCaption.loaded === true) {
return true;
}
return false;
}, 'Expect captions to be loaded.', WAIT_TIMEOUT);
runs(function () {
expect($.ajaxWithPrefix).toHaveBeenCalledWith({
url: '/transcript/translation',
notifyOnError: false,
data: jasmine.any(Object),
success: jasmine.any(Function),
error: jasmine.any(Function)
});
expect($.ajaxWithPrefix.mostRecentCall.args[0].data)
.toEqual({
language: 'en',
videoId: 'abcdefghijkl'
});
});
});
it('bind window resize event', function () {
state = jasmine.initializePlayer();
expect($(window)).toHandleWith(
'resize', state.videoCaption.resize
);
});
it('bind the hide caption button', function () {
state = jasmine.initializePlayer();
expect($('.hide-subtitles')).toHandleWith(
'click', state.videoCaption.toggle
);
});
it('bind the mouse movement', function () {
state = jasmine.initializePlayer();
expect($('.subtitles')).toHandleWith(
'mouseover', state.videoCaption.onMouseEnter
);
......@@ -103,8 +140,9 @@
});
it('bind the scroll', function () {
expect($('.subtitles'))
.toHandleWith('scroll', state.videoControl.showControls);
state = jasmine.initializePlayer();
expect($('.subtitles'))
.toHandleWith('scroll', state.videoControl.showControls);
});
});
......@@ -284,7 +322,8 @@
describe('when no captions file was specified', function () {
beforeEach(function () {
state = jasmine.initializePlayer('video_all.html', {
'sub': ''
'sub': '',
'transcriptLanguages': {},
});
});
......@@ -395,6 +434,8 @@
});
it('reRenderCaption', function () {
state = jasmine.initializePlayer();
var Caption = state.videoCaption,
li;
......@@ -426,14 +467,6 @@
spyOn(state, 'youtubeId').andReturn('Z5KLxerq05Y');
});
it('do not fetch captions, if 1.0 speed is absent', function () {
state.youtubeId.andReturn(void(0));
Caption.fetchCaption();
expect($.ajaxWithPrefix).not.toHaveBeenCalled();
expect(Caption.hideCaptions).not.toHaveBeenCalled();
});
it('show caption on language change', function () {
Caption.loaded = true;
Caption.fetchCaption();
......
......@@ -45,7 +45,6 @@ function (VideoPlayer) {
it('create video caption', function () {
expect(state.videoCaption).toBeDefined();
expect(state.youtubeId('1.0')).toEqual('Z5KLxerq05Y');
expect(state.speed).toEqual('1.50');
expect(state.config.transcriptTranslationUrl)
.toEqual('/transcript/translation');
......
......@@ -202,12 +202,6 @@ function (VideoPlayer, VideoStorage) {
);
state.speeds = ['0.75', '1.0', '1.25', '1.50'];
state.videos = {
'0.75': state.config.sub,
'1.0': state.config.sub,
'1.25': state.config.sub,
'1.50': state.config.sub
};
// We must have at least one non-YouTube video source available.
// Otherwise, return a negative.
......
......@@ -461,7 +461,7 @@ function (HTML5Video, Resizer) {
this.videoPlayer.log(
'pause_video',
{
'currentTime': this.videoPlayer.currentTime
currentTime: this.videoPlayer.currentTime
}
);
......@@ -482,7 +482,7 @@ function (HTML5Video, Resizer) {
this.videoPlayer.log(
'play_video',
{
'currentTime': this.videoPlayer.currentTime
currentTime: this.videoPlayer.currentTime
}
);
......@@ -863,8 +863,7 @@ function (HTML5Video, Resizer) {
// Default parameters that always get logged.
logInfo = {
'id': this.id,
'code': this.youtubeId()
id: this.id
};
// If extra parameters were passed to the log.
......
......@@ -226,14 +226,10 @@ function () {
*/
function fetchCaption() {
var self = this,
Caption = self.videoCaption;
// Check whether the captions file was specified. This is the point
// where we either stop with the caption panel (so that a white empty
// panel to the right of the video will not be shown), or carry on
// further.
if (!this.youtubeId('1.0')) {
return false;
}
Caption = self.videoCaption,
data = {
language: this.getCurrentLanguage()
};
if (Caption.loaded) {
Caption.hideCaptions(false);
......@@ -245,15 +241,16 @@ function () {
Caption.fetchXHR.abort();
}
if (this.videoType === 'youtube') {
data.videoId = this.youtubeId();
}
// Fetch the captions file. If no file was specified, or if an error
// occurred, then we hide the captions panel, and the "CC" button
Caption.fetchXHR = $.ajaxWithPrefix({
url: self.config.transcriptTranslationUrl,
notifyOnError: false,
data: {
videoId: this.youtubeId(),
language: this.getCurrentLanguage()
},
data: data,
success: function (captions) {
Caption.captions = captions.text;
Caption.start = captions.start;
......
......@@ -10,7 +10,6 @@ in-browser HTML5 video method (when in HTML5 mode).
in XML.
"""
import os
import json
import logging
from operator import itemgetter
......@@ -329,7 +328,7 @@ class VideoModule(VideoFields, XModule):
`available_translations`: returns list of languages, for which SRT files exist. For 'en' check if SJSON exists.
"""
if dispatch == 'translation':
if 'language' not in request.GET or 'videoId' not in request.GET:
if 'language' not in request.GET:
log.info("Invalid /transcript GET parameters.")
return Response(status=400)
......@@ -341,7 +340,7 @@ class VideoModule(VideoFields, XModule):
self.transcript_language = lang
try:
transcript = self.translation(request.GET.get('videoId'))
transcript = self.translation(request.GET.get('videoId', None))
except (TranscriptException, NotFoundError) as ex:
log.info(ex.message)
response = Response(status=404)
......@@ -390,26 +389,30 @@ class VideoModule(VideoFields, XModule):
return response
def translation(self, subs_id):
def translation(self, youtube_id):
"""
This is called to get transcript file for specific language.
subs_id: str: must be on of: self.sub or one of youtube_ids.
youtube_id: str: must be one of youtube_ids or None if HTML video
Logic flow:
If english -> give back `sub` subtitles:
Return what we have in contentstore for given subs_id,
We should not regenerate needed transcripts, if, for example, they present for youtube 1.0 speed,
and we need for other speeds. Such generation should be done in transcripts workflow.
If non-english:
a) extract subs_id from srt file name
if non-youtube:
b) try to find sjson by subs_id and return if sucessful
c) otherwise generate sjson from srt and return it.
if youtube:
b) try to find sjson by subs_id and return if sucessful
c) generate sjson from srt for all youtube speeds
If youtube_id doesn't exist, we have a video in HTML5 mode. Otherwise,
video video in Youtube or Flash modes.
if youtube:
If english -> give back youtube_id subtitles:
Return what we have in contentstore for given youtube_id.
If non-english:
a) extract youtube_id from srt file name.
b) try to find sjson by youtube_id and return if successful.
c) generate sjson from srt for all youtube speeds.
if non-youtube:
If english -> give back `sub` subtitles:
Return what we have in contentstore for given subs_if that is stored in self.sub.
If non-english:
a) try to find previously generated sjson.
b) otherwise generate sjson from srt and return it.
Filenames naming:
en: subs_videoid.srt.sjson
......@@ -418,28 +421,36 @@ class VideoModule(VideoFields, XModule):
Raises:
NotFoundError if for 'en' subtitles no asset is uploaded.
"""
if self.transcript_language == 'en':
return asset(self.location, subs_id).data
if not self.youtube_id_1_0: # Non-youtube (HTML5) case:
return get_or_create_sjson(self)
# Youtube case:
youtube_ids = youtube_speed_dict(self)
assert subs_id in youtube_ids
try:
sjson_transcript = asset(self.location, subs_id, self.transcript_language).data
except (NotFoundError):
log.info("Can't find content in storage for %s transcript: generating.", subs_id)
generate_sjson_for_all_speeds(
self,
self.transcripts[self.transcript_language],
{speed: subs_id for subs_id, speed in youtube_ids.iteritems()},
self.transcript_language
)
sjson_transcript = asset(self.location, subs_id, self.transcript_language).data
return sjson_transcript
if youtube_id:
# Youtube case:
if self.transcript_language == 'en':
return asset(self.location, youtube_id).data
youtube_ids = youtube_speed_dict(self)
assert youtube_id in youtube_ids
try:
sjson_transcript = asset(self.location, youtube_id, self.transcript_language).data
except (NotFoundError):
log.info("Can't find content in storage for %s transcript: generating.", youtube_id)
generate_sjson_for_all_speeds(
self,
self.transcripts[self.transcript_language],
{speed: youtube_id for youtube_id, speed in youtube_ids.iteritems()},
self.transcript_language
)
sjson_transcript = asset(self.location, youtube_id, self.transcript_language).data
return sjson_transcript
else:
# HTML5 case
if self.transcript_language == 'en':
return asset(self.location, self.sub).data
else:
return get_or_create_sjson(self)
class VideoDescriptor(VideoFields, TabsEditingDescriptor, EmptyDataRawDescriptor):
......
......@@ -2,7 +2,7 @@
Feature: LMS Video component
As a student, I want to view course videos in LMS
# 0
# 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
......@@ -13,51 +13,51 @@ Feature: LMS Video component
And I click video button "play"
Then I see video starts playing from "0:10" position
# 1
# 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
And all sources are correct
# 2
# 3
# Firefox doesn't have HTML5 (only mp4 - fix here)
@skip_firefox
Scenario: Autoplay is disabled in LMS for a Video component
Given the course has a Video component in HTML5 mode
Then when I view the video it does not have autoplay enabled
# 3
# 4
# 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
# 4
# 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
# 5
# 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
# 6
# 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
# 7
# 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
Then error message is shown
And error message has correct text
# 8
# 9
Scenario: Video component stores speed correctly when each video is in separate sequence
Given I am registered for the course "test_course"
And it has a video "A" in "Youtube" mode in position "1" of sequential
......@@ -79,8 +79,8 @@ Feature: LMS Video component
When I open video "C"
Then video "C" should start playing at speed "1.0"
# 9
Scenario: Language menu in Video component works correctly
# 10
Scenario: Language menu works correctly in Video component
Given the course has a Video component in Youtube mode:
| transcripts | sub |
| {"zh": "OEoXaMPEzfM"} | OEoXaMPEzfM |
......@@ -90,3 +90,42 @@ Feature: LMS Video component
Then I see "好 各位同学" text in the captions
And I select language with code "en"
And I see "Hi, welcome to Edx." text in the captions
# 11
Scenario: CC button works correctly w/o english transcript in HTML5 mode of Video component
Given the course has a Video component in HTML5 mode:
| transcripts |
| {"zh": "OEoXaMPEzfM"} |
And I make sure captions are opened
Then I see "好 各位同学" text in the captions
# 12
Scenario: CC button works correctly only w/ english transcript in HTML5 mode of Video component
Given I am registered for the course "test_course"
And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
And it has a video in "HTML5" mode:
| sub |
| OEoXaMPEzfM |
And I make sure captions are opened
Then I see "Hi, welcome to Edx." text in the captions
# 13
Scenario: CC button works correctly w/o english transcript in Youtube mode of Video component
Given the course has a Video component in Youtube mode:
| transcripts |
| {"zh": "OEoXaMPEzfM"} |
And I make sure captions are opened
Then I see "好 各位同学" text in the captions
# 14
Scenario: CC button works correctly if transcripts and sub fields are empty, but transcript file exists is assets (Youtube mode of Video component)
Given I am registered for the course "test_course"
And I have a "subs_OEoXaMPEzfM.srt.sjson" transcript file in assets
And it has a video in "Youtube" mode
And I make sure captions are opened
Then I see "Hi, welcome to Edx." text in the captions
# 15
Scenario: CC button is hidden if no translations
Given the course has a Video component in Youtube mode
Then button "CC" is hidden
......@@ -9,7 +9,6 @@ from django.conf import settings
from cache_toolbox.core import del_cached_content
from xmodule.contentstore.content import StaticContent
import os
from functools import partial
from xmodule.contentstore.django import contentstore
TEST_ROOT = settings.COMMON_TEST_DATA_ROOT
LANGUAGES = settings.ALL_LANGUAGES
......@@ -46,48 +45,6 @@ VIDEO_BUTTONS = {
coursenum = 'test_course'
sequence = {}
@step('when I view the (.*) it does not have autoplay enabled$')
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(?:\:)?$')
def view_video(_step, player_mode):
i_am_registered_for_the_course(_step, coursenum)
# Make sure we have a video
add_video_to_course(coursenum, player_mode.lower(), _step.hashes)
visit_scenario_item('SECTION')
@step('a video "([^"]*)" in "([^"]*)" mode in position "([^"]*)" of sequential(?:\:)?$')
def add_video(_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('I open the section with videos$')
def visit_video_section(_step):
visit_scenario_item('SECTION')
@step('I select the "([^"]*)" speed on video "([^"]*)"$')
def change_video_speed(_step, speed, player_id):
_navigate_to_an_item_in_a_sequence(sequence[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])
@step('video "([^"]*)" should start playing at speed "([^"]*)"$')
def check_video_speed(_step, player_id, speed):
speed_css = '.speeds p.active'
assert world.css_has_text(speed_css, '{0}x'.format(speed))
def add_video_to_course(course, player_mode, hashes, display_name='Video'):
category = 'video'
......@@ -129,16 +86,105 @@ def add_video_to_course(course, player_mode, hashes, display_name='Video'):
if 'transcripts' in kwargs['metadata']:
kwargs['metadata']['transcripts'] = json.loads(kwargs['metadata']['transcripts'])
course_location = world.scenario_dict['COURSE'].location
if 'sub' in kwargs['metadata']:
_upload_file(kwargs['metadata']['sub'], 'en', world.scenario_dict['COURSE'].location)
filename = _get_transcript_filename(kwargs['metadata']['sub'], 'en')
_upload_file(filename, course_location)
for lang, videoId in kwargs['metadata']['transcripts'].items():
_upload_file(videoId, lang, world.scenario_dict['COURSE'].location)
filename = _get_transcript_filename(videoId, lang)
_upload_file(filename, course_location)
world.scenario_dict['VIDEO'] = world.ItemFactory.create(**kwargs)
def _get_transcript_filename(videoId, lang):
if lang == 'en':
return 'subs_{0}.srt.sjson'.format(videoId)
else:
return '{0}_subs_{1}.srt.sjson'.format(lang, videoId)
def _upload_file(filename, location):
path = os.path.join(TEST_ROOT, 'uploads/', filename)
f = open(os.path.abspath(path))
mime_type = "application/json"
content_location = StaticContent.compute_location(
location.org, location.course, filename
)
content = StaticContent(content_location, filename, mime_type, f.read())
contentstore().save(content)
del_cached_content(content.location)
def _navigate_to_an_item_in_a_sequence(number):
sequence_css = 'a[data-element="{0}"]'.format(number)
world.css_click(sequence_css)
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):
world.browser.execute_script("$('{selector}').parent().addClass('open')".format(
selector=VIDEO_MENUS[menu]
))
@step('when I view the (.*) it does not have autoplay enabled$')
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(?:\:)?$')
def view_video(_step, player_mode):
i_am_registered_for_the_course(_step, coursenum)
# Make sure we have a video
add_video_to_course(coursenum, player_mode.lower(), _step.hashes)
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)
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('I open the section with videos$')
def visit_video_section(_step):
visit_scenario_item('SECTION')
@step('I select the "([^"]*)" speed on video "([^"]*)"$')
def change_video_speed(_step, speed, player_id):
_navigate_to_an_item_in_a_sequence(sequence[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])
@step('video "([^"]*)" should start playing at speed "([^"]*)"$')
def check_video_speed(_step, player_id, speed):
speed_css = '.speeds p.active'
assert world.css_has_text(speed_css, '{0}x'.format(speed))
@step('youtube server is up and response time is (.*) seconds$')
def set_youtube_response_timeout(_step, time):
world.youtube.config['time_to_response'] = float(time)
......@@ -232,47 +278,6 @@ def click_button(_step, button):
world.css_find(VIDEO_BUTTONS[button]).click()
def _upload_file(videoId, lang, location):
if lang == 'en':
filename = 'subs_{0}.srt.sjson'.format(videoId)
else:
filename = '{0}_subs_{1}.srt.sjson'.format(lang, videoId)
path = os.path.join(TEST_ROOT, 'uploads/', filename)
f = open(os.path.abspath(path))
mime_type = "application/json"
content_location = StaticContent.compute_location(
location.org, location.course, filename
)
sc_partial = partial(StaticContent, content_location, filename, mime_type)
content = sc_partial(f.read())
(thumbnail_content, thumbnail_location) = contentstore().generate_thumbnail(
content,
tempfile_path=None
)
del_cached_content(thumbnail_location)
if thumbnail_content is not None:
content.thumbnail_location = thumbnail_location
contentstore().save(content)
del_cached_content(content.location)
def _navigate_to_an_item_in_a_sequence(number):
sequence_css = 'a[data-element="{0}"]'.format(number)
world.css_click(sequence_css)
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)
@step('I click video button "([^"]*)"$')
def click_button_video(_step, button_type):
world.wait_for_ajax_complete()
......@@ -295,7 +300,12 @@ def seek_video_to_n_seconds(_step, seconds):
world.browser.execute_script(jsCode)
def _open_menu(menu):
world.browser.execute_script("$('{selector}').parent().addClass('open')".format(
selector=VIDEO_MENUS[menu]
))
@step('I have a "([^"]*)" transcript file in assets$')
def upload_to_assets(_step, filename):
_upload_file(filename, world.scenario_dict['COURSE'].location)
@step('button "([^"]*)" is hidden$')
def is_hidden_button(_step, button):
assert not world.css_visible(VIDEO_BUTTONS[button])
......@@ -189,17 +189,22 @@ class TestVideoTranscriptTranslation(TestVideo):
# Tests for `translation` dispatch:
def test_translation_fails(self):
# No videoId
request = Request.blank('/translation?language=ru')
# No language
request = Request.blank('/translation')
response = self.item.transcript(request=request, dispatch='translation')
self.assertEqual(response.status, '400 Bad Request')
# No videoId - HTML5 video with language that is not in available languages
request = Request.blank('/translation?language=ru')
response = self.item.transcript(request=request, dispatch='translation')
self.assertEqual(response.status, '404 Not Found')
# Language is not in available languages
request = Request.blank('/translation?language=ru&videoId=12345')
response = self.item.transcript(request=request, dispatch='translation')
self.assertEqual(response.status, '404 Not Found')
def test_translaton_en_success(self):
def test_translaton_en_youtube_success(self):
subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
good_sjson = _create_file(json.dumps(subs))
_upload_sjson_file(good_sjson, self.item_descriptor.location)
......@@ -210,25 +215,7 @@ class TestVideoTranscriptTranslation(TestVideo):
response = self.item.transcript(request=request, dispatch='translation')
self.assertDictEqual(json.loads(response.body), subs)
def test_translaton_non_en_non_youtube_success(self):
subs = {
u'end': [100],
u'start': [12],
u'text': [
u'\u041f\u0440\u0438\u0432\u0456\u0442, edX \u0432\u0456\u0442\u0430\u0454 \u0432\u0430\u0441.'
]
}
self.non_en_file.seek(0)
_upload_file(self.non_en_file, self.item_descriptor.location, os.path.split(self.non_en_file.name)[1])
subs_id = _get_subs_id(self.non_en_file.name)
# manually clean youtube_id_1_0, as it has default value
self.item.youtube_id_1_0 = ""
request = Request.blank('/translation?language=uk&videoId={}'.format(subs_id))
response = self.item.transcript(request=request, dispatch='translation')
self.assertDictEqual(json.loads(response.body), subs)
def test_translation_non_en_youtube(self):
def test_translation_non_en_youtube_success(self):
subs = {
u'end': [100],
u'start': [12],
......@@ -270,6 +257,34 @@ class TestVideoTranscriptTranslation(TestVideo):
}
self.assertDictEqual(json.loads(response.body), calculated_1_5)
def test_translaton_en_html5_success(self):
subs = {"start": [10], "end": [100], "text": ["Hi, welcome to Edx."]}
good_sjson = _create_file(json.dumps(subs))
_upload_sjson_file(good_sjson, self.item_descriptor.location)
subs_id = _get_subs_id(good_sjson.name)
self.item.sub = subs_id
request = Request.blank('/translation?language=en')
response = self.item.transcript(request=request, dispatch='translation')
self.assertDictEqual(json.loads(response.body), subs)
def test_translaton_non_en_html5_success(self):
subs = {
u'end': [100],
u'start': [12],
u'text': [
u'\u041f\u0440\u0438\u0432\u0456\u0442, edX \u0432\u0456\u0442\u0430\u0454 \u0432\u0430\u0441.'
]
}
self.non_en_file.seek(0)
_upload_file(self.non_en_file, self.item_descriptor.location, os.path.split(self.non_en_file.name)[1])
# manually clean youtube_id_1_0, as it has default value
self.item.youtube_id_1_0 = ""
request = Request.blank('/translation?language=uk')
response = self.item.transcript(request=request, dispatch='translation')
self.assertDictEqual(json.loads(response.body), subs)
class TestVideoTranscriptsDownload(TestVideo):
"""
......
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